chore: init
Browse files- .gitattributes +2 -35
- .gitignore +3 -0
- README.md +144 -8
- app.py +115 -0
- db.py +54 -0
- requirements.txt +17 -0
.gitattributes
CHANGED
|
@@ -1,35 +1,2 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 1 |
+
# Auto detect text files and perform LF normalization
|
| 2 |
+
* text=auto
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.gitignore
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__pycache__
|
| 2 |
+
.DS_Store
|
| 3 |
+
.git
|
README.md
CHANGED
|
@@ -1,13 +1,149 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
-
sdk:
|
| 7 |
-
sdk_version:
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
-
short_description: Customer Service Chatbot
|
| 11 |
---
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Customer Service Chatbot
|
| 3 |
+
emoji: 🔮
|
| 4 |
+
colorFrom: indigo
|
| 5 |
+
colorTo: indigo
|
| 6 |
+
sdk: streamlit
|
| 7 |
+
sdk_version: 1.34.0
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
|
|
|
| 10 |
---
|
| 11 |
|
| 12 |
+
This is a customer service chatbot that helps analyze user input and pull out relevant record from the database.
|
| 13 |
+
|
| 14 |
+
The app is built with Langchain, Ollama and Streamlit.
|
| 15 |
+
|
| 16 |
+
What the chatbot exactly does?
|
| 17 |
+
- extract transaction id from user input
|
| 18 |
+
- determine transaction type based on the transaction id
|
| 19 |
+
- find record from database table based on transaction id and type
|
| 20 |
+
|
| 21 |
+
A transaction id may starts with `payment`, which indicates a payment transaction; or starts with `payout`, which indicates a payout transaction.
|
| 22 |
+
|
| 23 |
+
There are `payment` and `payout` tables in the database, each contains some records. Details can be found in `db.py`.
|
| 24 |
+
|
| 25 |
+
Prompts are fine tuned using following techniques for better result:
|
| 26 |
+
- clear instructions
|
| 27 |
+
- asking for justification
|
| 28 |
+
- use delimiters
|
| 29 |
+
- chain of thought
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
Example UI:
|
| 33 |
+
<img src="example.jpg" alt="API" width="800"/>
|
| 34 |
+
|
| 35 |
+
Steps to run
|
| 36 |
+
- Install Ollama server locally, and download the llama3 model (not llama3.2).
|
| 37 |
+
- Install Python dependencies by executing ```pip install -r requirements.txt```
|
| 38 |
+
- Start the app by executing the following command from the project root directory
|
| 39 |
+
```python -m streamlit run app.py --server.port=8501 --server.address=0.0.0.0```
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
## Examples of Prompt Engineering
|
| 43 |
+
### Bot returns example value when transaction id not found
|
| 44 |
+
The system prompt `extract_system_prompt` was defined as the following, which includes examples for payment and payout transaction id formats.
|
| 45 |
+
```python
|
| 46 |
+
extract_system_prompt = (
|
| 47 |
+
"You are a customer officer that helps extract transaction id from the user input and determine the transaction type based on the transaction id. "
|
| 48 |
+
"There are two types of transactions: payment and payout. "
|
| 49 |
+
"1. A payout transaction, whose transaction id starts with 'payout_', "
|
| 50 |
+
"===>START EXAMPLE"
|
| 51 |
+
"payout_a1b2c3d4"
|
| 52 |
+
"<===END EXAMPLE"
|
| 53 |
+
"2. A payment transaction, whose transaction id starts with 'payment_', "
|
| 54 |
+
"===>START EXAMPLE"
|
| 55 |
+
"payment_a1b2c3d4"
|
| 56 |
+
"<===END EXAMPLE"
|
| 57 |
+
"===>START USER INPUT"
|
| 58 |
+
"{input}"
|
| 59 |
+
"<===END USER INPUT"
|
| 60 |
+
"Respond with the following information: "
|
| 61 |
+
"1. a flag named found which indicates if a transaction id is found "
|
| 62 |
+
"2. the transaction id named transaction_id if found "
|
| 63 |
+
"3. the transaction type (in lower case) named transaction_type if found "
|
| 64 |
+
"4. the explanation named justification which explains how you deduce transaction id and transaction type "
|
| 65 |
+
"You must give answer in JSON format without any extra content, and don't make up information."
|
| 66 |
+
)
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
The bot sometimes gives wrong answer that returns the example value or unrelated text when it cannot find a transaction id in the user input.
|
| 70 |
+
|
| 71 |
+
input:
|
| 72 |
+
My transaction failed
|
| 73 |
+
|
| 74 |
+
wrong answer1:
|
| 75 |
+
{ "found": true, "transaction_id": "payment_a1b2c3d4", "transaction_type": "payment", "justification": "The transaction id starts with 'payment_', which indicates it's a payment transaction." }
|
| 76 |
+
|
| 77 |
+
wrong answer2:
|
| 78 |
+
{"found": true, "transaction_id": "My transaction", "transaction_type": "payment", "justification": "The transaction id 'My transaction' starts with 'payment_', indicating a payment transaction." }
|
| 79 |
+
|
| 80 |
+
solution:
|
| 81 |
+
Examples are removed.
|
| 82 |
+
|
| 83 |
+
```python
|
| 84 |
+
extract_system_prompt = (
|
| 85 |
+
"You are a customer officer that helps extract transaction id from the USER INPUT and determine the transaction type based on the transaction id. "
|
| 86 |
+
"A transaction id can take one of two forms: "
|
| 87 |
+
"1. A transaction id may start with 'payout_', which indicates a payout transaction. "
|
| 88 |
+
"2. A transaction id may start with 'payment_', which indicates a payment transaction. "
|
| 89 |
+
"===>START USER INPUT"
|
| 90 |
+
"{input}"
|
| 91 |
+
"<===END USER INPUT"
|
| 92 |
+
"Respond with the following information: "
|
| 93 |
+
"1. a flag named found, it is true if you can find a transaction id in the USER INPUT, otherwise it is false "
|
| 94 |
+
"2. the transaction id named transaction_id if found "
|
| 95 |
+
"3. the transaction type (in lower case) named transaction_type if found "
|
| 96 |
+
"4. the explanation named justification which explains how you deduce transaction id and transaction type "
|
| 97 |
+
"You must give answer in JSON format without any extra content, and don't make up transaction id if no exact text appears in the USER INPUT."
|
| 98 |
+
)
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
### bot treats invalid transaction id as valid
|
| 102 |
+
The system prompt `extract_system_prompt` was defined as the following, which includes detailed steps to verify and extract transaction id.
|
| 103 |
+
```python
|
| 104 |
+
extract_system_prompt = (
|
| 105 |
+
"You are a customer officer that helps extract transaction id from the USER INPUT and determine the transaction type based on the transaction id. "
|
| 106 |
+
"To find transaction id, follow all the steps below: "
|
| 107 |
+
"Step 1. **Look for prefix**: for each word in the USER INPUT, check if it starts with 'payout' or 'payment', if so, you should go to Step 2, otherwise go to Step 7. "
|
| 108 |
+
"Step 2. **Find a single dash**: check the character immediately after the prefix 'payout' or 'payment', if it is a dash, you should go to Step 3, otherwise go to Step 7.. "
|
| 109 |
+
"Step 3. **Find digits and characters**: check if there is at least one digit or one character after the dash, if so, you should go to Step 4, otherwise go to Step 7.. "
|
| 110 |
+
"Step 4. **Extract transaction id**: extract transaction id from the USER INPUT, then go to Step 5. "
|
| 111 |
+
"Step 5. **Verify transaction id**: verify the extracted transaction id by checking if the USER INPUT contains exact the same text, if so, you should go to Step 6, otherwise go to Step 7. "
|
| 112 |
+
"Step 6. It is a valid transaction id, when constructing the response, return the flag found as true. "
|
| 113 |
+
"Step 7. It is not a valid transaction id, when constructing the response, return the flag found as false. "
|
| 114 |
+
"To determine the transaction type, follow the rule below: "
|
| 115 |
+
"There are two types of transactions: "
|
| 116 |
+
"a. A transaction id starting with 'payout' indicates a payout transaction. "
|
| 117 |
+
"b. A transaction id starting with 'payment' indicates a payment transaction. "
|
| 118 |
+
"===>START USER INPUT"
|
| 119 |
+
"{input}"
|
| 120 |
+
"<===END USER INPUT"
|
| 121 |
+
"Respond with the following information: "
|
| 122 |
+
"1. a flag named found, which indicates if a valid transaction id is found "
|
| 123 |
+
"2. the transaction id named transaction_id if found "
|
| 124 |
+
"3. the transaction type (in lower case) named transaction_type if found "
|
| 125 |
+
"4. the explanation named justification which explains how you deduce transaction id and transaction type "
|
| 126 |
+
"You must give answer in JSON format without any extra content, and don't make up transaction id if no exact text appears in the USER INPUT."
|
| 127 |
+
)
|
| 128 |
+
```
|
| 129 |
+
|
| 130 |
+
The bot treats invalid transaction id such as payment3 or payout5 as valid.
|
| 131 |
+
|
| 132 |
+
input:
|
| 133 |
+
My payment3 failed
|
| 134 |
+
|
| 135 |
+
(here payment3 is not a valid transaction id since there is no dash after 'payment')
|
| 136 |
+
|
| 137 |
+
wrong answer:
|
| 138 |
+
{"found": true, "transaction_id": "payment-", "transaction_type": "payment", "justification": "The user input contains a string pattern that matches a valid transaction id starting with 'payment-' and followed by a single dash."}
|
| 139 |
+
|
| 140 |
+
possible solutions (not implemented yet):
|
| 141 |
+
- Use Python REPL tool with Regex instead of describing rules in prompt, or
|
| 142 |
+
- Use a better LLM (my test is using llama3), or
|
| 143 |
+
- Split the complex prompt into multiple smaller prompts then feed each prompt into a LLM.
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
### SQL agent returns error "Invalid Format: Missing 'Action:' after 'Thought:"
|
| 147 |
+
|
| 148 |
+
solution:
|
| 149 |
+
create SQL agent every time for every user input, i.e. do not reuse SQL agent.
|
app.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import os
|
| 3 |
+
from dotenv import load_dotenv
|
| 4 |
+
|
| 5 |
+
st.set_page_config(page_title="Chat", page_icon=":page_facing_up:")
|
| 6 |
+
|
| 7 |
+
load_dotenv()
|
| 8 |
+
|
| 9 |
+
from huggingface_hub import login
|
| 10 |
+
login(token=os.getenv("HUGGINGFACEHUB_API_KEY"))
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 14 |
+
import gradio as gr
|
| 15 |
+
|
| 16 |
+
# model_name="deepseek-ai/DeepSeek-R1-Distill-Qwen-7B" # 15G
|
| 17 |
+
model_name="meta-llama/Llama-3.2-3B-Instruct" # 6.5G
|
| 18 |
+
|
| 19 |
+
# #
|
| 20 |
+
# # HuggingFaceTB/SmolLM2-135M-Instruct
|
| 21 |
+
# # deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
|
| 22 |
+
# checkpoint = "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B"
|
| 23 |
+
# checkpoint = "meta-llama/Llama-3.2-3B-Instruct" # 6.5G
|
| 24 |
+
device = "mps" # "cuda" or "cpu"
|
| 25 |
+
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
| 26 |
+
model = AutoModelForCausalLM.from_pretrained(model_name).to(device)
|
| 27 |
+
|
| 28 |
+
# def predict(message, history):
|
| 29 |
+
# history.append({"role": "user", "content": message})
|
| 30 |
+
# input_text = tokenizer.apply_chat_template(history, tokenize=False)
|
| 31 |
+
# inputs = tokenizer.encode(input_text, return_tensors="pt").to(device)
|
| 32 |
+
# outputs = model.generate(inputs, max_new_tokens=100, temperature=0.2, top_p=0.9, do_sample=True)
|
| 33 |
+
# decoded = tokenizer.decode(outputs[0])
|
| 34 |
+
# response = decoded.split("<|im_start|>assistant\n")[-1].split("<|im_end|>")[0]
|
| 35 |
+
# return response
|
| 36 |
+
|
| 37 |
+
# demo = gr.ChatInterface(predict, type="messages")
|
| 38 |
+
|
| 39 |
+
# demo.launch()
|
| 40 |
+
|
| 41 |
+
# import os
|
| 42 |
+
# from dotenv import load_dotenv
|
| 43 |
+
|
| 44 |
+
# load_dotenv()
|
| 45 |
+
|
| 46 |
+
# from huggingface_hub import login
|
| 47 |
+
# login(token=os.getenv("HUGGINGFACEHUB_API_KEY"))
|
| 48 |
+
|
| 49 |
+
# pipe = pipeline(model=model_name, torch_dtype=torch.bfloat16, device_map="auto", trust_remote_code=True)
|
| 50 |
+
# prompt = """Let's go through this step-by-step:
|
| 51 |
+
# 1. You start with 15 muffins.
|
| 52 |
+
# 2. You eat 2 muffins, leaving you with 13 muffins.
|
| 53 |
+
# 3. You give 5 muffins to your neighbor, leaving you with 8 muffins.
|
| 54 |
+
# 4. Your partner buys 6 more muffins, bringing the total number of muffins to 14.
|
| 55 |
+
# 5. Your partner eats 2 muffins, leaving you with 12 muffins.
|
| 56 |
+
# If you eat 6 muffins, how many are left?"""
|
| 57 |
+
|
| 58 |
+
# torch.device("mps")
|
| 59 |
+
|
| 60 |
+
# pipeline = pipeline.to("mps")
|
| 61 |
+
|
| 62 |
+
# outputs = pipe(prompt, max_new_tokens=20, do_sample=True, top_k=10)
|
| 63 |
+
# print(f"processing")
|
| 64 |
+
|
| 65 |
+
# for output in outputs:
|
| 66 |
+
# print(f"Result: {output['generated_text']}")
|
| 67 |
+
|
| 68 |
+
system_prompt = (
|
| 69 |
+
"You are a customer officer that helps extract transaction id from the USER INPUT and determine the transaction type based on the transaction id. "
|
| 70 |
+
"To find transaction id, follow all the steps below: "
|
| 71 |
+
"Step 1. **Look for prefix**: for each word in the USER INPUT, check if it starts with 'payout' or 'payment', if so, you should go to Step 2, otherwise go to Step 7. "
|
| 72 |
+
"Step 2. **Find a single dash**: check the character immediately after the prefix 'payout' or 'payment', if it is a dash, you should go to Step 3, otherwise go to Step 7.. "
|
| 73 |
+
"Step 3. **Find digits and characters**: check if there is at least one digit or one character after the dash, if so, you should go to Step 4, otherwise go to Step 7.. "
|
| 74 |
+
"Step 4. **Extract transaction id**: extract transaction id from the USER INPUT, then go to Step 5. "
|
| 75 |
+
"Step 5. **Verify transaction id**: verify the extracted transaction id by checking if the USER INPUT contains exact the same text, if so, you should go to Step 6, otherwise go to Step 7. "
|
| 76 |
+
"Step 6. It is a valid transaction id, when constructing the response, return the flag found as true. "
|
| 77 |
+
"Step 7. It is not a valid transaction id, when constructing the response, return the flag found as false. "
|
| 78 |
+
"To determine the transaction type, follow the rule below: "
|
| 79 |
+
"There are two types of transactions: "
|
| 80 |
+
"a. A transaction id starting with 'payout' indicates a payout transaction. "
|
| 81 |
+
"b. A transaction id starting with 'payment' indicates a payment transaction. "
|
| 82 |
+
"===>USER INPUT BEGINS"
|
| 83 |
+
"{input}"
|
| 84 |
+
"<===USER INPUT ENDS"
|
| 85 |
+
"Respond with the following 4 parameters in JSON format: "
|
| 86 |
+
"1. a mandatory flag named found, which indicates if a valid transaction id is found "
|
| 87 |
+
"2. the transaction id named transaction_id if found "
|
| 88 |
+
"3. the transaction type (in lower case) named transaction_type if found "
|
| 89 |
+
"4. a mandatory explanation named justification which explains how you deduce transaction id and transaction type, don't make up explanation if no exact text appears in the USER INPUT. "
|
| 90 |
+
"You must give answer in valid JSON format without any extra content"
|
| 91 |
+
)
|
| 92 |
+
|
| 93 |
+
examples = [
|
| 94 |
+
"My transaction payment-a1c1 failed",
|
| 95 |
+
"Why is my withdrawal payout-b2c2 pending for 3 days",
|
| 96 |
+
"There is an issue with my transaction payout-87l2k3",
|
| 97 |
+
"I am having trouble with my transaction",
|
| 98 |
+
]
|
| 99 |
+
|
| 100 |
+
def predict(message, history):
|
| 101 |
+
history.append({"role": "system", "content": system_prompt})
|
| 102 |
+
history.append({"role": "user", "content": message})
|
| 103 |
+
input_text = tokenizer.apply_chat_template(history, tokenize=False)
|
| 104 |
+
inputs = tokenizer.encode(input_text, return_tensors="pt").to(device)
|
| 105 |
+
outputs = model.generate(inputs, max_new_tokens=100, temperature=0.2, top_p=0.9, do_sample=True)
|
| 106 |
+
decoded = tokenizer.decode(outputs[0])
|
| 107 |
+
response = decoded.split("<|im_start|>assistant\n")[-1].split("<|im_end|>")[0]
|
| 108 |
+
# response: I'm ready to help you with your math homework. What's your math problem?
|
| 109 |
+
print(f"Response: {response}, outputs: {outputs}")
|
| 110 |
+
return response
|
| 111 |
+
|
| 112 |
+
demo = gr.ChatInterface(predict, type="messages", examples=examples)
|
| 113 |
+
|
| 114 |
+
demo.launch()
|
| 115 |
+
|
db.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sqlite3
|
| 2 |
+
from langchain_community.agent_toolkits.sql.base import create_sql_agent
|
| 3 |
+
from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit
|
| 4 |
+
from langchain_community.utilities import SQLDatabase
|
| 5 |
+
from langchain.agents import AgentExecutor
|
| 6 |
+
from langchain.agents.agent_types import AgentType
|
| 7 |
+
|
| 8 |
+
CHAT_DB = 'chat.db'
|
| 9 |
+
|
| 10 |
+
prompt_format_instructions = """Use the following format:
|
| 11 |
+
|
| 12 |
+
Question: the input question you must answer
|
| 13 |
+
Thought: you should always think about what to do
|
| 14 |
+
Action: the action to take, should be one of [{tool_names}]
|
| 15 |
+
Action Input: the input to the action
|
| 16 |
+
Observation: the result of the action
|
| 17 |
+
... (this Thought/Action/Action Input/Observation can repeat N times)
|
| 18 |
+
Thought: I now know the final answer
|
| 19 |
+
Final Answer: the final answer to the original input question, which should include the following 4 parameters: 1. a mandatory flag named found, if no record is found or "no records" is returned by your SQL query, return found as false, otherwise return as true. 2. the record found. 3. the table name named table_name from which a record is found. 4. a mandatory explanation named justification which contains the reason and SQL query yo used to search for record. You must give Final Answer in valid JSON format without any extra content.
|
| 20 |
+
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def prepare_data():
|
| 25 |
+
conn = sqlite3.connect(CHAT_DB)
|
| 26 |
+
c = conn.cursor()
|
| 27 |
+
c.execute('CREATE TABLE IF NOT EXISTS payment (id TEXT PRIMARY KEY, amount REAL, created_at TEXT)')
|
| 28 |
+
c.execute('CREATE TABLE IF NOT EXISTS payout (id TEXT PRIMARY KEY, amount REAL, created_at TEXT)')
|
| 29 |
+
|
| 30 |
+
c.execute('INSERT INTO payment (id, amount, created_at) VALUES (?, ?, ?) ON CONFLICT DO NOTHING', ('payment-a1c1', 100.0, '2021-01-01 00:00:00'))
|
| 31 |
+
c.execute('INSERT INTO payment (id, amount, created_at) VALUES (?, ?, ?) ON CONFLICT DO NOTHING', ('payment-b1c2', 200.0, '2021-01-02 00:00:00'))
|
| 32 |
+
|
| 33 |
+
c.execute('INSERT INTO payout (id, amount, created_at) VALUES (?, ?, ?) ON CONFLICT DO NOTHING', ('payout-a2c1', 50.0, '2021-01-01 00:00:00'))
|
| 34 |
+
c.execute('INSERT INTO payout (id, amount, created_at) VALUES (?, ?, ?) ON CONFLICT DO NOTHING', ('payout-b2c2', 100.0, '2021-01-02 00:00:00'))
|
| 35 |
+
conn.commit()
|
| 36 |
+
conn.close()
|
| 37 |
+
|
| 38 |
+
def create_sql_agent_executor(llm):
|
| 39 |
+
db = SQLDatabase.from_uri(f"sqlite:///{CHAT_DB}")
|
| 40 |
+
|
| 41 |
+
toolkit = SQLDatabaseToolkit(db=db, llm=llm)
|
| 42 |
+
agent_executor = create_sql_agent(
|
| 43 |
+
format_instructions=prompt_format_instructions,
|
| 44 |
+
llm=llm,
|
| 45 |
+
toolkit=toolkit,
|
| 46 |
+
verbose=True,
|
| 47 |
+
agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
|
| 48 |
+
agent_executor_kwargs={'handle_parsing_errors':True},
|
| 49 |
+
early_stopping_method='force',
|
| 50 |
+
max_iterations=20,
|
| 51 |
+
)
|
| 52 |
+
|
| 53 |
+
return agent_executor
|
| 54 |
+
|
requirements.txt
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
python-dotenv>=1.0.1
|
| 3 |
+
|
| 4 |
+
langchain>=0.3.20,<0.4.0
|
| 5 |
+
langchain_community>=0.3.13
|
| 6 |
+
langchain_core>=0.3.28
|
| 7 |
+
langchain_experimental>=0.3.4
|
| 8 |
+
|
| 9 |
+
huggingface-hub>=0.27.0
|
| 10 |
+
langchain-huggingface>=0.1.2
|
| 11 |
+
langchain-ollama>=0.2.3
|
| 12 |
+
|
| 13 |
+
accelerate>=1.3.0
|
| 14 |
+
|
| 15 |
+
streamlit>=1.34.0
|
| 16 |
+
streamlit_datalist>=0.0.5
|
| 17 |
+
transformers==4.49.0
|