diff --git a/scenarios/Assistants/code-interptreter/.gitignore b/scenarios/Assistants/code-interptreter/.gitignore new file mode 100644 index 00000000..4c49bd78 --- /dev/null +++ b/scenarios/Assistants/code-interptreter/.gitignore @@ -0,0 +1 @@ +.env diff --git a/scenarios/Assistants/code-interptreter/Dockerfile b/scenarios/Assistants/code-interptreter/Dockerfile new file mode 100644 index 00000000..dd4843da --- /dev/null +++ b/scenarios/Assistants/code-interptreter/Dockerfile @@ -0,0 +1,21 @@ +# Use the official Python image with version 3.9 +FROM python:3.9-slim + +# Set the working directory in the container +WORKDIR /app + +# Copy the requirements file into the container at /app +COPY requirements.txt . + +# Install any needed packages specified in requirements.txt +RUN pip install --no-cache-dir -r requirements.txt + +# Copy the rest of the application code into the container +COPY . . + +# Expose port 8501 for Streamlit +EXPOSE 8501 + + +# Command to run when the container starts +CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"] \ No newline at end of file diff --git a/scenarios/Assistants/code-interptreter/README.md b/scenarios/Assistants/code-interptreter/README.md new file mode 100644 index 00000000..b8ac6075 --- /dev/null +++ b/scenarios/Assistants/code-interptreter/README.md @@ -0,0 +1,60 @@ +# Advanced Analyst Assistant + +This demo app showcases the capabilities of Azure OpenAI Assistants API with Code Interpreter. The frontend is developed with Streamlit. + +![Demo](https://github.com/Valentina-Alto/CodeInterpreter-anomalies/blob/main/assets/ezgif-5-697c67b237.gif?raw=true) + +## Prerequisites + +- Python 3.7 or higher +- Azure OpenAI account with access to at least one chat model (e.g. GPT-4o) +- Azure Blob Storage account (optional, for exporting results) +- Required Python packages listed in `requirements.txt` + +## Installation + +- **Clone the Repository:** + + ```bash + git clone https://github.com/Valentina-Alto/CodeInterpreter-anomalies.git + cd CodeIntepreter-anomalies + ``` + +- **Create a .env File:** + + ```bash + AZURE_OPENAI_ENDPOINT=your-azure-openai-endpoint + AZURE_OPENAI_API_KEY=your-azure-openai-api-key + AZURE_STORAGE_CONNECTION_STRING=your-azure-storage-connection-string + ``` + +### Option 1: Run the App Locally + +- **Run the streamlit app** + ```bash + streamlit run app.py + ``` + + +### Option 2: Create Docker Image and deploy to a container registry + +- **Build Docker Image** + ```bash + docker build -t codeassistant:latest . + ``` +- **Login into Azure (or your Container Registry of choice)** + ```bash + az login + az acr login --name your-acr-name + ``` +- **Tag and Push your image** + ```bash + docker tag codeassistant:latest .azurecr.io/codeassistant:latest + docker push .azurecr.io/codeassistant:latest + ``` + +- **Run the container locally** + ```bash + docker pull .azurecr.io/codeassistant:latest + docker run -p 8501:8501 .azurecr.io/codeassistant:latest + ``` \ No newline at end of file diff --git a/scenarios/Assistants/code-interptreter/app.py b/scenarios/Assistants/code-interptreter/app.py new file mode 100644 index 00000000..583ec36e --- /dev/null +++ b/scenarios/Assistants/code-interptreter/app.py @@ -0,0 +1,328 @@ +from openai import AzureOpenAI +from dotenv import load_dotenv +import streamlit as st +import os +import time +from azure.storage.blob import BlobServiceClient, BlobClient, ContainerClient + +load_dotenv() + +# Initialize session state variables +if 'assistant_run_complete' not in st.session_state: + st.session_state['assistant_run_complete'] = False +if 'run' not in st.session_state: + st.session_state['run'] = None +if 'thread' not in st.session_state: + st.session_state['thread'] = None +if 'messages' not in st.session_state: + st.session_state['messages'] = None +if 'file_ids' not in st.session_state: + st.session_state['file_ids'] = None +if 'assistant_file_id' not in st.session_state: + st.session_state['assistant_file_id'] = None +if 'content' not in st.session_state: + st.session_state['content'] = None +if 'uploaded_file_name' not in st.session_state: + st.session_state['uploaded_file_name'] = None + + + + +def display_assistant_response(messages_data): + if messages_data: + with st.expander("Assistant Messages", expanded=True): + st.write("**Assistant's Final Response:**") + assistant_messages = [msg for msg in messages_data if msg.role == 'assistant'] + if assistant_messages: + final_message = assistant_messages[0] + if final_message.content: + for content_piece in final_message.content: + if hasattr(content_piece, 'text'): + st.write(content_piece.text.value) + elif hasattr(content_piece, 'error'): + st.write(f"**Error:** {content_piece.error.message}") + else: + st.write("No content in the assistant's final message.") + else: + st.write("No assistant messages available.") + else: + st.write("No messages available.") + +def provide_download_and_export(content): + if content is not None: + col1, col2 = st.columns(2) + + with col1: + st.download_button( + label="Download Outliers CSV", + data=content, + file_name='outliers.csv', + mime='text/csv' + ) + + with col2: + if st.button("Export to Blob Storage"): + try: + blob_client = container_client.get_blob_client('outliers.csv') + blob_client.upload_blob(content, overwrite=True) + st.success("File exported to Blob Storage successfully.") + except Exception as e: + st.error(f"An error occurred while exporting to Blob Storage: {e}") + else: + st.write("No content available to download or export.") + +# Create the title and subheader for the Streamlit page +st.title("Advanced Analyst Assistant") +st.subheader("Upload a CSV and ask your questions:") + +# Create placeholders in the sidebar +st.sidebar.header('Configuration') + +# Placeholder for Blob Connection String +blob_connection_placeholder = st.sidebar.empty() + +container_name_placeholder = st.sidebar.empty() + +# Placeholder for Azure OpenAI API Key +azure_api_key_placeholder = st.sidebar.empty() + +azure_api_endpoint_placeholder = st.sidebar.empty() + +# Placeholder for Model Type selection +model_type_placeholder = st.sidebar.empty() + +# Placeholder for Model Type selection +version_placeholder = st.sidebar.empty() + + + +# Update the placeholders with input fields +with blob_connection_placeholder.container(): + blob_connection_string = st.text_input('Blob Connection String', value=os.getenv('AZURE_STORAGE_CONNECTION_STRING'), type = 'password') + +with container_name_placeholder.container(): + container_name = st.text_input('Blob Container name', value='anomalies') + +with azure_api_key_placeholder.container(): + azure_openai_api_key = st.text_input('Azure OpenAI API Key', value=os.getenv("AZURE_OPENAI_API_KEY"), type='password') + +with azure_api_endpoint_placeholder.container(): + azure_api_endpoint = st.text_input('Azure OpenAI Endpoint', value=os.getenv("AZURE_OPENAI_ENDPOINT"), type='password') + +with model_type_placeholder.container(): + model_type = st.selectbox('Model Type', options=['gpt-4o', 'gpt-3.5-turbo']) + +with version_placeholder.container(): + version = st.selectbox('Version', options=["2024-05-01-preview"]) + +client = AzureOpenAI( + azure_endpoint=azure_api_endpoint, + api_key=azure_openai_api_key, + api_version=version +) + +# Define the metaprompt +metaprompt = st.text_area('Your System Message', height=150, value=""" +You are a Risk Detector assistant. You specialize in analyzing CSV files to identify anomalies and outliers. + +""") + +download_ph = "Save these rows in a CSV file named 'outliers.csv'. Ensure that you save the file with the exact name 'outliers.csv' so that it can be retrieved later." + +if st.checkbox('Generate CSV with results'): + metaprompt += download_ph + +# Define the user query/prompt +query = st.text_input("Enter your query here:", "Are there any outliers?") + +if st.button('Check Blob connection'): + try: + connection_string = blob_connection_string + blob_service_client = BlobServiceClient.from_connection_string(connection_string) + container_name = st.text_input('Your container name', 'anomalies') + container_client = blob_service_client.get_container_client(container_name) + st.markdown(''':green-background[Connection to Blob Storage successful.]''') + # Ensure the container exists + if not container_client.exists(): + container_client.create_container() + st.write(f"Container '{container_name}' created successfully.") + except Exception as e: + st.error(f"An error occurred while checking the Blob connection: {e}") + +# Create a file input for the user to upload a CSV +uploaded_file = st.file_uploader( + "Upload a CSV", type="csv", label_visibility="collapsed" +) + +# If the user has uploaded a file, start the assistant process... +if metaprompt and query and uploaded_file is not None: + # Check if a new file has been uploaded + if st.session_state['uploaded_file_name'] != uploaded_file.name: + # Reset the session state because a new file has been uploaded + st.session_state['uploaded_file_name'] = uploaded_file.name + st.session_state['assistant_run_complete'] = False + st.session_state['run'] = None + st.session_state['thread'] = None + st.session_state['messages'] = None + st.session_state['file_ids'] = None + st.session_state['assistant_file_id'] = None + st.session_state['content'] = None + + if not st.session_state['assistant_run_complete']: + # Create a status indicator to show the user the assistant is working + placeholder = st.empty() # Use a placeholder + with placeholder.container(): + status_box = st.info("Starting work...") + + try: + # Upload the file to OpenAI + file = client.files.create( + file=uploaded_file, purpose="assistants" + ) + st.session_state['assistant_file_id'] = file.id + + assistant = client.beta.assistants.create( + model="gpt-4o", # Replace with your model deployment name. + instructions=metaprompt, + tools=[{"type": "code_interpreter"}], + tool_resources={"code_interpreter": {"file_ids": [file.id]}}, + temperature=1, + top_p=1 + ) + thread = client.beta.threads.create() + st.session_state['thread'] = thread + + # Add a user question to the thread + message = client.beta.threads.messages.create( + thread_id=thread.id, + role="user", + content=query # Replace this with your prompt + ) + + # Create a run with the new thread + run = client.beta.threads.runs.create( + thread_id=thread.id, + assistant_id=assistant.id, + ) + st.session_state['run'] = run + + # Check periodically whether the run is done, and update the status + while run.status != "completed": + time.sleep(5) + status_box.info(f"{run.status.title()}...") + run = client.beta.threads.runs.retrieve( + thread_id=thread.id, run_id=run.id + ) + + # Once the run is complete, update the status box and show the content + status_box.success("Complete") + placeholder.empty() # Remove the placeholder to avoid nesting + + messages = client.beta.threads.messages.list( + thread_id=thread.id + ) + st.session_state['messages'] = messages.data + + # Display the assistant's final response + display_assistant_response(st.session_state['messages']) + + st.session_state['assistant_run_complete'] = True + + # Retrieve generated files + file_ids = [] + + for message in messages.data: + # Check if the message has attachments + if hasattr(message, 'attachments') and message.attachments: + for attachment in message.attachments: + # Check if the attachment has a 'file_id' attribute + if hasattr(attachment, 'file_id'): + file_ids.append(attachment.file_id) + st.session_state['file_ids'] = file_ids + + # Provide the download and export buttons + if file_ids: + # Read the content of the file into memory + content = client.files.content(file_ids[0]).read() + st.session_state['content'] = content + + provide_download_and_export(content) + else: + st.write("No files generated by the assistant.") + + except Exception as e: + st.error(f"An error occurred: {e}") + st.stop() + else: + # Assistant has already run, display the results from session state + display_assistant_response(st.session_state['messages']) + provide_download_and_export(st.session_state['content']) + + # "Show code" button and expander + if st.button('Show Thinking Steps'): + with st.expander("Thinking Steps"): + if st.session_state['run'] is not None and st.session_state['thread'] is not None: + try: + run_steps = client.beta.threads.runs.steps.list( + thread_id=st.session_state['thread'].id, + run_id=st.session_state['run'].id # Use the correct run_id here + ) + + for idx, step in enumerate(reversed(run_steps.data)): + st.write(f"**Step {idx+1}:**") + step_type = step.step_details.type + + # Handle message creation steps + if step_type == 'message_creation': + message_id = step.step_details.message_creation.message_id + # Retrieve the message content + message = client.beta.threads.messages.retrieve( + thread_id=st.session_state['thread'].id, + message_id=message_id + ) + if message.content: + for content_piece in message.content: + if hasattr(content_piece, 'text'): + st.markdown(content_piece.text.value) + elif step_type == 'tool_calls': + tool_calls = step.step_details.tool_calls + for tool_call in tool_calls: + code = tool_call.code_interpreter.input + st.code(code, language="python") + # Display any error messages + if hasattr(tool_call.code_interpreter, 'error'): + error_message = tool_call.code_interpreter.error.message + st.write(f"Code Interpreter Error: {error_message}") + else: + st.write(f"Unknown step type: {step_type}") + except Exception as e: + st.error(f"An error occurred while retrieving thinking steps: {e}") + else: + st.write("No run data available.") + + # Optionally, add a reset button to allow the user to start over + if st.button('Reset'): + # Clean up files + if st.session_state['assistant_file_id'] is not None: + try: + client.files.delete(st.session_state['assistant_file_id']) + except Exception as e: + st.error(f"Error deleting assistant file: {e}") + if st.session_state['file_ids'] is not None: + for file_id in st.session_state['file_ids']: + try: + client.files.delete(file_id) + except Exception as e: + st.error(f"Error deleting file {file_id}: {e}") + # Reset session state + st.session_state['assistant_run_complete'] = False + st.session_state['run'] = None + st.session_state['thread'] = None + st.session_state['messages'] = None + st.session_state['file_ids'] = None + st.session_state['assistant_file_id'] = None + st.session_state['content'] = None + st.session_state['uploaded_file_name'] = None + st.experimental_rerun() +else: + st.write("Please upload a CSV file to start.") \ No newline at end of file diff --git a/scenarios/Assistants/code-interptreter/assets/ezgif-5-697c67b237.gif b/scenarios/Assistants/code-interptreter/assets/ezgif-5-697c67b237.gif new file mode 100644 index 00000000..58ebcef7 Binary files /dev/null and b/scenarios/Assistants/code-interptreter/assets/ezgif-5-697c67b237.gif differ diff --git a/scenarios/Assistants/code-interptreter/notebook.ipynb b/scenarios/Assistants/code-interptreter/notebook.ipynb new file mode 100644 index 00000000..607540fe --- /dev/null +++ b/scenarios/Assistants/code-interptreter/notebook.ipynb @@ -0,0 +1,1029 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Assistant APIs with Code Interpreter for Audit" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import json\n", + "import requests\n", + "import time\n", + "from openai import AzureOpenAI\n", + "from dotenv import load_dotenv\n", + "\n", + "load_dotenv() \n", + "\n", + "client = AzureOpenAI(\n", + " azure_endpoint = os.getenv(\"AZURE_OPENAI_ENDPOINT\"),\n", + " api_key= os.getenv(\"AZURE_OPENAI_API_KEY\"),\n", + " api_version=\"2024-05-01-preview\"\n", + ")\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "FileObject(id='assistant-XMHdmyW3OM60Mi43qhKZUX58', bytes=1783, created_at=1730451786, filename='data.csv', object='file', purpose='assistants', status='processed', status_details=None)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "file = client.files.create(file=open(\"data.csv\", \"rb\"), purpose=\"assistants\")\n", + "file" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'assistant-XMHdmyW3OM60Mi43qhKZUX58'" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "file.id" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "assistant = client.beta.assistants.retrieve(test.id)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "thread = client.beta.threads.create(\n", + " messages=[\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"are there any outliers?\",\n", + " \"attachments\": [\n", + " {\n", + " \"file_id\": file.id,\n", + " \"tools\": [{\"type\": \"code_interpreter\"}]\n", + " }\n", + " ]\n", + " }\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "If you need any further analysis or assistance, please let me know!\n" + ] + } + ], + "source": [ + "# Run the thread\n", + "run = client.beta.threads.runs.create(\n", + " thread_id=thread.id,\n", + " assistant_id=assistant.id\n", + ")\n", + "\n", + "# Looping until the run completes or fails\n", + "while run.status in ['queued', 'in_progress', 'cancelling']:\n", + " time.sleep(1)\n", + " run = client.beta.threads.runs.retrieve(\n", + " thread_id=thread.id,\n", + " run_id=run.id\n", + " )\n", + "\n", + "if run.status == 'completed':\n", + " messages = client.beta.threads.messages.list(\n", + " thread_id=thread.id\n", + " )\n", + " print(messages.data[0].content[0].text.value)\n", + "elif run.status == 'requires_action':\n", + " # the assistant requires calling some functions\n", + " # and submit the tool outputs back to the run\n", + " pass\n", + "else:\n", + " print(run.status)\n", + "\n", + "\n", + "run_steps = client.beta.threads.runs.steps.list(\n", + " thread_id=thread.id,\n", + " run_id=run.id\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [], + "source": [ + "metaprompt = \"\"\"\"\n", + "You are a Risk Detector assistant. You are specialized in running code against provided files to identify anomalies and outliers.\n", + "\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [], + "source": [ + "assistant = client.beta.assistants.create(\n", + " model=\"gpt-4o\", # replace with model deployment name.\n", + " instructions= metaprompt,\n", + " tools=[{\"type\":\"code_interpreter\"}],\n", + " tool_resources={\"code_interpreter\":{\"file_ids\":[file.id]}},\n", + " temperature=1,\n", + " top_p=1\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The following outliers were identified in the dataset:\n", + "\n", + "**Revenue (USD):**\n", + "```\n", + " ID Company Revenue (USD) Expenses (USD) Profit (USD)\n", + " 5 6 Zeta Corp 1500000.0 1200000.0 300000.0\n", + " 17 18 Sigma Corp 1800000.0 1500000.0 300000.0\n", + " 24 25 Alpha2 Corp 2500000.0 2000000.0 500000.0\n", + " 29 30 Zeta2 Corp 1200000.0 1000000.0 200000.0\n", + " 33 34 Kappa2 Corp 2200000.0 1700000.0 500000.0\n", + " 39 40 Pi2 Ltd. 3000000.0 2500000.0 500000.0\n", + "```\n", + "\n", + "**Expenses (USD):**\n", + "```\n", + " ID Company Revenue (USD) Expenses (USD) Profit (USD)\n", + " 5 6 Zeta Corp 1500000.0 1200000.0 300000.0\n", + " 17 18 Sigma Corp 1800000.0 1500000.0 300000.0\n", + " 24 25 Alpha2 Corp 2500000.0 2000000.0 500000.0\n", + " 29 30 Zeta2 Corp 1200000.0 1000000.0 200000.0\n", + " 33 34 Kappa2 Corp 2200000.0 1700000.0 500000.0\n", + " 39 40 Pi2 Ltd. 3000000.0 2500000.0 500000.0\n", + "```\n", + "\n", + "**Profit (USD):**\n", + "```\n", + " ID Company Revenue (USD) Expenses (USD) Profit (USD)\n", + " 5 6 Zeta Corp 1500000.0 1200000.0 300000.0\n", + " 17 18 Sigma Corp 1800000.0 1500000.0 300000.0\n", + " 24 25 Alpha2 Corp 2500000.0 2000000.0 500000.0\n", + " 33 34 Kappa2 Corp 2200000.0 1700000.0 500000.0\n", + " 39 40 Pi2 Ltd. 3000000.0 2500000.0 500000.0\n", + "```\n", + "\n", + "These rows represent potential outliers based on the Interquartile Range (IQR) method. Let me know if you need further analysis or visualization of these outliers.\n" + ] + } + ], + "source": [ + "# Create a thread\n", + "thread = client.beta.threads.create()\n", + "\n", + "# Add a user question to the thread\n", + "message = client.beta.threads.messages.create(\n", + " thread_id=thread.id,\n", + " role=\"user\",\n", + " content=\"are there any outliers?\" # Replace this with your prompt\n", + ")\n", + "\n", + "\n", + "# Run the thread\n", + "run = client.beta.threads.runs.create(\n", + " thread_id=thread.id,\n", + " assistant_id=assistant.id\n", + ")\n", + "\n", + "# Looping until the run completes or fails\n", + "while run.status in ['queued', 'in_progress', 'cancelling']:\n", + " time.sleep(1)\n", + " run = client.beta.threads.runs.retrieve(\n", + " thread_id=thread.id,\n", + " run_id=run.id\n", + " )\n", + "\n", + "if run.status == 'completed':\n", + " messages = client.beta.threads.messages.list(\n", + " thread_id=thread.id\n", + " )\n", + " print(messages.data[0].content[0].text.value)\n", + "elif run.status == 'requires_action':\n", + " # the assistant requires calling some functions\n", + " # and submit the tool outputs back to the run\n", + " pass\n", + "else:\n", + " print(run.status)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Message(id='msg_g1NQSt3XqeeryqsqZAeYs1rd', assistant_id='asst_1HPxDrzB7v30dFSJaDmtUfEb', attachments=[], completed_at=None, content=[TextContentBlock(text=Text(annotations=[], value='If you need any further analysis or assistance, please let me know!'), type='text')], created_at=1730452584, incomplete_at=None, incomplete_details=None, metadata={}, object='thread.message', role='assistant', run_id='run_fOiFcSpaTOJG4cQjXdaEa7VV', status=None, thread_id='thread_N7BqNs8oZDlCfxUOIxUsipDX'),\n", + " Message(id='msg_ZXSFV2Wl8ZNqXPwBb2ZU6mVr', assistant_id='asst_1HPxDrzB7v30dFSJaDmtUfEb', attachments=[Attachment(file_id='assistant-CbpQ0Ff0zDuHYwhYrmzouMyA', tools=[CodeInterpreterTool(type='code_interpreter')])], completed_at=None, content=[TextContentBlock(text=Text(annotations=[FilePathAnnotation(end_index=137, file_path=FilePath(file_id='assistant-CbpQ0Ff0zDuHYwhYrmzouMyA'), start_index=107, text='sandbox:/mnt/data/outliers.csv', type='file_path')], value='The table with outliers has been saved. You can download it using the link below:\\n\\n[Download outliers.csv](sandbox:/mnt/data/outliers.csv)'), type='text')], created_at=1730452395, incomplete_at=None, incomplete_details=None, metadata={}, object='thread.message', role='assistant', run_id='run_oJmF08gCCQAYdA8tvVUis3PU', status=None, thread_id='thread_N7BqNs8oZDlCfxUOIxUsipDX'),\n", + " Message(id='msg_xruJAOOOqkO2vaDgnaB1cYlr', assistant_id='asst_1HPxDrzB7v30dFSJaDmtUfEb', attachments=[], completed_at=None, content=[TextContentBlock(text=Text(annotations=[], value='The following rows have been identified as outliers:\\n \\n ID | Company | Revenue (USD) | Expenses (USD) | Profit (USD)\\n ---|--------------|---------------|----------------|--------------\\n 6 | Zeta Corp | 1500000.0| 1200000.0| 300000.0\\n 18 | Sigma Corp | 1800000.0| 1500000.0| 300000.0\\n 25 | Alpha2 Corp | 2500000.0| 2000000.0| 500000.0\\n 30 | Zeta2 Corp | 1200000.0| 1000000.0| 200000.0\\n 34 | Kappa2 Corp | 2200000.0| 1700000.0| 500000.0\\n 40 | Pi2 Ltd. | 3000000.0| 2500000.0| 500000.0\\n\\nI will now save this table with the outliers as a CSV file.'), type='text')], created_at=1730452391, incomplete_at=None, incomplete_details=None, metadata={}, object='thread.message', role='assistant', run_id='run_oJmF08gCCQAYdA8tvVUis3PU', status=None, thread_id='thread_N7BqNs8oZDlCfxUOIxUsipDX'),\n", + " Message(id='msg_wRjm4Jog87utYvJUZKA3fWbx', assistant_id='asst_1HPxDrzB7v30dFSJaDmtUfEb', attachments=[], completed_at=None, content=[TextContentBlock(text=Text(annotations=[], value=\"The dataset contains the following columns: `ID`, `Company`, `Revenue (USD)`, `Expenses (USD)`, and `Profit (USD)`.\\n\\nTo identify outliers, we need to analyze the relevant columns for numerical anomalies. Let's start by removing any non-numerical columns and converting the numerical values to the appropriate data type. Then, we will use statistical methods to identify potential outliers.\"), type='text')], created_at=1730452386, incomplete_at=None, incomplete_details=None, metadata={}, object='thread.message', role='assistant', run_id='run_oJmF08gCCQAYdA8tvVUis3PU', status=None, thread_id='thread_N7BqNs8oZDlCfxUOIxUsipDX'),\n", + " Message(id='msg_wHJgjGKIslPLeFd0UScuXwF5', assistant_id=None, attachments=[Attachment(file_id='assistant-XMHdmyW3OM60Mi43qhKZUX58', tools=[CodeInterpreterTool(type='code_interpreter')])], completed_at=None, content=[TextContentBlock(text=Text(annotations=[], value='are there any outliers?'), type='text')], created_at=1730452376, incomplete_at=None, incomplete_details=None, metadata={}, object='thread.message', role='user', run_id=None, status=None, thread_id='thread_N7BqNs8oZDlCfxUOIxUsipDX')]" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "messages.data" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Extracted file IDs: ['assistant-CbpQ0Ff0zDuHYwhYrmzouMyA', 'assistant-XMHdmyW3OM60Mi43qhKZUX58']\n" + ] + } + ], + "source": [ + "# Assuming 'messages_page' is your SyncCursorPage[Message] object\n", + "file_ids = []\n", + "\n", + "for message in messages.data:\n", + " # Check if the message has attachments\n", + " if hasattr(message, 'attachments') and message.attachments:\n", + " for attachment in message.attachments:\n", + " # Check if the attachment has a 'file_id' attribute\n", + " if hasattr(attachment, 'file_id'):\n", + " file_ids.append(attachment.file_id)\n", + "\n", + "# Now 'file_ids' contains all the extracted file IDs\n", + "print(\"Extracted file IDs:\", file_ids)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['assistant-o6QzcwtUgZJm7aj8NWXsdwVD']\n" + ] + } + ], + "source": [ + "def get_file_ids_from_thread(client, thread_id):\n", + " \"\"\"\n", + " Extracts file_ids from the attachments of messages in a thread, if attachments are not empty.\n", + "\n", + " :param client: The client object used to interact with the API.\n", + " :param thread_id: The ID of the thread to extract messages from.\n", + " :return: A list of file_ids extracted from the attachments of the messages.\n", + " \"\"\"\n", + " # Get the list of messages from the thread\n", + " messages = [i for i in client.beta.threads.messages.list(thread_id=thread_id)]\n", + "\n", + " # Extract file_ids from each message's attachments if attachments are not empty\n", + " file_ids = [\n", + " attachment.file_id\n", + " for message in messages\n", + " if message.attachments\n", + " for attachment in message.attachments\n", + " ]\n", + " \n", + " return file_ids\n", + "\n", + "# Example usage\n", + "file_ids = get_file_ids_from_thread(client, thread_id='thread_12yh3C890jvQYzTsutTUc4rh')\n", + "print(file_ids) # Output will be a list of file_ids from all messages with attachments\n" + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "b'ID,Company,Revenue (USD),Expenses (USD),Profit (USD)\\n6,Zeta Corp,1500000.0,1200000.0,300000.0\\n18,Sigma Corp,1800000.0,1500000.0,300000.0\\n25,Alpha2 Corp,2500000.0,2000000.0,500000.0\\n30,Zeta2 Corp,1200000.0,1000000.0,200000.0\\n34,Kappa2 Corp,2200000.0,1700000.0,500000.0\\n40,Pi2 Ltd.,3000000.0,2500000.0,500000.0\\n'" + ] + }, + "execution_count": 99, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "content = client.files.content(file_ids[0]).read()\n", + "content" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "def write_file_to_temp_dir(file_id, output_path):\n", + " file_data = client.files.content(file_id)\n", + " file_data_bytes = file_data.read()\n", + " with open(output_path, \"wb\") as file:\n", + " file.write(file_data_bytes)\n", + "\n", + "\n", + "some_file_id = file_ids[0]\n", + "write_file_to_temp_dir(some_file_id, 'outliers.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [], + "source": [ + "run_steps = client.beta.threads.runs.steps.list(\n", + " thread_id=thread.id,\n", + " run_id=run.id\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[RunStep(id='step_tKIWsukUzBEa2oWwwQLxxZ8s', assistant_id='asst_0dhgPrqdSNNMCsFvo7Lcsgoz', cancelled_at=None, completed_at=1730474285, created_at=1730474279, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_krLX6OpCIwXPjaYDxGS3Y9UT', status='completed', step_details=MessageCreationStepDetails(message_creation=MessageCreation(message_id='msg_YdICRQ1LOgbUY5noT0oNpnA7'), type='message_creation'), thread_id='thread_rIRMFkyfW45t0fensuFDSgaB', type='message_creation', usage=Usage(completion_tokens=648, prompt_tokens=1867, total_tokens=2515), expires_at=None),\n", + " RunStep(id='step_InhMJNvdmbaEZx4o0Y23ncdI', assistant_id='asst_0dhgPrqdSNNMCsFvo7Lcsgoz', cancelled_at=None, completed_at=1730474279, created_at=1730474276, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_krLX6OpCIwXPjaYDxGS3Y9UT', status='completed', step_details=ToolCallsStepDetails(tool_calls=[CodeInterpreterToolCall(id='call_bSLd6cL6PT9r8gZ1JrSKG41O', code_interpreter=CodeInterpreter(input=\"def identify_outliers(data, column):\\n # Calculate Q1 (25th percentile) and Q3 (75th percentile)\\n Q1 = data[column].quantile(0.25)\\n Q3 = data[column].quantile(0.75)\\n IQR = Q3 - Q1\\n \\n # Calculate the lower and upper bounds\\n lower_bound = Q1 - 1.5 * IQR\\n upper_bound = Q3 + 1.5 * IQR\\n \\n # Identify outliers\\n outliers = data[(data[column] < lower_bound) | (data[column] > upper_bound)]\\n return outliers\\n\\n# Identify outliers in 'Revenue (USD)', 'Expenses (USD)', and 'Profit (USD)'\\noutliers_revenue = identify_outliers(data, 'Revenue (USD)')\\noutliers_expenses = identify_outliers(data, 'Expenses (USD)')\\noutliers_profit = identify_outliers(data, 'Profit (USD)')\\n\\noutliers_revenue, outliers_expenses, outliers_profit\", outputs=[]), type='code_interpreter')], type='tool_calls'), thread_id='thread_rIRMFkyfW45t0fensuFDSgaB', type='tool_calls', usage=Usage(completion_tokens=221, prompt_tokens=0, total_tokens=221), expires_at=None),\n", + " RunStep(id='step_nBIQFKIW4WSxD9fZMsi06C4i', assistant_id='asst_0dhgPrqdSNNMCsFvo7Lcsgoz', cancelled_at=None, completed_at=1730474276, created_at=1730474275, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_krLX6OpCIwXPjaYDxGS3Y9UT', status='completed', step_details=MessageCreationStepDetails(message_creation=MessageCreation(message_id='msg_pB0lpRWgjM9f1NAWgPXU8WIq'), type='message_creation'), thread_id='thread_rIRMFkyfW45t0fensuFDSgaB', type='message_creation', usage=Usage(completion_tokens=70, prompt_tokens=0, total_tokens=70), expires_at=None),\n", + " RunStep(id='step_avoNUErMfr1RPYRMGnWPcjl5', assistant_id='asst_0dhgPrqdSNNMCsFvo7Lcsgoz', cancelled_at=None, completed_at=1730474275, created_at=1730474274, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_krLX6OpCIwXPjaYDxGS3Y9UT', status='completed', step_details=ToolCallsStepDetails(tool_calls=[CodeInterpreterToolCall(id='call_gveDZUzuYNnTSbIPx6eYuQMY', code_interpreter=CodeInterpreter(input=\"# Remove commas and convert columns to numeric types\\ndata['Revenue (USD)'] = data['Revenue (USD)'].str.replace(',', '').astype(float)\\ndata['Expenses (USD)'] = data['Expenses (USD)'].str.replace(',', '').astype(float)\\ndata['Profit (USD)'] = data['Profit (USD)'].str.replace(',', '').astype(float)\\n\\n# Display the first few rows to confirm the conversion\\ndata.head()\", outputs=[]), type='code_interpreter')], type='tool_calls'), thread_id='thread_rIRMFkyfW45t0fensuFDSgaB', type='tool_calls', usage=Usage(completion_tokens=96, prompt_tokens=0, total_tokens=96), expires_at=None),\n", + " RunStep(id='step_F1ZHNlIMtyZJpuc32QOLX1vz', assistant_id='asst_0dhgPrqdSNNMCsFvo7Lcsgoz', cancelled_at=None, completed_at=1730474274, created_at=1730474273, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_krLX6OpCIwXPjaYDxGS3Y9UT', status='completed', step_details=MessageCreationStepDetails(message_creation=MessageCreation(message_id='msg_qbLNtjo9IkZ6TwZeh5Jfa3J5'), type='message_creation'), thread_id='thread_rIRMFkyfW45t0fensuFDSgaB', type='message_creation', usage=Usage(completion_tokens=119, prompt_tokens=0, total_tokens=119), expires_at=None),\n", + " RunStep(id='step_hDfZRSv8hDcADJOZKWCNEmgo', assistant_id='asst_0dhgPrqdSNNMCsFvo7Lcsgoz', cancelled_at=None, completed_at=1730474273, created_at=1730474268, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_krLX6OpCIwXPjaYDxGS3Y9UT', status='completed', step_details=ToolCallsStepDetails(tool_calls=[CodeInterpreterToolCall(id='call_IysG1VuKf2IG2IZ9eNjkT5hg', code_interpreter=CodeInterpreter(input=\"import pandas as pd\\n\\n# Load the data from the uploaded file\\nfile_path = '/mnt/data/assistant-XMHdmyW3OM60Mi43qhKZUX58'\\ndata = pd.read_csv(file_path)\\n\\n# Display the first few rows and basic information about the data\\ndata_info = data.info()\\ndata_head = data.head()\\n\\ndata_info, data_head\", outputs=[CodeInterpreterOutputLogs(logs=\"\\nRangeIndex: 40 entries, 0 to 39\\nData columns (total 5 columns):\\n # Column Non-Null Count Dtype \\n--- ------ -------------- ----- \\n 0 ID 40 non-null int64 \\n 1 Company 40 non-null object\\n 2 Revenue (USD) 40 non-null object\\n 3 Expenses (USD) 40 non-null object\\n 4 Profit (USD) 40 non-null object\\ndtypes: int64(1), object(4)\\nmemory usage: 1.7+ KB\\n\", type='logs')]), type='code_interpreter')], type='tool_calls'), thread_id='thread_rIRMFkyfW45t0fensuFDSgaB', type='tool_calls', usage=Usage(completion_tokens=82, prompt_tokens=0, total_tokens=82), expires_at=None),\n", + " RunStep(id='step_hsJX5SgKmaqpsUoLadFYXw1S', assistant_id='asst_0dhgPrqdSNNMCsFvo7Lcsgoz', cancelled_at=None, completed_at=1730474268, created_at=1730474267, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_krLX6OpCIwXPjaYDxGS3Y9UT', status='completed', step_details=MessageCreationStepDetails(message_creation=MessageCreation(message_id='msg_tSaOeKsNMKjOOljDvWEoetzT'), type='message_creation'), thread_id='thread_rIRMFkyfW45t0fensuFDSgaB', type='message_creation', usage=Usage(completion_tokens=34, prompt_tokens=0, total_tokens=34), expires_at=None)]" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "run_steps.data" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "# Remove commas and convert columns to numeric types\n", + "data['Revenue (USD)'] = data['Revenue (USD)'].str.replace(',', '').astype(float)\n", + "data['Expenses (USD)'] = data['Expenses (USD)'].str.replace(',', '').astype(float)\n", + "data['Profit (USD)'] = data['Profit (USD)'].str.replace(',', '').astype(float)\n", + "\n", + "# Display the first few rows to confirm the conversion\n", + "data.head()\n" + ] + } + ], + "source": [ + "for i in run_steps.data[3].step_details.tool_calls:\n", + " print(i.code_interpreter.input)" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "message_creation\n", + "tool_calls\n", + "message_creation\n", + "tool_calls\n", + "message_creation\n", + "tool_calls\n", + "message_creation\n" + ] + } + ], + "source": [ + "for idx, step in enumerate(reversed(run_steps.data)):\n", + " print(step.step_details.type)" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "**Step 1:**\n", + "To identify any outliers in the provided file, I will first need to load the data and inspect its contents. Let's read the file and take a look.\n", + "**Step 2:**\n", + "import pandas as pd\n", + "\n", + "# Load the data from the uploaded file\n", + "file_path = '/mnt/data/assistant-XMHdmyW3OM60Mi43qhKZUX58'\n", + "data = pd.read_csv(file_path)\n", + "\n", + "# Display the first few rows and basic information about the data\n", + "data_info = data.info()\n", + "data_head = data.head()\n", + "\n", + "data_info, data_head\n", + "**Step 3:**\n", + "The dataset contains 40 entries with the following columns: 'ID', 'Company', 'Revenue (USD)', 'Expenses (USD)', and 'Profit (USD)'. It appears that the columns 'Revenue (USD)', 'Expenses (USD)', and 'Profit (USD)' are stored as object (string) types because they contain commas as thousand separators.\n", + "\n", + "To identify outliers, I will first need to convert these columns to numeric types. I'll remove the commas and convert the columns to numeric data types, then I will proceed with detecting any outliers.\n", + "\n", + "Let's perform these steps now.\n", + "**Step 4:**\n", + "# Remove commas and convert columns to numeric types\n", + "data['Revenue (USD)'] = data['Revenue (USD)'].str.replace(',', '').astype(float)\n", + "data['Expenses (USD)'] = data['Expenses (USD)'].str.replace(',', '').astype(float)\n", + "data['Profit (USD)'] = data['Profit (USD)'].str.replace(',', '').astype(float)\n", + "\n", + "# Display the first few rows to confirm the conversion\n", + "data.head()\n", + "**Step 5:**\n", + "The columns 'Revenue (USD)', 'Expenses (USD)', and 'Profit (USD)' have been successfully converted to numeric types. Now, let's identify any outliers in these columns using statistical methods such as the Interquartile Range (IQR).\n", + "\n", + "I will calculate the IQR and determine the outliers in each of the three columns.\n", + "**Step 6:**\n", + "def identify_outliers(data, column):\n", + " # Calculate Q1 (25th percentile) and Q3 (75th percentile)\n", + " Q1 = data[column].quantile(0.25)\n", + " Q3 = data[column].quantile(0.75)\n", + " IQR = Q3 - Q1\n", + " \n", + " # Calculate the lower and upper bounds\n", + " lower_bound = Q1 - 1.5 * IQR\n", + " upper_bound = Q3 + 1.5 * IQR\n", + " \n", + " # Identify outliers\n", + " outliers = data[(data[column] < lower_bound) | (data[column] > upper_bound)]\n", + " return outliers\n", + "\n", + "# Identify outliers in 'Revenue (USD)', 'Expenses (USD)', and 'Profit (USD)'\n", + "outliers_revenue = identify_outliers(data, 'Revenue (USD)')\n", + "outliers_expenses = identify_outliers(data, 'Expenses (USD)')\n", + "outliers_profit = identify_outliers(data, 'Profit (USD)')\n", + "\n", + "outliers_revenue, outliers_expenses, outliers_profit\n", + "**Step 7:**\n", + "The following outliers were identified in the dataset:\n", + "\n", + "**Revenue (USD):**\n", + "```\n", + " ID Company Revenue (USD) Expenses (USD) Profit (USD)\n", + " 5 6 Zeta Corp 1500000.0 1200000.0 300000.0\n", + " 17 18 Sigma Corp 1800000.0 1500000.0 300000.0\n", + " 24 25 Alpha2 Corp 2500000.0 2000000.0 500000.0\n", + " 29 30 Zeta2 Corp 1200000.0 1000000.0 200000.0\n", + " 33 34 Kappa2 Corp 2200000.0 1700000.0 500000.0\n", + " 39 40 Pi2 Ltd. 3000000.0 2500000.0 500000.0\n", + "```\n", + "\n", + "**Expenses (USD):**\n", + "```\n", + " ID Company Revenue (USD) Expenses (USD) Profit (USD)\n", + " 5 6 Zeta Corp 1500000.0 1200000.0 300000.0\n", + " 17 18 Sigma Corp 1800000.0 1500000.0 300000.0\n", + " 24 25 Alpha2 Corp 2500000.0 2000000.0 500000.0\n", + " 29 30 Zeta2 Corp 1200000.0 1000000.0 200000.0\n", + " 33 34 Kappa2 Corp 2200000.0 1700000.0 500000.0\n", + " 39 40 Pi2 Ltd. 3000000.0 2500000.0 500000.0\n", + "```\n", + "\n", + "**Profit (USD):**\n", + "```\n", + " ID Company Revenue (USD) Expenses (USD) Profit (USD)\n", + " 5 6 Zeta Corp 1500000.0 1200000.0 300000.0\n", + " 17 18 Sigma Corp 1800000.0 1500000.0 300000.0\n", + " 24 25 Alpha2 Corp 2500000.0 2000000.0 500000.0\n", + " 33 34 Kappa2 Corp 2200000.0 1700000.0 500000.0\n", + " 39 40 Pi2 Ltd. 3000000.0 2500000.0 500000.0\n", + "```\n", + "\n", + "These rows represent potential outliers based on the Interquartile Range (IQR) method. Let me know if you need further analysis or visualization of these outliers.\n" + ] + } + ], + "source": [ + "for idx, step in enumerate(reversed(run_steps.data)):\n", + " print(f\"**Step {idx+1}:**\")\n", + " step_type = step.step_details.type\n", + "\n", + " # Handle message creation steps\n", + " if step_type == 'message_creation':\n", + " message_id = step.step_details.message_creation.message_id\n", + " # Retrieve the message content\n", + " message = client.beta.threads.messages.retrieve(\n", + " thread_id=thread.id,\n", + " message_id=message_id\n", + " )\n", + " if message.content:\n", + " for content_piece in message.content:\n", + " if hasattr(content_piece, 'text'):\n", + " print(content_piece.text.value)\n", + " elif step_type == 'tool_calls':\n", + " tool_calls = step.step_details.tool_calls\n", + " for tool_call in tool_calls:\n", + " code = tool_call.code_interpreter.input\n", + " print(code)\n", + " # Display any error messages\n", + " if hasattr(tool_call.code_interpreter, 'error'):\n", + " error_message = tool_call.code_interpreter.error.message\n", + " print(f\"Code Interpreter Error: {error_message}\")\n", + " else:\n", + " print(f\"Unknown step type: {step_type}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "def identify_outliers(data, column):\n", + " # Calculate Q1 (25th percentile) and Q3 (75th percentile)\n", + " Q1 = data[column].quantile(0.25)\n", + " Q3 = data[column].quantile(0.75)\n", + " IQR = Q3 - Q1\n", + " \n", + " # Calculate the lower and upper bounds\n", + " lower_bound = Q1 - 1.5 * IQR\n", + " upper_bound = Q3 + 1.5 * IQR\n", + " \n", + " # Identify outliers\n", + " outliers = data[(data[column] < lower_bound) | (data[column] > upper_bound)]\n", + " return outliers\n", + "\n", + "# Identify outliers in 'Revenue (USD)', 'Expenses (USD)', and 'Profit (USD)'\n", + "outliers_revenue = identify_outliers(data, 'Revenue (USD)')\n", + "outliers_expenses = identify_outliers(data, 'Expenses (USD)')\n", + "outliers_profit = identify_outliers(data, 'Profit (USD)')\n", + "\n", + "outliers_revenue, outliers_expenses, outliers_profit\n" + ] + } + ], + "source": [ + "print(run_steps.data[1].step_details.tool_calls[0].code_interpreter.input)" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: azure-storage-blob in c:\\users\\vaalt\\appdata\\local\\anaconda3\\lib\\site-packages (12.23.1)\n", + "Requirement already satisfied: azure-core>=1.30.0 in c:\\users\\vaalt\\appdata\\local\\anaconda3\\lib\\site-packages (from azure-storage-blob) (1.31.0)\n", + "Requirement already satisfied: cryptography>=2.1.4 in c:\\users\\vaalt\\appdata\\local\\anaconda3\\lib\\site-packages (from azure-storage-blob) (43.0.1)\n", + "Requirement already satisfied: typing-extensions>=4.6.0 in c:\\users\\vaalt\\appdata\\local\\anaconda3\\lib\\site-packages (from azure-storage-blob) (4.11.0)\n", + "Requirement already satisfied: isodate>=0.6.1 in c:\\users\\vaalt\\appdata\\local\\anaconda3\\lib\\site-packages (from azure-storage-blob) (0.6.1)\n", + "Requirement already satisfied: requests>=2.21.0 in c:\\users\\vaalt\\appdata\\local\\anaconda3\\lib\\site-packages (from azure-core>=1.30.0->azure-storage-blob) (2.32.2)\n", + "Requirement already satisfied: six>=1.11.0 in c:\\users\\vaalt\\appdata\\local\\anaconda3\\lib\\site-packages (from azure-core>=1.30.0->azure-storage-blob) (1.16.0)\n", + "Requirement already satisfied: cffi>=1.12 in c:\\users\\vaalt\\appdata\\local\\anaconda3\\lib\\site-packages (from cryptography>=2.1.4->azure-storage-blob) (1.16.0)\n", + "Requirement already satisfied: pycparser in c:\\users\\vaalt\\appdata\\local\\anaconda3\\lib\\site-packages (from cffi>=1.12->cryptography>=2.1.4->azure-storage-blob) (2.21)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\vaalt\\appdata\\local\\anaconda3\\lib\\site-packages (from requests>=2.21.0->azure-core>=1.30.0->azure-storage-blob) (2.0.4)\n", + "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\vaalt\\appdata\\local\\anaconda3\\lib\\site-packages (from requests>=2.21.0->azure-core>=1.30.0->azure-storage-blob) (3.7)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\vaalt\\appdata\\local\\anaconda3\\lib\\site-packages (from requests>=2.21.0->azure-core>=1.30.0->azure-storage-blob) (2.2.2)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\vaalt\\appdata\\local\\anaconda3\\lib\\site-packages (from requests>=2.21.0->azure-core>=1.30.0->azure-storage-blob) (2024.8.30)\n" + ] + } + ], + "source": [ + "! pip install azure-storage-blob" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": {}, + "outputs": [], + "source": [ + "from azure.storage.blob import BlobServiceClient, BlobClient, ContainerClient\n", + "\n", + "\n", + "connect_str = os.getenv('AZURE_STORAGE_CONNECTION_STRING')\n", + "\n", + "# Create the BlobServiceClient object\n", + "blob_service_client = BlobServiceClient.from_connection_string(connect_str)" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'etag': '\"0x8DCFB40B78F6D2E\"',\n", + " 'last_modified': datetime.datetime(2024, 11, 2, 13, 17, 35, tzinfo=datetime.timezone.utc),\n", + " 'content_md5': bytearray(b'\\xb3\\x18^\\xdc\\x93Q\\x9e\\xc6`\\x1a\\x89\\xebF\\xd1\\xa6\\xa3'),\n", + " 'client_request_id': 'd2dae111-991c-11ef-9181-010101010000',\n", + " 'request_id': '0fa4d28d-e01e-0059-5329-2d2bbe000000',\n", + " 'version': '2024-11-04',\n", + " 'version_id': None,\n", + " 'date': datetime.datetime(2024, 11, 2, 13, 17, 34, tzinfo=datetime.timezone.utc),\n", + " 'request_server_encrypted': True,\n", + " 'encryption_key_sha256': None,\n", + " 'encryption_scope': None}" + ] + }, + "execution_count": 100, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "blob_client = blob_service_client.get_blob_client(container='anomalies', blob='outliers.csv')\n", + "blob_client.upload_blob(content, overwrite=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": {}, + "outputs": [], + "source": [ + "blob_client = blob_service_client.get_blob_client(container='anomalies', blob='outliers.csv')\n", + "with open(file='outliers.csv', mode=\"rb\") as data:\n", + " blob_client.upload_blob(data, overwrite=True)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Testing bulk queries" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Result for query 1: I have identified the outliers in the dataset. Here are the rows that contain outliers:\n", + "\n", + "| ID | Company | Revenue (USD) | Expenses (USD) | Profit (USD) |\n", + "|----|-------------|---------------|----------------|--------------|\n", + "| 6 | Zeta Corp | 1,500,000 | 1,200,000 | 300,000 |\n", + "| 18 | Sigma Corp | 1,800,000 | 1,500,000 | 300,000 |\n", + "| 25 | Alpha2 Corp | 2,500,000 | 2,000,000 | 500,000 |\n", + "| 30 | Zeta2 Corp | 1,200,000 | 1,000,000 | 200,000 |\n", + "| 34 | Kappa2 Corp | 2,200,000 | 1,700,000 | 500,000 |\n", + "| 40 | Pi2 Ltd. | 3,000,000 | 2,500,000 | 500,000 |\n", + "\n", + "The file containing these outliers has been saved at: [outliers.csv](sandbox:/mnt/data/outliers.csv)\n", + "Result for query 2: Here is a summary of the data trends based on the calculated statistics:\n", + "\n", + "1. **Revenue (USD)**:\n", + " - Mean (average) revenue: $476,625\n", + " - Standard deviation (spread): $726,632.9\n", + " - Minimum revenue: $45,000\n", + " - Maximum revenue: $3,000,000\n", + " - The 25th percentile (Q1) is $88,750, the 50th percentile (median) is $145,000, and the 75th percentile (Q3) is $425,000.\n", + "\n", + "2. **Expenses (USD)**:\n", + " - Mean (average) expenses: $387,500\n", + " - Standard deviation (spread): $591,825.7\n", + " - Minimum expenses: $30,000\n", + " - Maximum expenses: $2,500,000\n", + " - The 25th percentile (Q1) is $70,000, the 50th percentile (median) is $115,000, and the 75th percentile (Q3) is $362,500.\n", + "\n", + "3. **Profit (USD)**:\n", + " - Mean (average) profit: $89,125\n", + " - Standard deviation (spread): $137,621.2\n", + " - Minimum profit: $5,000\n", + " - Maximum profit: $500,000\n", + " - The 25th percentile (Q1) is $18,750, the 50th percentile (median) is $30,000, and the 75th percentile (Q3) is $100,000.\n", + "\n", + "### Observations:\n", + "- The data shows that there is a significant variation in the revenue, expenses, and profit values among the companies.\n", + "- The revenue and expenses data have a wide range, with a few companies having very high revenue and expenses.\n", + "- The profit data also varies considerably, with the highest profit being $500,000.\n", + "\n", + "Next, we can visualize the data trends using plots to get a better understanding of the distributions and identify any potential outliers. Shall we proceed with that?\n", + "Result for query 3: I have detected the following outliers in the dataset:\n", + "\n", + "| ID | Company | Revenue (USD) | Expenses (USD) | Profit (USD) | Revenue_zscore | Expenses_zscore | Profit_zscore |\n", + "|----|-------------|---------------|----------------|--------------|----------------|-----------------|---------------|\n", + "| 25 | Alpha2 Corp | 2,500,000 | 2,000,000 | 500,000 | 2.820064 | 2.759330 | 3.023584 |\n", + "| 34 | Kappa2 Corp | 2,200,000 | 1,700,000 | 500,000 | 2.401941 | 2.245966 | 3.023584 |\n", + "| 40 | Pi2 Ltd. | 3,000,000 | 2,500,000 | 500,000 | 3.516936 | 3.614936 | 3.023584 |\n", + "\n", + "The file containing these outliers has been saved as [outliers.csv](sandbox:/mnt/data/outliers.csv).\n" + ] + } + ], + "source": [ + "import time\n", + "\n", + "def run_queries(queries, client, assistant_id):\n", + " results = []\n", + " \n", + " for query in queries:\n", + " # Create a thread for each query\n", + " thread = client.beta.threads.create()\n", + "\n", + " # Add the user query to the thread\n", + " message = client.beta.threads.messages.create(\n", + " thread_id=thread.id,\n", + " role=\"user\",\n", + " content=query # Use the current query from the list\n", + " )\n", + "\n", + " # Run the assistant with the query\n", + " run = client.beta.threads.runs.create(\n", + " thread_id=thread.id,\n", + " assistant_id=assistant_id\n", + " )\n", + "\n", + " # Looping until the run completes or fails\n", + " while run.status in ['queued', 'in_progress', 'cancelling']:\n", + " time.sleep(1)\n", + " run = client.beta.threads.runs.retrieve(\n", + " thread_id=thread.id,\n", + " run_id=run.id\n", + " )\n", + "\n", + " # Collect the result once the run is completed\n", + " if run.status == 'completed':\n", + " messages = client.beta.threads.messages.list(\n", + " thread_id=thread.id\n", + " )\n", + " results.append(messages.data[0].content[0].text.value)\n", + " elif run.status == 'requires_action':\n", + " # Handle any required actions if necessary\n", + " results.append(\"Assistant requires action for query: \" + query)\n", + " else:\n", + " # Store the status for failed queries\n", + " results.append(f\"Query failed: {run.status} for query: {query}\")\n", + "\n", + " return results\n", + "\n", + "\n", + "# List of queries to run\n", + "queries = [\n", + " \"Are there any outliers?\",\n", + " \"Can you summarize the data trends?\",\n", + " \"What anomalies do you detect?\"\n", + "]\n", + "\n", + "# Call the function with the list of queries\n", + "results = run_queries(queries, client, assistant.id)\n", + "\n", + "# Output the results for each query\n", + "for i, result in enumerate(results):\n", + " print(f\"Result for query {i+1}: {result}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Display images" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from PIL import Image\n", + "import io\n", + "\n", + "# Assuming response_content is the binary content you're getting from the OpenAI API\n", + "response_content = client.files.content(messages.data[0].content[0].image_file.file_id)\n", + "\n", + "# Convert the binary response content to an image\n", + "image_bytes = response_content.content\n", + "image = Image.open(io.BytesIO(image_bytes))\n", + "\n", + "# Display the image\n", + "image.show()\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "SyncCursorPage[Message](data=[Message(id='msg_WPUgNixVlcYTmKw4W3pKZ3Ce', assistant_id='asst_4aatBVInAyCOhUfzWA5M8yZD', attachments=[Attachment(file_id='assistant-o6QzcwtUgZJm7aj8NWXsdwVD', tools=[CodeInterpreterTool(type='code_interpreter')])], completed_at=None, content=[TextContentBlock(text=Text(annotations=[FilePathAnnotation(end_index=147, file_path=FilePath(file_id='assistant-o6QzcwtUgZJm7aj8NWXsdwVD'), start_index=117, text='sandbox:/mnt/data/outliers.csv', type='file_path')], value='The outliers have been saved to a CSV file. You can download the file using the link below:\\n\\n[Download outliers.csv](sandbox:/mnt/data/outliers.csv)'), type='text')], created_at=1729577434, incomplete_at=None, incomplete_details=None, metadata={}, object='thread.message', role='assistant', run_id='run_7NXbrQMJPp73SXurSWDzbfSo', status=None, thread_id='thread_12yh3C890jvQYzTsutTUc4rh'), Message(id='msg_jUNoPpyPnv1iNy5ksR6Faayr', assistant_id='asst_4aatBVInAyCOhUfzWA5M8yZD', attachments=[], completed_at=None, content=[TextContentBlock(text=Text(annotations=[], value='The records from the following rows have been identified as outliers based on the IQR method:\\n\\n```\\n ID Company Revenue (USD) Expenses (USD) Profit (USD)\\n5 6 Zeta Corp 1500000.0 1200000.0 300000.0\\n17 18 Sigma Corp 1800000.0 1500000.0 300000.0\\n24 25 Alpha2 Corp 2500000.0 2000000.0 500000.0\\n29 30 Zeta2 Corp 1200000.0 1000000.0 200000.0\\n33 34 Kappa2 Corp 2200000.0 1700000.0 500000.0\\n39 40 Pi2 Ltd. 3000000.0 2500000.0 500000.0\\n```\\n\\nNext, we will save these outliers to a CSV file.'), type='text')], created_at=1729577430, incomplete_at=None, incomplete_details=None, metadata={}, object='thread.message', role='assistant', run_id='run_7NXbrQMJPp73SXurSWDzbfSo', status=None, thread_id='thread_12yh3C890jvQYzTsutTUc4rh'), Message(id='msg_UvdWpdOxd2bVVUrX4IFqAlvi', assistant_id='asst_4aatBVInAyCOhUfzWA5M8yZD', attachments=[], completed_at=None, content=[TextContentBlock(text=Text(annotations=[], value='The file contains financial data of different companies, including columns for ID, Company, Revenue (USD), Expenses (USD), and Profit (USD). \\n\\nNext, we will check each of the numerical columns (Revenue (USD), Expenses (USD), and Profit (USD)) for any outliers using statistical methods such as the IQR (Interquartile Range) method. This will help us identify and report any outliers.'), type='text')], created_at=1729577424, incomplete_at=None, incomplete_details=None, metadata={}, object='thread.message', role='assistant', run_id='run_7NXbrQMJPp73SXurSWDzbfSo', status=None, thread_id='thread_12yh3C890jvQYzTsutTUc4rh'), Message(id='msg_g7SVpjC0o09RQldyZAEBwkO0', assistant_id='asst_4aatBVInAyCOhUfzWA5M8yZD', attachments=[], completed_at=None, content=[TextContentBlock(text=Text(annotations=[], value=\"Let's begin by loading the provided file and examining its contents. After that, we'll identify any outliers within the data.\"), type='text')], created_at=1729577420, incomplete_at=None, incomplete_details=None, metadata={}, object='thread.message', role='assistant', run_id='run_7NXbrQMJPp73SXurSWDzbfSo', status=None, thread_id='thread_12yh3C890jvQYzTsutTUc4rh'), Message(id='msg_FX285K1mSlWvGKZXPPIG8jhq', assistant_id=None, attachments=[], completed_at=None, content=[TextContentBlock(text=Text(annotations=[], value='are there any outliers?'), type='text')], created_at=1729577419, incomplete_at=None, incomplete_details=None, metadata={}, object='thread.message', role='user', run_id=None, status=None, thread_id='thread_12yh3C890jvQYzTsutTUc4rh')], object='list', first_id='msg_WPUgNixVlcYTmKw4W3pKZ3Ce', last_id='msg_FX285K1mSlWvGKZXPPIG8jhq', has_more=False)" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "messages" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "SyncCursorPage[RunStep](data=[RunStep(id='step_AbDJI5I1aABzai99pxuAH9Cc', assistant_id='asst_4aatBVInAyCOhUfzWA5M8yZD', cancelled_at=None, completed_at=1729577435, created_at=1729577434, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_7NXbrQMJPp73SXurSWDzbfSo', status='completed', step_details=MessageCreationStepDetails(message_creation=MessageCreation(message_id='msg_WPUgNixVlcYTmKw4W3pKZ3Ce'), type='message_creation'), thread_id='thread_12yh3C890jvQYzTsutTUc4rh', type='message_creation', usage=Usage(completion_tokens=37, prompt_tokens=1645, total_tokens=1682), expires_at=None), RunStep(id='step_AYnkm56sje4mZkMtUofdQiTD', assistant_id='asst_4aatBVInAyCOhUfzWA5M8yZD', cancelled_at=None, completed_at=1729577434, created_at=1729577432, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_7NXbrQMJPp73SXurSWDzbfSo', status='completed', step_details=ToolCallsStepDetails(tool_calls=[CodeInterpreterToolCall(id='call_LF9OvrgK2fJ2rJs4au64e6sJ', code_interpreter=CodeInterpreter(input=\"# Remove duplicate rows as a result of multiple outlier detections on the same data points\\r\\noutliers = outliers.drop_duplicates()\\r\\n\\r\\n# Save the outliers to a CSV file\\r\\noutliers_file_path = '/mnt/data/outliers.csv'\\r\\noutliers.to_csv(outliers_file_path, index=False)\\r\\noutliers_file_path\", outputs=[]), type='code_interpreter')], type='tool_calls'), thread_id='thread_12yh3C890jvQYzTsutTUc4rh', type='tool_calls', usage=Usage(completion_tokens=71, prompt_tokens=0, total_tokens=71), expires_at=None), RunStep(id='step_l7tI9lHKV1C2hVhguOw3TKtW', assistant_id='asst_4aatBVInAyCOhUfzWA5M8yZD', cancelled_at=None, completed_at=1729577432, created_at=1729577430, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_7NXbrQMJPp73SXurSWDzbfSo', status='completed', step_details=MessageCreationStepDetails(message_creation=MessageCreation(message_id='msg_jUNoPpyPnv1iNy5ksR6Faayr'), type='message_creation'), thread_id='thread_12yh3C890jvQYzTsutTUc4rh', type='message_creation', usage=Usage(completion_tokens=233, prompt_tokens=0, total_tokens=233), expires_at=None), RunStep(id='step_hinzcxp4VKsRUBZ2zbQttFH1', assistant_id='asst_4aatBVInAyCOhUfzWA5M8yZD', cancelled_at=None, completed_at=1729577430, created_at=1729577425, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_7NXbrQMJPp73SXurSWDzbfSo', status='completed', step_details=ToolCallsStepDetails(tool_calls=[CodeInterpreterToolCall(id='call_EZ5yMebfi7NYnFY1ZOa6lgne', code_interpreter=CodeInterpreter(input=\"# Convert columns to numeric\\ndata['Revenue (USD)'] = data['Revenue (USD)'].str.replace(',', '').astype(float)\\ndata['Expenses (USD)'] = data['Expenses (USD)'].str.replace(',', '').astype(float)\\ndata['Profit (USD)'] = data['Profit (USD)'].str.replace(',', '').astype(float)\\n\\ndef detect_outliers_iqr(df):\\n outliers = pd.DataFrame(columns=df.columns)\\n for column in df.select_dtypes(include=[float, int]).columns:\\n Q1 = df[column].quantile(0.25)\\n Q3 = df[column].quantile(0.75)\\n IQR = Q3 - Q1\\n lower_bound = Q1 - 1.5 * IQR\\n upper_bound = Q3 + 1.5 * IQR\\n\\n column_outliers = df[(df[column] < lower_bound) | (df[column] > upper_bound)]\\n outliers = pd.concat([outliers, column_outliers])\\n\\n return outliers\\n\\noutliers = detect_outliers_iqr(data)\\n\\noutliers\", outputs=[]), type='code_interpreter')], type='tool_calls'), thread_id='thread_12yh3C890jvQYzTsutTUc4rh', type='tool_calls', usage=Usage(completion_tokens=235, prompt_tokens=0, total_tokens=235), expires_at=None), RunStep(id='step_Fc0SbJxEdkDL7eW4OuPMNqtg', assistant_id='asst_4aatBVInAyCOhUfzWA5M8yZD', cancelled_at=None, completed_at=1729577425, created_at=1729577424, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_7NXbrQMJPp73SXurSWDzbfSo', status='completed', step_details=MessageCreationStepDetails(message_creation=MessageCreation(message_id='msg_UvdWpdOxd2bVVUrX4IFqAlvi'), type='message_creation'), thread_id='thread_12yh3C890jvQYzTsutTUc4rh', type='message_creation', usage=Usage(completion_tokens=87, prompt_tokens=0, total_tokens=87), expires_at=None), RunStep(id='step_jJGmV86LdMkaI4jIiginQpfV', assistant_id='asst_4aatBVInAyCOhUfzWA5M8yZD', cancelled_at=None, completed_at=1729577424, created_at=1729577420, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_7NXbrQMJPp73SXurSWDzbfSo', status='completed', step_details=ToolCallsStepDetails(tool_calls=[CodeInterpreterToolCall(id='call_22UsrZRCviBDpR09NBABYpot', code_interpreter=CodeInterpreter(input=\"import pandas as pd\\n\\n# Load the uploaded file\\nfile_path = '/mnt/data/assistant-JpCZy3t3PwSzwlhImLxit8NX'\\ndata = pd.read_csv(file_path)\\n\\n# Display the first few rows of the dataframe\\ndata.head()\", outputs=[]), type='code_interpreter')], type='tool_calls'), thread_id='thread_12yh3C890jvQYzTsutTUc4rh', type='tool_calls', usage=Usage(completion_tokens=63, prompt_tokens=0, total_tokens=63), expires_at=None), RunStep(id='step_qEOTmIIU5G4M6glwdoqfNu3a', assistant_id='asst_4aatBVInAyCOhUfzWA5M8yZD', cancelled_at=None, completed_at=1729577420, created_at=1729577420, expired_at=None, failed_at=None, last_error=None, metadata=None, object='thread.run.step', run_id='run_7NXbrQMJPp73SXurSWDzbfSo', status='completed', step_details=MessageCreationStepDetails(message_creation=MessageCreation(message_id='msg_g7SVpjC0o09RQldyZAEBwkO0'), type='message_creation'), thread_id='thread_12yh3C890jvQYzTsutTUc4rh', type='message_creation', usage=Usage(completion_tokens=26, prompt_tokens=0, total_tokens=26), expires_at=None)], object='list', first_id='step_AbDJI5I1aABzai99pxuAH9Cc', last_id='step_qEOTmIIU5G4M6glwdoqfNu3a', has_more=False)" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "run_steps = client.beta.threads.runs.steps.list(\n", + " thread_id=thread.id,\n", + " run_id=run.id\n", + ")\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "# Convert columns to numeric\n", + "data['Revenue (USD)'] = data['Revenue (USD)'].str.replace(',', '').astype(float)\n", + "data['Expenses (USD)'] = data['Expenses (USD)'].str.replace(',', '').astype(float)\n", + "data['Profit (USD)'] = data['Profit (USD)'].str.replace(',', '').astype(float)\n", + "\n", + "def detect_outliers_iqr(df):\n", + " outliers = pd.DataFrame(columns=df.columns)\n", + " for column in df.select_dtypes(include=[float, int]).columns:\n", + " Q1 = df[column].quantile(0.25)\n", + " Q3 = df[column].quantile(0.75)\n", + " IQR = Q3 - Q1\n", + " lower_bound = Q1 - 1.5 * IQR\n", + " upper_bound = Q3 + 1.5 * IQR\n", + "\n", + " column_outliers = df[(df[column] < lower_bound) | (df[column] > upper_bound)]\n", + " outliers = pd.concat([outliers, column_outliers])\n", + "\n", + " return outliers\n", + "\n", + "outliers = detect_outliers_iqr(data)\n", + "\n", + "outliers\n" + ] + } + ], + "source": [ + "print(run_steps.data[3].step_details.tool_calls[0].code_interpreter.input)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/scenarios/Assistants/code-interptreter/requirements.txt b/scenarios/Assistants/code-interptreter/requirements.txt new file mode 100644 index 00000000..979921aa --- /dev/null +++ b/scenarios/Assistants/code-interptreter/requirements.txt @@ -0,0 +1,6 @@ +openai +python-dotenv +streamlit +azure-storage-blob +pandas +numpy \ No newline at end of file