Files
nba-fan-hub/api.py
T

175 lines
5.5 KiB
Python

# -*- coding: utf-8 -*-
"""NBA球迷大全 - Flask 服务入口(API + 前端静态页)"""
import logging
import os
from flask import Flask, jsonify, request, send_from_directory
from config import STATIC_DIR, SERVICE_NAME, SERVICE_PORT, SERVICE_HOST
from db import init_db, table_count, query_one
import tools
import chat
import vector_store
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("app")
app = Flask(__name__, static_folder=None)
app.config["JSON_AS_ASCII"] = False
# ------------------------------------------------------------------ 页面
@app.route("/")
def index():
return send_from_directory(STATIC_DIR, "index.html")
@app.route("/static/<path:path>")
def static_files(path):
return send_from_directory(STATIC_DIR, path)
# ------------------------------------------------------------------ 健康/统计
@app.route("/api/health")
def health():
return jsonify({"status": "ok", "service": SERVICE_NAME,
"db": {t: table_count(t) for t in ("teams", "players", "games", "news", "persons")},
"vector_docs": vector_store.collection_count()})
@app.route("/api/suggestions")
def suggestions():
return jsonify(chat.suggest_questions())
# ------------------------------------------------------------------ 对话
@app.route("/api/chat", methods=["POST"])
def api_chat():
body = request.get_json(force=True, silent=True) or {}
message = (body.get("message") or "").strip()
history = body.get("history") or []
if not message:
return jsonify({"error": "消息不能为空"}), 400
try:
reply, sources, used_tools = chat.chat_once(message, history)
return jsonify({"reply": reply, "sources": sources, "used_tools": used_tools})
except Exception as e:
log.exception("chat error")
return jsonify({"error": f"服务异常: {e}"}), 500
# ------------------------------------------------------------------ 球队
@app.route("/api/teams")
def api_teams():
q = request.args.get("q", "")
r = tools.search_teams(q, limit=int(request.args.get("limit", 50)))
return jsonify(r.get("results", []))
@app.route("/api/teams/<int:tid>")
def api_team(tid):
t = tools.get_team(tid)
if not t:
return jsonify({"error": "not found"}), 404
roster = tools.search_players(t["name"], limit=20)["results"]
games = tools.search_games(t["name"], limit=10)["results"]
return jsonify({"team": t, "roster": roster, "recent_games": games})
# ------------------------------------------------------------------ 球员
@app.route("/api/players")
def api_players():
q = request.args.get("q", "")
r = tools.search_players(q, limit=int(request.args.get("limit", 60)))
return jsonify(r.get("results", []))
@app.route("/api/players/<int:pid>")
def api_player(pid):
p = tools.get_player(pid)
if not p:
return jsonify({"error": "not found"}), 404
return jsonify(p)
# ------------------------------------------------------------------ 比赛
@app.route("/api/games")
def api_games():
q = request.args.get("q", "")
status = request.args.get("status", "")
limit = int(request.args.get("limit", 30))
r = tools.search_games(q, limit=limit)
results = r.get("results", [])
if status:
results = [g for g in results if g["status"] == status]
return jsonify(results)
@app.route("/api/games/<int:gid>")
def api_game(gid):
g = tools.get_game_detail(gid)
if not g:
return jsonify({"error": "not found"}), 404
return jsonify(g)
# ------------------------------------------------------------------ 排名
@app.route("/api/standings")
def api_standings():
conf = request.args.get("conf", "")
r = tools.search_standings(conf, limit=30)
return jsonify(r.get("results", []))
# ------------------------------------------------------------------ 新闻
@app.route("/api/news")
def api_news():
q = request.args.get("q", "")
kind = request.args.get("kind", "")
limit = int(request.args.get("limit", 20))
if q:
r = tools.search_news(q, limit=limit)
return jsonify(r.get("results", []))
from db import query
rows = query("""SELECT id,title,author,source,publish_time,tags,kind,substr(content,1,160) AS summary
FROM news WHERE (?='' OR kind=?) ORDER BY publish_time DESC, id DESC LIMIT ?""",
(kind, kind, limit))
return jsonify(rows)
@app.route("/api/news/<int:nid>")
def api_news_detail(nid):
from db import query_one as q1
n = q1("SELECT * FROM news WHERE id=?", (nid,))
if not n:
return jsonify({"error": "not found"}), 404
return jsonify(n)
# ------------------------------------------------------------------ 人物
@app.route("/api/persons")
def api_persons():
q = request.args.get("q", "")
role = request.args.get("role", "")
limit = int(request.args.get("limit", 50))
r = tools.search_persons(q, limit=limit)
results = r.get("results", [])
if role:
results = [p for p in results if p["role"] == role]
return jsonify(results)
@app.route("/api/persons/<int:pid>")
def api_person(pid):
r = tools.search_persons("", limit=100)
p = next((x for x in r["results"] if x["id"] == pid), None)
if not p:
return jsonify({"error": "not found"}), 404
return jsonify(p)
if __name__ == "__main__":
init_db()
log.info("%s 启动于 http://%s:%s", SERVICE_NAME, SERVICE_HOST, SERVICE_PORT)
app.run(host=SERVICE_HOST, port=SERVICE_PORT, threaded=True)