from fastapi import Request, HTTPException from pydantic import BaseModel, BaseModel, HttpUrl from modal import Secret, App, web_endpoint, Image from typing import Optional, List from example import proposal import os app = App(name="circleback", image=Image.debian_slim().pip_install("openai", "pydantic", "fastapi")) class Attendee(BaseModel): name: Optional[str] email: Optional[str] def markdown(self) -> str: if self.name: return f"- {self.name} ({self.email})" return f"- {self.email}" class Assignee(BaseModel): name: Optional[str] email: Optional[str] def markdown(self) -> str: if self.name: return f"{self.name} ({self.email})" return f"{self.email}" class ActionItem(BaseModel): id: int title: str description: str assignee: Optional[Assignee] status: str def markdown(self) -> str: assignee_info = self.assignee.markdown() if self.assignee else "Unassigned" return f"**{self.title}** (Status: {self.status})\n" \ f"- Description: {self.description}\n" \ f"- Assignee: {assignee_info}\n" class MeetingNotes(BaseModel): id: int name: str createdAt: str duration: int url: Optional[HttpUrl] recordingUrl: Optional[HttpUrl] attendees: List[Attendee] notes: str actionItems: List[ActionItem] def to_markdown(self) -> str: attendees_md = "\n".join([attendee.markdown() for attendee in self.attendees]) action_items_md = "\n".join([item.markdown() for item in self.actionItems]) return f"# Meeting: {self.name}\n\n" \ f"**Created At:** {self.createdAt}\n" \ f"**Duration:** {self.duration} seconds\n" \ f"**URL:** {self.url if self.url else 'N/A'}\n\n" \ f"**Attendees:**\n{attendees_md}\n\n" \ f"# Notes\n\n{self.notes}\n\n" \ f"# Action Items\n\n{action_items_md}\n" @app.function(secrets=[Secret.from_name("OPENAI_API_KEY")]) @web_endpoint(method="POST") async def f(request: Request): body = await request.json() try: webhook_data = MeetingNotes(**body) except Exception as e: raise HTTPException(status_code=400, detail=str(e)) from e transcript = webhook_data.to_markdown() print('PROMPT:\n', '==='*10, '\n', prompt(transcript), '\n', '==='*10) proposal = gen_proposal(transcript) print('\n\nAI GENERATED PROPOSAL:\n\n', '==='*10, '\n', proposal, '\n', '==='*10) def prompt(transcript: str): return f""" Here is an example consulting proposal: {proposal} Here is a transcript of a recent call with a potential client (the client name is in the transcript): {transcript} Write a detailed project proposal, but do not worry about the pricing or the rate. Focus on fleshing out the different tasks we would do that is compelling and convincing for a founder. Flesh out these ideas and add more as necessary. Do not anchor too much on the given examples, instead write a convincing proposal. """ def gen_proposal(transcript: str): from openai import OpenAI client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) response = client.chat.completions.create( model="gpt-4-turbo", messages=[ {"role": "system", "content": "You are an expert AI consultant. Your task is to write a project proposal for a potential client. The client is interested in your services and wants to know more about your approach to solving their problems. Write a detailed proposal that outlines the tasks you would do to help them grow their business. Focus on the value you can provide and how you can help them achieve their goals. Be persuasive and convincing."}, {"role": "user", "content": prompt(transcript)} ] ) return response.choices[0].message.content