Download api/server.py from mothy-08/ragbot: direct link, hf CLI and curl.
- Browser
- Download file 4.47 kB
-
https://huggingface.co/spaces/mothy-08/ragbot/resolve/main/api/server.py
- Command line
-
hf download hf://spaces/mothy-08/ragbot/api/server.py
-
curl -L -o server.py https://huggingface.co/spaces/mothy-08/ragbot/resolve/main/api/server.py
4.47 kB
| import time | |
| from fastapi import FastAPI, BackgroundTasks, HTTPException | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from api.utils import get_namespace_id, logger | |
| from api.crawler import crawl_website | |
| from api.schemas import ChatRequest, IngestRequest | |
| from api.config import vs, flash, system_instruction | |
| from google.genai import types | |
| app = FastAPI(title="RAG Chatbot API", version="1.0") | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=False, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| def background_ingest_task(url: str, namespace_id: str): | |
| logger.info(f"Background crawl STARTED for: {url}") | |
| start = time.perf_counter() | |
| try: | |
| crawler_gen = crawl_website(url, limit=50) | |
| buffer = [] | |
| for source_url, chunks in crawler_gen: | |
| for chunk in chunks: | |
| buffer.append({"text": chunk, "source": source_url}) | |
| if len(buffer) >= 50: | |
| vs.batch_upsert(buffer, namespace_id) | |
| buffer = [] | |
| if buffer: | |
| vs.batch_upsert(buffer, namespace_id) | |
| logger.info(f"Background crawl COMPLETED for {namespace_id}") | |
| except Exception as e: | |
| logger.error(f"Background task failed for {url}: {e}") | |
| end = time.perf_counter() | |
| logger.info(f"Time elapsed: {end - start}") | |
| def check_health(): | |
| return {"status": "online", "system": "RAG-Chatbot v1.0"} | |
| def check_endpoint(req: IngestRequest): | |
| url_str = str(req.url) | |
| namespace_id = get_namespace_id(url_str) | |
| try: | |
| stats = vs.index.describe_index_stats() | |
| exists = namespace_id in stats.namespaces | |
| count = 0 | |
| if exists: | |
| count = stats.namespaces[namespace_id].vector_count | |
| return { | |
| "exists": exists and count > 0, | |
| "namespace": namespace_id, | |
| "vector_count": count, | |
| } | |
| except Exception as e: | |
| logger.error(f"Check failed: {e}") | |
| return {"exists": False, "error": str(e)} | |
| def ingest_endpoint(req: IngestRequest, background_tasks: BackgroundTasks): | |
| url_str = str(req.url) | |
| namespace_id = get_namespace_id(url_str) | |
| background_tasks.add_task(background_ingest_task, url_str, namespace_id) | |
| logger.info(f"Background ingest dispatched: {url_str} -> {namespace_id}") | |
| return { | |
| "status": "processing", | |
| "message": "Ingestion started in background.", | |
| "namespace": namespace_id, | |
| } | |
| # Add this near your other endpoints | |
| def reset_endpoint(req: IngestRequest): | |
| url_str = str(req.url) | |
| namespace_id = get_namespace_id(url_str) | |
| success = vs.delete_namespace(namespace_id) | |
| if success: | |
| return {"status": "success", "message": f"Memory wiped for {url_str}"} | |
| else: | |
| raise HTTPException(status_code=500, detail="Failed to delete namespace") | |
| def chat_endpoint(req: ChatRequest): | |
| url_str = str(req.url) | |
| namespace_id = get_namespace_id(url_str) | |
| # 1. Retrieval | |
| results = vs.query_namespace(req.message, namespace_id) | |
| contexts = [] | |
| sources = set() | |
| logger.info(f"\n--- DEBUG: RETRIEVED FOR '{req.message}' ---") | |
| if results and results.matches: | |
| for i, match in enumerate(results.matches): | |
| logger.info( | |
| f"[{i}] Score: {match.score:.4f} | Text: {match.metadata.get('text', '')[:100]}..." | |
| ) | |
| if match.metadata: | |
| text = match.metadata.get("text", "") | |
| src = match.metadata.get("source", None) | |
| if text: | |
| contexts.append(text) | |
| if src: | |
| sources.add(src) | |
| if not contexts: | |
| return { | |
| "answer": "I haven't learned this website yet. Please click 'Train' first!", | |
| "sources": [], | |
| } | |
| # 2. Prompting | |
| context = "\n\n".join(contexts[:5]) | |
| try: | |
| response = flash.models.generate_content( | |
| model="gemini-2.0-flash", | |
| config=types.GenerateContentConfig( | |
| system_instruction=system_instruction(url_str, context) | |
| ), | |
| contents=req.message, | |
| ) | |
| return {"answer": response.text, "sources": list(sources)} | |
| except Exception as e: | |
| logger.error(f"LLM Error: {e}") | |
| raise HTTPException(status_code=500, detail="AI Service Error") | |