BF-Realtime-V2 / app.py
SamiKoen
Use WhatsApp BF-WAB smart_warehouse_with_price + prompts (proven quality)
e325b6a
Raw
History Blame Contribute Delete
5.24 kB
"""BF-Realtime V2 — FastAPI entry point.
Sadece routing ve startup logic. Tum is logic'i ayri modullerde:
- product_index: Trek katalog XML parse + hash index
- product_matcher: fuzzy ana urun + renk varyanti eslestirme
- stock_service: BizimHesap + Trek PHP stok cache
- tools: get_warehouse_stock implementasyonu
- realtime_relay: OpenAI Realtime WS proxy
"""
from __future__ import annotations
import asyncio
import logging
from fastapi import FastAPI, WebSocket
from fastapi.responses import FileResponse, JSONResponse, Response
from fastapi.staticfiles import StaticFiles
from config import (
OPENAI_API_KEY,
REALTIME_MODEL,
REFRESH_INTERVAL,
)
from product_index import background_refresh_loop, get_index
from product_matcher import find_main_product_in_text
from realtime_relay import realtime_relay
from stock_service import (
cached_bh,
cached_bh_inventory,
get_cached_warehouse_xml,
)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI(title="BF-Realtime V2")
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.on_event("startup")
async def _startup():
"""Background refresh tasks — index + warehouse XML her saatte tazelenir."""
async def warehouse_loop():
while True:
try:
await asyncio.to_thread(get_cached_warehouse_xml)
except Exception:
logger.exception("warehouse refresh hatasi")
await asyncio.sleep(REFRESH_INTERVAL)
asyncio.create_task(background_refresh_loop(REFRESH_INTERVAL))
asyncio.create_task(warehouse_loop())
# ---------- Frontend ----------
@app.get("/")
async def root():
return FileResponse("static/index.html")
@app.get("/health")
async def health():
idx = get_index()
return {
"status": "ok",
"model": REALTIME_MODEL,
"has_api_key": bool(OPENAI_API_KEY),
"index_main_count": idx.main_count,
}
# ---------- Realtime WebSocket ----------
@app.websocket("/ws")
async def ws_endpoint(client_ws: WebSocket):
await realtime_relay(client_ws)
# ---------- Public proxy: warehouse XML (digerservisler kullaniyor) ----------
@app.get("/warehouse-xml")
async def warehouse_xml():
xml = await asyncio.to_thread(get_cached_warehouse_xml)
if not xml:
return Response(
content='<?xml version="1.0" encoding="UTF-8"?>\n<Products></Products>',
media_type="application/xml",
headers={"Cache-Control": "no-cache"},
)
return Response(
content=xml,
media_type="application/xml",
headers={
"Access-Control-Allow-Origin": "*",
"Cache-Control": "public, max-age=300",
},
)
# ---------- Public proxy: BizimHesap raw (tavsiye/sold/diger client'lar) ----------
@app.get("/bh/products")
async def bh_products():
from stock_service import bh_get
from config import BIZIMHESAP_BASE, CACHE_TTL_BH_PRODUCTS
data, status = await asyncio.to_thread(
cached_bh,
"products",
lambda: bh_get(f"{BIZIMHESAP_BASE}/products"),
CACHE_TTL_BH_PRODUCTS,
)
if data is None:
return JSONResponse(
{"resultCode": 0, "errorText": "BizimHesap fetch failed", "data": None},
status_code=502,
)
return JSONResponse(
data,
headers={
"Access-Control-Allow-Origin": "*",
"X-Cache": status,
"Cache-Control": "public, max-age=300",
},
)
@app.get("/bh/warehouses")
async def bh_warehouses():
from stock_service import bh_get
from config import BIZIMHESAP_BASE, CACHE_TTL_BH_WAREHOUSES
data, status = await asyncio.to_thread(
cached_bh,
"warehouses",
lambda: bh_get(f"{BIZIMHESAP_BASE}/warehouses"),
CACHE_TTL_BH_WAREHOUSES,
)
if data is None:
return JSONResponse(
{"resultCode": 0, "errorText": "BizimHesap fetch failed", "data": None},
status_code=502,
)
return JSONResponse(
data,
headers={
"Access-Control-Allow-Origin": "*",
"X-Cache": status,
"Cache-Control": "public, max-age=300",
},
)
@app.get("/bh/inventory/{wid}")
async def bh_inventory(wid: str):
data, status = await asyncio.to_thread(cached_bh_inventory, wid)
if data is None:
return JSONResponse(
{"resultCode": 0, "errorText": "BizimHesap fetch failed", "data": None},
status_code=502,
)
return JSONResponse(
data,
headers={
"Access-Control-Allow-Origin": "*",
"X-Cache": status,
"Cache-Control": "public, max-age=300",
},
)
# ---------- Debug ----------
@app.get("/debug-find")
async def debug_find(q: str):
p = find_main_product_in_text(q)
return {"query": q, "matched": (p.get("name") if p else None), "result": p}
@app.get("/debug-search")
async def debug_search(q: str):
from smart_warehouse_with_price import get_warehouse_stock_smart_with_price
result = await asyncio.to_thread(get_warehouse_stock_smart_with_price, q)
return {"query": q, "result": result}