From 3233fcd2a9963679006fca221f923770b4e76c1e Mon Sep 17 00:00:00 2001 From: Zhijie Huang false Date: Fri, 14 Jun 2024 14:56:47 +0800 Subject: [PATCH 1/3] add sample code --- .gitignore | 3 ++- src/.env | 4 ++++ src/app.py | 36 ++++++++++++++++++++++++++++++++++++ src/requirements.txt | 3 +++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/.env create mode 100644 src/app.py create mode 100644 src/requirements.txt diff --git a/.gitignore b/.gitignore index 347ea51..5128fb6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.azure \ No newline at end of file +.azure +.env \ No newline at end of file diff --git a/src/.env b/src/.env new file mode 100644 index 0000000..7a6b1ae --- /dev/null +++ b/src/.env @@ -0,0 +1,4 @@ +OPENAI_API_VERSION= +AZURE_OPENAI_ENDPOINT= +AZURE_OPENAI_DEPLOYMENT= +AZURE_OPENAI_API_KEY= \ No newline at end of file diff --git a/src/app.py b/src/app.py new file mode 100644 index 0000000..59ce1f5 --- /dev/null +++ b/src/app.py @@ -0,0 +1,36 @@ +from quart import Quart, request +from openai import AzureOpenAI +from dotenv import load_dotenv +import os + +load_dotenv() +azure_endpoint = os.environ["AZURE_OPENAI_ENDPOINT"] +azure_deployment = os.environ["AZURE_OPENAI_DEPLOYMENT"] + +app = Quart(__name__) + +@app.route("/api/chat", methods=['POST']) +async def chat(): + # Get the message from the request data + data = await request.get_json() + message = data["message"] + + # gets the API Key from environment variable AZURE_OPENAI_API_KEY + client = AzureOpenAI( + azure_endpoint=azure_endpoint, + ) + + completion = client.chat.completions.create( + model=azure_deployment, + messages=[ + { + "role": "user", + "content": message, + }, + ], + ) + + return completion.choices[0].message.content + +if __name__ == "__main__": + app.run() diff --git a/src/requirements.txt b/src/requirements.txt new file mode 100644 index 0000000..78f89c5 --- /dev/null +++ b/src/requirements.txt @@ -0,0 +1,3 @@ +quart +openai +python-dotenv \ No newline at end of file From 1169f5ea4a5e142ed61e392723045597b0fa0231 Mon Sep 17 00:00:00 2001 From: Zhijie Huang false Date: Mon, 17 Jun 2024 15:04:18 +0800 Subject: [PATCH 2/3] use managed identity rather than key auth --- src/.env | 1 - src/app.py | 15 +++++++++++---- src/requirements.txt | 3 ++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/.env b/src/.env index 7a6b1ae..8b83c51 100644 --- a/src/.env +++ b/src/.env @@ -1,4 +1,3 @@ OPENAI_API_VERSION= AZURE_OPENAI_ENDPOINT= AZURE_OPENAI_DEPLOYMENT= -AZURE_OPENAI_API_KEY= \ No newline at end of file diff --git a/src/app.py b/src/app.py index 59ce1f5..7fa72bf 100644 --- a/src/app.py +++ b/src/app.py @@ -1,23 +1,30 @@ -from quart import Quart, request -from openai import AzureOpenAI -from dotenv import load_dotenv import os +from azure.identity import DefaultAzureCredential, get_bearer_token_provider +from dotenv import load_dotenv +from openai import AzureOpenAI +from quart import Quart, request + load_dotenv() azure_endpoint = os.environ["AZURE_OPENAI_ENDPOINT"] azure_deployment = os.environ["AZURE_OPENAI_DEPLOYMENT"] +token_provider = get_bearer_token_provider( + DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default") + app = Quart(__name__) + @app.route("/api/chat", methods=['POST']) async def chat(): # Get the message from the request data data = await request.get_json() message = data["message"] - # gets the API Key from environment variable AZURE_OPENAI_API_KEY + # gets the API Version from envrionment variable OPENAI_API_VERSION client = AzureOpenAI( azure_endpoint=azure_endpoint, + azure_ad_token_provider=token_provider, ) completion = client.chat.completions.create( diff --git a/src/requirements.txt b/src/requirements.txt index 78f89c5..693de82 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,3 +1,4 @@ quart openai -python-dotenv \ No newline at end of file +python-dotenv +azure-identity From d6eb6d5efca040e6eed68e352311ddf7f007a145 Mon Sep 17 00:00:00 2001 From: Zhijie Huang false Date: Tue, 18 Jun 2024 15:19:02 +0800 Subject: [PATCH 3/3] apply ai chat protocol specification --- .gitignore | 3 ++- src/app.py | 62 ++++++++++++++++++++++++++++++++--------------- src/config.py | 28 +++++++++++++++++++++ src/stateStore.py | 12 +++++++++ 4 files changed, 84 insertions(+), 21 deletions(-) create mode 100644 src/config.py create mode 100644 src/stateStore.py diff --git a/.gitignore b/.gitignore index 5128fb6..ba6d7f8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .azure -.env \ No newline at end of file +.env +__pycache__ diff --git a/src/app.py b/src/app.py index 7fa72bf..bad8199 100644 --- a/src/app.py +++ b/src/app.py @@ -1,43 +1,65 @@ -import os +import uuid from azure.identity import DefaultAzureCredential, get_bearer_token_provider -from dotenv import load_dotenv from openai import AzureOpenAI -from quart import Quart, request - -load_dotenv() -azure_endpoint = os.environ["AZURE_OPENAI_ENDPOINT"] -azure_deployment = os.environ["AZURE_OPENAI_DEPLOYMENT"] +from quart import Quart, g, request +from stateStore import StateStore +from config import Config token_provider = get_bearer_token_provider( DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default") app = Quart(__name__) +config = Config() +state_store = StateStore() + + +@app.before_request +async def load_history(): + data = await request.get_json() + messages = data.get('messages', []) + session_state = data.get('sessionState', None) + + if session_state: + try: + history = state_store.read(session_state) + messages = history + messages + except ValueError: + pass + else: + session_state = str(uuid.uuid4()) + + g.messages = [ + {"role": "system", "content": config.system_prompt}] + messages + g.session_state = session_state + @app.route("/api/chat", methods=['POST']) async def chat(): - # Get the message from the request data - data = await request.get_json() - message = data["message"] + messages = g.messages + session_state = g.session_state - # gets the API Version from envrionment variable OPENAI_API_VERSION client = AzureOpenAI( - azure_endpoint=azure_endpoint, + api_version=config.azure_api_version, + azure_endpoint=config.azure_endpoint, azure_ad_token_provider=token_provider, ) completion = client.chat.completions.create( - model=azure_deployment, - messages=[ - { - "role": "user", - "content": message, - }, - ], + model=config.azure_deployment, + messages=messages, + max_tokens=1024 ) + choice = completion.choices[0] + responseMessage = { + "role": choice.message.role, + "content": choice.message.content + } + + state_store.save(session_state, messages + [responseMessage]) - return completion.choices[0].message.content + return {"messages": responseMessage, "sessionState": session_state} if __name__ == "__main__": app.run() diff --git a/src/config.py b/src/config.py new file mode 100644 index 0000000..0440003 --- /dev/null +++ b/src/config.py @@ -0,0 +1,28 @@ +import os +from dotenv import load_dotenv + + +class Config: + def __init__(self): + load_dotenv() + self._azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT") + self._azure_deployment = os.environ.get("AZURE_OPENAI_DEPLOYMENT") + self._azure_api_version = os.environ.get("OPENAI_API_VERSION") + self._system_prompt = os.environ.get( + "SYSTEM_PROMPT", "You are a helpful assistant that responds succintly to questions.") + + @property + def azure_endpoint(self): + return self._azure_endpoint + + @property + def azure_deployment(self): + return self._azure_deployment + + @property + def azure_api_version(self): + return self._azure_api_version + + @property + def system_prompt(self): + return self._system_prompt diff --git a/src/stateStore.py b/src/stateStore.py new file mode 100644 index 0000000..d192770 --- /dev/null +++ b/src/stateStore.py @@ -0,0 +1,12 @@ +class StateStore: + def __init__(self): + self.store = {} + + def read(self, key): + state = self.store.get(key) + if state is None: + raise ValueError("Not found.") + return state + + def save(self, key, state): + self.store[key] = state