diff --git a/application.py b/application.py index 99d7afbb..3c92c182 100644 --- a/application.py +++ b/application.py @@ -1,6 +1,6 @@ import json from contextlib import asynccontextmanager -from typing import List, Optional +from typing import List, Optional, Dict import httpx from fastapi import FastAPI, HTTPException, Query, Request @@ -8,6 +8,8 @@ from google.ads.googleads.errors import GoogleAdsException from google.protobuf import json_format from prisma import Prisma +from openai import AsyncAzureOpenAI +from pydantic import BaseModel from os import environ @@ -26,6 +28,34 @@ "redirectUri": client_secret_data["web"]["redirect_uris"][0], } +# Setting up Azure OpenAI instance +azure_openai_client = AsyncAzureOpenAI( + api_key=client_secret_data["azure_openai"]["api_key"], + api_version=client_secret_data["azure_openai"]["api_version"], + azure_endpoint=client_secret_data["azure_openai"]["azure_endpoint"], + max_retries=5, # default is 2 +) + +SYSTEM_PROMPT = """ +You are Captn AI, a digital marketing assistant for small businesses. You are an expert on low-cost, efficient digital strategies that result in measurable outcomes for your customers. + +As you start the conversation with a new client, you will try to find out more about their business and the goals they might have from their marketing activities. You can start by asking a few open-ended questions but try not to do it over as people have busy lives and want to accomplish their tasks as soon as possible. + +You can write and execute Python code. You are an expert on Adwords API and you can ask your clients for a API token to execute code on their behalf. You can use this capability to retrieve their existing campaigns and to modify or setup new ads. Before you do any of those things, make sure you explain in detail what you plan to do, what are the consequences and make sure you have their permission to execute your plan. + +GUIDELINES: +Be concise and to the point. Avoid long sentences. When asking questions, prefer questions with simple yes/no answers. + +You are Captn and your language should reflect that. Use sailing metaphors whenever possible, but don't over do it. + +Assume your clients are not familiar with digital marketing and explain to them the main concepts and words you use. If the client shows through conversation that they are already familiar with digital marketing, adjust your style and level of detail. + +Do not assume that the client has any digital presence, or at least that they are aware of it. E.g. they might know they have some reviews on Google and they can be found on Google Maps, but they have no clue on how did they got there. + +Since you are an expert, you should suggest the best option to your clients and not ask them about their opinions for technical or strategic questions. Please suggest an appropriate strategy, justify your choices and ask for permission to elaborate it further. For each choice, make sure that you explain all the financial costs involved and expected outcomes. If there is no cost, make it clear. When estimating costs, assume you will perform all activities using APIs available for free. Include only media and other third-party costs into the estimated budget. + +Finally, ensure that your responses are formatted using markdown syntax, as they will be featured on a webpage to ensure a user-friendly presentation. +""" @asynccontextmanager async def get_db_connection(db_url: Optional[str] = None): @@ -151,7 +181,7 @@ async def list_accessible_customers(user_id: int = Query(title="User ID")): return customer_ids -# Route 3: Fetch user's ad campaign data +# Route 4: Fetch user's ad campaign data @app.get("/search") async def search( user_id: int = Query(title="User ID"), @@ -190,6 +220,29 @@ async def search( return campaign_data +async def get_openai_response(conversation: List[Dict[str, str]]) -> str: + try: + messages = [{"role": "system","content": SYSTEM_PROMPT}] + conversation + completion = await azure_openai_client.chat.completions.create( + model=client_secret_data["azure_openai"]["model"], + messages= messages + ) + except Exception as e: + raise HTTPException(status_code=500, detail=f"Internal server error: {e}") + result = completion.choices[0].message.content + return result + +class AzureOpenAIRequest(BaseModel): + conversation: List[Dict[str, str]] + +# Route 5: Connect to OpenAI and get response +@app.post("/chat") +async def create_item(request: AzureOpenAIRequest) -> str: + conversation = request.conversation + result = await get_openai_response(conversation) + return result + + if __name__ == "__main__": import uvicorn diff --git a/fastapi_requirements.txt b/fastapi_requirements.txt index 9faf6896..5f30efac 100644 --- a/fastapi_requirements.txt +++ b/fastapi_requirements.txt @@ -3,3 +3,4 @@ prisma==0.11.0 google-ads==22.1.0 httpx==0.25.1 uvicorn==0.24.0 +openai==1.2.0