v1.1.0: AI分析历史记录 + 数据源详情页(/analysis/<id>),展示大模型参考的RAG新闻/概况/指标/评级/持仓/提示词
This commit is contained in:
+58
-1
@@ -59,6 +59,7 @@ def _rag_news(code, stock_name, query_text, top_k=6):
|
||||
"date": m.get("date", ""),
|
||||
"sentiment": m.get("sentiment", 0),
|
||||
"text": h.get("document", "")[:400],
|
||||
"distance": round(h.get("distance", 0), 3),
|
||||
})
|
||||
return out
|
||||
except Exception as e:
|
||||
@@ -140,7 +141,8 @@ def _build_prompt(stock, ind, news_hits, profile, ratings, holdings, score, focu
|
||||
|
||||
|
||||
def generate_report_sync(code, focus=""):
|
||||
"""同步生成报告(后台线程调用)"""
|
||||
"""同步生成报告(后台线程调用),并记录历史 + 数据源"""
|
||||
import json
|
||||
stock = query_one("SELECT * FROM stocks WHERE code=?", (code,))
|
||||
if not stock:
|
||||
return {"error": "股票不存在"}
|
||||
@@ -150,6 +152,17 @@ def generate_report_sync(code, focus=""):
|
||||
profile = _rag_profile(code)
|
||||
ratings, holdings = _inst_summary(code)
|
||||
prompt = _build_prompt(stock, ind, hits, profile, ratings, holdings, score, focus)
|
||||
# 记录大模型参考的数据源(供详情页展示)
|
||||
sources = {
|
||||
"focus": focus,
|
||||
"score": score,
|
||||
"indicators": _fmt_indicators(ind),
|
||||
"profile": profile or stock.get("description", ""),
|
||||
"news": hits,
|
||||
"ratings": ratings,
|
||||
"holdings": holdings,
|
||||
"prompt": prompt,
|
||||
}
|
||||
try:
|
||||
report = llm_chat([
|
||||
{"role": "system", "content": "你是一名严谨专业的A股投资顾问,输出结构化、简洁、可执行的研报。"},
|
||||
@@ -160,6 +173,10 @@ def generate_report_sync(code, focus=""):
|
||||
raise RuntimeError("LLM 返回为空")
|
||||
execute("INSERT OR REPLACE INTO analysis_cache(code, report, created_at) VALUES(?,?,datetime('now','localtime'))",
|
||||
(code, report))
|
||||
execute(
|
||||
"INSERT INTO analysis_history(code, stock_name, focus, report, sources, created_at) "
|
||||
"VALUES(?,?,?,?,?,datetime('now','localtime'))",
|
||||
(code, stock["name"], focus, report, json.dumps(sources, ensure_ascii=False)))
|
||||
return {"report": report, "ts": time.time()}
|
||||
except Exception as e:
|
||||
log.exception("gen report fail")
|
||||
@@ -221,3 +238,43 @@ def report_status(code):
|
||||
|
||||
def get_cached_report(code):
|
||||
return query_one("SELECT report, created_at FROM analysis_cache WHERE code=?", (code,))
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ 历史记录
|
||||
def list_history(code, limit=20):
|
||||
"""某股票的历史 AI 分析记录(不含正文,只返回摘要)"""
|
||||
rows = query(
|
||||
"SELECT id, code, stock_name, focus, created_at, sources, LENGTH(report) AS len, "
|
||||
"SUBSTR(report, 1, 60) AS excerpt FROM analysis_history "
|
||||
"WHERE code=? ORDER BY id DESC LIMIT ?", (code, limit))
|
||||
out = []
|
||||
for r in rows:
|
||||
try:
|
||||
import json
|
||||
src = json.loads(r.get("sources") or "{}")
|
||||
except Exception:
|
||||
src = {}
|
||||
out.append({
|
||||
"id": r["id"], "code": r["code"], "stock_name": r["stock_name"],
|
||||
"focus": r["focus"], "created_at": r["created_at"],
|
||||
"chars": r["len"], "excerpt": (r["excerpt"] or "").strip(),
|
||||
"news_count": len(src.get("news") or []),
|
||||
})
|
||||
return out
|
||||
|
||||
|
||||
def get_history(aid):
|
||||
"""单条分析详情:正文 + 数据源 JSON"""
|
||||
import json
|
||||
row = query_one("SELECT * FROM analysis_history WHERE id=?", (aid,))
|
||||
if not row:
|
||||
return None
|
||||
try:
|
||||
src = json.loads(row.get("sources") or "{}")
|
||||
except Exception:
|
||||
src = {}
|
||||
return {
|
||||
"id": row["id"], "code": row["code"], "stock_name": row["stock_name"],
|
||||
"focus": row["focus"], "report": row["report"], "created_at": row["created_at"],
|
||||
"sources": src,
|
||||
}
|
||||
Reference in New Issue
Block a user