Files
group_xinghuo_jinrong/docs/course/jinrong-module-frontend/modules/02-chat-auth.html
T
zhanghongyu_0626 4b8e11c9bd feat(threshold): Implement customer loss threshold configuration and notification system
- Added `ThresholdRepository` for managing customer loss threshold configurations and notifications.
- Introduced `threshold_service` to handle loss threshold alerts based on customer portfolio performance.
- Enhanced `customer_prompts` to include new intent for querying product net values.
- Updated `customer_service` to integrate new threshold alert functionality into existing workflows.
- Implemented `sanitize_postprocess` for improved compliance handling in customer interactions.
- Enhanced course documentation to reflect updates in advisor training modules and interactive elements.

This update significantly improves the customer experience by providing proactive loss threshold notifications and enhancing the overall service framework.
2026-09-10 10:57:40 +08:00

102 lines
6.5 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<section class="module" id="module-2">
<div class="module-inner">
<p class="eyebrow animate-in">模块 2 · 对话与鉴权</p>
<h1 class="module-title animate-in">ChatPanel / useChatPanel:<br>三条 API 线的头不一样</h1>
<p class="module-lead animate-in">
对话 UI 统一用 <code>ChatPanel</code> + <code>useChatPanel</code>,但后端入口分三条:
<code>/api/chat</code>(四 Agent)、<code>/api/analyst/*</code>(问数平台)、风控台账 REST。
指挥 AI 接新页面时,<strong>先对表再写 headers</strong>。
</p>
<div class="screen animate-in">
<h2>鉴权差异对照</h2>
<table style="width:100%; border-collapse:collapse; margin: 1.5rem 0; font-size: 0.95rem;">
<thead><tr><th>前端模块</th><th>API</th><th>Authorization</th><th>X-Agent-Type</th></tr></thead>
<tbody>
<tr><td><code>api/chat.ts</code></td><td>/api/chat, /stream, sessions</td><td>Bearer</td><td><strong>必须</strong>(与 prop agentType 一致)</td></tr>
<tr><td><code>api/analyst.ts</code></td><td>/api/analyst/chat 等</td><td>Bearer(apiFetch)</td><td><strong>不要</strong></td></tr>
<tr><td><code>api/risk.ts</code></td><td>/api/risk/*</td><td>Bearer</td><td><strong>必须 risk</strong></td></tr>
<tr><td>持仓/产品页</td><td>/api/customers/* 等</td><td>Bearer</td><td>不要</td></tr>
</tbody>
</table>
<div class="callout callout-warning">
<strong>真实 bug:</strong> <code>risk.ts</code> 曾漏 <code>X-Agent-Type: risk</code>,JWT 正确也 401。接新风控页先 grep 这个头。
</div>
</div>
<div class="screen animate-in">
<h2>数据流:理财师打开顾问助手</h2>
<div class="flow-animation" data-steps='[
{"highlight":"flow-actor-1","label":"ChatPanel(agentType=advisor, mode=stream)"},
{"highlight":"flow-actor-2","label":"useChatPanel → listChatSessions(token, advisor)","packet":true,"from":"1","to":"2"},
{"highlight":"flow-actor-3","label":"chat.ts:Bearer + X-Agent-Type: advisor","packet":true,"from":"2","to":"3"},
{"highlight":"flow-actor-4","label":"对话 HTTP 入口(chat.py):get_auth_context + 准入矩阵","packet":true,"from":"3","to":"4"},
{"highlight":"flow-actor-1","label":"SSE 流式 delta → UI 逐字显示","packet":true,"from":"4","to":"1"}
]'>
<div class="flow-actors">
<div class="flow-actor" id="flow-actor-1"><span class="flow-actor-icon">💬</span><span>ChatPanel</span></div>
<div class="flow-actor" id="flow-actor-2"><span class="flow-actor-icon">🪝</span><span>useChatPanel</span></div>
<div class="flow-actor" id="flow-actor-3"><span class="flow-actor-icon">📡</span><span>api/chat.ts</span></div>
<div class="flow-actor" id="flow-actor-4"><span class="flow-actor-icon">🚪</span><span>对话 HTTP 入口(chat.py)</span></div>
</div>
<p class="flow-step-label">对比:问数走 analyst.ts,无 X-Agent-Type</p>
<div class="flow-controls">
<button class="btn flow-next-btn">下一步</button>
<button class="btn flow-reset-btn">重来</button>
</div>
</div>
</div>
<div class="screen animate-in">
<div class="translation-block">
<div class="translation-code">
<span class="translation-label">chat.ts vs analyst.ts</span>
<pre><code><span class="code-line"><span class="code-comment">// chat.ts — 对话线</span></span>
<span class="code-line"><span class="code-keyword">function</span> <span class="code-function">chatHeaders</span>(token, agentType) {</span>
<span class="code-line"> <span class="code-keyword">return</span> {</span>
<span class="code-line"> Authorization: <span class="code-string">`Bearer ${token}`</span>,</span>
<span class="code-line"> <span class="code-string">'X-Agent-Type'</span>: agentType,</span>
<span class="code-line"> }</span>
<span class="code-line">}</span>
<span class="code-line"></span>
<span class="code-line"><span class="code-comment">// analyst.ts — 问数平台线</span></span>
<span class="code-line">apiFetch(<span class="code-string">'/api/analyst/chat'</span>, { method: <span class="code-string">'POST'</span>, token, body })</span>
<span class="code-line"><span class="code-comment">// apiFetch 只加 Authorization,不加 X-Agent-Type</span></span></code></pre>
</div>
<div class="translation-english">
<span class="translation-label">白话</span>
<div class="translation-lines">
<p class="tl">Chat 相关请求:token 证明身份,agentType 证明走哪条 Agent 线。</p>
<p class="tl">useChatPanel 把 agentType 从页面 prop 一路传到每次 list/send/close。</p>
<p class="tl">问数用 apiFetch 通用封装,后端走 get_platform_auth_context,不需要 Agent 头。</p>
<p class="tl">customer 线 mode 常用 sync(后端 LangGraph 整图跑完再推);advisor/risk 用 stream SSE。</p>
</div>
</div>
</div>
<div class="quiz-container" id="quiz-frontend-m2">
<div class="quiz-question-block"
data-correct="option-c"
data-explanation-right="风控对话页 ChatPanel agentType=risk,chat.ts 自动带 X-Agent-Type: risk。"
data-explanation-wrong="风控 Chat 走 /api/chat,不是 /api/risk;但 REST 台账才用 risk.ts。">
<h3 class="quiz-question">RiskChatPage 发消息,请求头应长什么样?</h3>
<div class="quiz-options">
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
<div class="quiz-option-radio"></div><span>只要 Bearer,和问数一样</span>
</button>
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
<div class="quiz-option-radio"></div><span>Bearer + X-Agent-Type: analyst</span>
</button>
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
<div class="quiz-option-radio"></div><span>Bearer + X-Agent-Type: risk</span>
</button>
</div>
<div class="quiz-feedback"></div>
</div>
<button class="quiz-check-btn" onclick="checkQuiz('quiz-frontend-m2')">检查答案</button>
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-frontend-m2')">重做</button>
</div>
</div>
</div>
</section>