Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Azdevify chat-with-your-data-solution-accelerator. #2

Merged
merged 45 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
24be759
azdevify this sample and add azd new feature in devcontainer
Nov 5, 2023
fbfd9b7
instead parameters.json file with .bicepparam
Nov 5, 2023
d32d977
processing format
Nov 7, 2023
552f254
keep consistent casing for params
Nov 7, 2023
c00f55a
move appsettings
Nov 7, 2023
b2e62b2
remove some invalid changes
Nov 9, 2023
b1a97b7
fix format issues
Nov 9, 2023
625487e
Remove depandsOn
Nov 9, 2023
65ac3c5
remove resources file
Nov 10, 2023
43b09e7
remov keys from output
Nov 10, 2023
bd29d31
remove existing reference in module
Nov 10, 2023
8587450
update ReadMe
Nov 15, 2023
afd3ca8
add rgName in listkeys
Nov 22, 2023
654762e
add use keyvault option
Nov 23, 2023
cc3e957
set default value in .bicepparam
Nov 23, 2023
9dc6a78
fix some bugs
Nov 28, 2023
9bcb2a7
update rbac
Dec 14, 2023
1a9212b
update rbac
Dec 21, 2023
eb11eab
fix some format and update infra core
Jan 3, 2024
a403d25
Update openai to v1
ChenxiJiang333 Jan 3, 2024
b88ee5f
use resourcegroup.name() instead pass in rhName
Jan 3, 2024
4bdf8c3
Merge pull request #1 from zedy-wj/openaiv1
zedy-wj Jan 3, 2024
1ecb9be
Revert "Update openai to v1"
zedy-wj Jan 3, 2024
75f230e
Merge pull request #2 from zedy-wj/revert-1-openaiv1
zedy-wj Jan 3, 2024
969aa25
add token provider
ChenxiJiang333 Jan 4, 2024
ffee3f8
Merge branch 'azdevify' into openaiv1
ChenxiJiang333 Jan 4, 2024
778e1d4
Merge pull request #3 from zedy-wj/openaiv1
zedy-wj Jan 4, 2024
5892d5d
Update requirements.txt
ChenxiJiang333 Jan 4, 2024
ce7d48d
Merge pull request #4 from zedy-wj/ChenxiJiang333-patch-1
zedy-wj Jan 4, 2024
2b683de
revert
Jan 4, 2024
397ab11
fix chat
ChenxiJiang333 Jan 4, 2024
1e21f2a
Update TextProcessingTool.py
ChenxiJiang333 Jan 4, 2024
9481a66
Merge pull request #5 from zedy-wj/newcommit
zedy-wj Jan 5, 2024
b25cce5
update KeyVault options
Jan 10, 2024
332402a
abstract auth type with define method
Jan 11, 2024
bd092df
remove invalid infra/core
Jan 11, 2024
5406c5a
update readme and storage.bicep in infra/core
Jan 12, 2024
d2145ec
Update output format
Jan 17, 2024
c83a409
default to use rbac
Jan 22, 2024
aa86081
add some comments
Jan 26, 2024
06bb879
solve conflicts
ChenxiJiang333 Jan 31, 2024
1a7303a
add readme and speech service related code in main.bicep
Feb 1, 2024
2c8abfb
fix azd deploy problem
Feb 2, 2024
5dcf10c
move code folder structure
Feb 5, 2024
779065f
fix conflict
Feb 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,7 @@ ORCHESTRATION_STRATEGY=openai_functions
#Speech-to-text feature
AZURE_SPEECH_SERVICE_KEY=
AZURE_SPEECH_SERVICE_REGION=
AZURE_AUTH_TYPE=rbac
# Auth type related param. When your AZURE_AUTH_TYPE = rbac, please make sure setting USE_KEY_VAULT= false; When your USE_KEY_VAULT= true, please setting your key vault endpoint.
AZURE_AUTH_TYPE=keys
USE_KEY_VAULT=true
AZURE_KEY_VAULT_ENDPOINT=
6 changes: 3 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"run",
"Admin.py"
],
"cwd": "${workspaceFolder}/code/admin",
"cwd": "${workspaceFolder}/code/backend",
"preLaunchTask": "pip install (code)",
},
{
Expand All @@ -31,14 +31,14 @@
"--debug",
"run"
],
"cwd": "${workspaceFolder}/code/app",
"cwd": "${workspaceFolder}/code",
"preLaunchTask": "pip install (code)"
},
{
"name": "Launch Frontend (UI)",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}/code/app/frontend",
"cwd": "${workspaceFolder}/code/frontend",
"preLaunchTask": "npm install (code)",
"runtimeExecutable": "npm",
"runtimeArgs": [
Expand Down
6 changes: 3 additions & 3 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"isBackground": true,
"dependsOn": "pip install (functions)",
"options": {
"cwd": "${workspaceFolder}/backend"
"cwd": "${workspaceFolder}/code/backend/batch"
}
},
{
Expand All @@ -26,7 +26,7 @@
},
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}/backend"
"cwd": "${workspaceFolder}/code/backend"
}
},
{
Expand All @@ -44,7 +44,7 @@
"command": "npm install",
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}/code/app/frontend"
"cwd": "${workspaceFolder}/code/frontend"
}
}
]
Expand Down
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,49 @@ az deployment group create --resource-group $RESOURCE_GROUP_NAME --template-file


![A screenshot of the chat app.](./media/web-unstructureddata.png)
### Running the sample using the Azure Developer CLI (azd)

The Azure Developer CLI (`azd`) is a developer-centric command-line interface (CLI) tool for creating Azure applications.

You need to install it before running and deploying with the Azure Developer CLI.

### Windows

```powershell
powershell -ex AllSigned -c "Invoke-RestMethod 'https://aka.ms/install-azd.ps1' | Invoke-Expression"
```

### Linux/MacOS

```
curl -fsSL https://aka.ms/install-azd.sh | bash
```

After logging in with the following command, you will be able to use the `azd` cli to quickly provision and deploy the application.

```
azd auth login
```

Then, execute the `azd init` command to initialize the environment (You do not need to run this command if you already have the code or have opened this in a Codespace or DevContainer).
```
azd init -t chat-with-your-data-solution-accelerator
```
Enter an environment name.

**Notes:** the default auth type uses keys, if you want to switch to rbac, please run `azd env set AUTH_TYPE rbac`.
```
azd env set AUTH_TYPE rbac
```

Then, run `azd up` to provision all the resources to Azure and deploy the code to those resources.
```
azd up
```

Select your desired `subscription` and `location`. Then choose a resource group or create a new resource group. Wait a moment for the resource deployment to complete, click the Website endpoint and you will see the web app page.

You can also run the sample directly locally (See below).

### [Local deployment instructions](./docs/LOCAL_DEPLOYMENT.md)
To customize the accelerator or run it locally, first, copy the .env.sample file to your development environment's .env file, and edit it according to environment variable values table. Learn more about deploying locally [here](./docs/LOCAL_DEPLOYMENT.md).
Expand Down
28 changes: 28 additions & 0 deletions azure.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json

name: chat-with-your-data-solution-accelerator
metadata:
template: [email protected]

services:
web:
project: ./code
language: py
host: appservice
hooks:
prepackage:
windows:
shell: pwsh
run: cd ./frontend;npm install;npm run build;
interactive: true
continueOnError: false

adminweb:
project: ./code/backend
language: py
host: appservice

function:
project: ./code/backend/batch
language: py
host: function
90 changes: 45 additions & 45 deletions code/app/app.py → code/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
import os
import logging
import requests
import openai
from openai import AzureOpenAI

# Fixing MIME types for static files under Windows
import mimetypes
from flask import Flask, Response, request, jsonify
from dotenv import load_dotenv
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
from azure.keyvault.secrets import SecretClient
import sys

# Fixing MIME types for static files under Windows
Expand All @@ -26,29 +30,39 @@
def static_file(path):
return app.send_static_file(path)


@app.route("/api/config", methods=["GET"])
AZURE_AUTH_TYPE = os.environ.get("AZURE_AUTH_TYPE", "keys")
# Initialize Azure keys based on authentication type and environment settings.
# When AZURE_AUTH_TYPE is not 'rbac' and USE_KEY_VAULT environment variable is set,
# Azure keys are securely fetched from Azure Key Vault using DefaultAzureCredential.
# Otherwise, keys are obtained from environment variables, with fallbacks to None or
# an empty string depending on the AZURE_AUTH_TYPE.
if not AZURE_AUTH_TYPE == 'rbac' and os.environ.get("USE_KEY_VAULT"):
credential = DefaultAzureCredential()
secret_client = SecretClient(os.environ.get("AZURE_KEY_VAULT_ENDPOINT"), credential)
AZURE_SEARCH_KEY = secret_client.get_secret(os.environ.get("AZURE_SEARCH_KEY")).value
AZURE_OPENAI_KEY = secret_client.get_secret(os.environ.get("AZURE_OPENAI_KEY")).value
AZURE_SPEECH_KEY = secret_client.get_secret(os.environ.get("AZURE_SPEECH_SERVICE_KEY")).value
else:
AZURE_SEARCH_KEY = None if AZURE_AUTH_TYPE == 'rbac' else os.environ.get("AZURE_SEARCH_KEY")
AZURE_OPENAI_KEY = "" if AZURE_AUTH_TYPE == 'rbac' else os.environ.get("AZURE_OPENAI_KEY")
AZURE_SPEECH_KEY = None if AZURE_AUTH_TYPE == 'rbac' else os.environ.get("AZURE_SPEECH_SERVICE_KEY")

@app.route('/api/config', methods=['GET'])
def get_config():
# Retrieve the environment variables or other configuration data
azure_speech_key = os.getenv("AZURE_SPEECH_SERVICE_KEY")
azure_speech_region = os.getenv("AZURE_SPEECH_SERVICE_REGION")
azure_speech_region = os.getenv('AZURE_SPEECH_SERVICE_REGION')

# Return the configuration data as JSON
return jsonify(
{"azureSpeechKey": azure_speech_key, "azureSpeechRegion": azure_speech_region}
)

return jsonify({
'azureSpeechKey': AZURE_SPEECH_KEY,
'azureSpeechRegion': azure_speech_region
})

# ACS Integration Settings
AZURE_SEARCH_SERVICE = os.environ.get("AZURE_SEARCH_SERVICE")
AZURE_SEARCH_INDEX = os.environ.get("AZURE_SEARCH_INDEX")
AZURE_SEARCH_KEY = os.environ.get("AZURE_SEARCH_KEY")
AZURE_SEARCH_USE_SEMANTIC_SEARCH = os.environ.get(
"AZURE_SEARCH_USE_SEMANTIC_SEARCH", "False"
)
AZURE_SEARCH_SEMANTIC_SEARCH_CONFIG = os.environ.get(
"AZURE_SEARCH_SEMANTIC_SEARCH_CONFIG", "default"
)
AZURE_SEARCH_USE_SEMANTIC_SEARCH = os.environ.get("AZURE_SEARCH_USE_SEMANTIC_SEARCH", "False")
AZURE_SEARCH_SEMANTIC_SEARCH_CONFIG = os.environ.get("AZURE_SEARCH_SEMANTIC_SEARCH_CONFIG", "default")
AZURE_SEARCH_TOP_K = os.environ.get("AZURE_SEARCH_TOP_K", 5)
AZURE_SEARCH_ENABLE_IN_DOMAIN = os.environ.get("AZURE_SEARCH_ENABLE_IN_DOMAIN", "true")
AZURE_SEARCH_CONTENT_COLUMNS = os.environ.get("AZURE_SEARCH_CONTENT_COLUMNS")
Expand All @@ -59,7 +73,6 @@ def get_config():
# AOAI Integration Settings
AZURE_OPENAI_RESOURCE = os.environ.get("AZURE_OPENAI_RESOURCE")
AZURE_OPENAI_MODEL = os.environ.get("AZURE_OPENAI_MODEL")
AZURE_OPENAI_KEY = os.environ.get("AZURE_OPENAI_KEY")
AZURE_OPENAI_TEMPERATURE = os.environ.get("AZURE_OPENAI_TEMPERATURE", 0)
AZURE_OPENAI_TOP_P = os.environ.get("AZURE_OPENAI_TOP_P", 1.0)
AZURE_OPENAI_MAX_TOKENS = os.environ.get("AZURE_OPENAI_MAX_TOKENS", 1000)
Expand All @@ -72,10 +85,8 @@ def get_config():
"AZURE_OPENAI_API_VERSION", "2023-06-01-preview"
)
AZURE_OPENAI_STREAM = os.environ.get("AZURE_OPENAI_STREAM", "true")
AZURE_OPENAI_MODEL_NAME = os.environ.get(
"AZURE_OPENAI_MODEL_NAME", "gpt-35-turbo"
) # Name of the model, e.g. 'gpt-35-turbo' or 'gpt-4'
AZURE_AUTH_TYPE = os.environ.get("AZURE_AUTH_TYPE", "keys")
AZURE_OPENAI_MODEL_NAME = os.environ.get("AZURE_OPENAI_MODEL_NAME", "gpt-35-turbo") # Name of the model, e.g. 'gpt-35-turbo' or 'gpt-4'
AZURE_TOKEN_PROVIDER = get_bearer_token_provider(DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default")

SHOULD_STREAM = True if AZURE_OPENAI_STREAM.lower() == "true" else False

Expand Down Expand Up @@ -241,20 +252,21 @@ def stream_without_data(response):


def conversation_without_data(request):
openai.api_type = "azure"
openai.api_base = f"https://{AZURE_OPENAI_RESOURCE}.openai.azure.com/"
openai.api_version = "2023-03-15-preview"
openai.api_key = AZURE_OPENAI_KEY
azure_endpoint = f"https://{AZURE_OPENAI_RESOURCE}.openai.azure.com/"
if AZURE_AUTH_TYPE == 'rbac':
openai_client = AzureOpenAI(azure_endpoint=azure_endpoint, api_version=AZURE_OPENAI_API_VERSION, azure_ad_token_provider=AZURE_TOKEN_PROVIDER)
else:
openai_client = AzureOpenAI(azure_endpoint=azure_endpoint, api_version=AZURE_OPENAI_API_VERSION, api_key=AZURE_OPENAI_KEY)

request_messages = request.json["messages"]
messages = [{"role": "system", "content": AZURE_OPENAI_SYSTEM_MESSAGE}]

for message in request_messages:
messages.append({"role": message["role"], "content": message["content"]})

response = openai.ChatCompletion.create(
engine=AZURE_OPENAI_MODEL,
messages=messages,
response = openai_client.chat.completions.create(
model=AZURE_OPENAI_MODEL,
messages = messages,
temperature=float(AZURE_OPENAI_TEMPERATURE),
max_tokens=int(AZURE_OPENAI_MAX_TOKENS),
top_p=float(AZURE_OPENAI_TOP_P),
Expand Down Expand Up @@ -315,8 +327,7 @@ def conversation_azure_byod():

@app.route("/api/conversation/custom", methods=["GET", "POST"])
def conversation_custom():
from utilities.helpers.OrchestratorHelper import Orchestrator

from backend.batch.utilities.helpers.OrchestratorHelper import Orchestrator, OrchestrationSettings
message_orchestrator = Orchestrator()

try:
Expand All @@ -331,20 +342,9 @@ def conversation_custom():
chat_history = []
for i, k in enumerate(user_assistant_messages):
if i % 2 == 0:
chat_history.append(
(
user_assistant_messages[i]["content"],
user_assistant_messages[i + 1]["content"],
)
)
from utilities.helpers.ConfigHelper import ConfigHelper

messages = message_orchestrator.handle_message(
user_message=user_message,
chat_history=chat_history,
conversation_id=conversation_id,
orchestrator=ConfigHelper.get_active_config_or_default().orchestrator,
)
chat_history.append((user_assistant_messages[i]['content'],user_assistant_messages[i+1]['content']))
from backend.batch.utilities.helpers.ConfigHelper import ConfigHelper
messages = message_orchestrator.handle_message(user_message=user_message, chat_history=chat_history, conversation_id=conversation_id, orchestrator=ConfigHelper.get_active_config_or_default().orchestrator)

response_obj = {
"id": "response.id",
Expand All @@ -370,4 +370,4 @@ def conversation_custom():


if __name__ == "__main__":
app.run()
app.run()
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading