# -*- 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/") 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/") 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/") 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/") 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/") 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/") 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)