ChienChung commited on
Commit
bc4f7e9
·
verified ·
1 Parent(s): 20620c4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +84 -28
app.py CHANGED
@@ -1238,15 +1238,56 @@ def multi_agent_chat_advanced(query: str, file=None) -> str:
1238
 
1239
 
1240
  # LangGraph 使用的節點函數(會接續你的 Crew Agent)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1241
  def router_run(state: dict) -> dict:
1242
  query = state["query"]
1243
  result = router_agent.kickoff(inputs={"query": query})
1244
  return {"query": query, "route_result": result.output}
1245
 
1246
- def general_run(state: dict) -> dict:
1247
- result = general_agent.kickoff(inputs={"query": state["query"]})
1248
- return {"query": state["query"], "final_answer": result.output}
1249
-
1250
  def docqa_run(state: dict) -> dict:
1251
  result = document_qa_agent.kickoff(inputs={"query": state["query"]})
1252
  return {"query": state["query"], "final_answer": result.output}
@@ -1268,13 +1309,10 @@ def build_langgraph_gpt_like():
1268
 
1269
  # Router 條件邏輯:你可以換成你自己的邏輯規則
1270
  def decide_next(state):
1271
- route = state.get("route_result", "").lower()
1272
- if "summarise" in route or "summary" in route:
1273
- return "Summarise"
1274
- elif "document" in route or "file" in route:
1275
- return "DocQA"
1276
- else:
1277
- return "General"
1278
 
1279
  graph.add_conditional_edges("Router", decide_next, {
1280
  "DocQA": "DocQA",
@@ -1289,28 +1327,43 @@ def build_langgraph_gpt_like():
1289
  return graph.compile()
1290
 
1291
  # 用於 Gradio Tab 6 的主入口函數
1292
- def langgraph_tab6_main(query: str, file=None) -> str:
1293
  try:
1294
- file_path = get_file_path(file)
1295
- if not file_path:
1296
- return "Please upload a document file first."
1297
-
1298
- # 檢查文件類型並建立 retriever
1299
- if file_path.lower().endswith(".pdf"):
1300
- loader = PyPDFLoader(file_path)
1301
- elif file_path.lower().endswith(".docx"):
1302
- loader = UnstructuredWordDocumentLoader(file_path)
1303
- else:
1304
- loader = TextLoader(file_path)
1305
- docs = loader.load()
1306
- chunks = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50).split_documents(docs)
 
 
 
 
 
 
 
 
 
 
 
1307
  db = FAISS.from_documents(chunks, embeddings)
1308
  retriever = db.as_retriever()
1309
 
1310
- # 建構 LangGraph vB QA Chain
1311
  graph = build_langgraph_doc_qa_chain(llm=llm_gpt4, retriever=retriever, memory=None, prompt=custom_prompt)
1312
- result = graph(query)
 
 
 
1313
  return result.get("answer", "No answer generated.")
 
1314
  except Exception as e:
1315
  return f"[Tab6 Error] {e}"
1316
 
@@ -1459,7 +1512,10 @@ demo = gr.TabbedInterface(
1459
  ),
1460
  gr.Interface(
1461
  fn=langgraph_tab6_main,
1462
- inputs=[gr.Textbox(label="Ask anything")],
 
 
 
1463
  outputs="text",
1464
  title="LangGraph GPT-like QA (Tab6)",
1465
  allow_flagging="never",
 
1238
 
1239
 
1240
  # LangGraph 使用的節點函數(會接續你的 Crew Agent)
1241
+ from sentence_transformers import SentenceTransformer
1242
+
1243
+ embedding_model = SentenceTransformer("all-MiniLM-L6-v2")
1244
+
1245
+ # Intent label embeddings(你可以再自訂)
1246
+ INTENT_LABELS = {
1247
+ "DocQA": ["document", "file", "paper", "cb", "proposal"],
1248
+ "Summarise": ["summarise", "summary", "abstract", "key points", "要點", "總結", "摘要"],
1249
+ "General": ["who are you", "tell me something", "what can you do", "fun fact"],
1250
+ }
1251
+
1252
+ def detect_intent_embedding(query, file_names=[]):
1253
+ query_emb = embedding_model.encode(query, normalize_embeddings=True)
1254
+
1255
+ best_label = None
1256
+ best_score = -1
1257
+
1258
+ # 把上傳的檔名也當成一種 prompt
1259
+ all_phrases = INTENT_LABELS.copy()
1260
+ if file_names:
1261
+ all_phrases["DocQA"] += [name.lower() for name in file_names]
1262
+
1263
+ for label, examples in all_phrases.items():
1264
+ for example in examples:
1265
+ example_emb = embedding_model.encode(example, normalize_embeddings=True)
1266
+ score = float(query_emb @ example_emb.T)
1267
+ if score > best_score:
1268
+ best_score = score
1269
+ best_label = label
1270
+ return best_label if best_label else "General"
1271
+
1272
+ def decide_next(state):
1273
+ query = state.get("query", "")
1274
+ file_names = state.get("file_names", [])
1275
+ label = detect_intent_embedding(query, file_names)
1276
+ return label
1277
+
1278
+ # General → Search fallback handoff(當 general 回應不了)
1279
+ def general_run(state: dict) -> dict:
1280
+ result = general_agent.kickoff(inputs={"query": state["query"]})
1281
+ output = result.output.lower()
1282
+ if any(x in output for x in ["i don't know", "no idea", "not sure", "can't answer", "no info"]):
1283
+ result = search_agent.kickoff(inputs={"query": state["query"]})
1284
+ return {"query": state["query"], "final_answer": result.output}
1285
+
1286
  def router_run(state: dict) -> dict:
1287
  query = state["query"]
1288
  result = router_agent.kickoff(inputs={"query": query})
1289
  return {"query": query, "route_result": result.output}
1290
 
 
 
 
 
1291
  def docqa_run(state: dict) -> dict:
1292
  result = document_qa_agent.kickoff(inputs={"query": state["query"]})
1293
  return {"query": state["query"], "final_answer": result.output}
 
1309
 
1310
  # Router 條件邏輯:你可以換成你自己的邏輯規則
1311
  def decide_next(state):
1312
+ query = state.get("query", "")
1313
+ file_names = state.get("file_names", [])
1314
+ label = detect_intent_embedding(query, file_names)
1315
+ return label
 
 
 
1316
 
1317
  graph.add_conditional_edges("Router", decide_next, {
1318
  "DocQA": "DocQA",
 
1327
  return graph.compile()
1328
 
1329
  # 用於 Gradio Tab 6 的主入口函數
1330
+ def langgraph_tab6_main(query: str, files=None) -> str:
1331
  try:
1332
+ if not files:
1333
+ return "Please upload at least one document file."
1334
+
1335
+ all_docs = []
1336
+ file_names = []
1337
+
1338
+ for file in files:
1339
+ file_path = get_file_path(file)
1340
+ if not file_path:
1341
+ continue
1342
+ file_names.append(os.path.basename(file_path))
1343
+ if file_path.lower().endswith(".pdf"):
1344
+ loader = PyPDFLoader(file_path)
1345
+ elif file_path.lower().endswith(".docx"):
1346
+ loader = UnstructuredWordDocumentLoader(file_path)
1347
+ else:
1348
+ loader = TextLoader(file_path)
1349
+ docs = loader.load()
1350
+ all_docs.extend(docs)
1351
+
1352
+ if not all_docs:
1353
+ return "No valid documents loaded."
1354
+
1355
+ chunks = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50).split_documents(all_docs)
1356
  db = FAISS.from_documents(chunks, embeddings)
1357
  retriever = db.as_retriever()
1358
 
1359
+ # 建構 LangGraph QA Chain
1360
  graph = build_langgraph_doc_qa_chain(llm=llm_gpt4, retriever=retriever, memory=None, prompt=custom_prompt)
1361
+ result = graph.invoke({
1362
+ "query": query,
1363
+ "file_names": file_names # Pass all file names for intent detection
1364
+ })
1365
  return result.get("answer", "No answer generated.")
1366
+
1367
  except Exception as e:
1368
  return f"[Tab6 Error] {e}"
1369
 
 
1512
  ),
1513
  gr.Interface(
1514
  fn=langgraph_tab6_main,
1515
+ inputs=[
1516
+ gr.Textbox(label="Ask anything"),
1517
+ gr.File(label="Upload one or more files", file_types=[".pdf", ".txt", ".docx"], file_count="multiple")
1518
+ ],
1519
  outputs="text",
1520
  title="LangGraph GPT-like QA (Tab6)",
1521
  allow_flagging="never",