Skip to content

Commit

Permalink
fastap, streamlit samples added
Browse files Browse the repository at this point in the history
  • Loading branch information
isc-afuentes committed Nov 19, 2024
1 parent 46c781b commit f791589
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 5 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
.local
.npm
.cache
.env
shared
data/model
data/model
__pycache__
54 changes: 52 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ After running the containers, you should be able to access to:
* InterSystems IRIS [Management Portal](http://localhost:52774/csp/sys/UtilHome.csp). You can login using `superuser` / `SYS`
* [Jupyter Notebook](http://localhost:8888)

# RAG Application
# Explore RAG applications using Jupyter

## Medicine Leaflet examples

Expand All @@ -59,4 +59,54 @@ This example is about a company called Holefoods that sells food with some hole
Using the sales data model of the company, the goal is to create an assistant that can translate natural language questions into valid SQL that answer the question.

In [Jupyter Notebook](http://localhost:8888), you will find:
* [QA-SQL-LLM.ipynb](./jupyter/QA-SQL-LLM.ipynb) - text to SQL example using OpenAI LLM.
* [QA-SQL-LLM.ipynb](./jupyter/QA-SQL-LLM.ipynb) - text to SQL example using OpenAI LLM.

# Create other applications

There are some other examples you can try to build and modify in your local environment.

First of all, create a new environment and install some requirements:

```bash
# create a local venv environment
python3 -m venv .venv

# activate venv
source .venv/bin/activate

# install dependencies
pip3 install -r requirements.txt
```

Create an `.env` file for storing API keys for OpenAI / MistralAI. They will be used in the applications.

```
OPENAI_API_KEY="your-api"
MISTRAL_API_KEY="your-api"
```

## Text to SQL service API
You can find a sample Text to SQL based on [QA-SQL-LLM.ipynb](./jupyter/QA-SQL-LLM.ipynb) [here](python/holefoods_text2sql/main.py).

You can run it like this:

```bash
cd python/holefoods_text2sql
fastapi dev main.py
```

Then open http://127.0.0.1:8000/docs to explore the API and try it out using the web client.

## Streamlit Assistant
There is also a great example of a langchain / streamlit chatbot assitant in https://alejandro-ao.com/how-to-use-streaming-in-langchain-and-streamlit/

You can play with it here as well:

```bash
cd python/assitant
streamlit run chatbot.py
```

Then open http://localhost:8501 and have a look at it.

Are you able to add the logic to reproduce the Medicine Leaflet example in the assitant ?
2 changes: 0 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ services:

# iris
iris:
init: true
container_name: iris
build:
context: .
Expand All @@ -14,7 +13,6 @@ services:
- ./shared:/shared
environment:
- ISC_DATA_DIRECTORY=/shared/durable
command: --check-caps false --ISCAgent false

# jupyter notebook
jupyter:
Expand Down
1 change: 1 addition & 0 deletions jupyter/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ langchain-community
mistral_common
langchain_mistralai
langchain-openai
langchain_iris
transformers
torch
67 changes: 67 additions & 0 deletions python/assistant/chatbot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import streamlit as st
from langchain_core.messages import AIMessage, HumanMessage
#from langchain_openai import ChatOpenAI
from langchain_mistralai import ChatMistralAI
from dotenv import load_dotenv
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate

load_dotenv()

#llm = ChatOpenAI()
llm = ChatMistralAI(model="mistral-large-latest")


# app config
st.set_page_config(page_title="Streamlit Chatbot", page_icon="🤖")
st.title("Chatbot")


def get_response(user_query, chat_history):

template = """
You are a helpful assistant. Answer the following questions considering the history of the conversation:
Chat history: {chat_history}
User question: {user_question}
"""

prompt = ChatPromptTemplate.from_template(template)

chain = prompt | llm | StrOutputParser()

return chain.invoke({
"chat_history": chat_history,
"user_question": user_query,
})

# session state
if "chat_history" not in st.session_state:
st.session_state.chat_history = [
AIMessage(content="Hello, I am a bot. How can I help you?"),
]


# conversation
for message in st.session_state.chat_history:
if isinstance(message, AIMessage):
with st.chat_message("AI"):
st.write(message.content)
elif isinstance(message, HumanMessage):
with st.chat_message("Human"):
st.write(message.content)

# user input
user_query = st.chat_input("Type your message here...")
if user_query is not None and user_query != "":
st.session_state.chat_history.append(HumanMessage(content=user_query))

with st.chat_message("Human"):
st.markdown(user_query)

with st.chat_message("AI"):
response = get_response(user_query, st.session_state.chat_history)
st.write(response)

st.session_state.chat_history.append(AIMessage(content=response))
124 changes: 124 additions & 0 deletions python/holefoods_text2sql/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
from fastapi import FastAPI, Query
from typing import Dict

app = FastAPI(
title="Sample Holefoods schema Text to SQL API",
description="This is an example of a Text to SQL API using OpenAI LLM and IRIS Vector Database",
version="1.0.0"
)

# load OpenAI APIKEY from env
from dotenv import load_dotenv
load_dotenv()

# database connection to extract information
from langchain_community.utilities import SQLDatabase
db = SQLDatabase.from_uri("iris://superuser:SYS@localhost:51774/LLMRAG", sample_rows_in_table_info=3, schema='Holefoods')

# openai model
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini")

from langchain_core.prompts import PromptTemplate

# define the custom prompt template
template = '''
You are an InterSystems IRIS SQL expert.
Given an input question, first create a syntactically correct InterSystems IRIS SQL query to run and return the answer to the input question.
Unless the user specifies in the question a specific number of examples to obtain, query for at most {top_k} results using the TOP as defined in InterSystems IRIS syntax: ```SELECT [DISTINCT] TOP int select-item, select-item,...```
Always specify table names using schema as prefix.
Do not use LIMIT clause as it is not correct in IRIS dialect.
Do not end SQL sentences with an ;
Do not enclose fields in quotes or double quotes.
Do not enclose table names in quotes or double quotes.
You can order the results to return the most informative data in the database.
Never query for all columns from a table. You must query only the columns that are needed to answer the question.
Pay attention to use only the column names you can see in the tables below. Be careful to not query for columns that do not exist. Also, pay attention to which column is in which table.
Pay attention to use CAST(CURRENT_DATE as date) function to get the current date, if the question involves "today".
Return only plain SQL without any formatting.
Only use the following tables:
{table_info}.
Question: {input}'''

# provide some examples to improve the results
examples = [
{
"input": "List all regions.",
"query": "SELECT ID, Name FROM HoleFoods.Region;"
},
{
"input": "List all countries.",
"query": "SELECT c.ID, c.Name, r.Name Region FROM HoleFoods.Country c JOIN HoleFoods.Region r on c.Region=r.ID"
},
{
"input": "What are the different product categories ?",
"query": "SELECT DISTINCT(Category) Categories FROM HoleFoods.Product"
},
{
"input": "How many pasta products where sold online in 2023 ?",
"query": "SELECT SUM(UnitsSold) FROM HoleFoods.SalesTransaction st JOIN HoleFoods.Product p ON st.Product=p.ID WHERE st.Channel='Online' AND YEAR(st.DateOfSale) = 2023 AND p.Category = 'Pasta'"
},
{
"input": "Find all snack products",
"query": "SELECT SKU, Name, Price FROM HoleFoods.Product p WHERE p.Category='Snack'"
},
{
"input": "Find all candy products",
"query": "SELECT SKU, Name, Price FROM HoleFoods.Product p WHERE p.Category='Candy'"
},
{
"input": "How many products were sold in Europe in 2022 ?",
"query": "SELECT SUM(UnitsSold) FROM HoleFoods.SalesTransaction st JOIN HoleFoods.Outlet o ON st.Outlet=o.ID JOIN HoleFoods.Country c ON o.Country=c.ID JOIN HoleFoods.Region r ON c.Region=r.ID WHERE r.Name='Europe' AND YEAR(st.DateOfSale) = 2022"
}
]

from langchain_iris import IRISVector
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_openai import OpenAIEmbeddings

example_selector = SemanticSimilarityExampleSelector.from_examples(
examples,
OpenAIEmbeddings(),
IRISVector,
k=3,
input_keys=["input"],
connection_string='iris://superuser:SYS@localhost:51774/LLMRAG',
collection_name="sql_samples",
pre_delete_collection=True
)

from langchain_core.prompts import FewShotPromptTemplate

example_prompt = PromptTemplate.from_template("User input: {input}\nSQL query: {query}")

prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
prefix=template,
suffix="User input: {input}\nSQL query: ",
input_variables=["input", "top_k", "table_info"],
)

from langchain.chains import create_sql_query_chain
chain = create_sql_query_chain(llm, db, prompt)

from pydantic import BaseModel, Field
class Text2SQLResponse(BaseModel):
sql: str # the generated SQL query

@app.get("/text2sql")
async def text2sql(text: str = Query(..., description="Natural language text about Holefoods schema to convert to SQL")) -> Text2SQLResponse:
"""
Convert input text to a SQL query.
Parameters:
- text: The input natural language string.
Returns:
- JSON object containing the generated SQL query.
"""
query = chain.invoke({"question": text})
return {"sql": query}
8 changes: 8 additions & 0 deletions python/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
langchain-community
langchain-openai
langchain_iris
fastapi[standard]
streamlit
mistral_common
langchain_mistralai
../jupyter/intersystems_irispython-3.2.0-py3-none-any.whl

0 comments on commit f791589

Please sign in to comment.