-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
141 lines (127 loc) · 5.08 KB
/
Copy pathapp.py
File metadata and controls
141 lines (127 loc) · 5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# -*- coding: utf-8 -*-
import uvicorn
import openai
import logging
import argparse
from operator import itemgetter
from typing import List, Annotated
import faiss
from langchain_core.output_parsers import StrOutputParser
from langchain_community.vectorstores import FAISS
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableLambda, RunnableParallel, RunnablePassthrough
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.embeddings import HuggingFaceBgeEmbeddings
from langchain.chains.llm import LLMChain
from langchain.prompts import PromptTemplate
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Form, Request, Response
from pydantic import BaseModel
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
__author__ = "Ting-Shuo Yo"
__copyright__ = "Copyright 2024~, Akira Dialog Technology"
__credits__ = ["Ting-Shuo Yo"]
__license__ = "Apache License 2.0"
__version__ = "0.1.0"
__maintainer__ = "Ting-Shuo Yo"
__email__ = "tingyo@dataqualia.com"
__status__ = "development"
__date__ = '2024-02-20'
'''
This app is a demo of Retrieval Augmented Generation (RAG).
'''
#-----------------------------------------------------------------
# Define global parameters
#-----------------------------------------------------------------
VECTOR_STORE_PATH = "./data/vectorstore/"
LLM_RAG = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
EMB_MOD = OpenAIEmbeddings()
#-----------------------------------------------------------------
# Define BSA
#-----------------------------------------------------------------
def invoke_RAG_chain(question):
''' Invoke the RAG chain. '''
# Load vectorestore as the retriever
vstore = FAISS.load_local(VECTOR_STORE_PATH, embeddings=EMB_MOD)
retriever = vstore.as_retriever()
# Define prompts
prompt = ChatPromptTemplate.from_messages(
[
("system",
"You're a helpful AI assistant. Given a user question and the context, \
answer the user question in Traditional Chinese. If none of the \
articles answer the question, just say you don't know.\n\n\
Here is the context:{context}",
),
("human", "{question}"),
]
)
# Define answer
def format_docs(docs):
return "\n\n".join([d.page_content for d in docs])
format = itemgetter("docs") | RunnableLambda(format_docs)
# subchain for generating an answer once we've done retrieval
answer = prompt | LLM_RAG | StrOutputParser()
#Define chain
chain = (
RunnableParallel(question=RunnablePassthrough(), docs=retriever)
.assign(context=format)
.assign(answer=answer)
.pick(["answer", "docs"])
)
# Invoke the RAG chain
res = chain.invoke(question)
logging.debug('Answer:\t'+res['answer'])
logging.info('Sources:\t'+str([doc.metadata for doc in res['docs']]))
# Done
return(res)
def beautify_results(results, format='md'):
''' Format the results for display '''
output=("## 您的提問:\n>> " + results['question']+"\n\n")
output+=("## 查詢的結果:\n")
output+=("### 摘要:\n>> "+results['answer'].replace('\n','\n>> ')+"\n\n")
output+=("### 引用來源:\n")
for source in results['citations']:
output+=("- "+str(source).replace('\n','\n>> ')+"\n")
return(output)
#-----------------------------------------------------------------
# Define FastAPI app
#-----------------------------------------------------------------
app = FastAPI()
# locate templates
templates = Jinja2Templates(directory="templates")
chat_log = []
@app.get("/", response_class=HTMLResponse)
async def bsa_page(request: Request):
''' GET: show the landing page as the interface '''
return templates.TemplateResponse("home.html", {"request": request, "chat_log": chat_log})
@app.post("/", response_class=HTMLResponse)
async def bsa_run(request: Request, user_input: Annotated[str, Form()]):
''' POST: perform RAG and display the results. '''
logging.info('[QUESTION]'+user_input)
res_rag = invoke_RAG_chain(user_input)
#logging.debug('[RESPONSE_RAG]'+res_rag)
results = {
'question': user_input,
'answer': res_rag['answer'],
'citations': [doc.metadata for doc in res_rag['docs']],
}
response = beautify_results(results)
logging.debug('[OUTPUT]'+response)
chat_log.append(response)
return templates.TemplateResponse("home.html", {"request": request, "chat_log": chat_log})
if __name__ == "__main__":
parser = argparse.ArgumentParser()
# Create an argument parser
parser = argparse.ArgumentParser(description='Example RAG Parameters')
# Add arguments
parser.add_argument('--vectorstore_path', type=str, required=False,
help="Path to vectorestore for retrival.", default=VECTOR_STORE_PATH)
# Parse the arguments
args = parser.parse_args()
# Setup logging
logging.basicConfig(level=logging.DEBUG)
# Use the provided arguments
VECTOR_STORE_PATH = args.vectorstore_path
#run server
uvicorn.run(app)