├── .gitignore ├── README.md ├── api ├── README.md ├── client-api-test.ipynb └── server-api-test.ipynb ├── assets ├── 2024-02-14-16-42-14.png ├── 2024-02-14-16-49-31.png ├── 2024-02-15-09-49-05.png ├── 2024-02-15-14-36-25.png └── intro.png ├── backend ├── 1-WatsonX-with-Croma.ipynb ├── 1_build_question_answering_engine_medical.ipynb ├── 1_build_question_answering_engine_medical_big.ipynb ├── 2-WatsonX-with-Milvus.ipynb ├── 3-WatsonX-with-Milvus-Medical.ipynb ├── 4-WatsonX-with-Milvus.ipynb ├── 5-WatsonX-Client-Milvus.ipynb ├── README.md ├── id_answer.pkl ├── question_answer.csv └── requirements.txt ├── cloud-function ├── README.md ├── requirements.txt └── wikipedia │ ├── Dockerfile │ ├── README.md │ ├── app.py │ ├── assets │ └── 2024-02-24-11-51-24.png │ ├── backup │ ├── v1 │ │ ├── app.py │ │ └── test.py │ ├── v2 │ │ └── app.py │ ├── v3 │ │ └── app.py │ └── v4 │ │ └── wiki.py │ ├── run.bat │ ├── test.md │ ├── test.ps1 │ ├── test.py │ └── test.sh ├── code-engine ├── README.md ├── api-test.py ├── assets │ ├── 2024-02-22-17-07-03.png │ ├── 2024-02-22-17-11-30.png │ ├── 2024-02-22-17-33-52.png │ ├── 2024-02-22-17-50-52.png │ ├── 2024-02-22-17-52-36.png │ ├── 2024-02-22-18-55-09.png │ ├── 2024-02-22-19-35-13.png │ ├── 2024-02-22-19-35-38.png │ ├── 2024-02-22-19-36-03.png │ ├── 2024-02-23-11-41-13.png │ ├── 2024-02-23-11-43-31.png │ ├── 2024-02-23-12-00-45.png │ ├── 2024-02-23-12-03-04.png │ ├── 2024-02-23-12-05-08.png │ ├── 2024-02-23-12-09-02.png │ ├── 2024-02-23-12-10-22.png │ ├── 2024-03-11-15-41-12.png │ ├── 2024-03-11-16-57-05.png │ ├── 2024-03-11-17-03-25.png │ └── 2024-03-11-17-05-03.png └── openapi.json ├── container-api ├── Dockerfile ├── README.md ├── api-test.ipynb ├── api-test.py ├── app.py ├── assets │ ├── 2024-02-22-13-55-09.png │ ├── 2024-02-22-14-22-34.png │ ├── 2024-02-22-14-38-43.png │ ├── 2024-02-22-15-29-04.png │ ├── 2024-03-02-17-36-34.png │ ├── 2024-03-02-17-38-13.png │ ├── 2024-03-07-17-53-44.png │ ├── 2024-03-11-12-05-35.png │ ├── 2024-03-11-12-15-02.png │ ├── 2024-03-11-12-39-07.png │ └── python api-test.py.png ├── openapi.json └── requirements.txt ├── container ├── Dockerfile ├── README.md ├── app.py ├── assets │ ├── 2024-02-22-13-55-09.png │ ├── 2024-02-22-14-22-34.png │ ├── 2024-02-22-14-38-43.png │ └── 2024-02-22-15-29-04.png └── requirements.txt ├── containers └── milvus │ ├── Dockerfile │ ├── prebuildfs │ ├── opt │ │ └── bitnami │ │ │ ├── .bitnami_components.json │ │ │ └── licenses │ │ │ └── licenses.txt │ └── usr │ │ └── sbin │ │ ├── install_packages │ │ └── run-script │ └── tags-info.yaml ├── demo └── demo1.png ├── imagenx.png ├── notebooks ├── 0-Manage-VectorDatabase.ipynb ├── 1_build_question_answering_engine.ipynb ├── 1_build_text_image_search_engine.ipynb ├── README.md ├── assets │ ├── 2024-02-15-15-40-21.png │ ├── 2024-02-15-15-42-06.png │ ├── 2024-02-15-15-42-45.png │ ├── 2024-02-15-15-54-48.png │ └── 2024-02-15-17-55-07.png ├── hello_milvus.ipynb ├── hello_milvus.py ├── question_answer.csv └── workflow.png ├── openapi-extension ├── README.md ├── chat │ ├── app.py │ └── openapi.json ├── example1 │ ├── README.md │ ├── app.py │ └── openapi.json ├── example2 │ ├── README.md │ ├── app.py │ └── openapi.json ├── example3 │ ├── README.md │ ├── app.py │ └── openapi.json └── openapi-notebook.ipynb ├── requirements.txt ├── voice-interaction ├── README.md └── assets │ └── 2024-03-11-17-10-13.png ├── watson-assistant ├── API-Test-WatsonX.ipynb ├── API-Watson.ipynb ├── README.md ├── actions │ ├── v1 │ │ └── action-skill.json │ └── v2 │ │ └── medical-bot-action-v2.json ├── api-notes.md ├── assets │ ├── 2024-02-22-16-25-12.png │ ├── 2024-02-23-16-56-55.png │ ├── 2024-02-23-17-14-57.png │ ├── 2024-03-11-18-54-49.png │ ├── 2024-03-11-18-56-03.png │ ├── 2024-03-11-19-00-33.png │ ├── 2024-03-11-19-01-23.png │ ├── 2024-03-11-19-04-10.png │ ├── 2024-03-11-19-05-24.png │ ├── 2024-03-11-19-07-16.png │ ├── 2024-03-11-19-07-46.png │ ├── 2024-03-11-19-10-23.png │ ├── 2024-03-11-19-12-25.png │ ├── 2024-03-11-19-14-07.png │ ├── 2024-03-12-10-21-43.png │ ├── 2024-03-12-17-23-04.png │ ├── 2024-03-12-17-23-58.png │ ├── 2024-03-12-17-26-24.png │ ├── 2024-03-12-17-28-25.png │ ├── 2024-03-12-17-31-51.png │ ├── 2024-03-12-17-33-44.png │ ├── 2024-03-12-17-49-55.png │ ├── 2024-03-12-17-50-43.png │ ├── 2024-03-12-17-53-09.png │ ├── 2024-03-13-08-56-44.png │ ├── 2024-03-13-10-30-17.png │ ├── 2024-03-13-10-30-20.png │ ├── 2024-03-13-12-03-45.png │ ├── 2024-03-13-12-04-57.png │ ├── 2024-03-13-12-06-02.png │ ├── 2024-03-13-12-06-39.png │ ├── 2024-03-13-12-12-27.png │ ├── 2024-03-13-12-38-17.png │ ├── 2024-03-13-12-39-05.png │ ├── 2024-03-13-12-39-23.png │ ├── 2024-03-13-12-42-14.png │ ├── 2024-03-13-12-42-46.png │ ├── 2024-03-13-12-43-13.png │ └── benchmark.png ├── gradio-beta.md └── setup-notebook.md └── webhook-integration ├── README.md └── assets ├── 2024-02-27-18-34-16.png ├── 2024-02-27-18-35-04.png ├── 2024-02-27-18-43-03.png ├── 2024-02-27-18-44-25.png └── 2024-02-27-18-49-57.png /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | backup/* 3 | venv/* 4 | .venv/ 5 | .env 6 | */.ipynb_checkpoints/* 7 | .ipynb_checkpoints* 8 | notebooks/.ipynb_checkpoints/0-Manage-VectorDatabase-checkpoint.ipynb 9 | notebooks/.ipynb_checkpoints/0-Manage-VectorDatabase-checkpoint.ipynb 10 | backend/.chroma/* 11 | cloud-function/wikipedia/__pycache__/app.cpython-310.pyc 12 | env.sh 13 | */backup/* 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Watsonx Assistant with Milvus as Vector Database 3 | Hello everyone, today We are going to build a WatsonX Assistant with Milvus as Vector Database. 4 | ![alt text](./assets/intro.png) 5 | # Introduction 6 | 7 | ![alt text](imagenx.png) 8 | 9 | 10 | In this blog, we will explore the development of a WatsonX Assistant that can engage in voice interactions and deliver responses using synthetic speech from Watsonx.ai within a Vector Database. This innovative solution harnesses the power of the latest artificial intelligence models, for retrieving questions. Specifically, we will delve into the integration of a Milvus Vector Database within a healthcare use case, creating a virtual assistant doctor for an enhanced patient experience. 11 | 12 | Milvus is a database designed to store, index, and manage massive embedding vectors generated by deep neural networks and other machine learning models. It is capable of indexing vectors on a trillion scale and is built to handle embedding vectors converted from unstructured data, which has become increasingly common with the growth of the internet. 13 | 14 | By calculating similarity distances between vectors, WatsonX.ai's Foundation Model analyzes the questions using the Augmented Knowledge Base created by Milvus. This process allows for the examination of correlations between original data sources. In our specific case, we have numerous questions and answers, and our goal is to identify the best answer for each given question. 15 | 16 | # Setup 17 | 18 | ## Step 1 - Creation of the Virtual Server 19 | 20 | First we need to install our Vector Database. The sytem where we want to deploy our database is Ubuntu 22.04. 21 | 1. Log in to your IBM Cloud account [here](https://cloud.ibm.com/). 22 | 2. From the IBM Cloud dashboard, click on the "Catalog" tab. 23 | 3. In the search bar, type `Virtual Servers` and select the "Virtual Servers" option from the results. 24 | 4. On the Virtual Servers page, you will find various options for virtual servers. 25 | Got to Image and Profile and click Change image and find for ubuntu and we choose 26 | `22.04 LTS Jammy Jellyfish Minimal Install` and click save 27 | ![](assets/2024-02-14-16-42-14.png) 28 | 5. Click on the chosen virtual server option to start configuring it. 29 | 6. On the configuration page, you will be prompted to provide various details like the location, CPU, memory, storage, and operating system. We choose the simplest `bx2-2x8` 30 | ![](assets/2024-02-14-16-49-31.png) 31 | 7. We create a ssh key with the name pem_ibmcloud and we download. 32 | 8. Complete the remaining configuration options as default, storage options and network settings with exception of adding a port open to connect it. 33 | 9. Once you have configured the instance, review the settings and click on the "Create" button to create the instance. 34 | 10. IBM Cloud will initiate the provisioning process, and your Ubuntu instance will be created. 35 | Copy the public ip of you virtual instance. 36 | 37 | ## Step 2 - Connection to the server 38 | 39 | Open an SSH client. 40 | 41 | Locate your private key file. The key used to launch this instance is private-key.pem 42 | Run this command, if necessary, to ensure your key is not publicly viewable. 43 | ``` 44 | chmod 400 "private-key.pem" 45 | ``` 46 | 47 | Connect to your instance using its Public ip: 48 | 49 | Example: 50 | ``` 51 | ssh -p 2223 -i private-key.pem itzuser@158.175.181.145 52 | ``` 53 | 54 | ## Step 3 - Install Milvus 55 | 56 | Install Milvus with dpkg on Ubuntu 57 | $ wget https://github.com/milvus-io/milvus/releases/download/v2.3.7/milvus_2.3.7-1_amd64.deb 58 | 59 | ``` 60 | sudo apt-get update 61 | sudo dpkg -i milvus_2.3.7-1_amd64.deb 62 | sudo apt-get -f install 63 | ``` 64 | ## Check the status of Milvus 65 | 66 | First you restart, 67 | ``` 68 | sudo systemctl restart milvus 69 | ``` 70 | there is not expected out, and then 71 | 72 | ``` 73 | sudo systemctl status milvus 74 | 75 | ``` 76 | ![](assets/2024-02-15-09-49-05.png) 77 | 78 | ### Testing Server 79 | 80 | First we assure that python3 is installed 81 | Add the deadsnakes PPA (might have Python 3.10) 82 | ``` 83 | sudo add-apt-repository -y ppa:deadsnakes/ppa 84 | ``` 85 | # Update package list again 86 | ``` 87 | sudo apt-get update 88 | ``` 89 | Install Python 3.10 90 | ``` 91 | sudo apt-get install -y python3.10 92 | sudo apt-get install -y python-pip 93 | sudo apt-get install python-is-python3 94 | ``` 95 | # Verify installation 96 | python --version 97 | We install some packages to test 98 | ``` 99 | pip install numpy pymilvus 100 | ``` 101 | Download hello_milvus.py directly or with the following command. 102 | ``` 103 | wget https://raw.githubusercontent.com/milvus-io/pymilvus/master/examples/hello_milvus.py 104 | 105 | ``` 106 | and then we proceed with the following actions 107 | 1. connect to Milvus 108 | 2. create collection 109 | 3. insert data 110 | 4. create index 111 | 5. search, query, and hybrid search on entities 112 | 6. delete entities by PK 113 | 7. drop collection 114 | 115 | you can visulaze the code [here](https://raw.githubusercontent.com/milvus-io/pymilvus/master/examples/hello_milvus.py) 116 | 117 | ``` 118 | python hello_milvus.py 119 | ``` 120 | the output is: 121 | 122 | ![](assets/2024-02-15-14-36-25.png) 123 | 124 | ## Port checking 125 | Finaly, we are interested to execute this application by usin the port `19530`. 126 | 127 | To check if port `19530` is open on your server, you can use a port scanning tool like `nmap` or `telnet`. Here are the steps to check the port status: 128 | Use the `telnet` command to check the port status. Run the following command in the terminal in the Server: 129 | ``` 130 | telnet 19530 131 | ``` 132 | Replace `` with the actual IP address of your server. If the port is open, you will see a connection established. If the port is closed or not reachable, the connection will fail. 133 | 134 | If you are unable to perform these checks you should open the inboud port of the server, you can add the source the server where you will use to make the query. 135 | 136 | 137 | # Milvus Embedding Client 138 | 139 | Let first check if our Server can be connected remotelly. 140 | Let deep dive the question Answering Demo Test [here](notebooks/README.md) 141 | # Creation the Assistant 142 | Once our Vector Database is running, we can continue to create our Assitant. 143 | First let us create our backend pipeline [here](backend/README.md) -------------------------------------------------------------------------------- /api/README.md: -------------------------------------------------------------------------------- 1 | https://cloud.ibm.com/docs/watson-assistant?topic=watson-assistant-webhook-overview -------------------------------------------------------------------------------- /api/client-api-test.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from gradio_client import Client\n", 10 | "client = Client(\"http://127.0.0.1:7861/\")\n", 11 | "result = client.predict(\n", 12 | "\t\t\"Howdy!\",\t# str in 'input' Textbox component\n", 13 | "\t\tapi_name=\"/predict\"\n", 14 | ")\n", 15 | "#print(result)\n", 16 | "# Read the JSON file\n", 17 | "import json\n", 18 | "with open(result, 'r') as f:\n", 19 | " data = json.load(f)\n", 20 | "# Convert the list to a dictionary\n", 21 | "data_dict = {\"message\": data['message']}\n", 22 | "# Print the content of the dictionary\n", 23 | "output_json=json.dumps(data_dict, indent=2)\n", 24 | "print(output_json) \n" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "def api_request(url):\n", 34 | " import requests\n", 35 | " response = requests.get(url)\n", 36 | " if response.status_code == 200:\n", 37 | " return response.json()\n", 38 | " else:\n", 39 | " print(response.text) # Print the error message for debugging\n", 40 | " return f\"Error: {response.status_code}\"" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": null, 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "url=\"http://127.0.0.1:7861/predict?input=Hello\"" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "api_request(url)" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": null, 64 | "metadata": {}, 65 | "outputs": [], 66 | "source": [ 67 | "from gradio import Interface, Textbox, JSON\n", 68 | "\n", 69 | "def api_request(url):\n", 70 | " import requests\n", 71 | " response = requests.get(url)\n", 72 | " if response.status_code == 200:\n", 73 | " return response.json()\n", 74 | " else:\n", 75 | " return f\"Error: {response.status_code}\"\n", 76 | "\n", 77 | "interface = Interface(\n", 78 | " fn=api_request,\n", 79 | " inputs=[Textbox(label=\"API URL\")],\n", 80 | " outputs=[JSON(label=\"JSON Response\")],\n", 81 | " title=\"API Get Request Tester\",\n", 82 | " description=\"Enter an API URL and retrieve the JSON response.\",\n", 83 | " examples=[[\"http://127.0.0.1:7861/predict?input=Hello\"],\n", 84 | " [\"https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41¤t=temperature_2m,wind_speed_10m&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m\"]], # Use the correct endpoint\n", 85 | ")\n", 86 | "interface.launch(debug=True)\n" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [ 95 | "from gradio import Interface, Textbox, JSON\n", 96 | "\n", 97 | "def api_request(url):\n", 98 | " import requests\n", 99 | " response = requests.get(url)\n", 100 | " if response.status_code == 200:\n", 101 | " return response.json()\n", 102 | " else:\n", 103 | " return f\"Error: {response.status_code}\"\n", 104 | "\n", 105 | "interface = Interface(\n", 106 | " fn=api_request,\n", 107 | " inputs=[Textbox(label=\"API URL\")],\n", 108 | " outputs=[JSON(label=\"JSON Response\")],\n", 109 | " title=\"API Get Request Tester\",\n", 110 | " description=\"Enter an API URL and retrieve the JSON response.\",\n", 111 | " examples=[[\"http://127.0.0.1:7861/?text=Hello\"],\n", 112 | " [\"https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41¤t=temperature_2m,wind_speed_10m&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m\"]], # Use the correct endpoint\n", 113 | ")\n", 114 | "interface.launch()\n" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": null, 120 | "metadata": {}, 121 | "outputs": [], 122 | "source": [ 123 | "from gradio import Interface, Textbox, JSON\n", 124 | "\n", 125 | "def api_request(url):\n", 126 | " \"\"\"\n", 127 | " Fetches the JSON response from the given URL using a GET request.\n", 128 | " \"\"\"\n", 129 | " import requests\n", 130 | " response = requests.get(url)\n", 131 | " if response.status_code == 200:\n", 132 | " return response.json()\n", 133 | " else:\n", 134 | " return f\"Error: {response.status_code}\"\n", 135 | "\n", 136 | "# Define the Gradio interface\n", 137 | "interface = Interface(\n", 138 | " fn=api_request,\n", 139 | " inputs=[Textbox(label=\"API URL\")],\n", 140 | " outputs=[JSON(label=\"JSON Response\")],\n", 141 | " title=\"API Get Request Tester\",\n", 142 | " description=\"Enter an API URL and retrieve the JSON response.\",\n", 143 | " examples=[]\n", 144 | ")\n", 145 | "# Launch the web interface\n", 146 | "interface.launch()" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": null, 152 | "metadata": {}, 153 | "outputs": [], 154 | "source": [] 155 | } 156 | ], 157 | "metadata": { 158 | "kernelspec": { 159 | "display_name": ".venv", 160 | "language": "python", 161 | "name": "python3" 162 | }, 163 | "language_info": { 164 | "codemirror_mode": { 165 | "name": "ipython", 166 | "version": 3 167 | }, 168 | "file_extension": ".py", 169 | "mimetype": "text/x-python", 170 | "name": "python", 171 | "nbconvert_exporter": "python", 172 | "pygments_lexer": "ipython3", 173 | "version": "3.10.12" 174 | } 175 | }, 176 | "nbformat": 4, 177 | "nbformat_minor": 2 178 | } 179 | -------------------------------------------------------------------------------- /api/server-api-test.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import gradio as gr\n", 10 | "def hello_world(input):\n", 11 | " output = {\"message\": f\"Hello World, {input}\"}\n", 12 | " return output # Gradio automatically handles JSON encoding\n", 13 | "\n", 14 | "iface = gr.Interface(\n", 15 | " fn=hello_world,\n", 16 | " inputs=[\"text\"], # Use a list for inputs\n", 17 | " outputs=\"json\",\n", 18 | " title=\"Hello World App\",\n", 19 | " description=\"Type a string to append to the 'Hello World' prompt.\",\n", 20 | " allow_flagging=\"never\", # Prevent flagging since this is a local server\n", 21 | ")\n", 22 | "iface.launch(share=False, server_name=\"127.0.0.1\", server_port=7861)\n" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "import gradio as gr\n", 32 | "\n", 33 | "def hello_world(input):\n", 34 | " output = {\"message\": f\"Hello World, {input}\"}\n", 35 | " return output # Gradio automatically handles JSON encoding\n", 36 | "\n", 37 | "iface = gr.Interface(\n", 38 | " fn=hello_world,\n", 39 | " inputs=[\"text\"], # Use a list for inputs\n", 40 | " outputs=\"json\",\n", 41 | " title=\"Hello World App\",\n", 42 | " description=\"Type a string to append to the 'Hello World' prompt.\",\n", 43 | " allow_flagging=\"never\", # Prevent flagging since this is a local server\n", 44 | ")\n", 45 | "iface.launch(share=False, server_name=\"0.0.0.0\", server_port=7861)\n" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "import gradio as gr\n", 55 | "\n", 56 | "def hello_world(input):\n", 57 | " output = {\"message\": f\"Hello World, {input}\"}\n", 58 | " return output # Gradio handles JSON encoding\n", 59 | "\n", 60 | "iface = gr.Interface(\n", 61 | " fn=hello_world,\n", 62 | " inputs=[gr.Textbox(lines=1)], # Use gr.Textbox for input\n", 63 | " outputs=gr.JSON(label=\"JSON Response\"), # Use gr.JSON for output\n", 64 | " title=\"Hello World App\",\n", 65 | " description=\"Type a string to append to the 'Hello World' prompt.\",\n", 66 | ")\n", 67 | "iface.launch(share=False, server_name=\"0.0.0.0\", server_port=7861) # Enable sharing\n" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": null, 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [ 76 | "import gradio as gr\n", 77 | "def hello_world(input):\n", 78 | " output = {\"message\": f\"Hello World, {input}\"}\n", 79 | " return output # Return the output as a dictionary, Gradio handles JSON encoding\n", 80 | "\n", 81 | "iface = gr.Interface(\n", 82 | " fn=hello_world, # Pass the function directly without json.dumps\n", 83 | " inputs=[\"text\"], # Use a list for inputs\n", 84 | " outputs=\"json\",\n", 85 | " title=\"Hello World App\",\n", 86 | " description=\"Type a string to append to the 'Hello World' prompt.\"\n", 87 | "\n", 88 | ")\n", 89 | "iface.launch(share=False, server_name=\"0.0.0.0\", server_port=7861)\n" 90 | ] 91 | } 92 | ], 93 | "metadata": { 94 | "kernelspec": { 95 | "display_name": ".venv", 96 | "language": "python", 97 | "name": "python3" 98 | }, 99 | "language_info": { 100 | "codemirror_mode": { 101 | "name": "ipython", 102 | "version": 3 103 | }, 104 | "file_extension": ".py", 105 | "mimetype": "text/x-python", 106 | "name": "python", 107 | "nbconvert_exporter": "python", 108 | "pygments_lexer": "ipython3", 109 | "version": "3.10.12" 110 | } 111 | }, 112 | "nbformat": 4, 113 | "nbformat_minor": 2 114 | } 115 | -------------------------------------------------------------------------------- /assets/2024-02-14-16-42-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/assets/2024-02-14-16-42-14.png -------------------------------------------------------------------------------- /assets/2024-02-14-16-49-31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/assets/2024-02-14-16-49-31.png -------------------------------------------------------------------------------- /assets/2024-02-15-09-49-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/assets/2024-02-15-09-49-05.png -------------------------------------------------------------------------------- /assets/2024-02-15-14-36-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/assets/2024-02-15-14-36-25.png -------------------------------------------------------------------------------- /assets/intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/assets/intro.png -------------------------------------------------------------------------------- /backend/README.md: -------------------------------------------------------------------------------- 1 | # Building WatsonX.ai API for Watson Assistant 2 | 3 | We are going to build the API for Watson Assistant. 4 | 5 | To developing purposes, let us install Jupyter notebook. 6 | 7 | First let us activate our environment 8 | 9 | ``` 10 | source .venv/bin/activate 11 | ``` 12 | 13 | ``` 14 | pip install ipykernel notebook 15 | ``` 16 | 17 | ``` 18 | python3 -m ipykernel install --user --name LLM --display-name "Python (watsonx)" 19 | ``` 20 | 21 | ``` 22 | pip install python-dotenv pymilvus 23 | ``` 24 | 25 | Then, create a .env file in your project directory with the following content: 26 | ``` 27 | REMOTE_SERVER=my_host_value 28 | ``` 29 | Replace "my_host_value" with the desired value for the "REMOTE_SERVER" environment variable. 30 | 31 | and then just we ran 32 | 33 | ``` 34 | jupyter notebook 35 | ``` -------------------------------------------------------------------------------- /backend/id_answer.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/backend/id_answer.pkl -------------------------------------------------------------------------------- /backend/requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.9.3 2 | aiosignal==1.3.1 3 | annotated-types==0.6.0 4 | anyio==3.7.1 5 | argon2-cffi==23.1.0 6 | argon2-cffi-bindings==21.2.0 7 | asttokens==2.4.1 8 | async-timeout==4.0.3 9 | attrs==23.2.0 10 | backoff==2.2.1 11 | beautifulsoup4==4.12.3 12 | bs4==0.0.2 13 | certifi==2024.2.2 14 | cffi==1.16.0 15 | charset-normalizer==3.3.2 16 | chromadb==0.3.22 17 | click==8.1.7 18 | clickhouse-connect==0.7.0 19 | comm==0.2.1 20 | dataclasses-json==0.6.4 21 | debugpy==1.8.1 22 | decorator==5.1.1 23 | duckdb==0.10.0 24 | environs==9.5.0 25 | exceptiongroup==1.2.0 26 | executing==2.0.1 27 | fastapi==0.109.2 28 | filelock==3.13.1 29 | frozenlist==1.4.1 30 | fsspec==2024.2.0 31 | greenlet==3.0.3 32 | grpcio==1.60.0 33 | h11==0.14.0 34 | hnswlib==0.8.0 35 | httptools==0.6.1 36 | huggingface-hub==0.20.3 37 | ibm-cos-sdk==2.13.4 38 | ibm-cos-sdk-core==2.13.4 39 | ibm-cos-sdk-s3transfer==2.13.4 40 | ibm-watson-machine-learning==1.0.347 41 | idna==3.6 42 | importlib-metadata==7.0.1 43 | ipykernel==6.29.2 44 | ipython==8.21.0 45 | ipywidgets==8.1.2 46 | jedi==0.19.1 47 | Jinja2==3.1.3 48 | jmespath==1.0.1 49 | joblib==1.3.2 50 | jsonpatch==1.33 51 | jsonpointer==2.4 52 | jupyter_client==8.6.0 53 | jupyter_core==5.7.1 54 | jupyterlab_widgets==3.0.10 55 | langchain==0.0.345 56 | langchain-core==0.0.13 57 | langsmith==0.0.92 58 | lomond==0.3.3 59 | lz4==4.3.3 60 | MarkupSafe==2.1.5 61 | marshmallow==3.20.2 62 | matplotlib-inline==0.1.6 63 | minio==7.2.4 64 | monotonic==1.6 65 | mpmath==1.3.0 66 | multidict==6.0.5 67 | mypy-extensions==1.0.0 68 | nest-asyncio==1.6.0 69 | networkx==3.2.1 70 | nltk==3.8.1 71 | numpy==1.26.4 72 | nvidia-cublas-cu12==12.1.3.1 73 | nvidia-cuda-cupti-cu12==12.1.105 74 | nvidia-cuda-nvrtc-cu12==12.1.105 75 | nvidia-cuda-runtime-cu12==12.1.105 76 | nvidia-cudnn-cu12==8.9.2.26 77 | nvidia-cufft-cu12==11.0.2.54 78 | nvidia-curand-cu12==10.3.2.106 79 | nvidia-cusolver-cu12==11.4.5.107 80 | nvidia-cusparse-cu12==12.1.0.106 81 | nvidia-nccl-cu12==2.19.3 82 | nvidia-nvjitlink-cu12==12.3.101 83 | nvidia-nvtx-cu12==12.1.105 84 | packaging==23.2 85 | pandas==1.5.3 86 | parso==0.8.3 87 | pexpect==4.9.0 88 | pillow==10.2.0 89 | platformdirs==4.2.0 90 | posthog==3.4.1 91 | prompt-toolkit==3.0.43 92 | protobuf==4.25.3 93 | psutil==5.9.8 94 | ptyprocess==0.7.0 95 | pure-eval==0.2.2 96 | pyarrow==15.0.0 97 | pycparser==2.21 98 | pycryptodome==3.20.0 99 | pydantic==1.10.14 100 | pydantic_core==2.16.2 101 | Pygments==2.17.2 102 | pymilvus==2.3.6 103 | python-dateutil==2.8.2 104 | python-dotenv==1.0.1 105 | pytz==2024.1 106 | PyYAML==6.0.1 107 | pyzmq==25.1.2 108 | regex==2023.12.25 109 | requests==2.31.0 110 | safetensors==0.4.2 111 | scikit-learn==1.4.1.post1 112 | scipy==1.12.0 113 | sentence-transformers==2.3.1 114 | sentencepiece==0.2.0 115 | six==1.16.0 116 | sniffio==1.3.0 117 | soupsieve==2.5 118 | SQLAlchemy==2.0.27 119 | stack-data==0.6.3 120 | starlette==0.36.3 121 | sympy==1.12 122 | tabulate==0.9.0 123 | tenacity==8.2.3 124 | threadpoolctl==3.3.0 125 | tokenizers==0.15.2 126 | torch==2.2.0 127 | tornado==6.4 128 | tqdm==4.66.2 129 | traitlets==5.14.1 130 | transformers==4.37.2 131 | triton==2.2.0 132 | typing-inspect==0.9.0 133 | typing_extensions==4.9.0 134 | tzdata==2024.1 135 | ujson==5.9.0 136 | urllib3==2.1.0 137 | uvicorn==0.27.1 138 | uvloop==0.19.0 139 | watchfiles==0.21.0 140 | wcwidth==0.2.13 141 | websockets==12.0 142 | wget==3.2 143 | widgetsnbextension==4.0.10 144 | yarl==1.9.4 145 | zipp==3.17.0 146 | zstandard==0.22.0 147 | -------------------------------------------------------------------------------- /cloud-function/README.md: -------------------------------------------------------------------------------- 1 | # Serverless Cloud-Function 2 | 3 | We are building a simple serverless cloud function application . 4 | 5 | # Example 1 - Wikipedia 6 | In ordering to build our Medical Chatbot, let us first build a simple example, to build a serverless application that answer questions based on the api of wikipedia. 7 | A detailed process to build and follow this [link](./README.md) 8 | -------------------------------------------------------------------------------- /cloud-function/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | requests -------------------------------------------------------------------------------- /cloud-function/wikipedia/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Python 3.11 image as the base image 2 | FROM python:3.11 3 | 4 | # Set the working directory 5 | WORKDIR /app 6 | 7 | # Copy the requirements file into the container 8 | COPY requirements.txt . 9 | 10 | # Install dependencies 11 | RUN pip install --no-cache-dir -r requirements.txt 12 | 13 | # Copy the rest of the application code 14 | COPY . . 15 | 16 | # Expose the port the app will run on 17 | EXPOSE 8080 18 | 19 | # Run the Flask command to start the app 20 | CMD ["flask", "run", "-h", "0.0.0.0", "-p", "8080"] 21 | -------------------------------------------------------------------------------- /cloud-function/wikipedia/README.md: -------------------------------------------------------------------------------- 1 | # Serverless Cloud Function Example - Wikipedia 2 | 3 | First we enter the directory of wikipedia 4 | ### Build the Docker image: 5 | ``` 6 | docker build -t my-cloud-function . 7 | ``` 8 | ### Run the container: 9 | 10 | ``` 11 | docker run -p 8080:8080 my-cloud-function 12 | ``` 13 | 14 | ### How to use 15 | Send a POST request to http://localhost:8080/cloud-function with the following JSON data: 16 | 17 | ```JSON 18 | { 19 | "object_of_interest": "Gravity" 20 | } 21 | ``` 22 | 23 | The server will respond with a JSON object containing the extracted Wikipedia summary for "Gravity". 24 | 25 | This is just a basic example, and you can customize the code further based on your specific needs. For example, you could add error handling, authentication, and additional features to your cloud function. 26 | 27 | ## Local test 28 | You can just test the app.py by typing 29 | ``` 30 | flask run -h 0.0.0.0 -p 8080 31 | ``` 32 | then you can execute 33 | 34 | ``` 35 | python test.py 36 | ``` 37 | and you will get 38 | 39 | ![](assets/2024-02-24-11-51-24.png) 40 | so this local function is working. 41 | Additional test might done [here](test.md) 42 | 43 | -------------------------------------------------------------------------------- /cloud-function/wikipedia/app.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | from flask import Flask, request, jsonify 4 | app = Flask(__name__) 5 | 6 | @app.route('/cloud-function', methods=['POST']) 7 | def main(): 8 | """Retrieves and summarizes Wikipedia information based on the provided object of interest. 9 | 10 | This function handles POST requests with a JSON payload containing the `object_of_interest` key. 11 | It fetches the Wikipedia summary for the specified object and returns it as a JSON response. 12 | 13 | Returns: 14 | A JSON response containing the summary or an error message if unsuccessful. 15 | """ 16 | 17 | if request.content_type != 'application/json': 18 | return jsonify({"message": "Invalid content type. Expected application/json"}), 400 19 | 20 | try: 21 | params = request.get_json() 22 | object_of_interest = params.get('object_of_interest') 23 | 24 | if not object_of_interest: 25 | return jsonify({"message": "Missing 'object_of_interest' parameter"}), 400 26 | 27 | url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{object_of_interest}?redirect=true" 28 | headers = {'accept': 'application/json'} 29 | response = requests.get(url, headers=headers) 30 | 31 | if response.status_code != 200: 32 | return jsonify({"message": f"Error fetching Wikipedia summary: {response.status_code}"}), response.status_code 33 | 34 | data = response.json() 35 | summary = data.get('extract') 36 | 37 | if not summary: 38 | return jsonify({"message": "No summary found for the specified object of interest"}), 404 39 | 40 | return jsonify({"summary": summary}), 200 41 | except Exception as e: 42 | return jsonify({"message": f"An error occurred: {e}"}), 500 43 | if __name__ == '__main__': 44 | app.run(host='0.0.0.0', port=8080, debug=True) -------------------------------------------------------------------------------- /cloud-function/wikipedia/assets/2024-02-24-11-51-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/cloud-function/wikipedia/assets/2024-02-24-11-51-24.png -------------------------------------------------------------------------------- /cloud-function/wikipedia/backup/v1/app.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | from flask import Flask, request, jsonify 4 | 5 | app = Flask(__name__) 6 | 7 | @app.route('/cloud-function', methods=['POST']) 8 | def main(): 9 | params = request.get_json() 10 | object_of_interest = params.get('object_of_interest') 11 | 12 | if not object_of_interest: 13 | return jsonify({"message": "Missing 'object_of_interest' parameter"}), 400 14 | 15 | url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{object_of_interest}?redirect=true" 16 | headers = {'accept': 'application/json'} 17 | r = requests.get(url, headers=headers) 18 | 19 | if r.status_code != 200: 20 | return jsonify({"message": "Error fetching Wikipedia summary"}), r.status_code 21 | 22 | data = json.loads(r.content) 23 | summary = data.get('extract') 24 | 25 | return jsonify({"summary": summary}), 200 26 | 27 | if __name__ == '__main__': 28 | app.run(debug=True) 29 | -------------------------------------------------------------------------------- /cloud-function/wikipedia/backup/v1/test.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | # Replace with your cloud function URL 4 | URL = "http://localhost:8080/cloud-function" 5 | 6 | # Replace with your desired object of interest 7 | object_of_interest = "Artificial Intelligence" 8 | 9 | # Build the payload 10 | payload = {"object_of_interest": object_of_interest} 11 | 12 | # Send the POST request 13 | response = requests.post(URL, json=payload) 14 | 15 | # Check the response status code 16 | if response.status_code == 200: 17 | # Parse the JSON response 18 | data = response.json() 19 | summary = data.get("summary") 20 | print(f"Wikipedia summary for '{object_of_interest}':\n{summary}") 21 | else: 22 | print(f"Error: {response.status_code} - {response.text}") -------------------------------------------------------------------------------- /cloud-function/wikipedia/backup/v2/app.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/cloud-function/wikipedia/backup/v2/app.py -------------------------------------------------------------------------------- /cloud-function/wikipedia/backup/v3/app.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | from flask import Flask, request, jsonify 4 | 5 | app = Flask(__name__) 6 | 7 | @app.route('/cloud-function', methods=['POST']) 8 | def main(): 9 | params = request.get_json() 10 | object_of_interest = params.get('object_of_interest') 11 | 12 | if not object_of_interest: 13 | return jsonify({"message": "Missing 'object_of_interest' parameter"}), 400 14 | 15 | response_data = {"object_of_interest": object_of_interest} 16 | 17 | try: 18 | url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{object_of_interest}?redirect=true" 19 | headers = {'accept': 'application/json'} 20 | response = requests.get(url, headers=headers) 21 | response.raise_for_status() 22 | 23 | data = json.loads(response.content) 24 | summary = data.get('extract') 25 | response_data["summary"] = summary 26 | 27 | except requests.exceptions.RequestException as e: 28 | response_data["message"] = f"Error fetching Wikipedia summary: {str(e)}" 29 | 30 | return jsonify(response_data), 200 31 | 32 | if __name__ == '__main__': 33 | app.run(host='0.0.0.0', port=8080, debug=True) 34 | -------------------------------------------------------------------------------- /cloud-function/wikipedia/backup/v4/wiki.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | from flask import Flask, request, jsonify 4 | 5 | app = Flask(__name__) 6 | 7 | @app.route('/cloud-function', methods=['POST']) 8 | def main(): 9 | """Retrieves and summarizes Wikipedia information based on the provided object of interest. 10 | 11 | This function handles POST requests with a JSON payload containing the `object_of_interest` key. 12 | It fetches the Wikipedia summary for the specified object and returns it as a JSON response. 13 | 14 | Returns: 15 | A JSON response containing the summary or an error message if unsuccessful. 16 | """ 17 | 18 | if request.content_type != 'application/json': 19 | return jsonify({"message": "Invalid content type. Expected application/json"}), 400 20 | 21 | try: 22 | params = request.get_json() 23 | object_of_interest = params.get('object_of_interest') 24 | 25 | if not object_of_interest: 26 | return jsonify({"message": "Missing 'object_of_interest' parameter"}), 400 27 | 28 | url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{object_of_interest}?redirect=true" 29 | headers = {'accept': 'application/json'} 30 | response = requests.get(url, headers=headers) 31 | 32 | if response.status_code != 200: 33 | return jsonify({"message": f"Error fetching Wikipedia summary: {response.status_code}"}), response.status_code 34 | 35 | data = response.json() 36 | summary = data.get('extract') 37 | 38 | if not summary: 39 | return jsonify({"message": "No summary found for the specified object of interest"}), 404 40 | 41 | return jsonify({"summary": summary}), 200 42 | 43 | except Exception as e: 44 | return jsonify({"message": f"An error occurred: {e}"}), 500 45 | 46 | if __name__ == '__main__': 47 | app.run(host='0.0.0.0', port=8080, debug=True) -------------------------------------------------------------------------------- /cloud-function/wikipedia/run.bat: -------------------------------------------------------------------------------- 1 | flask run -h 0.0.0.0 -p 8080 -------------------------------------------------------------------------------- /cloud-function/wikipedia/test.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ### Bash Linux Ubuntu 22.04 5 | ``` 6 | curl --request POST --url "http://localhost:8080/cloud-function" --header "Content-Type: application/json" --header "accept: application/json" --data '{"object_of_interest": "Artificial Intelligence"}' 7 | ``` 8 | 9 | ### Command Prompt - Windows 11 10 | ``` 11 | curl --request POST --url "http://localhost:8080/cloud-function" --header "Content-Type: application/json" --header "accept: application/json" --data "{\"object_of_interest\": \"Artificial Intelligence\"}" 12 | ``` 13 | 14 | ### Power Shell - Windows 11 15 | ``` 16 | Invoke-WebRequest -Method POST -Uri 'http://localhost:8080/cloud-function' -ContentType 'application/json' -Body '{"object_of_interest": "Artificial Intelligence"}' 17 | ``` 18 | 19 | ``` 20 | .\test.ps1 21 | 22 | ``` 23 | ### Python 24 | python test.py -------------------------------------------------------------------------------- /cloud-function/wikipedia/test.ps1: -------------------------------------------------------------------------------- 1 | # Specify the URL and data 2 | $url = 'http://localhost:8080/cloud-function' 3 | $data = '{"object_of_interest": "Artificial Intelligence"}' 4 | 5 | # Send the POST request 6 | $response = Invoke-WebRequest -Method POST -Uri $url -ContentType 'application/json' -Body $data 7 | 8 | # Display the response 9 | Write-Output $response 10 | -------------------------------------------------------------------------------- /cloud-function/wikipedia/test.py: -------------------------------------------------------------------------------- 1 | import requests 2 | # Replace with your cloud function URL 3 | URL = "http://localhost:8080/cloud-function" 4 | # Replace with your desired object of interest 5 | object_of_interest = "Artificial Intelligence" 6 | # Build the payload 7 | payload = {"object_of_interest": object_of_interest} 8 | # Send the POST request 9 | response = requests.post(URL, json=payload) 10 | # Check the response status code 11 | if response.status_code == 200: 12 | # Parse the JSON response 13 | data = response.json() 14 | summary = data.get("summary") 15 | print(f"Wikipedia summary for '{object_of_interest}':\n{summary}") 16 | else: 17 | print(f"Error: {response.status_code} - {response.text}") -------------------------------------------------------------------------------- /cloud-function/wikipedia/test.sh: -------------------------------------------------------------------------------- 1 | #* Running on all addresses (0.0.0.0) 2 | #* Running on http://127.0.0.1:8080 3 | #* Running on http://192.168.1.188:8080 4 | 5 | echo "Test1" 6 | curl --request POST \ 7 | --url 'http://localhost:8080/cloud-function' \ 8 | --header 'accept: application/json' \ 9 | --data '{"object_of_interest": "Artificial Intelligence"}' 10 | 11 | echo "Test2" 12 | 13 | curl --request POST \ 14 | --url 'http://localhost:8080/cloud-function' \ 15 | --header 'accept: application/json' \ 16 | --data '{"object_of_interest": "Artificial Intelligence"}' 17 | 18 | 19 | echo "Test3" 20 | 21 | curl -X POST \ 22 | -H "Content-Type: application/json" \ 23 | -d '{"object_of_interest": "Artificial Intelligence"}' \ 24 | http://localhost:8080/cloud-function 25 | 26 | echo "Test4" 27 | 28 | curl --request POST \ 29 | --url 'http://127.0.0.1:8080/cloud-function' \ 30 | --header 'accept: application/json' \ 31 | --data '{"object_of_interest": "Artificial Intelligence"}' 32 | -------------------------------------------------------------------------------- /code-engine/README.md: -------------------------------------------------------------------------------- 1 | # Code Engine Application 2 | 3 | In ordering to run our API for WatsonX.ai we need to create a serverless application. 4 | 5 | We can use Code Engine as example to run our application. 6 | 7 | # By using the Console 8 | First we go to Secrets and configmaps 9 | ![](assets/2024-02-22-17-50-52.png) 10 | ![](assets/2024-02-22-17-52-36.png) 11 | We create a `docker-hub-secrets` where we indicate our credentials to acces to our docker server. 12 | ![](assets/2024-02-23-11-43-31.png) 13 | Additionally we need to define the `Secret (generic)` 14 | we we define our secrets keys used for the enviroment in the docker container 15 | ![](assets/2024-02-23-12-00-45.png) 16 | 17 | Finally we can create an application 18 | we choose the `Container image` we give a name like for example `watsonx-medical` 19 | 20 | and we click configure image, and we full fill with our previos `docker-hubs-secrets created` before 21 | 22 | ![](assets/2024-02-23-12-03-04.png) 23 | 24 | For rersource and scaling we use 25 | ![](assets/2024-02-23-12-05-08.png) 26 | 27 | It is important that our application should have 16 gb of ram and also min number of instances 1, becasue it load the model of encoding, if becomes zero should start download from zero. 28 | 29 | Then we add the enviroment variables just created 30 | ![](assets/2024-02-23-12-09-02.png) 31 | 32 | then we add the listeing port `7860` 33 | ![](assets/2024-02-23-12-10-22.png) 34 | 35 | Note if we are using the container-api version we should use port `8080`. 36 | And finally click in create 37 | ![](assets/2024-02-22-18-55-09.png) 38 | Then we can see the app is deployed and running 39 | ![](assets/2024-02-23-11-41-13.png) 40 | 41 | Once the application is created and deployes we can check our Image that was to run 42 | ![](assets/2024-02-22-19-35-38.png) 43 | 44 | Finally we can make questions to our Medical Bot 45 | ![](assets/2024-02-22-19-35-13.png) 46 | 47 | # By using IBM CLI 48 | 49 | Step 1 - Connect bucket to Code Engine Application 50 | Login to Code Engine First we need to login to our account that has the Code Engine enabeled. 51 | 52 | ``` 53 | ibmcloud login -sso 54 | ``` 55 | 56 | Install the IBM Cloud Code Engine plugin: 57 | 58 | ``` 59 | ibmcloud plugin install code-engine 60 | ``` 61 | Choose the resource group targeted. 62 | For example you can retrieve it by clicking Manage > Account > Resource groups 63 | 64 | ![](assets/2024-02-22-17-33-52.png) 65 | 66 | 67 | 68 | Run `ibmcloud target -g RESOURCE_GROUP_NAME`, for example 69 | 70 | ``` 71 | ibmcloud target -g cc-6670df0nwl8-ug0jk8nz 72 | 73 | ``` 74 | 75 | First, list the available regions using the following command: 76 | ``` 77 | ibmcloud regions 78 | ``` 79 | ![](assets/2024-02-22-17-07-03.png) 80 | This command will display a list of available regions and their respective endpoints. 81 | 82 | Next, set the desired region using the `ibmcloud target` command with the `--region` flag. Replace `` with the desired region from the list of available regions: 83 | ``` 84 | ibmcloud target --region 85 | ``` 86 | For example, to set the region to `us-south`, run: 87 | ``` 88 | ibmcloud target --r us-south 89 | ``` 90 | 91 | Confirm that the region has been changed by running the following command: 92 | ``` 93 | ibmcloud target 94 | ``` 95 | This command will display the current target region, organization, and space. 96 | 97 | ### Create a Code Engine project 98 | 99 | ``` 100 | ibmcloud ce project create --name watsonx-medical-project 101 | ``` 102 | Set the current project context 103 | 104 | ``` 105 | ibmcloud ce project select -n watsonx-medical-project 106 | ``` 107 | or also you can choose it by id 108 | 109 | ``` 110 | ibmcloud ce project select --id 349bb3bc-482a-4b6e-a226-e5ee6f29ef9c 111 | ``` 112 | 113 | 114 | We have to create the Registry Container 115 | 116 | ## For IBM Cloud Container 117 | If you want to to load your container from the IBM Cloud you can type the following command 118 | 119 | 120 | ``` 121 | ibmcloud ce secret create --format registry --name watsonx-medical-registry --server icr.io --username iamapikey --password YOUR_API_KEY 122 | ``` 123 | 124 | 125 | ## For Docker Container 126 | 127 | If you want to load your Docker Container from Docker site, we setup the Docker credentials in the Code Engine 128 | 129 | ``` 130 | ibmcloud ce secret create --format registry --name my-docker-registry --server https://index.docker.io/v1/ --username YOUR_USERNAME --password YOUR_PASSWORD 131 | ``` 132 | ### Secrets and configmaps 133 | It is possible to use the ‘Secret’ object in Code Engine to store sensitive information for connection in a secure way. 134 | 135 | ``` 136 | ibmcloud code-engine secret create --name bucket-secret --from-env-file secrets.env 137 | ``` 138 | 139 | In the project’s dashboard navigate to ‘Secret and Configmap’ and create a Secret you will have something like 140 | 141 | You can see the secret This will be store in a key:value format. 142 | 143 | After that it is possible to create the application and, in the environment variable section, connect the application to the secret. The application can now access the data with the standard API for environment variables. 144 | 145 | Create the Code Engine application using the image from IBM Cloud Container Registry. To create an application in IBM Cloud Code Engine with the previously created secrets 146 | 147 | ### Create application from IBM Cloud Container 148 | To create an application in IBM Cloud Code Engine using an image from IBM Cloud Container Registry and the previously created secrets, you can modify the command as follows: 149 | 150 | ``` 151 | ibmcloud code-engine application create --name watsonx-medical --image icr.io/watsonx-medical-namespace/watsonx-medical:latest --port 7860 --env-from-secret bucket-secret --registry-secret watsonx-medical-registry 152 | ``` 153 | In this command: 154 | 155 | 156 | watsonx-medical is the name you want to give to your application. 157 | `icr.io/watsonx-medical-namespace/watsonx-medical:latest` is the image reference for your application. The watsonx-medical-namespace is the namespace with the image tag latest . 158 | 8501 is the port on which your application will listen. 159 | 160 | `--env-from-secret bucket-secret` specifies the secret you previously created (bucket-secret) to be used as environment variables for your application. 161 | 162 | `--registry-secret watsonx-medical-registry` specifies the name of the registry secret watsonx-medical-registry that contains the credentials for accessing the container registry. 163 | By providing the --registry-secret flag, you are ensuring that the necessary credentials are available to access the container registry where the image is stored. 164 | 165 | Create Application from Docker 166 | If you want to create the application form the Docker Container 167 | ``` 168 | ibmcloud code-engine application create --name watsonx-medical --image docker.io/ruslanmv/watsonx-medical:latest --port 8501 --env-from-secret bucket-secret --registry-secret my-docker-registry 169 | ``` 170 | After you typed the previous command you have created your app. 171 | 172 | For example my case is the url of the app is 173 | ``` 174 | https://watsonx-medical-api.1doe5vsg6flg.us-south.codeengine.appdomain.cloud/ 175 | 176 | ``` 177 | 178 | ## Contianer Gradio version 179 | 180 | You can open this application on your web browser 181 | 182 | ![](assets/2024-02-22-19-35-13.png) 183 | 184 | 185 | ## Container-Api version 186 | 187 | If you are using this version so simply you can test it by oppening the [openapi.json](./openapi.json) and add the appropiate url 188 | 189 | ![](assets/2024-03-11-16-57-05.png) 190 | 191 | then test it by typing 192 | ``` 193 | python ./code-engine/api-test.py 194 | ``` 195 | 196 | will get the following response 197 | 198 | ![](assets/2024-03-11-17-03-25.png) 199 | 200 | Additionally you can monitor your application in Code Engine 201 | 202 | ![](assets/2024-03-11-17-05-03.png) -------------------------------------------------------------------------------- /code-engine/api-test.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | import os 4 | # get the current working directory 5 | current_working_directory = os.getcwd() 6 | # Join various path components 7 | openapi_path=os.path.join(current_working_directory,"code-engine", "openapi.json") 8 | print(openapi_path) 9 | # Load the openapi.json file 10 | with open(openapi_path, 'r') as file: 11 | openapi_data = json.load(file) 12 | 13 | # Get the base URL of the API from the openapi.json file 14 | base_url = openapi_data['servers'][0]['url'] 15 | 16 | # Define a function to test a specific API endpoint 17 | def test_endpoint(endpoint, method, parameters=None, data=None): 18 | url = f"{base_url}{endpoint}" 19 | response = requests.request(method, url, params=parameters, json=data) 20 | if response.status_code == 200: 21 | print(f"API endpoint '{endpoint}' is working well.") 22 | else: 23 | print(f"API endpoint '{endpoint}' returned status code {response.status_code}.") 24 | 25 | # Define a function to run a specific API endpoint 26 | def run_endpoint(endpoint, method, parameters=None, data=None): 27 | url = f"{base_url}{endpoint}" 28 | response = requests.request(method, url, params=parameters, json=data) 29 | 30 | if response.status_code == 200: 31 | print(f"API endpoint '{endpoint}' is working well.") 32 | else: 33 | print(f"API endpoint '{endpoint}' returned status code {response.status_code}.") 34 | 35 | return response 36 | 37 | # Define a function to test the API endpoint and print the results 38 | def test_and_print_results(endpoint, method, data=None): 39 | response = run_endpoint(endpoint, method, data=data) 40 | 41 | if response.status_code == 200: 42 | response_data = response.json() 43 | print("Response data:") 44 | print(json.dumps(response_data, indent=2)) 45 | else: 46 | print("Error occurred. No data to display.") 47 | 48 | # Test the POST request on the /chat endpoint 49 | example_endpoint = '/chat' 50 | example_method = 'POST' 51 | prompt = "I have started to get lots of acne on my face, particularly on my forehead what can I do" 52 | 53 | example_data = {'message': prompt} 54 | 55 | test_endpoint(example_endpoint, example_method, data=example_data) 56 | test_and_print_results(example_endpoint, example_method, data=example_data) 57 | -------------------------------------------------------------------------------- /code-engine/assets/2024-02-22-17-07-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-22-17-07-03.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-22-17-11-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-22-17-11-30.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-22-17-33-52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-22-17-33-52.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-22-17-50-52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-22-17-50-52.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-22-17-52-36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-22-17-52-36.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-22-18-55-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-22-18-55-09.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-22-19-35-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-22-19-35-13.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-22-19-35-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-22-19-35-38.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-22-19-36-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-22-19-36-03.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-23-11-41-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-23-11-41-13.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-23-11-43-31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-23-11-43-31.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-23-12-00-45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-23-12-00-45.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-23-12-03-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-23-12-03-04.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-23-12-05-08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-23-12-05-08.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-23-12-09-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-23-12-09-02.png -------------------------------------------------------------------------------- /code-engine/assets/2024-02-23-12-10-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-02-23-12-10-22.png -------------------------------------------------------------------------------- /code-engine/assets/2024-03-11-15-41-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-03-11-15-41-12.png -------------------------------------------------------------------------------- /code-engine/assets/2024-03-11-16-57-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-03-11-16-57-05.png -------------------------------------------------------------------------------- /code-engine/assets/2024-03-11-17-03-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-03-11-17-03-25.png -------------------------------------------------------------------------------- /code-engine/assets/2024-03-11-17-05-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/code-engine/assets/2024-03-11-17-05-03.png -------------------------------------------------------------------------------- /code-engine/openapi.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "title": "Chat API", 5 | "version": "1.0.0" 6 | }, 7 | "servers": [ 8 | { 9 | "url": "https://watsonx-medical-api.1doe5vsg6flg.us-south.codeengine.appdomain.cloud/" 10 | } 11 | ], 12 | "paths": { 13 | "/chat": { 14 | "post": { 15 | "summary": "Send a message to the chat and receive a response", 16 | "requestBody": { 17 | "required": true, 18 | "content": { 19 | "application/json": { 20 | "schema": { 21 | "type": "object", 22 | "properties": { 23 | "message": { 24 | "type": "string", 25 | "description": "The message to send to the chat" 26 | }, 27 | "history": { 28 | "type": "array", 29 | "items": { 30 | "type": "object", 31 | "properties": { 32 | "message": { 33 | "type": "string" 34 | }, 35 | "response": { 36 | "type": "string" 37 | } 38 | } 39 | }, 40 | "description": "The chat history (optional)" 41 | } 42 | } 43 | } 44 | } 45 | } 46 | }, 47 | "responses": { 48 | "200": { 49 | "description": "Successful response with the chat message, response, and updated history", 50 | "content": { 51 | "application/json": { 52 | "schema": { 53 | "type": "object", 54 | "properties": { 55 | "message": { 56 | "type": "string", 57 | "description": "The message sent to the chat" 58 | }, 59 | "response": { 60 | "type": "string", 61 | "description": "The chat response" 62 | }, 63 | "history": { 64 | "type": "array", 65 | "items": { 66 | "type": "object", 67 | "properties": { 68 | "message": { 69 | "type": "string" 70 | }, 71 | "response": { 72 | "type": "string" 73 | } 74 | } 75 | }, 76 | "description": "The updated chat history" 77 | } 78 | } 79 | } 80 | } 81 | } 82 | }, 83 | "400": { 84 | "description": "Missing required parameter", 85 | "content": { 86 | "application/json": { 87 | "schema": { 88 | "type": "object", 89 | "properties": { 90 | "message": { 91 | "type": "string", 92 | "description": "Error message explaining the missing parameter" 93 | } 94 | } 95 | } 96 | } 97 | } 98 | }, 99 | "500": { 100 | "description": "Internal server error", 101 | "content": { 102 | "application/json": { 103 | "schema": { 104 | "type": "object", 105 | "properties": { 106 | "message": { 107 | "type": "string", 108 | "description": "Error message describing the internal issue" 109 | } 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | } 118 | }, 119 | "components": { 120 | "securitySchemes": { 121 | "ApiKey": { 122 | "type": "apiKey", 123 | "name": "APIKey", 124 | "in": "header" 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /container-api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10 2 | 3 | WORKDIR /code 4 | 5 | COPY ./requirements.txt /code/requirements.txt 6 | 7 | RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt 8 | 9 | # Set up a new user named "user" with user ID 1000 10 | RUN useradd -m -u 1000 user 11 | 12 | # Switch to the "user" user 13 | USER user 14 | 15 | # Set home to the user's home directory 16 | ENV HOME=/home/user \ 17 | PATH=/home/user/.local/bin:$PATH 18 | 19 | # Set the working directory to the user's home directory 20 | WORKDIR $HOME/app 21 | 22 | # Copy the current directory contents into the container at $HOME/app setting the owner to the user 23 | COPY --chown=user . $HOME/app 24 | 25 | EXPOSE 8080 26 | 27 | CMD ["python", "app.py"] -------------------------------------------------------------------------------- /container-api/README.md: -------------------------------------------------------------------------------- 1 | ## WatsonX.ai container client question-answering application with Milvus and LangChain with Flask and OpenApi. 2 | This guide demonstrates how to build an contiainer for client Watsonx.ai LLM-driven question-answering application with Milvus and LangChain 3 | To run this application locally just we ran the following command: 4 | ``` 5 | python app.py 6 | ``` 7 | ![](assets/2024-03-02-17-36-34.png) 8 | 9 | ## API Connection 10 | ### With Python 11 | 12 | ```python 13 | import json 14 | import requests 15 | 16 | # Load the openapi.json file 17 | with open('openapi.json', 'r') as file: 18 | openapi_data = json.load(file) 19 | 20 | # Get the base URL of the API from the openapi.json file 21 | base_url = openapi_data['servers'][0]['url'] 22 | 23 | # Define a function to test a specific API endpoint 24 | def test_endpoint(endpoint, method, parameters=None, data=None): 25 | url = f"{base_url}{endpoint}" 26 | response = requests.request(method, url, params=parameters, json=data) 27 | if response.status_code == 200: 28 | print(f"API endpoint '{endpoint}' is working well.") 29 | else: 30 | print(f"API endpoint '{endpoint}' returned status code {response.status_code}.") 31 | 32 | # Define a function to run a specific API endpoint 33 | def run_endpoint(endpoint, method, parameters=None, data=None): 34 | url = f"{base_url}{endpoint}" 35 | response = requests.request(method, url, params=parameters, json=data) 36 | 37 | if response.status_code == 200: 38 | print(f"API endpoint '{endpoint}' is working well.") 39 | else: 40 | print(f"API endpoint '{endpoint}' returned status code {response.status_code}.") 41 | 42 | return response 43 | 44 | # Define a function to test the API endpoint and print the results 45 | def test_and_print_results(endpoint, method, data=None): 46 | response = run_endpoint(endpoint, method, data=data) 47 | 48 | if response.status_code == 200: 49 | response_data = response.json() 50 | print("Response data:") 51 | print(json.dumps(response_data, indent=2)) 52 | else: 53 | print("Error occurred. No data to display.") 54 | 55 | # Test the POST request on the /chat endpoint 56 | example_endpoint = '/chat' 57 | example_method = 'POST' 58 | prompt = "I have started to get lots of acne on my face, particularly on my forehead what can I do" 59 | 60 | example_data = {'message': prompt} 61 | 62 | test_endpoint(example_endpoint, example_method, data=example_data) 63 | test_and_print_results(example_endpoint, example_method, data=example_data) 64 | 65 | ``` 66 | you will get 67 | ``` 68 | API endpoint '/chat' is working well. 69 | API endpoint '/chat' is working well. 70 | Response data: 71 | { 72 | "history": [ 73 | [ 74 | "I have started to get lots of acne on my face, particularly on my forehead what can I do", 75 | "\nFor mild grade acne, you can use a topical clindamycin or retinoid derivative face wash. For higher grade acne, you will need oral medications such as aluke doxycycline, azithromycin, or isotretinoin. It is essential to consult a dermatologist to confirm the grade of your acne and recommend appropriate treatment.\n\nPlease note that acne has a multifactorial etiology, and only acne soap may not be sufficient for severe cases. Oral and topical medications are often required to manage acne effectively.\n\nThanks for asking!" 76 | ] 77 | ], 78 | "message": "I have started to get lots of acne on my face, particularly on my forehead what can I do", 79 | "response": "\nFor mild grade acne, you can use a topical clindamycin or retinoid derivative face wash. For higher grade acne, you will need oral medications such as aluke doxycycline, azithromycin, or isotretinoin. It is essential to consult a dermatologist to confirm the grade of your acne and recommend appropriate treatment.\n\nPlease note that acne has a multifactorial etiology, and only acne soap may not be sufficient for severe cases. Oral and topical medications are often required to manage acne effectively.\n\nThanks for asking!" 80 | } 81 | ``` 82 | in the terminal also you get 83 | ![](assets/2024-03-02-17-38-13.png) 84 | 85 | ## Container 86 | 87 | To build and run the gradio application using the provided Dockerfile, follow these steps: 88 | 1. Ensure that you have Docker installed on your system. 89 | 2. Place the Dockerfile in the same directory as your gradio application code and the .env file. 90 | 3. Open a terminal or command prompt and navigate to the directory containing the Dockerfile. 91 | 4. Run the following command to build the Docker image, replacing "watsonx-medical-api" with your desired image name: 92 | ```bash 93 | docker build --no-cache -t watsonx-medical-api . 94 | ``` 95 | ![](assets/2024-03-07-17-53-44.png) 96 | This command will build the Docker image using the Dockerfile and the context of the current directory. 97 | 5. After successfully building the image, you can run the gradio application in a Docker container using the following command: 98 | 99 | ```bash 100 | docker run -it --env-file .env -p 8080:8080 watsonx-medical-api 101 | ``` 102 | During the previos execution You got 103 | ![](assets/2024-03-11-12-05-35.png) 104 | 105 | 106 | 107 | This command runs the Docker container, passing the environment variables from the .env file using the `--env-file` flag. It also maps the container's port 8080 to the host's port 8080, allowing you to access the gradio application through `http://localhost:8080`. 108 | 109 | You can see the image created at Docker Desktop 110 | ![](assets/2024-03-11-12-14-36.png) 111 | 112 | and also your container 113 | ![](assets/2024-03-11-12-15-02.png) 114 | 115 | 116 | Moreover you can test the container local by running in the root directory the following command 117 | 118 | ``` 119 | python ./container-api/api-test.py 120 | ``` 121 | 122 | Please note that the provided instructions assume that your gradio application code is correctly configured to read the environment variables from the .env file. 123 | 124 | ``` 125 | REMOTE_SERVER= 126 | API_KEY= 127 | PROJECT_ID= 128 | ``` 129 | 130 | If everythong went done well, just try with this prompt 131 | ``` 132 | I have started to get lots of acne on my face, particularly on my forehead what can I do 133 | ``` 134 | 135 | ![](assets/2024-03-11-12-39-07.png) 136 | 137 | 138 | 139 | 140 | ## Pushing your Docker image (optionally) 141 | 142 | To push your Docker image to a repository, follow these steps: 143 | 144 | 1. Sign up for an account on Docker Hub (https://hub.docker.com/) if you haven't already. 145 | 146 | 2. Log in to Docker Hub on your local machine using the terminal or command prompt. Run the following command and enter your Docker Hub credentials when prompted: 147 | ``` 148 | docker login 149 | ``` 150 | 151 | 3. Tag your local image with the repository name and a desired tag. For example: 152 | ``` 153 | docker tag watsonx-medical-api ruslanmv/watsonx-medical-api:latest 154 | ``` 155 | Replace `ruslanmv` with your Docker Hub username. You can also choose a different tag instead of `latest` if you prefer. 156 | 157 | 4. Push the tagged image to Docker Hub using the `docker push` command. For example: 158 | ``` 159 | docker push ruslanmv/watsonx-medical-api:latest 160 | ``` 161 | 162 | 163 | 5. After the push is completed, you can verify that the image is available in your Docker Hub repository by visiting https://hub.docker.com/ and checking your repositories. 164 | 165 | Now, others can pull the image from the repository using the following command: 166 | ``` 167 | docker pull ruslanmv/watsonx-medical-api:latest 168 | ``` 169 | **Congratulations!** You could build and execute your Medical Chatbot with Flask within WatsonX and Milvus -------------------------------------------------------------------------------- /container-api/api-test.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Testing API Medical Chat" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": null, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import json\n", 17 | "import requests\n", 18 | "import os\n", 19 | "# get the current working directory\n", 20 | "current_working_directory = os.getcwd()\n", 21 | "# Join various path components\n", 22 | "openapi_path=os.path.join(current_working_directory, \"openapi.json\")\n", 23 | "print(openapi_path)\n", 24 | "# Load the openapi.json file\n", 25 | "with open(openapi_path, 'r') as file:\n", 26 | " openapi_data = json.load(file)\n", 27 | "\n", 28 | "# Get the base URL of the API from the openapi.json file\n", 29 | "base_url = openapi_data['servers'][0]['url']\n", 30 | "\n", 31 | "# Define a function to test a specific API endpoint\n", 32 | "def test_endpoint(endpoint, method, parameters=None, data=None):\n", 33 | " url = f\"{base_url}{endpoint}\"\n", 34 | " response = requests.request(method, url, params=parameters, json=data)\n", 35 | " if response.status_code == 200:\n", 36 | " print(f\"API endpoint '{endpoint}' is working well.\")\n", 37 | " else:\n", 38 | " print(f\"API endpoint '{endpoint}' returned status code {response.status_code}.\")\n", 39 | "\n", 40 | "# Define a function to run a specific API endpoint\n", 41 | "def run_endpoint(endpoint, method, parameters=None, data=None):\n", 42 | " url = f\"{base_url}{endpoint}\"\n", 43 | " response = requests.request(method, url, params=parameters, json=data)\n", 44 | " \n", 45 | " if response.status_code == 200:\n", 46 | " print(f\"API endpoint '{endpoint}' is working well.\")\n", 47 | " else:\n", 48 | " print(f\"API endpoint '{endpoint}' returned status code {response.status_code}.\")\n", 49 | " \n", 50 | " return response\n", 51 | "\n", 52 | "# Define a function to test the API endpoint and print the results\n", 53 | "def test_and_print_results(endpoint, method, data=None):\n", 54 | " response = run_endpoint(endpoint, method, data=data)\n", 55 | " \n", 56 | " if response.status_code == 200:\n", 57 | " response_data = response.json()\n", 58 | " print(\"Response data:\")\n", 59 | " print(json.dumps(response_data, indent=2))\n", 60 | " else:\n", 61 | " print(\"Error occurred. No data to display.\")\n", 62 | "\n", 63 | "# Test the POST request on the /chat endpoint\n", 64 | "example_endpoint = '/chat'\n", 65 | "example_method = 'POST'\n", 66 | "prompt = \"I have started to get lots of acne on my face, particularly on my forehead what can I do\"\n", 67 | "\n", 68 | "example_data = {'message': prompt}\n", 69 | "\n", 70 | "test_endpoint(example_endpoint, example_method, data=example_data)\n", 71 | "test_and_print_results(example_endpoint, example_method, data=example_data)\n" 72 | ] 73 | } 74 | ], 75 | "metadata": { 76 | "kernelspec": { 77 | "display_name": ".venv", 78 | "language": "python", 79 | "name": "python3" 80 | }, 81 | "language_info": { 82 | "codemirror_mode": { 83 | "name": "ipython", 84 | "version": 3 85 | }, 86 | "file_extension": ".py", 87 | "mimetype": "text/x-python", 88 | "name": "python", 89 | "nbconvert_exporter": "python", 90 | "pygments_lexer": "ipython3", 91 | "version": "3.10.12" 92 | } 93 | }, 94 | "nbformat": 4, 95 | "nbformat_minor": 2 96 | } 97 | -------------------------------------------------------------------------------- /container-api/api-test.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | import os 4 | # get the current working directory 5 | current_working_directory = os.getcwd() 6 | # Join various path components 7 | openapi_path=os.path.join(current_working_directory,"container-api", "openapi.json") 8 | print(openapi_path) 9 | # Load the openapi.json file 10 | with open(openapi_path, 'r') as file: 11 | openapi_data = json.load(file) 12 | 13 | # Get the base URL of the API from the openapi.json file 14 | base_url = openapi_data['servers'][0]['url'] 15 | 16 | # Define a function to test a specific API endpoint 17 | def test_endpoint(endpoint, method, parameters=None, data=None): 18 | url = f"{base_url}{endpoint}" 19 | response = requests.request(method, url, params=parameters, json=data) 20 | if response.status_code == 200: 21 | print(f"API endpoint '{endpoint}' is working well.") 22 | else: 23 | print(f"API endpoint '{endpoint}' returned status code {response.status_code}.") 24 | 25 | # Define a function to run a specific API endpoint 26 | def run_endpoint(endpoint, method, parameters=None, data=None): 27 | url = f"{base_url}{endpoint}" 28 | response = requests.request(method, url, params=parameters, json=data) 29 | 30 | if response.status_code == 200: 31 | print(f"API endpoint '{endpoint}' is working well.") 32 | else: 33 | print(f"API endpoint '{endpoint}' returned status code {response.status_code}.") 34 | 35 | return response 36 | 37 | # Define a function to test the API endpoint and print the results 38 | def test_and_print_results(endpoint, method, data=None): 39 | response = run_endpoint(endpoint, method, data=data) 40 | 41 | if response.status_code == 200: 42 | response_data = response.json() 43 | print("Response data:") 44 | print(json.dumps(response_data, indent=2)) 45 | else: 46 | print("Error occurred. No data to display.") 47 | 48 | # Test the POST request on the /chat endpoint 49 | example_endpoint = '/chat' 50 | example_method = 'POST' 51 | prompt = "I have started to get lots of acne on my face, particularly on my forehead what can I do" 52 | 53 | example_data = {'message': prompt} 54 | 55 | test_endpoint(example_endpoint, example_method, data=example_data) 56 | test_and_print_results(example_endpoint, example_method, data=example_data) 57 | -------------------------------------------------------------------------------- /container-api/app.py: -------------------------------------------------------------------------------- 1 | from datasets import load_dataset 2 | from IPython.display import clear_output 3 | import pandas as pd 4 | import re 5 | from dotenv import load_dotenv 6 | import os 7 | from ibm_watson_machine_learning.foundation_models.utils.enums import ModelTypes 8 | from ibm_watson_machine_learning.metanames import GenTextParamsMetaNames as GenParams 9 | from ibm_watson_machine_learning.foundation_models.utils.enums import DecodingMethods 10 | from langchain.llms import WatsonxLLM 11 | from langchain.embeddings import SentenceTransformerEmbeddings 12 | from langchain.embeddings.base import Embeddings 13 | from langchain.vectorstores.milvus import Milvus 14 | from langchain.embeddings import HuggingFaceEmbeddings # Not used in this example 15 | from dotenv import load_dotenv 16 | import os 17 | from pymilvus import Collection, utility 18 | from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility 19 | from towhee import pipe, ops 20 | import numpy as np 21 | #import langchain.chains as lc 22 | from langchain_core.retrievers import BaseRetriever 23 | from langchain_core.callbacks import CallbackManagerForRetrieverRun 24 | from langchain_core.documents import Document 25 | from pymilvus import Collection, utility 26 | from towhee import pipe, ops 27 | import numpy as np 28 | from towhee.datacollection import DataCollection 29 | from typing import List 30 | from langchain.chains import RetrievalQA 31 | from langchain.prompts import PromptTemplate 32 | from langchain.schema.runnable import RunnablePassthrough 33 | from langchain_core.retrievers import BaseRetriever 34 | from langchain_core.callbacks import CallbackManagerForRetrieverRun 35 | 36 | print_full_prompt=False 37 | 38 | ## Step 1 Dataset Retrieving 39 | 40 | dataset = load_dataset("ruslanmv/ai-medical-chatbot") 41 | clear_output() 42 | train_data = dataset["train"] 43 | #For this demo let us choose the first 1000 dialogues 44 | 45 | df = pd.DataFrame(train_data[:1000]) 46 | #df = df[["Patient", "Doctor"]].rename(columns={"Patient": "question", "Doctor": "answer"}) 47 | df = df[["Description", "Doctor"]].rename(columns={"Description": "question", "Doctor": "answer"}) 48 | # Add the 'ID' column as the first column 49 | df.insert(0, 'id', df.index) 50 | # Reset the index and drop the previous index column 51 | df = df.reset_index(drop=True) 52 | 53 | # Clean the 'question' and 'answer' columns 54 | df['question'] = df['question'].apply(lambda x: re.sub(r'\s+', ' ', x.strip())) 55 | df['answer'] = df['answer'].apply(lambda x: re.sub(r'\s+', ' ', x.strip())) 56 | df['question'] = df['question'].str.replace('^Q.', '', regex=True) 57 | # Assuming your DataFrame is named df 58 | max_length = 500 # Due to our enbeeding model does not allow long strings 59 | df['question'] = df['question'].str.slice(0, max_length) 60 | #To use the dataset to get answers, let's first define the dictionary: 61 | #- `id_answer`: a dictionary of id and corresponding answer 62 | id_answer = df.set_index('id')['answer'].to_dict() 63 | 64 | ## Step 2 WatsonX connection 65 | 66 | load_dotenv() 67 | try: 68 | API_KEY = os.environ.get("API_KEY") 69 | project_id =os.environ.get("PROJECT_ID") 70 | except KeyError: 71 | API_KEY: input("Please enter your WML api key (hit enter): ") 72 | project_id = input("Please project_id (hit enter): ") 73 | 74 | credentials = { 75 | "url": "https://us-south.ml.cloud.ibm.com", 76 | "apikey": API_KEY 77 | } 78 | 79 | model_id = ModelTypes.GRANITE_13B_CHAT_V2 80 | 81 | 82 | parameters = { 83 | GenParams.DECODING_METHOD: DecodingMethods.GREEDY, 84 | GenParams.MIN_NEW_TOKENS: 1, 85 | GenParams.MAX_NEW_TOKENS: 500, 86 | GenParams.STOP_SEQUENCES: ["<|endoftext|>"] 87 | } 88 | 89 | 90 | watsonx_granite = WatsonxLLM( 91 | model_id=model_id.value, 92 | url=credentials.get("url"), 93 | apikey=credentials.get("apikey"), 94 | project_id=project_id, 95 | params=parameters 96 | ) 97 | 98 | 99 | ## Step 3 Milvus connection 100 | 101 | COLLECTION_NAME='qa_medical' 102 | load_dotenv() 103 | host_milvus = os.environ.get("REMOTE_SERVER", '127.0.0.1') 104 | connections.connect(host=host_milvus, port='19530') 105 | 106 | 107 | collection = Collection(COLLECTION_NAME) 108 | collection.load(replica_number=1) 109 | utility.load_state(COLLECTION_NAME) 110 | utility.loading_progress(COLLECTION_NAME) 111 | 112 | 113 | max_input_length = 500 # Maximum length allowed by the model 114 | 115 | 116 | 117 | # Create the combined pipe for question encoding and answer retrieval 118 | combined_pipe = ( 119 | pipe.input('question') 120 | .map('question', 'vec', lambda x: x[:max_input_length]) # Truncate the question if longer than 512 tokens 121 | .map('vec', 'vec', ops.text_embedding.dpr(model_name='facebook/dpr-ctx_encoder-single-nq-base')) 122 | .map('vec', 'vec', lambda x: x / np.linalg.norm(x, axis=0)) 123 | .map('vec', 'res', ops.ann_search.milvus_client(host=host_milvus, port='19530', collection_name=COLLECTION_NAME, limit=1)) 124 | .map('res', 'answer', lambda x: [id_answer[int(i[0])] for i in x]) 125 | .output('question', 'answer') 126 | ) 127 | 128 | # Step 4 Langchain Definitions 129 | 130 | class CustomRetrieverLang(BaseRetriever): 131 | def get_relevant_documents( 132 | self, query: str, *, run_manager: CallbackManagerForRetrieverRun 133 | ) -> List[Document]: 134 | # Perform the encoding and retrieval for a specific question 135 | ans = combined_pipe(query) 136 | ans = DataCollection(ans) 137 | answer=ans[0]['answer'] 138 | answer_string = ' '.join(answer) 139 | return [Document(page_content=answer_string)] 140 | # Ensure correct VectorStoreRetriever usage 141 | retriever = CustomRetrieverLang() 142 | 143 | # Define the prompt template 144 | template = """Use the following pieces of context to answer the question at the end. 145 | If you don't know the answer, just say that you don't know, don't try to make up an answer. 146 | Use three sentences maximum and keep the answer as concise as possible. 147 | Always say "thanks for asking!" at the end of the answer. 148 | {context} 149 | Question: {question} 150 | Helpful Answer:""" 151 | rag_prompt = PromptTemplate.from_template(template) 152 | rag_chain = ( 153 | {"context": retriever, "question": RunnablePassthrough()} 154 | | rag_prompt 155 | | watsonx_granite 156 | ) 157 | 158 | prompt = "I have started to get lots of acne on my face, particularly on my forehead what can I do" 159 | 160 | if print_full_prompt: 161 | # Get the retrieved context 162 | context = retriever.get_relevant_documents(prompt) 163 | print("Retrieved context:") 164 | for doc in context: 165 | print(doc) 166 | # Construct the full prompt 167 | full_prompt = rag_prompt.format(context=context, question=prompt) 168 | print("Full prompt:", full_prompt) 169 | 170 | print(rag_chain.invoke(prompt)) 171 | collection.load() 172 | import towhee 173 | def chat_function(message, history): 174 | history = history or [] 175 | response = rag_chain.invoke(message) 176 | history.append((message, response)) 177 | return history, history 178 | 179 | import json 180 | import requests 181 | from flask import Flask, request, jsonify 182 | 183 | app = Flask(__name__) 184 | 185 | @app.route('/chat', methods=['POST']) 186 | def chat(): 187 | params = request.get_json() 188 | message = params.get('message') 189 | history = params.get('history', []) 190 | 191 | if not message: 192 | return jsonify({"message": "Missing 'message' parameter"}), 400 193 | 194 | history, chat_history = chat_function(message, history) 195 | 196 | response_data = { 197 | "message": message, 198 | "response": chat_history[-1][1], 199 | "history": chat_history 200 | } 201 | return jsonify(response_data), 200 202 | 203 | if __name__ == '__main__': 204 | app.run(host='0.0.0.0', port=8080, debug=True) 205 | 206 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /container-api/assets/2024-02-22-13-55-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container-api/assets/2024-02-22-13-55-09.png -------------------------------------------------------------------------------- /container-api/assets/2024-02-22-14-22-34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container-api/assets/2024-02-22-14-22-34.png -------------------------------------------------------------------------------- /container-api/assets/2024-02-22-14-38-43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container-api/assets/2024-02-22-14-38-43.png -------------------------------------------------------------------------------- /container-api/assets/2024-02-22-15-29-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container-api/assets/2024-02-22-15-29-04.png -------------------------------------------------------------------------------- /container-api/assets/2024-03-02-17-36-34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container-api/assets/2024-03-02-17-36-34.png -------------------------------------------------------------------------------- /container-api/assets/2024-03-02-17-38-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container-api/assets/2024-03-02-17-38-13.png -------------------------------------------------------------------------------- /container-api/assets/2024-03-07-17-53-44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container-api/assets/2024-03-07-17-53-44.png -------------------------------------------------------------------------------- /container-api/assets/2024-03-11-12-05-35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container-api/assets/2024-03-11-12-05-35.png -------------------------------------------------------------------------------- /container-api/assets/2024-03-11-12-15-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container-api/assets/2024-03-11-12-15-02.png -------------------------------------------------------------------------------- /container-api/assets/2024-03-11-12-39-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container-api/assets/2024-03-11-12-39-07.png -------------------------------------------------------------------------------- /container-api/assets/python api-test.py.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container-api/assets/python api-test.py.png -------------------------------------------------------------------------------- /container-api/openapi.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "title": "Chat API", 5 | "version": "1.0.0" 6 | }, 7 | "servers": [ 8 | { 9 | "url": "http://127.0.0.1:8080" 10 | } 11 | ], 12 | "paths": { 13 | "/chat": { 14 | "post": { 15 | "summary": "Send a message to the chat and receive a response", 16 | "requestBody": { 17 | "required": true, 18 | "content": { 19 | "application/json": { 20 | "schema": { 21 | "type": "object", 22 | "properties": { 23 | "message": { 24 | "type": "string", 25 | "description": "The message to send to the chat" 26 | }, 27 | "history": { 28 | "type": "array", 29 | "items": { 30 | "type": "object", 31 | "properties": { 32 | "message": { 33 | "type": "string" 34 | }, 35 | "response": { 36 | "type": "string" 37 | } 38 | } 39 | }, 40 | "description": "The chat history (optional)" 41 | } 42 | } 43 | } 44 | } 45 | } 46 | }, 47 | "responses": { 48 | "200": { 49 | "description": "Successful response with the chat message, response, and updated history", 50 | "content": { 51 | "application/json": { 52 | "schema": { 53 | "type": "object", 54 | "properties": { 55 | "message": { 56 | "type": "string", 57 | "description": "The message sent to the chat" 58 | }, 59 | "response": { 60 | "type": "string", 61 | "description": "The chat response" 62 | }, 63 | "history": { 64 | "type": "array", 65 | "items": { 66 | "type": "object", 67 | "properties": { 68 | "message": { 69 | "type": "string" 70 | }, 71 | "response": { 72 | "type": "string" 73 | } 74 | } 75 | }, 76 | "description": "The updated chat history" 77 | } 78 | } 79 | } 80 | } 81 | } 82 | }, 83 | "400": { 84 | "description": "Missing required parameter", 85 | "content": { 86 | "application/json": { 87 | "schema": { 88 | "type": "object", 89 | "properties": { 90 | "message": { 91 | "type": "string", 92 | "description": "Error message explaining the missing parameter" 93 | } 94 | } 95 | } 96 | } 97 | } 98 | }, 99 | "500": { 100 | "description": "Internal server error", 101 | "content": { 102 | "application/json": { 103 | "schema": { 104 | "type": "object", 105 | "properties": { 106 | "message": { 107 | "type": "string", 108 | "description": "Error message describing the internal issue" 109 | } 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | } 118 | }, 119 | "components": { 120 | "securitySchemes": { 121 | "ApiKey": { 122 | "type": "apiKey", 123 | "name": "APIKey", 124 | "in": "header" 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /container-api/requirements.txt: -------------------------------------------------------------------------------- 1 | aiofiles==23.2.1 2 | aiohttp==3.9.3 3 | aiosignal==1.3.1 4 | altair==5.2.0 5 | annotated-types==0.6.0 6 | anyio==3.7.1 7 | argon2-cffi==23.1.0 8 | argon2-cffi-bindings==21.2.0 9 | asttokens==2.4.1 10 | async-timeout==4.0.3 11 | attrs==23.2.0 12 | backoff==2.2.1 13 | beautifulsoup4==4.12.3 14 | bs4==0.0.2 15 | certifi==2024.2.2 16 | cffi==1.16.0 17 | charset-normalizer==3.3.2 18 | chromadb==0.3.22 19 | click==8.1.7 20 | clickhouse-connect==0.7.0 21 | comm==0.2.1 22 | contourpy==1.2.0 23 | cryptography==42.0.3 24 | cycler==0.12.1 25 | dataclasses-json==0.6.4 26 | datasets==2.17.1 27 | debugpy==1.8.1 28 | decorator==5.1.1 29 | dill==0.3.8 30 | docutils==0.20.1 31 | duckdb==0.10.0 32 | environs==9.5.0 33 | exceptiongroup==1.2.0 34 | executing==2.0.1 35 | fastapi==0.109.2 36 | ffmpy==0.3.2 37 | filelock==3.13.1 38 | fonttools==4.49.0 39 | frozenlist==1.4.1 40 | fsspec==2023.10.0 41 | gradio==3.50.2 42 | gradio_client==0.6.1 43 | greenlet==3.0.3 44 | grpcio==1.60.0 45 | h11==0.14.0 46 | hnswlib==0.8.0 47 | httpcore==1.0.3 48 | httptools==0.6.1 49 | httpx==0.26.0 50 | huggingface-hub==0.20.3 51 | ibm-cos-sdk==2.13.4 52 | ibm-cos-sdk-core==2.13.4 53 | ibm-cos-sdk-s3transfer==2.13.4 54 | ibm-watson-machine-learning==1.0.347 55 | idna==3.6 56 | importlib-metadata==7.0.1 57 | importlib-resources==6.1.1 58 | ipykernel==6.29.2 59 | ipython==8.21.0 60 | ipywidgets==8.1.2 61 | jaraco.classes==3.3.1 62 | jedi==0.19.1 63 | jeepney==0.8.0 64 | Jinja2==3.1.3 65 | jmespath==1.0.1 66 | joblib==1.3.2 67 | jsonpatch==1.33 68 | jsonpointer==2.4 69 | jsonschema==4.21.1 70 | jsonschema-specifications==2023.12.1 71 | jupyter_client==8.6.0 72 | jupyter_core==5.7.1 73 | jupyterlab_widgets==3.0.10 74 | keyring==24.3.0 75 | kiwisolver==1.4.5 76 | langchain==0.0.345 77 | langchain-core==0.0.13 78 | langsmith==0.0.92 79 | lomond==0.3.3 80 | lz4==4.3.3 81 | markdown-it-py==3.0.0 82 | MarkupSafe==2.1.5 83 | marshmallow==3.20.2 84 | matplotlib==3.8.3 85 | matplotlib-inline==0.1.6 86 | mdurl==0.1.2 87 | minio==7.2.4 88 | monotonic==1.6 89 | more-itertools==10.2.0 90 | mpmath==1.3.0 91 | multidict==6.0.5 92 | multiprocess==0.70.16 93 | mypy-extensions==1.0.0 94 | nest-asyncio==1.6.0 95 | networkx==3.2.1 96 | nh3==0.2.15 97 | nltk==3.8.1 98 | numpy==1.26.4 99 | nvidia-cublas-cu12==12.1.3.1 100 | nvidia-cuda-cupti-cu12==12.1.105 101 | nvidia-cuda-nvrtc-cu12==12.1.105 102 | nvidia-cuda-runtime-cu12==12.1.105 103 | nvidia-cudnn-cu12==8.9.2.26 104 | nvidia-cufft-cu12==11.0.2.54 105 | nvidia-curand-cu12==10.3.2.106 106 | nvidia-cusolver-cu12==11.4.5.107 107 | nvidia-cusparse-cu12==12.1.0.106 108 | nvidia-nccl-cu12==2.19.3 109 | nvidia-nvjitlink-cu12==12.3.101 110 | nvidia-nvtx-cu12==12.1.105 111 | orjson==3.9.14 112 | packaging==23.2 113 | pandas==1.5.3 114 | parso==0.8.3 115 | pexpect==4.9.0 116 | pillow==10.2.0 117 | pkginfo==1.9.6 118 | platformdirs==4.2.0 119 | posthog==3.4.1 120 | prompt-toolkit==3.0.43 121 | protobuf==4.25.3 122 | psutil==5.9.8 123 | ptyprocess==0.7.0 124 | pure-eval==0.2.2 125 | pyarrow==15.0.0 126 | pyarrow-hotfix==0.6 127 | pycparser==2.21 128 | pycryptodome==3.20.0 129 | pydantic==1.10.14 130 | pydantic_core==2.16.2 131 | pydub==0.25.1 132 | Pygments==2.17.2 133 | pymilvus==2.3.6 134 | pyparsing==3.1.1 135 | python-dateutil==2.8.2 136 | python-dotenv==1.0.1 137 | python-multipart==0.0.9 138 | pytz==2024.1 139 | PyYAML==6.0.1 140 | pyzmq==25.1.2 141 | readme-renderer==42.0 142 | referencing==0.33.0 143 | regex==2023.12.25 144 | requests==2.31.0 145 | requests-toolbelt==1.0.0 146 | rfc3986==2.0.0 147 | rich==13.7.0 148 | rpds-py==0.18.0 149 | safetensors==0.4.2 150 | scikit-learn==1.4.1.post1 151 | scipy==1.12.0 152 | SecretStorage==3.3.3 153 | semantic-version==2.10.0 154 | sentence-transformers==2.3.1 155 | sentencepiece==0.2.0 156 | six==1.16.0 157 | sniffio==1.3.0 158 | soupsieve==2.5 159 | SQLAlchemy==2.0.27 160 | stack-data==0.6.3 161 | starlette==0.36.3 162 | sympy==1.12 163 | tabulate==0.9.0 164 | tenacity==8.2.3 165 | threadpoolctl==3.3.0 166 | tokenizers==0.15.2 167 | toolz==0.12.1 168 | torch==2.2.0 169 | tornado==6.4 170 | towhee==1.1.3 171 | towhee.models==1.1.3 172 | tqdm==4.66.2 173 | traitlets==5.14.1 174 | transformers==4.37.2 175 | triton==2.2.0 176 | twine==5.0.0 177 | typing-inspect==0.9.0 178 | typing_extensions==4.9.0 179 | tzdata==2024.1 180 | ujson==5.9.0 181 | urllib3==2.1.0 182 | uvicorn==0.27.1 183 | uvloop==0.19.0 184 | watchfiles==0.21.0 185 | wcwidth==0.2.13 186 | websockets==11.0.3 187 | wget==3.2 188 | widgetsnbextension==4.0.10 189 | xxhash==3.4.1 190 | yarl==1.9.4 191 | zipp==3.17.0 192 | zstandard==0.22.0 193 | Flask==3.0.2 194 | -------------------------------------------------------------------------------- /container/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10 2 | 3 | WORKDIR /code 4 | 5 | COPY ./requirements.txt /code/requirements.txt 6 | 7 | RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt 8 | 9 | # Set up a new user named "user" with user ID 1000 10 | RUN useradd -m -u 1000 user 11 | 12 | # Switch to the "user" user 13 | USER user 14 | 15 | # Set home to the user's home directory 16 | ENV HOME=/home/user \ 17 | PATH=/home/user/.local/bin:$PATH 18 | 19 | # Set the working directory to the user's home directory 20 | WORKDIR $HOME/app 21 | 22 | # Copy the current directory contents into the container at $HOME/app setting the owner to the user 23 | COPY --chown=user . $HOME/app 24 | 25 | EXPOSE 7860 26 | 27 | CMD ["python", "app.py"] -------------------------------------------------------------------------------- /container/README.md: -------------------------------------------------------------------------------- 1 | ## WatsonX.ai container client question-answering application with Milvus and LangChain 2 | This guide demonstrates how to build an contiainer for client Watsonx.ai LLM-driven question-answering application with Milvus and LangChain 3 | 4 | To run this application locally just we ran the following command: 5 | 6 | ``` 7 | python app.py 8 | ``` 9 | 10 | ![](assets/2024-02-22-13-55-09.png) 11 | 12 | ## API Connection 13 | ### With Python 14 | 15 | $ pip install gradio_client 16 | 17 | ``` 18 | from gradio_client import Client 19 | 20 | client = Client("http://127.0.0.1:7860/") 21 | result = client.predict( 22 | "Howdy!", # str in 'message' Textbox component 23 | api_name="/predict" 24 | ) 25 | print(result) 26 | ``` 27 | 28 | ### JavaScript 29 | or just Use the gradio_client Python library or the @gradio/client Javascript package to query the demo via API. 30 | 31 | ``` 32 | $ npm i -D @gradio/client 33 | ``` 34 | 35 | ``` 36 | import { client } from "@gradio/client"; 37 | 38 | const app = await client("http://127.0.0.1:7860/"); 39 | const result = await app.predict("/predict", [ 40 | "Howdy!", // string in 'message' Textbox component 41 | ]); 42 | 43 | console.log(result.data); 44 | ``` 45 | 46 | ## Container 47 | 48 | To build and run the gradio application using the provided Dockerfile, follow these steps: 49 | 50 | 1. Ensure that you have Docker installed on your system. 51 | 52 | 2. Place the Dockerfile in the same directory as your gradio application code and the .env file. 53 | 54 | 3. Open a terminal or command prompt and navigate to the directory containing the Dockerfile. 55 | 56 | 4. Run the following command to build the Docker image, replacing "watsonx-medical" with your desired image name: 57 | 58 | ```bash 59 | docker build -t watsonx-medical . 60 | ``` 61 | ![](assets/2024-02-22-14-22-34.png) 62 | This command will build the Docker image using the Dockerfile and the context of the current directory. 63 | 64 | 5. After successfully building the image, you can run the gradio application in a Docker container using the following command: 65 | 66 | ```bash 67 | docker run -it --env-file .env -p 7860:7860 watsonx-medical 68 | ``` 69 | During the previos execution You got 70 | ![](assets/2024-02-22-15-29-04.png) 71 | 72 | 73 | 74 | This command runs the Docker container, passing the environment variables from the .env file using the `--env-file` flag. It also maps the container's port 7860 to the host's port 7860, allowing you to access the gradio application through `http://localhost:7860`. 75 | 76 | Moreover ther is a test inside the ran of app.py to verify if indeed the program works. 77 | 78 | 79 | Please note that the provided instructions assume that your gradio application code is correctly configured to read the environment variables from the .env file. 80 | 81 | ``` 82 | REMOTE_SERVER= 83 | API_KEY= 84 | PROJECT_ID= 85 | ``` 86 | 87 | If everythong went done well, just try with this prompt 88 | ``` 89 | I have drink too much alcohol and I have headache what should do 90 | ``` 91 | 92 | and you will recieve the following output 93 | 94 | ![](assets/2024-02-22-14-38-43.png) 95 | 96 | 97 | 98 | ## Pushing your Docker image (optionally) 99 | 100 | To push your Docker image to a repository, follow these steps: 101 | 102 | 1. Sign up for an account on Docker Hub (https://hub.docker.com/) if you haven't already. 103 | 104 | 2. Log in to Docker Hub on your local machine using the terminal or command prompt. Run the following command and enter your Docker Hub credentials when prompted: 105 | ``` 106 | docker login 107 | ``` 108 | 109 | 3. Tag your local image with the repository name and a desired tag. For example: 110 | ``` 111 | docker tag watsonx-medical ruslanmv/watsonx-medical:latest 112 | ``` 113 | Replace `ruslanmv` with your Docker Hub username. You can also choose a different tag instead of `latest` if you prefer. 114 | 115 | 4. Push the tagged image to Docker Hub using the `docker push` command. For example: 116 | ``` 117 | docker push ruslanmv/watsonx-medical:latest 118 | ``` 119 | 120 | 121 | 5. After the push is completed, you can verify that the image is available in your Docker Hub repository by visiting https://hub.docker.com/ and checking your repositories. 122 | 123 | Now, others can pull the image from the repository using the following command: 124 | ``` 125 | docker pull ruslanmv/watsonx-medical:latest 126 | ``` 127 | 128 | 129 | **Congratulations!** You could build and execute your Medical Chatbot with Gradio within WatsonX and Milvus -------------------------------------------------------------------------------- /container/app.py: -------------------------------------------------------------------------------- 1 | from datasets import load_dataset 2 | from IPython.display import clear_output 3 | import pandas as pd 4 | import re 5 | from dotenv import load_dotenv 6 | import os 7 | from ibm_watson_machine_learning.foundation_models.utils.enums import ModelTypes 8 | from ibm_watson_machine_learning.metanames import GenTextParamsMetaNames as GenParams 9 | from ibm_watson_machine_learning.foundation_models.utils.enums import DecodingMethods 10 | from langchain.llms import WatsonxLLM 11 | from langchain.embeddings import SentenceTransformerEmbeddings 12 | from langchain.embeddings.base import Embeddings 13 | from langchain.vectorstores.milvus import Milvus 14 | from langchain.embeddings import HuggingFaceEmbeddings # Not used in this example 15 | from dotenv import load_dotenv 16 | import os 17 | from pymilvus import Collection, utility 18 | from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility 19 | from towhee import pipe, ops 20 | import numpy as np 21 | #import langchain.chains as lc 22 | from langchain_core.retrievers import BaseRetriever 23 | from langchain_core.callbacks import CallbackManagerForRetrieverRun 24 | from langchain_core.documents import Document 25 | from pymilvus import Collection, utility 26 | from towhee import pipe, ops 27 | import numpy as np 28 | from towhee.datacollection import DataCollection 29 | from typing import List 30 | from langchain.chains import RetrievalQA 31 | from langchain.prompts import PromptTemplate 32 | from langchain.schema.runnable import RunnablePassthrough 33 | from langchain_core.retrievers import BaseRetriever 34 | from langchain_core.callbacks import CallbackManagerForRetrieverRun 35 | 36 | print_full_prompt=False 37 | 38 | ## Step 1 Dataset Retrieving 39 | 40 | dataset = load_dataset("ruslanmv/ai-medical-chatbot") 41 | clear_output() 42 | train_data = dataset["train"] 43 | #For this demo let us choose the first 1000 dialogues 44 | 45 | df = pd.DataFrame(train_data[:1000]) 46 | #df = df[["Patient", "Doctor"]].rename(columns={"Patient": "question", "Doctor": "answer"}) 47 | df = df[["Description", "Doctor"]].rename(columns={"Description": "question", "Doctor": "answer"}) 48 | # Add the 'ID' column as the first column 49 | df.insert(0, 'id', df.index) 50 | # Reset the index and drop the previous index column 51 | df = df.reset_index(drop=True) 52 | 53 | # Clean the 'question' and 'answer' columns 54 | df['question'] = df['question'].apply(lambda x: re.sub(r'\s+', ' ', x.strip())) 55 | df['answer'] = df['answer'].apply(lambda x: re.sub(r'\s+', ' ', x.strip())) 56 | df['question'] = df['question'].str.replace('^Q.', '', regex=True) 57 | # Assuming your DataFrame is named df 58 | max_length = 500 # Due to our enbeeding model does not allow long strings 59 | df['question'] = df['question'].str.slice(0, max_length) 60 | #To use the dataset to get answers, let's first define the dictionary: 61 | #- `id_answer`: a dictionary of id and corresponding answer 62 | id_answer = df.set_index('id')['answer'].to_dict() 63 | 64 | ## Step 2 WatsonX connection 65 | 66 | load_dotenv() 67 | try: 68 | API_KEY = os.environ.get("API_KEY") 69 | project_id =os.environ.get("PROJECT_ID") 70 | except KeyError: 71 | API_KEY: input("Please enter your WML api key (hit enter): ") 72 | project_id = input("Please project_id (hit enter): ") 73 | 74 | credentials = { 75 | "url": "https://us-south.ml.cloud.ibm.com", 76 | "apikey": API_KEY 77 | } 78 | 79 | model_id = ModelTypes.GRANITE_13B_CHAT_V2 80 | 81 | 82 | parameters = { 83 | GenParams.DECODING_METHOD: DecodingMethods.GREEDY, 84 | GenParams.MIN_NEW_TOKENS: 1, 85 | GenParams.MAX_NEW_TOKENS: 500, 86 | GenParams.STOP_SEQUENCES: ["<|endoftext|>"] 87 | } 88 | 89 | 90 | watsonx_granite = WatsonxLLM( 91 | model_id=model_id.value, 92 | url=credentials.get("url"), 93 | apikey=credentials.get("apikey"), 94 | project_id=project_id, 95 | params=parameters 96 | ) 97 | 98 | 99 | ## Step 3 Milvus connection 100 | 101 | COLLECTION_NAME='qa_medical' 102 | load_dotenv() 103 | host_milvus = os.environ.get("REMOTE_SERVER", '127.0.0.1') 104 | connections.connect(host=host_milvus, port='19530') 105 | 106 | 107 | collection = Collection(COLLECTION_NAME) 108 | collection.load(replica_number=1) 109 | utility.load_state(COLLECTION_NAME) 110 | utility.loading_progress(COLLECTION_NAME) 111 | 112 | 113 | max_input_length = 500 # Maximum length allowed by the model 114 | 115 | 116 | 117 | # Create the combined pipe for question encoding and answer retrieval 118 | combined_pipe = ( 119 | pipe.input('question') 120 | .map('question', 'vec', lambda x: x[:max_input_length]) # Truncate the question if longer than 512 tokens 121 | .map('vec', 'vec', ops.text_embedding.dpr(model_name='facebook/dpr-ctx_encoder-single-nq-base')) 122 | .map('vec', 'vec', lambda x: x / np.linalg.norm(x, axis=0)) 123 | .map('vec', 'res', ops.ann_search.milvus_client(host=host_milvus, port='19530', collection_name=COLLECTION_NAME, limit=1)) 124 | .map('res', 'answer', lambda x: [id_answer[int(i[0])] for i in x]) 125 | .output('question', 'answer') 126 | ) 127 | 128 | # Step 4 Langchain Definitions 129 | 130 | class CustomRetrieverLang(BaseRetriever): 131 | def get_relevant_documents( 132 | self, query: str, *, run_manager: CallbackManagerForRetrieverRun 133 | ) -> List[Document]: 134 | # Perform the encoding and retrieval for a specific question 135 | ans = combined_pipe(query) 136 | ans = DataCollection(ans) 137 | answer=ans[0]['answer'] 138 | answer_string = ' '.join(answer) 139 | return [Document(page_content=answer_string)] 140 | # Ensure correct VectorStoreRetriever usage 141 | retriever = CustomRetrieverLang() 142 | 143 | # Define the prompt template 144 | template = """Use the following pieces of context to answer the question at the end. 145 | If you don't know the answer, just say that you don't know, don't try to make up an answer. 146 | Use three sentences maximum and keep the answer as concise as possible. 147 | Always say "thanks for asking!" at the end of the answer. 148 | {context} 149 | Question: {question} 150 | Helpful Answer:""" 151 | rag_prompt = PromptTemplate.from_template(template) 152 | rag_chain = ( 153 | {"context": retriever, "question": RunnablePassthrough()} 154 | | rag_prompt 155 | | watsonx_granite 156 | ) 157 | 158 | prompt = "I have started to get lots of acne on my face, particularly on my forehead what can I do" 159 | 160 | if print_full_prompt: 161 | # Get the retrieved context 162 | context = retriever.get_relevant_documents(prompt) 163 | print("Retrieved context:") 164 | for doc in context: 165 | print(doc) 166 | # Construct the full prompt 167 | full_prompt = rag_prompt.format(context=context, question=prompt) 168 | print("Full prompt:", full_prompt) 169 | 170 | print(rag_chain.invoke(prompt)) 171 | 172 | import towhee 173 | def chat(message, history): 174 | history = history or [] 175 | response = rag_chain.invoke(message) 176 | history.append((message, response)) 177 | return history, history 178 | 179 | import gradio 180 | collection.load() 181 | chatbot = gradio.Chatbot() 182 | interface = gradio.Interface( 183 | chat, 184 | ["text", "state"], 185 | [chatbot, "state"], 186 | allow_flagging="never", 187 | ) 188 | #interface.launch(inline=True, share=False) #For the notebook 189 | interface.launch(server_name="0.0.0.0",server_port=7860) -------------------------------------------------------------------------------- /container/assets/2024-02-22-13-55-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container/assets/2024-02-22-13-55-09.png -------------------------------------------------------------------------------- /container/assets/2024-02-22-14-22-34.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container/assets/2024-02-22-14-22-34.png -------------------------------------------------------------------------------- /container/assets/2024-02-22-14-38-43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container/assets/2024-02-22-14-38-43.png -------------------------------------------------------------------------------- /container/assets/2024-02-22-15-29-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/container/assets/2024-02-22-15-29-04.png -------------------------------------------------------------------------------- /container/requirements.txt: -------------------------------------------------------------------------------- 1 | aiofiles==23.2.1 2 | aiohttp==3.9.3 3 | aiosignal==1.3.1 4 | altair==5.2.0 5 | annotated-types==0.6.0 6 | anyio==3.7.1 7 | argon2-cffi==23.1.0 8 | argon2-cffi-bindings==21.2.0 9 | asttokens==2.4.1 10 | async-timeout==4.0.3 11 | attrs==23.2.0 12 | backoff==2.2.1 13 | beautifulsoup4==4.12.3 14 | bs4==0.0.2 15 | certifi==2024.2.2 16 | cffi==1.16.0 17 | charset-normalizer==3.3.2 18 | chromadb==0.3.22 19 | click==8.1.7 20 | clickhouse-connect==0.7.0 21 | comm==0.2.1 22 | contourpy==1.2.0 23 | cryptography==42.0.3 24 | cycler==0.12.1 25 | dataclasses-json==0.6.4 26 | datasets==2.17.1 27 | debugpy==1.8.1 28 | decorator==5.1.1 29 | dill==0.3.8 30 | docutils==0.20.1 31 | duckdb==0.10.0 32 | environs==9.5.0 33 | exceptiongroup==1.2.0 34 | executing==2.0.1 35 | fastapi==0.109.2 36 | ffmpy==0.3.2 37 | filelock==3.13.1 38 | fonttools==4.49.0 39 | frozenlist==1.4.1 40 | fsspec==2023.10.0 41 | gradio==3.50.2 42 | gradio_client==0.6.1 43 | greenlet==3.0.3 44 | grpcio==1.60.0 45 | h11==0.14.0 46 | hnswlib==0.8.0 47 | httpcore==1.0.3 48 | httptools==0.6.1 49 | httpx==0.26.0 50 | huggingface-hub==0.20.3 51 | ibm-cos-sdk==2.13.4 52 | ibm-cos-sdk-core==2.13.4 53 | ibm-cos-sdk-s3transfer==2.13.4 54 | ibm-watson-machine-learning==1.0.347 55 | idna==3.6 56 | importlib-metadata==7.0.1 57 | importlib-resources==6.1.1 58 | ipykernel==6.29.2 59 | ipython==8.21.0 60 | ipywidgets==8.1.2 61 | jaraco.classes==3.3.1 62 | jedi==0.19.1 63 | jeepney==0.8.0 64 | Jinja2==3.1.3 65 | jmespath==1.0.1 66 | joblib==1.3.2 67 | jsonpatch==1.33 68 | jsonpointer==2.4 69 | jsonschema==4.21.1 70 | jsonschema-specifications==2023.12.1 71 | jupyter_client==8.6.0 72 | jupyter_core==5.7.1 73 | jupyterlab_widgets==3.0.10 74 | keyring==24.3.0 75 | kiwisolver==1.4.5 76 | langchain==0.0.345 77 | langchain-core==0.0.13 78 | langsmith==0.0.92 79 | lomond==0.3.3 80 | lz4==4.3.3 81 | markdown-it-py==3.0.0 82 | MarkupSafe==2.1.5 83 | marshmallow==3.20.2 84 | matplotlib==3.8.3 85 | matplotlib-inline==0.1.6 86 | mdurl==0.1.2 87 | minio==7.2.4 88 | monotonic==1.6 89 | more-itertools==10.2.0 90 | mpmath==1.3.0 91 | multidict==6.0.5 92 | multiprocess==0.70.16 93 | mypy-extensions==1.0.0 94 | nest-asyncio==1.6.0 95 | networkx==3.2.1 96 | nh3==0.2.15 97 | nltk==3.8.1 98 | numpy==1.26.4 99 | nvidia-cublas-cu12==12.1.3.1 100 | nvidia-cuda-cupti-cu12==12.1.105 101 | nvidia-cuda-nvrtc-cu12==12.1.105 102 | nvidia-cuda-runtime-cu12==12.1.105 103 | nvidia-cudnn-cu12==8.9.2.26 104 | nvidia-cufft-cu12==11.0.2.54 105 | nvidia-curand-cu12==10.3.2.106 106 | nvidia-cusolver-cu12==11.4.5.107 107 | nvidia-cusparse-cu12==12.1.0.106 108 | nvidia-nccl-cu12==2.19.3 109 | nvidia-nvjitlink-cu12==12.3.101 110 | nvidia-nvtx-cu12==12.1.105 111 | orjson==3.9.14 112 | packaging==23.2 113 | pandas==1.5.3 114 | parso==0.8.3 115 | pexpect==4.9.0 116 | pillow==10.2.0 117 | pkginfo==1.9.6 118 | platformdirs==4.2.0 119 | posthog==3.4.1 120 | prompt-toolkit==3.0.43 121 | protobuf==4.25.3 122 | psutil==5.9.8 123 | ptyprocess==0.7.0 124 | pure-eval==0.2.2 125 | pyarrow==15.0.0 126 | pyarrow-hotfix==0.6 127 | pycparser==2.21 128 | pycryptodome==3.20.0 129 | pydantic==1.10.14 130 | pydantic_core==2.16.2 131 | pydub==0.25.1 132 | Pygments==2.17.2 133 | pymilvus==2.3.6 134 | pyparsing==3.1.1 135 | python-dateutil==2.8.2 136 | python-dotenv==1.0.1 137 | python-multipart==0.0.9 138 | pytz==2024.1 139 | PyYAML==6.0.1 140 | pyzmq==25.1.2 141 | readme-renderer==42.0 142 | referencing==0.33.0 143 | regex==2023.12.25 144 | requests==2.31.0 145 | requests-toolbelt==1.0.0 146 | rfc3986==2.0.0 147 | rich==13.7.0 148 | rpds-py==0.18.0 149 | safetensors==0.4.2 150 | scikit-learn==1.4.1.post1 151 | scipy==1.12.0 152 | SecretStorage==3.3.3 153 | semantic-version==2.10.0 154 | sentence-transformers==2.3.1 155 | sentencepiece==0.2.0 156 | six==1.16.0 157 | sniffio==1.3.0 158 | soupsieve==2.5 159 | SQLAlchemy==2.0.27 160 | stack-data==0.6.3 161 | starlette==0.36.3 162 | sympy==1.12 163 | tabulate==0.9.0 164 | tenacity==8.2.3 165 | threadpoolctl==3.3.0 166 | tokenizers==0.15.2 167 | toolz==0.12.1 168 | torch==2.2.0 169 | tornado==6.4 170 | towhee==1.1.3 171 | towhee.models==1.1.3 172 | tqdm==4.66.2 173 | traitlets==5.14.1 174 | transformers==4.37.2 175 | triton==2.2.0 176 | twine==5.0.0 177 | typing-inspect==0.9.0 178 | typing_extensions==4.9.0 179 | tzdata==2024.1 180 | ujson==5.9.0 181 | urllib3==2.1.0 182 | uvicorn==0.27.1 183 | uvloop==0.19.0 184 | watchfiles==0.21.0 185 | wcwidth==0.2.13 186 | websockets==11.0.3 187 | wget==3.2 188 | widgetsnbextension==4.0.10 189 | xxhash==3.4.1 190 | yarl==1.9.4 191 | zipp==3.17.0 192 | zstandard==0.22.0 193 | -------------------------------------------------------------------------------- /containers/milvus/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright VMware, Inc. 2 | # SPDX-License-Identifier: APACHE-2.0 3 | 4 | FROM docker.io/bitnami/minideb:bullseye 5 | 6 | ARG TARGETARCH 7 | 8 | LABEL com.vmware.cp.artifact.flavor="sha256:1e1b4657a77f0d47e9220f0c37b9bf7802581b93214fff7d1bd2364c8bf22e8e" \ 9 | org.opencontainers.image.base.name="docker.io/bitnami/minideb:bullseye" \ 10 | org.opencontainers.image.created="2024-02-07T10:39:47Z" \ 11 | org.opencontainers.image.description="Application packaged by VMware, Inc" \ 12 | org.opencontainers.image.licenses="Apache-2.0" \ 13 | org.opencontainers.image.ref.name="2.3.7-debian-11-r2" \ 14 | org.opencontainers.image.title="milvus" \ 15 | org.opencontainers.image.vendor="VMware, Inc." \ 16 | org.opencontainers.image.version="2.3.7" 17 | 18 | ENV HOME="/" \ 19 | OS_ARCH="${TARGETARCH:-amd64}" \ 20 | OS_FLAVOUR="debian-11" \ 21 | OS_NAME="linux" 22 | 23 | COPY prebuildfs / 24 | SHELL ["/bin/bash", "-o", "errexit", "-o", "nounset", "-o", "pipefail", "-c"] 25 | # Install required system packages and dependencies 26 | RUN install_packages ca-certificates curl libgcc-s1 libgomp1 libstdc++6 procps 27 | RUN mkdir -p /tmp/bitnami/pkg/cache/ ; cd /tmp/bitnami/pkg/cache/ ; \ 28 | COMPONENTS=( \ 29 | "yq-4.40.5-4-linux-${OS_ARCH}-debian-11" \ 30 | "wait-for-port-1.0.7-8-linux-${OS_ARCH}-debian-11" \ 31 | "render-template-1.0.6-8-linux-${OS_ARCH}-debian-11" \ 32 | "milvus-2.3.7-2-linux-${OS_ARCH}-debian-11" \ 33 | ) ; \ 34 | for COMPONENT in "${COMPONENTS[@]}"; do \ 35 | if [ ! -f "${COMPONENT}.tar.gz" ]; then \ 36 | curl -SsLf "https://downloads.bitnami.com/files/stacksmith/${COMPONENT}.tar.gz" -O ; \ 37 | curl -SsLf "https://downloads.bitnami.com/files/stacksmith/${COMPONENT}.tar.gz.sha256" -O ; \ 38 | fi ; \ 39 | sha256sum -c "${COMPONENT}.tar.gz.sha256" ; \ 40 | tar -zxf "${COMPONENT}.tar.gz" -C /opt/bitnami --strip-components=2 --no-same-owner --wildcards '*/files' ; \ 41 | rm -rf "${COMPONENT}".tar.gz{,.sha256} ; \ 42 | done 43 | RUN apt-get autoremove --purge -y curl && \ 44 | apt-get update && apt-get upgrade -y && \ 45 | apt-get clean && rm -rf /var/lib/apt/lists /var/cache/apt/archives 46 | RUN useradd -r -u 1001 -g root milvus 47 | RUN find / -perm /6000 -type f -exec chmod a-s {} \; || true 48 | RUN mkdir -p /opt/bitnami/milvus/tmp && chmod g+rwX /opt/bitnami/milvus/tmp && ln -s /opt/bitnami/milvus/tmp /run/milvus && mkdir -p /bitnami/milvus/data && chmod g+rwX /bitnami/milvus/data && ln -s /bitnami/milvus/data /var/lib/milvus && ln -s /opt/bitnami/milvus /milvus 49 | 50 | ENV APP_VERSION="2.3.7" \ 51 | BITNAMI_APP_NAME="milvus" \ 52 | LD_LIBRARY_PATH="/opt/bitnami/milvus/lib:$LD_LIBRARY_PATH" \ 53 | PATH="/opt/bitnami/common/bin:/opt/bitnami/milvus/bin:$PATH" 54 | 55 | WORKDIR /opt/bitnami/milvus 56 | USER 1001 57 | ENTRYPOINT [ "/opt/bitnami/milvus/bin/milvus" ] 58 | -------------------------------------------------------------------------------- /containers/milvus/prebuildfs/opt/bitnami/.bitnami_components.json: -------------------------------------------------------------------------------- 1 | { 2 | "milvus": { 3 | "arch": "amd64", 4 | "distro": "debian-11", 5 | "type": "NAMI", 6 | "version": "2.3.7-2" 7 | }, 8 | "render-template": { 9 | "arch": "amd64", 10 | "distro": "debian-11", 11 | "type": "NAMI", 12 | "version": "1.0.6-8" 13 | }, 14 | "wait-for-port": { 15 | "arch": "amd64", 16 | "distro": "debian-11", 17 | "type": "NAMI", 18 | "version": "1.0.7-8" 19 | }, 20 | "yq": { 21 | "arch": "amd64", 22 | "distro": "debian-11", 23 | "type": "NAMI", 24 | "version": "4.40.5-4" 25 | } 26 | } -------------------------------------------------------------------------------- /containers/milvus/prebuildfs/opt/bitnami/licenses/licenses.txt: -------------------------------------------------------------------------------- 1 | Bitnami containers ship with software bundles. You can find the licenses under: 2 | /opt/bitnami/[name-of-bundle]/licenses/[bundle-version].txt 3 | -------------------------------------------------------------------------------- /containers/milvus/prebuildfs/usr/sbin/install_packages: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright VMware, Inc. 3 | # SPDX-License-Identifier: APACHE-2.0 4 | set -eu 5 | 6 | n=0 7 | max=2 8 | export DEBIAN_FRONTEND=noninteractive 9 | 10 | until [ $n -gt $max ]; do 11 | set +e 12 | ( 13 | apt-get update -qq && 14 | apt-get install -y --no-install-recommends "$@" 15 | ) 16 | CODE=$? 17 | set -e 18 | if [ $CODE -eq 0 ]; then 19 | break 20 | fi 21 | if [ $n -eq $max ]; then 22 | exit $CODE 23 | fi 24 | echo "apt failed, retrying" 25 | n=$(($n + 1)) 26 | done 27 | apt-get clean && rm -rf /var/lib/apt/lists /var/cache/apt/archives 28 | -------------------------------------------------------------------------------- /containers/milvus/prebuildfs/usr/sbin/run-script: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright VMware, Inc. 3 | # SPDX-License-Identifier: APACHE-2.0 4 | set -u 5 | 6 | if [ $# -eq 0 ]; then 7 | >&2 echo "No arguments provided" 8 | exit 1 9 | fi 10 | 11 | script=$1 12 | exit_code="${2:-96}" 13 | fail_if_not_present="${3:-n}" 14 | 15 | if test -f "$script"; then 16 | sh $script 17 | 18 | if [ $? -ne 0 ]; then 19 | exit $((exit_code)) 20 | fi 21 | elif [ "$fail_if_not_present" = "y" ]; then 22 | >&2 echo "script not found: $script" 23 | exit 127 24 | fi 25 | -------------------------------------------------------------------------------- /containers/milvus/tags-info.yaml: -------------------------------------------------------------------------------- 1 | rolling-tags: 2 | - "2" 3 | - 2-debian-11 4 | - 2.3.7 5 | - latest 6 | -------------------------------------------------------------------------------- /demo/demo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/demo/demo1.png -------------------------------------------------------------------------------- /imagenx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/imagenx.png -------------------------------------------------------------------------------- /notebooks/0-Manage-VectorDatabase.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "961dd942-c947-46b2-ab5c-b1557e55374b", 6 | "metadata": {}, 7 | "source": [ 8 | "# Manage the Vector Database Milvus\n", 9 | "The purpose of this notebook is introduce the vector database, how to use it." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "id": "846876b0-b381-486f-b25c-62520a3fa146", 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "#!pip install python-dotenv pymilvus" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 1, 25 | "id": "b7a75a8a-9087-48fc-b94f-9fbb4d443884", 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "from pymilvus import connections\n", 30 | "from dotenv import load_dotenv\n", 31 | "import os\n", 32 | "load_dotenv()\n", 33 | "host_milvus = os.environ.get(\"REMOTE_SERVER\", \"localhost\")" 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "id": "86a9aa86-22ea-403b-8310-872c4b195a62", 39 | "metadata": {}, 40 | "source": [ 41 | "## Connect to a Milvus server\n" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 3, 47 | "id": "4b154195-6fd5-4b20-9ae4-026d40ed748b", 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [ 51 | "from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility\n", 52 | "conn = connections.connect(host=host_milvus, port=19530)" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "id": "1902db61-7edf-4ba6-8e2f-ff2d7b9cd895", 58 | "metadata": {}, 59 | "source": [ 60 | "## Create database\n" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": 5, 66 | "id": "e73b495f", 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [ 70 | "from pymilvus import connections, db" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": 6, 76 | "id": "ce8c5a70-14f2-4266-83b9-304359f3c405", 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [ 80 | "database = db.create_database(\"book\")" 81 | ] 82 | }, 83 | { 84 | "cell_type": "markdown", 85 | "id": "e281ce59-04f9-45b7-ba45-7daa5cc1ebb2", 86 | "metadata": {}, 87 | "source": [ 88 | "## List databases" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 7, 94 | "id": "537b28d3-19b6-4fce-a623-64d9ecc3cd7e", 95 | "metadata": {}, 96 | "outputs": [ 97 | { 98 | "data": { 99 | "text/plain": [ 100 | "['default', 'book']" 101 | ] 102 | }, 103 | "execution_count": 7, 104 | "metadata": {}, 105 | "output_type": "execute_result" 106 | } 107 | ], 108 | "source": [ 109 | "db.list_database()" 110 | ] 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "id": "f0c28313-a552-4feb-9071-ea102eb6d023", 115 | "metadata": {}, 116 | "source": [ 117 | "## Drop database" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 8, 123 | "id": "a8d87cf7-e0d1-4ee7-9b92-2a1b5f201041", 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "db.drop_database(\"book\")" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": 9, 133 | "id": "818c7566-4f57-44e2-8ec8-2142e1deebab", 134 | "metadata": {}, 135 | "outputs": [ 136 | { 137 | "data": { 138 | "text/plain": [ 139 | "['default']" 140 | ] 141 | }, 142 | "execution_count": 9, 143 | "metadata": {}, 144 | "output_type": "execute_result" 145 | } 146 | ], 147 | "source": [ 148 | "db.list_database()\n" 149 | ] 150 | }, 151 | { 152 | "cell_type": "markdown", 153 | "id": "b7023bf4-227e-43e7-aaf2-36b88c196698", 154 | "metadata": {}, 155 | "source": [ 156 | "## Create a Collection\n", 157 | "\n" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": 30, 163 | "id": "4ef6d6c8-b194-49fa-b269-aa27e094ff06", 164 | "metadata": {}, 165 | "outputs": [], 166 | "source": [ 167 | "from pymilvus import CollectionSchema, FieldSchema, DataType\n", 168 | "book_id = FieldSchema(\n", 169 | " name=\"book_id\",\n", 170 | " dtype=DataType.INT64,\n", 171 | " is_primary=True,\n", 172 | ")\n", 173 | "book_name = FieldSchema(\n", 174 | " name=\"book_name\",\n", 175 | " dtype=DataType.VARCHAR,\n", 176 | " max_length=200,\n", 177 | " # The default value will be used if this field is left empty during data inserts or upserts.\n", 178 | " # The data type of `default_value` must be the same as that specified in `dtype`.\n", 179 | " default_value=\"Unknown\"\n", 180 | ")\n", 181 | "word_count = FieldSchema(\n", 182 | " name=\"word_count\",\n", 183 | " dtype=DataType.INT64,\n", 184 | " # The default value will be used if this field is left empty during data inserts or upserts.\n", 185 | " # The data type of `default_value` must be the same as that specified in `dtype`.\n", 186 | " default_value=9999\n", 187 | ")\n", 188 | "book_intro = FieldSchema(\n", 189 | " name=\"book_intro\",\n", 190 | " dtype=DataType.FLOAT_VECTOR,\n", 191 | " dim=2\n", 192 | ")\n", 193 | "schema = CollectionSchema(\n", 194 | " fields=[book_id, book_name, word_count, book_intro],\n", 195 | " description=\"Test book search\",\n", 196 | " enable_dynamic_field=True\n", 197 | ")\n", 198 | "collection_name = \"book\"\n" 199 | ] 200 | }, 201 | { 202 | "cell_type": "markdown", 203 | "id": "e569459c-0daa-4609-8fd8-4d0afac363d2", 204 | "metadata": {}, 205 | "source": [ 206 | "## Create a collection with the schema" 207 | ] 208 | }, 209 | { 210 | "cell_type": "code", 211 | "execution_count": 31, 212 | "id": "06ba00ef-01aa-4c70-9fe5-3e8602cc2e6d", 213 | "metadata": {}, 214 | "outputs": [], 215 | "source": [ 216 | "from pymilvus import Collection\n", 217 | "collection = Collection(\n", 218 | " name=collection_name,\n", 219 | " schema=schema,\n", 220 | " using='default',\n", 221 | " shards_num=2\n", 222 | " )\n" 223 | ] 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "id": "c8d78d7d-6dda-48b2-aa40-69d41951bf42", 228 | "metadata": {}, 229 | "source": [ 230 | "## List all collections" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": 38, 236 | "id": "dbcbac83-b4e3-45b5-9393-5dabc31184fd", 237 | "metadata": {}, 238 | "outputs": [ 239 | { 240 | "data": { 241 | "text/plain": [ 242 | "['question_answers', 'question_answer_medical', 'question_answer']" 243 | ] 244 | }, 245 | "execution_count": 38, 246 | "metadata": {}, 247 | "output_type": "execute_result" 248 | } 249 | ], 250 | "source": [ 251 | "from pymilvus import utility\n", 252 | "utility.list_collections()\n" 253 | ] 254 | }, 255 | { 256 | "cell_type": "markdown", 257 | "id": "58da99e6-0fb9-41e2-9702-88f2349d04f6", 258 | "metadata": {}, 259 | "source": [ 260 | "## Check if a collection exists" 261 | ] 262 | }, 263 | { 264 | "cell_type": "code", 265 | "execution_count": 33, 266 | "id": "f8eb7aa0-7f80-4057-beab-750d29410c0b", 267 | "metadata": {}, 268 | "outputs": [ 269 | { 270 | "data": { 271 | "text/plain": [ 272 | "True" 273 | ] 274 | }, 275 | "execution_count": 33, 276 | "metadata": {}, 277 | "output_type": "execute_result" 278 | } 279 | ], 280 | "source": [ 281 | "from pymilvus import utility\n", 282 | "utility.has_collection(\"book\")" 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": 35, 288 | "id": "69d590e9-dbca-4b3f-be21-dfacd9163ba8", 289 | "metadata": {}, 290 | "outputs": [ 291 | { 292 | "data": { 293 | "text/plain": [ 294 | "[]" 295 | ] 296 | }, 297 | "execution_count": 35, 298 | "metadata": {}, 299 | "output_type": "execute_result" 300 | } 301 | ], 302 | "source": [ 303 | "from pymilvus import Collection\n", 304 | "collection = Collection(\"book\") # Get an existing collection.\n", 305 | "collection.schema # Return the schema.CollectionSchema of the collection.\n", 306 | "collection.description # Return the description of the collection.\n", 307 | "collection.name # Return the name of the collection.\n", 308 | "collection.is_empty # Return the boolean value that indicates if the collection is empty.\n", 309 | "collection.num_entities # Return the number of entities in the collection.\n", 310 | "collection.primary_field # Return the schema.FieldSchema of the primary key field.\n", 311 | "collection.partitions # Return the list[Partition] object.\n", 312 | "collection.indexes # Return the list[Index] object.\n", 313 | "#collection.properties\t\t# Return the expiration time of data in the collection.\n" 314 | ] 315 | }, 316 | { 317 | "cell_type": "code", 318 | "execution_count": 36, 319 | "id": "17b2cde0-9b52-4894-a894-19c5e5e0e7f3", 320 | "metadata": {}, 321 | "outputs": [ 322 | { 323 | "data": { 324 | "text/plain": [ 325 | "{'auto_id': False, 'description': 'Test book search', 'fields': [{'name': 'book_id', 'description': '', 'type': , 'is_primary': True, 'auto_id': False}, {'name': 'book_name', 'description': '', 'type': , 'params': {'max_length': 200}}, {'name': 'word_count', 'description': '', 'type': }, {'name': 'book_intro', 'description': '', 'type': , 'params': {'dim': 2}}], 'enable_dynamic_field': True}" 326 | ] 327 | }, 328 | "execution_count": 36, 329 | "metadata": {}, 330 | "output_type": "execute_result" 331 | } 332 | ], 333 | "source": [ 334 | "collection.schema " 335 | ] 336 | }, 337 | { 338 | "cell_type": "markdown", 339 | "id": "8bae79cb-e210-4c14-afe8-fa87a06aab6f", 340 | "metadata": {}, 341 | "source": [ 342 | "## Drop a collection\n" 343 | ] 344 | }, 345 | { 346 | "cell_type": "code", 347 | "execution_count": 37, 348 | "id": "ef809d18-b0ef-4ccb-96dc-cc4869e7b83c", 349 | "metadata": {}, 350 | "outputs": [], 351 | "source": [ 352 | "from pymilvus import utility\n", 353 | "#Dropping a collection irreversibly deletes all data within it.\n", 354 | "utility.drop_collection(\"book\")\n" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "id": "d4b1972a-289a-40c7-80d2-50ecfbd4b694", 360 | "metadata": {}, 361 | "source": [ 362 | "## Disconnect from a Milvus server" 363 | ] 364 | }, 365 | { 366 | "cell_type": "code", 367 | "execution_count": 10, 368 | "id": "c1c22c8d-5867-4d76-9332-0723ec10768c", 369 | "metadata": {}, 370 | "outputs": [], 371 | "source": [ 372 | "connections.disconnect(\"default\")" 373 | ] 374 | } 375 | ], 376 | "metadata": { 377 | "kernelspec": { 378 | "display_name": ".venv", 379 | "language": "python", 380 | "name": "python3" 381 | }, 382 | "language_info": { 383 | "codemirror_mode": { 384 | "name": "ipython", 385 | "version": 3 386 | }, 387 | "file_extension": ".py", 388 | "mimetype": "text/x-python", 389 | "name": "python", 390 | "nbconvert_exporter": "python", 391 | "pygments_lexer": "ipython3", 392 | "version": "3.10.12" 393 | } 394 | }, 395 | "nbformat": 4, 396 | "nbformat_minor": 5 397 | } 398 | -------------------------------------------------------------------------------- /notebooks/README.md: -------------------------------------------------------------------------------- 1 | ## Question Answering for Milvus 2 | Question answering is a classic problem in the field of natural language processing. While it sounds like an easy problem to solve, there is still a lot of research going on to improve the techniques that we have now. A large part of solving questions is finding questions that are similar to the one being asked. 3 | 4 | ## Setup Enviroment 5 | You can use Google Colab or Simply run localy. 6 | 7 | In Windows we use Ubuntu WSL 2.0 8 | ``` 9 | bash 10 | ``` 11 | then 12 | ``` 13 | python -m venv .venv 14 | ``` 15 | we activate it 16 | ``` 17 | source .venv/bin/activate 18 | ``` 19 | we dopwnlod the requirements 20 | ``` 21 | wget https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/master/requirements.txt 22 | 23 | ``` 24 | then we install it 25 | 26 | ``` 27 | pip install -r requirements.txt 28 | ``` 29 | then if you are in bash, 30 | 1. Open Visual Studio Code. 31 | 32 | ``` 33 | code . 34 | ``` 35 | 2. We install the followig `Jupyter` extension 36 | ![](assets/2024-02-15-15-40-21.png) 37 | 38 | 3. Press `Ctrl + Shift + P` (or `Cmd + Shift + P` on macOS) to open the command palette. 39 | 4. Type `Python: Select Interpreter` in the command palette and select it. 40 | ![](assets/2024-02-15-15-42-06.png) 41 | 5. A list of available Python interpreters will appear. Scroll down or use the search box to find the WSL Ubuntu interpreter. 42 | ![](assets/2024-02-15-15-42-45.png) 43 | 44 | ## Question Answering Notebook 45 | 46 | This example will show you how to find the similar asked question and get the answer. 47 | 48 | [build_question_answering_engine.ipynb](./1_build_question_answering_engine.ipynb) 49 | Then repeat the previos step by selecting Select Kernel 50 | ![](assets/2024-02-15-15-54-48.png) 51 | and now we can proceed with the notebook. 52 | Run all the cells and and the end you can 53 | open the following link 54 | 55 | [ http://127.0.0.1:7860/](http://127.0.0.1:7860/) 56 | 57 | and you got a Chat where you can make queries to your database. 58 | ![](assets/2024-02-15-17-55-07.png) 59 | -------------------------------------------------------------------------------- /notebooks/assets/2024-02-15-15-40-21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/notebooks/assets/2024-02-15-15-40-21.png -------------------------------------------------------------------------------- /notebooks/assets/2024-02-15-15-42-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/notebooks/assets/2024-02-15-15-42-06.png -------------------------------------------------------------------------------- /notebooks/assets/2024-02-15-15-42-45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/notebooks/assets/2024-02-15-15-42-45.png -------------------------------------------------------------------------------- /notebooks/assets/2024-02-15-15-54-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/notebooks/assets/2024-02-15-15-54-48.png -------------------------------------------------------------------------------- /notebooks/assets/2024-02-15-17-55-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/notebooks/assets/2024-02-15-17-55-07.png -------------------------------------------------------------------------------- /notebooks/hello_milvus.py: -------------------------------------------------------------------------------- 1 | # hello_milvus.py demonstrates the basic operations of PyMilvus, a Python SDK of Milvus. 2 | # 1. connect to Milvus 3 | # 2. create collection 4 | # 3. insert data 5 | # 4. create index 6 | # 5. search, query, and hybrid search on entities 7 | # 6. delete entities by PK 8 | # 7. drop collection 9 | import time 10 | 11 | import numpy as np 12 | from pymilvus import ( 13 | connections, 14 | utility, 15 | FieldSchema, CollectionSchema, DataType, 16 | Collection, 17 | ) 18 | 19 | fmt = "\n=== {:30} ===\n" 20 | search_latency_fmt = "search latency = {:.4f}s" 21 | num_entities, dim = 3000, 8 22 | 23 | ################################################################################# 24 | # 1. connect to Milvus 25 | # Add a new connection alias `default` for Milvus server in `localhost:19530` 26 | # Actually the "default" alias is built-in to PyMilvus. 27 | # If the address of Milvus is the same as `localhost:19530`, you can omit all 28 | # parameters and call the method as: `connections.connect()`. 29 | # 30 | # Note: the `using` parameter of the following methods is default to "default". 31 | print(fmt.format("start connecting to Milvus")) 32 | connections.connect("default", host="localhost", port="19530") 33 | 34 | has = utility.has_collection("hello_milvus") 35 | print(f"Does collection hello_milvus exist in Milvus: {has}") 36 | 37 | ################################################################################# 38 | # 2. create collection 39 | # We're going to create a collection with 3 fields. 40 | # +-+------------+------------+------------------+------------------------------+ 41 | # | | field name | field type | other attributes | field description | 42 | # +-+------------+------------+------------------+------------------------------+ 43 | # |1| "pk" | VarChar | is_primary=True | "primary field" | 44 | # | | | | auto_id=False | | 45 | # +-+------------+------------+------------------+------------------------------+ 46 | # |2| "random" | Double | | "a double field" | 47 | # +-+------------+------------+------------------+------------------------------+ 48 | # |3|"embeddings"| FloatVector| dim=8 | "float vector with dim 8" | 49 | # +-+------------+------------+------------------+------------------------------+ 50 | fields = [ 51 | FieldSchema(name="pk", dtype=DataType.VARCHAR, is_primary=True, auto_id=False, max_length=100), 52 | FieldSchema(name="random", dtype=DataType.DOUBLE), 53 | FieldSchema(name="embeddings", dtype=DataType.FLOAT_VECTOR, dim=dim) 54 | ] 55 | 56 | schema = CollectionSchema(fields, "hello_milvus is the simplest demo to introduce the APIs") 57 | 58 | print(fmt.format("Create collection `hello_milvus`")) 59 | hello_milvus = Collection("hello_milvus", schema, consistency_level="Strong") 60 | 61 | ################################################################################ 62 | # 3. insert data 63 | # We are going to insert 3000 rows of data into `hello_milvus` 64 | # Data to be inserted must be organized in fields. 65 | # 66 | # The insert() method returns: 67 | # - either automatically generated primary keys by Milvus if auto_id=True in the schema; 68 | # - or the existing primary key field from the entities if auto_id=False in the schema. 69 | 70 | print(fmt.format("Start inserting entities")) 71 | rng = np.random.default_rng(seed=19530) 72 | entities = [ 73 | # provide the pk field because `auto_id` is set to False 74 | [str(i) for i in range(num_entities)], 75 | rng.random(num_entities).tolist(), # field random, only supports list 76 | rng.random((num_entities, dim), np.float32), # field embeddings, supports numpy.ndarray and list 77 | ] 78 | 79 | insert_result = hello_milvus.insert(entities) 80 | 81 | row = { 82 | "pk": "19530", 83 | "random": 0.5, 84 | "embeddings": rng.random((1, dim), np.float32)[0] 85 | } 86 | hello_milvus.insert(row) 87 | 88 | hello_milvus.flush() 89 | print(f"Number of entities in Milvus: {hello_milvus.num_entities}") # check the num_entities 90 | 91 | ################################################################################ 92 | # 4. create index 93 | # We are going to create an IVF_FLAT index for hello_milvus collection. 94 | # create_index() can only be applied to `FloatVector` and `BinaryVector` fields. 95 | print(fmt.format("Start Creating index IVF_FLAT")) 96 | index = { 97 | "index_type": "IVF_FLAT", 98 | "metric_type": "L2", 99 | "params": {"nlist": 128}, 100 | } 101 | 102 | hello_milvus.create_index("embeddings", index) 103 | 104 | ################################################################################ 105 | # 5. search, query, and hybrid search 106 | # After data were inserted into Milvus and indexed, you can perform: 107 | # - search based on vector similarity 108 | # - query based on scalar filtering(boolean, int, etc.) 109 | # - hybrid search based on vector similarity and scalar filtering. 110 | # 111 | 112 | # Before conducting a search or a query, you need to load the data in `hello_milvus` into memory. 113 | print(fmt.format("Start loading")) 114 | hello_milvus.load() 115 | 116 | # ----------------------------------------------------------------------------- 117 | # search based on vector similarity 118 | print(fmt.format("Start searching based on vector similarity")) 119 | vectors_to_search = entities[-1][-2:] 120 | search_params = { 121 | "metric_type": "L2", 122 | "params": {"nprobe": 10}, 123 | } 124 | 125 | start_time = time.time() 126 | result = hello_milvus.search(vectors_to_search, "embeddings", search_params, limit=3, output_fields=["random"]) 127 | end_time = time.time() 128 | 129 | for hits in result: 130 | for hit in hits: 131 | print(f"hit: {hit}, random field: {hit.entity.get('random')}") 132 | print(search_latency_fmt.format(end_time - start_time)) 133 | 134 | # ----------------------------------------------------------------------------- 135 | # query based on scalar filtering(boolean, int, etc.) 136 | print(fmt.format("Start querying with `random > 0.5`")) 137 | 138 | start_time = time.time() 139 | result = hello_milvus.query(expr="random > 0.5", output_fields=["random", "embeddings"]) 140 | end_time = time.time() 141 | 142 | print(f"query result:\n-{result[0]}") 143 | print(search_latency_fmt.format(end_time - start_time)) 144 | 145 | # ----------------------------------------------------------------------------- 146 | # pagination 147 | r1 = hello_milvus.query(expr="random > 0.5", limit=4, output_fields=["random"]) 148 | r2 = hello_milvus.query(expr="random > 0.5", offset=1, limit=3, output_fields=["random"]) 149 | print(f"query pagination(limit=4):\n\t{r1}") 150 | print(f"query pagination(offset=1, limit=3):\n\t{r2}") 151 | 152 | 153 | # ----------------------------------------------------------------------------- 154 | # hybrid search 155 | print(fmt.format("Start hybrid searching with `random > 0.5`")) 156 | 157 | start_time = time.time() 158 | result = hello_milvus.search(vectors_to_search, "embeddings", search_params, limit=3, expr="random > 0.5", output_fields=["random"]) 159 | end_time = time.time() 160 | 161 | for hits in result: 162 | for hit in hits: 163 | print(f"hit: {hit}, random field: {hit.entity.get('random')}") 164 | print(search_latency_fmt.format(end_time - start_time)) 165 | 166 | ############################################################################### 167 | # 6. delete entities by PK 168 | # You can delete entities by their PK values using boolean expressions. 169 | ids = insert_result.primary_keys 170 | 171 | expr = f'pk in ["{ids[0]}" , "{ids[1]}"]' 172 | print(fmt.format(f"Start deleting with expr `{expr}`")) 173 | 174 | result = hello_milvus.query(expr=expr, output_fields=["random", "embeddings"]) 175 | print(f"query before delete by expr=`{expr}` -> result: \n-{result[0]}\n-{result[1]}\n") 176 | 177 | hello_milvus.delete(expr) 178 | 179 | result = hello_milvus.query(expr=expr, output_fields=["random", "embeddings"]) 180 | print(f"query after delete by expr=`{expr}` -> result: {result}\n") 181 | 182 | 183 | ############################################################################### 184 | # 7. drop collection 185 | # Finally, drop the hello_milvus collection 186 | print(fmt.format("Drop collection `hello_milvus`")) 187 | utility.drop_collection("hello_milvus") 188 | -------------------------------------------------------------------------------- /notebooks/workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/notebooks/workflow.png -------------------------------------------------------------------------------- /openapi-extension/README.md: -------------------------------------------------------------------------------- 1 | # OpenAPI Extension 2 | 3 | OpenAPI (formerly known as Swagger) is an open standard for describing and documenting REST APIs. An OpenAPI document defines the resources and operations that are supported by an API, including request parameters and response data, along with details such as server URLs and authentication methods. 4 | 5 | An OpenAPI document describes a REST API in terms of paths and operations. A path identifies a particular resource that can be accessed by using the API (for example, a hotel reservation or a customer record). An operation defines a particular action that can be performed on that resource (such as creating, retrieving, updating, or deleting it). 6 | 7 | The OpenAPI document specifies all of the details for each operation, including the HTTP method that is used, request parameters, the data included in the request body, and the structure of the response body. 8 | 9 | ## API definition 10 | 11 | To create a custom extension, you need access to an OpenAPI document that describes the REST API you want to integrate with. Many third-party services publish OpenAPI documents that describe their APIs, which you can download and import. For an API that your company maintains, you can use standard tools to create an OpenAPI document that describes it. 12 | 13 | The SwaggerHub website offers an OpenAPI 3.0 Tutorial, and tools to help you develop and validate your OpenAPI document. You can use the online Swagger editor to convert your OpenAPI document to the correct format and OpenAPI version. 14 | 15 | The OpenAPI document must satisfy the following requirements and restrictions: 16 | 17 | - The document must conform to the OpenAPI 3.0 specification. If you have an OpenAPI (or Swagger) document that uses an earlier version of the specification, you can use the online Swagger editor to convert it to OpenAPI 3.0. 18 | [https://editor.swagger.io/](https://editor.swagger.io/) 19 | 20 | - The document must be in JSON format (YAML is not supported). If you have a YAML document, you can use the online Swagger editor to convert it to JSON. 21 | 22 | - The size of the document must not be more than 4 MB if you have a Plus or higher plan of watsonx Assistant. However, if you have an Enteprise plan with data isolation, the size of the document must not be more than 8 MB. 23 | 24 | - The content-type must be application/json. 25 | - Each operation must have a clear and concise summary. The summary text is used in the UI to describe the operations that are available from an action, so it should be short and meaningful to someone who is building an assistant. 26 | - Relative URLs are currently not supported. 27 | - Only Basic, Bearer, OAuth 2.0, and API key authentication are supported. 28 | For OAuth 2.0 authentication, Authorization Code, Client Credentials, Password, and custom grant types that starts with x- are supported. Note that x- is used by the IBM IAM authentication mechanism and by watsonx. 29 | - Schemas that are defined by using anyOf, oneOf, and allOf are currently not supported. 30 | 31 | - In addition, any call to the external API must complete within 30 seconds. 32 | 33 | 34 | # Testing OpenAPI extensions 35 | 36 | We developed a simple notebook to verify the openapi.json extensions. 37 | 38 | ## Examples 1 39 | 40 | ``` 41 | cd example1 42 | 43 | ``` 44 | -------------------------------------------------------------------------------- /openapi-extension/chat/app.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | from flask import Flask, request, jsonify 4 | 5 | app = Flask(__name__) 6 | 7 | @app.route('/chat', methods=['POST']) 8 | def chat(): 9 | params = request.get_json() 10 | message = params.get('message') 11 | history = params.get('history', []) 12 | 13 | if not message: 14 | return jsonify({"message": "Missing 'message' parameter"}), 400 15 | 16 | history, chat_history = custom_chat_function(message, history) 17 | 18 | response_data = { 19 | "message": message, 20 | "response": chat_history[-1][1], 21 | "history": chat_history 22 | } 23 | 24 | return jsonify(response_data), 200 25 | 26 | def custom_chat_function(message, history): 27 | # Implement your custom chat function here 28 | # For example, using a simple echo response: 29 | response = f"Echo: {message}" 30 | history.append((message, response)) 31 | return history, history 32 | 33 | if __name__ == '__main__': 34 | app.run(host='0.0.0.0', port=8080, debug=True) 35 | -------------------------------------------------------------------------------- /openapi-extension/chat/openapi.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "title": "Chat API", 5 | "version": "1.0.0" 6 | }, 7 | "servers": [ 8 | { 9 | "url": "http://127.0.0.1:8080" 10 | } 11 | ], 12 | "paths": { 13 | "/chat": { 14 | "post": { 15 | "summary": "Send a message to the chat and receive a response", 16 | "requestBody": { 17 | "required": true, 18 | "content": { 19 | "application/json": { 20 | "schema": { 21 | "type": "object", 22 | "properties": { 23 | "message": { 24 | "type": "string", 25 | "description": "The message to send to the chat" 26 | }, 27 | "history": { 28 | "type": "array", 29 | "items": { 30 | "type": "object", 31 | "properties": { 32 | "message": { 33 | "type": "string" 34 | }, 35 | "response": { 36 | "type": "string" 37 | } 38 | } 39 | }, 40 | "description": "The chat history (optional)" 41 | } 42 | } 43 | } 44 | } 45 | } 46 | }, 47 | "responses": { 48 | "200": { 49 | "description": "Successful response with the chat message, response, and updated history", 50 | "content": { 51 | "application/json": { 52 | "schema": { 53 | "type": "object", 54 | "properties": { 55 | "message": { 56 | "type": "string", 57 | "description": "The message sent to the chat" 58 | }, 59 | "response": { 60 | "type": "string", 61 | "description": "The chat response" 62 | }, 63 | "history": { 64 | "type": "array", 65 | "items": { 66 | "type": "object", 67 | "properties": { 68 | "message": { 69 | "type": "string" 70 | }, 71 | "response": { 72 | "type": "string" 73 | } 74 | } 75 | }, 76 | "description": "The updated chat history" 77 | } 78 | } 79 | } 80 | } 81 | } 82 | }, 83 | "400": { 84 | "description": "Missing required parameter", 85 | "content": { 86 | "application/json": { 87 | "schema": { 88 | "type": "object", 89 | "properties": { 90 | "message": { 91 | "type": "string", 92 | "description": "Error message explaining the missing parameter" 93 | } 94 | } 95 | } 96 | } 97 | } 98 | }, 99 | "500": { 100 | "description": "Internal server error", 101 | "content": { 102 | "application/json": { 103 | "schema": { 104 | "type": "object", 105 | "properties": { 106 | "message": { 107 | "type": "string", 108 | "description": "Error message describing the internal issue" 109 | } 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | } 118 | }, 119 | "components": { 120 | "securitySchemes": { 121 | "ApiKey": { 122 | "type": "apiKey", 123 | "name": "APIKey", 124 | "in": "header" 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /openapi-extension/example1/README.md: -------------------------------------------------------------------------------- 1 | Hello World Python application with a REST API and a simple OpenAPI Specification (openapi.json) 2 | 3 | 4 | Explanation: 5 | 6 | The app.py file defines a simple Flask app with a single route / that returns a JSON response with the message "Hello, world!". 7 | The openapi.json file defines the OpenAPI specification for the API. It includes information about the title, version, and paths available in the API. 8 | Each path has an operation defined (in this case, only GET). 9 | The operation has a summary describing its functionality and a response object. 10 | The response object specifies the expected content type (application/json) and schema of the response data. 11 | This example uses basic JSON schema with a single property message. 12 | Additional Notes: 13 | 14 | This example uses Flask for simplicity, but you can use other frameworks like FastAPI or Django for more complex APIs. 15 | You can adjust the openapi.json file to include additional information about your API, such as security requirements, additional paths, and operation parameters. 16 | -------------------------------------------------------------------------------- /openapi-extension/example1/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/') 6 | def hello_world(): 7 | return jsonify({'message': 'Hello, world!'}) 8 | 9 | if __name__ == '__main__': 10 | app.run(debug=True) 11 | -------------------------------------------------------------------------------- /openapi-extension/example1/openapi.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "title": "Hello World API", 5 | "version": "1.0.0" 6 | }, 7 | "servers": [ 8 | { 9 | "url": "http://127.0.0.1:5000" 10 | } 11 | ], 12 | "paths": { 13 | "/": { 14 | "get": { 15 | "summary": "Returns a 'Hello, world!' message", 16 | "responses": { 17 | "200": { 18 | "description": "Successful response", 19 | "content": { 20 | "application/json": { 21 | "schema": { 22 | "type": "object", 23 | "properties": { 24 | "message": { 25 | "type": "string", 26 | "example": "Hello, world!" 27 | } 28 | } 29 | } 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /openapi-extension/example2/README.md: -------------------------------------------------------------------------------- 1 | Hello World Python application with a REST API and a simple OpenAPI Specification (openapi.json) 2 | 3 | 4 | Explanation: 5 | 6 | The app.py file defines a simple Flask app with a single route / that returns a JSON response with the message "Hello, world!". 7 | The openapi.json file defines the OpenAPI specification for the API. It includes information about the title, version, and paths available in the API. 8 | Each path has an operation defined (in this case, only GET). 9 | The operation has a summary describing its functionality and a response object. 10 | The response object specifies the expected content type (application/json) and schema of the response data. 11 | This example uses basic JSON schema with a single property message. 12 | Additional Notes: 13 | 14 | This example uses Flask for simplicity, but you can use other frameworks like FastAPI or Django for more complex APIs. 15 | You can adjust the openapi.json file to include additional information about your API, such as security requirements, additional paths, and operation parameters. 16 | -------------------------------------------------------------------------------- /openapi-extension/example2/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify, request 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/') 6 | def hello_world(): 7 | return jsonify({'message': 'Hello, world!'}) 8 | 9 | @app.route('/cloud-function', methods=['POST']) 10 | def cloud_function(): 11 | data = request.get_json() 12 | 13 | if 'object_of_interest' not in data: 14 | return jsonify({'message': 'Missing required parameter: object_of_interest'}), 400 15 | 16 | object_of_interest = data['object_of_interest'] 17 | summary = f"Summary about {object_of_interest}." 18 | 19 | return jsonify({ 20 | 'object_of_interest': object_of_interest, 21 | 'summary': summary 22 | }) 23 | 24 | if __name__ == '__main__': 25 | app.run(debug=True, port=8080) 26 | -------------------------------------------------------------------------------- /openapi-extension/example2/openapi.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "title": "Cloud Function API", 5 | "version": "1.0.0" 6 | }, 7 | "servers": [ 8 | { 9 | "url": "http://127.0.0.1:8080" 10 | } 11 | ], 12 | "paths": { 13 | "/cloud-function": { 14 | "post": { 15 | "summary": "Get information about an object of interest", 16 | "requestBody": { 17 | "required": true, 18 | "content": { 19 | "application/json": { 20 | "schema": { 21 | "type": "object", 22 | "properties": { 23 | "object_of_interest": { 24 | "type": "string", 25 | "description": "The name of the object you want information about" 26 | } 27 | } 28 | } 29 | } 30 | } 31 | }, 32 | "responses": { 33 | "200": { 34 | "description": "Successful response with object information and optional summary", 35 | "content": { 36 | "application/json": { 37 | "schema": { 38 | "type": "object", 39 | "properties": { 40 | "object_of_interest": { 41 | "type": "string", 42 | "description": "The name of the object provided" 43 | }, 44 | "summary": { 45 | "type": "string", 46 | "description": "Wikipedia summary of the object (optional)" 47 | }, 48 | "message": { 49 | "type": "string", 50 | "description": "Error message if Wikipedia summary failed" 51 | } 52 | } 53 | } 54 | } 55 | } 56 | }, 57 | "400": { 58 | "description": "Missing required parameter", 59 | "content": { 60 | "application/json": { 61 | "schema": { 62 | "type": "object", 63 | "properties": { 64 | "message": { 65 | "type": "string", 66 | "description": "Error message explaining the missing parameter" 67 | } 68 | } 69 | } 70 | } 71 | } 72 | }, 73 | "500": { 74 | "description": "Internal server error", 75 | "content": { 76 | "application/json": { 77 | "schema": { 78 | "type": "object", 79 | "properties": { 80 | "message": { 81 | "type": "string", 82 | "description": "Error message describing the internal issue" 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | } 90 | } 91 | } 92 | }, 93 | "components": { 94 | "securitySchemes": { 95 | "ApiKey": { 96 | "type": "apiKey", 97 | "name": "APIKey", 98 | "in": "header" 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /openapi-extension/example3/README.md: -------------------------------------------------------------------------------- 1 | Explanation: 2 | 3 | The spec adheres to OpenAPI 3.0 and uses JSON format. 4 | It defines a single path /cloud-function with a POST method. 5 | The summary for the operation clearly describes its purpose. 6 | The request body schema specifies the expected JSON structure with the object_of_interest parameter. 7 | The response schema describes the possible responses: success with optional summary or error messages. 8 | Error codes and descriptions are included for clarity. 9 | Basic authentication using an API key in the header is defined. 10 | Remember: 11 | 12 | Replace ApiKey with your actual authentication scheme if applicable. 13 | This spec doesn't include authentication details for the Wikipedia API call. 14 | Ensure your server responds within 30 seconds to comply with Watson Assistant limitations. -------------------------------------------------------------------------------- /openapi-extension/example3/app.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | from flask import Flask, request, jsonify 4 | 5 | app = Flask(__name__) 6 | 7 | @app.route('/cloud-function', methods=['POST']) 8 | def main(): 9 | params = request.get_json() 10 | object_of_interest = params.get('object_of_interest') 11 | 12 | if not object_of_interest: 13 | return jsonify({"message": "Missing 'object_of_interest' parameter"}), 400 14 | 15 | response_data = {"object_of_interest": object_of_interest} 16 | 17 | try: 18 | url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{object_of_interest}?redirect=true" 19 | headers = {'accept': 'application/json'} 20 | response = requests.get(url, headers=headers) 21 | response.raise_for_status() 22 | 23 | data = json.loads(response.content) 24 | summary = data.get('extract') 25 | response_data["summary"] = summary 26 | 27 | except requests.exceptions.RequestException as e: 28 | response_data["message"] = f"Error fetching Wikipedia summary: {str(e)}" 29 | 30 | return jsonify(response_data), 200 31 | 32 | if __name__ == '__main__': 33 | app.run(host='0.0.0.0', port=8080, debug=True) 34 | -------------------------------------------------------------------------------- /openapi-extension/example3/openapi.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "info": { 4 | "title": "Cloud Function API", 5 | "version": "1.0.0" 6 | }, 7 | "servers": [ 8 | { 9 | "url": "http://127.0.0.1:8080" 10 | } 11 | ], 12 | "paths": { 13 | "/cloud-function": { 14 | "post": { 15 | "summary": "Get information about an object of interest", 16 | "requestBody": { 17 | "required": true, 18 | "content": { 19 | "application/json": { 20 | "schema": { 21 | "type": "object", 22 | "properties": { 23 | "object_of_interest": { 24 | "type": "string", 25 | "description": "The name of the object you want information about" 26 | } 27 | } 28 | } 29 | } 30 | } 31 | }, 32 | "responses": { 33 | "200": { 34 | "description": "Successful response with object information and optional summary", 35 | "content": { 36 | "application/json": { 37 | "schema": { 38 | "type": "object", 39 | "properties": { 40 | "object_of_interest": { 41 | "type": "string", 42 | "description": "The name of the object provided" 43 | }, 44 | "summary": { 45 | "type": "string", 46 | "description": "Wikipedia summary of the object (optional)" 47 | }, 48 | "message": { 49 | "type": "string", 50 | "description": "Error message if Wikipedia summary failed" 51 | } 52 | } 53 | } 54 | } 55 | } 56 | }, 57 | "400": { 58 | "description": "Missing required parameter", 59 | "content": { 60 | "application/json": { 61 | "schema": { 62 | "type": "object", 63 | "properties": { 64 | "message": { 65 | "type": "string", 66 | "description": "Error message explaining the missing parameter" 67 | } 68 | } 69 | } 70 | } 71 | } 72 | }, 73 | "500": { 74 | "description": "Internal server error", 75 | "content": { 76 | "application/json": { 77 | "schema": { 78 | "type": "object", 79 | "properties": { 80 | "message": { 81 | "type": "string", 82 | "description": "Error message describing the internal issue" 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | } 90 | } 91 | } 92 | }, 93 | "components": { 94 | "securitySchemes": { 95 | "ApiKey": { 96 | "type": "apiKey", 97 | "name": "APIKey", 98 | "in": "header" 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /openapi-extension/openapi-notebook.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## Testing OpenAPI - Swagger Applications" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "In ordering to connect a custom serveless application in Watson Assistant we Require to build a custom extension designed in openapi, for this reason in this notebook we just learn how to build it , starting with the hello world example and later build a more complex extension." 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## Example 1" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 5, 27 | "metadata": {}, 28 | "outputs": [ 29 | { 30 | "name": "stdout", 31 | "output_type": "stream", 32 | "text": [ 33 | "API endpoint '/' is working well.\n" 34 | ] 35 | } 36 | ], 37 | "source": [ 38 | "import json\n", 39 | "import requests\n", 40 | "\n", 41 | "# Load the openapi.json file\n", 42 | "with open('example1/openapi.json', 'r') as file:\n", 43 | " openapi_data = json.load(file)\n", 44 | "\n", 45 | "# Get the base URL of the API from the openapi.json file\n", 46 | "base_url = openapi_data['servers'][0]['url']\n", 47 | "\n", 48 | "# Define a function to test a specific API endpoint\n", 49 | "def test_endpoint(endpoint, method, parameters=None):\n", 50 | " url = f\"{base_url}{endpoint}\"\n", 51 | " response = requests.request(method, url, params=parameters)\n", 52 | " \n", 53 | " if response.status_code == 200:\n", 54 | " print(f\"API endpoint '{endpoint}' is working well.\")\n", 55 | " else:\n", 56 | " print(f\"API endpoint '{endpoint}' returned status code {response.status_code}.\")\n", 57 | "\n", 58 | "# Use the function to test the example endpoint\n", 59 | "example_endpoint = '/'\n", 60 | "example_method = 'GET'\n", 61 | "\n", 62 | "test_endpoint(example_endpoint, example_method)\n" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": {}, 68 | "source": [ 69 | "## Example 2" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 11, 75 | "metadata": {}, 76 | "outputs": [ 77 | { 78 | "name": "stdout", 79 | "output_type": "stream", 80 | "text": [ 81 | "API endpoint '/' is working well.\n", 82 | "API endpoint '/cloud-function' is working well.\n" 83 | ] 84 | } 85 | ], 86 | "source": [ 87 | "import json\n", 88 | "import requests\n", 89 | "\n", 90 | "# Load the openapi.json file\n", 91 | "with open('example2/openapi.json', 'r') as file:\n", 92 | " openapi_data = json.load(file)\n", 93 | "\n", 94 | "# Get the base URL of the API from the openapi.json file\n", 95 | "base_url = openapi_data['servers'][0]['url']\n", 96 | "\n", 97 | "# Define a function to test a specific API endpoint\n", 98 | "def test_endpoint(endpoint, method, parameters=None, data=None):\n", 99 | " url = f\"{base_url}{endpoint}\"\n", 100 | " response = requests.request(method, url, params=parameters, json=data)\n", 101 | " \n", 102 | " if response.status_code == 200:\n", 103 | " print(f\"API endpoint '{endpoint}' is working well.\")\n", 104 | " else:\n", 105 | " print(f\"API endpoint '{endpoint}' returned status code {response.status_code}.\")\n", 106 | "\n", 107 | "# Test the GET request on the root endpoint\n", 108 | "test_endpoint('/', 'GET')\n", 109 | "\n", 110 | "# Test the POST request on the /cloud-function endpoint\n", 111 | "example_endpoint = '/cloud-function'\n", 112 | "example_method = 'POST'\n", 113 | "example_data = {'object_of_interest': 'Eiffel Tower'}\n", 114 | "\n", 115 | "test_endpoint(example_endpoint, example_method, data=example_data)" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "metadata": {}, 121 | "source": [ 122 | "## Example 3" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 12, 128 | "metadata": {}, 129 | "outputs": [ 130 | { 131 | "name": "stdout", 132 | "output_type": "stream", 133 | "text": [ 134 | "API endpoint '/cloud-function' is working well.\n" 135 | ] 136 | } 137 | ], 138 | "source": [ 139 | "import json\n", 140 | "import requests\n", 141 | "\n", 142 | "# Load the openapi.json file\n", 143 | "with open('example3/openapi.json', 'r') as file:\n", 144 | " openapi_data = json.load(file)\n", 145 | "\n", 146 | "# Get the base URL of the API from the openapi.json file\n", 147 | "base_url = openapi_data['servers'][0]['url']\n", 148 | "\n", 149 | "# Define a function to test a specific API endpoint\n", 150 | "def test_endpoint(endpoint, method, parameters=None, data=None):\n", 151 | " url = f\"{base_url}{endpoint}\"\n", 152 | " response = requests.request(method, url, params=parameters, json=data)\n", 153 | " \n", 154 | " if response.status_code == 200:\n", 155 | " print(f\"API endpoint '{endpoint}' is working well.\")\n", 156 | " else:\n", 157 | " print(f\"API endpoint '{endpoint}' returned status code {response.status_code}.\")\n", 158 | "# Test the POST request on the /cloud-function endpoint\n", 159 | "example_endpoint = '/cloud-function'\n", 160 | "example_method = 'POST'\n", 161 | "example_data = {'object_of_interest': 'Eiffel Tower'}\n", 162 | "\n", 163 | "test_endpoint(example_endpoint, example_method, data=example_data)" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": 14, 169 | "metadata": {}, 170 | "outputs": [], 171 | "source": [ 172 | "# Define a function to test a specific API endpoint\n", 173 | "def run_endpoint(endpoint, method, parameters=None, data=None):\n", 174 | " url = f\"{base_url}{endpoint}\"\n", 175 | " response = requests.request(method, url, params=parameters, json=data)\n", 176 | " \n", 177 | " if response.status_code == 200:\n", 178 | " print(f\"API endpoint '{endpoint}' is working well.\")\n", 179 | " else:\n", 180 | " print(f\"API endpoint '{endpoint}' returned status code {response.status_code}.\")\n", 181 | " \n", 182 | " return response" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": 15, 188 | "metadata": {}, 189 | "outputs": [ 190 | { 191 | "name": "stdout", 192 | "output_type": "stream", 193 | "text": [ 194 | "API endpoint '/cloud-function' is working well.\n", 195 | "Response data:\n", 196 | "{\n", 197 | " \"object_of_interest\": \"Eiffel Tower\",\n", 198 | " \"summary\": \"The Eiffel Tower is a wrought-iron lattice tower on the Champ de Mars in Paris, France. It is named after the engineer Gustave Eiffel, whose company designed and built the tower from 1887 to 1889.\"\n", 199 | "}\n" 200 | ] 201 | } 202 | ], 203 | "source": [ 204 | "# Define a function to test the API endpoint and print the results\n", 205 | "def test_and_print_results(endpoint, method, data=None):\n", 206 | " response = run_endpoint(endpoint, method, data=data)\n", 207 | " \n", 208 | " if response.status_code == 200:\n", 209 | " response_data = response.json()\n", 210 | " print(\"Response data:\")\n", 211 | " print(json.dumps(response_data, indent=2))\n", 212 | " else:\n", 213 | " print(\"Error occurred. No data to display.\")\n", 214 | "\n", 215 | "# Test the POST request on the /cloud-function endpoint\n", 216 | "example_endpoint = '/cloud-function'\n", 217 | "example_method = 'POST'\n", 218 | "example_data = {'object_of_interest': 'Eiffel Tower'}\n", 219 | "test_and_print_results(example_endpoint, example_method, data=example_data)" 220 | ] 221 | }, 222 | { 223 | "cell_type": "markdown", 224 | "metadata": {}, 225 | "source": [ 226 | "## Chat" 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": 19, 232 | "metadata": {}, 233 | "outputs": [ 234 | { 235 | "name": "stdout", 236 | "output_type": "stream", 237 | "text": [ 238 | "API endpoint '/chat' is working well.\n", 239 | "API endpoint '/chat' is working well.\n", 240 | "Response data:\n", 241 | "{\n", 242 | " \"history\": [\n", 243 | " [\n", 244 | " \"Hello Chat\",\n", 245 | " \"Echo: Hello Chat\"\n", 246 | " ]\n", 247 | " ],\n", 248 | " \"message\": \"Hello Chat\",\n", 249 | " \"response\": \"Echo: Hello Chat\"\n", 250 | "}\n" 251 | ] 252 | } 253 | ], 254 | "source": [ 255 | "import json\n", 256 | "import requests\n", 257 | "\n", 258 | "# Load the openapi.json file\n", 259 | "with open('chat/openapi.json', 'r') as file:\n", 260 | " openapi_data = json.load(file)\n", 261 | "\n", 262 | "# Get the base URL of the API from the openapi.json file\n", 263 | "base_url = openapi_data['servers'][0]['url']\n", 264 | "\n", 265 | "# Define a function to test a specific API endpoint\n", 266 | "def test_endpoint(endpoint, method, parameters=None, data=None):\n", 267 | " url = f\"{base_url}{endpoint}\"\n", 268 | " response = requests.request(method, url, params=parameters, json=data)\n", 269 | " if response.status_code == 200:\n", 270 | " print(f\"API endpoint '{endpoint}' is working well.\")\n", 271 | " else:\n", 272 | " print(f\"API endpoint '{endpoint}' returned status code {response.status_code}.\")\n", 273 | "\n", 274 | "# Define a function to run a specific API endpoint\n", 275 | "def run_endpoint(endpoint, method, parameters=None, data=None):\n", 276 | " url = f\"{base_url}{endpoint}\"\n", 277 | " response = requests.request(method, url, params=parameters, json=data)\n", 278 | " \n", 279 | " if response.status_code == 200:\n", 280 | " print(f\"API endpoint '{endpoint}' is working well.\")\n", 281 | " else:\n", 282 | " print(f\"API endpoint '{endpoint}' returned status code {response.status_code}.\")\n", 283 | " \n", 284 | " return response\n", 285 | "\n", 286 | "# Define a function to test the API endpoint and print the results\n", 287 | "def test_and_print_results(endpoint, method, data=None):\n", 288 | " response = run_endpoint(endpoint, method, data=data)\n", 289 | " \n", 290 | " if response.status_code == 200:\n", 291 | " response_data = response.json()\n", 292 | " print(\"Response data:\")\n", 293 | " print(json.dumps(response_data, indent=2))\n", 294 | " else:\n", 295 | " print(\"Error occurred. No data to display.\")\n", 296 | "\n", 297 | "# Test the POST request on the /chat endpoint\n", 298 | "example_endpoint = '/chat'\n", 299 | "example_method = 'POST'\n", 300 | "example_data = {'message': 'Hello Chat'}\n", 301 | "\n", 302 | "test_endpoint(example_endpoint, example_method, data=example_data)\n", 303 | "test_and_print_results(example_endpoint, example_method, data=example_data)\n" 304 | ] 305 | } 306 | ], 307 | "metadata": { 308 | "kernelspec": { 309 | "display_name": ".venv", 310 | "language": "python", 311 | "name": "python3" 312 | }, 313 | "language_info": { 314 | "codemirror_mode": { 315 | "name": "ipython", 316 | "version": 3 317 | }, 318 | "file_extension": ".py", 319 | "mimetype": "text/x-python", 320 | "name": "python", 321 | "nbconvert_exporter": "python", 322 | "pygments_lexer": "ipython3", 323 | "version": "3.10.12" 324 | } 325 | }, 326 | "nbformat": 4, 327 | "nbformat_minor": 2 328 | } 329 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | towhee 2 | towhee.models 3 | gradio 4 | pymilvus==2.2.11 5 | flask -------------------------------------------------------------------------------- /voice-interaction/README.md: -------------------------------------------------------------------------------- 1 | ## Watson Assistant for Voice Interaction 2 | In this section we are going to integrate the Watson Assistant for Voice Interaction. 3 | ![](assets/2024-03-11-17-10-13.png) -------------------------------------------------------------------------------- /voice-interaction/assets/2024-03-11-17-10-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/voice-interaction/assets/2024-03-11-17-10-13.png -------------------------------------------------------------------------------- /watson-assistant/API-Watson.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# API Test WatsonX Medical\n", 8 | "In thise notebook just we will test our api to make queries to our server api\n", 9 | "that has running the backend app of the container. " 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 2, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "from gradio_client import Client\n", 19 | "import json\n", 20 | "import requests\n", 21 | "def test_api_connection(api_url):\n", 22 | " try:\n", 23 | " response = requests.get(api_url, timeout=5)\n", 24 | " if response.status_code == 200:\n", 25 | " return True\n", 26 | " except requests.exceptions.RequestException:\n", 27 | " pass\n", 28 | " return False" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 3, 34 | "metadata": {}, 35 | "outputs": [ 36 | { 37 | "name": "stdout", 38 | "output_type": "stream", 39 | "text": [ 40 | "Connected to API: https://watsonx-medical.16jc1w8uq8wb.us-south.codeengine.appdomain.cloud/\n" 41 | ] 42 | } 43 | ], 44 | "source": [ 45 | "REMOTE_API = \"https://watsonx-medical.16jc1w8uq8wb.us-south.codeengine.appdomain.cloud/\"\n", 46 | "LOCAL_API = \"http://127.0.0.1:7860/\"\n", 47 | "api_to_connect = None\n", 48 | "if test_api_connection(REMOTE_API):\n", 49 | " api_to_connect = REMOTE_API\n", 50 | "elif test_api_connection(LOCAL_API):\n", 51 | " api_to_connect = LOCAL_API\n", 52 | "else:\n", 53 | " print(\"There are no APIs to connect\")\n", 54 | "\n", 55 | "if api_to_connect:\n", 56 | " print(f\"Connected to API: {api_to_connect}\")\n" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": 4, 62 | "metadata": {}, 63 | "outputs": [], 64 | "source": [ 65 | "query=\"I have drink too much alcohol and I have headache what should do\"" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": 5, 71 | "metadata": {}, 72 | "outputs": [ 73 | { 74 | "name": "stdout", 75 | "output_type": "stream", 76 | "text": [ 77 | "Loaded as API: https://watsonx-medical.16jc1w8uq8wb.us-south.codeengine.appdomain.cloud/ ✔\n" 78 | ] 79 | } 80 | ], 81 | "source": [ 82 | "client = Client(api_to_connect)\n", 83 | "result = client.predict(\n", 84 | "\t\tquery,\t# str in 'message' Textbox component\n", 85 | "\t\tapi_name=\"/predict\"\n", 86 | ")" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": 6, 92 | "metadata": {}, 93 | "outputs": [ 94 | { 95 | "name": "stdout", 96 | "output_type": "stream", 97 | "text": [ 98 | "{\n", 99 | " \"user\": \"I have drink too much alcohol and I have headache what should do\",\n", 100 | " \"ai\": \"If you've had too much alcohol and are experiencing a headache, it's important to drink plenty of water and rest. Over-the-counter pain relievers can also help alleviate the pain. However, if your headache persists or worsens, or if you experience any other symptoms such as chest pain, difficulty breathing, or nausea, seek immediate medical attention.\"\n", 101 | "}\n" 102 | ] 103 | } 104 | ], 105 | "source": [ 106 | "# Read the JSON file\n", 107 | "with open(result, 'r') as f:\n", 108 | " data = json.load(f)\n", 109 | "# Convert the list to a dictionary\n", 110 | "data_dict = {\"user\": data[0][0], \"ai\": data[0][1]}\n", 111 | "# Print the content of the dictionary\n", 112 | "output_json=json.dumps(data_dict, indent=2)\n", 113 | "print(output_json)\n", 114 | " " 115 | ] 116 | } 117 | ], 118 | "metadata": { 119 | "kernelspec": { 120 | "display_name": ".venv", 121 | "language": "python", 122 | "name": "python3" 123 | }, 124 | "language_info": { 125 | "codemirror_mode": { 126 | "name": "ipython", 127 | "version": 3 128 | }, 129 | "file_extension": ".py", 130 | "mimetype": "text/x-python", 131 | "name": "python", 132 | "nbconvert_exporter": "python", 133 | "pygments_lexer": "ipython3", 134 | "version": "3.10.12" 135 | } 136 | }, 137 | "nbformat": 4, 138 | "nbformat_minor": 2 139 | } 140 | -------------------------------------------------------------------------------- /watson-assistant/README.md: -------------------------------------------------------------------------------- 1 | 2 | ![](assets/2024-03-13-10-30-20.png) 3 | 4 | ## Creating a Watson Assistant with a Custom Extension (MedicX) 5 | 6 | 7 | 8 | This tutorial guides you through creating a Watson assistant that utilizes a custom extension (MedicX) to interact with an external API. We'll achieve this without dialog skills or webhooks, focusing on modern actions and extension calls. 9 | 10 | ### Prerequisites: 11 | 12 | * An IBM Cloud account with access to Watson Assistant service 13 | * Basic understanding of Watson Assistant and creating actions 14 | 15 | ### Steps: 16 | 17 | 1. **Create a New Watson Assistant:** 18 | * Log in to your IBM Cloud account and access the Watson Assistant service. 19 | * Click on "Create assistant" and provide a name and description for your assistant. 20 | ![](assets/2024-03-11-18-54-49.png) 21 | 22 | * Click "Create" to initiate the assistant creation. 23 | ![](assets/2024-03-11-18-56-03.png) 24 | 2. **Build the Custom Extension:** 25 | * Navigate to the "Integrations" tab within your newly created assistant. 26 | * Click on "Build custom extension." 27 | ![](assets/2024-03-11-19-00-33.png) 28 | * In the "Basic information" section, provide a name and description for your custom extension (e.g., MedicX Extension). 29 | ![](assets/2024-03-11-19-01-23.png) 30 | * Click "Next" to proceed to the "Import OpenAPI" step. 31 | * In this step, you'll import the OpenAPI document (openapi.json) that describes the MedicX API. You can typically find this file on the MedicX developer portal or documentation. Click "Browse" and select the `code-engine/openapi.json` file (replace with the actual location of your file) 32 | ![](assets/2024-03-11-19-04-10.png) 33 | * Click "Next" to review the imported operations. This allows you to verify that the extension can interact with the MedicX API endpoints as defined in the OpenAPI document. 34 | * If everything looks good, click "Finish" to create the custom extension. 35 | ![](assets/2024-03-11-19-05-24.png) 36 | 37 | 3. **Add the Custom Extension to Your Assistant:** 38 | * On the "Extensions" dashboard, locate your newly created MedicX extension. 39 | ![](assets/2024-03-11-19-07-16.png) 40 | * Click the extension tile and then click "Add" to integrate it with your assistant. 41 | ![](assets/2024-03-11-19-07-46.png) 42 | * Follow the on-screen prompts to complete the integration process. 43 | ![](assets/2024-03-11-19-10-23.png) 44 | 4. **Create an Action:** 45 | * Navigate to the "Actions" tab within your assistant. 46 | * Click on "Create action" and provide a name and description for your action (e.g., Process Medical Query). 47 | 48 | ![](assets/2024-03-11-19-12-25.png) 49 | * This action will handle user queries and interact with the MedicX API through the custom extension. 50 | ![](assets/2024-03-12-10-21-43.png) 51 | 52 | 53 | 5. **Define Action Variables:** 54 | * In the action editor, create a new assistant variable to store the user's input message. 55 | 56 | We create the first step, we can say 57 | 58 | ``` 59 | Please enter in your question 60 | ``` 61 | ![](assets/2024-03-12-17-23-04.png) 62 | 63 | 64 | and then we define a custemer response like Free text 65 | ![](assets/2024-03-12-17-23-58.png) 66 | 67 | 68 | 6. **Call the MedicX API:** 69 | 70 | 71 | We create an extra step, the step we name 72 | 73 | `Call custom extension` 74 | 75 | 76 | 77 | * Within continue to next step, you'll use the `Use extension` node to invoke the desired MedicX API endpoint. 78 | * In the "Extension" dropdown, choose your custom extension (MedicX Extension). 79 | ![](assets/2024-03-12-17-26-24.png) 80 | 81 | * Select the specific operation you want to call from the MedicX API (e.g., send a message and receive a response). 82 | 83 | * Update the optional parameters as needed. 84 | * **Message:** This parameter should be set to the user's input retrieved 85 | * **History:** (Optional) This parameter might be used by the MedicX API to maintain conversation context. You can leave it blank or populate it based on your specific use case. 86 | 87 | For input message you will choose Action Step Variables and then you choose the first step 1.`Please enter in your question` 88 | ![](assets/2024-03-12-17-28-25.png) 89 | This ensures the MedicX API receives the user's query. 90 | * Click "Apply" to save the extension call configuration, 91 | and we will obtain in Step 2 this 92 | ![](assets/2024-03-13-08-56-44.png) 93 | 94 | 95 | 7. **Process the Response:** 96 | * After calling the MedicX API, we create a new step, with conditions, we choose My Medical Api (step2) then Ran successfully 97 | 98 | 99 | ![](assets/2024-03-12-17-31-51.png) 100 | 101 | in order to express code we set variable values, and we create a `New session variable` 102 | ![](assets/2024-03-12-17-33-44.png) 103 | 104 | we name result and will be free text and then apply. 105 | 106 | ``` 107 | ${result} =${body.message}+"\\nOutput: \\n"+${body.response} 108 | 109 | ``` 110 | ![](assets/2024-03-12-17-49-55.png) 111 | 112 | If you want clean answer try this 113 | ``` 114 | ${result_clean} =${body.response} 115 | 116 | ``` 117 | ![](assets/2024-03-13-12-12-27.png) 118 | 119 | then in the assitant says you add a function result 120 | 121 | ![](assets/2024-03-12-17-50-43.png) 122 | 123 | This might involve parsing the response data, extracting relevant information, and crafting a response for the user. 124 | 125 | 8. **Ending** 126 | If you want to end you can create a new step 127 | ``` 128 | Do you you need anything else? 129 | ``` 130 | ![](assets/2024-03-13-12-38-17.png) 131 | Create new step for yes 132 | ![](assets/2024-03-13-12-39-05.png) 133 | and another for no 134 | ![](assets/2024-03-13-12-39-23.png) 135 | 136 | 137 | 138 | 9. **Test and Train:** 139 | * Once you've defined the action flow, including the MedicX extension call and response processing, save your action. 140 | Click on Preview and then type 141 | 142 | ``` 143 | Medical Query 144 | ``` 145 | 146 | then you ask for example 147 | 148 | ``` 149 | I have drunk too much alcohol I have headache what should do 150 | ``` 151 | 152 | you got 153 | 154 | 155 | ![](assets/2024-03-12-17-53-09.png) 156 | 157 | * Test your assistant Watson Assistant to simulate user interactions and observe how your assistant interacts with the MedicX API. 158 | You can try the following question and check it out in preview, clickin on Medical query and then type the question 159 | ``` 160 | I have drunk too much alcohol I have headache what should do 161 | ``` 162 | ![](assets/2024-03-13-12-42-14.png) 163 | 164 | then yes 165 | ``` 166 | What precautions should I take to avoid the spread of contagious illnesses, like the flu or common cold, within my household? 167 | ``` 168 | ![](assets/2024-03-13-12-42-46.png) 169 | 170 | ``` 171 | How to maintain good indoor air quality? 172 | ``` 173 | ![](assets/2024-03-13-12-43-13.png) 174 | 175 | 176 | **By following these steps, you've successfully created a Watson assistant that leverages a custom extension to interact with an external API (MedicX). This empowers your assistant to access valuable data and functionalities from external sources, enhancing its capabilities and user experience.** 177 | 178 | -------------------------------------------------------------------------------- /watson-assistant/api-notes.md: -------------------------------------------------------------------------------- 1 | # Watson Assistant with WatsonX Medical 2 | 3 | First let us create a simple notebook to just test our API, if is working. We would like use Jupyter Notebook in Visual Studio Code. 4 | To create a new Jupyter Notebook in Visual Studio Code check it out [this](./setup-notebook.md) 5 | Now you have created and started working on a new Jupyter Notebook in Visual Studio Code. 6 | In particular we have created for you this notebook of test here 7 | [API-Test-WatsonX.ipynb](./API-Test-WatsonX.ipynb) 8 | For example having this query 9 | ![](assets/2024-02-23-16-56-55.png) 10 | 11 | you will get something like this 12 | ![](assets/2024-02-22-16-25-12.png) 13 | 14 | For the benchmarking we executed different questions on local and in the cloud 15 | on the Code Engine and we got the following results: 16 | ![](assets/benchmark.png) 17 | 18 | As you see our cloud version fortunatelly is working better that locally. 19 | ## Watson Assistant Setup 20 | 21 | First we create our watson assitant 22 | ![](assets/2024-02-23-17-14-57.png) -------------------------------------------------------------------------------- /watson-assistant/assets/2024-02-22-16-25-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-02-22-16-25-12.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-02-23-16-56-55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-02-23-16-56-55.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-02-23-17-14-57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-02-23-17-14-57.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-11-18-54-49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-11-18-54-49.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-11-18-56-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-11-18-56-03.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-11-19-00-33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-11-19-00-33.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-11-19-01-23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-11-19-01-23.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-11-19-04-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-11-19-04-10.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-11-19-05-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-11-19-05-24.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-11-19-07-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-11-19-07-16.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-11-19-07-46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-11-19-07-46.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-11-19-10-23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-11-19-10-23.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-11-19-12-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-11-19-12-25.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-11-19-14-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-11-19-14-07.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-12-10-21-43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-12-10-21-43.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-12-17-23-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-12-17-23-04.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-12-17-23-58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-12-17-23-58.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-12-17-26-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-12-17-26-24.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-12-17-28-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-12-17-28-25.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-12-17-31-51.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-12-17-31-51.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-12-17-33-44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-12-17-33-44.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-12-17-49-55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-12-17-49-55.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-12-17-50-43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-12-17-50-43.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-12-17-53-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-12-17-53-09.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-08-56-44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-08-56-44.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-10-30-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-10-30-17.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-10-30-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-10-30-20.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-12-03-45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-12-03-45.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-12-04-57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-12-04-57.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-12-06-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-12-06-02.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-12-06-39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-12-06-39.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-12-12-27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-12-12-27.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-12-38-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-12-38-17.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-12-39-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-12-39-05.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-12-39-23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-12-39-23.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-12-42-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-12-42-14.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-12-42-46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-12-42-46.png -------------------------------------------------------------------------------- /watson-assistant/assets/2024-03-13-12-43-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/2024-03-13-12-43-13.png -------------------------------------------------------------------------------- /watson-assistant/assets/benchmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/watson-assistant/assets/benchmark.png -------------------------------------------------------------------------------- /watson-assistant/gradio-beta.md: -------------------------------------------------------------------------------- 1 | ## Integrating your Gradio API into a Watson Assistant Chatbot 2 | 3 | How you can integrate your Gradio API into a Watson Assistant chatbot to answer user questions: 4 | 5 | **1. Create a Watson Assistant Skill:** 6 | 7 | * Head to the IBM Cloud console and create a new Watson Assistant resource. 8 | * Follow the steps to create a new skill and choose "Dialog" as the authoring experience. 9 | * Start building your skill by defining intents and dialog nodes. 10 | 11 | **2. Design Intents and Dialog Nodes:** 12 | 13 | * Define an intent for each type of question you want your chatbot to answer. For example, you could have intents for "Ask a medical question", "Ask about symptoms", or "Get information on a medication". 14 | * Under each intent, create dialog nodes that capture the user's specific question. You can use entities to extract relevant information like keywords or specific details. 15 | 16 | **3. Integrate the API call:** 17 | 18 | * Within your dialog nodes, use the "Actions" feature to call your Gradio API endpoint. 19 | * You can use Watson Assistant's built-in HTTP Request action to send the user's question to your API endpoint. For example: 20 | python 21 | from gradio_client import Client 22 | 23 | client = Client("https://watsonx-medical.16jc1w8uq8wb.us-south.codeengine.appdomain.cloud/") 24 | result = client.predict( 25 | "Howdy!", # str in 'message' Textbox component 26 | api_name="/predict" 27 | ) 28 | print(result) 29 | 30 | * Pass the user's question as the input to the API (e.g., as the "message" field). 31 | 32 | **4. Process the API response:** 33 | 34 | * Configure your dialog node to capture the response from your API. You can access the response data using variables like `$api_response`. 35 | * Depending on the format of your API response, you might need to parse or manipulate the data to extract the answer. 36 | 37 | **5. Respond to the user:** 38 | 39 | * Use the "Text Response" or "Conditional Response" options to craft a response for the user based on the extracted answer. 40 | * You can personalize the response by including the user's name or tailoring the answer to their specific question. 41 | 42 | **6. Test and refine:** 43 | 44 | * Test your chatbot with various questions and ensure it's providing accurate and helpful answers. 45 | * Refine your dialog nodes, intents, and API calls based on user feedback and the performance of your chatbot. 46 | 47 | **Demo Chatbot Example:** 48 | 49 | Here's a simplified example of a dialog node that calls your Gradio API: 50 | 51 | **Intent:** Ask_Medical_Question 52 | 53 | **Dialog Node:** Get_Medical_Answer 54 | 55 | * **Conditions:** 56 | * User input matches the #Ask_Medical_Question intent. 57 | * **Actions:** 58 | * Send HTTP request to "/predict" endpoint of your Gradio API. 59 | * Pass the user's input as the "message" parameter. 60 | * Store the API response in the `$api_response` variable. 61 | * **Then:** 62 | * Extract the answer from `$api_response` (based on your specific API format). 63 | * Respond to the user with the answer, personalized with their name ("Hi [User Name], %s" % extracted_answer). 64 | 65 | Remember, this is just a starting point, and you might need to adjust it based on your specific API and desired functionality. 66 | 67 | **Additional Tips:** 68 | 69 | * Use context variables to store information across different dialog nodes. 70 | * Consider using Watson Assistant's built-in NLP capabilities for improved question understanding. 71 | * Explore the various response options in Watson Assistant to create engaging and informative interactions. 72 | 73 | By following these steps and customizing them to your specific needs, you can create a Watson Assistant chatbot that leverages your Gradio API to answer user questions effectively. -------------------------------------------------------------------------------- /watson-assistant/setup-notebook.md: -------------------------------------------------------------------------------- 1 | To create a new Jupyter Notebook in Visual Studio Code, follow these steps: 2 | 3 | 1. Open Visual Studio Code. 4 | 5 | 2. Click on the "Extensions" icon in the Activity Bar on the side of the window (it looks like a square with four smaller squares inside) or press `Ctrl+Shift+X`. 6 | 7 | 3. Make sure the Jupyter extension is installed. If not, search for "Jupyter" in the search bar, find the Jupyter extension by Microsoft, and click on the Install button. 8 | 9 | 4. Press `Ctrl+Shift+P` to open the Command Palette. 10 | 11 | 5. Type "Jupyter" in the Command Palette search bar, and select "Jupyter: Create New Blank Jupyter Notebook" from the dropdown list. This will create a new Jupyter Notebook with a `.ipynb` file extension. 12 | 13 | 6. A new tab will open with an empty Jupyter Notebook. You can start adding code and markdown cells by clicking the `+` button in the toolbar or by using the "Insert cell" button (it looks like a blue rectangle with a plus sign) that appears when you hover over the space between cells. 14 | 15 | 7. To run a code cell, click on the cell and press `Shift+Enter`. The output will appear below the cell. 16 | 17 | 8. To save the notebook, press `Ctrl+S` or click on "File" in the top menu and then "Save As" to choose the location and file name for your notebook. -------------------------------------------------------------------------------- /webhook-integration/README.md: -------------------------------------------------------------------------------- 1 | ## Building a Watson Assistant with a Webhook for Translation 2 | 3 | This guide expands on the previous explanation, providing details on calling a webhook in the dialog menu to translate user input using the Watson Language Translator service. 4 | 5 | **Prerequisites:** 6 | 7 | * An IBM Cloud account 8 | * Access to the Watson Assistant service 9 | * A Watson Language Translator service instance 10 | 11 | **Steps:** 12 | 13 | **1. Define the Webhook:** 14 | 15 | 1. Navigate to your Watson Assistant service ancd create Assistant. 16 | 2. Then go to Assistant settings and click Activate dialog 17 | 3. Under the "Dialog" tab, go to Options and click on "Webhooks" located on the left sidebar. 18 | 4. Enter the URL of the Watson Language Translator service endpoint: `https://api.us-south.language-translator.watson.cloud.ibm.com/v3/translate?version=2018-05-01` 19 | - In the "Headers" section, add a header named "Content-Type" with the value "application/json" to specify the request format. 20 | 21 | **2. Add a Webhook Callout to a Dialog Node:** 22 | 23 | 1. Open te dialog and create dialog. 24 | 2. Create a new node by clicking add new node, and the dialog node where you want to trigger the translation. 25 | 3. Click "Customize" on the right corner of the node. 26 | ![](assets/2024-02-27-18-34-16.png) 27 | 4. Scroll down to the "Webhook" section and toggle "Call out to webhooks/actions" to **On**. 28 | ![](assets/2024-02-27-18-43-03.png) 29 | 5. Select "Call a webhook" and click **Apply**. 30 | and you got 31 | ![](assets/2024-02-27-18-44-25.png) 32 | **3. Configure the Webhook Request:** 33 | 34 | 1. **In the "Parameters" section:** 35 | - Add a key-value pair: 36 | - **Key:** "model_id" 37 | - **Value:** "en-es" (replace "en-es" with your desired translation language code, e.g., "es-fr" for Spanish to French) 38 | - Add another key-value pair: 39 | - **Key:** "text" 40 | - **Value:** "" (this sends the user's input text to the service) 41 | ![](assets/2024-02-27-18-49-57.png) 42 | 43 | 44 | **4. Create Conditional Responses:** 45 | 46 | 1. Two response conditions are automatically added: 47 | - **Success:** This response is displayed if the translator returns a valid translation. 48 | - **Failure:** This response is displayed if the call fails. 49 | 2. Edit the "Success" response to include: 50 | - `.translations[0].translation>` (this extracts the translated text from the webhook response). 51 | 3. Customize the "Failure" response as needed. 52 | 53 | **5. Example Usage and Run:** 54 | 55 | 1. Create a new dialog node where the user will enter text for translation. 56 | 2. In the node, capture the user's input in a context variable, for example, `$user_text`. 57 | 3. In the next node, trigger the webhook callout you configured. This node will receive the translated text in the `$webhook_result_1` variable. 58 | 4. In the response section of the translation node, use SpEL syntax to display the translated text to the user: `.translations[0].translation>`. 59 | 5. Test your Assistant by starting a conversation and entering text in the initial node. You should see the translated text displayed in the response. 60 | 61 | **Additional Notes:** 62 | 63 | * Remember to replace the example language code (`en-es`) with the desired translation language pair. 64 | * Ensure your Watson Language Translator service has the necessary plan and billing enabled to handle your translation requests. 65 | * Refer to the Watson Language Translator documentation for detailed information on available languages and options: [https://www.ibm.com/docs/en/openpages/9.0.0?topic=integrations-watson-language-translator](https://www.ibm.com/docs/en/openpages/9.0.0?topic=integrations-watson-language-translator) 66 | 67 | This enhanced explanation provides a clearer understanding of how to configure the webhook, call the Watson Language Translator service, and include user input for translation within your Watson Assistant. 68 | 69 | References: 70 | https://cloud.ibm.com/docs/watson-assistant?topic=watson-assistant-dialog-webhooks 71 | https://cloud.ibm.com/docs/assistant?topic=assistant-dialog-webhooks 72 | https://cloud.ibm.com/docs/watson-assistant?topic=watson-assistant-webhook-overview -------------------------------------------------------------------------------- /webhook-integration/assets/2024-02-27-18-34-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/webhook-integration/assets/2024-02-27-18-34-16.png -------------------------------------------------------------------------------- /webhook-integration/assets/2024-02-27-18-35-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/webhook-integration/assets/2024-02-27-18-35-04.png -------------------------------------------------------------------------------- /webhook-integration/assets/2024-02-27-18-43-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/webhook-integration/assets/2024-02-27-18-43-03.png -------------------------------------------------------------------------------- /webhook-integration/assets/2024-02-27-18-44-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/webhook-integration/assets/2024-02-27-18-44-25.png -------------------------------------------------------------------------------- /webhook-integration/assets/2024-02-27-18-49-57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanmv/Watsonx-Assistant-with-Milvus-as-Vector-Database/e9dc15c6ea6169945df32fce4cdf68dfca37a072/webhook-integration/assets/2024-02-27-18-49-57.png --------------------------------------------------------------------------------