v1.1.0: 真实网页采集(可读正文全文入库) + 大模型接口多预置一键切换(SiliconFlow默认) + 数据源可编辑
- 新增 crawler.py: requests+bs4 readability风格清洗, 提取候选链接按文章相似度排序, 前5条抓全文存 articles.full_text, 详情页展示; example.com占位源走模拟, 真实源失败标记error不造假 - 大模型: 新增 llm_providers 表(预置 SiliconFlow/DeepSeek官方/Autodl/Local Qwen), 设置页增删改/测试/一键切换, 激活接口失败自动切换备用 - 数据源: 前端补编辑按钮+弹窗(后端 update 已支持), 列表显示URL与采集状态 - 数据库迁移: articles.full_text 列 + llm_providers 表
This commit is contained in:
@@ -8,6 +8,8 @@ from datetime import datetime, timedelta
|
||||
|
||||
from flask import Flask, render_template, request, jsonify, redirect, url_for
|
||||
|
||||
import requests
|
||||
|
||||
import config
|
||||
import db
|
||||
import simulate
|
||||
@@ -87,7 +89,8 @@ def logs():
|
||||
|
||||
@app.route("/settings")
|
||||
def settings_page():
|
||||
return render_template("settings.html", auto=db.get_all_settings())
|
||||
return render_template("settings.html", auto=db.get_all_settings(),
|
||||
providers=db.list_providers())
|
||||
|
||||
|
||||
# ---------------- API ----------------
|
||||
@@ -170,6 +173,69 @@ def api_settings():
|
||||
return jsonify({"ok": True})
|
||||
|
||||
|
||||
@app.route("/api/llm", methods=["POST"])
|
||||
def api_llm():
|
||||
"""大模型接口管理:增删改 / 一键切换 / 测试"""
|
||||
data = request.get_json(force=True) or {}
|
||||
action = data.get("action")
|
||||
if action == "add":
|
||||
pid = db.add_provider(
|
||||
data.get("name", ""), data.get("base_url", ""), data.get("api_key", ""),
|
||||
data.get("model", ""),
|
||||
active=1 if data.get("active") else 0,
|
||||
enabled=1 if data.get("enabled", 1) else 0,
|
||||
)
|
||||
if data.get("active"):
|
||||
db.set_active_provider(pid)
|
||||
return jsonify({"ok": True, "id": pid})
|
||||
if action == "update":
|
||||
db.update_provider(data["id"], name=data.get("name"), base_url=data.get("base_url"),
|
||||
api_key=data.get("api_key"), model=data.get("model"),
|
||||
enabled=1 if data.get("enabled", 1) else 0)
|
||||
return jsonify({"ok": True})
|
||||
if action == "delete":
|
||||
db.delete_provider(data["id"])
|
||||
return jsonify({"ok": True})
|
||||
if action == "switch":
|
||||
db.set_active_provider(data["id"])
|
||||
p = db.get_provider(data["id"])
|
||||
return jsonify({"ok": True, "name": p["name"] if p else ""})
|
||||
if action == "toggle":
|
||||
p = db.get_provider(data["id"])
|
||||
if not p:
|
||||
return jsonify({"ok": False, "error": "not found"})
|
||||
db.update_provider(data["id"], enabled=0 if p["enabled"] else 1)
|
||||
return jsonify({"ok": True})
|
||||
if action == "test":
|
||||
# 用指定接口(或当前激活接口)发一条测试消息
|
||||
cfg = None
|
||||
if data.get("id"):
|
||||
p = db.get_provider(data["id"])
|
||||
if p and p.get("base_url"):
|
||||
cfg = {"name": p["name"], "base_url": p["base_url"].rstrip("/"),
|
||||
"api_key": p.get("api_key", ""), "model": p.get("model", "")}
|
||||
try:
|
||||
if cfg is None:
|
||||
import analysis
|
||||
cfg = analysis.get_llm_cfg()
|
||||
r = requests.post(
|
||||
f"{cfg['base_url']}/chat/completions",
|
||||
headers={"Authorization": f"Bearer {cfg['api_key']}",
|
||||
"Content-Type": "application/json"},
|
||||
json={"model": cfg["model"],
|
||||
"messages": [{"role": "user", "content": "请回复:连接正常"}],
|
||||
"max_tokens": 60, "temperature": 0.3},
|
||||
timeout=60,
|
||||
)
|
||||
r.raise_for_status()
|
||||
content = r.json()["choices"][0]["message"]["content"]
|
||||
return jsonify({"ok": True, "name": cfg["name"], "model": cfg["model"],
|
||||
"reply": content})
|
||||
except Exception as e:
|
||||
return jsonify({"ok": False, "error": str(e)})
|
||||
return jsonify({"ok": False, "error": "unknown action"})
|
||||
|
||||
|
||||
@app.route("/api/actions", methods=["POST"])
|
||||
def api_actions():
|
||||
data = request.get_json(force=True) or {}
|
||||
@@ -223,6 +289,13 @@ def main():
|
||||
db.add_domain(d, w)
|
||||
for c in config.DEFAULT_COMPANIES:
|
||||
db.add_company(c)
|
||||
# 预置大模型接口(可一键切换)
|
||||
if not db.list_providers():
|
||||
for p in config.LLM_PROVIDERS_DEFAULT:
|
||||
pid = db.add_provider(p["name"], p["base_url"], p["api_key"], p["model"],
|
||||
active=1 if p.get("active") else 0)
|
||||
if p.get("active"):
|
||||
db.set_active_provider(pid)
|
||||
db.set_setting("initialized", 1)
|
||||
db.set_setting("auto", dict(config.AUTO_DEFAULTS))
|
||||
db.set_setting("mail", dict(config.MAIL_DEFAULTS))
|
||||
|
||||
Reference in New Issue
Block a user