Viraj2307 commited on
Commit
3618a4d
·
verified ·
1 Parent(s): 105ad85

Initial Commit

Browse files
Files changed (12) hide show
  1. FineTuning.ipynb +0 -0
  2. __init__.py +2 -0
  3. app.py +182 -0
  4. config.py +23 -0
  5. context.py +88 -0
  6. data.xlsx +0 -0
  7. data_section.py +20 -0
  8. fine_tune_dataset.xlsx +0 -0
  9. llm_agent.py +190 -0
  10. page.py +191 -0
  11. requirements.txt +16 -0
  12. utils.py +6 -0
FineTuning.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from utils import client, llm
2
+ from data_section import data_bifercation
app.py ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from math import ceil
2
+ from config import settings
3
+ from mongoengine import connect
4
+ from llm_agent import ReactAgent
5
+ from fastapi import FastAPI, Response
6
+ from chat import (
7
+ ChatSession,
8
+ FeedbackRequest,
9
+ LikeDislikeRequest,
10
+ UpdateSessionNameRequest,
11
+ Message,
12
+ ChatSessionSchema,
13
+ Role,
14
+ )
15
+
16
+
17
+ app = FastAPI()
18
+ react_agent = ReactAgent()
19
+
20
+
21
+ @app.on_event("startup")
22
+ async def load_scheduler_and_DB():
23
+ connect(settings.DB_NAME, host=settings.DB_URI, alias="default")
24
+ print("Database connection established!!")
25
+
26
+
27
+ @app.post("/query", tags=["Chat-Model"])
28
+ def handle_query(chat_schema: ChatSessionSchema):
29
+ if chat_schema.session_id:
30
+ chat_session = ChatSession.objects(id=chat_schema.session_id)
31
+ chat_session = chat_session.first()
32
+
33
+ chat_history = chat_session.get_last_messages()
34
+ response = react_agent.handle_query(
35
+ session_id=chat_schema.session_id,
36
+ query=chat_schema.query,
37
+ chat_history=chat_history,
38
+ )
39
+
40
+ chat_session.add_message_with_metadata(
41
+ role=Role.USER.value, content=chat_schema.query
42
+ )
43
+ chat_session.add_message_with_metadata(role=Role.MODEL.value, content=response)
44
+
45
+ return {"response": response}
46
+
47
+
48
+ @app.post(
49
+ "/temp_session",
50
+ tags=["Chat-Session"],
51
+ )
52
+ def temp_session() -> dict:
53
+ session = ChatSession()
54
+ session.save()
55
+ return {"message": "Session created", "session_id": session.get_id()}
56
+
57
+
58
+ @app.post("/feedback", tags=["Chat-Features"])
59
+ def feedback(feedback_request: FeedbackRequest):
60
+ chat_session = ChatSession.objects.get(id=feedback_request.session_id)
61
+ if chat_session:
62
+ chat_session.feedback_message(
63
+ feedback_request.message_id, feedback_request.feedback
64
+ )
65
+ return {"message": "Feedback saved successfully"}
66
+ else:
67
+ return Response(
68
+ content="Chat session not found", status_code=404, media_type="text/plain"
69
+ )
70
+
71
+
72
+ @app.post("/like", tags=["Chat-Features"])
73
+ def like_message(like_request: LikeDislikeRequest):
74
+ chat_session = ChatSession.objects.get(id=like_request.session_id)
75
+ if chat_session:
76
+ chat_session.like_message(like_request.message_id)
77
+ return {"message": "Message liked successfully"}
78
+ else:
79
+ return Response(
80
+ content="Chat session not found", status_code=404, media_type="text/plain"
81
+ )
82
+
83
+
84
+ @app.post("/dislike", tags=["Chat-Features"])
85
+ def dislike_message(dislike_request: LikeDislikeRequest):
86
+ chat_session = ChatSession.objects.get(id=dislike_request.session_id)
87
+ if chat_session:
88
+ chat_session.dislike_message(dislike_request.message_id)
89
+ return {"message": "Message disliked successfully"}
90
+ else:
91
+ return Response(
92
+ content="Chat session not found", status_code=404, media_type="text/plain"
93
+ )
94
+
95
+
96
+ @app.post(
97
+ "/session_name_change",
98
+ tags=["Chat-Session"],
99
+ )
100
+ def update_session_name(request: UpdateSessionNameRequest):
101
+ try:
102
+ chat_session = ChatSession.objects(id=request.session_id).first()
103
+ if not chat_session:
104
+ return Response(
105
+ content="Session not found", status_code=404, media_type="text/plain"
106
+ )
107
+
108
+ chat_session.session_name = request.new_session_name
109
+ chat_session.save()
110
+
111
+ return {"message": "Session name updated successfully"}
112
+ except Exception:
113
+ return Response(
114
+ content="Session not found", status_code=404, media_type="text/plain"
115
+ )
116
+
117
+
118
+ @app.get(
119
+ "/chat_session/<session_id>",
120
+ tags=["Chat-Session"],
121
+ )
122
+ def get_chat_session(
123
+ session_id: str,
124
+ page: int = 1,
125
+ size: int = 20,
126
+ ):
127
+ try:
128
+ chat_session = ChatSession.objects.get(id=session_id)
129
+ except BaseException:
130
+ return Response(
131
+ content="Chat session not found", status_code=404, media_type="text/plain"
132
+ )
133
+ skip = (page - 1) * size
134
+ message_ids = [
135
+ message.id for message in chat_session.messages[skip : skip + size] # noqa
136
+ ]
137
+ messages = Message.objects(id__in=message_ids)
138
+ serialized_messages = [
139
+ {
140
+ **message.to_mongo().to_dict(),
141
+ "_id": str(message.id),
142
+ "chat_session": (
143
+ str(message.chat_session.id) if message.chat_session else None
144
+ ),
145
+ }
146
+ for message in messages
147
+ ]
148
+
149
+ total_count = ChatSession.objects.get(id=session_id).count()
150
+ total_pages = ceil(total_count / size)
151
+ has_next_page = page < total_pages
152
+ next_page = page + 1 if has_next_page else None
153
+
154
+ return {
155
+ "total_count": total_count,
156
+ "total_pages": total_pages,
157
+ "has_next_page": has_next_page,
158
+ "next_page": next_page,
159
+ "messages": serialized_messages,
160
+ }
161
+
162
+
163
+ @app.delete(
164
+ "/delete_session",
165
+ tags=["Chat-Session"],
166
+ )
167
+ def delete_session(session_id: str):
168
+ try:
169
+ chat_session = ChatSession.objects(id=session_id).first()
170
+ if not chat_session:
171
+ return Response(
172
+ content="Chat session not found",
173
+ status_code=404,
174
+ media_type="text/plain",
175
+ )
176
+
177
+ chat_session.delete()
178
+ return {"message": "Session deleted successfully"}
179
+ except Exception:
180
+ raise Response(
181
+ content="Chat session not found", status_code=404, media_type="text/plain"
182
+ )
config.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic_settings import BaseSettings, SettingsConfigDict
2
+ import os
3
+ from dotenv import load_dotenv
4
+
5
+ load_dotenv()
6
+
7
+
8
+ class Settings(BaseSettings):
9
+ NGROK_URL: str = os.environ.get("NGROK_URL", "FAKE")
10
+ MODEL_NAME: str = os.environ.get("MODEL_NAME", "FAKE")
11
+ DB_URI: str = os.environ.get("DB_URI", "FAKE")
12
+ DB_NAME: str = os.environ.get("DB_NAME", "FAKE")
13
+ BASE_URL: str = os.environ.get("BASE_URL", "FAKE")
14
+ ORIGIN: str = os.environ.get("ORIGIN", "FAKE")
15
+ COOKIE: str = os.environ.get("COOKIE", "FAKE")
16
+ STORE_ID: str = os.environ.get("STORE_ID", "FAKE")
17
+ BRAND_ID: str = os.environ.get("BRAND_ID", "FAKE")
18
+ PHONE_NUMBER_ID: str = os.environ.get("PHONE_NUMBER_ID", "FAKE")
19
+ BEARER_TOKEN: str = os.environ.get("BEARER_TOKEN", "FAKE")
20
+ model_config = SettingsConfigDict(env_file=".env")
21
+
22
+
23
+ settings = Settings()
context.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime
2
+ from utils import client
3
+ from config import settings
4
+
5
+
6
+ def ollama_context_query(chat_history, user_query):
7
+ print(user_query)
8
+ prompt = f"""You are a Contextualisation engine for a Restaurant Order Bot. Your role is to rewrite the user's natural language query so that it is optimized for the relevant tool processing without changing its original intent. Always ensure that the context from previous interactions is utilized, but avoid generating long or unnecessary context queries. Keep the response minimal and concise.
9
+
10
+ IMPORTANT:
11
+ - **NEVER** alter the meaning or context of the user's query.
12
+ - **Minimize the query** whenever possible, focusing only on the essential parts required for tool processing.
13
+ - **Keep context queries as short as possible** and never generate long or redundant queries.
14
+
15
+ You have the following tools available:
16
+ - 'MenuTool': For menu-related queries like available dishes, specials, or recommendations.
17
+ - 'CartTool': For managing cart operations such as adding, removing, or viewing items.
18
+ - 'OrderTool': For placing orders or checking out.
19
+
20
+ GUIDELINES:
21
+ 1. **Menu-Related Queries**: When the user asks about menu items (e.g., 'What can I have for lunch?','What are the katsu items?', 'Can I see the breakfast menu?', 'What’s in the combo meal?', 'What’s the price for the burger?'), route the query to the MenuTool. Ensure the suggestions are current and relevant to the user's preferences.
22
+ 2. **Cart Operations**: For queries about cart management (e.g., 'add to cart', 'remove from cart', or 'view cart'), route them to the CartTool. Reference previous cart interactions when necessary.
23
+ - Example: "add 2 quantity of Mango Kani Salad" → `CartTool`: "add 2 quantity of Mango Kani Salad".
24
+ - Example: "I would like Vegetable Spring Rolls" → `CartTool`: "add 1 quantity of Vegetable Spring Rolls".
25
+ - Example: ""I’ll take a burger." → `CartTool`: "add 1 quantity of burger".
26
+ - Example: ""Could you put five servings of lemon chicken in my cart?" → `CartTool`: "add 5 quantity of lemon chicken".
27
+ 3. **Order and Checkout Queries**: For queries about order placement or checkout, route them to the OrderTool. Break down complex queries where multiple operations are involved.
28
+ - Example: "add 2 quantity of Mango Kani Salad and place order" should result in:
29
+ - `CartTool`: "add 2 quantity of Mango Kani Salad".
30
+ - `OrderTool`: "place order".
31
+ 4. **Multiple Tools in One Query**: When a query involves multiple operations, split it into separate tool calls for clarity.
32
+ - Example: "remove the Mango Kani Salad from the cart and checkout" →
33
+ - `CartTool`: "remove Mango Kani Salad".
34
+ - `OrderTool`: "checkout".
35
+ 5. **If a query involves tool utilization, return the tool name only (e.g., 'MenuTool', 'CartTool', 'OrderTool').**
36
+ 6. **Do not return long contextual information**; focus on minimal and clear context queries that directly relate to the tool's operation.
37
+ 7. If the quantity is not defined while calling the cart tool, then rearrange the sentence to include the quantity as one.
38
+ 8. If no tool utilization is required, respond naturally and suggest more specific questions about the restaurant's offerings.
39
+ 9. Convert any date information to the format YYYY-MM-DD.
40
+ 10. If asked 'Who are you?', respond with 'I am SAHL order bot.'
41
+ 11. Always use previous chat history between the user and assistant for continuity, but DO NOT include chat history in the response.
42
+ 12. If the cart tool is utilized and the user's response doesn't contain any item name, then use the previous history to include the item name.
43
+
44
+ Use the above guidelines to generate context, ensuring you maintain the meaning and intent of the user’s query without introducing unnecessary complexity or length.
45
+ NOTE: The current date and time is: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n
46
+ PREVIOUS CHAT HISTORY: {chat_history} Use the chat history to inform your response. Reference relevant previous user inputs or interactions to maintain context, continuity, and coherence. When providing a response, ensure it builds on past conversations and avoids unnecessary repetition, while addressing any new information or questions introduced by the user.\n
47
+ Use the above chat history to generate the context, but do not include it in the response."""
48
+
49
+ system_msg = {"role": "system", "content": prompt}
50
+ user_msg = {"role": "user", "content": user_query}
51
+ response = client.chat(
52
+ model=settings.MODEL_NAME,
53
+ messages=[system_msg, user_msg],
54
+ )
55
+ context_query = response["message"]["content"]
56
+ print("CONTEXT .... ")
57
+ print(context_query)
58
+ if any(tool in context_query for tool in ["MenuTool", "CartTool", "OrderTool"]):
59
+ return context_query, True
60
+
61
+ print("check this contexyt query in your terminal ::::::::::::: " * 5, context_query)
62
+ return context_query, False
63
+
64
+
65
+ def summarised_output(messages, chat_history, context_query, user_query):
66
+ prompt = (
67
+ "You are a summarization engine. Your role is to merge multiple tool responses related to Restaurant Order into a simplified and concise response for the user.\n"
68
+ "IMPORTANT:\n"
69
+ "- Only use the information provided by the tools and the user's query; do not add any extra information from your end.\n"
70
+ "- Merge the responses into a simplified format, making it easy for the customer to understand.\n"
71
+ "- Always show numbers clearly if provided in the tool response (e.g., '2 items added to cart', 'Order total is 150 Dirhams').\n"
72
+ "- Avoid adding unnecessary context or extra phrases. Just focus on providing the relevant information in a clear manner.\n"
73
+ "- If the response contains lists of items or details, format them neatly for readability.\n"
74
+ "- For long answers, if all the information is relevant, provide it in full, but ensure it's simplified and concise.\n"
75
+ "- Ignore unnecessary or irrelevant information from the tool responses to ensure that only what is important for the customer is shown.\n"
76
+ "- If the orderId is present in the tool's response, then always include this orderId in the summarization.\n\n"
77
+ f"PREVIOUS CHAT HISTORY: {chat_history}\n"
78
+ f"CURRENT TOOL RESPONSES: {messages}\n"
79
+ f"CONTEXTUALIZATION QUERY: {context_query}\n"
80
+ )
81
+ system_msg = {"role": "system", "content": prompt}
82
+ user_msg = {"role": "user", "content": user_query}
83
+ response = client.chat(
84
+ model=settings.MODEL_NAME,
85
+ messages=[system_msg, user_msg],
86
+ )
87
+ summarized_response = response["message"]["content"]
88
+ return summarized_response
data.xlsx ADDED
Binary file (5.85 kB). View file
 
data_section.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from tools.menu_tools_utils import get_data_store_id
2
+ from config import settings
3
+
4
+ def data_bifercation(store_id, brand_id):
5
+ data = get_data_store_id(settings.STORE_ID, settings.BRAND_ID).get("data")
6
+ category = {}
7
+ items = {}
8
+ main_data = []
9
+ for cate in data:
10
+ print("----"*30)
11
+ for item in cate.get("itemsData"):
12
+ inner_data = []
13
+ inner_data.append(cate.get("name"))
14
+ inner_data.append(item.get("title"))
15
+ inner_data.append(item.get("price"))
16
+ items[item.get("title")] = item.get("_id")
17
+ main_data.append(inner_data)
18
+ category[cate.get("name").lower().strip()] = cate.get("_id")
19
+ print("----"*30)
20
+ return main_data, category, items
fine_tune_dataset.xlsx ADDED
Binary file (26.2 kB). View file
 
llm_agent.py ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from tools import MenuTool, CartTool, OrderTool, greetings_function
2
+ from data_section import data_bifercation
3
+ from tools.prompts import tool_prompt_function
4
+ from config import settings
5
+ from utils import client
6
+ from context import ollama_context_query, summarised_output
7
+ import pandas as pd
8
+
9
+
10
+ class ReactAgent:
11
+ def __init__(self):
12
+ self.store_id = "66dff7a04b17303d454d4bbc"
13
+ self.brand_id = "66cec85093c5b0896c9125c5"
14
+ columns = ["category", "item", "price"]
15
+ main_data, category, items = data_bifercation(self.store_id, self.brand_id)
16
+
17
+ self.items = items
18
+ self.category = category
19
+
20
+ df = pd.DataFrame(main_data)
21
+ df.columns = columns
22
+ df["item"] = df["item"].str.lower()
23
+ df["category"] = df["category"].str.lower()
24
+
25
+ self.df = df
26
+ self.menu_tool = MenuTool(df)
27
+ self.cart_tool = CartTool(df)
28
+ self.order_tool = OrderTool(df)
29
+ self.llm_client = client
30
+
31
+ def handle_query(self, session_id, query, chat_history):
32
+
33
+ prompt = tool_prompt_function(current_query=query, session_id=session_id)
34
+
35
+ context_query, greet_bool = ollama_context_query(
36
+ chat_history=chat_history, user_query=query
37
+ )
38
+
39
+ if not greet_bool:
40
+ return greetings_function(query)
41
+
42
+ if context_query in ["MenuTool", "CartTool", "OrderTool"]:
43
+ user_message_content = query
44
+ else:
45
+ user_message_content = context_query
46
+
47
+ messages = [
48
+ {"role": "system", "content": prompt},
49
+ {"role": "user", "content": user_message_content},
50
+ ]
51
+
52
+ response = self.llm_client.chat(
53
+ model=settings.MODEL_NAME,
54
+ messages=messages,
55
+ tools=[
56
+ {
57
+ "type": "function",
58
+ "function": {
59
+ "name": "menu_tool",
60
+ "description": "Fetch the restaurant menu based on user input",
61
+ "parameters": {
62
+ "type": "object",
63
+ "properties": {
64
+ "query": {
65
+ "type": "string",
66
+ "description": "User's natural language query for the menu",
67
+ }
68
+ },
69
+ "required": ["query"],
70
+ },
71
+ },
72
+ },
73
+ {
74
+ "type": "function",
75
+ "function": {
76
+ "name": "cart_tool",
77
+ "description": "Manage the cart based on user input (add/remove/view)",
78
+ "parameters": {
79
+ "type": "object",
80
+ "properties": {
81
+ "query": {
82
+ "type": "string",
83
+ "description": "User's cart query to add/remove/view items",
84
+ },
85
+ "session_id": {
86
+ "type": "string",
87
+ "description": "current session id",
88
+ },
89
+ },
90
+ "required": ["query", "session_id"],
91
+ },
92
+ },
93
+ },
94
+ {
95
+ "type": "function",
96
+ "function": {
97
+ "name": "order_tool",
98
+ "description": "Handle order and checkout functionality",
99
+ "parameters": {
100
+ "type": "object",
101
+ "properties": {
102
+ "query": {
103
+ "type": "string",
104
+ "description": "User's request to place an order",
105
+ },
106
+ },
107
+ "required": ["query"],
108
+ },
109
+ },
110
+ },
111
+ ],
112
+ )
113
+
114
+ print("----" * 30)
115
+ print(query)
116
+ print("----" * 30)
117
+ print(response)
118
+ print("----" * 30)
119
+
120
+ tool_call = response["message"].get("tool_calls", [])
121
+ tool_calls = [
122
+ tool_call[i].get("function").get("name")
123
+ for i in range(0, len(response["message"].get("tool_calls", [])))
124
+ ]
125
+
126
+ print("----" * 30)
127
+ print(tool_call)
128
+ print("----" * 30)
129
+ print(tool_calls)
130
+ print("----" * 30)
131
+
132
+ tool_responses = []
133
+ for tool_name in tool_calls:
134
+ if tool_name == "menu_tool":
135
+ tool_call_index = next(
136
+ (
137
+ index
138
+ for index, call in enumerate(tool_call)
139
+ if call["function"]["name"] == "menu_tool"
140
+ ),
141
+ None,
142
+ )
143
+ tool_args = tool_call[tool_call_index]["function"]["arguments"]
144
+ response = self.menu_tool.run(tool_args["query"], session_id)
145
+ print("menu tool response :: ", response)
146
+ tool_responses.append(response)
147
+
148
+ elif tool_name == "cart_tool":
149
+ tool_call_index = next(
150
+ (
151
+ index
152
+ for index, call in enumerate(tool_call)
153
+ if call["function"]["name"] == "cart_tool"
154
+ ),
155
+ None,
156
+ )
157
+ tool_args = tool_call[tool_call_index]["function"]["arguments"]
158
+ response = self.cart_tool.run(tool_args["query"], session_id=session_id)
159
+ print("cart tool response :: ", response)
160
+ tool_responses.append(response)
161
+
162
+ elif tool_name == "order_tool":
163
+ tool_call_index = next(
164
+ (
165
+ index
166
+ for index, call in enumerate(tool_call)
167
+ if call["function"]["name"] == "order_tool"
168
+ ),
169
+ None,
170
+ )
171
+ tool_args = tool_call[tool_call_index]["function"]["arguments"]
172
+ print("order tool response :: ", response)
173
+ response = self.order_tool.run(
174
+ df=self.df,
175
+ session_id=session_id,
176
+ category=self.category,
177
+ items=self.items,
178
+ store_id=self.store_id,
179
+ brand_id=self.brand_id,
180
+ )
181
+ tool_responses.append(response)
182
+
183
+ combined_response = summarised_output(
184
+ messages=tool_responses,
185
+ chat_history=chat_history,
186
+ context_query=context_query,
187
+ user_query=query,
188
+ )
189
+
190
+ return combined_response
page.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from chat import ChatSession, ChatSessionSchema, Role
3
+ from app import react_agent
4
+ from mongoengine import connect
5
+ from config import settings
6
+ import requests
7
+ from tools.menu_tools_utils import get_data_store_id
8
+ import speech_recognition as sr
9
+
10
+ st.set_page_config(layout="wide")
11
+
12
+ connect(settings.DB_NAME, host=settings.DB_URI, alias="default")
13
+ print("Database connection established!!")
14
+
15
+
16
+ def speech_to_text():
17
+ r = sr.Recognizer()
18
+ with sr.Microphone() as mic:
19
+ st.write("Listening for your query...")
20
+ r.adjust_for_ambient_noise(mic, duration=1)
21
+ audio = r.listen(mic)
22
+ try:
23
+ text = r.recognize_google(audio)
24
+ st.success(f"Recognized: {text}")
25
+ return text
26
+ except sr.UnknownValueError:
27
+ st.error("Sorry, I could not understand the audio.")
28
+ return ""
29
+ except sr.RequestError as e:
30
+ st.error(
31
+ f"Could not request results from Google Speech Recognition service; {e}"
32
+ )
33
+ return ""
34
+
35
+
36
+ col1, col2 = st.columns([1, 3])
37
+
38
+ with col2:
39
+ st.title("Restaurant Order Bot")
40
+
41
+ if "session_id" not in st.session_state:
42
+ session = ChatSession()
43
+ session.save()
44
+ st.session_state["session_id"] = str(session.id)
45
+
46
+ if "conversation" not in st.session_state:
47
+ st.session_state["conversation"] = []
48
+
49
+ # Input: Either type in or use the speech-to-text button
50
+ user_query = st.text_input("Ask something:")
51
+
52
+ col3, col4, col5 = st.columns([3, 3, 3])
53
+ # New button for speech recognition
54
+ with col3:
55
+ if st.button("🎤 Speak your query"):
56
+ recognized_text = speech_to_text()
57
+ if recognized_text:
58
+ user_query = recognized_text # Set recognized text to the user input
59
+ st.session_state["conversation"].append(
60
+ {"role": "user", "text": user_query}
61
+ )
62
+
63
+ chat_schema = ChatSessionSchema(
64
+ session_id=st.session_state["session_id"], query=user_query
65
+ )
66
+ chat_session = ChatSession.objects(id=chat_schema.session_id).first()
67
+
68
+ chat_history = chat_session.get_last_messages()
69
+ response = react_agent.handle_query(
70
+ session_id=chat_schema.session_id,
71
+ query=chat_schema.query,
72
+ chat_history=chat_history,
73
+ )
74
+
75
+ chat_session.add_message_with_metadata(
76
+ role=Role.USER.value, content=chat_schema.query
77
+ )
78
+ chat_session.add_message_with_metadata(
79
+ role=Role.MODEL.value, content=response
80
+ )
81
+ if response:
82
+ st.session_state["conversation"].append(
83
+ {"role": "bot", "text": response}
84
+ )
85
+ else:
86
+ st.session_state["conversation"].append(
87
+ {
88
+ "role": "bot",
89
+ "text": "Error: Could not get a response from the server.",
90
+ }
91
+ )
92
+
93
+ # Submit button for text input
94
+ with col4:
95
+ if st.button("Submit"):
96
+ if user_query:
97
+ st.session_state["conversation"].append(
98
+ {"role": "user", "text": user_query}
99
+ )
100
+
101
+ chat_schema = ChatSessionSchema(
102
+ session_id=st.session_state["session_id"], query=user_query
103
+ )
104
+ chat_session = ChatSession.objects(id=chat_schema.session_id).first()
105
+
106
+ chat_history = chat_session.get_last_messages()
107
+ response = react_agent.handle_query(
108
+ session_id=chat_schema.session_id,
109
+ query=chat_schema.query,
110
+ chat_history=chat_history,
111
+ )
112
+
113
+ chat_session.add_message_with_metadata(
114
+ role=Role.USER.value, content=chat_schema.query
115
+ )
116
+ chat_session.add_message_with_metadata(
117
+ role=Role.MODEL.value, content=response
118
+ )
119
+ if response:
120
+ st.session_state["conversation"].append(
121
+ {"role": "bot", "text": response}
122
+ )
123
+ else:
124
+ st.session_state["conversation"].append(
125
+ {
126
+ "role": "bot",
127
+ "text": "Error: Could not get a response from the server.",
128
+ }
129
+ )
130
+ with col5:
131
+ if st.button("Clear Chat"):
132
+ st.session_state["conversation"] = []
133
+
134
+ # Display conversation
135
+ user_message_style = """
136
+ background-color: #d1e7dd;
137
+ padding: 10px;
138
+ border-radius: 10px;
139
+ margin-bottom: 10px;
140
+ color: #0f5132;
141
+ text-align: left;
142
+ """
143
+ bot_message_style = """
144
+ background-color: #f8d7da;
145
+ padding: 10px;
146
+ border-radius: 10px;
147
+ margin-bottom: 10px;
148
+ color: #842029;
149
+ text-align: left;
150
+ """
151
+
152
+ for message in st.session_state["conversation"]:
153
+ if message["role"] == "user":
154
+ st.markdown(
155
+ f"<div style='{user_message_style}'><strong>You:</strong> {message['text']}</div>",
156
+ unsafe_allow_html=True,
157
+ )
158
+ else:
159
+ st.markdown(
160
+ f"<div style='{bot_message_style}'><strong>Bot:</strong> {message['text']}</div>",
161
+ unsafe_allow_html=True,
162
+ )
163
+
164
+ with col1:
165
+ st.title("Menu")
166
+ # store_id = "66dff7a04b17303d454d4bbc"
167
+ # brand_id = "66cec85093c5b0896c9125c5"
168
+ response = get_data_store_id(settings.STORE_ID, settings.BRAND_ID)
169
+ menu_data = response
170
+
171
+ blank_image_url = "https://via.placeholder.com/1x1/FFFFFF/FFFFFF"
172
+
173
+ with st.container():
174
+ if menu_data.get("success"):
175
+ for category in menu_data["data"]:
176
+ with st.expander(category["name"], expanded=False):
177
+ for item in category.get("itemsData", []):
178
+ try:
179
+ img_url = item.get("img_url", None)
180
+ if img_url:
181
+ st.image(img_url, width=100)
182
+ else:
183
+ st.image(blank_image_url, width=100)
184
+ except Exception as e:
185
+ st.image(blank_image_url, width=100)
186
+
187
+ st.write(f"**{item['title']}**: {item['price']} Dirham AED")
188
+ st.write(item["description"])
189
+ st.write("---")
190
+ else:
191
+ st.write("Failed to load menu data.")
requirements.txt ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ streamlit
4
+ mongoengine
5
+ requests
6
+ pydantic
7
+ ollama
8
+ pydantic_settings
9
+ openpyxl
10
+ llama-index-experimental
11
+ llama_index
12
+ llama-index-llms-ollama
13
+ spacy
14
+ pycryptodome
15
+ SpeechRecognition
16
+ PyAudio
utils.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ import ollama
2
+ from config import settings
3
+ from llama_index.llms.ollama import Ollama
4
+
5
+ client = ollama.Client(host=settings.NGROK_URL)
6
+ llm = Ollama(model=settings.MODEL_NAME, base_url=settings.NGROK_URL)