SUT-Tender-API / main.py
Therdpoom's picture
Upload main.py
9c6fecc verified
Raw
History Blame Contribute Delete
3.35 kB
"""
main.py
FastAPI app สำหรับ Hugging Face Space (Docker)
- ดึงข้อมูล e-GP ของ SUT ครั้งเดียวตอน startup แล้ว cache ไว้ใน memory
- เปิด endpoint ให้ frontend (Lovable) เรียกไปแสดงผล
- มี endpoint /refresh สำหรับสั่งดึงข้อมูลใหม่แบบ manual (ไม่ auto-refresh)
"""
from fastapi import FastAPI, Query
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
from typing import Optional
import logging
from scraper import scrape_all
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("sut-tender-api")
# cache เก็บข้อมูลไว้ใน memory ของ process
CACHE: dict = {"data": [], "last_updated": None, "error": None}
@asynccontextmanager
async def lifespan(app: FastAPI):
# ดึงข้อมูลครั้งเดียวตอน startup ตามที่ตกลงกันไว้
refresh_cache()
yield
app = FastAPI(title="SUT Tender API", lifespan=lifespan)
# เปิด CORS ให้ Lovable (หรือ origin ใดๆ) เรียกได้
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
def refresh_cache():
import datetime
try:
logger.info("Scraping SUT e-GP data...")
data = scrape_all()
CACHE["data"] = data
CACHE["last_updated"] = datetime.datetime.utcnow().isoformat()
CACHE["error"] = None
logger.info(f"Done. Got {len(data)} items.")
except Exception as e:
logger.exception("Scrape failed")
CACHE["error"] = str(e)
@app.get("/")
def root():
return {
"status": "ok",
"items_cached": len(CACHE["data"]),
"last_updated": CACHE["last_updated"],
"error": CACHE["error"],
}
@app.get("/api/tenders")
def get_tenders(
keyword: Optional[str] = Query(
None,
description="กรองคำในชื่อโครงการ รองรับหลายคำคั่นด้วย comma เช่น 'server,คอมพิวเตอร์,computer' (เจอคำใดคำหนึ่งก็ติด)",
),
limit: int = Query(50, ge=1, le=500),
offset: int = Query(0, ge=0),
):
items = CACHE["data"]
if keyword:
# แตกคำด้วย comma แล้ว trim whitespace, ตัดคำว่างทิ้ง
keywords = [kw.strip().lower() for kw in keyword.split(",") if kw.strip()]
if keywords:
items = [
i for i in items
if any(kw in i["title"].lower() for kw in keywords)
]
total = len(items)
items = items[offset: offset + limit]
return {
"total": total,
"limit": limit,
"offset": offset,
"last_updated": CACHE["last_updated"],
"items": items,
}
@app.post("/refresh")
def refresh():
"""สั่งดึงข้อมูลใหม่แบบ manual (ไม่ auto-refresh ตามที่ตกลงไว้)"""
refresh_cache()
return {"status": "refreshed", "items_cached": len(CACHE["data"]), "error": CACHE["error"]}