nikeshn commited on
Commit
52e8e7a
·
verified ·
1 Parent(s): af226a7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +31 -19
app.py CHANGED
@@ -38,7 +38,8 @@ import httpx
38
 
39
  # ===== CONFIG =====
40
  KNOWLEDGE_DIR = "knowledge"
41
- FAISS_INDEX_PATH = "faiss_index"
 
42
  DB_PATH = "/data/analytics.db" if os.path.exists("/data") else "analytics.db"
43
  CHUNK_SIZE = 800
44
  CHUNK_OVERLAP = 100
@@ -113,8 +114,11 @@ def set_config(key, value):
113
 
114
 
115
  # ===== ADMIN AUTH =====
116
- # Set ADMIN_PASSWORD as HF Space Secret
117
- ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD", "kulibadmin2026")
 
 
 
118
  admin_sessions = {} # token -> expiry timestamp
119
 
120
  def create_session():
@@ -309,15 +313,19 @@ async def tool_search_pubmed(query, limit=5):
309
  return {"error": f"PubMed: {str(e)}", "results": [], "source": "PubMed"}
310
 
311
 
312
- # ===== TOOL: SEARCH CONSENSUS (direct link MCP requires OAuth) =====
313
  async def tool_search_consensus(query, limit=5):
314
- return {
315
- "total": 0,
316
- "results": [],
317
- "source": "Consensus",
318
- "search_url": f"https://consensus.app/results/?q={query}",
319
- "message": "Search Consensus for AI-powered research synthesis.",
320
- }
 
 
 
 
321
 
322
 
323
  # ===== TOOL: SEARCH SEMANTIC SCHOLAR (direct API — free, no auth) =====
@@ -371,8 +379,7 @@ async def tool_search_scholar(query, limit=5):
371
  except Exception as e:
372
  return {"error": f"Semantic Scholar: {str(e)}", "results": [], "source": "Semantic Scholar"}
373
 
374
- # ===== TOOL: LIBRARY INFO (RAG) =====
375
- async def tool_library_info(question, history=None):
376
  if not vectorstore:
377
  return {"answer": "Knowledge base not initialized.", "sources": []}
378
 
@@ -397,7 +404,14 @@ Question: {question}
397
 
398
  Answer:"""
399
 
400
- llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.2, max_tokens=500)
 
 
 
 
 
 
 
401
  response = llm.invoke(prompt)
402
 
403
  sources = []
@@ -515,14 +529,13 @@ async def search(req: SearchRequest):
515
  result = {"error": f"Unknown source: {source}", "results": []}
516
 
517
  elapsed = time.time() - start
518
- log_query(req.query, source, req.model, elapsed, len(result.get("results", [])), result.get("error"))
519
  result["response_time"] = round(elapsed, 2)
520
  result["is_medical"] = is_medical_topic(req.query)
521
  return result
522
 
523
  except Exception as e:
524
  elapsed = time.time() - start
525
- log_query(req.query, source, req.model, elapsed, 0, str(e))
526
  return {"error": str(e), "results": [], "response_time": round(elapsed, 2)}
527
 
528
 
@@ -547,9 +560,9 @@ async def rag_query(req: RAGRequest):
547
  start = time.time()
548
  try:
549
  history = [{"role": m.role, "content": m.content} for m in req.history] if req.history else None
550
- result = await tool_library_info(req.question, history)
551
  elapsed = time.time() - start
552
- log_query(req.question, "rag", req.model, elapsed, len(result.get("sources", [])))
553
  return {
554
  "answer": result["answer"],
555
  "sources": result["sources"],
@@ -558,7 +571,6 @@ async def rag_query(req: RAGRequest):
558
  }
559
  except Exception as e:
560
  elapsed = time.time() - start
561
- log_query(req.question, "rag", req.model, elapsed, 0, str(e))
562
  return {"answer": "Error processing your question.", "sources": [], "error": str(e)}
563
 
564
 
 
38
 
39
  # ===== CONFIG =====
40
  KNOWLEDGE_DIR = "knowledge"
41
+ # Use /data for persistence across HF Space restarts — fall back to local if /data unavailable
42
+ FAISS_INDEX_PATH = "/data/faiss_index" if os.path.exists("/data") else "faiss_index"
43
  DB_PATH = "/data/analytics.db" if os.path.exists("/data") else "analytics.db"
44
  CHUNK_SIZE = 800
45
  CHUNK_OVERLAP = 100
 
114
 
115
 
116
  # ===== ADMIN AUTH =====
117
+ # ADMIN_PASSWORD must be set as HF Space Secret — no insecure fallback
118
+ ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD", "")
119
+ if not ADMIN_PASSWORD:
120
+ import warnings
121
+ warnings.warn("ADMIN_PASSWORD secret is not set. Admin dashboard will be inaccessible until configured.")
122
  admin_sessions = {} # token -> expiry timestamp
123
 
124
  def create_session():
 
313
  return {"error": f"PubMed: {str(e)}", "results": [], "source": "PubMed"}
314
 
315
 
316
+ # ===== TOOL: SEARCH CONSENSUS (via Semantic Scholar with consensus framing) =====
317
  async def tool_search_consensus(query, limit=5):
318
+ """
319
+ Consensus.app requires OAuth so we can't call it directly.
320
+ Instead we search Semantic Scholar with the same query and return
321
+ results alongside a direct Consensus deep-link so the user can
322
+ also check the AI-synthesized answer there.
323
+ """
324
+ scholar = await tool_search_scholar(query, limit)
325
+ scholar["source"] = "Consensus / Semantic Scholar"
326
+ scholar["consensus_url"] = f"https://consensus.app/results/?q={query}"
327
+ scholar["message"] = "Results from Semantic Scholar. For AI-synthesized consensus, click the Consensus link."
328
+ return scholar
329
 
330
 
331
  # ===== TOOL: SEARCH SEMANTIC SCHOLAR (direct API — free, no auth) =====
 
379
  except Exception as e:
380
  return {"error": f"Semantic Scholar: {str(e)}", "results": [], "source": "Semantic Scholar"}
381
 
382
+ async def tool_library_info(question, history=None, model="gpt"):
 
383
  if not vectorstore:
384
  return {"answer": "Knowledge base not initialized.", "sources": []}
385
 
 
404
 
405
  Answer:"""
406
 
407
+ # Respect the model selection — use Claude if requested, GPT otherwise
408
+ use_claude = model == "claude" and os.environ.get("ANTHROPIC_API_KEY")
409
+ if use_claude:
410
+ from langchain_anthropic import ChatAnthropic
411
+ llm = ChatAnthropic(model="claude-haiku-4-5-20251001", temperature=0.2, max_tokens=500)
412
+ else:
413
+ llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.2, max_tokens=500)
414
+
415
  response = llm.invoke(prompt)
416
 
417
  sources = []
 
529
  result = {"error": f"Unknown source: {source}", "results": []}
530
 
531
  elapsed = time.time() - start
532
+ # Logging handled by Cloudflare D1 via worker /log endpoint (single source of truth)
533
  result["response_time"] = round(elapsed, 2)
534
  result["is_medical"] = is_medical_topic(req.query)
535
  return result
536
 
537
  except Exception as e:
538
  elapsed = time.time() - start
 
539
  return {"error": str(e), "results": [], "response_time": round(elapsed, 2)}
540
 
541
 
 
560
  start = time.time()
561
  try:
562
  history = [{"role": m.role, "content": m.content} for m in req.history] if req.history else None
563
+ result = await tool_library_info(req.question, history, model=req.model)
564
  elapsed = time.time() - start
565
+ # Logging handled by Cloudflare D1 via worker /log endpoint
566
  return {
567
  "answer": result["answer"],
568
  "sources": result["sources"],
 
571
  }
572
  except Exception as e:
573
  elapsed = time.time() - start
 
574
  return {"answer": "Error processing your question.", "sources": [], "error": str(e)}
575
 
576