vip11017 commited on
Commit
649efae
·
1 Parent(s): 1fdc232

Finished building RAG from form to complete RAG

Browse files
app/chatbot/demo_rag.py CHANGED
@@ -14,9 +14,11 @@ import time
14
  import os
15
  from dotenv import load_dotenv
16
 
17
- from qdrant_client import QdrantClient
18
 
19
- from app.mongodb import log_chat
 
 
20
 
21
  load_dotenv()
22
  os.environ["TOKENIZERS_PARALLELISM"] = "false"
@@ -50,12 +52,6 @@ llm = ChatMistralAI(
50
 
51
  embeddings = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL)
52
 
53
- try:
54
- client = QdrantClient(url=QDRANT_URL, api_key=QDRANT_API_KEY)
55
- print(f"Qdrant Collections: {client.get_collections()}")
56
- except Exception as e:
57
- raise RuntimeError(f"Failed to connect to Qdrant: {e}")
58
-
59
 
60
  class GraphState(TypedDict):
61
  """
@@ -67,6 +63,8 @@ class GraphState(TypedDict):
67
  response: str
68
  tool_results: dict
69
  prompt: str
 
 
70
 
71
  from pydantic import BaseModel
72
 
@@ -74,28 +72,85 @@ class ToolInput(BaseModel):
74
  prompt: str
75
  iteration: int = 1
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
 
 
 
 
78
 
 
 
79
 
80
- all_tools = []
 
 
 
 
 
 
81
 
82
 
83
  def retrieve_node(state: GraphState) -> GraphState:
 
 
 
 
 
 
 
 
 
84
  query = state['input']
85
  tool_results = {}
86
 
87
- for tool in all_tools:
88
- print(f"Invoking tool: {tool.name} with query: {query}")
89
  try:
90
- tool_results[tool.name] = tool.invoke({'query': query})
91
- print(f"{tool.name} returned {len(tool_results[tool.name])} result(s)")
 
92
  except Exception as e:
93
- tool_results[tool.name] = [{'content': f"Tool {tool.name} failed: {str(e)}", "source": "system"}]
94
-
 
95
  state['tool_results'] = tool_results
96
  return state
97
 
98
-
99
  def generate_answer(state: GraphState):
100
  """
101
  This function generates an answer to the query using the llm and the context provided.
@@ -119,9 +174,8 @@ def generate_answer(state: GraphState):
119
  )
120
  for tool_name, results in intermediate_steps.items() if results
121
  )
122
-
123
-
124
- prompt_input = template.format(
125
  input=query,
126
  agent_scratchpad=steps_string,
127
  history=history_text
@@ -151,13 +205,15 @@ graph.add_edge("generate_response", END)
151
 
152
  app = graph.compile()
153
 
154
- async def get_response(query: str, name, email, config) -> dict:
155
  start_time = time.time()
156
  session_id = config['configurable']['thread_id']
157
  history = session_histories.get(session_id, [])
158
  input_data = {
159
  "input": query,
160
- "history": history
 
 
161
  }
162
  metadata={}
163
  latency_ms = None
@@ -182,6 +238,8 @@ async def get_response(query: str, name, email, config) -> dict:
182
 
183
  log_chat(
184
  session_id=session_id,
 
 
185
  name=name,
186
  email=email,
187
  query=query,
 
14
  import os
15
  from dotenv import load_dotenv
16
 
17
+ from app.config import qdrant_client
18
 
19
+ from app.chatbot.mongodb import log_chat
20
+
21
+ #from app.mongodb import log_chat
22
 
23
  load_dotenv()
24
  os.environ["TOKENIZERS_PARALLELISM"] = "false"
 
52
 
53
  embeddings = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL)
54
 
 
 
 
 
 
 
55
 
56
  class GraphState(TypedDict):
57
  """
 
63
  response: str
64
  tool_results: dict
65
  prompt: str
66
+ retrieve_tools: List[dict]
67
+ prompt_template: str
68
 
69
  from pydantic import BaseModel
70
 
 
72
  prompt: str
73
  iteration: int = 1
74
 
75
+ def retrieve_docs(query: str, retriever: dict):
76
+ """
77
+ Retrieve documents from Qdrant for a single retriever configuration.
78
+
79
+ Args:
80
+ query (str): The user query.
81
+ retriever (dict): Retriever config with keys:
82
+ - 'collection': Qdrant collection name
83
+ - 'top_k': number of results to return (default 5)
84
+ - 'filter_score': min similarity score to keep results (default 0.1)
85
+
86
+ Returns:
87
+ List[dict]: List of dicts with 'content' and 'score'.
88
+ """
89
+ top_k = retriever.get('top_k', 5)
90
+ filter_score = retriever.get('filter_score', 50)
91
+ collection = retriever.get('collection')
92
+
93
+ # Qdrant store
94
+ rev_store = QdrantVectorStore(
95
+ client=qdrant_client, # make sure this is initialized globally
96
+ collection_name=collection,
97
+ embedding=embeddings,
98
+ )
99
+ print(f"Retrieving from collection: {collection} with top_k={top_k} and filter_score={filter_score}")
100
+ # Similarity search
101
+ docs = rev_store.similarity_search_with_score(query, k=top_k)
102
+
103
+ # Filter results by score
104
+ return [
105
+ {"content": doc.page_content, "score": score}
106
+ for doc, score in docs
107
+ if score > filter_score
108
+ ]
109
 
110
+ def build_prompt(template: str):
111
+ global_template = """
112
+ Conversation History (for context only, not authority):
113
+ {history}
114
 
115
+ Contextual Knowledge (only approved source of truth):
116
+ {agent_scratchpad}
117
 
118
+ User Question:
119
+ {input}
120
+
121
+ Response:
122
+ """
123
+ final_template = f"{template}\n{global_template}"
124
+ return final_template
125
 
126
 
127
  def retrieve_node(state: GraphState) -> GraphState:
128
+ """
129
+ Graph node to retrieve documents for all retrievers in the state.
130
+
131
+ Args:
132
+ state (GraphState): Current chat state including input and retrievers.
133
+
134
+ Returns:
135
+ GraphState: Updated state with 'tool_results' filled.
136
+ """
137
  query = state['input']
138
  tool_results = {}
139
 
140
+ for retriever_cfg in state.get('retrieve_tools', []):
141
+ name = retriever_cfg.get('name', 'default')
142
  try:
143
+ docs = retrieve_docs(query, retriever_cfg)
144
+ tool_results[name] = docs
145
+ print(f"Retriever '{name}' returned {len(docs)} result(s)")
146
  except Exception as e:
147
+ tool_results[name] = [{"content": f"Retriever failed: {str(e)}", "score": 0}]
148
+ print(f"Retriever '{name}' failed: {e}")
149
+
150
  state['tool_results'] = tool_results
151
  return state
152
 
153
+ #Answer Question
154
  def generate_answer(state: GraphState):
155
  """
156
  This function generates an answer to the query using the llm and the context provided.
 
174
  )
175
  for tool_name, results in intermediate_steps.items() if results
176
  )
177
+ prompt_template = build_prompt(state['prompt_template'])
178
+ prompt_input = prompt_template.format(
 
179
  input=query,
180
  agent_scratchpad=steps_string,
181
  history=history_text
 
205
 
206
  app = graph.compile()
207
 
208
+ async def get_response(query, session_id, name, email, rag_config, config) -> dict:
209
  start_time = time.time()
210
  session_id = config['configurable']['thread_id']
211
  history = session_histories.get(session_id, [])
212
  input_data = {
213
  "input": query,
214
+ "history": history,
215
+ "retrieve_tools": rag_config.get('retrievers', []),
216
+ "prompt_template": rag_config.get('prompt_template', ""),
217
  }
218
  metadata={}
219
  latency_ms = None
 
238
 
239
  log_chat(
240
  session_id=session_id,
241
+ company_id=rag_config.get('company_id'),
242
+ chatbot_id=rag_config.get('chatbot_id'),
243
  name=name,
244
  email=email,
245
  query=query,
app/chatbot/demo_routes.py CHANGED
@@ -1,23 +1,43 @@
1
- from fastapi import APIRouter
2
  from pydantic import BaseModel
3
  from app.chatbot.demo_rag import get_response
 
4
 
5
  router = APIRouter()
 
6
 
7
  class ChatInput(BaseModel):
8
- chatbot_id: str
9
  question: str
10
  session_id: str
11
  name: str
12
  email: str
13
 
14
- @router.post("/demochat")
15
- async def demo_chat(input: ChatInput):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  response = await get_response(
17
- chatbot_id=input.chatbot_id,
18
  query=input.question,
19
  session_id=input.session_id,
20
  name=input.name,
21
- email=input.email
 
 
22
  )
23
  return {"answer": response['response']}
 
1
+ from fastapi import APIRouter, HTTPException
2
  from pydantic import BaseModel
3
  from app.chatbot.demo_rag import get_response
4
+ from app.config import demo_chatbot_configs
5
 
6
  router = APIRouter()
7
+ chatbot_sessions = {} # chatbot_id -> loaded config/session
8
 
9
  class ChatInput(BaseModel):
 
10
  question: str
11
  session_id: str
12
  name: str
13
  email: str
14
 
15
+
16
+ @router.post("/demo/{chatbot_id}")
17
+ async def demo_chat(chatbot_id: str, input: ChatInput):
18
+ # Lazy-load chatbot config
19
+ print(f"got question: {input.question} for chatbot_id: {chatbot_id} and session_id: {input.session_id}")
20
+ if chatbot_id not in chatbot_sessions:
21
+ rag_config = demo_chatbot_configs.find_one({"chatbot_id": chatbot_id})
22
+ if not rag_config:
23
+ raise HTTPException(status_code=404, detail="Chatbot not found")
24
+ chatbot_sessions[chatbot_id] = rag_config
25
+
26
+ rag_config = chatbot_sessions[chatbot_id]
27
+ print(rag_config)
28
+
29
+ config = {
30
+ 'configurable': {
31
+ 'thread_id': input.session_id
32
+ }
33
+ }
34
+
35
  response = await get_response(
 
36
  query=input.question,
37
  session_id=input.session_id,
38
  name=input.name,
39
+ email=input.email,
40
+ rag_config=rag_config,
41
+ config=config
42
  )
43
  return {"answer": response['response']}
app/chatbot/mongodb.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # %%
2
+ from pymongo.mongo_client import MongoClient
3
+ from pymongo.server_api import ServerApi
4
+
5
+ import os
6
+ from dotenv import load_dotenv
7
+
8
+ from datetime import datetime, timezone
9
+ from app.config import client, chat_logs
10
+
11
+
12
+ # %%
13
+ def log_chat(session_id: str, name: str, email: str, query: str, answer: str, latency_ms: float, chatbot_id: str, company_id: str, metadata: dict=None):
14
+ """
15
+ Logs a chat interaction to the MongoDB 'ChatLogs' collection.
16
+ """
17
+ data = {
18
+ "company_id": company_id,
19
+ "chatbot_id": chatbot_id,
20
+ "session_id": session_id,
21
+ "name": name,
22
+ "email": email,
23
+ "timestamp": datetime.now(timezone.utc),
24
+ "query": query,
25
+ "answer": answer,
26
+ "metadata": metadata or {},
27
+ "starred": False
28
+ }
29
+
30
+ if latency_ms is not None:
31
+ data["latency_ms"] = latency_ms
32
+
33
+ try:
34
+ print("Logging chat:", data)
35
+ result = chat_logs.insert_one(data)
36
+ except Exception as e:
37
+ print("Failed to log chat interaction:", e)
38
+ # %%
app/chatbot/prod_rag.py ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from typing import List, TypedDict
3
+
4
+ from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
5
+ from langchain_core.tools import tool
6
+ from langchain_core.runnables import RunnableLambda
7
+
8
+ from langchain_qdrant import QdrantVectorStore
9
+ from langchain_huggingface import HuggingFaceEmbeddings
10
+ from langgraph.graph import StateGraph, END
11
+ from langchain_mistralai import ChatMistralAI
12
+
13
+ import time
14
+ import os
15
+ from dotenv import load_dotenv
16
+
17
+ from app.config import qdrant_client
18
+
19
+ from app.chatbot.mongodb import log_chat
20
+
21
+ #from app.mongodb import log_chat
22
+
23
+ load_dotenv()
24
+ os.environ["TOKENIZERS_PARALLELISM"] = "false"
25
+
26
+
27
+ session_histories: dict[str, list] = {}
28
+
29
+ LLM_MODEL = "mistral-medium-latest"
30
+ OPENROUTER_API_KEY = os.getenv('OPENROUTER_API_KEY')
31
+ COLLECTION_NAME = "chatbot_context"
32
+ EMBEDDING_MODEL = "intfloat/e5-base-v2"
33
+ QDRANT_URL = os.getenv('QDRANT_URL')
34
+ QDRANT_API_KEY = os.getenv('QDRANT_API_KEY')
35
+ SUPABASE_URL = os.getenv('SUPABASE_URL')
36
+ SUPABASE_KEY = os.getenv('SUPABASE_KEY')
37
+ MISTRAL_API_KEY = os.getenv('MISTRAL_API_KEY')
38
+
39
+ FAQ_COLLECTION = "auro_faqs"
40
+ BLOGS_COLLECTION = "auro_blogs"
41
+ TECHNOLOGY_COLLECTION = "auro_technology"
42
+ REVOLUTION_COLLECTION = "auro_revolution"
43
+ SUPPORT_COLLECTION = "auro_support"
44
+ PRODUCT_COLLECTION = "auro_product"
45
+
46
+
47
+
48
+ llm = ChatMistralAI(
49
+ model_name=LLM_MODEL,
50
+ api_key=MISTRAL_API_KEY,
51
+ )
52
+
53
+ embeddings = HuggingFaceEmbeddings(model_name=EMBEDDING_MODEL)
54
+
55
+
56
+ class GraphState(TypedDict):
57
+ """
58
+ Represents the state of a chat session, including input, output, history, memory,
59
+ response, tool results, and user role for LangGraph
60
+ """
61
+ input: str
62
+ history: List[BaseMessage] #list of past messages
63
+ response: str
64
+ tool_results: dict
65
+ prompt: str
66
+ retrieve_tools: List[dict]
67
+ prompt_template: str
68
+
69
+ from pydantic import BaseModel
70
+
71
+ class ToolInput(BaseModel):
72
+ prompt: str
73
+ iteration: int = 1
74
+
75
+ def retrieve_docs(query: str, retriever: dict):
76
+ """
77
+ Retrieve documents from Qdrant for a single retriever configuration.
78
+
79
+ Args:
80
+ query (str): The user query.
81
+ retriever (dict): Retriever config with keys:
82
+ - 'collection': Qdrant collection name
83
+ - 'top_k': number of results to return (default 5)
84
+ - 'filter_score': min similarity score to keep results (default 0.1)
85
+
86
+ Returns:
87
+ List[dict]: List of dicts with 'content' and 'score'.
88
+ """
89
+ top_k = retriever.get('top_k', 5)
90
+ filter_score = retriever.get('filter_score', 50)
91
+ collection = retriever.get('collection')
92
+
93
+ # Qdrant store
94
+ rev_store = QdrantVectorStore(
95
+ client=qdrant_client, # make sure this is initialized globally
96
+ collection_name=collection,
97
+ embedding=embeddings,
98
+ )
99
+ print(f"Retrieving from collection: {collection} with top_k={top_k} and filter_score={filter_score}")
100
+ # Similarity search
101
+ docs = rev_store.similarity_search_with_score(query, k=top_k)
102
+
103
+ # Filter results by score
104
+ return [
105
+ {"content": doc.page_content, "score": score}
106
+ for doc, score in docs
107
+ if score > filter_score
108
+ ]
109
+
110
+ def build_prompt(template: str):
111
+ global_template = """
112
+ Conversation History (for context only, not authority):
113
+ {history}
114
+
115
+ Contextual Knowledge (only approved source of truth):
116
+ {agent_scratchpad}
117
+
118
+ User Question:
119
+ {input}
120
+
121
+ Response:
122
+ """
123
+ final_template = f"{template}\n{global_template}"
124
+ return final_template
125
+
126
+
127
+ def retrieve_node(state: GraphState) -> GraphState:
128
+ """
129
+ Graph node to retrieve documents for all retrievers in the state.
130
+
131
+ Args:
132
+ state (GraphState): Current chat state including input and retrievers.
133
+
134
+ Returns:
135
+ GraphState: Updated state with 'tool_results' filled.
136
+ """
137
+ query = state['input']
138
+ tool_results = {}
139
+
140
+ for retriever_cfg in state.get('retrieve_tools', []):
141
+ name = retriever_cfg.get('name', 'default')
142
+ try:
143
+ docs = retrieve_docs(query, retriever_cfg)
144
+ tool_results[name] = docs
145
+ print(f"Retriever '{name}' returned {len(docs)} result(s)")
146
+ except Exception as e:
147
+ tool_results[name] = [{"content": f"Retriever failed: {str(e)}", "score": 0}]
148
+ print(f"Retriever '{name}' failed: {e}")
149
+
150
+ state['tool_results'] = tool_results
151
+ return state
152
+
153
+ #Answer Question
154
+ def generate_answer(state: GraphState):
155
+ """
156
+ This function generates an answer to the query using the llm and the context provided.
157
+ """
158
+ query = state['input']
159
+
160
+ history = state.get('history', [])
161
+ history_text = "\n".join(
162
+ f"Human: {m.content}" if isinstance(m, HumanMessage) else f"AI: {m.content}"
163
+ for m in history
164
+ )
165
+
166
+
167
+ intermediate_steps = state.get('tool_results', {})
168
+
169
+ steps_string = "\n".join(
170
+ f"{tool_name} Results:\n" +
171
+ "\n".join(
172
+ f"- Product: {entry.get('metadata', {}).get('product_name', 'N/A')}\n {entry['content']}"
173
+ for entry in results
174
+ )
175
+ for tool_name, results in intermediate_steps.items() if results
176
+ )
177
+ prompt_template = build_prompt(state['prompt_template'])
178
+ prompt_input = prompt_template.format(
179
+ input=query,
180
+ agent_scratchpad=steps_string,
181
+ history=history_text
182
+ )
183
+
184
+ print(prompt_input)
185
+ state['prompt'] = prompt_input
186
+
187
+ llm_response = llm.invoke(prompt_input)
188
+ state['response'] = llm_response.content if hasattr(llm_response, 'content') else str(llm_response)
189
+ state['history'].append(HumanMessage(content=query))
190
+ state['history'].append(AIMessage(content=state['response']))
191
+
192
+ return state
193
+
194
+
195
+ graph = StateGraph(GraphState)
196
+
197
+ #Add nodes to the graph
198
+ graph.add_node("route_tool", RunnableLambda(retrieve_node))
199
+ graph.add_node("generate_response", RunnableLambda(generate_answer))
200
+
201
+ # Define the flow of the graph
202
+ graph.set_entry_point("route_tool")
203
+ graph.add_edge("route_tool", "generate_response")
204
+ graph.add_edge("generate_response", END)
205
+
206
+ app = graph.compile()
207
+
208
+ async def get_response(query, session_id, name, email, rag_config, config) -> dict:
209
+ start_time = time.time()
210
+ session_id = config['configurable']['thread_id']
211
+ history = session_histories.get(session_id, [])
212
+ input_data = {
213
+ "input": query,
214
+ "history": history,
215
+ "retrieve_tools": rag_config.get('retrievers', []),
216
+ "prompt_template": rag_config.get('prompt_template', ""),
217
+ }
218
+ metadata={}
219
+ latency_ms = None
220
+ try:
221
+ result = await app.ainvoke(input_data, config=config)
222
+ latency_ms = int((time.time() - start_time) * 1000)
223
+ session_histories[session_id] = result.get("history", [])
224
+
225
+ metadata = {
226
+ "retrieved_docs": result.get("tool_results", {}),
227
+ "model": LLM_MODEL,
228
+ "embedding_model": EMBEDDING_MODEL,
229
+ "prompt": result.get("prompt", "")
230
+ }
231
+ filtered_result = result['response'].replace("transdermal", "topical")
232
+ result['response'] = filtered_result
233
+ except Exception as e:
234
+ result = {}
235
+ result['response'] = f"Error in processing chat: {e}"
236
+
237
+ print(f"Response: {result['response']}")
238
+
239
+ log_chat(
240
+ session_id=session_id,
241
+ company_id=rag_config.get('company_id'),
242
+ chatbot_id=rag_config.get('chatbot_id'),
243
+ name=name,
244
+ email=email,
245
+ query=query,
246
+ answer=result.get("response", ""),
247
+ latency_ms= latency_ms,
248
+ metadata=metadata
249
+ )
250
+
251
+ return result
app/chatbot/prod_route.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, HTTPException
2
+ from pydantic import BaseModel
3
+ from app.chatbot.demo_rag import get_response
4
+ from app.config import demo_chatbot_configs
5
+
6
+ router = APIRouter()
7
+ chatbot_sessions = {} # chatbot_id -> loaded config/session
8
+
9
+ class ChatInput(BaseModel):
10
+ question: str
11
+ session_id: str
12
+ name: str
13
+ email: str
14
+
15
+
16
+ @router.post("/prod/{chatbot_id}")
17
+ async def prod_chat(chatbot_id: str, input: ChatInput):
18
+ # Lazy-load chatbot config
19
+ print(f"got question: {input.question} for chatbot_id: {chatbot_id} and session_id: {input.session_id}")
20
+ if chatbot_id not in chatbot_sessions:
21
+ rag_config = demo_chatbot_configs.find_one({"chatbot_id": chatbot_id})
22
+ if not rag_config:
23
+ raise HTTPException(status_code=404, detail="Chatbot not found")
24
+ chatbot_sessions[chatbot_id] = rag_config
25
+
26
+ rag_config = chatbot_sessions[chatbot_id]
27
+ print(rag_config)
28
+
29
+ config = {
30
+ 'configurable': {
31
+ 'thread_id': input.session_id
32
+ }
33
+ }
34
+
35
+ response = await get_response(
36
+ query=input.question,
37
+ session_id=input.session_id,
38
+ name=input.name,
39
+ email=input.email,
40
+ rag_config=rag_config,
41
+ config=config
42
+ )
43
+ return {"answer": response['response']}
app/config.py CHANGED
@@ -31,6 +31,9 @@ try:
31
  demo_database = client["Demo"]
32
  demo_form_submissions = demo_database["demo_form_submissions"]
33
  demo_chatbot_configs = demo_database["demo_chatbot_config"]
 
 
 
34
  print("Connected to MongoDB collection successfully!")
35
  except Exception as e:
36
  print(e)
 
31
  demo_database = client["Demo"]
32
  demo_form_submissions = demo_database["demo_form_submissions"]
33
  demo_chatbot_configs = demo_database["demo_chatbot_config"]
34
+
35
+ admin_database = client["AdminLogs"]
36
+ chat_logs = admin_database["ChatLogs"]
37
  print("Connected to MongoDB collection successfully!")
38
  except Exception as e:
39
  print(e)
app/ingestion/demo_form_fetch_store.py CHANGED
@@ -14,6 +14,8 @@ def store_demo_chatbot(ingest_data: ChatbotIngest):
14
 
15
  # Generate a unique chatbot_id
16
  chatbot_id = str(uuid.uuid4())
 
 
17
  data_dict['chatbot_id'] = chatbot_id
18
 
19
  # Insert into MongoDB
 
14
 
15
  # Generate a unique chatbot_id
16
  chatbot_id = str(uuid.uuid4())
17
+ company_id = str(uuid.uuid4())
18
+ data_dict['company_id'] = company_id
19
  data_dict['chatbot_id'] = chatbot_id
20
 
21
  # Insert into MongoDB
app/ingestion/rag_setup.py CHANGED
@@ -157,7 +157,7 @@ def build_demo_prompt(ingest: ChatbotIngest) -> str:
157
  allowed_topics = ", ".join(ingest.chatbot_purpose) or "general questions"
158
  banned_topics = ingest.sensitive_topics or "sensitive topics"
159
  response_style = ", ".join(ingest.tone_style) if ingest.tone_style else "clear and concise"
160
- fallback_message = f"Sorry, I cannot answer that question. Please contact {ingest.contact_email} or call {ingest.contact_phone}."
161
  additional_content = "\n".join(ingest.additional_content) if ingest.additional_content else ""
162
 
163
  template = f"""
@@ -170,23 +170,24 @@ STRICT RULES:
170
  3. Only reference topics explicitly allowed: {allowed_topics}.
171
  4. Do NOT discuss banned topics: {banned_topics}.
172
  5. Keep responses {response_style}.
173
- 6. Additional context to consider: {additional_content}
174
  """
175
  return template
176
 
177
- def store_demo_rag_config(chatbot_id, ingest: ChatbotIngest) -> None:
178
  """
179
  Stores the RAG configuration prompt for the demo chatbot in MongoDB.
180
  """
181
  demo_rag_dict = {
182
  "chatbot_id": chatbot_id,
 
183
  "company_name": ingest.company_name,
184
  "prompt_template": build_demo_prompt(ingest),
185
  "retrievers": [
186
  {
187
  "name": "all",
188
  "collection": f"chatbot_{chatbot_id}",
189
- "top_k": 25
 
190
  }
191
  ]
192
  }
 
157
  allowed_topics = ", ".join(ingest.chatbot_purpose) or "general questions"
158
  banned_topics = ingest.sensitive_topics or "sensitive topics"
159
  response_style = ", ".join(ingest.tone_style) if ingest.tone_style else "clear and concise"
160
+ fallback_message = f"Sorry, I cannot answer that question. Please call or email for further assistance. Information can be found on the website"
161
  additional_content = "\n".join(ingest.additional_content) if ingest.additional_content else ""
162
 
163
  template = f"""
 
170
  3. Only reference topics explicitly allowed: {allowed_topics}.
171
  4. Do NOT discuss banned topics: {banned_topics}.
172
  5. Keep responses {response_style}.
 
173
  """
174
  return template
175
 
176
+ def store_demo_rag_config(chatbot_id, company_id, ingest: ChatbotIngest) -> None:
177
  """
178
  Stores the RAG configuration prompt for the demo chatbot in MongoDB.
179
  """
180
  demo_rag_dict = {
181
  "chatbot_id": chatbot_id,
182
+ "company_id": company_id,
183
  "company_name": ingest.company_name,
184
  "prompt_template": build_demo_prompt(ingest),
185
  "retrievers": [
186
  {
187
  "name": "all",
188
  "collection": f"chatbot_{chatbot_id}",
189
+ "top_k": 25,
190
+ "filter_score": 50
191
  }
192
  ]
193
  }
app/ingestion/workers.py CHANGED
@@ -19,4 +19,4 @@ def build_rag_for_chatbot(chatbot_id: str) -> None:
19
  chatbot_id=chatbot_id,
20
  pages=pages,
21
  )
22
- store_demo_rag_config(chatbot_id=chatbot_id, ingest=ChatbotIngest(**config))
 
19
  chatbot_id=chatbot_id,
20
  pages=pages,
21
  )
22
+ store_demo_rag_config(chatbot_id=chatbot_id, company_id=config['company_id'], ingest=ChatbotIngest(**config))
app/main.py CHANGED
@@ -1,4 +1,5 @@
1
  from fastapi import FastAPI
 
2
  from app.ingestion.routes import router as ingestion_router
3
  from app.chatbot.demo_routes import router as demo_router
4
 
@@ -8,5 +9,17 @@ app = FastAPI(
8
  version="1.0.0"
9
  )
10
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  app.include_router(ingestion_router, prefix="/ingestion", tags=["ingestion"])
12
- app.include_router(demo_router, prefix="/demochatbot", tags=["demochatbot"])
 
1
  from fastapi import FastAPI
2
+ from fastapi.middleware.cors import CORSMiddleware
3
  from app.ingestion.routes import router as ingestion_router
4
  from app.chatbot.demo_routes import router as demo_router
5
 
 
9
  version="1.0.0"
10
  )
11
 
12
+ @app.get("/")
13
+ def root():
14
+ return {"message": "Chatbot Platform is Live"}
15
+
16
+ # CORS setup (so React can call API)
17
+ app.add_middleware(
18
+ CORSMiddleware,
19
+ allow_origins=["*"],
20
+ allow_methods=["*"],
21
+ allow_headers=["*"],
22
+ )
23
+
24
  app.include_router(ingestion_router, prefix="/ingestion", tags=["ingestion"])
25
+ app.include_router(demo_router, prefix="/chatbot", tags=["demochatbot"])
requirements.txt CHANGED
Binary files a/requirements.txt and b/requirements.txt differ