Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, Request, HTTPException | |
| from fastapi.responses import HTMLResponse | |
| from fastapi.templating import Jinja2Templates | |
| from duckduckgo_search import DDGS | |
| import logging | |
| import uvicorn | |
| from collections import deque | |
| from datetime import datetime | |
| app = FastAPI() | |
| templates = Jinja2Templates(directory="templates") | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| # Global in-memory queue to store search results | |
| # Stores dicts: {"query": str, "results": list, "timestamp": str} | |
| response_queue = deque() | |
| async def read_root(request: Request): | |
| return templates.TemplateResponse("index.html", {"request": request}) | |
| async def queue_search(q: str): | |
| """ | |
| Performs the search immediately and pushes the result onto the in-memory queue. | |
| """ | |
| if not q: | |
| return {"error": "Query parameter 'q' is required"} | |
| try: | |
| logger.info(f"Processing search for: {q}") | |
| with DDGS() as ddgs: | |
| # text() returns an iterator/generator in newer versions, convert to list | |
| # backend="html" is removed in v7+ | |
| results = list(ddgs.text(q, max_results=10)) | |
| logger.info(f"Found {len(results)} results for '{q}'") | |
| response_data = { | |
| "query": q, | |
| "results": results, | |
| "timestamp": datetime.now().isoformat() | |
| } | |
| response_queue.append(response_data) | |
| return { | |
| "status": "queued", | |
| "message": "Search completed and added to queue", | |
| "queue_size": len(response_queue) | |
| } | |
| except Exception as e: | |
| logger.error(f"Search error: {e}") | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def pop_result(): | |
| """ | |
| Retrieves the next result from the queue (FIFO). | |
| Returns the result and the number of remaining items. | |
| """ | |
| if not response_queue: | |
| return { | |
| "status": "empty", | |
| "message": "No results in queue", | |
| "remaining": 0 | |
| } | |
| # Using popleft for FIFO (First-In-First-Out) behavior | |
| # If you strictly wanted a stack (LIFO), use pop() instead | |
| result = response_queue.popleft() | |
| return { | |
| "status": "success", | |
| "data": result, | |
| "remaining": len(response_queue) | |
| } | |
| async def get_status(): | |
| """Helper endpoint to check queue size""" | |
| return {"queue_size": len(response_queue)} | |
| # Keep the original endpoint for backward compatibility if needed, | |
| # or it can be ignored. | |
| async def search(q: str): | |
| if not q: return {"results": []} | |
| try: | |
| # DDGS context manager is recommended | |
| with DDGS() as ddgs: | |
| # text() returns an iterator/generator in newer versions, convert to list | |
| # max_results is valid in newer versions of duckduckgo_search | |
| results = list(ddgs.text(q, max_results=10)) | |
| logger.info(f"Direct search found {len(results)} results for '{q}'") | |
| return {"results": results} | |
| except Exception as e: | |
| logger.error(f"Search error: {e}") | |
| # In production we might want to hide the exact error, but for dev this is fine | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| if __name__ == "__main__": | |
| uvicorn.run(app, host="0.0.0.0", port=7860) | |