Spaces:
Running
Running
Streaming Chatbot
Browse files- chatbot/__pycache__/main.cpython-310.pyc +0 -0
- chatbot/agents/graphs/__pycache__/food_similarity_graph.cpython-310.pyc +0 -0
- chatbot/agents/nodes/app_functions/optimize_select.py +9 -11
- chatbot/agents/nodes/chatbot/classify_topic.py +11 -4
- chatbot/agents/nodes/chatbot/general_chat.py +16 -9
- chatbot/agents/nodes/chatbot/generate_final_response.py +73 -20
- chatbot/agents/nodes/chatbot/policy.py +6 -4
- chatbot/agents/nodes/chatbot/select_food.py +7 -8
- chatbot/agents/nodes/chatbot/select_food_plan.py +6 -6
- chatbot/main.py +1 -3
- chatbot/models/__pycache__/llm_setup.cpython-310.pyc +0 -0
- chatbot/models/llm_setup.py +9 -0
- chatbot/routes/__pycache__/chat_router.cpython-310.pyc +0 -0
- chatbot/routes/__pycache__/food_replace_route.cpython-310.pyc +0 -0
- chatbot/routes/chat_router.py +33 -26
chatbot/__pycache__/main.cpython-310.pyc
CHANGED
|
Binary files a/chatbot/__pycache__/main.cpython-310.pyc and b/chatbot/__pycache__/main.cpython-310.pyc differ
|
|
|
chatbot/agents/graphs/__pycache__/food_similarity_graph.cpython-310.pyc
CHANGED
|
Binary files a/chatbot/agents/graphs/__pycache__/food_similarity_graph.cpython-310.pyc and b/chatbot/agents/graphs/__pycache__/food_similarity_graph.cpython-310.pyc differ
|
|
|
chatbot/agents/nodes/app_functions/optimize_select.py
CHANGED
|
@@ -60,19 +60,17 @@ def calculate_top_options(state: SwapState):
|
|
| 60 |
try:
|
| 61 |
loss, scale = calculate_score(item)
|
| 62 |
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
item_score["optimization_loss"] = round(loss, 4)
|
| 67 |
-
item_score["portion_scale"] = round(scale, 2)
|
| 68 |
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
|
| 75 |
-
|
| 76 |
except Exception as e:
|
| 77 |
logger.warning(f"Lỗi khi xử lý món {item.get('name', 'N/A')}: {e}")
|
| 78 |
continue
|
|
|
|
| 60 |
try:
|
| 61 |
loss, scale = calculate_score(item)
|
| 62 |
|
| 63 |
+
item_score = item.copy()
|
| 64 |
+
item_score["optimization_loss"] = round(loss, 4)
|
| 65 |
+
item_score["portion_scale"] = round(scale, 2)
|
|
|
|
|
|
|
| 66 |
|
| 67 |
+
# Tính chỉ số hiển thị sau khi scale
|
| 68 |
+
item_score["final_kcal"] = int(item["kcal"] * scale)
|
| 69 |
+
item_score["final_protein"] = int(item["protein"] * scale)
|
| 70 |
+
item_score["final_totalfat"] = int(item["totalfat"] * scale)
|
| 71 |
+
item_score["final_carbs"] = int(item["carbs"] * scale)
|
| 72 |
|
| 73 |
+
scored_candidates.append(item_score)
|
| 74 |
except Exception as e:
|
| 75 |
logger.warning(f"Lỗi khi xử lý món {item.get('name', 'N/A')}: {e}")
|
| 76 |
continue
|
chatbot/agents/nodes/chatbot/classify_topic.py
CHANGED
|
@@ -20,8 +20,10 @@ class Topic(BaseModel):
|
|
| 20 |
|
| 21 |
def classify_topic(state: AgentState):
|
| 22 |
print("---CLASSIFY TOPIC ---")
|
| 23 |
-
|
| 24 |
-
|
|
|
|
|
|
|
| 25 |
|
| 26 |
system_msg = """
|
| 27 |
Bạn là bộ điều hướng thông minh.
|
|
@@ -45,15 +47,20 @@ def classify_topic(state: AgentState):
|
|
| 45 |
|
| 46 |
prompt = ChatPromptTemplate.from_messages([
|
| 47 |
("system", system_msg),
|
| 48 |
-
MessagesPlaceholder(variable_name="history"),
|
|
|
|
| 49 |
])
|
| 50 |
|
|
|
|
| 51 |
chain = prompt | classifier_llm
|
| 52 |
|
| 53 |
recent_messages = get_chat_history(state["messages"], max_tokens=500)
|
| 54 |
|
| 55 |
try:
|
| 56 |
-
topic_result = chain.invoke({
|
|
|
|
|
|
|
|
|
|
| 57 |
topic_name = topic_result.name
|
| 58 |
except Exception as e:
|
| 59 |
print(f"⚠️ Lỗi phân loại: {e}")
|
|
|
|
| 20 |
|
| 21 |
def classify_topic(state: AgentState):
|
| 22 |
print("---CLASSIFY TOPIC ---")
|
| 23 |
+
all_messages = state["messages"]
|
| 24 |
+
|
| 25 |
+
question = all_messages[-1].content
|
| 26 |
+
history_messages = all_messages[:-1]
|
| 27 |
|
| 28 |
system_msg = """
|
| 29 |
Bạn là bộ điều hướng thông minh.
|
|
|
|
| 47 |
|
| 48 |
prompt = ChatPromptTemplate.from_messages([
|
| 49 |
("system", system_msg),
|
| 50 |
+
MessagesPlaceholder(variable_name="history"), # Bối cảnh chat
|
| 51 |
+
("human", "{input}") # Câu hỏi MỚI CẦN PHÂN LOẠI
|
| 52 |
])
|
| 53 |
|
| 54 |
+
classifier_llm = llm.with_structured_output(Topic)
|
| 55 |
chain = prompt | classifier_llm
|
| 56 |
|
| 57 |
recent_messages = get_chat_history(state["messages"], max_tokens=500)
|
| 58 |
|
| 59 |
try:
|
| 60 |
+
topic_result = chain.invoke({
|
| 61 |
+
"history": recent_messages, # Lịch sử chat (MessagesPlaceholder)
|
| 62 |
+
"input": question # Câu hỏi mới (HumanMessage)
|
| 63 |
+
})
|
| 64 |
topic_name = topic_result.name
|
| 65 |
except Exception as e:
|
| 66 |
print(f"⚠️ Lỗi phân loại: {e}")
|
chatbot/agents/nodes/chatbot/general_chat.py
CHANGED
|
@@ -1,19 +1,22 @@
|
|
| 1 |
from chatbot.agents.states.state import AgentState
|
| 2 |
from chatbot.models.llm_setup import llm
|
| 3 |
-
from langchain.schema.messages import SystemMessage, HumanMessage
|
| 4 |
from chatbot.utils.chat_history import get_chat_history
|
|
|
|
| 5 |
import logging
|
| 6 |
|
| 7 |
# --- Cấu hình logging ---
|
| 8 |
logging.basicConfig(level=logging.INFO)
|
| 9 |
logger = logging.getLogger(__name__)
|
| 10 |
|
| 11 |
-
def general_chat(state: AgentState):
|
| 12 |
logger.info("---GENERAL CHAT---")
|
| 13 |
|
|
|
|
|
|
|
| 14 |
history = get_chat_history(state["messages"], max_tokens=1000)
|
| 15 |
|
| 16 |
-
|
| 17 |
Bạn là một chuyên gia dinh dưỡng và ẩm thực AI.
|
| 18 |
Hãy trả lời các câu hỏi về:
|
| 19 |
- món ăn, thành phần, dinh dưỡng, calo, protein, chất béo, carb,
|
|
@@ -21,18 +24,22 @@ def general_chat(state: AgentState):
|
|
| 21 |
- sức khỏe, lối sống, chế độ tập luyện liên quan đến ăn uống.
|
| 22 |
- chức năng, điều khoản, chính sách của ứng dụng.
|
| 23 |
|
|
|
|
|
|
|
| 24 |
Quy tắc:
|
| 25 |
- Không trả lời các câu hỏi ngoài chủ đề này (hãy từ chối lịch sự).
|
| 26 |
- Giải thích ngắn gọn, tự nhiên, rõ ràng.
|
| 27 |
- Dựa vào lịch sử trò chuyện để trả lời mạch lạc nếu có câu hỏi nối tiếp.
|
| 28 |
"""
|
| 29 |
|
| 30 |
-
messages_to_send = [SystemMessage(content=system_text)] + history
|
| 31 |
-
|
| 32 |
try:
|
| 33 |
-
response = llm.
|
| 34 |
-
|
|
|
|
|
|
|
|
|
|
| 35 |
return {"messages": [response]}
|
|
|
|
| 36 |
except Exception as e:
|
| 37 |
-
|
| 38 |
-
return {"messages": []}
|
|
|
|
| 1 |
from chatbot.agents.states.state import AgentState
|
| 2 |
from chatbot.models.llm_setup import llm
|
| 3 |
+
from langchain.schema.messages import SystemMessage, HumanMessage, AIMessage
|
| 4 |
from chatbot.utils.chat_history import get_chat_history
|
| 5 |
+
from langchain_core.runnables import RunnableConfig
|
| 6 |
import logging
|
| 7 |
|
| 8 |
# --- Cấu hình logging ---
|
| 9 |
logging.basicConfig(level=logging.INFO)
|
| 10 |
logger = logging.getLogger(__name__)
|
| 11 |
|
| 12 |
+
async def general_chat(state: AgentState, config: RunnableConfig):
|
| 13 |
logger.info("---GENERAL CHAT---")
|
| 14 |
|
| 15 |
+
messages = state["messages"]
|
| 16 |
+
question = messages[-1].content
|
| 17 |
history = get_chat_history(state["messages"], max_tokens=1000)
|
| 18 |
|
| 19 |
+
system_prompt = f"""
|
| 20 |
Bạn là một chuyên gia dinh dưỡng và ẩm thực AI.
|
| 21 |
Hãy trả lời các câu hỏi về:
|
| 22 |
- món ăn, thành phần, dinh dưỡng, calo, protein, chất béo, carb,
|
|
|
|
| 24 |
- sức khỏe, lối sống, chế độ tập luyện liên quan đến ăn uống.
|
| 25 |
- chức năng, điều khoản, chính sách của ứng dụng.
|
| 26 |
|
| 27 |
+
Lịch sử hội thoại: {history}
|
| 28 |
+
|
| 29 |
Quy tắc:
|
| 30 |
- Không trả lời các câu hỏi ngoài chủ đề này (hãy từ chối lịch sự).
|
| 31 |
- Giải thích ngắn gọn, tự nhiên, rõ ràng.
|
| 32 |
- Dựa vào lịch sử trò chuyện để trả lời mạch lạc nếu có câu hỏi nối tiếp.
|
| 33 |
"""
|
| 34 |
|
|
|
|
|
|
|
| 35 |
try:
|
| 36 |
+
response = await llm.ainvoke([
|
| 37 |
+
SystemMessage(content=system_prompt),
|
| 38 |
+
HumanMessage(content=question)
|
| 39 |
+
], config=config)
|
| 40 |
+
|
| 41 |
return {"messages": [response]}
|
| 42 |
+
|
| 43 |
except Exception as e:
|
| 44 |
+
print(f"Lỗi LLM: {e}")
|
| 45 |
+
return {"messages": [AIMessage(content="Xin lỗi, có lỗi xảy ra.")]}
|
chatbot/agents/nodes/chatbot/generate_final_response.py
CHANGED
|
@@ -1,46 +1,99 @@
|
|
| 1 |
from langchain_core.messages import AIMessage
|
| 2 |
from chatbot.agents.states.state import AgentState
|
|
|
|
|
|
|
|
|
|
| 3 |
import logging
|
| 4 |
|
| 5 |
# --- Cấu hình logging ---
|
| 6 |
logging.basicConfig(level=logging.INFO)
|
| 7 |
logger = logging.getLogger(__name__)
|
| 8 |
|
| 9 |
-
def generate_final_response(state: AgentState):
|
| 10 |
-
|
|
|
|
|
|
|
| 11 |
menu = state.get("final_menu", [])
|
| 12 |
-
reason = state.get("reason", "")
|
| 13 |
profile = state.get("user_profile", {})
|
| 14 |
-
|
| 15 |
if not menu:
|
| 16 |
return {"messages": [AIMessage(content="Xin lỗi, tôi chưa thể tạo thực đơn lúc này.")]}
|
| 17 |
|
|
|
|
| 18 |
meal_priority = {"sáng": 1, "trưa": 2, "tối": 3}
|
| 19 |
sorted_menu = sorted(
|
| 20 |
menu,
|
| 21 |
key=lambda x: meal_priority.get(x.get('assigned_meal', '').lower(), 99)
|
| 22 |
)
|
| 23 |
-
|
| 24 |
-
output_text = "📋 **THỰC ĐƠN DINH DƯỠNG CÁ NHÂN HÓA**\n"
|
| 25 |
-
output_text += f"🎯 Mục tiêu: {int(profile.get('targetcalories', 0))} Kcal | {int(profile.get('protein', 0))}g Protein\n\n"
|
| 26 |
-
|
| 27 |
-
current_meal = None
|
| 28 |
|
| 29 |
-
|
| 30 |
-
|
|
|
|
| 31 |
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
scale = dish.get('portion_scale', 1.0)
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
-
|
| 43 |
-
output_text += f"\n💡 **Góc nhìn chuyên gia:**\n{reason}"
|
| 44 |
|
| 45 |
-
|
|
|
|
|
|
|
| 46 |
|
|
|
|
| 1 |
from langchain_core.messages import AIMessage
|
| 2 |
from chatbot.agents.states.state import AgentState
|
| 3 |
+
from chatbot.models.llm_setup import llm
|
| 4 |
+
from langchain_core.messages import SystemMessage, HumanMessage
|
| 5 |
+
from langchain_core.runnables import RunnableConfig
|
| 6 |
import logging
|
| 7 |
|
| 8 |
# --- Cấu hình logging ---
|
| 9 |
logging.basicConfig(level=logging.INFO)
|
| 10 |
logger = logging.getLogger(__name__)
|
| 11 |
|
| 12 |
+
async def generate_final_response(state: AgentState, config: RunnableConfig):
|
| 13 |
+
print("---NODE: FINAL RESPONSE (FULL NUTRITION AI SUMMARY)---")
|
| 14 |
+
|
| 15 |
+
# 1. Lấy dữ liệu từ State
|
| 16 |
menu = state.get("final_menu", [])
|
|
|
|
| 17 |
profile = state.get("user_profile", {})
|
| 18 |
+
|
| 19 |
if not menu:
|
| 20 |
return {"messages": [AIMessage(content="Xin lỗi, tôi chưa thể tạo thực đơn lúc này.")]}
|
| 21 |
|
| 22 |
+
# 2. Chuẩn bị bối cảnh thực đơn chi tiết (Full Macros)
|
| 23 |
meal_priority = {"sáng": 1, "trưa": 2, "tối": 3}
|
| 24 |
sorted_menu = sorted(
|
| 25 |
menu,
|
| 26 |
key=lambda x: meal_priority.get(x.get('assigned_meal', '').lower(), 99)
|
| 27 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
+
# Tính toán tổng dinh dưỡng thực tế của cả thực đơn để gửi cho AI nhận xét
|
| 30 |
+
actual_total = {"kcal": 0, "p": 0, "f": 0, "c": 0}
|
| 31 |
+
menu_context = ""
|
| 32 |
|
| 33 |
+
for dish in sorted_menu:
|
| 34 |
+
# Lấy giá trị dinh dưỡng
|
| 35 |
+
k = dish.get('final_kcal', 0)
|
| 36 |
+
p = dish.get('final_protein', 0)
|
| 37 |
+
f = dish.get('final_totalfat', 0)
|
| 38 |
+
c = dish.get('final_carbs', 0)
|
| 39 |
+
|
| 40 |
+
# Cộng dồn tổng
|
| 41 |
+
actual_total["kcal"] += k
|
| 42 |
+
actual_total["p"] += p
|
| 43 |
+
actual_total["f"] += f
|
| 44 |
+
actual_total["c"] += c
|
| 45 |
|
| 46 |
scale = dish.get('portion_scale', 1.0)
|
| 47 |
+
scale_text = f" (x{scale} suất)" if scale != 1.0 else ""
|
| 48 |
+
|
| 49 |
+
menu_context += (
|
| 50 |
+
f"- Bữa {dish.get('assigned_meal', '').upper()}: {dish['name']}{scale_text}\n"
|
| 51 |
+
f" + Năng lượng: {k} Kcal\n"
|
| 52 |
+
f" + Protein: {p}g | Lipid: {f}g | Carbs: {c}g\n\n"
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
# 3. Thiết lập System Prompt tập trung vào sự cân bằng chất
|
| 56 |
+
target_kcal = int(profile.get('targetcalories', 0))
|
| 57 |
+
target_p = int(profile.get('protein', 0))
|
| 58 |
+
# Ước tính mục tiêu F/C nếu app có lưu (giả định có trong profile)
|
| 59 |
+
target_f = int(profile.get('totalfat', 0))
|
| 60 |
+
target_c = int(profile.get('carbs', 0))
|
| 61 |
+
|
| 62 |
+
system_prompt = f"""
|
| 63 |
+
Bạn là một Chuyên gia Dinh dưỡng AI. Hãy trình bày thực đơn và phân tích sâu về các chỉ số dinh dưỡng.
|
| 64 |
+
|
| 65 |
+
DỮ LIỆU THỰC ĐƠN:
|
| 66 |
+
{menu_context}
|
| 67 |
+
|
| 68 |
+
TỔNG DINH DƯỠNG THỰC TẾ:
|
| 69 |
+
- Tổng: {actual_total['kcal']} Kcal | {actual_total['p']}g P | {actual_total['f']}g F | {actual_total['c']}g C
|
| 70 |
+
|
| 71 |
+
MỤC TIÊU CỦA NGƯỜI DÙNG:
|
| 72 |
+
- Mục tiêu: {target_kcal} Kcal | {target_p}g P | {target_f}g F | {target_c}g C
|
| 73 |
+
|
| 74 |
+
YÊU CẦU TRÌNH BÀY:
|
| 75 |
+
1. Trình bày danh sách món ăn theo từng bữa (Sử dụng Markdown đẹp).
|
| 76 |
+
2. Nhận xét chi tiết về 3 nhóm chất (Macros):
|
| 77 |
+
- Protein: Đủ để xây dựng cơ bắp chưa?
|
| 78 |
+
- Lipid (Chất béo): Có nằm trong ngưỡng lành mạnh không?
|
| 79 |
+
- Carbs (Bột đường): Có cung cấp đủ năng lượng cho hoạt động không?
|
| 80 |
+
3. So sánh tổng thực tế với mục tiêu người dùng (Sai số bao nhiêu %).
|
| 81 |
+
4. Đưa ra lời khuyên về cách phân bổ các chất này trong ngày.
|
| 82 |
+
5. Tuyệt đối KHÔNG bịa đặt con số ngoài dữ liệu đã cho.
|
| 83 |
+
6. Trả lời một cách ngắn gọn không dài dòng.
|
| 84 |
+
"""
|
| 85 |
+
print(f"👉 Prompt: {system_prompt}")
|
| 86 |
|
| 87 |
+
# 4. Gọi LLM Stream
|
| 88 |
+
try:
|
| 89 |
+
response = await llm.ainvoke([
|
| 90 |
+
SystemMessage(content=system_prompt),
|
| 91 |
+
HumanMessage(content="Hãy phân tích thực đơn đầy đủ các chất giúp tôi.")
|
| 92 |
+
], config=config)
|
| 93 |
|
| 94 |
+
return {"messages": [response]}
|
|
|
|
| 95 |
|
| 96 |
+
except Exception as e:
|
| 97 |
+
print(f"Lỗi LLM: {e}")
|
| 98 |
+
return {"messages": [AIMessage(content="Xin lỗi, có lỗi xảy ra.")]}
|
| 99 |
|
chatbot/agents/nodes/chatbot/policy.py
CHANGED
|
@@ -2,13 +2,14 @@ from chatbot.agents.states.state import AgentState
|
|
| 2 |
from langchain_core.messages import AIMessage, SystemMessage, HumanMessage
|
| 3 |
from chatbot.models.llm_setup import llm
|
| 4 |
from chatbot.agents.tools.info_app_retriever import policy_retriever
|
|
|
|
| 5 |
import logging
|
| 6 |
|
| 7 |
# --- Cấu hình logging ---
|
| 8 |
logging.basicConfig(level=logging.INFO)
|
| 9 |
logger = logging.getLogger(__name__)
|
| 10 |
|
| 11 |
-
def policy(state: AgentState):
|
| 12 |
logger.info("---POLICY---")
|
| 13 |
messages = state["messages"]
|
| 14 |
question = messages[-1].content if messages else state.question
|
|
@@ -42,12 +43,13 @@ QUY TẮC AN TOÀN:
|
|
| 42 |
logger.info(f"Prompt gửi đến LLM cho chính sách: {system_prompt}")
|
| 43 |
|
| 44 |
try:
|
| 45 |
-
response = llm.
|
| 46 |
SystemMessage(content=system_prompt),
|
| 47 |
HumanMessage(content=question)
|
| 48 |
-
])
|
| 49 |
|
| 50 |
return {"messages": [response]}
|
| 51 |
|
| 52 |
except Exception as e:
|
| 53 |
-
|
|
|
|
|
|
| 2 |
from langchain_core.messages import AIMessage, SystemMessage, HumanMessage
|
| 3 |
from chatbot.models.llm_setup import llm
|
| 4 |
from chatbot.agents.tools.info_app_retriever import policy_retriever
|
| 5 |
+
from langchain_core.runnables import RunnableConfig
|
| 6 |
import logging
|
| 7 |
|
| 8 |
# --- Cấu hình logging ---
|
| 9 |
logging.basicConfig(level=logging.INFO)
|
| 10 |
logger = logging.getLogger(__name__)
|
| 11 |
|
| 12 |
+
async def policy(state: AgentState, config: RunnableConfig):
|
| 13 |
logger.info("---POLICY---")
|
| 14 |
messages = state["messages"]
|
| 15 |
question = messages[-1].content if messages else state.question
|
|
|
|
| 43 |
logger.info(f"Prompt gửi đến LLM cho chính sách: {system_prompt}")
|
| 44 |
|
| 45 |
try:
|
| 46 |
+
response = await llm.ainvoke([
|
| 47 |
SystemMessage(content=system_prompt),
|
| 48 |
HumanMessage(content=question)
|
| 49 |
+
], config=config)
|
| 50 |
|
| 51 |
return {"messages": [response]}
|
| 52 |
|
| 53 |
except Exception as e:
|
| 54 |
+
print(f"Lỗi LLM: {e}")
|
| 55 |
+
return {"messages": [AIMessage(content="Xin lỗi, có lỗi xảy ra.")]}
|
chatbot/agents/nodes/chatbot/select_food.py
CHANGED
|
@@ -1,13 +1,14 @@
|
|
| 1 |
from chatbot.agents.states.state import AgentState
|
| 2 |
from chatbot.models.llm_setup import llm
|
| 3 |
from langchain_core.messages import AIMessage, SystemMessage, HumanMessage
|
|
|
|
| 4 |
import logging
|
| 5 |
|
| 6 |
# --- Cấu hình logging ---
|
| 7 |
logging.basicConfig(level=logging.INFO)
|
| 8 |
logger = logging.getLogger(__name__)
|
| 9 |
|
| 10 |
-
def select_food(state: AgentState):
|
| 11 |
print("---NODE: ANALYZE & ANSWER---")
|
| 12 |
|
| 13 |
suggested_meals = state["suggested_meals"]
|
|
@@ -44,17 +45,15 @@ def select_food(state: AgentState):
|
|
| 44 |
|
| 45 |
Lưu ý: Chỉ sử dụng thông tin từ danh sách cung cấp, không bịa đặt số liệu.
|
| 46 |
"""
|
| 47 |
-
|
| 48 |
try:
|
| 49 |
-
response = llm.
|
| 50 |
SystemMessage(content=system_prompt),
|
| 51 |
HumanMessage(content=user_message)
|
| 52 |
-
])
|
| 53 |
-
|
| 54 |
-
logger.info("💬 AI Response:", response.content)
|
| 55 |
|
| 56 |
return {"messages": [response]}
|
| 57 |
|
| 58 |
except Exception as e:
|
| 59 |
-
|
| 60 |
-
return {"messages": [AIMessage(content="
|
|
|
|
| 1 |
from chatbot.agents.states.state import AgentState
|
| 2 |
from chatbot.models.llm_setup import llm
|
| 3 |
from langchain_core.messages import AIMessage, SystemMessage, HumanMessage
|
| 4 |
+
from langchain_core.runnables import RunnableConfig
|
| 5 |
import logging
|
| 6 |
|
| 7 |
# --- Cấu hình logging ---
|
| 8 |
logging.basicConfig(level=logging.INFO)
|
| 9 |
logger = logging.getLogger(__name__)
|
| 10 |
|
| 11 |
+
async def select_food(state: AgentState, config: RunnableConfig):
|
| 12 |
print("---NODE: ANALYZE & ANSWER---")
|
| 13 |
|
| 14 |
suggested_meals = state["suggested_meals"]
|
|
|
|
| 45 |
|
| 46 |
Lưu ý: Chỉ sử dụng thông tin từ danh sách cung cấp, không bịa đặt số liệu.
|
| 47 |
"""
|
| 48 |
+
|
| 49 |
try:
|
| 50 |
+
response = await llm.ainvoke([
|
| 51 |
SystemMessage(content=system_prompt),
|
| 52 |
HumanMessage(content=user_message)
|
| 53 |
+
], config=config)
|
|
|
|
|
|
|
| 54 |
|
| 55 |
return {"messages": [response]}
|
| 56 |
|
| 57 |
except Exception as e:
|
| 58 |
+
print(f"Lỗi LLM: {e}")
|
| 59 |
+
return {"messages": [AIMessage(content="Xin lỗi, có lỗi xảy ra.")]}
|
chatbot/agents/nodes/chatbot/select_food_plan.py
CHANGED
|
@@ -1,13 +1,14 @@
|
|
| 1 |
from chatbot.agents.states.state import AgentState
|
| 2 |
from langchain_core.messages import AIMessage, SystemMessage, HumanMessage
|
| 3 |
from chatbot.models.llm_setup import llm
|
|
|
|
| 4 |
import logging
|
| 5 |
|
| 6 |
# --- Cấu hình logging ---
|
| 7 |
logging.basicConfig(level=logging.INFO)
|
| 8 |
logger = logging.getLogger(__name__)
|
| 9 |
|
| 10 |
-
def select_food_plan(state: AgentState):
|
| 11 |
logger.info("---SELECT FOOD PLAN---")
|
| 12 |
|
| 13 |
user_profile = state.get("user_profile", {})
|
|
@@ -49,14 +50,13 @@ def select_food_plan(state: AgentState):
|
|
| 49 |
"""
|
| 50 |
|
| 51 |
try:
|
| 52 |
-
response = llm.
|
| 53 |
SystemMessage(content=system_prompt),
|
| 54 |
HumanMessage(content=user_message)
|
| 55 |
-
])
|
| 56 |
|
| 57 |
-
print("💬 AI Response:", response.content)
|
| 58 |
return {"messages": [response]}
|
| 59 |
|
| 60 |
except Exception as e:
|
| 61 |
-
print(f"
|
| 62 |
-
return {"messages": [AIMessage(content="Xin lỗi,
|
|
|
|
| 1 |
from chatbot.agents.states.state import AgentState
|
| 2 |
from langchain_core.messages import AIMessage, SystemMessage, HumanMessage
|
| 3 |
from chatbot.models.llm_setup import llm
|
| 4 |
+
from langchain_core.runnables import RunnableConfig
|
| 5 |
import logging
|
| 6 |
|
| 7 |
# --- Cấu hình logging ---
|
| 8 |
logging.basicConfig(level=logging.INFO)
|
| 9 |
logger = logging.getLogger(__name__)
|
| 10 |
|
| 11 |
+
async def select_food_plan(state: AgentState, config: RunnableConfig):
|
| 12 |
logger.info("---SELECT FOOD PLAN---")
|
| 13 |
|
| 14 |
user_profile = state.get("user_profile", {})
|
|
|
|
| 50 |
"""
|
| 51 |
|
| 52 |
try:
|
| 53 |
+
response = await llm.ainvoke([
|
| 54 |
SystemMessage(content=system_prompt),
|
| 55 |
HumanMessage(content=user_message)
|
| 56 |
+
], config=config)
|
| 57 |
|
|
|
|
| 58 |
return {"messages": [response]}
|
| 59 |
|
| 60 |
except Exception as e:
|
| 61 |
+
print(f"Lỗi LLM: {e}")
|
| 62 |
+
return {"messages": [AIMessage(content="Xin lỗi, có lỗi xảy ra.")]}
|
chatbot/main.py
CHANGED
|
@@ -11,16 +11,14 @@ app = FastAPI(
|
|
| 11 |
version="1.0.0",
|
| 12 |
)
|
| 13 |
|
| 14 |
-
# Cho phép CORS để kết nối frontend
|
| 15 |
app.add_middleware(
|
| 16 |
CORSMiddleware,
|
| 17 |
-
allow_origins=["*"],
|
| 18 |
allow_credentials=True,
|
| 19 |
allow_methods=["*"],
|
| 20 |
allow_headers=["*"],
|
| 21 |
)
|
| 22 |
|
| 23 |
-
# Đăng ký route
|
| 24 |
app.include_router(chat_router)
|
| 25 |
app.include_router(meal_plan_router)
|
| 26 |
app.include_router(food_replace_router)
|
|
|
|
| 11 |
version="1.0.0",
|
| 12 |
)
|
| 13 |
|
|
|
|
| 14 |
app.add_middleware(
|
| 15 |
CORSMiddleware,
|
| 16 |
+
allow_origins=["*"],
|
| 17 |
allow_credentials=True,
|
| 18 |
allow_methods=["*"],
|
| 19 |
allow_headers=["*"],
|
| 20 |
)
|
| 21 |
|
|
|
|
| 22 |
app.include_router(chat_router)
|
| 23 |
app.include_router(meal_plan_router)
|
| 24 |
app.include_router(food_replace_router)
|
chatbot/models/__pycache__/llm_setup.cpython-310.pyc
CHANGED
|
Binary files a/chatbot/models/__pycache__/llm_setup.cpython-310.pyc and b/chatbot/models/__pycache__/llm_setup.cpython-310.pyc differ
|
|
|
chatbot/models/llm_setup.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
from langchain_deepseek import ChatDeepSeek
|
|
|
|
| 2 |
from chatbot.config import DEEPSEEK_API_KEY
|
| 3 |
|
| 4 |
if not DEEPSEEK_API_KEY:
|
|
@@ -12,6 +13,14 @@ llm = ChatDeepSeek(
|
|
| 12 |
max_retries=2,
|
| 13 |
)
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
def get_llm(model_name: str = "deepseek-chat", temperature: float = 0.3):
|
| 16 |
return ChatDeepSeek(
|
| 17 |
model=model_name,
|
|
|
|
| 1 |
from langchain_deepseek import ChatDeepSeek
|
| 2 |
+
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
|
| 3 |
from chatbot.config import DEEPSEEK_API_KEY
|
| 4 |
|
| 5 |
if not DEEPSEEK_API_KEY:
|
|
|
|
| 13 |
max_retries=2,
|
| 14 |
)
|
| 15 |
|
| 16 |
+
llm_stream = ChatDeepSeek(
|
| 17 |
+
model="deepseek-chat",
|
| 18 |
+
temperature=0.3,
|
| 19 |
+
max_tokens=2048,
|
| 20 |
+
streaming=True,
|
| 21 |
+
callbacks=[StreamingStdOutCallbackHandler()],
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
def get_llm(model_name: str = "deepseek-chat", temperature: float = 0.3):
|
| 25 |
return ChatDeepSeek(
|
| 26 |
model=model_name,
|
chatbot/routes/__pycache__/chat_router.cpython-310.pyc
CHANGED
|
Binary files a/chatbot/routes/__pycache__/chat_router.cpython-310.pyc and b/chatbot/routes/__pycache__/chat_router.cpython-310.pyc differ
|
|
|
chatbot/routes/__pycache__/food_replace_route.cpython-310.pyc
CHANGED
|
Binary files a/chatbot/routes/__pycache__/food_replace_route.cpython-310.pyc and b/chatbot/routes/__pycache__/food_replace_route.cpython-310.pyc differ
|
|
|
chatbot/routes/chat_router.py
CHANGED
|
@@ -1,14 +1,17 @@
|
|
| 1 |
-
from fastapi import APIRouter
|
|
|
|
| 2 |
from pydantic import BaseModel
|
| 3 |
from langchain_core.messages import HumanMessage
|
| 4 |
from chatbot.agents.graphs.chatbot_graph import workflow_chatbot
|
| 5 |
import logging
|
|
|
|
|
|
|
| 6 |
|
| 7 |
# --- Cấu hình logging ---
|
| 8 |
logging.basicConfig(level=logging.INFO)
|
| 9 |
logger = logging.getLogger(__name__)
|
| 10 |
|
| 11 |
-
# --- Định nghĩa request body ---
|
| 12 |
class ChatRequest(BaseModel):
|
| 13 |
user_id: str
|
| 14 |
thread_id: str
|
|
@@ -22,32 +25,36 @@ router = APIRouter(
|
|
| 22 |
|
| 23 |
try:
|
| 24 |
chatbot_app = workflow_chatbot()
|
|
|
|
| 25 |
except Exception as e:
|
| 26 |
logger.error(f"❌ Failed to compile Chatbot Graph: {e}")
|
| 27 |
raise e
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import APIRouter
|
| 2 |
+
from fastapi.responses import StreamingResponse
|
| 3 |
from pydantic import BaseModel
|
| 4 |
from langchain_core.messages import HumanMessage
|
| 5 |
from chatbot.agents.graphs.chatbot_graph import workflow_chatbot
|
| 6 |
import logging
|
| 7 |
+
import json
|
| 8 |
+
from chatbot.models.llm_setup import llm_stream
|
| 9 |
|
| 10 |
# --- Cấu hình logging ---
|
| 11 |
logging.basicConfig(level=logging.INFO)
|
| 12 |
logger = logging.getLogger(__name__)
|
| 13 |
|
| 14 |
+
# # --- Định nghĩa request body ---
|
| 15 |
class ChatRequest(BaseModel):
|
| 16 |
user_id: str
|
| 17 |
thread_id: str
|
|
|
|
| 25 |
|
| 26 |
try:
|
| 27 |
chatbot_app = workflow_chatbot()
|
| 28 |
+
logger.info("✅ Chatbot Graph compiled successfully!")
|
| 29 |
except Exception as e:
|
| 30 |
logger.error(f"❌ Failed to compile Chatbot Graph: {e}")
|
| 31 |
raise e
|
| 32 |
|
| 33 |
+
async def generate_chat_response(initial_state, config):
|
| 34 |
+
async for event in chatbot_app.astream_events(
|
| 35 |
+
initial_state,
|
| 36 |
+
config=config,
|
| 37 |
+
version="v2"
|
| 38 |
+
):
|
| 39 |
+
if event["event"] == "on_chat_model_stream":
|
| 40 |
+
|
| 41 |
+
data = event.get("data", {})
|
| 42 |
+
chunk = data.get("chunk")
|
| 43 |
+
|
| 44 |
+
if chunk and hasattr(chunk, "content") and chunk.content:
|
| 45 |
+
yield chunk.content
|
| 46 |
|
| 47 |
+
@router.post("/")
|
| 48 |
+
async def chat(request: ChatRequest):
|
| 49 |
+
logger.info(f"Nhận được tin nhắn chat từ user: {request.user_id}")
|
| 50 |
+
config = {"configurable": {"thread_id": request.thread_id}}
|
| 51 |
+
|
| 52 |
+
initial_state = {
|
| 53 |
+
"user_id": request.user_id,
|
| 54 |
+
"messages": [HumanMessage(content=request.message)]
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
return StreamingResponse(
|
| 58 |
+
generate_chat_response(initial_state, config),
|
| 59 |
+
media_type="text/plain"
|
| 60 |
+
)
|