Meta-API / app.py
sandeepmudhiraj's picture
Upload folder using huggingface_hub
a0709fa verified
#!/usr/bin/env python3
"""Meta API wrapper — starts engine via werkzeug, exposes on port 7860."""
import os
import sys
import subprocess
import time
import threading
import httpx
import uvicorn
from fastapi import FastAPI, Query
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse, Response
app = FastAPI(title="Meta API", docs_url=None, redoc_url=None)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
INTERNAL_PORT = 8888
INTERNAL_URL = f"http://127.0.0.1:{INTERNAL_PORT}"
_engine_proc = None
_engine_ready = False
def start_engine():
"""Start internal engine via werkzeug (process = python3, NOT granian/searxng)."""
global _engine_proc, _engine_ready
os.environ["SEARXNG_SETTINGS_PATH"] = "/etc/searxng/settings.yml"
launcher = "/tmp/eng.py"
with open(launcher, "w") as lf:
lf.write(f"""
import os, sys
os.environ["SEARXNG_SETTINGS_PATH"] = "/etc/searxng/settings.yml"
sys.path.insert(0, "/usr/local/searxng")
os.chdir("/usr/local/searxng")
from searx.webapp import app
from werkzeug.serving import run_simple
run_simple("127.0.0.1", {INTERNAL_PORT}, app, threaded=True, use_reloader=False)
""")
_engine_proc = subprocess.Popen(
[sys.executable, launcher],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd="/usr/local/searxng",
)
print(f"Engine starting (pid={_engine_proc.pid})...", flush=True)
for i in range(120):
if _engine_proc.poll() is not None:
stderr = _engine_proc.stderr.read().decode()[-500:]
print(f"Engine died: {stderr}", flush=True)
return
try:
resp = httpx.get(f"{INTERNAL_URL}/", timeout=2.0)
if resp.status_code == 200:
_engine_ready = True
print(f"Engine ready after {i+1}s", flush=True)
return
except Exception:
pass
time.sleep(1)
print("Engine timeout after 120s", flush=True)
@app.on_event("startup")
async def startup():
threading.Thread(target=start_engine, daemon=True).start()
@app.on_event("shutdown")
async def shutdown():
if _engine_proc:
_engine_proc.terminate()
@app.get("/")
async def root():
return {"status": "ok", "service": "meta-api", "version": "6.0.0", "engine": "ready" if _engine_ready else "starting"}
@app.get("/health")
async def health():
return {"status": "healthy" if _engine_ready else "starting", "engine": "ready" if _engine_ready else "initializing"}
@app.get("/search")
async def search(
q: str = Query(...),
format: str = Query("json"),
categories: str = Query("general"),
language: str = Query("en"),
time_range: str = Query(None),
pageno: int = Query(1),
):
if not _engine_ready:
return JSONResponse(status_code=503, content={"error": "Engine still starting", "results": []})
params = {"q": q, "format": "json", "categories": categories, "language": language, "pageno": pageno}
if time_range:
params["time_range"] = time_range
try:
async with httpx.AsyncClient(timeout=20.0) as client:
resp = await client.get(f"{INTERNAL_URL}/search", params=params)
if resp.status_code == 200:
return JSONResponse(content=resp.json())
return JSONResponse(status_code=resp.status_code, content={"error": f"Engine {resp.status_code}", "results": []})
except Exception as e:
return JSONResponse(status_code=503, content={"error": str(e), "results": []})
if __name__ == "__main__":
port = int(os.environ.get("GRANIAN_PORT", os.environ.get("PORT", 7860)))
uvicorn.run(app, host="0.0.0.0", port=port, log_level="info")