wop commited on
Commit
3d9e926
Β·
verified Β·
1 Parent(s): fa34c49

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +59 -5
main.py CHANGED
@@ -9,7 +9,7 @@ from typing import Any, Optional
9
 
10
  import numpy as np
11
  from fastapi import FastAPI, Request
12
- from fastapi.responses import HTMLResponse, JSONResponse
13
  from fastapi.templating import Jinja2Templates
14
 
15
  try:
@@ -284,6 +284,45 @@ def find_similar_conversation(
284
  return {"conversation": conv, "score": score}
285
 
286
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  # ────────────────────── Actions ──────────────────────
288
 
289
  def create_conversation(question: str, author: str = "Anonymous") -> dict[str, Any]:
@@ -359,10 +398,14 @@ def add_answer(
359
  return None, "empty answer"
360
 
361
  conversation = load_conversation(conversation_id)
362
- if conversation is None:
363
- if not question_if_new:
364
- return None, "conversation not found"
365
- conversation = create_conversation(question_if_new, author)
 
 
 
 
366
 
367
  now = now_iso()
368
  version = normalize_version({
@@ -493,6 +536,14 @@ def home(request: Request):
493
  )
494
 
495
 
 
 
 
 
 
 
 
 
496
  @app.get("/health")
497
  def health():
498
  return {"ok": True}
@@ -538,6 +589,7 @@ async def api(request: Request):
538
  if match and match.get("conversation"):
539
  conversation = match["conversation"]
540
  best = best_answer_payload(conversation)
 
541
  return JSONResponse({
542
  "ok": True,
543
  "matched": True,
@@ -545,6 +597,7 @@ async def api(request: Request):
545
  "conversation": conversation,
546
  "assistant_text": best["text"] if best else "No answer yet. You can write one.",
547
  "best_answer": best,
 
548
  })
549
 
550
  # 2) No match β€” create new
@@ -555,6 +608,7 @@ async def api(request: Request):
555
  "conversation": conversation,
556
  "assistant_text": "No answer yet. You can write one.",
557
  "best_answer": None,
 
558
  })
559
 
560
  # ── answer ──
 
9
 
10
  import numpy as np
11
  from fastapi import FastAPI, Request
12
+ from fastapi.responses import FileResponse, HTMLResponse, JSONResponse
13
  from fastapi.templating import Jinja2Templates
14
 
15
  try:
 
284
  return {"conversation": conv, "score": score}
285
 
286
 
287
+ def find_top_k_similar(question: str, k: int = 3) -> list[dict[str, Any]]:
288
+ idx = load_embed_index()
289
+ if not idx or SentenceTransformer is None:
290
+ return []
291
+
292
+ q_vec = np.array(embed_text(question), dtype=float)
293
+ if q_vec.size == 0:
294
+ return []
295
+
296
+ results: list[tuple[str, float]] = []
297
+ for cid, data in idx.items():
298
+ try:
299
+ vec = np.array(data["vector"], dtype=float)
300
+ except Exception:
301
+ continue
302
+ if vec.shape != q_vec.shape:
303
+ continue
304
+ score = float(vec @ q_vec)
305
+ results.append((cid, score))
306
+
307
+ results.sort(key=lambda x: x[1], reverse=True)
308
+
309
+ out: list[dict[str, Any]] = []
310
+ for cid, score in results[:k]:
311
+ conv = load_conversation(cid)
312
+ if not conv:
313
+ continue
314
+ best = best_answer_payload(conv)
315
+ if not best:
316
+ continue
317
+ out.append({
318
+ "conversation_id": cid,
319
+ "question": conv.get("question"),
320
+ "answer": best["text"],
321
+ "score": score,
322
+ })
323
+ return out
324
+
325
+
326
  # ────────────────────── Actions ──────────────────────
327
 
328
  def create_conversation(question: str, author: str = "Anonymous") -> dict[str, Any]:
 
398
  return None, "empty answer"
399
 
400
  conversation = load_conversation(conversation_id)
401
+
402
+ # If user is answering a NEW question (even if matched),
403
+ # create a new conversation instead of polluting the matched one.
404
+ if question_if_new:
405
+ if conversation is None or conversation.get("question") != question_if_new:
406
+ conversation = create_conversation(question_if_new, author)
407
+ elif conversation is None:
408
+ return None, "conversation not found"
409
 
410
  now = now_iso()
411
  version = normalize_version({
 
536
  )
537
 
538
 
539
+ @app.get("/logo.png")
540
+ def logo():
541
+ logo_path = Path(__file__).with_name("logo.png")
542
+ if logo_path.exists():
543
+ return FileResponse(logo_path)
544
+ return JSONResponse({"ok": False, "error": "logo not found"}, status_code=404)
545
+
546
+
547
  @app.get("/health")
548
  def health():
549
  return {"ok": True}
 
589
  if match and match.get("conversation"):
590
  conversation = match["conversation"]
591
  best = best_answer_payload(conversation)
592
+ related = find_top_k_similar(question, k=3)
593
  return JSONResponse({
594
  "ok": True,
595
  "matched": True,
 
597
  "conversation": conversation,
598
  "assistant_text": best["text"] if best else "No answer yet. You can write one.",
599
  "best_answer": best,
600
+ "related": related,
601
  })
602
 
603
  # 2) No match β€” create new
 
608
  "conversation": conversation,
609
  "assistant_text": "No answer yet. You can write one.",
610
  "best_answer": None,
611
+ "related": [],
612
  })
613
 
614
  # ── answer ──