Commit Graph

32 Commits

Author SHA1 Message Date
Elvis Wang
972c314656 feat: Web/API 指数入口与共享 canonical 去重基础 (#2312)
* feat: Web/API 指数入口与共享 canonical 去重基础

为 Issue #2303 Phase 2 PR1 落地 Web/API 指数入口适配:

- API 使用 parse_analysis_target 构造结构化 AnalysisTarget 并贯通到 pipeline
- API 与 TaskQueue 去重按 asset_type 分支(指数用 canonical_id,个股用 legacy code)
- BatchTaskAcceptedResponse 追加可选 rejected 字段,未登记 CSI 单股 400、批量仅该目标失败
- TaskInfo 固化 dedupe_key,避免指数与同码个股折叠及 _analyzing_stocks 残留
- Web 移除 assetType=index 全局过滤,Chat 名称识别保护指数 canonical
- 补齐 Pipeline 指数 DecisionSignal market_override=cn 真实分支测试

* fix: 收敛指数 canonical 身份与批量响应契约

PR #2312 review 修复:报告 meta 补充 asset_type 隐藏指数自选;/analyze 在解析前限制非空原始 token;is_single 统一驱动 metadata/409/单任务 202;HomePage 三元计数继续后续 chunk。

* fix: avoid double space in index news search query

* fix: preserve canonical index identity

* fix: validate legacy task asset type

* fix: preserve canonical index identity in chat

* fix: preserve index identity across chat backends
2026-09-01 19:25:15 +08:00
青玉案
d0e66a1dc3 feat: 新闻检索为空时在报告中如实标注 (#2229)
* feat: 新闻检索为空时在报告中如实标注

消息面章节此前是「有内容才渲染」,检索一条没拿到时整段直接消失,
读报告的人无从判断是确实没新闻,还是检索静默失败了(搜索源限流、
未配置可用渠道等)。这把「抓取失败」呈现成了「确实没有新闻」。

- src/analyzer.py: AnalysisResult 新增 news_result_count,默认 None
- src/core/pipeline.py: 把 Step 4 已算好的计数交给结果对象
  (此前只进了 diagnostic context snapshot,报告层拿不到)
- src/notification.py: news_lines 为空且计数为 0 时,渲染明确提示,
  并说明结论未纳入新闻维度证据
- tests: 新增 5 条用例,含两条负例——计数为 None 时不得报警
  (那是未配置搜索渠道,不是失败)、拿到新闻时行为与改动前一致

不触碰任何检索路径,纯展示层增量。

* fix: 把新闻缺失提示放进真实渲染路径,并独立于模型输出判定

按 review 三条意见修正:

P1-1 提示只存在于 generate_daily_report,而正常流程从不调用它——
_send_single_stock_notification 与聚合报告走的是 dashboard / brief /
single_stock。原实现对所有标准 REPORT_TYPE 都不生效。
改为抽出共享判定 _empty_news_disclosure,四个渲染器统一接入。

P2 检索零命中但模型按 schema 写出了 market_sentiment / hot_topics 时,
原 elif 分支被跳过,报告会展示模型生成的情绪判断却隐瞒无新闻证据。
改为独立判定 news_result_count == 0,与模型是否产出文字无关。

P1-2 补 docs/CHANGELOG.md [Unreleased] 条目,并在
docs/data-source-stability.md 的「用户可见提示建议」一节记录该行为,
含 None / 0 / >0 三态语义表。

测试从 5 条增至 10 条,新增覆盖 dashboard、brief、single_stock 三个真实
渲染器,以及「模型有输出但检索为空」这一最糟组合。39 passed

* fix: 把新闻零命中披露覆盖到模板链路与企业微信入口

按 review 指出的 blocker 修正。此前只接了字符串拼接分支,遗漏两类活路径:

1. REPORT_RENDERER_ENABLED=true 时,generate_dashboard_report /
   generate_brief_report / generate_wechat_dashboard 会先 return render(...),
   模板链路一路不渲染披露;
2. generate_wechat_dashboard 的非模板 fallback 从未接入,而 pipeline 在
   企业微信非 brief 场景会直接调用它。

后果是同一份分析结果在部分渠道披露、在另一些渠道沉默。

改法不再逐点打补丁,而是抽出单一事实来源:

- 新增 src/services/empty_news.py 持有判定与中英文案
- src/notification.py 的 _empty_news_disclosure 改为委托该模块
- src/services/report_renderer.py 为每条结果预计算 empty_news_disclosure,
  三个平台模板共用
- templates/report_markdown.j2 / report_brief.j2 / report_wechat.j2 各加渲染分支
- generate_wechat_dashboard 的 fallback 正文接入披露

新增 6 条回归测试:模板链路三个平台各一条、企业微信入口一条,
外加两条负例(未执行检索时模板与企业微信均不得提示)。

本文件测试 10 → 16 全过;全量 5824 passed,9 个既有失败与本 PR 无关
(干净 main 上同样失败,属测试顺序依赖)。

* fix: 修正计数源头的两处缺口(自查发现)

按 review 的 merge-base..HEAD 方法自查全链路,发现此前几轮都只盯着渲染出口,
从未核对计数源头,而源头本身在两条路径上是错的:

1. src/core/pipeline.py: news_result_count 只在 intel_results 非空时赋值,
   搜索服务整体失败(正是所有搜索源限流全挂的场景)时停留在 None,
   语义为「未执行检索」,于是本 PR 想解决的头号场景反而不提示。
   改为检索一发起即置 0。

2. _analyze_with_agent: Agent 模式自行调用 search_stock_news 完成检索,
   却从不回写计数,该路径下零命中永远静默。改为按检索结果回写 0 或实际条数。

渲染层再周全,源头数据不对则全部落空。

新增 2 条测试锁住这两处语义(18 passed,此前 16)。
全量 5826 passed,9 个既有失败与本 PR 无关。

* fix: disclose missing news search configuration

* chore: remove unrelated agent guidance

* test: run all empty news tests directly

* fix: preserve empty news disclosure across reports

* fix: 让 Agent 模式的新闻披露跟随实际消费的证据

原问题:agent_arch=multi 等受支持的 Agent 配置下,报告可能声称「未纳入新闻
面证据」而分析其实用了新闻,或反过来该提示而不提示。

根因:news_result_count 取自 executor.run() 结束后为持久化情报补打的一次
search_stock_news()。真实情报由 IntelAgent 通过 search_comprehensive_intel
取得,两者不等价,因此披露与真实证据链可能相反。

修复点:新增 src/agent/news_evidence.py,以运行期证据作用域收集 Agent 搜索
工具的真实返回条数;搜索渠道不可用为 None(未执行检索),可用则从 0 起步、
拿到多少算多少。pipeline 在 executor.run() 前后开启并读取该作用域,事后的
持久化补查不再回写计数。

回归风险:工具在 ThreadPoolExecutor 中执行,runner.py 以
contextvars.copy_context() 提交,故作用域中必须是可变累加器对象,换成不可变
值会让父线程读不到;已加回归测试锁住该机制。原 test_agent_path_records_count
断言的正是被修复的错误行为,已替换为反向断言。

Refs #2225

* fix: 让新闻披露以实际证据为准而非搜索命中数

原问题:本地已落库的资讯池或社交情绪进入 news_context 参与分析后,报告仍可能
声称「未配置搜索渠道,本次分析未纳入新闻面证据」或「零命中」。

根因:news_context 由三路来源拼成——实时检索、社交情绪(美股)、本地资讯池,
但只有实时检索会更新 news_result_count。披露断言的是「结论有没有用到新闻面
证据」,而计数只是「搜索命中了几条」,两者是不同命题,后两路参与时必然失真。

修复点:AnalysisResult 新增 news_evidence_present,由 news_context 是否非空
得出,pipeline 两条路径共用 src/services/empty_news.news_evidence_present()
这一个判定函数。披露改为先看有无证据;确无证据时才用计数解释原因
(None=未配置渠道,0=检索零命中)。历史重建同步恢复该字段。

回归风险:旧记录没有该字段,按计数回退推断,与该记录当时的报告表现一致,不会
追溯改变旧报告;已有用例锁住。review 只点名了本地资讯池,社交情绪属同一缺陷类,
本次一并修复并加测试。另加源码断言:任一 pipeline 路径改回只传计数即失败。

Refs #2225

* fix: 按来源登记新闻证据,不让零命中占位文本冒充证据

原问题:普通分析链路在「搜索已执行但一条证据都没拿到」时,报告不再显示零命中
披露——正是本 PR 要修的核心场景,反而比改动前更差。

根因:src/search_service.py 的 format_intel_report() 即使所有维度失败或为空,
也会输出「【XX 情报搜索结果】」标题和每个维度的「未找到相关信息」占位文本,
整段永远非空。上一版把拼好的 news_context 整段交给 news_evidence_present()
判定,于是 news_result_count == 0 时 evidence 被翻成 true,披露被吞掉,错误
状态还会经 to_dict() 持久化,继续影响历史、详情 API 与 Web。

修复点:判定改为按来源逐个登记——实时检索的真实命中数、社交情绪内容、本地
资讯池内容,任一为真才算有证据;两条 pipeline 路径都不再传拼好的整段。
news_evidence_present() 的契约随之改为接收各来源,并在文档串里写明为什么不能
传整段。

回归风险:新增反例用真实的 format_intel_report() 产出占位文本(不用 mock),
断言其不得被判成证据、且报告必须出现零命中披露。另有源码断言:谁把整段
news_context 交回判定函数即失败。上一版两条测试实际在保护该缺陷(一条名为
「任何非空 context 都算证据」,一条要求必须传入 news_context),已一并纠正。

Refs #2225

---------

Co-authored-by: Mach-Chan <zz-b240@zz-b240deMacBook-Air.local>
2026-08-22 21:27:04 +08:00
zhulinsen
46d5bf3472 fix: 恢复桌面端报告分享图 (#2169)
* fix: enable desktop report share images

* fix: include default share image branding

* fix(review-feedback-2169): Keep custom branding paired with its QR code

* fix: show default share image nickname

* fix(review-feedback-2169): Document the atomic branding fallback

* fix(review-feedback-2169): Remove the hard-coded social account default

* fix(review-feedback-2169): Remove the bundled account QR fallback

* fix(review-feedback-2169): update docs/share-images

* fix(review-feedback-2169): [Verification blocker] 当前 Head 的阻断型 CI

* fix(review-feedback-2169): 补一条回归:用包含超长 fenced-code 行和超长原始 URL 的完整/通用报告分别走 build share image html
2026-08-09 13:53:00 +08:00
zhulinsen
91988da149 feat: 添加报告分享图片与 Web 一键分享 (#2146)
* feat: add report image sharing

* fix(review-feedback-2146): 评审结论 - 代码检查 :当前整个 PR 仍有 2 个未关闭的高置信度代码 blocker。最新复核摘要:基于 merge-base

* fix(review-feedback-2146): preserve the Markdown fallback for unavailable snapshots and preserve

* fix(review-feedback-2146): 补一组通知回归测试,至少覆盖

* fix(review-feedback-2146): 在源码树执行 npm ci 和 npx playwright install chromium,这与预编译 desktop 发行包环境不一致

* fix(review-feedback-2146): 评审结论 - 代码检查 :当前整个 PR 仍有 1 个未关闭的高置信度代码 blocker。最新复核摘要:基于 merge-base

* fix(review-feedback-2146): 补上明确的 CLI/Chromium 安装提示,避免当前日志和 503 文案继续把用户引向

* fix(review-feedback-2146): 补到与 docs/share-images.md 一致,直接提示 cd apps/dsa-web && npm ci 和 npx
2026-08-02 16:45:37 +08:00
lyl2104626211
68fc575f15 feat: 支持 Web/API 按市场触发大盘复盘 (#2074)
* feat: add request-scoped market review regions

* fix: keep server default runtime-resolved

* fix: trace market review regions through task lifecycle

---------

Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-07-25 22:14:15 +08:00
Kushida
44371c2961 fix: delete all history records by stock code (#1987)
* fix: delete all history records by stock code

* fix: reject blank history stock codes

---------

Co-authored-by: zhulinsen <42829555+ZhuLinsen@users.noreply.github.com>
2026-07-12 15:02:54 +08:00
zhulinsen
6da1360a0b feat: 重建市场结构上下文 (#1981)
* feat: rebuild market structure context

* fix(review-feedback-1981): apps/dsa-web/src/components/report/MarketStructureCard.tsx 新增用户可见界面,但

* fix(review-feedback-1981): apps/dsa-web/src/components/report/MarketStructureCard.tsx 新增用户可见界面,但

* fix(review-feedback-1981): Scope in-flight ranking keys to each fetcher manager

* fix(review-feedback-1981): 修正无证据情况下的个股层级判定,并按仓库规范补充可访问的 Web 页面截图、更新 PR 描述事实

* fix(review-feedback-1981): apps/dsa-web/src/components/report/MarketStructureCard.tsx 新增用户可见界面,但

* fix(review-feedback-1981): 按 AGENTS.md 为新增市场结构卡片补充可直接查看的截图,并同步 PR 描述中的 diff 与 CI 事实

* fix(review-feedback-1981): apps/dsa-web/src/components/report/MarketStructureCard.tsx 新增用户可见界面,但

* fix(review-feedback-1981): 按仓库规范补充可直接审查的市场结构卡片截图,并同步 PR 描述中的 diff 与 CI 事实

* fix(review-feedback-1981): apps/dsa-web/e2e/market-structure-card-visual.spec.ts:276 在

* fix(review-feedback-1981): apps/dsa-web/e2e/market-structure-card-visual.spec.ts 将本 PR

* fix(review-feedback-1981): 同步当前 Head 的 diff/CI 结论,并按仓库规范在 PR 描述或评论中附可访问的市场结构卡片截图

* fix(review-feedback-1981): apps/dsa-web/e2e/market-structure-card-visual.spec.ts:261 新增 async 空对象解构

* fix(review-feedback-1981): 按仓库规范在 PR 描述或评论中附市场结构卡片的可访问截图,并同步当前 diff 统计和 CI 结果

* fix(review-feedback-1981): 消除当前运行结果对历史持久化成功的依赖,补充对应回归测试,并补齐可访问的 UI 截图及更新失真的 PR 描述

* fix(review-feedback-1981): src/utils/data processing.py 提取榜单时丢弃了上游 boards / concept boards 的

* fix(review-feedback-1981): 修正 PR 描述并补齐可访问的视觉证据

* fix(review-feedback-1981): 关闭市场结构前置数据获取可能阻塞主分析的问题,并同步修正 PR 描述、范围清单和视觉证据

* fix(review-feedback-1981): 将 PR 描述、完整范围、当前 CI 证据、视觉证据及回滚表述同步到最新 Head

* fix(review-feedback-1981): PR 描述与最新 Head 不一致:完整 diff 包含 38 个文件及 src/services/analysis

* fix(review-feedback-1981): 按最新 Head 同步 PR 描述,并补充可访问的市场结构卡片截图证据

* fix(review-feedback-1981): 统一即时响应与历史响应的 details.raw result 契约并补最终 API 回归测试,同时更新 PR 描述和可访问的视觉证据

* fix(review-feedback-1981): 将 PR 描述、完整范围、CI 结果及可访问的 UI 截图同步到最新 Head,消除描述与实际改动的实质性不一致

* fix(review-feedback-1981): 同步 PR 描述与最新 Head,并补充可访问的 Web 页面截图

* fix(review-feedback-1981): 同步 PR 描述并按仓库规范附上可访问的 Web 页面截图

* fix(review-feedback-1981): 代码结论 :不可。已按 origin/main...76b5b596fdff 的完整 38 文件 diff 重新建立基线。上次 6 个

* fix(review-feedback-1981): 代码结论 :不可。最新修复已正确收窄无成分股、无龙头证据的原生榜单路径:该路径现在返回 edge/partial,不再直接输出
2026-07-12 11:30:59 +08:00
zhulinsen
01ebf70a10 feat: add reliable home watchlist workspace (#1984)
* feat: add reliable home watchlist workspace

* fix(review-feedback-1984): Don't trust stale stock-bar rows after refresh failures

* fix(review-feedback-1984): apps/dsa-web/src/stores/stockPoolStore.ts 的 refreshStockBar

* fix(review-feedback-1984): Clear loading when refresh supersedes initial stock-bar load

* fix(review-feedback-1984): Type stock-bar test fixtures as StockBarItem and 跟进结论 - 结论 :不接受;最新

* fix(review-feedback-1984): tying the Today fetch to the same refresh path while this tab is
2026-07-11 21:45:04 +08:00
zhulinsen
83b8154d0a fix: 评分建议过度归为持有,需收敛 hold/watch/buy/sell… (#1885) (#1887)
* fix(issue-1885): [bug]-评分建议过度归为持有,需收敛-hold/watch/buy/sell

* fix(review-feedback-1887): 澄清/修正评分与 action 的契约一致性问题,并补齐高风险路径的验证说明

* fix(review-feedback-1887): 补一句排除说明,避免和 AGENTS 对外部依赖/运行时配置变更需说明兼容、迁移与回退路径的要求产生歧义

* fix(review-feedback-1887): CI 当前未通过:结构化事实显示 backend-gate:failure,PR 描述中的本地验证也写明 test:TIMEOUT
2026-07-03 20:24:13 +08:00
zhulinsen
a448886f67 fix: restore stock bar summary badges (#1848) 2026-06-29 21:18:02 +08:00
zhulinsen
03fe7a00a9 feat: 补齐大盘报告与 Web 个股页的概念板块展示 (#1764) (#1778)
* feat(issue-1764): feat:-补齐大盘报告与-web-个股页的概念板块展示

* fix(review-feedback-1778): 确认历史报告 fallback 路径是否完整透传 conceptRankings,否则会出现新字段在部分历史详情/API 场景中静默丢失

* fix: render market review industry and concept rankings side-by-side

* fix: refine related board display and concept ranking cache
2026-06-27 23:07:18 +08:00
mumu
0ab94a8c3e fix: support KR stock autocomplete suggestions (#1723)
* fix: support KR stock autocomplete suggestions

* fix(review-feedback-1723): 补充自动补全 JP/KR 建议渲染截图、前后对比或无法截图说明

* fix(review-feedback-1723): 补充 Web 自动补全 JP/KR 建议渲染的截图或无法截图说明

* fix(review-feedback-1723): docs/review-evidence-kr-autocomplete-ui.md 是针对本 PR

* fix(review-feedback-1723): 修正 PR 描述与当前 head 的实际改动、验证范围不一致问题

* fix(review-feedback-1723): 修正 PR 描述与当前 diff 的实质性不一致,避免合入记录误导后续维护者

* fix(review-feedback-1723): 收敛 PR 描述与实际 diff 的契约不一致,避免用户误以为裸 005930 已会解析为 005930.KS

* fix(review-feedback-1723): 把描述、验证证据和兼容性说明收敛到当前 6 个改动文件真实范围,或补齐描述中声称的后端/历史链路实现与测试

* fix(review-feedback-1723): 收敛 PR 描述与实际 diff,避免把未实现的 bare-code/历史展示能力作为本 PR 已交付内容合入

* fix(review-feedback-1723): 补上相应真实代码与测试后再审

* fix(review-feedback-1723): 补齐所声称的后端实现与测试后再评审

* fix(review-feedback-1723): PR description 与当前完整 diff 不一致:描述声称新增 bare JP/KR code

* fix(review-feedback-1723): PR 描述与当前完整 diff 不一致

* fix(review-feedback-1723): 补充 Refs 1718,方便后续追踪

* fix(review-feedback-1723): 收敛描述与验证证据

* fix: resolve JP KR bare stock codes

* fix: backfill JP KR daily analysis context

* fix(review-feedback-1723): preserve persisted phase timing

* fix: align JP KR history lookup keys

* fix(review-feedback-1723): preserve raw code for snapshot lookups

* fix(review-feedback-1723): 收敛
2026-06-20 10:39:40 +08:00
LouisHong
fa9d9b0084 feat: [issue #1652] add run-flow snapshot contract and APIs (#1653)
* feat: add run-flow snapshot contract and APIs

* fix: address run-flow contract review notes

---------

Co-authored-by: mumu <42829555+ZhuLinsen@users.noreply.github.com>
2026-06-10 22:50:35 +08:00
Alfred
ff6494b5d7 feat: 新增建议动作 taxonomy 字段边界 P0 (#1631)
* feat: add decision action taxonomy fields

* fix: tighten decision action fallback handling

* fix: align legacy decision action guard fallback

* fix: tighten legacy decision action word boundaries

* fix: align decision action compound parsing

* fix: clean decision action residue

* fix: align web action label contract

* fix: classify avoided sell actions as hold
2026-06-08 07:24:07 +08:00
mumu
8df69fe036 feat: 完善大盘复盘历史聚合、查看与删除能力 (#1580) (#1598)
* feat(issue-1580): feat:-完善大盘复盘历史聚合、查看与删除能力

* fix(review-feedback-1598): resetting the paged window or deduping the merged list before storing it

* fix(review-feedback-1598): 补齐 AGENTS.md 要求的用户可见能力文档同步
2026-06-04 22:29:20 +08:00
Alfred
9b76f8d240 feat: #1386 P6 联动告警、持仓和历史阶段摘要 (#1589)
* feat: link phase summaries across P6 surfaces

* fix: align portfolio analysis response status

* fix: stabilize backtest phase filtering

* fix: normalize portfolio analysis symbols
2026-06-04 09:17:39 +08:00
zbl-96
81c0287803 feat: 新增个股栏与自选队列操作 (#1540)
* feat: add stock bar sidebar and watchlist management

- Replace history list sidebar with stock bar that deduplicates stocks
  and places market review at top, ordered by latest analysis time
- Add GET /api/v1/history/stocks endpoint for distinct stock list
- Add code normalization to merge code variants (e.g. 002460 / 002460.SZ)
- Add GET/POST /api/v1/stocks/watchlist CRUD endpoints
- Add watchlist card to report detail right sidebar
- Add watchlist buttons to chat/ask page with auto stock code detection
- Add useWatchlist hook for shared watchlist state management
- Update CHANGELOG with [Unreleased] flat entries

Refs #1530

* fix: use canonical normalize_stock_code for stock code dedup

Replace ad-hoc suffix stripping with the existing normalize_stock_code
in data_provider/base.py, which handles all supported variants:
SH600519 / 600519.SH / HK00700 / 00700.HK / BJ920748 / 920748.BJ.

Addresses Codex P2 suggestion on PR #1540.

* fix: address PR review feedback on #1540

1. Fix extractStockCodeFromMessage to reject exchange prefixes
   (SH/SZ/BJ/HK/US/SS) as standalone tickers; add explicit patterns
   for SH600519/SZ000001/BJ920748 prefix formats.
   Move function to utils/chatStockCode.ts to satisfy react-refresh.

2. Add stock code validation and normalization in watchlist API
   (add/remove endpoints now validate format and use
   normalize_stock_code before persisting to STOCK_LIST).

3. Over-fetch distinct stocks (limit*3) before normalization dedup
   to avoid losing results when code variants shrink after grouping.

4. Update HomePage tests: remove batch-delete test scenario (sidebar
   replaced by StockBar), add getStockBarList/getWatchlist mocks,
   adjust assertions to match StockBarItem accessible names.

Refs #1540

* fix: normalize watchlist codes on read/write and strengthen validation

1. _read_watchlist_codes now normalizes and deduplicates all existing
   STOCK_LIST entries via normalize_stock_code, so hk00700/HK00700/00700.HK
   are treated as one canonical entry.
2. _write_watchlist_codes deduplicates before persisting.
3. _validate_and_normalize_stock_code uses regex matching against
   all supported stock code formats (aligned with frontend validateStockCode).
4. Restore accidentally deleted CHANGELOG entry for same-stock history trend.
5. Fix CHANGELOG/PR description API paths to match actual routes.

Refs #1540

* fix: normalize stock codes in frontend watchlist comparison

Add normalizeStockCode utility mirroring backend normalize_stock_code,
and use it in isInWatchlist so SH600519/600519.SH/HK00700/00700.HK
variants are all recognized as the same stock. Add 10 regression tests.

Refs #1540

* fix: normalize stock code variants in watchlist comparison and extraction

1. ChatPage.tsx: stockInWatchlist now normalizes input via normalizeStockCode
   before comparing against watchlistCodes, so SH600519/600519.SH variants
   are correctly recognized as already being in the watchlist.
2. chatStockCode.ts: add \d{1,5}\.HK suffix pattern (e.g. 00700.HK → HK00700),
   and return normalizeStockCode(normalized) for all extracted codes.
3. stocks.py: add bare 5-digit HK code (\d{5}) to _STOCK_CODE_RE regex.
4. ChatPage tests: add mockGetWatchlist/AddToWatchlist/RemoveFromWatchlist mocks,
   add 2 regression tests for watchlist button with code variants
   (600519.SH → 600519 and 1810.HK → HK01810).

Refs #1540

* fix: keep STOCK_LIST as-is, normalize only for comparison

Revert read/write normalization in _read_watchlist_codes and
_write_watchlist_codes. STOCK_LIST is now stored exactly as the user
input, without auto-normalization. Add/remove endpoints normalize
only for duplicate/matching comparison, preserving raw codes.

Refs #1540

* feat: restore batch delete in StockBar and add delete-by-code API

1. Add DELETE /api/v1/history/by-code/{stock_code} endpoint to delete
   all history records for a given stock code in one call.
2. Add deleteByCode function to frontend historyApi.
3. StockBar: restore select-all checkbox and batch delete button,
   matching the original HistoryList UX.
4. StockBarItem: add per-item delete button (trash icon, visible on hover).
5. HomePage: wire handleDeleteStock to StockBar, refresh stock bar and
   history after deletion.
6. Update CHANGELOG to reflect restored batch delete capability.

Refs #1540
2026-06-02 23:16:46 +08:00
Alfred
f42b395745 feat: add market phase summary metadata (#1532) 2026-05-31 09:24:58 +08:00
mumu
47c287a062 feat: add same-stock history trend drawer (#1524)
* feat: add same-stock history trend drawer

* fix(review-feedback-1524): 澄清外部模型/API 兼容性检测点,说明本 PR 是否仅展示历史记录中的模型字段,是否不改变 provider/model/Base

* fix: refine stock history drawer layout

* fix(review-feedback-1524): preserve suffixed codes when filtering history

* fix: match stock history issue interaction

* fix(review-feedback-1524): 修复同股代码等价匹配漏查,以及前端抽屉在分页/时间范围下的记录注入与去重问题

* fix(review-feedback-1524): 确认并修复当前同股历史抽屉在空结果时间范围下的交互阻断问题

* fix(review-feedback-1524): CI 当前未通过:结构化事实显示 docker-build:failure、web-gate:failure,而 AGENTS.md 将

* fix: refine stock history trend page

* fix(review-feedback-1524): 修复同股代码等价匹配漏查和市场复盘切换时抽屉状态残留两个正确性问题
2026-05-30 21:01:34 +08:00
Alfred
0295f9d709 feat: expose analysis context pack overview (#1515)
Refs #1389
2026-05-30 09:20:11 +08:00
mumu
8a23124d01 feat: add #1391 Phase 2 run diagnostic summaries (#1444)
* fix(issue-1412): [bug]-stock_list格式问题

* fix(review-feedback-1413): preserve exchange hint for dotted A-share inputs

* fix(review-feedback-1413): Keep normalized A-share codes usable by market routing and preserve

* fix(review-feedback-1413): Limit raw dotted codes to fetchers that can parse them

* fix(review-feedback-1413): Keep Tushare daily input normalized for ETF detection

* fix(review-feedback-1413): 澄清结构化检测中的外部模型/API 与运行时配置迁移风险

* fix(review-feedback-1413): 处理或明确确认该失败与本 PR 无关且已有维护者豁免依据

* fix: keep stock list input as bare codes

* docs: add phase-0 run diagnostics contract

* fix(review-feedback-1435): 修正描述并澄清/补齐运行时代码变更的验证证据

* fix(review-feedback-1435): 补齐前缀提示识别,并增加对应回归测试

* fix(review-feedback-1435): 修正

* fix(review-feedback-1435): 解决冲突并更新描述/验证记录后再合入

* fix(review-feedback-1435): 解决冲突,并在最终 head 上重新确认 python -m pytest tests/test a share fetcher code

* fix(review-feedback-1435): 修复并补齐回归覆盖后再复核最终 head

* fix(review-feedback-1435): data provider/baostock fetcher.py 的 convert stock code 只从 .SH/.SS/.SZ

* fix: preserve A-share exchange hints

* fix(review-feedback-1435): 修正 docs/run-diagnostics-p0.md 对 Tushare 本轮范围的矛盾描述

* feat: add phase 1 run diagnostics trace plumbing

* feat: add phase 2 run diagnostic summaries

* fix(review-feedback-1441): 打通 trace id 与数据源运行快照,改动目标明确

* fix(review-feedback-1444): 修复 Agent 模式新报告通过历史诊断 API 返回 unknown 的正确性问题

* fix(review-feedback-1444): Propagate diagnostics lookup errors instead of masking them

* fix(review-feedback-1444): 补对应回归断言

* fix(review-feedback-1444): 解决冲突后再合入

* fix(review-feedback-1444): 解决冲突

* fix(review-feedback-1444): 解决冲突

* fix(review-feedback-1444): 解决

* fix(review-feedback-1444): 解决

* fix(review-feedback-1444): 解决冲突

* fix(review-feedback-1444): 解决

* fix(review-feedback-1444): 解决

* fix(review-feedback-1444): 解决冲突后再合入

* fix(review-feedback-1444): 解决冲突后再合入

* fix(review-feedback-1444): 解决冲突后再合入

* fix(review-feedback-1444): 解决冲突

* fix(review-feedback-1444): Derive news diagnostics from retrieval evidence

* fix(review-feedback-1444): 解决冲突后再合入

* fix(review-feedback-1444): 解决冲突并基于解决后的最终 diff 重新确认 docs/CHANGELOG.md、诊断链路和测试结果

* fix(review-feedback-1444): 解决冲突

* fix(review-feedback-1444): 解决冲突后再合入

* fix(review-feedback-1444): 解决冲突并重新跑阻断型 CI,尤其是 backend-gate 和相关诊断/API/history 回归

* fix(review-feedback-1444): preserve report timestamp when enriching task results

* fix: address run diagnostics review feedback

* fix: redact diagnostic copy text secrets

* fix(review-feedback-1444): 补一条多渠道部分失败的回归测试
2026-05-26 00:05:24 +08:00
zbl-96
639796f982 fix: restore board linkage for compatible history snapshots (#1416)
* fix: restore board linkage from compatible snapshots

* chore: drop local review artifact from pr

* fix: enrich in-memory status board details

* fix: merge partial fundamental snapshots

* fix: preserve fallback fields on empty snapshots

---------

Co-authored-by: ZhuLinsen <zhuls97@163.com>
2026-05-24 19:20:25 +08:00
mumu
b66ca1ecdd fix: preserve change_pct in history detail (#1084) (#1119)
* fix: preserve change_pct in history detail (#1084)

- Replace truthy 'or' chains with explicit 'is None' checks so a 0.0 daily
  change (flat) is no longer dropped from the response meta.
- Drop incorrect change_60d fallback (60-day cumulative) for the daily
  change_pct field.
- When enhanced_context.realtime has price but no change_pct, fall back to
  realtime_quote_raw.change_pct / pct_chg unconditionally, matching the
  fix already applied to api/v1/endpoints/analysis.py.

Adds two regression tests covering the zero-value preservation and the
realtime_quote_raw fallback path.
2026-04-25 12:23:51 +08:00
Alfred
e1dbee3318 feat: 在个股分析页展示个股所属板块及其与当日板块强弱的关系 (#669) (#800)
* feat: show related boards in stock reports (#669)

* fix: preserve unavailable related board states

---------

Co-authored-by: mumu <42829555+ZhuLinsen@users.noreply.github.com>
2026-03-22 20:52:40 +08:00
mumu
ef328e906b feat: add configurable report language (#764)
* feat: add configurable report language

* Fix review follow-ups for history and fallback localization

* fix: prefer .env report language at startup

* fix: address report language review feedback

* fix: address latest report language review feedback
2026-03-19 22:55:17 +08:00
Alfred
274720234a fix: add A-share financial/dividend context outputs (#710) (#731)
Co-authored-by: mumu <42829555+ZhuLinsen@users.noreply.github.com>
2026-03-17 21:38:31 +08:00
LouisHong
8ce8d49af1 Feat: 历史分析记录批量删除功能 (Batch Deletion) (#636)
* feat: implement batch deletion of analysis history with UI/UX improvements

- Backend: Added DELETE /api/v1/history endpoint for bulk deletion by IDs.
- Storage: Implemented DatabaseManager.delete_analysis_history_records with cascade cleanup of BacktestResult to prevent foreign key constraints.
- Frontend:
    - Added checkbox-based multi-selection to HistoryList component.
    - Implemented batch delete logic in HomePage with automatic selection fallback.
    - Extracted and standardized ConfirmDialog component for consistent design across the app.
    - Updated ChatPage to use the new standardized ConfirmDialog.
- Tests: Added unit tests for database cascade deletion and API endpoint functionality.

* docs: update README and CHANGELOG for batch history deletion

* feat: Implement the main HomePage for stock analysis and history management, supported by a new history service.

---------

Co-authored-by: mumu <42829555+ZhuLinsen@users.noreply.github.com>
2026-03-13 23:19:33 +08:00
graydovee
0483098f73 feat: web-ui add full report button (#621)
* feat: web-ui add full report button

* update change log

* fix(history): address PR review feedback for markdown report feature

* fix: full reporter ui

* fix(history): add generic exception handler for markdown endpoint
2026-03-12 21:00:15 +08:00
Alfred
c85423dfca [feat] 在分析报告中标记使用模型并完善展示链路 Issue #528 (#534)
* feat: mark model used in reports and notifications (#528)

* refactor: centralize model_used normalization and raw_result parsing (#528)

---------

Co-authored-by: mumu <42829555+ZhuLinsen@users.noreply.github.com>
2026-03-07 20:29:02 +08:00
zhulinsen
115811e319 fix: resolve LLM NoneType crash, history API 422 error, and sniper points extraction
- Guard against None/empty response.choices in LLMToolAdapter._call_api()
      before accessing choices[0]; raise descriptive ValueError instead of
      cryptic TypeError (Fixes #390)

    - Change history detail/news endpoint record_id type from int to str;
      add _resolve_record() that tries integer PK first then falls back to
      query_id lookup; add get_latest_analysis_by_query_id() in storage layer
      (Fixes #432)

    - Enhance _extract_sniper_points() with multi-level dashboard traversal
      (standard path → dashboard dict → raw_response); add _find_sniper_in_dashboard()
      recursive search; improve _parse_sniper_value() edge case handling for zero
      values, full-width commas, and placeholder strings (Fixes #436)

    #patch
2026-02-27 20:23:22 +08:00
Myrrolinz
026630adb4 fix: Date inconsistency & incorrect query id for db (fixes #322) (#363)
* resolve empty analysis result list problem by endDate + 1

* fix bug 322 by using record id for db query

* address comments

* address potential issue and error
2026-02-26 12:22:24 +08:00
Krane
9847157980 Feature/React web support 新的WebUI (#256)
* feat(web): add FastAPI & React web connect

* feat: add FastAPI package

* feat: system base struct

* feat: frontend base struct

* feat: 基础分析接口,历史记录接口

* fix: 使用正确的 FastAPI 方法定义,避免线程阻塞

* fix: 对接历史报告页、详情页

* fix: 修复接口问题

* fix: 网络配置 允许公网访问 跨域配置

* fix: 页面打包 & 提供 Server 静态访问

* fix: 优化dock栏样式

* fix: 优化图标样式

* fix: 修改部分配色

* fix: 删除垃圾文档

* fix: 删除垃圾代码

* fix: 驼峰转换工具

* fix: 历史记录列表滚动加载(分页)

* feat: 显示分析中任务

* fix: 调整布局

* fix: 优化 Market Sentiment 组件动效

* fix: 历史列表组件bug

* fix: FastAPI 日志配置

* feat: 新闻历史接口

* feat: 资讯列表

* feat: 优化布局

* fix: 修复页面元素变宽问题

* fix: 中文标题

* fix: 任务列表状态显示问题

* fix: 抽取日志配置

* fix: 优化报告价格显示

* fix: 修复编译错误

* fix: FastAPI 启动提取到 main.py

* fix: 补充新web-ui启动文档

* fix: 默认发送通知

* fix: FastAPI 模式适配 docker

* fix: FastAPI 模式文档

* Update api/v1/endpoints/stocks.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: package-lock.json

* fix: 修改错别字

* fix: 更新文档说明

* fix: 更新文档说明

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-05 20:56:38 +08:00