diff --git a/app.py b/app.py deleted file mode 100644 index 4bd338e8..00000000 --- a/app.py +++ /dev/null @@ -1,931 +0,0 @@ -import copy -import json -import logging -import os -import uuid - -import httpx -from azure.core.credentials import AzureKeyCredential -from azure.identity.aio import (DefaultAzureCredential, - get_bearer_token_provider) -from azure.search.documents import SearchClient -from openai import AsyncAzureOpenAI -from quart import (Blueprint, Quart, jsonify, make_response, render_template, - request, send_from_directory) - -from backend.auth.auth_utils import get_authenticated_user_details -from backend.history.cosmosdbservice import CosmosConversationClient -from backend.security.ms_defender_utils import get_msdefender_user_json -from backend.settings import ( - MINIMUM_SUPPORTED_AZURE_OPENAI_PREVIEW_API_VERSION, app_settings) -from backend.utils import (ChatType, format_as_ndjson, - format_non_streaming_response, - format_stream_response) - -bp = Blueprint("routes", __name__, static_folder="static", template_folder="static") - - -def create_app(): - app = Quart(__name__) - app.register_blueprint(bp) - app.config["TEMPLATES_AUTO_RELOAD"] = True - return app - - -@bp.route("/") -async def index(): - return await render_template( - "index.html", title=app_settings.ui.title, favicon=app_settings.ui.favicon - ) - - -@bp.route("/favicon.ico") -async def favicon(): - return await bp.send_static_file("favicon.ico") - - -@bp.route("/assets/") -async def assets(path): - return await send_from_directory("static/assets", path) - - -# Debug settings -DEBUG = os.environ.get("DEBUG", "false") -if DEBUG.lower() == "true": - logging.basicConfig(level=logging.DEBUG) - -USER_AGENT = "GitHubSampleWebApp/AsyncAzureOpenAI/1.0.0" - - -# Frontend Settings via Environment Variables -frontend_settings = { - "auth_enabled": app_settings.base_settings.auth_enabled, - "feedback_enabled": ( - app_settings.chat_history and app_settings.chat_history.enable_feedback - ), - "ui": { - "title": app_settings.ui.title, - "logo": app_settings.ui.logo, - "chat_logo": app_settings.ui.chat_logo or app_settings.ui.logo, - "chat_title": app_settings.ui.chat_title, - "chat_description": app_settings.ui.chat_description, - "show_share_button": app_settings.ui.show_share_button, - }, - "sanitize_answer": app_settings.base_settings.sanitize_answer, -} - - -# Enable Microsoft Defender for Cloud Integration -MS_DEFENDER_ENABLED = os.environ.get("MS_DEFENDER_ENABLED", "true").lower() == "true" - - -# Initialize Azure OpenAI Client -def init_openai_client(): - azure_openai_client = None - try: - # API version check - if ( - app_settings.azure_openai.preview_api_version - < MINIMUM_SUPPORTED_AZURE_OPENAI_PREVIEW_API_VERSION - ): - raise ValueError( - f"The minimum supported Azure OpenAI preview API version is" - f"'{MINIMUM_SUPPORTED_AZURE_OPENAI_PREVIEW_API_VERSION}'" - ) - - # Endpoint - if ( - not app_settings.azure_openai.endpoint - and not app_settings.azure_openai.resource - ): - raise ValueError( - "AZURE_OPENAI_ENDPOINT or AZURE_OPENAI_RESOURCE is required" - ) - - endpoint = ( - app_settings.azure_openai.endpoint - if app_settings.azure_openai.endpoint - else f"https://{app_settings.azure_openai.resource}.openai.azure.com/" - ) - - # Authentication - aoai_api_key = app_settings.azure_openai.key - ad_token_provider = None - if not aoai_api_key: - logging.debug("No AZURE_OPENAI_KEY found, using Azure AD auth") - ad_token_provider = get_bearer_token_provider( - DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default" - ) - - # Deployment - deployment = app_settings.azure_openai.model - if not deployment: - raise ValueError("AZURE_OPENAI_MODEL is required") - - # Default Headers - default_headers = {"x-ms-useragent": USER_AGENT} - - azure_openai_client = AsyncAzureOpenAI( - api_version=app_settings.azure_openai.preview_api_version, - api_key=aoai_api_key, - azure_ad_token_provider=ad_token_provider, - default_headers=default_headers, - azure_endpoint=endpoint, - ) - - return azure_openai_client - except Exception as e: - logging.exception("Exception in Azure OpenAI initialization", e) - azure_openai_client = None - raise e - - -def init_ai_search_client(): - client = None - - try: - endpoint = app_settings.datasource.endpoint - key_credential = app_settings.datasource.key - index_name = app_settings.datasource.index - client = SearchClient( - endpoint=endpoint, - index_name=index_name, - credential=AzureKeyCredential(key_credential), - ) - return client - except Exception as e: - logging.exception("Exception in Azure AI Client initialization", e) - raise e - - -def init_cosmosdb_client(): - cosmos_conversation_client = None - if app_settings.chat_history: - try: - cosmos_endpoint = ( - f"https://{app_settings.chat_history.account}.documents.azure.com:443/" - ) - - if not app_settings.chat_history.account_key: - credential = DefaultAzureCredential() - else: - credential = app_settings.chat_history.account_key - - cosmos_conversation_client = CosmosConversationClient( - cosmosdb_endpoint=cosmos_endpoint, - credential=credential, - database_name=app_settings.chat_history.database, - container_name=app_settings.chat_history.conversations_container, - enable_message_feedback=app_settings.chat_history.enable_feedback, - ) - except Exception as e: - logging.exception("Exception in CosmosDB initialization", e) - cosmos_conversation_client = None - raise e - else: - logging.debug("CosmosDB not configured") - - return cosmos_conversation_client - - -def prepare_model_args(request_body, request_headers): - chat_type = None - if "chat_type" in request_body: - chat_type = ( - ChatType.BROWSE - if not ( - request_body["chat_type"] and request_body["chat_type"] == "template" - ) - else ChatType.TEMPLATE - ) - - request_messages = request_body.get("messages", []) - - messages = [] - if not app_settings.datasource: - messages = [ - { - "role": "system", - "content": app_settings.azure_openai.system_message - if chat_type == ChatType.BROWSE or not chat_type - else app_settings.azure_openai.template_system_message, - } - ] - - for message in request_messages: - if message: - messages.append({"role": message["role"], "content": message["content"]}) - - user_json = None - if MS_DEFENDER_ENABLED: - authenticated_user_details = get_authenticated_user_details(request_headers) - user_json = get_msdefender_user_json( - authenticated_user_details, request_headers - ) - - model_args = { - "messages": messages, - "temperature": app_settings.azure_openai.temperature, - "max_tokens": app_settings.azure_openai.max_tokens, - "top_p": app_settings.azure_openai.top_p, - "stop": app_settings.azure_openai.stop_sequence, - "stream": app_settings.azure_openai.stream - if chat_type == ChatType.BROWSE - else False, - "model": app_settings.azure_openai.model, - "user": user_json, - } - - if app_settings.datasource: - model_args["extra_body"] = { - "data_sources": [ - app_settings.datasource.construct_payload_configuration(request=request) - ] - } - - # change role information if template chat - if chat_type == ChatType.TEMPLATE: - model_args["extra_body"]["data_sources"][0]["parameters"][ - "role_information" - ] = app_settings.azure_openai.template_system_message - - model_args_clean = copy.deepcopy(model_args) - if model_args_clean.get("extra_body"): - secret_params = [ - "key", - "connection_string", - "embedding_key", - "encoded_api_key", - "api_key", - ] - for secret_param in secret_params: - if model_args_clean["extra_body"]["data_sources"][0]["parameters"].get( - secret_param - ): - model_args_clean["extra_body"]["data_sources"][0]["parameters"][ - secret_param - ] = "*****" - authentication = model_args_clean["extra_body"]["data_sources"][0][ - "parameters" - ].get("authentication", {}) - for field in authentication: - if field in secret_params: - model_args_clean["extra_body"]["data_sources"][0]["parameters"][ - "authentication" - ][field] = "*****" - embeddingDependency = model_args_clean["extra_body"]["data_sources"][0][ - "parameters" - ].get("embedding_dependency", {}) - if "authentication" in embeddingDependency: - for field in embeddingDependency["authentication"]: - if field in secret_params: - model_args_clean["extra_body"]["data_sources"][0]["parameters"][ - "embedding_dependency" - ]["authentication"][field] = "*****" - - logging.debug(f"REQUEST BODY: {json.dumps(model_args_clean, indent=4)}") - - return model_args - - -async def send_chat_request(request_body, request_headers): - filtered_messages = [] - messages = request_body.get("messages", []) - for message in messages: - if message.get("role") != "tool": - filtered_messages.append(message) - - request_body["messages"] = filtered_messages - model_args = prepare_model_args(request_body, request_headers) - - try: - azure_openai_client = init_openai_client() - raw_response = ( - await azure_openai_client.chat.completions.with_raw_response.create( - **model_args - ) - ) - response = raw_response.parse() - apim_request_id = raw_response.headers.get("apim-request-id") - except Exception as e: - logging.exception("Exception in send_chat_request") - raise e - - return response, apim_request_id - - -async def complete_chat_request(request_body, request_headers): - response, apim_request_id = await send_chat_request(request_body, request_headers) - history_metadata = request_body.get("history_metadata", {}) - return format_non_streaming_response(response, history_metadata, apim_request_id) - - -async def stream_chat_request(request_body, request_headers): - response, apim_request_id = await send_chat_request(request_body, request_headers) - history_metadata = request_body.get("history_metadata", {}) - - async def generate(): - async for completionChunk in response: - yield format_stream_response( - completionChunk, history_metadata, apim_request_id - ) - - return generate() - - -async def conversation_internal(request_body, request_headers): - try: - chat_type = ( - ChatType.BROWSE - if not ( - request_body["chat_type"] and request_body["chat_type"] == "template" - ) - else ChatType.TEMPLATE - ) - if app_settings.azure_openai.stream and chat_type == ChatType.BROWSE: - result = await stream_chat_request(request_body, request_headers) - response = await make_response(format_as_ndjson(result)) - response.timeout = None - response.mimetype = "application/json-lines" - return response - else: - result = await complete_chat_request(request_body, request_headers) - return jsonify(result) - - except Exception as ex: - logging.exception(ex) - if hasattr(ex, "status_code"): - return jsonify({"error": str(ex)}), ex.status_code - else: - return jsonify({"error": str(ex)}), 500 - - -@bp.route("/conversation", methods=["POST"]) -async def conversation(): - if not request.is_json: - return jsonify({"error": "request must be json"}), 415 - request_json = await request.get_json() - - return await conversation_internal(request_json, request.headers) - - -@bp.route("/frontend_settings", methods=["GET"]) -def get_frontend_settings(): - try: - return jsonify(frontend_settings), 200 - except Exception as e: - logging.exception("Exception in /frontend_settings") - return jsonify({"error": str(e)}), 500 - - -# Conversation History API # -@bp.route("/history/generate", methods=["POST"]) -async def add_conversation(): - authenticated_user = get_authenticated_user_details(request_headers=request.headers) - user_id = authenticated_user["user_principal_id"] - - # check request for conversation_id - request_json = await request.get_json() - conversation_id = request_json.get("conversation_id", None) - - try: - # make sure cosmos is configured - cosmos_conversation_client = init_cosmosdb_client() - if not cosmos_conversation_client: - raise Exception("CosmosDB is not configured or not working") - - # check for the conversation_id, if the conversation is not set, we will create a new one - history_metadata = {} - if not conversation_id: - title = await generate_title(request_json["messages"]) - conversation_dict = await cosmos_conversation_client.create_conversation( - user_id=user_id, title=title - ) - conversation_id = conversation_dict["id"] - history_metadata["title"] = title - history_metadata["date"] = conversation_dict["createdAt"] - - # Format the incoming message object in the "chat/completions" messages format - # then write it to the conversation history in cosmos - messages = request_json["messages"] - if len(messages) > 0 and messages[-1]["role"] == "user": - createdMessageValue = await cosmos_conversation_client.create_message( - uuid=str(uuid.uuid4()), - conversation_id=conversation_id, - user_id=user_id, - input_message=messages[-1], - ) - if createdMessageValue == "Conversation not found": - raise Exception( - "Conversation not found for the given conversation ID: " - + conversation_id - + "." - ) - else: - raise Exception("No user message found") - - await cosmos_conversation_client.cosmosdb_client.close() - - # Submit request to Chat Completions for response - request_body = await request.get_json() - history_metadata["conversation_id"] = conversation_id - request_body["history_metadata"] = history_metadata - return await conversation_internal(request_body, request.headers) - - except Exception as e: - logging.exception("Exception in /history/generate") - return jsonify({"error": str(e)}), 500 - - -@bp.route("/history/update", methods=["POST"]) -async def update_conversation(): - authenticated_user = get_authenticated_user_details(request_headers=request.headers) - user_id = authenticated_user["user_principal_id"] - - # check request for conversation_id - request_json = await request.get_json() - conversation_id = request_json.get("conversation_id", None) - - try: - # make sure cosmos is configured - cosmos_conversation_client = init_cosmosdb_client() - if not cosmos_conversation_client: - raise Exception("CosmosDB is not configured or not working") - - # check for the conversation_id, if the conversation is not set, we will create a new one - if not conversation_id: - raise Exception("No conversation_id found") - - # Format the incoming message object in the "chat/completions" messages format - # then write it to the conversation history in cosmos - messages = request_json["messages"] - if len(messages) > 0 and messages[-1]["role"] == "assistant": - if len(messages) > 1 and messages[-2].get("role", None) == "tool": - # write the tool message first - await cosmos_conversation_client.create_message( - uuid=str(uuid.uuid4()), - conversation_id=conversation_id, - user_id=user_id, - input_message=messages[-2], - ) - # write the assistant message - await cosmos_conversation_client.create_message( - uuid=messages[-1]["id"], - conversation_id=conversation_id, - user_id=user_id, - input_message=messages[-1], - ) - else: - raise Exception("No bot messages found") - - # Submit request to Chat Completions for response - await cosmos_conversation_client.cosmosdb_client.close() - response = {"success": True} - return jsonify(response), 200 - - except Exception as e: - logging.exception("Exception in /history/update") - return jsonify({"error": str(e)}), 500 - - -@bp.route("/history/message_feedback", methods=["POST"]) -async def update_message(): - authenticated_user = get_authenticated_user_details(request_headers=request.headers) - user_id = authenticated_user["user_principal_id"] - cosmos_conversation_client = init_cosmosdb_client() - - # check request for message_id - request_json = await request.get_json() - message_id = request_json.get("message_id", None) - message_feedback = request_json.get("message_feedback", None) - try: - if not message_id: - return jsonify({"error": "message_id is required"}), 400 - - if not message_feedback: - return jsonify({"error": "message_feedback is required"}), 400 - - # update the message in cosmos - updated_message = await cosmos_conversation_client.update_message_feedback( - user_id, message_id, message_feedback - ) - if updated_message: - return ( - jsonify( - { - "message": f"Successfully updated message with feedback {message_feedback}", - "message_id": message_id, - } - ), - 200, - ) - else: - return ( - jsonify( - { - "error": f"Unable to update message {message_id}. " - "It either does not exist or the user does not have access to it." - } - ), - 404, - ) - - except Exception as e: - logging.exception("Exception in /history/message_feedback") - return jsonify({"error": str(e)}), 500 - - -@bp.route("/history/delete", methods=["DELETE"]) -async def delete_conversation(): - # get the user id from the request headers - authenticated_user = get_authenticated_user_details(request_headers=request.headers) - user_id = authenticated_user["user_principal_id"] - - # check request for conversation_id - request_json = await request.get_json() - conversation_id = request_json.get("conversation_id", None) - - try: - if not conversation_id: - return jsonify({"error": "conversation_id is required"}), 400 - - # make sure cosmos is configured - cosmos_conversation_client = init_cosmosdb_client() - if not cosmos_conversation_client: - raise Exception("CosmosDB is not configured or not working") - - # delete the conversation messages from cosmos first - deleted_messages = await cosmos_conversation_client.delete_messages( - conversation_id, user_id - ) - - # Now delete the conversation - deleted_conversation = await cosmos_conversation_client.delete_conversation( - user_id, conversation_id - ) - - await cosmos_conversation_client.cosmosdb_client.close() - - return ( - jsonify( - { - "message": "Successfully deleted conversation and messages", - "conversation_id": conversation_id, - } - ), - 200, - ) - except Exception as e: - logging.exception("Exception in /history/delete") - return jsonify({"error": str(e)}), 500 - - -@bp.route("/history/list", methods=["GET"]) -async def list_conversations(): - offset = request.args.get("offset", 0) - authenticated_user = get_authenticated_user_details(request_headers=request.headers) - user_id = authenticated_user["user_principal_id"] - - # make sure cosmos is configured - cosmos_conversation_client = init_cosmosdb_client() - if not cosmos_conversation_client: - raise Exception("CosmosDB is not configured or not working") - - # get the conversations from cosmos - conversations = await cosmos_conversation_client.get_conversations( - user_id, offset=offset, limit=25 - ) - await cosmos_conversation_client.cosmosdb_client.close() - if not isinstance(conversations, list): - return jsonify({"error": f"No conversations for {user_id} were found"}), 404 - - # return the conversation ids - - return jsonify(conversations), 200 - - -@bp.route("/history/read", methods=["POST"]) -async def get_conversation(): - authenticated_user = get_authenticated_user_details(request_headers=request.headers) - user_id = authenticated_user["user_principal_id"] - - # check request for conversation_id - request_json = await request.get_json() - conversation_id = request_json.get("conversation_id", None) - - if not conversation_id: - return jsonify({"error": "conversation_id is required"}), 400 - - # make sure cosmos is configured - cosmos_conversation_client = init_cosmosdb_client() - if not cosmos_conversation_client: - raise Exception("CosmosDB is not configured or not working") - - # get the conversation object and the related messages from cosmos - conversation = await cosmos_conversation_client.get_conversation( - user_id, conversation_id - ) - # return the conversation id and the messages in the bot frontend format - if not conversation: - return ( - jsonify( - { - "error": ( - f"Conversation {conversation_id} was not found. " - "It either does not exist or the logged in user does not have access to it." - ) - } - ), - 404, - ) - - # get the messages for the conversation from cosmos - conversation_messages = await cosmos_conversation_client.get_messages( - user_id, conversation_id - ) - - # format the messages in the bot frontend format - messages = [ - { - "id": msg["id"], - "role": msg["role"], - "content": msg["content"], - "createdAt": msg["createdAt"], - "feedback": msg.get("feedback"), - } - for msg in conversation_messages - ] - - await cosmos_conversation_client.cosmosdb_client.close() - return jsonify({"conversation_id": conversation_id, "messages": messages}), 200 - - -@bp.route("/history/rename", methods=["POST"]) -async def rename_conversation(): - authenticated_user = get_authenticated_user_details(request_headers=request.headers) - user_id = authenticated_user["user_principal_id"] - - # check request for conversation_id - request_json = await request.get_json() - conversation_id = request_json.get("conversation_id", None) - - if not conversation_id: - return jsonify({"error": "conversation_id is required"}), 400 - - # make sure cosmos is configured - cosmos_conversation_client = init_cosmosdb_client() - if not cosmos_conversation_client: - raise Exception("CosmosDB is not configured or not working") - - # get the conversation from cosmos - conversation = await cosmos_conversation_client.get_conversation( - user_id, conversation_id - ) - if not conversation: - return ( - jsonify( - { - "error": ( - f"Conversation {conversation_id} was not found. " - "It either does not exist or the logged in user does not have access to it." - ) - } - ), - 404, - ) - - # update the title - title = request_json.get("title", None) - if not title: - return jsonify({"error": "title is required"}), 400 - conversation["title"] = title - updated_conversation = await cosmos_conversation_client.upsert_conversation( - conversation - ) - - await cosmos_conversation_client.cosmosdb_client.close() - return jsonify(updated_conversation), 200 - - -@bp.route("/history/delete_all", methods=["DELETE"]) -async def delete_all_conversations(): - # get the user id from the request headers - authenticated_user = get_authenticated_user_details(request_headers=request.headers) - user_id = authenticated_user["user_principal_id"] - - # get conversations for user - try: - # make sure cosmos is configured - cosmos_conversation_client = init_cosmosdb_client() - if not cosmos_conversation_client: - raise Exception("CosmosDB is not configured or not working") - - conversations = await cosmos_conversation_client.get_conversations( - user_id, offset=0, limit=None - ) - if not conversations: - return jsonify({"error": f"No conversations for {user_id} were found"}), 404 - - # delete each conversation - for conversation in conversations: - # delete the conversation messages from cosmos first - deleted_messages = await cosmos_conversation_client.delete_messages( - conversation["id"], user_id - ) - - # Now delete the conversation - deleted_conversation = await cosmos_conversation_client.delete_conversation( - user_id, conversation["id"] - ) - await cosmos_conversation_client.cosmosdb_client.close() - return ( - jsonify( - { - "message": f"Successfully deleted conversation and messages for user {user_id}" - } - ), - 200, - ) - - except Exception as e: - logging.exception("Exception in /history/delete_all") - return jsonify({"error": str(e)}), 500 - - -@bp.route("/history/clear", methods=["POST"]) -async def clear_messages(): - # get the user id from the request headers - authenticated_user = get_authenticated_user_details(request_headers=request.headers) - user_id = authenticated_user["user_principal_id"] - - # check request for conversation_id - request_json = await request.get_json() - conversation_id = request_json.get("conversation_id", None) - - try: - if not conversation_id: - return jsonify({"error": "conversation_id is required"}), 400 - - # make sure cosmos is configured - cosmos_conversation_client = init_cosmosdb_client() - if not cosmos_conversation_client: - raise Exception("CosmosDB is not configured or not working") - - # delete the conversation messages from cosmos - deleted_messages = await cosmos_conversation_client.delete_messages( - conversation_id, user_id - ) - - return ( - jsonify( - { - "message": "Successfully deleted messages in conversation", - "conversation_id": conversation_id, - } - ), - 200, - ) - except Exception as e: - logging.exception("Exception in /history/clear_messages") - return jsonify({"error": str(e)}), 500 - - -@bp.route("/history/ensure", methods=["GET"]) -async def ensure_cosmos(): - if not app_settings.chat_history: - return jsonify({"error": "CosmosDB is not configured"}), 404 - - try: - cosmos_conversation_client = init_cosmosdb_client() - success, err = await cosmos_conversation_client.ensure() - if not cosmos_conversation_client or not success: - if err: - return jsonify({"error": err}), 422 - return jsonify({"error": "CosmosDB is not configured or not working"}), 500 - - await cosmos_conversation_client.cosmosdb_client.close() - return jsonify({"message": "CosmosDB is configured and working"}), 200 - except Exception as e: - logging.exception("Exception in /history/ensure") - cosmos_exception = str(e) - if "Invalid credentials" in cosmos_exception: - return jsonify({"error": cosmos_exception}), 401 - elif "Invalid CosmosDB database name" in cosmos_exception: - return ( - jsonify( - { - "error": f"{cosmos_exception} {app_settings.chat_history.database} for account {app_settings.chat_history.account}" - } - ), - 422, - ) - elif "Invalid CosmosDB container name" in cosmos_exception: - return ( - jsonify( - { - "error": f"{cosmos_exception}: {app_settings.chat_history.conversations_container}" - } - ), - 422, - ) - else: - return jsonify({"error": "CosmosDB is not working"}), 500 - - -@bp.route("/section/generate", methods=["POST"]) -async def generate_section_content(): - request_json = await request.get_json() - try: - # verify that section title and section description are provided - if "sectionTitle" not in request_json: - return jsonify({"error": "sectionTitle is required"}), 400 - - if "sectionDescription" not in request_json: - return jsonify({"error": "sectionDescription is required"}), 400 - - content = await generate_section_content(request_json, request.headers) - return jsonify({"section_content": content}), 200 - except Exception as e: - logging.exception("Exception in /section/generate") - return jsonify({"error": str(e)}), 500 - - -@bp.route("/document/") -async def get_document(filepath): - try: - document = retrieve_document(filepath) - return jsonify(document), 200 - except Exception as e: - logging.exception("Exception in /document/") - return jsonify({"error": str(e)}), 500 - - -async def generate_title(conversation_messages): - # make sure the messages are sorted by _ts descending - title_prompt = app_settings.azure_openai.title_prompt - - messages = [ - {"role": msg["role"], "content": msg["content"]} - for msg in conversation_messages - ] - messages.append({"role": "user", "content": title_prompt}) - - try: - azure_openai_client = init_openai_client(use_data=False) - response = await azure_openai_client.chat.completions.create( - model=app_settings.azure_openai.model, - messages=messages, - temperature=1, - max_tokens=64, - ) - - title = json.loads(response.choices[0].message.content)["title"] - return title - except Exception as e: - return messages[-2]["content"] - - -async def generate_section_content(request_body, request_headers): - prompt = f"""{app_settings.azure_openai.generate_section_content_prompt} - Section Title: {request_body['sectionTitle']} - Section Description: {request_body['sectionDescription']} - """ - - messages = [{"role": "system", "content": app_settings.azure_openai.system_message}] - messages.append({"role": "user", "content": prompt}) - - request_body["messages"] = messages - model_args = prepare_model_args(request_body, request_headers) - - try: - azure_openai_client = init_openai_client() - raw_response = ( - await azure_openai_client.chat.completions.with_raw_response.create( - **model_args - ) - ) - response = raw_response.parse() - - except Exception as e: - logging.exception("Exception in send_chat_request") - raise e - - return response.choices[0].message.content - - -def retrieve_document(filepath): - try: - search_client = init_ai_search_client() - search_query = f"filepath eq '{filepath}'" - # Execute the search query - results = search_client.search(search_query) - - # Get the full_content of the first result - document = next(results) - return document - except Exception as e: - logging.exception("Exception in retrieve_document") - raise e - - -app = create_app()