├── .env ├── Multi_AI_Agents_with_Azure_PostgreSQL v1.ipynb ├── README.md ├── SQL_Queries.sql └── requirements.txt /.env: -------------------------------------------------------------------------------- 1 | # Azure OpenAI 2 | AZURE_OPENAI_KEY=your_openai_api_key 3 | AZURE_OPENAI_ENDPOINT=https://your-openai-endpoint 4 | AZURE_OPENAI_DEPLOYMENT=gpt-4 5 | 6 | # PostgreSQL Database 7 | POSTGRES_USER=your_username 8 | POSTGRES_PASSWORD=your_password 9 | POSTGRES_HOST=your_postgresql_host 10 | POSTGRES_PORT=5432 11 | POSTGRES_DB=your_database_name # usually postgres -------------------------------------------------------------------------------- /Multi_AI_Agents_with_Azure_PostgreSQL v1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# Do not use it if you have already installed the requirements file\n", 10 | "# !pip install langchain langchain_openai langchain-community langchain_experimental gradio psycopg2 python-dotenv ag2\n", 11 | "# !pip uninstall pydantic\n", 12 | "# !pip install pydantic==2.9.2\n", 13 | "# !pip install autogen-agentchat~=0.2" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": null, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "import autogen\n", 23 | "from langchain_community.utilities.sql_database import SQLDatabase\n", 24 | "from langchain_experimental.sql import SQLDatabaseChain\n", 25 | "from langchain_openai import AzureChatOpenAI\n", 26 | "import os\n", 27 | "from dotenv import load_dotenv\n", 28 | "import gradio as gr\n", 29 | "import asyncio\n", 30 | "import psycopg2\n", 31 | "from autogen import AssistantAgent, UserProxyAgent, config_list_from_json\n", 32 | "from langchain.cache import InMemoryCache\n", 33 | "from langchain_experimental.sql.base import SQLDatabaseChain" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 2, 39 | "metadata": {}, 40 | "outputs": [], 41 | "source": [ 42 | "# Load environment variables from the .env file from the same directory as notebook \n", 43 | "load_dotenv()\n", 44 | "\n", 45 | "# Retrieve environment variables\n", 46 | "POSTGRES_USER = os.getenv('POSTGRES_USER')\n", 47 | "POSTGRES_PASSWORD = os.getenv('POSTGRES_PASSWORD')\n", 48 | "POSTGRES_HOST = os.getenv('POSTGRES_HOST')\n", 49 | "POSTGRES_PORT = os.getenv('POSTGRES_PORT')\n", 50 | "POSTGRES_DB = os.getenv('POSTGRES_DB')\n", 51 | "AZURE_OPENAI_KEY = os.getenv('AZURE_OPENAI_KEY')\n", 52 | "AZURE_OPENAI_ENDPOINT = os.getenv('AZURE_OPENAI_ENDPOINT')\n", 53 | "AZURE_OPENAI_DEPLOYMENT = os.getenv('AZURE_OPENAI_DEPLOYMENT')" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": null, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "# Construct the database URI\n", 63 | "shipment_db_uri = f\"postgresql+psycopg2://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}:{POSTGRES_PORT}/{POSTGRES_DB}\"\n", 64 | "crm_db_uri = f\"postgresql+psycopg2://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}:{POSTGRES_PORT}/{POSTGRES_DB}\"\n", 65 | "\n", 66 | "# Establish database connections\n", 67 | "shipment_db = SQLDatabase.from_uri(shipment_db_uri)\n", 68 | "crm_db = SQLDatabase.from_uri(crm_db_uri)" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": 4, 74 | "metadata": {}, 75 | "outputs": [], 76 | "source": [ 77 | "# Initialize the Azure OpenAI language model\n", 78 | "azure_llm = AzureChatOpenAI(\n", 79 | " azure_endpoint = AZURE_OPENAI_ENDPOINT,\n", 80 | " api_key=AZURE_OPENAI_KEY,\n", 81 | " api_version=\"2024-10-21\",\n", 82 | " deployment_name=AZURE_OPENAI_DEPLOYMENT,\n", 83 | ")" 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": 5, 89 | "metadata": {}, 90 | "outputs": [], 91 | "source": [ 92 | "# Query functions for each database\n", 93 | "def query_shipment(query):\n", 94 | " return shipment_chain.invoke(query)\n", 95 | "\n", 96 | "def query_crm(query):\n", 97 | " return crm_chain.invoke(query)\n", 98 | "\n", 99 | "# Function to retrieve database schema information\n", 100 | "def get_schema_info():\n", 101 | " from sqlalchemy import text\n", 102 | " import json # Import json module to convert data to JSON string\n", 103 | " with shipment_db._engine.connect() as connection:\n", 104 | " query = text(\"\"\"\n", 105 | " SELECT\n", 106 | " cols.table_schema,\n", 107 | " cols.table_name,\n", 108 | " cols.column_name,\n", 109 | " cols.data_type,\n", 110 | " cols.is_nullable,\n", 111 | " cons.constraint_type,\n", 112 | " cons.constraint_name,\n", 113 | " fk.references_table AS referenced_table,\n", 114 | " fk.references_column AS referenced_column\n", 115 | " FROM information_schema.columns cols\n", 116 | " LEFT JOIN information_schema.key_column_usage kcu\n", 117 | " ON cols.table_schema = kcu.table_schema\n", 118 | " AND cols.table_name = kcu.table_name\n", 119 | " AND cols.column_name = kcu.column_name\n", 120 | " LEFT JOIN information_schema.table_constraints cons\n", 121 | " ON kcu.table_schema = cons.table_schema\n", 122 | " AND kcu.table_name = cons.table_name\n", 123 | " AND kcu.constraint_name = cons.constraint_name\n", 124 | " LEFT JOIN (\n", 125 | " SELECT\n", 126 | " rc.constraint_name,\n", 127 | " kcu.table_name AS references_table,\n", 128 | " kcu.column_name AS references_column\n", 129 | " FROM information_schema.referential_constraints rc\n", 130 | " JOIN information_schema.key_column_usage kcu\n", 131 | " ON rc.unique_constraint_name = kcu.constraint_name\n", 132 | " ) fk\n", 133 | " ON cons.constraint_name = fk.constraint_name\n", 134 | " WHERE cols.table_schema = 'public'\n", 135 | " ORDER BY cols.table_schema, cols.table_name, cols.ordinal_position;\n", 136 | " \"\"\")\n", 137 | " result = connection.execute(query)\n", 138 | " columns = result.keys()\n", 139 | " rows = result.fetchall()\n", 140 | " # Convert the result to a list of dictionaries\n", 141 | " schema_info = [dict(zip(columns, row)) for row in rows]\n", 142 | " return json.dumps(schema_info, indent=2)\n", 143 | "\n", 144 | "# Function to share schema information between agents\n", 145 | "def get_shared_schema_info():\n", 146 | " if schema_agent.schema_info is None:\n", 147 | " schema_agent.retrieve_and_store_schema()\n", 148 | " return schema_agent.schema_info\n", 149 | "\n", 150 | "# Method to retrieve and store schema information\n", 151 | "def retrieve_and_store_schema(agent):\n", 152 | " schema_info = get_schema_info()\n", 153 | " agent.schema_info = schema_info\n", 154 | " return \"Schema information retrieved and stored.\"\n", 155 | "\n", 156 | "# Method to add a new customer to the CRM database\n", 157 | "def add_customer(procedure_name, parameters):\n", 158 | " from sqlalchemy import text\n", 159 | " with crm_db._engine.connect() as connection:\n", 160 | " trans = connection.begin() # Begin a transaction\n", 161 | " try:\n", 162 | " # Prepare the parameter placeholders\n", 163 | " param_placeholders = ', '.join([f\":{k}\" for k in parameters.keys()])\n", 164 | " # Construct the SQL command to execute the stored procedure\n", 165 | " sql_command = text(f\"CALL {procedure_name}({param_placeholders})\")\n", 166 | " # Pass parameters as a dictionary\n", 167 | " result = connection.execute(sql_command, parameters)\n", 168 | " # Commit the transaction\n", 169 | " trans.commit()\n", 170 | " # Return a success message\n", 171 | " return \"Customer added successfully.\"\n", 172 | " except Exception as e:\n", 173 | " trans.rollback()\n", 174 | " return f\"An error occurred while executing the stored procedure: {e}\"\n", 175 | "\n", 176 | "# Method to create a new shipment in the shipment database\n", 177 | "def send_shipment(procedure_name, parameters):\n", 178 | " from sqlalchemy import text\n", 179 | " import json\n", 180 | " with shipment_db._engine.connect() as connection:\n", 181 | " trans = connection.begin() # Begin a transaction\n", 182 | " try:\n", 183 | " # If 'items' is a list, convert it to JSON string\n", 184 | " if isinstance(parameters.get('items'), list):\n", 185 | " parameters['items'] = json.dumps(parameters['items'])\n", 186 | " # Prepare the parameter placeholders\n", 187 | " param_placeholders = ', '.join([f\":{k}\" for k in parameters.keys()])\n", 188 | " # Construct the SQL command\n", 189 | " sql_command = text(f\"CALL {procedure_name}({param_placeholders})\")\n", 190 | " # Execute the stored procedure\n", 191 | " result = connection.execute(sql_command, parameters)\n", 192 | " # Commit the transaction\n", 193 | " trans.commit()\n", 194 | " return \"Shipment sent successfully.\"\n", 195 | " except Exception as e:\n", 196 | " trans.rollback()\n", 197 | " return f\"An error occurred while executing the stored procedure: {e}\"" 198 | ] 199 | }, 200 | { 201 | "cell_type": "code", 202 | "execution_count": null, 203 | "metadata": {}, 204 | "outputs": [], 205 | "source": [ 206 | "# Language model configuration with functions\n", 207 | "llm_config = {\n", 208 | " \"config_list\": [\n", 209 | " {\n", 210 | " \"model\": AZURE_OPENAI_DEPLOYMENT,\n", 211 | " \"temperature\": 0.7,\n", 212 | " \"api_key\": AZURE_OPENAI_KEY,\n", 213 | " \"azure_endpoint\": AZURE_OPENAI_ENDPOINT,\n", 214 | " \"api_type\": \"azure\",\n", 215 | " \"api_version\": \"2024-10-21\"\n", 216 | " }\n", 217 | " ],\n", 218 | " \"seed\": 42,\n", 219 | " \"functions\": [\n", 220 | " {\n", 221 | " \"name\": \"query_shipment\",\n", 222 | " \"description\": \"Queries the Shipment database based on the provided query\",\n", 223 | " \"parameters\": {\n", 224 | " \"type\": \"object\",\n", 225 | " \"properties\": {\n", 226 | " \"query\": {\"type\": \"string\", \"description\": \"The SQL query to execute on the shipment database\"}\n", 227 | " },\n", 228 | " \"required\": [\"query\"]\n", 229 | " }\n", 230 | " },\n", 231 | " {\n", 232 | " \"name\": \"query_crm\",\n", 233 | " \"description\": \"Queries the CRM database based on the provided query\",\n", 234 | " \"parameters\": {\n", 235 | " \"type\": \"object\",\n", 236 | " \"properties\": {\n", 237 | " \"query\": {\"type\": \"string\", \"description\": \"The SQL query to execute on the CRM database\"}\n", 238 | " },\n", 239 | " \"required\": [\"query\"]\n", 240 | " }\n", 241 | " },\n", 242 | " {\n", 243 | " \"name\": \"get_schema_info\",\n", 244 | " \"description\": \"Retrieves the database schema and referential integrity information. Only use 'get_schema_info' to retrieve schema information and store it. Do not do anything else\",\n", 245 | " \"parameters\": {\"type\": \"object\", \"properties\": {}, \"required\": []}\n", 246 | " },\n", 247 | " {\n", 248 | " \"name\": \"get_shared_schema_info\",\n", 249 | " \"description\": \"Provides the stored schema information to other agents.\",\n", 250 | " \"parameters\": {\"type\": \"object\", \"properties\": {}, \"required\": []}\n", 251 | " },\n", 252 | " {\n", 253 | " \"name\": \"add_customer\",\n", 254 | " \"description\": \"Adds a customer to the CRM database by executing the 'add_customer' stored procedure with the provided parameters.\",\n", 255 | " \"parameters\": {\n", 256 | " \"type\": \"object\",\n", 257 | " \"properties\": {\n", 258 | " \"procedure_name\": {\n", 259 | " \"type\": \"string\",\n", 260 | " \"description\": \"The name of the stored procedure to execute (should be 'add_customer')\"\n", 261 | " },\n", 262 | " \"parameters\": {\n", 263 | " \"type\": \"object\",\n", 264 | " \"description\": \"A dictionary of parameters to pass to the stored procedure, including 'name', 'email', 'phone', and 'address'.\",\n", 265 | " \"properties\": {\n", 266 | " \"name\": {\"type\": \"string\"},\n", 267 | " \"email\": {\"type\": \"string\"},\n", 268 | " \"phone\": {\"type\": \"string\"},\n", 269 | " \"address\": {\"type\": \"string\"}\n", 270 | " },\n", 271 | " \"required\": [\"name\", \"email\", \"phone\", \"address\"]\n", 272 | " }\n", 273 | " },\n", 274 | " \"required\": [\"procedure_name\", \"parameters\"]\n", 275 | " }\n", 276 | " },\n", 277 | " {\n", 278 | " \"name\": \"send_shipment\",\n", 279 | " \"description\": \"Sends a shipment by executing the 'send_shipment' stored procedure with the provided parameters.\",\n", 280 | " \"parameters\": {\n", 281 | " \"type\": \"object\",\n", 282 | " \"properties\": {\n", 283 | " \"procedure_name\": {\n", 284 | " \"type\": \"string\",\n", 285 | " \"description\": \"The name of the stored procedure to execute (should be 'send_shipment')\"\n", 286 | " },\n", 287 | " \"parameters\": {\n", 288 | " \"type\": \"object\",\n", 289 | " \"description\": \"Parameters for the stored procedure, including 'customer_id', 'origin_id', 'destination_id', 'shipment_date', 'items', 'status', 'tracking_status', and 'location_id'.\",\n", 290 | " \"properties\": {\n", 291 | " \"customer_id\": {\"type\": \"integer\"},\n", 292 | " \"origin_id\": {\"type\": \"integer\"},\n", 293 | " \"destination_id\": {\"type\": \"integer\"},\n", 294 | " \"shipment_date\": {\"type\": \"string\", \"format\": \"date\"},\n", 295 | " \"items\": {\n", 296 | " \"type\": \"array\",\n", 297 | " \"items\": {\n", 298 | " \"type\": \"object\",\n", 299 | " \"properties\": {\n", 300 | " \"product_id\": {\"type\": \"integer\"},\n", 301 | " \"quantity\": {\"type\": \"integer\"}\n", 302 | " },\n", 303 | " \"required\": [\"product_id\", \"quantity\"]\n", 304 | " }\n", 305 | " },\n", 306 | " \"status\": {\"type\": \"string\"},\n", 307 | " \"tracking_status\": {\"type\": \"string\"},\n", 308 | " \"location_id\": {\"type\": \"integer\"}\n", 309 | " },\n", 310 | " \"required\": [\"customer_id\", \"origin_id\", \"destination_id\", \"shipment_date\", \"items\", \"status\", \"tracking_status\", \"location_id\"]\n", 311 | " }\n", 312 | " },\n", 313 | " \"required\": [\"procedure_name\", \"parameters\"]\n", 314 | " }\n", 315 | " }\n", 316 | " ]\n", 317 | "}\n", 318 | "\n", 319 | "\n", 320 | "# Initialize the database chains\n", 321 | "shipment_chain = SQLDatabaseChain(llm=azure_llm, database=shipment_db, verbose=True)\n", 322 | "crm_chain = SQLDatabaseChain(llm=azure_llm, database=crm_db, verbose=True)\n", 323 | "\n", 324 | "# Create assistant agents\n", 325 | "shipment_agent = autogen.ConversableAgent(\n", 326 | " name=\"ShipmentAgent\",\n", 327 | " llm_config=llm_config,\n", 328 | " description=\"Manage shipments in the main database.\",\n", 329 | " system_message=(\n", 330 | " \"Your role is to query the main database using 'query_shipment'. \"\n", 331 | " \"Focus on the shipments tables and ensure that all shipments are tracked correctly. You can make SELECT using PostgreSQL queries. Use the 'add_customer' function to call the appropriate stored procedure for adding new customers.\"\n", 332 | " \"For Insert, Update, and Delete operations, have human to validate the operation before making it.\"\n", 333 | " \"Here is an example on how to call add_customer stored procedure: CALL add_customer('marcre@contoso.com', 'marcre@contoso.com', '+1 123 456 7890','1 Main Street, Redmond');\"\n", 334 | " \"Use 'get_shared_schema_info' from SchemaAgent to retrieve schema information.\"\n", 335 | " ),\n", 336 | ")\n", 337 | "\n", 338 | "crm_agent = autogen.ConversableAgent(\n", 339 | " name=\"CRMAgent\",\n", 340 | " llm_config=llm_config,\n", 341 | " description=\"Manages customer and product information in the second database.\",\n", 342 | " system_message=(\n", 343 | " \"Your role is to query the second database using 'query_crm'. \"\n", 344 | " \"Focus on maintaining the customers and product tables. You can make SELECT using PostgreSQL queries. Use the 'send_shipment' function to call the appropriate stored procedure for creating shipments.\"\n", 345 | " \"For Insert, Update, and Delete operations, have human to validate the operation before making it.\"\n", 346 | " \"Here is an example on how to call 'send_shipment' stored procedure:\"\n", 347 | " \"CALL send_shipment(\"\n", 348 | " \" customer_id := 1,\"\n", 349 | " \" origin_id := 3,\"\n", 350 | " \" destination_id := 2,\"\n", 351 | " \" shipment_date := '2023-10-01',\"\n", 352 | " \" items := '[\"\n", 353 | " \" {'product_id': 1, 'quantity': 5},\"\n", 354 | " \" {'product_id': 2, 'quantity': 3}\"\n", 355 | " \" ]'::jsonb,\"\n", 356 | " \" status := 'In Transit',\"\n", 357 | " \" tracking_status := 'Departed Origin',\"\n", 358 | " \" location_id := 3\"\n", 359 | " \");\"\n", 360 | " \"Use 'get_shared_schema_info' from SchemaAgent to retrieve schema information. \"\n", 361 | " ),\n", 362 | ")\n", 363 | "\n", 364 | "schema_agent = autogen.ConversableAgent(\n", 365 | " name=\"SchemaAgent\",\n", 366 | " llm_config=llm_config,\n", 367 | " description=\"Understands and shares database schema information.\",\n", 368 | " system_message=(\n", 369 | " \"Your role is to retrieve and understand the database schema and referential integrity constraints.\"\n", 370 | " \"Only use 'get_schema_info' to retrieve schema information and store it. Do not do anything else. And always provide schema information when you start first.\"\n", 371 | " ),\n", 372 | ")\n", 373 | "\n", 374 | "# Register functions with the agents\n", 375 | "shipment_agent.register_function(function_map={\n", 376 | " \"query_shipment\": query_shipment,\n", 377 | " \"send_shipment\": send_shipment\n", 378 | "})\n", 379 | "crm_agent.register_function(function_map={\"query_crm\": query_crm,\n", 380 | " \"add_customer\": add_customer})\n", 381 | "schema_agent.register_function(\n", 382 | " function_map={\n", 383 | " \"get_schema_info\": get_schema_info,\n", 384 | " \"get_shared_schema_info\": get_shared_schema_info,\n", 385 | " }\n", 386 | ")\n", 387 | "\n", 388 | "# Add schema_info attribute and bind method to schema_agent\n", 389 | "import types\n", 390 | "schema_agent.schema_info = None\n", 391 | "schema_agent.retrieve_and_store_schema = types.MethodType(retrieve_and_store_schema, schema_agent)" 392 | ] 393 | }, 394 | { 395 | "cell_type": "code", 396 | "execution_count": 7, 397 | "metadata": {}, 398 | "outputs": [], 399 | "source": [ 400 | "# Create a user proxy agent\n", 401 | "user_proxy = autogen.UserProxyAgent(\n", 402 | " name=\"User_proxy\",\n", 403 | " system_message=\"A human admin.\",\n", 404 | " code_execution_config={\n", 405 | " \"last_n_messages\": 4,\n", 406 | " \"work_dir\": \"groupchat\",\n", 407 | " \"use_docker\": False,\n", 408 | " },\n", 409 | " human_input_mode=\"ALWAYS\", #Using this mode to give input to agents\n", 410 | ")\n", 411 | "\n", 412 | "# Set up the group chat and manager\n", 413 | "groupchat = autogen.GroupChat(\n", 414 | " agents=[user_proxy, schema_agent, shipment_agent, crm_agent],\n", 415 | " messages=[],\n", 416 | " max_round=30 # Maximum number of rounds in the conversation\n", 417 | ")\n", 418 | "\n", 419 | "manager = autogen.GroupChatManager(groupchat=groupchat)" 420 | ] 421 | }, 422 | { 423 | "cell_type": "code", 424 | "execution_count": null, 425 | "metadata": {}, 426 | "outputs": [], 427 | "source": [ 428 | "# Chat with your data use case\n", 429 | "\n", 430 | "user_proxy.initiate_chat(manager, message=\"Which products with names are currently tracking in transit?\") " 431 | ] 432 | }, 433 | { 434 | "cell_type": "code", 435 | "execution_count": null, 436 | "metadata": {}, 437 | "outputs": [], 438 | "source": [ 439 | "# See messages in the groupchat\n", 440 | "print(\"Current messages in the groupchat:\")\n", 441 | "for idx, msg in enumerate(manager.groupchat.messages):\n", 442 | " print(f\"Message {idx}: {msg}\")" 443 | ] 444 | }, 445 | { 446 | "cell_type": "code", 447 | "execution_count": null, 448 | "metadata": {}, 449 | "outputs": [], 450 | "source": [ 451 | "# Chat with your data use case\n", 452 | "\n", 453 | "user_proxy.initiate_chat(\n", 454 | " manager,\n", 455 | " message=(\n", 456 | " \"Is Alice Johnson a Customer?\"\n", 457 | " )\n", 458 | ")" 459 | ] 460 | }, 461 | { 462 | "cell_type": "code", 463 | "execution_count": null, 464 | "metadata": {}, 465 | "outputs": [], 466 | "source": [ 467 | "# Database Development use case\n", 468 | "\n", 469 | "user_proxy.initiate_chat(manager, message=\"I need to create a Stored Procedure to send shipments. It spans across shipments, shipment_items and shipment_tracking? Shipment_items might have multiple items and can vary. What stored procedure would you propose?\") " 470 | ] 471 | }, 472 | { 473 | "cell_type": "code", 474 | "execution_count": null, 475 | "metadata": {}, 476 | "outputs": [], 477 | "source": [ 478 | "\n", 479 | "user_proxy.initiate_chat(\n", 480 | " manager,\n", 481 | " message=(\n", 482 | " \"I would like to create a stored orodcedure to delete customers. What would be the best way to do this?\"\n", 483 | " )\n", 484 | ")" 485 | ] 486 | }, 487 | { 488 | "cell_type": "code", 489 | "execution_count": null, 490 | "metadata": {}, 491 | "outputs": [], 492 | "source": [ 493 | "# Act on Data use case: add a customer name\n", 494 | "\n", 495 | "user_proxy.initiate_chat(\n", 496 | " manager,\n", 497 | " message=(\n", 498 | " \"Can you add Marc with email address marcr@contoso.com, phone number +1 123 456 7890 and address in 1 Main Street, Redmond?\"\n", 499 | " )\n", 500 | ")" 501 | ] 502 | }, 503 | { 504 | "cell_type": "code", 505 | "execution_count": null, 506 | "metadata": {}, 507 | "outputs": [], 508 | "source": [ 509 | "# Act on Data use case: add a customer name with incomplete information\n", 510 | "\n", 511 | "user_proxy.initiate_chat(\n", 512 | " manager,\n", 513 | " message=(\n", 514 | " \"Can you add Marc with email address marcre@contoso.com, phone number +1 123 456 7890?\"\n", 515 | " )\n", 516 | ")" 517 | ] 518 | }, 519 | { 520 | "cell_type": "code", 521 | "execution_count": null, 522 | "metadata": {}, 523 | "outputs": [], 524 | "source": [ 525 | "# Act on Data use case: Create a shipment using stored procedure send_shipment writing across 3 tables\n", 526 | "\n", 527 | "user_proxy.initiate_chat(\n", 528 | " manager,\n", 529 | " message=(\n", 530 | " \"Can you create a new shipment of 1 Laptop and 1 Smartphone to Cathy Lee and ensure shipment is updated to Departed Origin from the location in New York and towards Los Angeles date is today? Ask questions if you have doubts.\"\n", 531 | " )\n", 532 | ")" 533 | ] 534 | }, 535 | { 536 | "cell_type": "code", 537 | "execution_count": null, 538 | "metadata": {}, 539 | "outputs": [], 540 | "source": [ 541 | "# Act on Data use case: Create a shipment using stored procedure send_shipment writing across 3 tables\n", 542 | "\n", 543 | "user_proxy.initiate_chat(\n", 544 | " manager,\n", 545 | " message=(\n", 546 | " \"Can you create a new shipment of 1 Laptop and 1 Smartphone to Cathy Lee and ensure shipment is updated to Departed Origin towards Los Angeles date is today? Ask questions if you miss information.\"\n", 547 | " )\n", 548 | ")" 549 | ] 550 | }, 551 | { 552 | "cell_type": "code", 553 | "execution_count": 10, 554 | "metadata": {}, 555 | "outputs": [], 556 | "source": [ 557 | "import asyncio\n", 558 | "\n", 559 | "# Initialize chat history\n", 560 | "chat_history = []\n", 561 | "\n", 562 | "async def process_user_input(user_message, chat_history):\n", 563 | " # Append your message with role 'assistant' (to appear on the left)\n", 564 | " chat_history.append({\"role\": \"assistant\", \"content\": user_message})\n", 565 | "\n", 566 | " # Append a placeholder for the agent's response with role 'user' (to appear on the right)\n", 567 | " placeholder_index = len(chat_history)\n", 568 | " chat_history.append({\"role\": \"user\", \"content\": \"Processing...\"})\n", 569 | "\n", 570 | " # Return the updated chat history immediately\n", 571 | " yield chat_history, chat_history\n", 572 | "\n", 573 | " # Now process the agent's response\n", 574 | " # Use the user_proxy agent to process the message\n", 575 | " await asyncio.to_thread(user_proxy.initiate_chat, manager, message=user_message)\n", 576 | "\n", 577 | " # Collect messages from the agents\n", 578 | " agent_messages = [\n", 579 | " msg for msg in manager.groupchat.messages if msg.get(\"role\", \"\") != \"System\"\n", 580 | " ]\n", 581 | "\n", 582 | " # Remove the placeholder\n", 583 | " if placeholder_index < len(chat_history):\n", 584 | " chat_history.pop(placeholder_index)\n", 585 | "\n", 586 | " # Append each agent's message to the chat history\n", 587 | " for msg in agent_messages:\n", 588 | " name = msg.get(\"name\", \"Agent\")\n", 589 | " content = msg.get(\"content\", \"\")\n", 590 | " role = \"user\" # Agents' messages will appear on the right\n", 591 | "\n", 592 | " # Include the agent's name in the content\n", 593 | " content_with_name = f\"**{name}**: {content}\"\n", 594 | "\n", 595 | " # Append to chat history\n", 596 | " chat_history.append({\"role\": role, \"content\": content_with_name})\n", 597 | "\n", 598 | " # Yield after each agent's message to update the UI\n", 599 | " yield chat_history, chat_history\n", 600 | "\n", 601 | " # Return the final chat history\n", 602 | " yield chat_history, chat_history\n", 603 | "\n", 604 | "def gradio_chat_interface():\n", 605 | " with gr.Blocks() as demo:\n", 606 | " chat_history_state = gr.State([])\n", 607 | "\n", 608 | " gr.Markdown(\"# Multi-Agent Chat Interface\")\n", 609 | "\n", 610 | " with gr.Row():\n", 611 | " chatbot = gr.Chatbot(type=\"messages\") # Use 'messages' format\n", 612 | " with gr.Row():\n", 613 | " user_input = gr.Textbox(\n", 614 | " placeholder=\"Type your message here...\",\n", 615 | " show_label=False\n", 616 | " )\n", 617 | " send_button = gr.Button(\"Send\")\n", 618 | " clear_button = gr.Button(\"Clear Chat\")\n", 619 | "\n", 620 | " async def on_user_message(user_message, chat_history):\n", 621 | " if user_message:\n", 622 | " # Process the user input and get the updated chat history\n", 623 | " # Use a generator to handle incremental updates\n", 624 | " response = process_user_input(user_message, chat_history)\n", 625 | " async for chat_history_update, chat_history_state_update in response:\n", 626 | " await asyncio.sleep(0)\n", 627 | " yield gr.update(value=chat_history_update), chat_history_state_update\n", 628 | "\n", 629 | " send_button.click(\n", 630 | " on_user_message,\n", 631 | " inputs=[user_input, chat_history_state],\n", 632 | " outputs=[chatbot, chat_history_state]\n", 633 | " )\n", 634 | "\n", 635 | " user_input.submit(\n", 636 | " on_user_message,\n", 637 | " inputs=[user_input, chat_history_state],\n", 638 | " outputs=[chatbot, chat_history_state]\n", 639 | " )\n", 640 | "\n", 641 | " clear_button.click(\n", 642 | " lambda: ([], []),\n", 643 | " None,\n", 644 | " [chatbot, chat_history_state],\n", 645 | " queue=False\n", 646 | " )\n", 647 | "\n", 648 | " return demo" 649 | ] 650 | }, 651 | { 652 | "cell_type": "code", 653 | "execution_count": null, 654 | "metadata": {}, 655 | "outputs": [], 656 | "source": [ 657 | "# Run the Gradio interface\n", 658 | "demo = gradio_chat_interface()\n", 659 | "demo.launch()" 660 | ] 661 | } 662 | ], 663 | "metadata": { 664 | "kernelspec": { 665 | "display_name": "test_notebook", 666 | "language": "python", 667 | "name": "python3" 668 | }, 669 | "language_info": { 670 | "codemirror_mode": { 671 | "name": "ipython", 672 | "version": 3 673 | }, 674 | "file_extension": ".py", 675 | "mimetype": "text/x-python", 676 | "name": "python", 677 | "nbconvert_exporter": "python", 678 | "pygments_lexer": "ipython3", 679 | "version": "3.13.0" 680 | } 681 | }, 682 | "nbformat": 4, 683 | "nbformat_minor": 2 684 | } 685 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |