Skip to content

Commit

Permalink
Merge pull request #119 from microsoft/Linting-fixes
Browse files Browse the repository at this point in the history
Linting fixes
  • Loading branch information
UtkarshMishra-Microsoft authored Dec 19, 2024
2 parents ac64505 + 70990de commit fe5d3ec
Show file tree
Hide file tree
Showing 19 changed files with 1,301 additions and 936 deletions.
259 changes: 140 additions & 119 deletions app.py

Large diffs are not rendered by default.

23 changes: 12 additions & 11 deletions backend/auth/auth_utils.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
def get_authenticated_user_details(request_headers):
user_object = {}

## check the headers for the Principal-Id (the guid of the signed in user)
# check the headers for the Principal-Id (the guid of the signed in user)
if "X-Ms-Client-Principal-Id" not in request_headers.keys():
## if it's not, assume we're in development mode and return a default user
# if it's not, assume we're in development mode and return a default user
from . import sample_user

raw_user_object = sample_user.sample_user
else:
## if it is, get the user details from the EasyAuth headers
raw_user_object = {k:v for k,v in request_headers.items()}
# if it is, get the user details from the EasyAuth headers
raw_user_object = {k: v for k, v in request_headers.items()}

user_object['user_principal_id'] = raw_user_object.get('X-Ms-Client-Principal-Id')
user_object['user_name'] = raw_user_object.get('X-Ms-Client-Principal-Name')
user_object['auth_provider'] = raw_user_object.get('X-Ms-Client-Principal-Idp')
user_object['auth_token'] = raw_user_object.get('X-Ms-Token-Aad-Id-Token')
user_object['client_principal_b64'] = raw_user_object.get('X-Ms-Client-Principal')
user_object['aad_id_token'] = raw_user_object.get('X-Ms-Token-Aad-Id-Token')
user_object["user_principal_id"] = raw_user_object.get("X-Ms-Client-Principal-Id")
user_object["user_name"] = raw_user_object.get("X-Ms-Client-Principal-Name")
user_object["auth_provider"] = raw_user_object.get("X-Ms-Client-Principal-Idp")
user_object["auth_token"] = raw_user_object.get("X-Ms-Token-Aad-Id-Token")
user_object["client_principal_b64"] = raw_user_object.get("X-Ms-Client-Principal")
user_object["aad_id_token"] = raw_user_object.get("X-Ms-Token-Aad-Id-Token")

return user_object
return user_object
74 changes: 37 additions & 37 deletions backend/auth/sample_user.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
sample_user = {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en",
"Client-Ip": "22.222.222.2222:64379",
"Content-Length": "192",
"Content-Type": "application/json",
"Cookie": "AppServiceAuthSession=/AuR5ENU+pmpoN3jnymP8fzpmVBgphx9uPQrYLEWGcxjIITIeh8NZW7r3ePkG8yBcMaItlh1pX4nzg5TFD9o2mxC/5BNDRe/uuu0iDlLEdKecROZcVRY7QsFdHLjn9KB90Z3d9ZeLwfVIf0sZowWJt03BO5zKGB7vZgL+ofv3QY3AaYn1k1GtxSE9HQWJpWar7mOA64b7Lsy62eY3nxwg3AWDsP3/rAta+MnDCzpdlZMFXcJLj+rsCppW+w9OqGhKQ7uCs03BPeon3qZOdmE8cOJW3+i96iYlhneNQDItHyQqEi1CHbBTSkqwpeOwWP4vcwGM22ynxPp7YFyiRw/X361DGYy+YkgYBkXq1AEIDZ44BCBz9EEaEi0NU+m6yUOpNjEaUtrJKhQywcM2odojdT4XAY+HfTEfSqp0WiAkgAuE/ueCu2JDOfvxGjCgJ4DGWCoYdOdXAN1c+MenT4OSvkMO41YuPeah9qk9ixkJI5s80lv8rUu1J26QF6pstdDkYkAJAEra3RQiiO1eAH7UEb3xHXn0HW5lX8ZDX3LWiAFGOt5DIKxBKFymBKJGzbPFPYjfczegu0FD8/NQPLl2exAX3mI9oy/tFnATSyLO2E8DxwP5wnYVminZOQMjB/I4g3Go14betm0MlNXlUbU1fyS6Q6JxoCNLDZywCoU9Y65UzimWZbseKsXlOwYukCEpuQ5QPT55LuEAWhtYier8LSh+fvVUsrkqKS+bg0hzuoX53X6aqUr7YB31t0Z2zt5TT/V3qXpdyD8Xyd884PqysSkJYa553sYx93ETDKSsfDguanVfn2si9nvDpvUWf6/R02FmQgXiaaaykMgYyIuEmE77ptsivjH3hj/MN4VlePFWokcchF4ciqqzonmICmjEHEx5zpjU2Kwa+0y7J5ROzVVygcnO1jH6ZKDy9bGGYL547bXx/iiYBYqSIQzleOAkCeULrGN2KEHwckX5MpuRaqTpoxdZH9RJv0mIWxbDA0kwGsbMICQd0ZODBkPUnE84qhzvXInC+TL7MbutPEnGbzgxBAS1c2Ct4vxkkjykOeOxTPxqAhxoefwUfIwZZax6A9LbeYX2bsBpay0lScHcA==",
"Disguised-Host": "your_app_service.azurewebsites.net",
"Host": "your_app_service.azurewebsites.net",
"Max-Forwards": "10",
"Origin": "https://your_app_service.azurewebsites.net",
"Referer": "https://your_app_service.azurewebsites.net/",
"Sec-Ch-Ua": "\"Microsoft Edge\";v=\"113\", \"Chromium\";v=\"113\", \"Not-A.Brand\";v=\"24\"",
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": "\"Windows\"",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"Traceparent": "00-24e9a8d1b06f233a3f1714845ef971a9-3fac69f81ca5175c-00",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.42",
"Was-Default-Hostname": "your_app_service.azurewebsites.net",
"X-Appservice-Proto": "https",
"X-Arr-Log-Id": "4102b832-6c88-4c7c-8996-0edad9e4358f",
"X-Arr-Ssl": "2048|256|CN=Microsoft Azure TLS Issuing CA 02, O=Microsoft Corporation, C=US|CN=*.azurewebsites.net, O=Microsoft Corporation, L=Redmond, S=WA, C=US",
"X-Client-Ip": "22.222.222.222",
"X-Client-Port": "64379",
"X-Forwarded-For": "22.222.222.22:64379",
"X-Forwarded-Proto": "https",
"X-Forwarded-Tlsversion": "1.2",
"X-Ms-Client-Principal": "your_base_64_encoded_token",
"X-Ms-Client-Principal-Id": "00000000-0000-0000-0000-000000000000",
"X-Ms-Client-Principal-Idp": "aad",
"X-Ms-Client-Principal-Name": "testusername@constoso.com",
"X-Ms-Token-Aad-Id-Token": "your_aad_id_token",
"X-Original-Url": "/chatgpt",
"X-Site-Deployment-Id": "your_app_service",
"X-Waws-Unencoded-Url": "/chatgpt"
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en",
"Client-Ip": "22.222.222.2222:64379",
"Content-Length": "192",
"Content-Type": "application/json",
"Cookie": "AppServiceAuthSession=/AuR5ENU+pmpoN3jnymP8fzpmVBgphx9uPQrYLEWGcxjIITIeh8NZW7r3ePkG8yBcMaItlh1pX4nzg5TFD9o2mxC/5BNDRe/uuu0iDlLEdKecROZcVRY7QsFdHLjn9KB90Z3d9ZeLwfVIf0sZowWJt03BO5zKGB7vZgL+ofv3QY3AaYn1k1GtxSE9HQWJpWar7mOA64b7Lsy62eY3nxwg3AWDsP3/rAta+MnDCzpdlZMFXcJLj+rsCppW+w9OqGhKQ7uCs03BPeon3qZOdmE8cOJW3+i96iYlhneNQDItHyQqEi1CHbBTSkqwpeOwWP4vcwGM22ynxPp7YFyiRw/X361DGYy+YkgYBkXq1AEIDZ44BCBz9EEaEi0NU+m6yUOpNjEaUtrJKhQywcM2odojdT4XAY+HfTEfSqp0WiAkgAuE/ueCu2JDOfvxGjCgJ4DGWCoYdOdXAN1c+MenT4OSvkMO41YuPeah9qk9ixkJI5s80lv8rUu1J26QF6pstdDkYkAJAEra3RQiiO1eAH7UEb3xHXn0HW5lX8ZDX3LWiAFGOt5DIKxBKFymBKJGzbPFPYjfczegu0FD8/NQPLl2exAX3mI9oy/tFnATSyLO2E8DxwP5wnYVminZOQMjB/I4g3Go14betm0MlNXlUbU1fyS6Q6JxoCNLDZywCoU9Y65UzimWZbseKsXlOwYukCEpuQ5QPT55LuEAWhtYier8LSh+fvVUsrkqKS+bg0hzuoX53X6aqUr7YB31t0Z2zt5TT/V3qXpdyD8Xyd884PqysSkJYa553sYx93ETDKSsfDguanVfn2si9nvDpvUWf6/R02FmQgXiaaaykMgYyIuEmE77ptsivjH3hj/MN4VlePFWokcchF4ciqqzonmICmjEHEx5zpjU2Kwa+0y7J5ROzVVygcnO1jH6ZKDy9bGGYL547bXx/iiYBYqSIQzleOAkCeULrGN2KEHwckX5MpuRaqTpoxdZH9RJv0mIWxbDA0kwGsbMICQd0ZODBkPUnE84qhzvXInC+TL7MbutPEnGbzgxBAS1c2Ct4vxkkjykOeOxTPxqAhxoefwUfIwZZax6A9LbeYX2bsBpay0lScHcA==",
"Disguised-Host": "your_app_service.azurewebsites.net",
"Host": "your_app_service.azurewebsites.net",
"Max-Forwards": "10",
"Origin": "https://your_app_service.azurewebsites.net",
"Referer": "https://your_app_service.azurewebsites.net/",
"Sec-Ch-Ua": '"Microsoft Edge";v="113", "Chromium";v="113", "Not-A.Brand";v="24"',
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '"Windows"',
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"Traceparent": "00-24e9a8d1b06f233a3f1714845ef971a9-3fac69f81ca5175c-00",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.42",
"Was-Default-Hostname": "your_app_service.azurewebsites.net",
"X-Appservice-Proto": "https",
"X-Arr-Log-Id": "4102b832-6c88-4c7c-8996-0edad9e4358f",
"X-Arr-Ssl": "2048|256|CN=Microsoft Azure TLS Issuing CA 02, O=Microsoft Corporation, C=US|CN=*.azurewebsites.net, O=Microsoft Corporation, L=Redmond, S=WA, C=US",
"X-Client-Ip": "22.222.222.222",
"X-Client-Port": "64379",
"X-Forwarded-For": "22.222.222.22:64379",
"X-Forwarded-Proto": "https",
"X-Forwarded-Tlsversion": "1.2",
"X-Ms-Client-Principal": "your_base_64_encoded_token",
"X-Ms-Client-Principal-Id": "00000000-0000-0000-0000-000000000000",
"X-Ms-Client-Principal-Idp": "aad",
"X-Ms-Client-Principal-Name": "testusername@constoso.com",
"X-Ms-Token-Aad-Id-Token": "your_aad_id_token",
"X-Original-Url": "/chatgpt",
"X-Site-Deployment-Id": "your_app_service",
"X-Waws-Unencoded-Url": "/chatgpt",
}
182 changes: 98 additions & 84 deletions backend/history/cosmosdbservice.py
Original file line number Diff line number Diff line change
@@ -1,66 +1,86 @@
import uuid
from datetime import datetime
from azure.cosmos.aio import CosmosClient

from azure.cosmos import exceptions

class CosmosConversationClient():

def __init__(self, cosmosdb_endpoint: str, credential: any, database_name: str, container_name: str, enable_message_feedback: bool = False):
from azure.cosmos.aio import CosmosClient


class CosmosConversationClient:
def __init__(
self,
cosmosdb_endpoint: str,
credential: any,
database_name: str,
container_name: str,
enable_message_feedback: bool = False,
):
self.cosmosdb_endpoint = cosmosdb_endpoint
self.credential = credential
self.database_name = database_name
self.container_name = container_name
self.enable_message_feedback = enable_message_feedback
try:
self.cosmosdb_client = CosmosClient(self.cosmosdb_endpoint, credential=credential)
self.cosmosdb_client = CosmosClient(
self.cosmosdb_endpoint, credential=credential
)
except exceptions.CosmosHttpResponseError as e:
if e.status_code == 401:
raise ValueError("Invalid credentials") from e
else:
raise ValueError("Invalid CosmosDB endpoint") from e

try:
self.database_client = self.cosmosdb_client.get_database_client(database_name)
self.database_client = self.cosmosdb_client.get_database_client(
database_name
)
except exceptions.CosmosResourceNotFoundError:
raise ValueError("Invalid CosmosDB database name")
raise ValueError("Invalid CosmosDB database name")

try:
self.container_client = self.database_client.get_container_client(container_name)
self.container_client = self.database_client.get_container_client(
container_name
)
except exceptions.CosmosResourceNotFoundError:
raise ValueError("Invalid CosmosDB container name")

raise ValueError("Invalid CosmosDB container name")

async def ensure(self):
if not self.cosmosdb_client or not self.database_client or not self.container_client:
if (
not self.cosmosdb_client
or not self.database_client
or not self.container_client
):
return False, "CosmosDB client not initialized correctly"
try:
database_info = await self.database_client.read()
except:
return False, f"CosmosDB database {self.database_name} on account {self.cosmosdb_endpoint} not found"

except Exception:
return (
False,
f"CosmosDB database {self.database_name} on account {self.cosmosdb_endpoint} not found",
)

try:
container_info = await self.container_client.read()
except:
except Exception:
return False, f"CosmosDB container {self.container_name} not found"

return True, "CosmosDB client initialized successfully"

async def create_conversation(self, user_id, title = ''):
async def create_conversation(self, user_id, title=""):
conversation = {
'id': str(uuid.uuid4()),
'type': 'conversation',
'createdAt': datetime.utcnow().isoformat(),
'updatedAt': datetime.utcnow().isoformat(),
'userId': user_id,
'title': title
"id": str(uuid.uuid4()),
"type": "conversation",
"createdAt": datetime.utcnow().isoformat(),
"updatedAt": datetime.utcnow().isoformat(),
"userId": user_id,
"title": title,
}
## TODO: add some error handling based on the output of the upsert_item call
resp = await self.container_client.upsert_item(conversation)
# TODO: add some error handling based on the output of the upsert_item call
resp = await self.container_client.upsert_item(conversation)
if resp:
return resp
else:
return False

async def upsert_conversation(self, conversation):
resp = await self.container_client.upsert_item(conversation)
if resp:
Expand All @@ -69,115 +89,109 @@ async def upsert_conversation(self, conversation):
return False

async def delete_conversation(self, user_id, conversation_id):
conversation = await self.container_client.read_item(item=conversation_id, partition_key=user_id)
conversation = await self.container_client.read_item(
item=conversation_id, partition_key=user_id
)
if conversation:
resp = await self.container_client.delete_item(item=conversation_id, partition_key=user_id)
resp = await self.container_client.delete_item(
item=conversation_id, partition_key=user_id
)
return resp
else:
return True


async def delete_messages(self, conversation_id, user_id):
## get a list of all the messages in the conversation
# get a list of all the messages in the conversation
messages = await self.get_messages(user_id, conversation_id)
response_list = []
if messages:
for message in messages:
resp = await self.container_client.delete_item(item=message['id'], partition_key=user_id)
resp = await self.container_client.delete_item(
item=message["id"], partition_key=user_id
)
response_list.append(resp)
return response_list


async def get_conversations(self, user_id, limit, sort_order = 'DESC', offset = 0):
parameters = [
{
'name': '@userId',
'value': user_id
}
]
async def get_conversations(self, user_id, limit, sort_order="DESC", offset=0):
parameters = [{"name": "@userId", "value": user_id}]
query = f"SELECT * FROM c where c.userId = @userId and c.type='conversation' order by c.updatedAt {sort_order}"
if limit is not None:
query += f" offset {offset} limit {limit}"
query += f" offset {offset} limit {limit}"

conversations = []
async for item in self.container_client.query_items(query=query, parameters=parameters):
async for item in self.container_client.query_items(
query=query, parameters=parameters
):
conversations.append(item)

return conversations

async def get_conversation(self, user_id, conversation_id):
parameters = [
{
'name': '@conversationId',
'value': conversation_id
},
{
'name': '@userId',
'value': user_id
}
{"name": "@conversationId", "value": conversation_id},
{"name": "@userId", "value": user_id},
]
query = f"SELECT * FROM c where c.id = @conversationId and c.type='conversation' and c.userId = @userId"
query = "SELECT * FROM c where c.id = @conversationId and c.type='conversation' and c.userId = @userId"
conversations = []
async for item in self.container_client.query_items(query=query, parameters=parameters):
async for item in self.container_client.query_items(
query=query, parameters=parameters
):
conversations.append(item)

## if no conversations are found, return None
# if no conversations are found, return None
if len(conversations) == 0:
return None
else:
return conversations[0]

async def create_message(self, uuid, conversation_id, user_id, input_message: dict):
message = {
'id': uuid,
'type': 'message',
'userId' : user_id,
'createdAt': datetime.utcnow().isoformat(),
'updatedAt': datetime.utcnow().isoformat(),
'conversationId' : conversation_id,
'role': input_message['role'],
'content': input_message['content']
"id": uuid,
"type": "message",
"userId": user_id,
"createdAt": datetime.utcnow().isoformat(),
"updatedAt": datetime.utcnow().isoformat(),
"conversationId": conversation_id,
"role": input_message["role"],
"content": input_message["content"],
}

if self.enable_message_feedback:
message['feedback'] = ''
resp = await self.container_client.upsert_item(message)
message["feedback"] = ""

resp = await self.container_client.upsert_item(message)
if resp:
## update the parent conversations's updatedAt field with the current message's createdAt datetime value
# update the parent conversations's updatedAt field with the current message's createdAt datetime value
conversation = await self.get_conversation(user_id, conversation_id)
if not conversation:
return "Conversation not found"
conversation['updatedAt'] = message['createdAt']
conversation["updatedAt"] = message["createdAt"]
await self.upsert_conversation(conversation)
return resp
else:
return False

async def update_message_feedback(self, user_id, message_id, feedback):
message = await self.container_client.read_item(item=message_id, partition_key=user_id)
message = await self.container_client.read_item(
item=message_id, partition_key=user_id
)
if message:
message['feedback'] = feedback
message["feedback"] = feedback
resp = await self.container_client.upsert_item(message)
return resp
else:
return False

async def get_messages(self, user_id, conversation_id):
parameters = [
{
'name': '@conversationId',
'value': conversation_id
},
{
'name': '@userId',
'value': user_id
}
{"name": "@conversationId", "value": conversation_id},
{"name": "@userId", "value": user_id},
]
query = f"SELECT * FROM c WHERE c.conversationId = @conversationId AND c.type='message' AND c.userId = @userId ORDER BY c.timestamp ASC"
query = "SELECT * FROM c WHERE c.conversationId = @conversationId AND c.type='message' AND c.userId = @userId ORDER BY c.timestamp ASC"
messages = []
async for item in self.container_client.query_items(query=query, parameters=parameters):
async for item in self.container_client.query_items(
query=query, parameters=parameters
):
messages.append(item)

return messages

Loading

0 comments on commit fe5d3ec

Please sign in to comment.