/* AI 选购助手(壳内层)— 9 个统一 Agent 工具的脚本化演示: 工具 needs_input → 对话内 GUI → resume → 结构化结果卡 → Agent 继续编排。 四个固定小工具仍可从“小工具”页独立打开;AR 量房 / 采光检测也可在同一对话内弹出。 电视对比看板以紧凑交互卡嵌入对话,并保留展开完整看板入口。 三条剧本:主线(标准选购闭环)· 反光 · 烧屏。对话为 demo 剧本,非真模型。 深链:?tool=agent · &auto=1 自动替用户点选项(走 AR→设备兼容→对比→配件→链接核验,评审/截图用) */ const AG_RM = !!(window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches); const AG_AUTO = new URLSearchParams(location.search).get('auto') === '1'; const agCx = (...a) => a.filter(Boolean).join(' '); const AG_CMD = '我想买台客厅用的电视'; /* 主页 Agent 卡片的三个建议问题 —— 文案单一事实源(home.jsx 读 window.AG_ASKS),顺序即剧本路由 */ const AG_ASKS = ['预算 1.5 万,客厅怎么选', '白天客厅很亮,怕反光', 'OLED 会烧屏吗']; /* 协议层保留英文 ID;展示层一律使用中文名称。 */ const AG_TOOL_LABELS = { research_products: '产品研究', compare_products: '电视对比', verify_model_and_offer: '购买链接核验', evaluate_room_and_size: '房间与尺寸评估', recommend_tv_accessories: '电视配件推荐', plan_device_setup: '设备与最佳设置', plan_installation_and_delivery: '安装与入户规划', evaluate_lifecycle_options: '长期成本与处置', diagnose_tv_problem: '验机与故障诊断', }; const AG_RESULT_LABELS = { needs_confirmation: '等待确认', needs_input: '需要补充', partial: '部分完成', ok: '已完成', PurchaseQuestionnaire: '选购问卷', RoomMeasurementWizard: '空间测量', AmbientLightCapture: '环境光采集', UsageMixSelector: '使用习惯选择', PurchaseLinkInput: '商品链接输入', required: '必需', recommended: '建议', not_needed: '不需要', }; const agToolLabel = (id) => AG_TOOL_LABELS[id] || id; const agResultLabel = (text) => Object.entries(AG_RESULT_LABELS) .reduce((s, [raw, label]) => s.replaceAll(raw, label), String(text || '')); /* 尺寸 → 在库命中数(dbdata.jsx 按尺寸实数:75″=7 · 85″=23 · 98″+=13)/ 包装箱最长边(入户预检用) */ const AG_HIT = { 75: 7, 85: 23, 98: 13 }; const AG_BOX = { 75: { long: '1.86 m' }, 85: { long: '2.08 m' }, 98: { long: '2.36 m', warn: '箱体超 2.3 m:需斜立进梯,建议约 2 名搬运(免费)' }, }; /* 预算选项按尺寸给(价格全部来自机型库在售录价;85″ 从 7 千档起步——在库 7499 有雷鸟鹤6U/Vidda发现X/酷开K6 PRO 三台) */ const AG_BUDGETS = { 75: [ { label: '4 – 6 千', v: '75b1' }, { label: '1 万左右', v: '75b2' }, { label: '不确定,直接推荐', v: '75b2' }, ], 85: [ { label: '7 – 8 千', v: '85v' }, { label: '1 万左右', v: '85low' }, { label: '1 – 1.5 万', v: '85mid' }, { label: '不设上限', v: '85high' }, ], 98: [ { label: '3 万左右', v: '98b1' }, { label: '5 万以上', v: '98b2' }, { label: '不确定,直接推荐', v: '98b1' }, ], }; /* Agent 里出现的机型只取两类证据:db/1.sql 的 brightness_plot,或仓库内完整评测报告。 peak / full 分别为该模式窗口曲线最大值与 100% 窗口平均值;价格为报告录入快照,不是实时到手价。 */ const AG_TV_DATA = { vision5: { id: 10000228, brand: '华为', model: '智慧屏 Vision 5 75', panel: 'MiniLED', size: 75, peak: 1080, full: 592, mode: 'HDR 标准', source: 'DB 实测', price: 5647, hl: '生态与大屏体验', why: 'HDR 标准模式实测峰值 1080 nit、100% 窗口 592 nit。报告更看重智慧交互与家居生态;若只追求极端画质,不必为生态功能加预算。' }, vision5se: { id: 10000233, brand: '华为', model: '智慧屏 Vision 5 SE 75', panel: 'MiniLED', size: 75, peak: 1088, full: 446, mode: 'HDR 标准', source: 'DB 实测', price: 4499, hl: '预算友好', why: 'HDR 标准模式实测峰值 1088 nit、100% 窗口 446 nit。峰值接近 Vision 5,但大面积亮场更弱;更适合预算优先、华为生态明确的家庭。' }, he6: { id: 10000223, brand: '雷鸟', model: '85 鹤6 Ultra 25款', panel: 'QD-MiniLED', size: 85, peak: 2428, full: 685, mode: 'HDR 标准', source: 'DB 实测', price: 7499, hl: '7 千档均衡', why: 'HDR 标准模式实测峰值 2428 nit、100% 窗口 685 nit。库内报告认为它同价位均衡、控光好、系统干净;短板是画面略有提亮。' }, viddaX: { id: 10000231, brand: 'VIDDA', model: '发现X 2026款 85', panel: 'QD-MiniLED', size: 85, peak: 1424, full: 500, mode: 'HDR 标准', source: 'DB 实测', price: 7499, hl: '雾面屏路线', why: 'HDR 标准模式实测峰值 1424 nit、100% 窗口 500 nit,亮度明显低于同价鹤6。优势是报告记录的雾面抗反与入门性价比,代价是清晰度和通透感。' }, he7: { id: 10000219, brand: '雷鸟', model: '85 鹤7 PRO 25款', panel: 'QD-MiniLED', size: 85, peak: 4016, full: 708, mode: 'HDR 标准', source: 'DB 实测', price: 9799, hl: '影音游戏双修', why: 'HDR 标准模式实测峰值 4016 nit、100% 窗口 708 nit。报告把它列为大屏游戏与观影的高性价比选择;短板是提亮偏多、外壳做工一般。' }, viddaXPro: { id: 10000222, brand: 'VIDDA', model: '发现X Pro 2026款 85', panel: 'QD-MiniLED', size: 85, peak: 1883, full: 721, mode: 'HDR 标准', source: 'DB 实测', price: 9999, hl: '调校较标准', why: 'HDR 标准模式实测峰值 1883 nit、100% 窗口 721 nit。报告评价是没有明显大短板、调校较标准;不足是画面偏清淡、对比感不强。' }, q10l: { id: 10000225, brand: 'TCL', model: '85 Q10L', panel: 'QD-MiniLED', size: 85, peak: 4728, full: 835, mode: 'HDR 标准', source: 'DB 实测', price: 11999, hl: '持续亮度强', why: 'HDR 标准模式实测峰值 4728 nit、100% 窗口 835 nit。库内报告认可亮度、光晕控制和超窄边;像素响应与背光延迟不是它的强项。' }, e8s: { id: 10000788, brand: '海信', model: '85 E8S', panel: 'RGB-MiniLED', size: 85, peak: 2631, full: null, refl: 1.732, mode: 'HDR 鲜艳', source: '本地报告实测', price: 14999, hl: 'RGB 控光均衡', why: '本地报告 HDR 鲜艳模式实测峰值 2631 nit、全反射率 1.732%。报告认为画面偏中性、光晕和延迟控制好;HDR 小窗口与白点仍有短板。' }, q10lPro: { id: 10000346, brand: 'TCL', model: '98 Q10L PRO', panel: 'QD-MiniLED', size: 98, peak: 7810, full: 826, mode: 'HDR 标准', source: 'DB 实测', price: 28999, hl: '98″ 高亮旗舰', why: 'HDR 标准模式实测峰值 7810 nit、100% 窗口 826 nit。报告认为整体达到高端水准,但相较 85 Q10L 的提升有限,性价比一般。' }, e8qPro: { id: 10000230, brand: '海信', model: '100 E8Q PRO', panel: 'MiniLED', size: 100, peak: 2887, full: 737, mode: 'HDR 标准', source: 'DB 实测', price: 28999, hl: '真正 100″', why: 'HDR 标准模式实测峰值 2887 nit、100% 窗口 737 nit。优势是比 98″ 更大的实际面积;报告也提醒它对空间、入户和安装要求更高。' }, g5: { id: 10000735, brand: 'LG', model: '65 G5', panel: 'OLED evo', size: 65, peak: 2484, full: null, refl: 0.816, mode: 'HDR 影院', source: '本地报告实测', price: 21999, hl: 'OLED 暗场与抗反', why: '本地报告 HDR 影院模式实测峰值 2484 nit、全反射率 0.816%。暗场、响应和抗反是强项;中国区应用生态与长期静态画面风险需要接受。' }, }; const agTv = (key, extra = {}) => ({ ...AG_TV_DATA[key], ...extra }); /* 推荐会同时吃预算与用途。游戏不再把有明显延迟短板的机型排到前面,直播/体育优先看 100% 窗口。 */ function agPickFor(budgetKey, usage = []) { const movie = usage.includes('movie'); const game = usage.includes('game'); const live = usage.includes('live'); const seniorFamily = usage.includes('senior') || usage.includes('family'); if (budgetKey === '75b1' || budgetKey === '75b2') return { say: budgetKey === '75b2' ? '库内有完整实测的 75″ 里,不需要为了花满一万元硬上未知机型——' : '4–6 千的 75″,先看这组有完整实测的候选——', main: agTv('vision5'), altSay: '如果预算更优先:', alt: agTv('vision5se'), }; if (budgetKey === '85v') return { say: '7 千档两台都实测过,亮度和综合完成度更好的这台排前面——', main: agTv('he6'), altSay: '如果更在意雾面屏:', alt: agTv('viddaX'), }; if (budgetKey === '85low') { const calmFirst = (live || seniorFamily) && !game; return calmFirst ? { say: '你更重视长时间观看和家庭共用,我把调校较标准的放前面——', main: agTv('viddaXPro'), altSay: '想要更强 HDR 高光和游戏能力:', alt: agTv('he7') } : { say: '你包含游戏或电影需求,实测和报告都更支持这台——', main: agTv('he7'), altSay: '更偏好克制、均衡的调校:', alt: agTv('viddaXPro') }; } if (budgetKey === '85mid' || budgetKey === '85high') { if (live && !game) return { say: '直播、体育和综艺更吃大面积持续亮度,100% 窗口实测更强的排前面——', main: agTv('q10l'), altSay: '如果更看重 RGB 控光与综合均衡:', alt: agTv('e8s'), }; const sceneLead = game && movie ? '电影和游戏都要,我先选报告里延迟与控光更均衡的一台——' : game ? '游戏优先,我先选报告里延迟与控光更均衡的一台——' : movie ? '电影为主,我先选暗场、控光和画面调校更均衡的一台——' : seniorFamily ? '家庭共用更看重均衡与稳定,我先把综合完成度更高的一台放前面——' : '按当前用途和现有实测,我先把综合更均衡的一台放前面——'; return { say: budgetKey === '85high' ? '85″ 不设上限也不等于要花满;按现有实测,这两台已经覆盖高端需求——' : sceneLead, main: agTv('e8s'), altSay: '想少花 3 千并换更高的实测亮度:', alt: agTv('q10l'), }; } return { say: budgetKey === '98b2' ? '5 万档机型缺少完整实测,我不会拿标称值硬推;先回到这两台证据完整的百吋候选——' : '3 万左右的百吋档,按相同 HDR 标准模式实测先看这台——', main: agTv('q10lPro'), altSay: '如果你更在意真正的 100″ 面积:', alt: agTv('e8qPro'), }; } /* 反光路线:有反射率实测才展示数值;缺失时明确标“未测”,不再用亮度冒充抗反。 */ const AG_GLARE = { g07: { say: '7 千档里,鹤6的亮度与报告结论更完整——', main: agTv('he6'), altSay: '想要雾面屏路线可以看:', alt: agTv('viddaX') }, oled: { say: '混合画面路线里,G5 的抗反有本地实测支撑——', main: agTv('g5'), altSay: '想上 85″,就换这台 RGB-MiniLED:', alt: agTv('e8s') }, g1: { say: '1 万左右先看 HDR 高光更强、影音游戏证据更完整的这台——', main: agTv('he7'), altSay: '想要调校更克制的备选:', alt: agTv('viddaXPro') }, g15: { say: '满屏亮画面看得多,100% 窗口实测 835 nit 的这台更稳——', main: agTv('q10l'), altSay: '更看重 RGB 控光与已测反射率:', alt: agTv('e8s') }, gbig: { say: '百吋路线里先按同模式实测亮度排序——', main: agTv('q10lPro'), altSay: '要真正 100″ 再看:', alt: agTv('e8qPro') }, }; /* 烧屏路线只使用仓库内两份完整报告给出的实测与定性结论。 */ const AG_BURN = { oled: agTv('g5', { hl: '暗场与响应优先', why: '逐像素控光、快速响应和 0.816% 全反射率是核心优势;报告也明确提醒,长期展示固定台标或游戏界面仍有烧屏风险。' }), mled: agTv('e8s', { hl: '固定画面更省心', why: 'MiniLED 背光没有 OLED 的像素老化路径,更适合台标或比分牌长时间固定;本地报告同时记录了不错的光晕与延迟控制。' }), }; const agSleep = (ms) => new Promise((r) => setTimeout(r, AG_RM ? Math.min(ms, 80) : ms)); /* ---- 假测量浮层(AR 量房 / 采光检测共用骨架):四相位扫描 → 两条标注 → 回传 ---- */ function AgScanOverlay({ bg, hints, l1, l2, runText, onDone }) { const { useState, useEffect } = React; const [ph, setPh] = useState(0); useEffect(() => { const k = AG_RM ? 0.1 : 1; const ts = [ setTimeout(() => setPh(1), 1000 * k), setTimeout(() => setPh(2), 2300 * k), setTimeout(() => setPh(3), 3600 * k), setTimeout(onDone, 4500 * k), ]; return () => ts.forEach(clearTimeout); }, []); return (
{hints[ph]}
{ph >= 1 &&
{l1}
} {ph >= 2 &&
{l2}
}
= 3 && 'ok')}> {ph >= 3 ? : } {ph >= 3 ? '测量完成' : runText}
); } const AgArOverlay = (p) => ( ); const AgLuxOverlay = (p) => ( ); /* ---- 消息卡片 ---- */ const agPurchaseUrl = (tv) => 'https://search.jd.com/Search?keyword=' + encodeURIComponent(`${tv.brand}${tv.model.replace(/\s+/g, '')}电视`); const agNit = (n) => n == null ? '未提供' : `${Number(n).toLocaleString()} nit`; const agRefl = (n) => n == null ? '未测' : `${Number(n).toFixed(3).replace(/0+$/, '').replace(/\.$/, '')}%`; function AgTvCard({ tv, tag }) { const color = (BRANDS.find((b) => b.zh === tv.brand) || {}).color || 'var(--accent)'; const second = tv.full != null ? { label: '100% 窗口', value: agNit(tv.full) } : { label: '全反射率', value: agRefl(tv.refl) }; return (
{tv.brand} {tv.model} {tag}
{tv.panel}{tv.size}″{tv.hl}{tv.source}
HDR 峰值{agNit(tv.peak)}
{second.label}{second.value}
实测模式{tv.mode}

{tv.why}

¥{tv.price.toLocaleString()}库内报告价
完整看板
); } function AgEntryCard({ size }) { const box = AG_BOX[size] || AG_BOX[85]; return (
入户可行性预检通过 ✓
包装箱最长边 {box.long}电梯轿厢 1.6×1.5×2.3 m
入户门净宽 0.95 m拆箱前可直进
楼道转角 · 无台阶路径已核对
{box.warn &&
{box.warn}
}
数据来自小区众包入户库(演示数据)
); } function AgArCard() { return (
AR 量房 · 测量结果
电视墙净宽3.62 m
沙发视距2.9 m
推荐尺寸85″
); } function AgLuxCard() { return (
采光检测 · 测量结果
午后峰值照度≈1400 lux
直射时段西晒 ≈2 h
抗反需求
); } function AgTradeCard() { return (
旧机估值 · 回收抵扣
¥360 – 52055″ 液晶 · 约 2017 年 · 屏幕完好
含上门拆挂与搬运费 · 回收款下单直接抵扣
); } function AgEndCard({ chips }) { return (
本次方案小结
{chips.map((c, i) => {c})}
); } /* ---- 电视对比的对话内结果 GUI:紧凑查看,必要时再展开完整看板 ---- */ function AgCompareCard({ tvs, scene = '客厅综合' }) { const { useState } = React; const [tab, setTab] = useState('evidence'); const sameMode = new Set(tvs.map((t) => t.mode)).size === 1; const evidenceRows = [ { n: 'HDR 峰值', get: (t) => agNit(t.peak), better: 'hi', raw: (t) => t.peak, modeBound: true }, tvs.some((t) => t.full != null) && { n: '100% 窗口', get: (t) => agNit(t.full), better: 'hi', raw: (t) => t.full, modeBound: true }, tvs.some((t) => t.refl != null) && { n: '全反射率', get: (t) => agRefl(t.refl), better: 'lo', raw: (t) => t.refl }, { n: '实测模式', get: (t) => t.mode }, ].filter(Boolean); const rows = tab === 'fit' ? [ { n: '屏幕 / 背光', get: (t) => t.panel }, { n: '尺寸', get: (t) => `${t.size}″` }, { n: '场景亮点', get: (t) => t.hl }, ] : tab === 'cost' ? [ { n: '库内报告价', get: (t) => `¥${t.price.toLocaleString()}`, better: 'lo', raw: (t) => t.price }, { n: '每英寸', get: (t) => `¥${Math.round(t.price / t.size)}`, better: 'lo', raw: (t) => t.price / t.size }, { n: '价格口径', get: () => '报告录入快照' }, ] : evidenceRows; const bestAt = (row) => { if (!row.better || (row.modeBound && !sameMode)) return -1; const valid = tvs.map((tv, i) => ({ i, v: row.raw(tv) })).filter(({ v }) => Number.isFinite(v)); if (valid.length !== tvs.length) return -1; return valid.reduce((best, cur) => row.better === 'hi' ? (cur.v > best.v ? cur : best) : (cur.v < best.v ? cur : best)).i; }; return (
电视对比看板
{scene}按当前需求权重排序
{[['evidence', '关键实测'], ['fit', '场景适配'], ['cost', '价格']].map(([k, n]) => ( ))}
{tvs.map((tv, i) => {i === 0 && 首选}{tv.brand}{tv.model}{tv.source})} {rows.map((row) => { const best = bestAt(row); return {row.n} {tvs.map((tv, i) => {row.get(tv)}{best === i && })} ; })}
{sameMode ? '同模式数据可比较;首选按当前用途排序' : '实测模式不同,保留原始口径,不把亮度强行判胜'}展开完整看板
); } function AgAccessoryNeedsCard({ usage = [] }) { const stateLabels = { required: '必需', recommended: '建议', not_needed: '不需要' }; const movieHeavy = usage.includes('movie'); const familyUse = usage.includes('family'); const liveUse = usage.includes('live'); const gameUse = usage.includes('game'); const rows = [ ['电视支架', 'required', familyUse ? '除匹配 VESA 与承重,还需优先防倾倒' : '立式或壁挂都需匹配 VESA 与承重'], ['回音壁', movieHeavy ? 'recommended' : 'not_needed', movieHeavy ? '电影权重高,电视原生低频偏弱' : '当前用途不需要优先升级声音'], ['电视盒子', 'not_needed', liveUse ? '沿用运营商机顶盒,不重复购买' : '原生流媒体与 DRM 已满足'], ['HDMI 线', 'not_needed', gameUse ? '主机原装线带宽足够' : '当前连接设备无需另购'], ]; return (
配件需要性分析
{rows.map(([n, state, why]) => (
{n}{stateLabels[state]}{why}
))}
); } const AG_MOUNT_STYLES = { floor: [ { id: 'easel', name: '画架式', desc: '家具感最强', image: 'accessory-stand-easel.webp', roomImage: 'room-composites/room-mount-easel.webp', roomColor: 'walnut' }, { id: 'pedestal', name: '立柱式', desc: '占地更小', image: 'accessory-stand-pedestal.webp', roomImage: 'room-composites/room-mount-pedestal.webp', roomColor: 'black' }, { id: 'mobile', name: '移动式', desc: '带轮可推', image: 'accessory-stand-mobile.webp', roomImage: 'room-composites/room-mount-mobile.webp', roomColor: 'gray' }, ], wall: [ { id: 'slim', name: '超薄固定', desc: '贴墙最薄', image: 'accessory-mount-slim.webp', roomImage: 'room-composites/room-mount-slim.webp', roomColor: 'black' }, { id: 'tilt', name: '俯仰可调', desc: '可调整上下角度', image: 'accessory-mount-slim.webp', roomImage: 'room-composites/room-mount-tilt.webp', roomColor: 'black' }, { id: 'arm', name: '全向伸缩', desc: '可拉出与左右转向', image: 'accessory-mount-slim.webp', roomImage: 'room-composites/room-mount-arm.webp', roomColor: 'black' }, ], }; function AgMountResultCard({ mount, tv }) { return (
支架方案已选商品示意
{mount.style.name
{mount.modeLabel} · {mount.style.name} {mount.style.desc}
{mount.lift}{mount.power} {mount.color.label}
已按 {tv.size}″ 预筛尺寸范围下单前核对 VESA 与承重
); } function AgSoundbarCard() { return (
回音壁方案商品示意
5.1.2 声道回音壁套装示意图
5.1.2 声道套装eARC · 杜比全景声 · 无线低音炮
); } function AgRoomPreviewCard({ tv, mount }) { const exactPreview = tv.size === 85 && mount.style.roomColor === mount.color.v; const bg = exactPreview && mount.style.roomImage ? mount.style.roomImage : (mount.mode === 'wall' ? IMG.wall : IMG.stand); return (
已保存客厅合成
电视与所选支架在客厅中的合成示意{exactPreview ? `${mount.style.name} · ${mount.color.label}` : `摆放参考 · ${mount.style.name}/${mount.color.label}已记录`}
{tv.brand} {tv.model} · {tv.size}″
); } function AgReturnTvCard({ tv, mount }) { return (
回到电视方案{tv.brand} {tv.model}
{mount && {mount.style.name}已保存}
); } function AgBuyLinkCard({ tv }) { return (
推荐搜索入口
京东
{tv.brand} {tv.model} · {tv.size}″型号关键词已锁定
打开
); } function AgLinkInputCard({ onSubmit }) { const [value, setValue] = React.useState(''); const valid = /^https?:\/\/\S+$/i.test(value.trim()); const submit = () => { if (valid) onSubmit(value.trim()); }; return (
购买链接核验
粘贴商品详情页链接
setValue(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') submit(); }} />
); } function AgOfferCard({ tv, source }) { const custom = source === '你提供的链接'; const checks = custom ? ['型号 / 尺寸一致', '销售主体可开票', '国补地区匹配', '无缩水后缀'] : ['型号关键词一致', '尺寸关键词一致', '进入商品页后核对店铺', '下单前确认地区补贴']; return (
{custom ? '购买链接核验' : '搜索入口检查'}{custom ? '通过 ✓' : '入口可用 ✓'}
{tv.brand} {tv.model} · {tv.size}″
{source}
{checks.map((check) => {check})}
价格和补贴会随地区与时间变化,下单当天建议再检查一次
); } /* ---- 聊天主体:剧本引擎 ---- */ function AgentChatInner({ onBack, onRestart, ask }) { const { useState, useEffect, useRef } = React; const [msgs, setMsgs] = useState([]); const [ov, setOv] = useState(null); // 'ar' | 'lux' | 'room' const [ovData, setOvData] = useState(null); const seq = useRef(0); const alive = useRef(true); const pend = useRef(null); // 选项或链接输入等待 {id, res} const ovRes = useRef(null); // 浮层等待 resolve const scRef = useRef(null); useEffect(() => () => { alive.current = false; }, []); useEffect(() => { const el = scRef.current; if (el) el.scrollTo({ top: el.scrollHeight, behavior: AG_RM ? 'auto' : 'smooth' }); }, [msgs, ov]); const push = (m) => { const id = ++seq.current; setMsgs((s) => [...s, { id, ...m }]); return id; }; const patch = (id, p) => setMsgs((s) => s.map((m) => (m.id === id ? { ...m, ...p } : m))); const sleep = async (ms) => { await agSleep(ms); if (!alive.current) throw 0; }; const ai = async (text, wait = 950) => { const id = push({ kind: 'ai', typing: true }); await sleep(wait); patch(id, { typing: false, text }); await sleep(260); }; const tool = async (icon, name, detail, result, wait = 1400, mode = '') => { const id = push({ kind: 'tool', icon, name, mode, detail, state: 'run' }); await sleep(wait); patch(id, { state: 'done', result }); await sleep(320); }; const opts = (items, meta = null) => new Promise((res) => { const id = push({ kind: 'opts', items, meta }); pend.current = { id, res }; if (AG_AUTO) agSleep(1100).then(() => { if (pend.current && pend.current.id === id) pick(items.find((it) => it.auto) || items.find((it) => it.wide) || items[0]); }); }); const multiOpts = (items, meta = null, max = 3) => new Promise((res) => { const id = push({ kind: 'multi-opts', items, meta, selected: [], max }); pend.current = { id, res, items, selected: new Set(), max }; if (AG_AUTO) agSleep(900).then(() => { const p = pend.current; if (!p || p.id !== id) return; p.selected = new Set(items.filter((it) => it.auto).map((it) => it.v)); patch(id, { selected: [...p.selected] }); agSleep(260).then(() => confirmMulti(id)); }); }); const pick = (it) => { const p = pend.current; if (!p) return; pend.current = null; patch(p.id, { done: true }); push({ kind: 'user', text: it.bubble || it.label }); p.res(it); }; const toggleMulti = (id, it) => { const p = pend.current; if (!p || p.id !== id) return; if (p.selected.has(it.v)) p.selected.delete(it.v); else if (p.selected.size < p.max) p.selected.add(it.v); patch(id, { selected: [...p.selected] }); }; const confirmMulti = (id) => { const p = pend.current; if (!p || p.id !== id || !p.selected.size) return; const chosen = p.items.filter((it) => p.selected.has(it.v)); pend.current = null; patch(id, { done: true }); push({ kind: 'user', text: chosen.map((it) => it.short || it.label).join(' + ') }); p.res(chosen); }; const submitLink = (id, value) => { const p = pend.current; if (!p || p.id !== id) return; pend.current = null; patch(id, { done: true, value }); push({ kind: 'user', text: '核验我找到的商品链接' }); p.res(value); }; const linkInput = (tv) => new Promise((res) => { const demoUrl = agPurchaseUrl(tv); const id = push({ kind: 'link-input', demoUrl }); pend.current = { id, res }; if (AG_AUTO) agSleep(1100).then(() => submitLink(id, demoUrl)); }); const ovRun = (kind, data = null) => new Promise((res) => { ovRes.current = res; setOvData(data); setOv(kind); }); const ovDone = (payload = null) => { setOv(null); setOvData(null); const r = ovRes.current; ovRes.current = null; if (r) r(payload); }; /* 剧本路由:三个建议问题各走一条;其余(固定命令/自由输入)走主线 */ useEffect(() => { const go = ask === AG_ASKS[1] ? runGlare : ask === AG_ASKS[2] ? runBurn : run; go().catch(() => {}); }, []); async function runMountFlow(tv) { let selected = null; let previewSaved = false; let choosing = true; await ai('支架我单独帮你选。先定安装方式和款式;立式再看升降与电动,最后选颜色。选好后还能直接放进你家客厅看看。'); while (choosing) { const mode = await opts([ { label: '立式', sub: '不打墙,款式更多', v: 'floor', accent: true, auto: true }, { label: '壁挂', sub: '更省地面空间', v: 'wall' }, ], { tool: 'recommend_tv_accessories', title: '支架怎么安装?' }); const styles = AG_MOUNT_STYLES[mode.v]; const style = await opts(styles.map((item, i) => ({ label: item.name, sub: item.desc, v: item.id, image: item.image, item, auto: i === 1, })), { tool: 'recommend_tv_accessories', title: `选择${mode.v === 'floor' ? '立式' : '壁挂'}款式` }); let lift = { label: '固定安装', v: 'fixed' }; let power = { label: '非电动', v: 'none' }; if (mode.v === 'floor') { lift = await opts([ { label: '固定高度', sub: '结构最简单', v: 'fixed', auto: true }, { label: '需要升降', sub: '沙发与餐桌视线都能兼顾', v: 'lift', accent: true }, ], { tool: 'recommend_tv_accessories', title: '需要升降吗?' }); } if (lift.v === 'lift' && style.v === 'mobile') { power = await opts([ { label: '手动调节', sub: '偶尔调一次即可', v: 'manual', auto: true }, { label: '电动升降', sub: '遥控调高低', v: 'electric', accent: true }, ], { tool: 'recommend_tv_accessories', title: '升降方式' }); } else if (lift.v === 'lift') { power = { label: '手动调节', v: 'manual' }; } const colorSet = style.v === 'easel' ? [ { label: '胡桃木', v: 'walnut', hex: '#6B4430' }, { label: '浅橡木', v: 'oak', hex: '#C49A68' }, { label: '曜石黑', v: 'black', hex: '#24252A' }, ] : mode.v === 'floor' ? [ { label: '曜石黑', v: 'black', hex: '#24252A' }, { label: '云母灰', v: 'gray', hex: '#777A80' }, { label: '奶油白', v: 'white', hex: '#E9E2D6' }, ] : [ { label: '曜石黑', v: 'black', hex: '#24252A' }, { label: '云母灰', v: 'gray', hex: '#777A80' }, { label: '钛金色', v: 'titanium', hex: '#A59A88' }, ]; const color = await opts(colorSet.map((item, i) => ({ ...item, swatch: item.hex, auto: i === 0 })), { tool: 'recommend_tv_accessories', title: '选择颜色', }); const wallAdjustment = style.v === 'tilt' ? '俯仰调节' : style.v === 'arm' ? '全向调节' : '固定安装'; selected = { mode: mode.v, modeLabel: mode.v === 'floor' ? '立式' : '壁挂', style: style.item, lift: mode.v === 'wall' ? wallAdjustment : lift.v === 'lift' ? '可升降' : '固定高度', power: power.label, color, }; await tool('layers', 'recommend_tv_accessories', `${tv.size}″ · ${selected.modeLabel} · ${selected.style.name} · ${selected.lift} · ${selected.power}`, 'needs_confirmation · 尺寸范围通过,VESA 与承重待商品页核对', 1100, 'recommend'); push({ kind: 'mount-result', mount: selected, tv }); await sleep(650); const next = await opts([ { label: '放进我家看看', sub: '调用“在我家试电视”合成', v: 'preview', accent: true }, { label: '换一个支架', v: 'again' }, { label: '选这个,回到电视方案', v: 'done', auto: true }, ], { tool: 'recommend_tv_accessories', title: '支架方案下一步' }); if (next.v === 'again') continue; if (next.v === 'preview') { await tool('sparkle', 'evaluate_room_and_size', `${tv.brand} ${tv.model} + ${selected.style.name} + ${selected.color.label}`, 'needs_input · 请确认客厅摆放效果', 850, 'room_preview'); const roomResult = await ovRun('room', { tv, mount: selected }); if (roomResult) { previewSaved = true; push({ kind: 'room-preview', tv, mount: selected }); await sleep(550); await ai('这套电视和支架已经按客厅尺度合成并保存。'); } else { await ai('合成没有保存,但刚才选的支架方案还在。'); } const afterPreview = await opts([ { label: previewSaved ? '回到电视方案' : '保留支架并返回', v: 'done', accent: true, auto: true }, { label: '换一个支架', v: 'again' }, ], { tool: 'recommend_tv_accessories', title: '完成支架选择' }); if (afterPreview.v === 'again') continue; } choosing = false; } return { mount: selected, previewSaved }; } async function run() { push({ kind: 'user', text: ask || AG_CMD }); await sleep(650); await tool('database', 'research_products', '先了解尺寸、家庭使用方式和预算', 'needs_input · 还差 3 个关键信息', 1200, 'candidate_search'); await ai('没问题。要把客厅电视选准,我先确认三件事:多大、家里谁用和主要看什么、预算多少。如果尺寸拿不准,我也可以帮你量。'); const s = await opts([ { label: '75″', sub: '视距 2.3 – 2.8 m', v: 75 }, { label: '85″', sub: '视距 2.8 – 3.4 m', v: 85 }, { label: '98″ 以上', sub: '视距 3.4 m+', v: 98 }, { label: '不知道怎么选,帮我量一下', sub: '用手机测电视墙和观看距离', v: 'ar', accent: true, wide: true, auto: true, bubble: '不知道怎么选' }, ], { tool: 'research_products', title: '1 / 3 · 先确定尺寸或测量空间' }); let size = s.v; if (size === 'ar') { await tool('cube', 'evaluate_room_and_size', '需要电视墙净宽和观看距离', 'needs_input · 请扫描电视墙', 850, 'room_preview'); await ai('尺寸拿不准很正常。请把镜头对准电视墙,慢慢扫一圈;我会一起看墙宽和观看距离。', 750); await sleep(900); await ovRun('ar'); push({ kind: 'ar' }); await sleep(750); await ai('量好了:电视墙净宽 3.62 m,观看距离 2.9 m。85″ 最合适;98″ 虽然放得下,但坐得有点近。我先按 85″ 给你选。'); size = 85; } const usage = await multiOpts([ { label: '电影 / 流媒体', short: '电影', sub: 'HDR、暗场、杜比与应用兼容', v: 'movie', auto: true }, { label: '主机 / PC 游戏', short: '游戏', sub: '4K 高刷、VRR 与低延迟', v: 'game', auto: true }, { label: '电视直播 / 体育综艺', short: '直播体育', sub: '换台快、运动清晰、长时间亮屏', v: 'live' }, { label: '长辈经常使用', short: '长辈使用', sub: '开机直达、少广告、语音好用', v: 'senior' }, { label: '儿童 / 全家共看', short: '儿童家庭', sub: '护眼、家长控制与防倾倒', v: 'family' }, { label: '手机投屏 / K歌', short: '投屏娱乐', sub: '投屏稳定、麦克风与家庭娱乐', v: 'cast' }, ], { tool: 'research_products', title: '2 / 3 · 主要怎么用(最多选 3 项)' }); const usageValues = usage.map((it) => it.v); const usageLabel = usage.map((it) => it.short || it.label).join(' + '); const usageSignals = [ usageValues.includes('movie') && '流媒体 · HDR 音画', usageValues.includes('game') && '主机 / PC · 4K 高刷 · VRR', usageValues.includes('live') && '直播源 · 开机直达 · 长时稳定', usageValues.includes('senior') && '简洁系统 · 语音 · 少广告', usageValues.includes('family') && '护眼 · 家长控制 · 防倾倒', usageValues.includes('cast') && '投屏 · 麦克风兼容', ].filter(Boolean).join(' · '); /* AG_ASKS[0]「预算 1.5 万」:预算已知,不再重复追问,按在库真实价位直接落档 */ const preBud = ask === AG_ASKS[0]; let b; if (!preBud) { b = await opts(AG_BUDGETS[size].map((it) => ({ ...it, auto: it.v === '85mid' })), { tool: 'research_products', title: '3 / 3 · 电视本体预算' }); } else if (size === 85) { await ai('预算 1.5 万已经在你的消息里,我不重复问。它正好落在 85″ 甜点档。'); b = { label: '1 – 1.5 万', v: '85mid' }; } else if (size === 75) { await ai('75″ 目前最贵的候选约 ¥9,749,1.5 万预算用不完。我会保留升级尺寸的余量,不为了花满而抬价。'); b = { label: '1 万左右', v: '75b2' }; } else { await ai('98″ 目前约 ¥28,999 起,1.5 万预算不够。你可以回到 85″ 选更好的画质,也可以增加预算上百吋。'); const g = await opts([ { label: '那就 85″ 里选最强', v: '85mid', accent: true, auto: true }, { label: '加预算,上百吋', v: '98b1' }, ], { tool: 'research_products', title: '硬条件冲突 · 请选择调整项', status: 'needs_confirmation' }); if (g.v === '85mid') { size = 85; b = { label: '1 – 1.5 万', v: '85mid' }; } else b = { label: '3 万左右', v: '98b1' }; } const P = agPickFor(b.v, usageValues); await tool('database', 'research_products', `${size}″ · ${usageLabel} · ${b.label} · 读取实测与证据`, `已完成 · 58 台评测 → 命中 ${AG_HIT[size]} 台 → 2 台证据完整`, 1500, 'candidate_search'); await tool('bolt', 'plan_device_setup', usageSignals, 'ok · 端口、协议与内容兼容无硬伤', 1200, 'compatibility_check'); await tool('cube', 'plan_installation_and_delivery', `${size}″ 包装箱 × 电梯 × 入户门 × 支架安装`, 'ok · 入户可行,立式 / 壁挂均可选', 1350, 'precheck'); push({ kind: 'entry', size }); await sleep(650); await tool('activity', 'compare_products', '候选 2 台 · 保留原始实测口径 · 当前场景权重', 'ok · 排序、优势、短板与妥协已生成', 1500, 'compare'); push({ kind: 'compare', tvs: [P.main, P.alt], scene: `${usageLabel} · ${size}″ · ${b.label}` }); await sleep(850); await ai(`${P.say} 我把两台最值得看的关键差异列在下面,你可以切换“关键实测、场景适配、价格”看看。`); const fb = await opts([ { label: `选首选 · ${P.main.brand} ${P.main.model}`, v: 'main', accent: true, auto: true }, { label: `选备选 · ${P.alt.brand} ${P.alt.model}`, v: 'alt' }, ], { tool: 'compare_products', title: '根据对比结果确认候选', status: 'needs_confirmation' }); const selected = fb.v === 'alt' ? P.alt : P.main; if (fb.v === 'alt') await ai(P.altSay, 700); push({ kind: 'tv', tv: selected, tag: fb.v === 'alt' ? '你的选择 · 备选' : '你的选择 · 首选' }); await sleep(750); const needsSoundbar = usageValues.includes('movie'); await tool('layers', 'recommend_tv_accessories', '根据电视、设备链、安装方式与已有配件分析缺口', `needs_confirmation · 1 required / ${needsSoundbar ? 1 : 0} recommended / ${needsSoundbar ? 2 : 3} not_needed`, 1200, 'needs_assessment'); push({ kind: 'accessory-needs', usage: usageValues }); await sleep(650); await ai('我先把该买、可买和不用买的配件分开,避免你多花冤枉钱。'); const ac = await opts([ { label: '继续推荐支架', v: 'y', accent: true, small: true, auto: true }, { label: '支架以后再说', v: 'n', small: true }, ], { tool: 'recommend_tv_accessories', title: '是否继续选支架?', status: 'needs_confirmation' }); let mountPlan = null; let soundbarAdded = false; if (ac.v === 'y') { const mountResult = await runMountFlow(selected); mountPlan = mountResult.mount; await ai(`支架方案先收好。现在回到电视本体:你选的仍是 ${selected.brand} ${selected.model}。`); push({ kind: 'return-tv', tv: selected, mount: mountPlan }); await sleep(650); } if (needsSoundbar) { const sb = await opts([ { label: '继续看回音壁', v: 'y', small: true }, { label: '声音以后再说', v: 'n', small: true, auto: true }, ], { tool: 'recommend_tv_accessories', title: '电影使用较多,是否继续看声音方案?' }); if (sb.v === 'y') { await tool('broadcast', 'recommend_tv_accessories', '电影权重 · eARC · 杜比全景声', 'ok · 回音壁类别建议已生成', 900, 'recommend'); push({ kind: 'soundbar' }); soundbarAdded = true; await sleep(550); } } await ai('我先给你一个匹配当前型号的搜索入口。你也可以把自己看到的商品链接贴进来,我会核对型号、尺寸、版本、店铺和补贴资格。'); push({ kind: 'buy-link', tv: selected }); await sleep(650); const vf = await opts([ { label: '检查推荐入口', v: 'recommended', accent: true, auto: true }, { label: '粘贴我的链接', v: 'custom' }, { label: '暂时不用', v: 'skip' }, ], { tool: 'verify_model_and_offer', title: '选择要检查的入口或链接', status: 'needs_confirmation' }); let linkChecked = false; let linkSource = null; if (vf.v !== 'skip') { let source = '推荐搜索入口'; if (vf.v === 'custom') { await tool('search', 'verify_model_and_offer', '需要商品详情页链接', 'needs_input · PurchaseLinkInput', 850, 'verify'); await linkInput(selected); source = '你提供的链接'; } const verifyResult = source === '你提供的链接' ? 'ok · 型号、尺寸、版本与销售条件一致' : 'ok · 推荐入口可用,具体店铺与补贴需进入商品页确认'; await tool('search', 'verify_model_and_offer', `${source} · ${selected.brand} ${selected.model} · 上海地区`, verifyResult, 1400, 'verify'); push({ kind: 'offer', tv: selected, source }); linkSource = source; linkChecked = true; await sleep(650); } await ai(linkChecked ? linkSource === '你提供的链接' ? '你贴的商品链接与推荐机型一致,可以按核验结果继续;下单当天我建议再看一次最终价格和补贴。' : '推荐搜索入口已经按目标型号和尺寸匹配好;进入具体商品页后,再核对店铺、版本和当地补贴。' : '机型和配件方案已经整理好。你准备下单时,把商品链接发给我,我再帮你核验一次。'); push({ kind: 'end', chips: [`${size}″`, b.label, `${selected.brand} ${selected.model}`, '对比已完成', mountPlan && `${mountPlan.style.name}支架`, soundbarAdded && '回音壁方案', linkChecked && (linkSource === '你提供的链接' ? '购买链接已核验 ✓' : '推荐入口已匹配')].filter(Boolean) }); } /* 剧本「反光」(AG_ASKS[1]):后台「光环境适配」引擎 + 前台「采光检测」小工具回传。 口径:全反射率(done) × 窗口亮度曲线(done·1%–100% 分档) × 满屏亮度(done) × 朝向反光风险规则(ext)。 结论逻辑:亮厅 ≠ 排除 OLED —— 混合画面下窗口高光 + 超低反射占优;满屏高亮内容才是 MiniLED 主场。 */ async function runGlare() { push({ kind: 'user', text: ask }); await sleep(650); await tool('sun', 'evaluate_room_and_size', '需要确认照度区间、直射方向和最差观看时段', 'needs_input · AmbientLightCapture', 1100, 'ambient_light'); await ai('怕反光我会分开看:全反射率决定倒影有多重,窗口和满屏亮度决定画面能不能压住环境光。缺少反射率实测的机型我会直接标“未测”,不拿亮度冒充抗反。先摸清你家多亮:白天阳光会直射到电视墙吗?'); const L = await opts([ { label: '会,西晒 / 落地窗直射', v: 'hard' }, { label: '挺亮,但晒不到屏幕', v: 'soft' }, { label: '说不准,帮我测一下', sub: '拍两张照片测反光和照度', v: 'lux', accent: true, wide: true, auto: true, bubble: '说不准,帮我测一下' }, ], { tool: 'evaluate_room_and_size', title: '采集客厅光环境', status: 'needs_input' }); let lvl = L.v; if (lvl === 'lux') { await ai('说不准没关系。请分别对着电视墙和窗户拍一张,我帮你估照度和直射时段。', 750); await sleep(900); await ovRun('lux'); push({ kind: 'lux' }); await sleep(750); await ai('测好了:午后峰值约 1400 lux,西晒直射约 2 小时,属于强光客厅。我按最严格的抗反和亮度标准筛。'); lvl = 'hard'; } else { await ai(lvl === 'hard' ? '西晒直射是最难伺候的光,我按 1500 lux 高光害标准筛。' : '没有直射就好办,按 600–800 lux 明亮客厅的标准筛。', 800); } await tool('sun', 'evaluate_room_and_size', '照度区间 × 直射方向 × 反光源', 'ok · 抗反需求高 · 最差观看时段 15:00–17:00', 1200, 'ambient_light'); await ai('亮厅不等于不能买 OLED。LG G5 在本地报告的 HDR 影院模式峰值是 2484 nit,全反射率 0.816%,看电影、剧和游戏这类混合画面很有优势;但如果经常看满屏明亮的体育和综艺,还要重点看 100% 窗口实测。'); await ai('所以真正的分水岭是内容:满屏高亮画面看得多不多。白天开电视,你们主要看什么?', 850); const R = await opts([ { label: '电影 / 剧 / 游戏为主', sub: '混合画面 · 高光都在窗口档', v: 'oled', auto: true }, { label: '体育·综艺·新闻开一天', sub: '满屏亮画面多 · 吃持续输出', v: 'mled' }, ], { tool: 'research_products', title: '补充内容类型,决定亮度路线' }); let P, bud; if (R.v === 'oled') { P = AG_GLARE.oled; bud = '2 万档'; } else { await ai('满屏亮画面更需要看 100% 窗口,而不是只看宣传峰值。预算大概什么范围?', 850); const b = await opts([ { label: '7 – 8 千', v: 'g07' }, { label: '1 万左右', v: 'g1' }, { label: '1.5 万左右', v: 'g15', auto: true }, { label: '3 万左右,上百吋', v: 'gbig' }, ], { tool: 'research_products', title: '电视本体预算' }); P = AG_GLARE[b.v]; bud = b.label; } await tool('database', 'research_products', `${R.v === 'oled' ? '已测反射率 + HDR 峰值' : '100% 窗口 + 抗反证据状态'} · ${bud}`, 'ok · 候选实测与缺失项均已标注', 1350, 'candidate_search'); await tool('activity', 'compare_products', '全反射率 · HDR 峰值 / 100% 窗口 · 尺寸 · 价格', 'ok · 2 台按原始实测口径对比', 1450, 'compare'); push({ kind: 'compare', tvs: [P.main, P.alt], scene: `强光客厅 · ${R.v === 'oled' ? '混合画面' : '满屏亮画面'}` }); await sleep(800); await ai(`${P.say} 下面把两台的关键实测和价格放在一起,你可以直接比较。`); const fb = await opts([ { label: '很合适,就它了', v: 'ok', accent: true, auto: true }, { label: '再看看备选', v: 'alt' }, ], { tool: 'compare_products', title: '确认当前路线', status: 'needs_confirmation' }); const chosen = fb.v === 'alt' ? P.alt : P.main; if (fb.v === 'alt') { await ai(P.altSay, 700); } push({ kind: 'tv', tv: chosen, tag: fb.v === 'alt' ? '你的选择 · 备选' : '你的选择 · 首选' }); await sleep(650); await ai('到货后告诉我电视型号和连接设备,我再按你家的光环境把亮度、HDR 和护眼设置调好。'); push({ kind: 'end', chips: [`${chosen.size}″`, bud, `${chosen.brand} ${chosen.model}`, chosen.refl != null ? '反射率已实测 ✓' : '反射率待补测', L.v === 'lux' && '照度已实测 ✓', '对比已完成'].filter(Boolean) }); } /* 剧本「烧屏」(AG_ASKS[2]):evaluate_lifecycle_options 评估长期风险 → compare_products 对比 OLED / MiniLED。 耐久库口径照实:质保条款已入库,烧屏/衰减实测 tier=todo(进行中)。 */ async function runBurn() { push({ kind: 'user', text: ask }); await sleep(650); await tool('gear', 'evaluate_lifecycle_options', '检索烧屏机制、防护能力、质保条款与使用风险', 'needs_input · UsageMixSelector', 1300, 'reliability_risk'); await ai('直说结论:OLED 确实存在烧屏风险,但风险主要取决于使用习惯。台标、比分牌、游戏血条这类固定画面停留越久,风险越高;正常混着看,并保持像素位移和补偿刷新开启,风险会低很多。'); await ai('风险大小主要看用法——你家电视平时开着干嘛?', 800); const u = await opts([ { label: '剧 / 电影为主,内容很杂', v: 'mix', auto: true }, { label: '新闻·体育台,一挂一整天', v: 'logo' }, { label: '主机游戏比较多', v: 'game' }, ], { tool: 'evaluate_lifecycle_options', title: '长期风险取决于固定画面与连续时长' }); await tool('activity', 'evaluate_lifecycle_options', '使用结构 × ABL 行为 × 质保条款 × 耐久证据', 'partial · 条款已入库,长期衰减实测进行中', 1500, 'reliability_risk'); const RISK = { mix: ['低风险用法 ✓', '你的内容一直在换,属于相对低风险的用法。OLED 可以优先考虑,但不要关闭系统自带的像素刷新。'], logo: ['高风险用法 ⚠', '固定台标 + 长时间开机是烧屏最高危组合,我不建议上 OLED——MiniLED 是背光方案,物理上不存在烧屏,这个用法选它更省心。'], game: ['中风险用法', '游戏属于中风险:血条和小地图位置固定,但 OLED 的响应速度确实更有优势。保持像素位移开启,并避免固定界面长时间连续显示,风险会更可控。'], }[u.v]; await ai(RISK[1]); await ai('要不要我把两条路线各拉一台实测对比?看完你心里就有数了。', 800); const c = await opts([ { label: '对比给我看', v: 'y', accent: true, auto: true }, { label: '不用,我了解了', v: 'n' }, ]); if (c.v === 'y') { await tool('database', 'research_products', 'OLED 与 MiniLED 各建立一个有完整证据的候选', 'ok · OLED 5 台 / MiniLED 30+ 台', 1200, 'candidate_search'); await tool('activity', 'compare_products', '黑位 · HDR 峰值 · 响应 · 反射率 · 长期风险', 'ok · 2 台保留各自报告模式', 1400, 'compare'); const burnTvs = u.v === 'logo' ? [AG_BURN.mled, AG_BURN.oled] : [AG_BURN.oled, AG_BURN.mled]; push({ kind: 'compare', tvs: burnTvs, scene: `${RISK[0]} · OLED vs MiniLED` }); await sleep(800); await ai('一句话总结:固定台标开一整天选 MiniLED;内容混着看、追求暗场和响应,可以选 OLED 并保留像素刷新。完整指标已经列在下面。'); push({ kind: 'end', chips: ['烧屏答疑 ✓', RISK[0], 'OLED vs MiniLED', '实测对比 2 台'] }); } else { await ai('行。送你三条防烧屏习惯:① 像素刷新保持开启;② 亮度别常年拉满;③ 长时间暂停记得息屏。真到要买的时候回来找我,我帮你核对具体机型的烧屏质保条款。'); push({ kind: 'end', chips: ['烧屏答疑 ✓', RISK[0], '防烧屏习惯 ×3'] }); } } return (
AI 选购助手已接入 {DB_STATS.inStock} 台电视评测库
{msgs.map((m) => { switch (m.kind) { case 'user': return
{m.text}
; case 'ai': return (
{m.typing ? : m.text}
); case 'tool': return (
{agToolLabel(m.name)} {agResultLabel(m.state === 'done' ? m.result : m.detail)}
{m.state === 'run' ? : }
); case 'opts': return m.done ? null : (
{m.meta && <>
{agToolLabel(m.meta.tool)}
{m.meta.title}
}
{m.items.map((it, i) => ( ))}
); case 'multi-opts': return m.done ? null : (
{m.meta && <>
{agToolLabel(m.meta.tool)}
{m.meta.title}
}
{m.items.map((it) => { const selected = m.selected.includes(it.v); const maxed = m.selected.length >= m.max && !selected; return ( ); })}
); case 'ar': return ; case 'lux': return ; case 'entry': return ; case 'tv': return ; case 'trade': return ; case 'compare': return ; case 'accessory-needs': return ; case 'mount-result': return ; case 'soundbar': return ; case 'room-preview': return ; case 'return-tv': return ; case 'buy-link': return ; case 'link-input': return m.done ? null : submitLink(m.id, value)} />; case 'offer': return ; case 'end': return ; default: return null; } })}
{msgs.some((m) => m.kind === 'link-input' && !m.done) ? '请粘贴商品链接继续' : msgs.some((m) => m.kind === 'opts' && !m.done) ? '请选择一个选项继续' : msgs.some((m) => m.kind === 'end') ? '方案已整理好 · 可以重新选择或返回主页' : '正在为你整理…'}
{ov === 'ar' && } {ov === 'lux' && } {ov === 'room' &&
ovDone(null)} onComplete={ovDone} initialTv={ovData && ovData.tv} initialMount={ovData && ovData.mount && ovData.mount.mode} standSelection={ovData && ovData.mount} initialPhase="place" />
}
); } /* 外壳:epoch 换 key 实现「重新演示」整段重跑 */ function AgentChat(props) { const { useState } = React; const [ep, setEp] = useState(0); return setEp((e) => e + 1)} />; } Object.assign(window, { AgentChat, AG_ASKS });