lakshyaag commited on
Commit
2e5aca2
β€’
1 Parent(s): a8ab4cd

project: add C-RAG project

Browse files
.chainlit/config.toml ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ # Whether to enable telemetry (default: true). No personal data is collected.
3
+ enable_telemetry = true
4
+
5
+ # List of environment variables to be provided by each user to use the app.
6
+ user_env = []
7
+
8
+ # Duration (in seconds) during which the session is saved when the connection is lost
9
+ session_timeout = 3600
10
+
11
+ # Enable third parties caching (e.g LangChain cache)
12
+ cache = false
13
+
14
+ # Follow symlink for asset mount (see https://github.com/Chainlit/chainlit/issues/317)
15
+ # follow_symlink = false
16
+
17
+ [features]
18
+ # Show the prompt playground
19
+ prompt_playground = true
20
+
21
+ # Process and display HTML in messages. This can be a security risk (see https://stackoverflow.com/questions/19603097/why-is-it-dangerous-to-render-user-generated-html-or-javascript)
22
+ unsafe_allow_html = false
23
+
24
+ # Process and display mathematical expressions. This can clash with "$" characters in messages.
25
+ latex = false
26
+
27
+ # Authorize users to upload files with messages
28
+ multi_modal = true
29
+
30
+ # Allows user to use speech to text
31
+ [features.speech_to_text]
32
+ enabled = false
33
+ # See all languages here https://github.com/JamesBrill/react-speech-recognition/blob/HEAD/docs/API.md#language-string
34
+ # language = "en-US"
35
+
36
+ [UI]
37
+ # Name of the app and chatbot.
38
+ name = "10-Q Bot"
39
+
40
+ # Show the readme while the conversation is empty.
41
+ show_readme_as_default = true
42
+
43
+ # Description of the app and chatbot. This is used for HTML tags.
44
+ description = "This is a 10-Q Bot, designed to assist with SEC filings and financial data queries."
45
+
46
+ # Large size content are by default collapsed for a cleaner ui
47
+ default_collapse_content = true
48
+
49
+ # The default value for the expand messages settings.
50
+ default_expand_messages = false
51
+
52
+ # Hide the chain of thought details from the user in the UI.
53
+ hide_cot = false
54
+
55
+ # Link to your github repo. This will add a github button in the UI's header.
56
+ # github = "https://github.com/lakshyaag/"
57
+
58
+ # Specify a CSS file that can be used to customize the user interface.
59
+ # The CSS file can be served from the public directory or via an external link.
60
+ # custom_css = "/public/test.css"
61
+
62
+ # Override default MUI light theme. (Check theme.ts)
63
+ [UI.theme.light]
64
+ #background = "#FAFAFA"
65
+ #paper = "#FFFFFF"
66
+
67
+ [UI.theme.light.primary]
68
+ #main = "#F80061"
69
+ #dark = "#980039"
70
+ #light = "#FFE7EB"
71
+
72
+ # Override default MUI dark theme. (Check theme.ts)
73
+ [UI.theme.dark]
74
+ #background = "#FAFAFA"
75
+ #paper = "#FFFFFF"
76
+
77
+ [UI.theme.dark.primary]
78
+ #main = "#F80061"
79
+ #dark = "#980039"
80
+ #light = "#FFE7EB"
81
+
82
+
83
+ [meta]
84
+ generated_by = "0.7.700"
Dockerfile ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10
2
+ RUN pip install --upgrade pip
3
+
4
+ RUN useradd -m -u 1000 user
5
+ USER user
6
+ ENV HOME=/home/user \
7
+ PATH=/home/user/.local/bin:$PATH
8
+
9
+ WORKDIR $HOME/app
10
+
11
+ COPY --chown=user ./requirements.txt $HOME/app/requirements.txt
12
+ RUN pip install -r $HOME/app/requirements.txt
13
+
14
+ COPY --chown=user . $HOME/app
15
+ RUN chown user -R ${HOME}/app/
16
+
17
+ CMD ["chainlit", "run", "app.py", "--port", "7860"]
README.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Airbnb 10-Q Chatbot
3
+ emoji: πŸ“
4
+ colorFrom: red
5
+ colorTo: green
6
+ sdk: docker
7
+ pinned: false
8
+ app_port: 7860
9
+ ---
10
+
11
+ This chatbot is designed to answer questions about Airbnb's 10-Q financial statement for the quarter ended March 31, 2024.
12
+
13
+ It uses corrective RAG as the architecture to retrieve information based on the user's input, grading the relevance of the retrieved documents, and optionally querying Wikipedia for additional information, if necessary.
app.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import chainlit as cl
3
+ from dotenv import load_dotenv
4
+ from graph import create_graph
5
+ from langchain_core.runnables import RunnableConfig
6
+
7
+
8
+ load_dotenv()
9
+
10
+ OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
11
+ graph = create_graph()
12
+
13
+ @cl.on_message
14
+ async def main(message: cl.Message):
15
+ """
16
+ This function will be called every time a message is recieved from a session.
17
+ """
18
+
19
+ msg = cl.Message(content="")
20
+
21
+ async for event in graph.astream_events(
22
+ {"question": message.content},
23
+ config=RunnableConfig(callbacks=[cl.LangchainCallbackHandler()]),
24
+ version="v1",
25
+ ):
26
+ if (
27
+ event["event"] == "on_chat_model_stream"
28
+ and event["metadata"]["langgraph_node"] == "generate"
29
+ ):
30
+ await msg.stream_token(event["data"]["chunk"].content)
31
+
32
+ await msg.send()
chainlit.md ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # Airbnb 10-Q Chatbot
2
+
3
+ This chatbot is designed to answer questions about Airbnb's 10-Q financial statement for the quarter ended March 31, 2024.
4
+
5
+ It uses corrective RAG as the architecture to retrieve information based on the user's input, grading the relevance of the retrieved documents, and optionally querying Wikipedia for additional information, if necessary.
crag.ipynb CHANGED
@@ -2,18 +2,9 @@
2
  "cells": [
3
  {
4
  "cell_type": "code",
5
- "execution_count": 6,
6
  "metadata": {},
7
- "outputs": [
8
- {
9
- "name": "stdout",
10
- "output_type": "stream",
11
- "text": [
12
- "The autoreload extension is already loaded. To reload it, use:\n",
13
- " %reload_ext autoreload\n"
14
- ]
15
- }
16
- ],
17
  "source": [
18
  "%load_ext autoreload\n",
19
  "%autoreload 2"
@@ -21,7 +12,7 @@
21
  },
22
  {
23
  "cell_type": "code",
24
- "execution_count": 7,
25
  "metadata": {},
26
  "outputs": [],
27
  "source": [
@@ -32,17 +23,17 @@
32
  },
33
  {
34
  "cell_type": "code",
35
- "execution_count": 8,
36
  "metadata": {},
37
  "outputs": [
38
  {
39
  "data": {
40
- "image/jpeg": "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",
41
  "text/plain": [
42
  "<IPython.core.display.Image object>"
43
  ]
44
  },
45
- "execution_count": 8,
46
  "metadata": {},
47
  "output_type": "execute_result"
48
  }
 
2
  "cells": [
3
  {
4
  "cell_type": "code",
5
+ "execution_count": 1,
6
  "metadata": {},
7
+ "outputs": [],
 
 
 
 
 
 
 
 
 
8
  "source": [
9
  "%load_ext autoreload\n",
10
  "%autoreload 2"
 
12
  },
13
  {
14
  "cell_type": "code",
15
+ "execution_count": 8,
16
  "metadata": {},
17
  "outputs": [],
18
  "source": [
 
23
  },
24
  {
25
  "cell_type": "code",
26
+ "execution_count": 9,
27
  "metadata": {},
28
  "outputs": [
29
  {
30
  "data": {
31
+ "image/jpeg": "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",
32
  "text/plain": [
33
  "<IPython.core.display.Image object>"
34
  ]
35
  },
36
+ "execution_count": 9,
37
  "metadata": {},
38
  "output_type": "execute_result"
39
  }
graph.py CHANGED
@@ -1,16 +1,13 @@
1
  from typing import List
2
 
3
- import aiosqlite
4
- from generator import rag_chain
5
- from grader import retrieval_grader
6
  from langchain.schema import Document
7
- from langgraph.checkpoint.aiosqlite import AsyncSqliteSaver
8
  from langgraph.graph import END, StateGraph
9
- from langgraph.graph.message import add_messages
10
- from retriever import retriever
11
- from rewriter import question_rewriter
 
12
  from tools.search_wikipedia import wikipedia
13
- from typing_extensions import Annotated, TypedDict
14
 
15
 
16
  # DEFINE STATE GRAPH
@@ -27,7 +24,7 @@ class GraphState(TypedDict):
27
 
28
  # Update this to work with memory in a better way.
29
  question: str
30
- generation: Annotated[List[str], add_messages]
31
  wiki_search: str
32
  documents: List[str]
33
 
@@ -111,45 +108,14 @@ def search_wikipedia(state):
111
  return {"question": question, "documents": documents}
112
 
113
 
114
- def question_node(state):
115
- question = state["question"]
116
- generation = state.get("generation", None)
117
-
118
- return {"question": question, "generation": generation}
119
-
120
-
121
- def check_memory_or_db(state):
122
- print("Checking memory or database...")
123
- print(state)
124
-
125
- if state.get("generation", None) is not None and len(state["generation"]) > 0:
126
- question = state["question"]
127
- generation = state["generation"]
128
-
129
- perform_rag = retrieval_grader.invoke(
130
- {"question": question, "document": generation}
131
- )
132
-
133
- if perform_rag.binary_score == "yes":
134
- print("Memory not sufficient. Performing RAG.")
135
- return "retrieve"
136
-
137
- else:
138
- print("Memory sufficient. Generating answer.")
139
- return "generate"
140
-
141
- else:
142
- print("No memory found. Retrieving documents...")
143
- return "retrieve"
144
-
145
-
146
  # DEFINE CONDITIONAL EDGES
147
  def generate_or_not(state):
148
  print("Determining whether to query Wikipedia...")
149
 
150
  wiki_search = state["wiki_search"]
 
151
 
152
- if wiki_search:
153
  print("Rewriting query and supplementing information from Wikipedia...")
154
  return "rewrite_query"
155
 
@@ -162,18 +128,13 @@ def create_graph():
162
  # DEFINE WORKFLOW
163
  workflow = StateGraph(GraphState)
164
 
165
- workflow.add_node("start", question_node)
166
-
167
  workflow.add_node("retrieve", retrieve)
168
  workflow.add_node("grade_documents", grade_documents)
169
  workflow.add_node("rewrite_query", rewrite_query)
170
  workflow.add_node("search_wikipedia", search_wikipedia)
171
  workflow.add_node("generate", generate)
172
 
173
- workflow.set_entry_point("start")
174
- workflow.add_conditional_edges(
175
- "start", check_memory_or_db, {"retrieve": "retrieve", "generate": "generate"}
176
- )
177
  workflow.add_edge("retrieve", "grade_documents")
178
  workflow.add_conditional_edges(
179
  "grade_documents",
@@ -185,11 +146,7 @@ def create_graph():
185
  workflow.add_edge("search_wikipedia", "generate")
186
  workflow.add_edge("generate", END)
187
 
188
- # DEFINE MEMORY
189
- checkpoints = aiosqlite.connect("./checkpoints/checkpoint.sqlite")
190
- memory = AsyncSqliteSaver(checkpoints)
191
-
192
  # COMPILE GRAPH
193
- app = workflow.compile(checkpointer=memory)
194
 
195
  return app
 
1
  from typing import List
2
 
 
 
 
3
  from langchain.schema import Document
 
4
  from langgraph.graph import END, StateGraph
5
+ from nodes.generator import rag_chain
6
+ from nodes.grader import retrieval_grader
7
+ from nodes.retriever import retriever
8
+ from nodes.rewriter import question_rewriter
9
  from tools.search_wikipedia import wikipedia
10
+ from typing_extensions import TypedDict
11
 
12
 
13
  # DEFINE STATE GRAPH
 
24
 
25
  # Update this to work with memory in a better way.
26
  question: str
27
+ generation: str
28
  wiki_search: str
29
  documents: List[str]
30
 
 
108
  return {"question": question, "documents": documents}
109
 
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  # DEFINE CONDITIONAL EDGES
112
  def generate_or_not(state):
113
  print("Determining whether to query Wikipedia...")
114
 
115
  wiki_search = state["wiki_search"]
116
+ filtered_docs = state["documents"]
117
 
118
+ if len(filtered_docs) == 0 and wiki_search:
119
  print("Rewriting query and supplementing information from Wikipedia...")
120
  return "rewrite_query"
121
 
 
128
  # DEFINE WORKFLOW
129
  workflow = StateGraph(GraphState)
130
 
 
 
131
  workflow.add_node("retrieve", retrieve)
132
  workflow.add_node("grade_documents", grade_documents)
133
  workflow.add_node("rewrite_query", rewrite_query)
134
  workflow.add_node("search_wikipedia", search_wikipedia)
135
  workflow.add_node("generate", generate)
136
 
137
+ workflow.set_entry_point("retrieve")
 
 
 
138
  workflow.add_edge("retrieve", "grade_documents")
139
  workflow.add_conditional_edges(
140
  "grade_documents",
 
146
  workflow.add_edge("search_wikipedia", "generate")
147
  workflow.add_edge("generate", END)
148
 
 
 
 
 
149
  # COMPILE GRAPH
150
+ app = workflow.compile()
151
 
152
  return app
nodes/__init__.py ADDED
File without changes
generator.py β†’ nodes/generator.py RENAMED
@@ -1,18 +1,15 @@
1
- ### Generate
2
- import config
3
  from langchain_openai import ChatOpenAI
4
- from langchain_core.output_parsers import StrOutputParser
5
  from langchain_core.prompts import ChatPromptTemplate
6
 
7
  # Prompt
8
- agent_prompt = """You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.\nQuestion: {question} \nContext: {context} \nAnswer:"""
9
-
10
- prompt = ChatPromptTemplate.from_messages([("human", agent_prompt)])
11
 
12
  prompt
13
 
14
  # Generator LLM
15
- llm = ChatOpenAI(model_name=config.GENERATOR_MODEL, temperature=0, streaming=True)
16
 
17
 
18
  # Post-processing
@@ -21,7 +18,7 @@ def format_docs(docs):
21
 
22
 
23
  # Chain
24
- rag_chain = prompt | llm | StrOutputParser()
25
 
26
  # generation = rag_chain.invoke({"context": docs, "question": question})
27
  # print(generation)
 
1
+ from utils.prompts import GENERATOR_PROMPT
2
+ from utils.config import GENERATOR_MODEL
3
  from langchain_openai import ChatOpenAI
 
4
  from langchain_core.prompts import ChatPromptTemplate
5
 
6
  # Prompt
7
+ prompt = ChatPromptTemplate.from_messages([("human", GENERATOR_PROMPT)])
 
 
8
 
9
  prompt
10
 
11
  # Generator LLM
12
+ llm = ChatOpenAI(model_name=GENERATOR_MODEL, temperature=0.7, streaming=True)
13
 
14
 
15
  # Post-processing
 
18
 
19
 
20
  # Chain
21
+ rag_chain = prompt | llm
22
 
23
  # generation = rag_chain.invoke({"context": docs, "question": question})
24
  # print(generation)
grader.py β†’ nodes/grader.py RENAMED
@@ -1,4 +1,5 @@
1
- import config
 
2
  from langchain_core.prompts import ChatPromptTemplate
3
  from langchain_core.pydantic_v1 import BaseModel, Field
4
  from langchain_openai import ChatOpenAI
@@ -11,26 +12,22 @@ class DocumentGrade(BaseModel):
11
  binary_score: str = Field(
12
  description='Document is relevant to the question, "yes" or "no"'
13
  )
 
14
 
15
 
16
  # Grader Prompts
17
- system = """You are a grader assessing relevance of a retrieved document to a user question. \n
18
- If the document contains keyword(s) or semantic meaning related to the question, grade it as relevant. \n
19
- Give a binary score 'yes' or 'no' score to indicate whether the document is relevant to the question."""
20
-
21
  grade_prompt = ChatPromptTemplate.from_messages(
22
  [
23
- ("system", system),
24
- ("human", "Retrieved document: \n\n {document} \n\n User question: {question}"),
25
  ]
26
  )
27
 
28
 
29
  # LLM with function call
30
- llm = ChatOpenAI(model=config.GRADER_MODEL, temperature=0, streaming=True)
31
 
32
  structured_llm_grader = llm.with_structured_output(DocumentGrade)
33
- structured_llm_grader
34
 
35
 
36
  retrieval_grader = grade_prompt | structured_llm_grader
 
1
+ from utils.prompts import GRADER_SYSTEM_PROMPT, GRADER_PROMPT
2
+ from utils.config import GRADER_MODEL
3
  from langchain_core.prompts import ChatPromptTemplate
4
  from langchain_core.pydantic_v1 import BaseModel, Field
5
  from langchain_openai import ChatOpenAI
 
12
  binary_score: str = Field(
13
  description='Document is relevant to the question, "yes" or "no"'
14
  )
15
+ reasoning: str = Field(description="Reasoning for the score")
16
 
17
 
18
  # Grader Prompts
 
 
 
 
19
  grade_prompt = ChatPromptTemplate.from_messages(
20
  [
21
+ ("system", GRADER_SYSTEM_PROMPT),
22
+ ("human", GRADER_PROMPT),
23
  ]
24
  )
25
 
26
 
27
  # LLM with function call
28
+ llm = ChatOpenAI(model=GRADER_MODEL, temperature=0, streaming=True)
29
 
30
  structured_llm_grader = llm.with_structured_output(DocumentGrade)
 
31
 
32
 
33
  retrieval_grader = grade_prompt | structured_llm_grader
retriever.py β†’ nodes/retriever.py RENAMED
@@ -1,17 +1,18 @@
 
1
  from langchain_community.document_loaders import PyPDFLoader
2
  from langchain.text_splitter import RecursiveCharacterTextSplitter
3
  from langchain_community.vectorstores import Qdrant
4
  from langchain_openai import OpenAIEmbeddings
5
  import os
6
 
7
- QDRANT_DATA_DIR = "./qdrant_data"
 
8
 
9
  if os.path.exists(QDRANT_DATA_DIR):
10
-
11
  vectorstore = Qdrant.from_existing_collection(
12
  embedding=OpenAIEmbeddings(),
13
  path=QDRANT_DATA_DIR,
14
- collection_name="rag-chroma",
15
  )
16
 
17
  else:
@@ -31,11 +32,11 @@ else:
31
  # Add to vectorDB with on-disk storage
32
  vectorstore = Qdrant.from_documents(
33
  documents=doc_splits,
34
- collection_name="rag-chroma",
35
- path="./qdrant_data", # Local mode with on-disk storage
36
  embedding=OpenAIEmbeddings(),
37
  )
38
 
39
- retriever = vectorstore.as_retriever()
40
 
41
- # print(retriever.invoke("What is the average length of stay for Airbnb guests?"))
 
1
+ from utils.config import QDRANT_DATA_DIR, COLLECTION_NAME
2
  from langchain_community.document_loaders import PyPDFLoader
3
  from langchain.text_splitter import RecursiveCharacterTextSplitter
4
  from langchain_community.vectorstores import Qdrant
5
  from langchain_openai import OpenAIEmbeddings
6
  import os
7
 
8
+ QDRANT_DATA_DIR = QDRANT_DATA_DIR
9
+ COLLECTION_NAME = COLLECTION_NAME
10
 
11
  if os.path.exists(QDRANT_DATA_DIR):
 
12
  vectorstore = Qdrant.from_existing_collection(
13
  embedding=OpenAIEmbeddings(),
14
  path=QDRANT_DATA_DIR,
15
+ collection_name=COLLECTION_NAME,
16
  )
17
 
18
  else:
 
32
  # Add to vectorDB with on-disk storage
33
  vectorstore = Qdrant.from_documents(
34
  documents=doc_splits,
35
+ collection_name=COLLECTION_NAME,
36
+ path=QDRANT_DATA_DIR, # Local mode with on-disk storage
37
  embedding=OpenAIEmbeddings(),
38
  )
39
 
40
+ retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
41
 
42
+ # print(retriever.invoke("What is the average length of stay for Airbnb guests?"))
rewriter.py β†’ nodes/rewriter.py RENAMED
@@ -1,23 +1,18 @@
1
  ### Rewrite a question to be more optimized for Wikipedia search
2
- import config
 
3
  from langchain_core.output_parsers import StrOutputParser
4
  from langchain_core.prompts import ChatPromptTemplate
5
  from langchain_openai import ChatOpenAI
6
 
7
  # Question rewriter LLM
8
- llm = ChatOpenAI(model=config.REWRITER_MODEL, temperature=0, streaming=True)
9
 
10
  # Prompt
11
- system = """You are a question re-writer that converts an input question to a better version that is optimized \n
12
- for searching on Wikipedia. Look at the input and try to reason about the underlying semantic intent / meaning, such that the new question is more optimized for search."""
13
-
14
  rewrite_prompt = ChatPromptTemplate.from_messages(
15
  [
16
- ("system", system),
17
- (
18
- "human",
19
- "Here is the initial question: \n\n {question} \n Formulate an improved question.",
20
- ),
21
  ]
22
  )
23
 
 
1
  ### Rewrite a question to be more optimized for Wikipedia search
2
+ from utils.config import REWRITER_MODEL
3
+ from utils.prompts import QUERY_REWRITE_PROMPT, QUERY_REWRITE_SYSTEM_PROMPT
4
  from langchain_core.output_parsers import StrOutputParser
5
  from langchain_core.prompts import ChatPromptTemplate
6
  from langchain_openai import ChatOpenAI
7
 
8
  # Question rewriter LLM
9
+ llm = ChatOpenAI(model=REWRITER_MODEL, temperature=0, streaming=True)
10
 
11
  # Prompt
 
 
 
12
  rewrite_prompt = ChatPromptTemplate.from_messages(
13
  [
14
+ ("system", QUERY_REWRITE_SYSTEM_PROMPT),
15
+ ("human", QUERY_REWRITE_PROMPT),
 
 
 
16
  ]
17
  )
18
 
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ chainlit==0.7.700
2
+ langchain==0.2.5
3
+ langchain_core==0.2.9
4
+ langchain_community==0.2.5
5
+ langchain_openai==0.1.8
6
+ langchain_text_splitters==0.2.1
7
+ langgraph==0.0.69
8
+ qdrant-client==1.9.1
9
+ python-dotenv==1.0.1
10
+ typing_extensions==4.12.2
11
+ wikipedia
server.py CHANGED
@@ -4,15 +4,15 @@ from fastapi.middleware.cors import CORSMiddleware
4
  from langserve import add_routes
5
 
6
  from graph import create_graph
7
- from chat_types import ChatInputType
8
 
9
  # Load environment variables from .env file
10
  load_dotenv()
11
 
12
  app = FastAPI(
13
- title="Gen UI Backend",
14
  version="1.0",
15
- description="A simple api server using Langchain's Runnable interfaces",
16
  )
17
 
18
  # Configure CORS
 
4
  from langserve import add_routes
5
 
6
  from graph import create_graph
7
+ from utils.chat_types import ChatInputType
8
 
9
  # Load environment variables from .env file
10
  load_dotenv()
11
 
12
  app = FastAPI(
13
+ title="CRAG Backend",
14
  version="1.0",
15
+ description="Backend to run agent performing corrective RAG over annual reports",
16
  )
17
 
18
  # Configure CORS
utils/__init__.py ADDED
File without changes
chat_types.py β†’ utils/chat_types.py RENAMED
File without changes
config.py β†’ utils/config.py RENAMED
@@ -1,3 +1,7 @@
1
  GENERATOR_MODEL = "gpt-4o"
2
  REWRITER_MODEL = "gpt-4o"
3
  GRADER_MODEL = "gpt-4o"
 
 
 
 
 
1
  GENERATOR_MODEL = "gpt-4o"
2
  REWRITER_MODEL = "gpt-4o"
3
  GRADER_MODEL = "gpt-4o"
4
+ MEMORY_MODEL = "gpt-4o"
5
+
6
+ QDRANT_DATA_DIR = "./qdrant_data"
7
+ COLLECTION_NAME='10k-docs'
utils/prompts.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ QUERY_REWRITE_SYSTEM_PROMPT = """You are a question re-writer that converts an input question to a better version that is optimized for searching on Wikipedia.
2
+ Look at the input and try to reason about the underlying semantic intent / meaning, such that the new question is more optimized for search."""
3
+
4
+ QUERY_REWRITE_PROMPT = (
5
+ "Here is the initial question: \n\n {question} \n Formulate an improved question."
6
+ )
7
+
8
+ GRADER_SYSTEM_PROMPT = """You are a grader assessing relevance of a retrieved document to a user question.
9
+ If the document contains keyword(s) or semantic meaning related to the question, grade it as relevant.
10
+ Give a binary score 'yes' or 'no' score to indicate whether the document is relevant to the question. Provide reasoning for your answer."""
11
+
12
+ GRADER_PROMPT = "Retrieved document: \n\n {document} \n\n User question: {question}"
13
+
14
+ GENERATOR_PROMPT = """You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question.
15
+ If you don't know the answer, just say that you don't know.
16
+ Use three sentences maximum and keep the answer concise.
17
+ Question: {question} \nContext: {context} \nAnswer:"""