作者:微信小助手
<p cid="n0" mdtype="paragraph" style="margin-top: 16px;margin-bottom: 24px;line-height: 2em;" data-pm-slice="0 0 []"><span md-inline="plain"><span leaf="" style="color: rgba(0, 0, 0, 0.9);font-size: 17px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.034em;font-style: normal;font-weight: normal;>兄弟们,有没有遇到过这种情况:凌晨三点在某东抢购显卡,刚提交订单就提示"系统繁忙",转头发现黄牛已经在海鲜市场挂出同款;扫码支付时突然弹出风险提示,非要验证人脸识别;更绝的是某银行APP,刚输完密码就收到短信提醒:"检测到您的账户存在异常操作"——但此时您根本没动过手机。</span></span></p> <p cid="n2" mdtype="paragraph" style="margin-top: 24px;margin-bottom: 24px;line-height: 2em;"><span md-inline="plain"><span leaf="" style="color: rgba(0, 0, 0, 0.9);font-size: 17px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.034em;font-style: normal;font-weight: normal;>这些让人又爱又恨的操作背后,都藏着一个叫"实时风控"的技术妖怪。今天咱们就来扒一扒,这个妖怪是如何用 Redis 和 AI 模型在 0.1 秒内完成逆天操作的。</span></span></p> <p cid="n2" mdtype="paragraph" style="margin-top: 24px;margin-bottom: 24px;line-height: 2em;"><span md-inline="plain"><span leaf="" style="color: rgba(0, 0, 0, 0.9);font-size: 17px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.034em;font-style: normal;font-weight: normal;><br></span></span></p> <section data-mpa-template="t" mpa-from-tpl="t" data-mpa-action-id="m8zww6721txr"> <section data-mpa-template="t" mpa-from-tpl="t"> <h4 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: 400;font-size: 16px;text-align: justify;outline: 0px;color: rgb(34, 34, 34);letter-spacing: 0.544px;caret-color: rgb(51, 51, 51);line-height: 2em;"><span style="font-size: 20px;"><strong mpa-from-tpl="t" style="outline: 0px;"><span mpa-is-content="t" style="font-size: 20px;outline: 0px;color: rgb(0, 122, 170);"><span leaf="">一、传统风控系统的"慢动作"人生</span></span></strong></span></h4> </section> </section> <p cid="n4" mdtype="paragraph" style="margin-top: 24px;margin-bottom: 24px;line-height: 2em;"><span md-inline="plain"><span leaf="" style="color: rgba(0, 0, 0, 0.9);font-size: 17px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.034em;font-style: normal;font-weight: normal;>先带大家看看传统风控系统是怎么工作的。假设你要在电商平台买东西,风控流程大概是这样:</span></span></p> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n7" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">数据采集</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:收集你的 IP 地址、设备指纹、行为轨迹等信息</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n9" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">特征提取</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:把这些信息转换成"用户画像"特征</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n11" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">规则匹配</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:用预先设定的风控规则进行判断(比如"同一 IP 10 分钟内下单 3 次触发警报")</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n13" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">人工审核</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:如果规则命中,进入漫长的人工复核流程 </span></span></p></li> </ol> <p cid="n14" mdtype="paragraph" style="box-sizing: border-box;line-height: 2em;orphans: 4;margin: 24px 0px;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">但问题来了:</span></span></span></p> <ul style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n17" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">延迟高</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:从数据采集到最终决策可能需要几分钟甚至几十分钟</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n19" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">规则僵化</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:道高一尺魔高一丈,规则永远追不上黑产的创新速度</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n21" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">成本爆炸</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:每增加一条规则都需要大量人力维护 </span></span></p></li> </ul> <p cid="n22" mdtype="paragraph" style="box-sizing: border-box;line-height: 2em;orphans: 4;margin: 24px 0px;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">举个栗子:某支付公司曾因为风控规则更新不及时,被羊毛党用"0.01元拼团"活动薅走 3000 万。等风控团队发现时,黑产已经换了三个作案手法。</span></span></span></p> <section mpa-from-tpl="t" data-mpa-action-id="m8zwxir7ofp" data-pm-slice="0 0 []"> <span leaf=""><br></span> </section> <section data-mpa-template="t" mpa-from-tpl="t" data-mpa-action-id="m8zwxir7jni"> <section data-mpa-template="t" mpa-from-tpl="t"> <h4 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: 400;font-size: 16px;text-align: justify;outline: 0px;color: rgb(34, 34, 34);letter-spacing: 0.544px;caret-color: rgb(51, 51, 51);line-height: 2em;"><span style="font-size: 20px;"><strong mpa-from-tpl="t" style="outline: 0px;"><span mpa-is-content="t" style="font-size: 20px;outline: 0px;color: rgb(0, 122, 170);"><span leaf="">二、Redis+AI 组合拳:给风控装上"超跑引擎"</span></span></strong></span></h4> </section> </section> <p cid="n25" mdtype="paragraph" style="box-sizing: border-box;line-height: 2em;orphans: 4;margin: 24px 0px;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">现在轮到我们的主角闪亮登场了:</span></span></span></p> <h3 cid="n26" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 2;font-size: 1.5em;margin-top: 24px;margin-bottom: 24px;font-weight: bold;line-height: 2em;cursor: text;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">(一)Redis:内存界的"闪电侠"</span></span></span></h3> <ul style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n29" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">速度快</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:读写速度可达 10 万次/秒,延迟低至 0.1 毫秒</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n31" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">数据结构丰富</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:支持哈希、列表、位图等 10 种数据结构</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n33" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">持久化机制</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:RDB+AOF 双重保障,数据安全不丢失</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n35" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">分布式特性</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:轻松支撑每秒百万级请求 </span></span></p></li> </ul> <p cid="n36" mdtype="paragraph" style="box-sizing: border-box;line-height: 2em;orphans: 4;margin: 24px 0px;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">想象一下,把用户行为数据比作快递包裹,Redis 就是 24 小时营业的智能快递柜,能瞬间完成包裹的存取和分拣。</span></span></span></p> <h3 cid="n37" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 2;font-size: 1.5em;margin-top: 24px;margin-bottom: 24px;font-weight: bold;line-height: 2em;cursor: text;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">(二)AI 模型:风控界的"福尔摩斯"</span></span></span></h3> <ul style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n40" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">机器学习</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:通过历史数据训练模型,自动识别异常行为模式</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n42" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">深度学习</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:处理高维复杂数据(比如设备指纹、行为轨迹)</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n44" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">实时更新</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:模型可在线增量学习,动态调整风控策略 </span></span></p></li> </ul> <p cid="n45" mdtype="paragraph" style="box-sizing: border-box;line-height: 2em;orphans: 4;margin: 24px 0px;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">传统规则是"看见红灯就停车",而 AI 模型是"分析路况、车流量、行人状态后智能决策"。</span></span></span></p> <h3 cid="n46" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 2;font-size: 1.5em;margin-top: 24px;margin-bottom: 24px;font-weight: bold;line-height: 2em;cursor: text;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">(三)组合后的化学反应</span></span></span></h3> <p cid="n47" mdtype="paragraph" style="box-sizing: border-box;line-height: 2em;orphans: 4;margin: 24px 0px;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">当 Redis 遇到 AI,就像给赛车装上了核动力引擎:</span></span></span></p> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n50" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">实时数据采集</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:用户行为数据毫秒级写入 Redis</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n52" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">特征实时计算</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:利用 Redis 的计算能力预处理数据</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n54" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">模型在线推理</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:AI 模型在 Redis 集群中并行运算</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n56" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">决策实时反馈</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:结果直接返回业务系统 </span></span></p></li> </ol> <p cid="n57" mdtype="paragraph" style="box-sizing: border-box;line-height: 2em;orphans: 4;margin: 24px 0px;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">某头部支付公司实测:通过这种组合,风控决策时间从 800ms 降至 70ms,误报率下降 65%。</span></span></span></p> <section mpa-from-tpl="t" data-mpa-action-id="m8zwylxi1tor" data-pm-slice="0 0 []"> <span leaf=""><br></span> </section> <section data-mpa-template="t" mpa-from-tpl="t" data-mpa-action-id="m8zwylxi2109"> <section data-mpa-template="t" mpa-from-tpl="t"> <h4 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: 400;font-size: 16px;text-align: justify;outline: 0px;color: rgb(34, 34, 34);letter-spacing: 0.544px;caret-color: rgb(51, 51, 51);line-height: 2em;"><span style="font-size: 20px;"><strong mpa-from-tpl="t" style="outline: 0px;"><span mpa-is-content="t" style="font-size: 20px;outline: 0px;color: rgb(0, 122, 170);"><span leaf="">三、实战指南:如何用 Redis+AI 实现实时风控</span></span></strong></span></h4> </section> </section> <p cid="n59" mdtype="paragraph" style="box-sizing: border-box;line-height: 2em;orphans: 4;margin: 24px 0px;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">接下来进入硬核环节,咱们一步步拆解实现过程。为了方便理解,这里用电商场景举例。</span></span></span></p> <h3 cid="n60" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 2;font-size: 1.5em;margin-top: 24px;margin-bottom: 24px;font-weight: bold;line-height: 2em;cursor: text;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">(一)系统架构设计</span></span></span></h3> <pre spellcheck="false" lang="plain" cid="n61" mdtype="fences" style="box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;display: block;break-inside: avoid;text-align: left;white-space: normal;background-image: inherit;background-position: inherit;background-size: inherit;background-repeat: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border: 1px solid rgb(231, 234, 237);border-radius: 3px;padding: 8px 4px 6px;margin-bottom: 15px;margin-top: 15px;width: inherit;color: rgb(51, 51, 51);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;"><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf="">用户行为 → 实时采集 → Redis 集群 → 特征工程 → AI 模型 → 决策引擎 → 业务系统</span></span></pre> <p cid="n62" mdtype="paragraph" style="box-sizing: border-box;line-height: 2em;orphans: 4;margin: 24px 0px;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">关键点:</span></span></span></p> <ul style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n65" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">数据管道</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:使用 Redis Streams 构建实时数据流</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n67" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">特征存储</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:用 Redis Hash 存储用户画像特征</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n69" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">模型部署</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:通过 Redis AI 模块加载 TensorFlow/PyTorch 模型</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n71" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">决策缓存</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:用 Redis Sorted Set 缓存高频决策结果</span></span></p></li> </ul> <h3 cid="n72" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 2;font-size: 1.5em;margin-top: 24px;margin-bottom: 24px;font-weight: bold;line-height: 2em;cursor: text;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">(二)数据采集与预处理</span></span></span></h3> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n75" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">埋点设计</span></span></strong></span></p></li> </ol> <pre spellcheck="false" lang="java" cid="n76" mdtype="fences" style="box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;display: block;break-inside: avoid;text-align: left;white-space: normal;background-image: inherit;background-position: inherit;background-size: inherit;background-repeat: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border: 1px solid rgb(231, 234, 237);border-radius: 3px;padding: 8px 4px 6px;margin-bottom: 15px;margin-top: 15px;width: inherit;color: rgb(51, 51, 51);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;"><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf="">// 伪代码:用户下单行为埋点</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 136, 85);"><span leaf="">void</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 255);"><span leaf="">onOrderSubmit</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">User</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">user</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">Order</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">order</span></span><span leaf="">) {</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf="">// 采集基础信息</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 136, 85);"><span leaf="">String</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">deviceId</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(152, 26, 26);"><span leaf="">=</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">user</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">getDeviceId</span></span><span leaf="">();</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 136, 85);"><span leaf="">String</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">ip</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(152, 26, 26);"><span leaf="">=</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">user</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">getIp</span></span><span leaf="">();</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 136, 85);"><span leaf="">long</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">timestamp</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(152, 26, 26);"><span leaf="">=</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">System</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">currentTimeMillis</span></span><span leaf="">();</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span cm-text="" style="box-sizing: border-box;"></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span cm-text="" style="box-sizing: border-box;"></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf="">// 写入 Redis Stream</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">redis</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">xadd</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"user_events:"</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(152, 26, 26);"><span leaf="">+</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">deviceId</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"*"</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"type"</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"order"</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"amount"</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">order</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">getAmount</span></span><span leaf="">());</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> }</span></span></pre> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n79" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">实时特征计算</span></span></strong></span></p></li> </ol> <pre spellcheck="false" lang="python" cid="n80" mdtype="fences" style="box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;display: block;break-inside: avoid;text-align: left;white-space: normal;background-image: inherit;background-position: inherit;background-size: inherit;background-repeat: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border: 1px solid rgb(231, 234, 237);border-radius: 3px;padding: 8px 4px 6px;margin-bottom: 15px;margin-top: 15px;width: inherit;color: rgb(51, 51, 51);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;"><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf=""># 示例:计算最近 5 分钟订单量</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">def</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 255);"><span leaf="">calculate_recent_orders</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">device_id</span></span><span leaf="">):</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf=""># 获取最近 5 分钟的事件</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">events</span></span><span leaf=""> = </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">redis</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">xrange</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"user_events:"</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(152, 26, 26);"><span leaf="">+</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">device_id</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"-"</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"+"</span></span><span leaf="">)</span></span><span leaf=""><br></span><span leaf=""><br></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf=""># 过滤出订单事件</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">orders</span></span><span leaf=""> = [</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">e</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">for</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">e</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">in</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">events</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">if</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">e</span></span><span leaf="">[</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">'type'</span></span><span leaf="">] == </span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">'order'</span></span><span leaf="">]</span></span><span leaf=""><br></span><span leaf=""><br></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf=""># 按时间倒序排序</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">orders</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">sort</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">key</span></span><span leaf="">=</span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">lambda</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">x</span></span><span leaf="">: </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">x</span></span><span leaf="">[</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">'timestamp'</span></span><span leaf="">], </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">reverse</span></span><span leaf="">=</span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">True</span></span><span leaf="">)</span></span><span leaf=""><br></span><span leaf=""><br></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf=""># 取最近 5 分钟的订单</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">recent_orders</span></span><span leaf=""> = [</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">o</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">for</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">o</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">in</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">orders</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">if</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">o</span></span><span leaf="">[</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">'timestamp'</span></span><span leaf="">] </span><span style="box-sizing: border-box;color: rgb(152, 26, 26);"><span leaf="">></span></span><span leaf=""> (</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">now</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(152, 26, 26);"><span leaf="">-</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(17, 102, 68);"><span leaf="">300000</span></span><span leaf="">)]</span></span><span leaf=""><br></span><span leaf=""><br></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">return</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(51, 0, 170);"><span leaf="">len</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">recent_orders</span></span><span leaf="">)</span></span></pre> <h3 cid="n81" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 2;font-size: 1.5em;margin-top: 24px;margin-bottom: 24px;font-weight: bold;line-height: 2em;cursor: text;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">(三)AI 模型构建与部署</span></span></span></h3> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n84" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">模型选择</span></span></strong></span></p></li> <ol style="box-sizing: border-box;margin: 0px;padding-left: 30px;" class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n87" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">二分类问题:逻辑回归、XGBoost、LightGBM</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n89" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">序列数据:LSTM、Transformer</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n91" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">高维稀疏数据:DeepFM、Wide & Deep</span></span></p></li> </ol> <li style="box-sizing: border-box;margin: 0px;"><p cid="n93" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">模型训练(示例)</span></span></strong></span></p></li> </ol> <pre spellcheck="false" lang="python" cid="n94" mdtype="fences" style="box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;display: block;break-inside: avoid;text-align: left;white-space: normal;background-image: inherit;background-position: inherit;background-size: inherit;background-repeat: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border: 1px solid rgb(231, 234, 237);border-radius: 3px;padding: 8px 4px 6px;margin-bottom: 15px;margin-top: 15px;width: inherit;color: rgb(51, 51, 51);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;"><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">import</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">xgboost</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">as</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">xgb</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">from</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">sklearn</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">model_selection</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">import</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">train_test_split</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf=""># 加载历史数据</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">data</span></span><span leaf=""> = </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">pd</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">read_csv</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">'risk_data.csv'</span></span><span leaf="">)</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">X</span></span><span leaf=""> = </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">data</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">drop</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">'label'</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">axis</span></span><span leaf="">=</span><span style="box-sizing: border-box;color: rgb(17, 102, 68);"><span leaf="">1</span></span><span leaf="">)</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">y</span></span><span leaf=""> = </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">data</span></span><span leaf="">[</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">'label'</span></span><span leaf="">]</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf=""># 划分训练集和测试集</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">X_train</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">X_test</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">y_train</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">y_test</span></span><span leaf=""> = </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">train_test_split</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">X</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">y</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">test_size</span></span><span leaf="">=</span><span style="box-sizing: border-box;color: rgb(17, 102, 68);"><span leaf="">0.2</span></span><span leaf="">)</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf=""># 训练 XGBoost 模型</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">model</span></span><span leaf=""> = </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">xgb</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">XGBClassifier</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">objective</span></span><span leaf="">=</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">'binary:logistic'</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">learning_rate</span></span><span leaf="">=</span><span style="box-sizing: border-box;color: rgb(17, 102, 68);"><span leaf="">0.1</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">max_depth</span></span><span leaf="">=</span><span style="box-sizing: border-box;color: rgb(17, 102, 68);"><span leaf="">3</span></span><span leaf="">)</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">model</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">fit</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">X_train</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">y_train</span></span><span leaf="">)</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf=""># 模型评估</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">accuracy</span></span><span leaf=""> = </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">model</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">score</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">X_test</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">y_test</span></span><span leaf="">)</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(51, 0, 170);"><span leaf="">print</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">f"Model accuracy: {accuracy}"</span></span><span leaf="">)</span></span></pre> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n97" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">模型部署到 Redis AI</span></span></strong></span></p></li> </ol> <pre spellcheck="false" lang="python" cid="n98" mdtype="fences" style="box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;display: block;break-inside: avoid;text-align: left;white-space: normal;background-image: inherit;background-position: inherit;background-size: inherit;background-repeat: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border: 1px solid rgb(231, 234, 237);border-radius: 3px;padding: 8px 4px 6px;margin-bottom: 15px;margin-top: 15px;width: inherit;color: rgb(51, 51, 51);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;"><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf=""># 保存模型到 Redis</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">import</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">redisai</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">as</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">rai</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">r</span></span><span leaf=""> = </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">rai</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">Client</span></span><span leaf="">()</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">r</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">modelset</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"risk_model"</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"TF"</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"CPU"</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">model_bytes</span></span><span leaf="">)</span></span></pre> <h3 cid="n99" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 2;font-size: 1.5em;margin-top: 24px;margin-bottom: 24px;font-weight: bold;line-height: 2em;cursor: text;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">(四)实时决策流程</span></span></span></h3> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n102" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">特征提取</span></span></strong></span></p></li> </ol> <pre spellcheck="false" lang="java" cid="n103" mdtype="fences" style="box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;display: block;break-inside: avoid;text-align: left;white-space: normal;background-image: inherit;background-position: inherit;background-size: inherit;background-repeat: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border: 1px solid rgb(231, 234, 237);border-radius: 3px;padding: 8px 4px 6px;margin-bottom: 15px;margin-top: 15px;width: inherit;color: rgb(51, 51, 51);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;"><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf="">// 从 Redis 获取用户特征</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">Map</span></span><span style="box-sizing: border-box;color: rgb(152, 26, 26);"><span leaf=""><</span></span><span style="box-sizing: border-box;color: rgb(0, 136, 85);"><span leaf="">String</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 136, 85);"><span leaf="">String</span></span><span style="box-sizing: border-box;color: rgb(152, 26, 26);"><span leaf="">></span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">features</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(152, 26, 26);"><span leaf="">=</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">redis</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">hgetall</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"user_features:"</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(152, 26, 26);"><span leaf="">+</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">userId</span></span><span leaf="">);</span></span></pre> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n106" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">模型推理</span></span></strong></span></p></li> </ol> <pre spellcheck="false" lang="python" cid="n107" mdtype="fences" style="box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;display: block;break-inside: avoid;text-align: left;white-space: normal;background-image: inherit;background-position: inherit;background-size: inherit;background-repeat: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border: 1px solid rgb(231, 234, 237);border-radius: 3px;padding: 8px 4px 6px;margin-bottom: 15px;margin-top: 15px;width: inherit;color: rgb(51, 51, 51);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;"><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf=""># 加载模型并进行预测</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">import</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">numpy</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">as</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">np</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">input_data</span></span><span leaf=""> = </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">np</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">array</span></span><span leaf="">([[</span><span style="box-sizing: border-box;color: rgb(51, 0, 170);"><span leaf="">float</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">features</span></span><span leaf="">[</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">'order_count'</span></span><span leaf="">]), </span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(51, 0, 170);"><span leaf="">float</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">features</span></span><span leaf="">[</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">'ip_blacklist_score'</span></span><span leaf="">])]])</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">result</span></span><span leaf=""> = </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">r</span></span><span leaf="">.</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">modelrun</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"risk_model"</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">inputs</span></span><span leaf="">=[</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">input_data</span></span><span leaf="">])</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">probability</span></span><span leaf=""> = </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">result</span></span><span leaf="">[</span><span style="box-sizing: border-box;color: rgb(17, 102, 68);"><span leaf="">0</span></span><span leaf="">][</span><span style="box-sizing: border-box;color: rgb(17, 102, 68);"><span leaf="">0</span></span><span leaf="">]</span></span></pre> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n110" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">决策逻辑</span></span></strong></span></p></li> </ol> <pre spellcheck="false" lang="java" cid="n111" mdtype="fences" style="box-sizing: border-box;overflow: visible;font-family: var(--monospace);font-size: 0.9em;display: block;break-inside: avoid;text-align: left;white-space: normal;background-image: inherit;background-position: inherit;background-size: inherit;background-repeat: inherit;background-attachment: inherit;background-origin: inherit;background-clip: inherit;background-color: rgb(248, 248, 248);border: 1px solid rgb(231, 234, 237);border-radius: 3px;padding: 8px 4px 6px;margin-bottom: 15px;margin-top: 15px;width: inherit;color: rgb(51, 51, 51);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;"><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf="">// 根据模型输出决定是否拦截</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">if</span></span><span leaf=""> (</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">probability</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(152, 26, 26);"><span leaf="">></span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(17, 102, 68);"><span leaf="">0.9</span></span><span leaf="">) {</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf="">// 高风险:拦截交易</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">return</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">new</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">RiskResult</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(34, 17, 153);"><span leaf="">true</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"高风险交易"</span></span><span leaf="">);</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> } </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">else</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">if</span></span><span leaf=""> (</span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">probability</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(152, 26, 26);"><span leaf="">></span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(17, 102, 68);"><span leaf="">0.7</span></span><span leaf="">) {</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf="">// 中风险:二次验证</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">return</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">new</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">RiskResult</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(34, 17, 153);"><span leaf="">true</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"需要短信验证"</span></span><span leaf="">);</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> } </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">else</span></span><span leaf=""> {</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(170, 85, 0);"><span leaf="">// 低风险:正常放行</span></span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">return</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(119, 0, 136);"><span leaf="">new</span></span><span leaf=""> </span><span style="box-sizing: border-box;color: rgb(0, 0, 0);"><span leaf="">RiskResult</span></span><span leaf="">(</span><span style="box-sizing: border-box;color: rgb(34, 17, 153);"><span leaf="">false</span></span><span leaf="">, </span><span style="box-sizing: border-box;color: rgb(170, 17, 17);"><span leaf="">"交易正常"</span></span><span leaf="">);</span></span><span leaf=""><br></span><span role="presentation" style="box-sizing: border-box;padding-right: 0.1px;"><span leaf=""> }</span></span></pre> <section mpa-from-tpl="t" data-mpa-action-id="m8zx0dwz1y87" data-pm-slice="0 0 []"> <span leaf=""><br></span> </section> <section data-mpa-template="t" mpa-from-tpl="t" data-mpa-action-id="m8zx0dwz3zx"> <section data-mpa-template="t" mpa-from-tpl="t"> <h4 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: 400;font-size: 16px;text-align: justify;outline: 0px;color: rgb(34, 34, 34);letter-spacing: 0.544px;caret-color: rgb(51, 51, 51);line-height: 2em;"><span style="font-size: 20px;"><strong mpa-from-tpl="t" style="outline: 0px;"><span mpa-is-content="t" style="font-size: 20px;outline: 0px;color: rgb(0, 122, 170);"><span leaf="">四、高级技巧:让系统飞起来的"黑科技"</span></span></strong></span></h4> </section> </section> <h3 cid="n113" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 2;font-size: 1.5em;margin-top: 24px;margin-bottom: 24px;font-weight: bold;line-height: 2em;cursor: text;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">(一)特征工程优化</span></span></span></h3> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n116" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">滑动窗口统计</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""> 使用 Redis HyperLogLog 统计独立用户数,SORTED SET 实现滑动窗口。</span></span></p></li> </ol> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t" data-mpa-action-id="m8zx692u1nu8"> <pre style="margin: 0px;padding: 0px;background: none;font-family: none;"><code style="border-radius: 4px;font-size: 0.85em;font-family: none;margin: 0px 0.15em;background: rgb(248, 248, 248);color: rgb(51, 51, 51);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;"><span style="color: rgb(153, 153, 136);background: rgba(0, 0, 0, 0);display: inline;width: 186px;text-decoration: none solid rgb(153, 153, 136);font-weight: 400;font-style: italic;font-family: none;"><span leaf=""># 计算过去 1 小时的独立设备数</span></span><span leaf=""><br></span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 164px;text-decoration: none solid rgb(51, 51, 51);font-weight: 400;font-style: normal;font-family: none;"><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(51, 51, 51);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">def</span></span><span leaf=""> </span><span style="color: rgb(153, 0, 0);background: rgba(0, 0, 0, 0);display: inline;width: 118px;text-decoration: none solid rgb(153, 0, 0);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">get_unique_devices</span></span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(51, 51, 51);font-weight: 400;font-style: normal;font-family: none;"><span leaf="">()</span></span><span leaf="">:</span></span><span leaf=""><br></span><span leaf=""> </span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(51, 51, 51);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">return</span></span><span leaf=""> redis.pfcount(</span><span style="color: rgb(221, 17, 68);background: rgba(0, 0, 0, 0);display: inline;width: 65px;text-decoration: none solid rgb(221, 17, 68);font-weight: 400;font-style: normal;font-family: none;"><span leaf="">"devices:"</span></span><span leaf=""> + now.hour)</span></code></pre> </section> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n120" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">实时特征交叉</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""> 结合用户行为、设备信息、环境特征等多维度数据。</span></span></p></li> </ol> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t" data-mpa-action-id="m8zx791ws32"> <pre style="margin: 0px;padding: 0px;background: none;font-family: none;"><code style="border-radius: 4px;font-size: 0.85em;font-family: none;margin: 0px 0.15em;background: rgb(248, 248, 248);color: rgb(51, 51, 51);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;"><span style="color: rgb(153, 153, 136);background: rgba(0, 0, 0, 0);display: inline;width: 154px;text-decoration: none solid rgb(153, 153, 136);font-weight: 400;font-style: italic;font-family: none;"><span leaf=""># 设备指纹与 IP 关联分析</span></span><span leaf=""><br></span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 268px;text-decoration: none solid rgb(51, 51, 51);font-weight: 400;font-style: normal;font-family: none;"><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(51, 51, 51);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">def</span></span><span leaf=""> </span><span style="color: rgb(153, 0, 0);background: rgba(0, 0, 0, 0);display: inline;width: 137px;text-decoration: none solid rgb(153, 0, 0);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">device_ip_correlation</span></span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 98px;text-decoration: none solid rgb(51, 51, 51);font-weight: 400;font-style: normal;font-family: none;"><span leaf="">(device_id, ip)</span></span><span leaf="">:</span></span><span leaf=""><br></span><span leaf=""> </span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 39px;text-decoration: none solid rgb(51, 51, 51);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">return</span></span><span leaf=""> redis.hget(</span><span style="color: rgb(221, 17, 68);background: rgba(0, 0, 0, 0);display: inline;width: 98px;text-decoration: none solid rgb(221, 17, 68);font-weight: 400;font-style: normal;font-family: none;"><span leaf="">"ip_device_map"</span></span><span leaf="">, ip) == device_id</span></code></pre> </section> <h3 cid="n122" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 2;font-size: 1.5em;margin-top: 24px;margin-bottom: 24px;font-weight: bold;line-height: 2em;cursor: text;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">(二)模型优化策略</span></span></span></h3> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n125" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">模型量化</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""> 使用 TensorFlow Lite 或 ONNX Runtime 对模型进行轻量化。</span></span></p></li> </ol> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t" data-mpa-action-id="m8zx4k4q22zp"> <pre style="margin: 0px;padding: 0px;background: none;font-family: none;"><code style="border-radius: 4px;font-size: 0.85em;font-family: none;margin: 0px 0.15em;background: rgb(248, 248, 248);color: rgb(51, 51, 51);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;"><span style="color: rgb(153, 153, 136);background: rgba(0, 0, 0, 0);display: inline;width: 279px;text-decoration: none solid rgb(153, 153, 136);font-weight: 400;font-style: italic;font-family: none;"><span leaf=""># 示例:将 Keras 模型转换为 TensorFlow Lite</span></span><span leaf=""><br></span><span leaf="">converter = tf.lite.TFLiteConverter.from_keras_model(model)</span><span leaf=""><br></span><span leaf="">tflite_model = converter.convert()</span><span leaf=""><br></span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(51, 51, 51);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">with</span></span><span leaf=""> open(</span><span style="color: rgb(221, 17, 68);background: rgba(0, 0, 0, 0);display: inline;width: 92px;text-decoration: none solid rgb(221, 17, 68);font-weight: 400;font-style: normal;font-family: none;"><span leaf="">"model.tflite"</span></span><span leaf="">, </span><span style="color: rgb(221, 17, 68);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(221, 17, 68);font-weight: 400;font-style: normal;font-family: none;"><span leaf="">"wb"</span></span><span leaf="">) </span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(51, 51, 51);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">as</span></span><span leaf=""> f:</span><span leaf=""><br></span><span leaf=""> f.write(tflite_model)</span></code></pre> </section> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n129" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">在线学习</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""> 用 Redis 存储实时反馈数据,定期触发模型增量训练。</span></span></p></li> </ol> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t" data-mpa-action-id="m8zxd4og1y54"> <pre style="margin: 0px;padding: 0px;background: none;font-family: none;"><code style="border-radius: 4px;font-size: 0.85em;font-family: none;margin: 0px 0.15em;background: rgb(248, 248, 248);color: rgb(51, 51, 51);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;"><span style="color: rgb(153, 153, 136);background: rgba(0, 0, 0, 0);display: inline;width: 128px;text-decoration: none solid rgb(153, 153, 136);font-weight: 400;font-style: italic;font-family: none;"><span leaf=""># 每小时重新训练模型</span></span><span leaf=""><br></span><span leaf="">schedule.every().hour.do(retrain_model)</span></code></pre> </section> <h3 cid="n131" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 2;font-size: 1.5em;margin-top: 24px;margin-bottom: 24px;font-weight: bold;line-height: 1.43;cursor: text;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">(三)性能优化方案</span></span></span></h3> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n134" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">批量推理</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""> 使用 Redis Pipelining 批量处理多个请求。</span></span></p></li> </ol> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t" data-mpa-action-id="m8zxh68kko5"> <pre style="margin: 0px;padding: 0px;background: none;font-family: none;"><code style="border-radius: 4px;font-size: 0.85em;font-family: none;margin: 0px 0.15em;background: rgb(248, 248, 248);color: rgb(51, 51, 51);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;"><span style="color: rgb(153, 153, 136);background: rgba(0, 0, 0, 0);display: inline;width: 142px;text-decoration: none solid rgb(153, 153, 136);font-weight: 400;font-style: italic;font-family: none;"><span leaf="">// Java 示例:批量推理</span></span><span leaf=""><br></span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(51, 51, 51);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">try</span></span><span leaf=""> (RedisPipeline pipeline = redis.pipelined()) {</span><span leaf=""><br></span><span leaf=""> </span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(51, 51, 51);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">for</span></span><span leaf=""> (User user : users) {</span><span leaf=""><br></span><span leaf=""> pipeline.hgetall(</span><span style="color: rgb(221, 17, 68);background: rgba(0, 0, 0, 0);display: inline;width: 105px;text-decoration: none solid rgb(221, 17, 68);font-weight: 400;font-style: normal;font-family: none;"><span leaf="">"user_features:"</span></span><span leaf=""> + user.getId());</span><span leaf=""><br></span><span leaf=""> }</span><span leaf=""><br></span><span leaf=""> </span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(51, 51, 51);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">List</span></span><span leaf=""><object> results = pipeline.syncAndReturnAll();<span leaf=""><br></span><span leaf="">}</span> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n138" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">缓存热点决策</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""> 用 Redis 缓存高频决策结果,减少模型调用次数。</span></span></p></li> </ol> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t" data-mpa-action-id="m8zxgdpeyrl"> <pre style="margin: 0px;padding: 0px;background: none;font-family: none;"><code style="border-radius: 4px;font-size: 0.85em;font-family: none;margin: 0px 0.15em;background: rgb(248, 248, 248);color: rgb(51, 51, 51);display: block;padding: 5.95px;overflow-x: auto;white-space: nowrap;"><span style="color: rgb(153, 153, 136);background: rgba(0, 0, 0, 0);display: inline;width: 128px;text-decoration: none solid rgb(153, 153, 136);font-weight: 400;font-style: italic;font-family: none;"><span leaf=""># 缓存高置信度的结果</span></span><span leaf=""><br></span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 236px;text-decoration: none solid rgb(51, 51, 51);font-weight: 400;font-style: normal;font-family: none;"><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 20px;text-decoration: none solid rgb(51, 51, 51);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">def</span></span><span leaf=""> </span><span style="color: rgb(153, 0, 0);background: rgba(0, 0, 0, 0);display: inline;width: 92px;text-decoration: none solid rgb(153, 0, 0);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">cache_decision</span></span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 111px;text-decoration: none solid rgb(51, 51, 51);font-weight: 400;font-style: normal;font-family: none;"><span leaf="">(user_id, result)</span></span><span leaf="">:</span></span><span leaf=""><br></span><span leaf=""> </span><span style="color: rgb(51, 51, 51);background: rgba(0, 0, 0, 0);display: inline;width: 13px;text-decoration: none solid rgb(51, 51, 51);font-weight: 700;font-style: normal;font-family: none;"><span leaf="">if</span></span><span leaf=""> result.confidence > </span><span style="color: rgb(0, 128, 128);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(0, 128, 128);font-weight: 400;font-style: normal;font-family: none;"><span leaf="">0.95</span></span><span leaf="">:</span><span leaf=""><br></span><span leaf=""> redis.setex(</span><span style="color: rgb(221, 17, 68);background: rgba(0, 0, 0, 0);display: inline;width: 52px;text-decoration: none solid rgb(221, 17, 68);font-weight: 400;font-style: normal;font-family: none;"><span leaf="">"cache:"</span></span><span leaf=""> + user_id, </span><span style="color: rgb(0, 128, 128);background: rgba(0, 0, 0, 0);display: inline;width: 26px;text-decoration: none solid rgb(0, 128, 128);font-weight: 400;font-style: normal;font-family: none;"><span leaf="">3600</span></span><span leaf="">, result)</span></code></pre> </section> <section mpa-from-tpl="t" data-mpa-action-id="m8zxi7fwbed" data-pm-slice="0 0 []"> <span leaf=""><br></span> </section> <section data-mpa-template="t" mpa-from-tpl="t" data-mpa-action-id="m8zxi7fwb9h"> <section data-mpa-template="t" mpa-from-tpl="t"> <h4 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: 400;font-size: 16px;text-align: justify;outline: 0px;color: rgb(34, 34, 34);letter-spacing: 0.544px;caret-color: rgb(51, 51, 51);line-height: 2em;"><span style="font-size: 20px;"><strong mpa-from-tpl="t" style="outline: 0px;"><span mpa-is-content="t" style="font-size: 20px;outline: 0px;color: rgb(0, 122, 170);"><span leaf="">五、避坑指南:那些你必须知道的细节</span></span></strong></span></h4> </section> </section><h3 cid="n141" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 2;font-size: 1.5em;margin-top: 24px;margin-bottom: 24px;font-weight: bold;line-height: 2em;cursor: text;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">(一)数据一致性问题</span></span></span></h3> <ul style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n144" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">解决方案</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:使用 Redis 事务(WATCH/MULTI/EXEC)保证数据原子性。</span></span></p></li> </ul><h3 cid="n146" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 2;font-size: 1.5em;margin-top: 24px;margin-bottom: 24px;font-weight: bold;line-height: 1.43;cursor: text;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 18px;">(二)模型漂移问题</span></span></span></h3> <ul style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n149" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">监控指标</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:AUC、准确率、召回率、F1 值</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n151" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">解决方案</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:定期重新训练模型,使用模型版本管理工具(如 MLflow)</span></span></p></li> </ul><h3 cid="n152" mdtype="heading" style="box-sizing: border-box;break-after: avoid-page;break-inside: avoid;orphans: 2;font-size: 1.5em;margin-top: 24px;margin-bottom: 24px;font-weight: bold;line-height: 2em;cursor: text;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">(三)Redis 内存管理</span></span></span></h3> <ul style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n155" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">内存监控</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:定期执行 </span></span><span md-inline="code" spellcheck="false" style="box-sizing: border-box;"><code style="box-sizing: border-box;font-family: var(--monospace);text-align: left;vertical-align: initial;border: 1px solid rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;padding: 0px 2px;font-size: 0.9em;"><span leaf="">redis-cli info memory</span></code></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n157" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">淘汰策略</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:设置合理的 </span></span><span md-inline="code" spellcheck="false" style="box-sizing: border-box;"><code style="box-sizing: border-box;font-family: var(--monospace);text-align: left;vertical-align: initial;border: 1px solid rgb(231, 234, 237);background-color: rgb(243, 244, 244);border-radius: 3px;padding: 0px 2px;font-size: 0.9em;"><span leaf="">maxmemory-policy</span></code></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">(如 allkeys-lru)</span></span></p></li> </ul> <section mpa-from-tpl="t" data-mpa-action-id="m8zxkvfxr62" data-pm-slice="0 0 []"> <span leaf=""><br></span> </section> <section data-mpa-template="t" mpa-from-tpl="t" data-mpa-action-id="m8zxkvfxbfu"> <section data-mpa-template="t" mpa-from-tpl="t"> <h4 data-tool="mdnice编辑器" style="margin-bottom: 15px;font-weight: 400;font-size: 16px;text-align: justify;outline: 0px;color: rgb(34, 34, 34);letter-spacing: 0.544px;caret-color: rgb(51, 51, 51);line-height: 2em;"><span style="font-size: 20px;"><strong mpa-from-tpl="t" style="outline: 0px;"><span mpa-is-content="t" style="font-size: 20px;outline: 0px;color: rgb(0, 122, 170);"><span leaf="">六、真实案例:某支付公司的实战经验</span></span></strong></span></h4> </section> </section><p cid="n159" mdtype="paragraph" style="box-sizing: border-box;line-height: 2em;orphans: 4;margin: 24px 0px;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;">某支付公司通过 Redis+AI 风控系统实现了:</span></span></span></p> <ul style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n162" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">响应时间</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:从 800ms 降至 70ms</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n164" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">拦截准确率</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:从 72% 提升至 93%</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n166" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">误报率</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:下降 65%</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n168" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="strong" style="box-sizing: border-box;"><strong style="box-sizing: border-box;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">运维成本</span></span></strong></span><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">:减少 40% 的人工规则维护工作量 </span></span></p></li> </ul><p cid="n169" mdtype="paragraph" style="box-sizing: border-box;line-height: 2em;orphans: 4;margin: 24px 0px;white-space: pre-wrap;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial;><span md-inline="plain" style="box-sizing: border-box;"><span leaf=""><span textstyle="" style="font-size: 17px;font-weight: bold;">具体实施步骤:</span></span></span></p> <ol style="box-sizing: border-box;margin: 0.8em 0px;padding-left: 30px;color: rgb(51, 51, 51);font-family: " open sans, clear helvetica neue, helvetica, arial, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-style: initial;text-decoration-color: initial; class="list-paddingleft-1"> <li style="box-sizing: border-box;margin: 0px;"><p cid="n172" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">搭建 Redis 集群(3 主 3 从)</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n174" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">使用 Redis Streams 实时采集交易数据</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n176" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">用 Redis AI 部署 XGBoost 模型</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n178" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">开发实时特征计算模块</span></span></p></li> <li style="box-sizing: border-box;margin: 0px;"><p cid="n180" mdtype="paragraph" style="box-sizing: border-box;line-height: inherit;orphans: 4;margin: 0px 0px 0.5rem;white-space: pre-wrap;"><span md-inline="plain" style="box-sizing: border-box;"><span leaf="">接入业务系统进行压力测试</span></span></p></li> </ol><p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p> <script type="text/javascript" nonce="1989770072" reportloaderror> var first_sceen__time = (+new Date()); if ("" == 1 && document.getElementById('js_content')) { document.getElementById('js_content').addEventListener("selectstart",function(e){ e.preventDefault(); }); } </script> <div id="js_tags_preview_toast" class="article-tag__error-tips" style="display: none;">预览时标签不可点 </div> <div id="content_bottom_area"></div> <div id="js_temp_bottom_area" class="rich_media_tool_area"> <div class="rich_media_tool__wrp"> <div class="rich_media_tool"> <div class="rich_media_info weui-flex "> </div> </div> </div> </div> <div class="rich_media_area_primary sougou" id="sg_tj" style="display:none"></div> <div class="rich_media_area_extra"> <div class="rich_media_area_extra_inner"> <div id="page_bottom_area"></div> </div> </div> <div id="js_pc_qr_code" class="qr_code_pc_outer" style="display:none;"> <div class="qr_code_pc_inner"> <div class="qr_code_pc"><img id="js_pc_qr_code_img" class="qr_code_pc_img"> <p>微信扫一扫<br>关注该公众号</p> </div> </div> </div> <div class="wx_stream_article_slide_tip" id="wx_stream_article_slide_tip"> <div class="wx_stream_article_slide_tip_wrp"> <span class="wx_stream_article_slide_tip_arrow"></span> <span class="wx_stream_article_slide_tip_text">继续滑动看下一个</span> </div> </div> <div class="wx_network_msg_wrp" id="js_network_msg_wrp"></div> <div class="wx_expand_article " id="wx_expand_article"> <div class="wx_expand_article_gradient_background" id="wx_expand_background"></div> <div class="wx_expand_article_bottom_area" id="wx_expand_bottom"> <div class="wx_expand_article_button_wrap" id="wx_expand_article_placeholder"><button class="wx_expand_article_button" id="wx_expand_article_button">轻触阅读原文</button> </div> <div id="js_stream_bottom_bar" class="stream_bottom_bar_wrp"> <div id="js_stream_bottom_bar_placeholder" class="bottom_bar_placeholder"> <div class="wx_follow_context wx_follow_primary wx_follow_smart wx_follow_top wx_follow_bottom"> <div class="function_mod js_function_mod wx_tap_cell"> <div class="function_mod_inner js_function_mod_inner"> <div class="function_bd"> <div class="wx_follow_media weui-flex weui-flex_align-center"> <div class="wx_follow_hd"><span class="wx_follow_avatar"> <img src="/upload/ac7ecb6e296202cc8a75f7993256decd.png" alt="" class="wx_follow_avatar_pic"> </span> </div> <div class="wx_follow_bd weui-flex__item"> <div class="wx_follow_info"> <div role="link" tabindex="0" aria-labelledby="js_wx_follow_nickname" aria-describedby="js_wx_follow_tips" class="wx_follow_nickname"> 石杉的架构笔记 </div> </div> </div> </div> </div> </div> </div> </div> <div class="interaction_bar__wrap" style="opacity: 1;"> <div class="interaction_bar" style="-webkit-text-size-adjust: 100%;"> </div> </div> </div> <div id="stream_article_bottom_area"></div> </div> </div> <div id="wx_expand_slidetip" class="wx_expand_article_slide_tip"> <div class="wx_stream_article_slide_tip"> <div class="wx_stream_article_slide_tip_wrp"><span class="wx_stream_article_slide_tip_arrow"></span> <span class="wx_stream_article_slide_tip_text">向上滑动看下一个</span> </div> </div> </div> </div> <div id="js_ad_control"></div> <div id="audio_panel_area"></div> <div id="js_profile_card_modal"></div> <div class="comment_primary_emotion_panel_wrp" id="js_emotion_panel_pc" style="display: none"> <div class="comment_primary_emotion_panel"> <ul class="comment_primary_emotion_list_pc" id="js_emotion_list_pc"> </ul> </div> </div> <div class="weui-dialog__wrp" id="js_alert_panel" style="display:none;"> <div class="weui-mask"></div> <div class="weui-dialog"> <div class="weui-dialog__bd" id="js_alert_content"></div> <div class="weui-dialog__ft"><a href="javascript:;" class="weui-dialog__btn weui-dialog__btn_default" id="js_alert_confirm">知道了</a> </div> </div> </div> <script type="text/javascript" nonce="1989770072" reportloaderror> window.img_popup = 1; </script> <style>.weui-dialog_link{-webkit-transform:translateY(-75%);transform:translateY(-75%)}</style> <div id="js_pc_weapp_code" class="weui-desktop-popover weui-desktop-popover_pos-up-center weui-desktop-popover_img-text weapp_code_popover" style="display: none;"> <div class="weui-desktop-popover__inner"> <div class="weui-desktop-popover__desc"><img id="js_pc_weapp_code_img"> 微信扫一扫<br>使用小程序<span id="js_pc_weapp_code_des"></span> </div> </div> </div> <div id="js_minipro_dialog" role="dialog" aria-modal="true" tabindex="0" aria-labelledby="js_minipro_dialog_head" style="display:none;"> <div class="weui-mask"></div> <div class="weui-dialog weui-dialog_link"> <div class="weui-dialog__hd"><strong class="weui-dialog__title" id="js_minipro_dialog_head" tabindex="0"></strong> </div> <div class="weui-dialog__bd" id="js_minipro_dialog_body"></div> <div class="weui-dialog__ft"><a role="button" id="js_minipro_dialog_cancel" href="javascript:void(0);" class="weui-dialog__btn weui-dialog__btn_default">取消</a> <a role="button" id="js_minipro_dialog_ok" href="javascript:void(0);" class="weui-dialog__btn weui-dialog__btn_primary">允许</a> </div> </div> </div> <div id="js_link_dialog" role="dialog" aria-modal="true" tabindex="0" aria-labelledby="js_link_dialog_body" style="display:none;"> <div class="weui-mask"></div> <div class="weui-dialog weui-dialog_link"> <div class="weui-dialog__hd"><strong class="weui-dialog__title" id="js_link_dialog_head" tabindex="0"></strong> </div> <div class="weui-dialog__bd" id="js_link_dialog_body" tabindex="0"></div> <div class="weui-dialog__ft"><a role="button" id="js_link_dialog_cancel" href="javascript:void(0);" class="weui-dialog__btn weui-dialog__btn_default">取消</a> <a role="button" id="js_link_dialog_ok" href="javascript:void(0);" class="weui-dialog__btn weui-dialog__btn_primary">允许</a> </div> </div> </div> <div class="analyze_btn_wrap" id="js_analyze_btn" style="display:none"> <button class="close-button">×</button> <button class="go-button wx_tap_card js_wx_tap_highlight">分析</button> </div> <div class="weui-dialog__wrp jump_wx_qrcode_dialog" id="js_jump_wx_qrcode_dialog" role="dialog" style="display:none;"> <div class="weui-mask js_dialog_mask"></div> <div class="weui-dialog"> <div class="weui-dialog__hd"><i class="weui-icon-close-thin js_dialog_close"></i> <div class="qrcode-con"><img class="jump_wx_qrcode_img js_qrcode_img" src="" alt="跳转二维码"> <div class="jump_author_avatar_con"><img class="jump_author_avatar" src="/upload/ac7ecb6e296202cc8a75f7993256decd.png" alt="作者头像"> </div> </div> </div> <div class="weui-dialog__bd"> <p class="jump_wx_qrcode_desc">微信扫一扫可打开此内容,<br>使用完整服务</p> </div> </div> </div> <div id="unlogin_bottom_bar" style="display:none;"> <div id="js_article_bottom_bar" class="bottom_bar_wrp"> <div id="article_bottom_bar_area"></div> </div> <div class="bottom_bar_padding_mask"></div> </div> <script type="text/javascript" nonce="1989770072" reportloaderror> window.logs.pagetime.page_begin = Date.now(); try { var adIframeUrl = localStorage.getItem('__WXLS_ad_iframe_url'); if (window === top) { if (adIframeUrl) { if (navigator.userAgent.indexOf('iPhone') > -1) { var img = new Image(); img.src = adIframeUrl; } else { var link = document.createElement('link'); link.rel = 'prefetch'; link.href = adIframeUrl; document.getElementsByTagName('head')[0].appendChild(link); } } } } catch (err) { } </script> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_colon">:</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_comma">,</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_comma0">,</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_comma1">,</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_comma2">,</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_comma3">,</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_comma4">,</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_comma5">,</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_comma6">,</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_comma7">,</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_comma8">,</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_comma9">,</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_comma10">,</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_period">。</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_space"> </span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_type_video">视频</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_type_weapp">小程序</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_zan_btn_txt">赞</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_zan_btn_tips">,轻点两下取消赞</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_like_btn_txt">在看</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_like_btn_tips">,轻点两下取消在看</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_share_btn_txt">分享</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_comment_btn_txt">留言</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_collect_btn_txt">收藏</span> <span aria-hidden="true" class="weui-a11y_ref" style="display:none" id="js_a11y_op_ting_heard">听过</span> <script type="text/javascript" nonce="1989770072" reportloaderror> (function () { var totalCount = 0, finishCount = 0; function _addScript(uri, cb) { totalCount++; var node = document.createElement('SCRIPT'); node.type = 'text/javascript'; node.src = uri; node.setAttribute('nonce', '1989770072'); if (cb) { node.onload = cb; } document.getElementsByTagName('head')[0].appendChild(node); } if ((document.cookie && document.cookie.indexOf('vconsole_open=1') > -1) || location.href.indexOf('vconsole=1') > -1) { _addScript('https://mp.weixin.qq.com/mmbizappmsg/zh_CN/htmledition/js/scripts/vconsole-3.14.6.js', function () { window.vConsole = new window.VConsole(); }); } if (document.cookie && document.cookie.indexOf('__xweb_remote_debug_device_token__') > -1) { _addScript('https://mp.weixin.qq.com/mmbizappmsg/zh_CN/htmledition/js/scripts/mprdev-0.2.5.js', function () { _addScript('https://mp.weixin.qq.com/mmbizappmsg/zh_CN/htmledition/js/scripts/xwebrd-0.0.2.js'); }); } })(); </script> <script type="text/javascript" h5only nonce="1989770072" reportloaderror>(function () { 'use strict'; function _arrayLikeToArray$1(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray$1(arr); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _unsupportedIterableToArray$1(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$1(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray$1(arr) || _nonIterableSpread(); } const A = { web: "common-web", app: "common-app", wechat: "common-webchat" }; function x(t, e) { const o = arguments[1] || window.location.search, n = new RegExp("(^|&)" + t + "=([^&]*)(&|$)"), s = o.substr(o.indexOf("?") + 1).match(n); return s != null ? s[2] : ""; } const f = x("color_scheme", location.href), $ = Number(x("uninteractive", location.href)), j$1 = { props: { platform: { type: String, default: "web" }, extraInfo: { type: Object, default: () => ({}) } }, mounted() { const t = this.$refs.js_custom_element; this.platform !== "wechat" && !f && t.setAttribute("data-weui-theme", "light"), f && f === "light" && t.setAttribute("data-weui-theme", "light"), $ === 1 && t.classList.add("wx_uninteractive"); }, data() { return { platformClassname: A[this.platform] }; } }; function _(t) { const e = {}; return t.attributes && Array.from(t.attributes).forEach((o) => { e[o.nodeName] = o.nodeValue; }), e; } function L$1(t = [], e) { let o = []; return t.childNodes.forEach((n) => { const s = _(n); if ("data-shadow-slot" in s) { if (!s.slot) return; const l = { attrs: s, domProps: { innerHTML: n.innerHTML === "" ? n.innerText : n.innerHTML }, slot: s.slot }; s.slot = void 0; const m = e(n.tagName, l); o.push(m); } else if (s.slot) { const l = e("slot", { attrs: { name: s.slot }, slot: s.slot }); o.push(l); } }), o; } function k({ iframeWindow: t, Component: e, platform: o, customName: n, styleText: s, extraInfo: l = {}, watchAttr: m, beforeRender: b, afterRender: g, selector: E, afterMounted: y, reflowProps: w, getProps: C, eventName: v = [] }) { let d = window; t && (d = t), l.window = d, d.customElements.define(n, class extends d.HTMLElement { constructor() { super(); const i = this.attachShadow({ mode: "open" }); this.shadow = i; } connectedCallback() { if (!e.install) { if (e.props && w && w.length) { const a = { watch: {} }; w.forEach((u) => { a.watch[u] = function() { const p = this.$el.getRootNode().host, T = { compEle: p, compType: n, compIdx: Array.from(document.querySelectorAll(E || n)).indexOf(p) }; b && b(Object.assign({ subCompType: u }, T)), this.$nextTick(() => { g && g(Object.assign({ subCompType: u }, T)); }); }; }), e.mixins.push(a); } typeof e.template == "function" && e.template(e); } const i = v.reduce((a, u) => (a[u] = (p) => { this.dispatchCustomEvent(u, p); }, a), {}), r = new Vue({ render: (a) => a( e, { props: C.call(this, o, l), on: i }, L$1(this, a) ) }); this.wrapper = r; const c = document.createElement("style"); c.textContent = ` :host { all: initial; -webkit-text-size-adjust: inherit; } `, this.shadowRoot.appendChild(c); const h = document.createElement("style"); h.appendChild(document.createTextNode(s)), this.shadowRoot.appendChild(h), this.wrapper.$mount(), this.shadowRoot.appendChild(this.wrapper.$el), this.debounceUpdate = this.debounce(() => { console.log("forceUpdate"), this.wrapper && this.wrapper.$forceUpdate(); }, 500), this.classList.add("mp_common_widget"), y && y.call(this); } debounce(i, r) { let c; return function(...h) { const a = this; clearTimeout(c), c = setTimeout(() => i.apply(a, h), r); }; } dispatchCustomEvent(i, r) { const c = new CustomEvent(i, { detail: r, bubbles: !0, composed: !0 }); this.dispatchEvent(c); } getKeyByDataValue(i) { for (const r in ATTR) if (ATTR[r] === i) return r; return null; } disconnectedCallback() { this.shadowRoot.innerHTML = "", this.wrapper && this.wrapper.$destroy(); } attributeChangedCallback(i, r, c) { this.wrapper && this.wrapper.$forceUpdate(); } static get observedAttributes() { return m; } }); } typeof Number.isFinite == "function" && Number.isFinite.bind(Number); function o$1(n) { const t = {}; return Object.keys(n).forEach((e) => { t[e] = this.getAttribute(n[e]); }), t; } function r$1(B) { const A = {}, E = /[?&]([^=&#]+)=([^&#]*)/g, w = B.match(E); if (w) { for (const i in w) if (Object.prototype.hasOwnProperty.call(w, i)) { const M = w[i].split("="), e = M[0].substr(1), F = M[1]; A[e] ? A[e] = [].concat(A[e], F) : A[e] = F; } } return A; } function T(B, A, E, w, i, M, e, F) { var I = typeof B == "function" ? B.options : B; A && (I.render = A, I.staticRenderFns = E, I._compiled = !0), w && (I.functional = !0), M && (I._scopeId = "data-v-" + M); var g; if (e ? (g = function(Q) { Q = Q || this.vnode.ssrContext || this.parent && this.parent.vnode.ssrContext, !Q && typeof __VUE_SSR_CONTEXT__ < "u" && (Q = __VUE_SSR_CONTEXT__), i && i.call(this, Q), Q && Q._registeredComponents && Q._registeredComponents.add(e); }, I._ssrRegister = g) : i && (g = F ? function() { i.call( this, (I.functional ? this.parent : this).options.shadowRoot ); } : i), g) if (I.functional) { I._injectStyles = g; var Y = I.render; I.render = function(c, t) { return g.call(t), Y(c, t); }; } else { var u = I.beforeCreate; I.beforeCreate = u ? [].concat(u, g) : [g]; } return { exports: B, options: I }; } const D = "https://mp.weixin.qq.com/shop/ssr/wap/business", U = "https://mp.weixin.qq.com/mmec/productcard", l = "https://mp.weixin.qq.com", N = { BIZ_ARTICLE_CSIDE_READ: 1, BIZ_ARTICLE_BSIDE_PREVIEW: 2, BIZ_PRIVATE_MESSAGE_BSIDE: 3, BIZ_PRIVATE_MESSAGE_CSIDE: 4, BIZ_AUTO_REPLY_BSIDE: 5, BIZ_AUTO_REPLY_CSIDE: 6, BIZ_CUSTOM_MENU_BSIDE: 7, BIZ_CUSTOM_MENU_CSIDE: 8 }; function h(B) { const A = B.length; let E = B.indexOf("?"), w = B.indexOf("#"); w = w === -1 ? A : w, E = E === -1 ? w : E; const i = B.substring(0, E), M = B.substring(E + 1, w), e = B.substring(w + 1); return { host: i, queryStr: M, hash: e }; } function C$1(B, A, E = !1) { const w = h(B); let i = w.queryStr; const M = []; if (typeof A == "object") for (const e in A) Object.prototype.hasOwnProperty.call(A, e) && M.push(e + "=" + (E ? A[e] : encodeURIComponent(A[e]))); else M.push(E ? A : encodeURIComponent(A)); return M.length > 0 && (i += (i !== "" ? "&" : "") + M.join("&")), `${w.host}${i !== "" ? "?" + i : ""}${w.hash !== "" ? "#" + w.hash : ""}`; } function L(B) { try { const { action: A, value: E } = JSON.parse(B); return { action: A, value: E }; } catch (A) { console.error(A); } return {}; } function G(B, A, E, w) { try { if (!B) return console.warn("postMessageToIframe: win is null"); B.postMessage( JSON.stringify({ action: A, value: E }), w || "*" ); } catch (i) { console.log("postMessage error", i); } } const d = { name: "mp-common-product", mixins: [j$1], props: { extraInfo: { type: Object, default: () => ({}) }, productInfo: { type: Object, default: () => ({}) }, immutable: { type: Number, default: 0 }, token: { type: String, default: "" }, windowproduct: { type: String, default: "" }, is_hover: { type: Number, default: 0 }, is_selected: { type: Number, default: 0 }, customstyle: { type: String, default: "{}" }, ecsource: { type: String, default: "" }, exportkey: { type: String, default: "" }, wap_export_token: { type: String, default: "" }, loaded: { type: Number, default: 0 }, cardtype: { type: Number, default: 0 }, productImage: { type: String, default: "" }, originPrice: { type: Number, default: 0 }, discountedPrice: { type: Number, default: 0 }, title: { type: String, default: "" }, req_scene: { type: Number, default: 0 }, urlParams: { type: Object, default: () => ({}) }, extInfo: { type: Object, default: () => ({}) }, scrollBlur: { type: Number, default: !1 }, wrpStyle: { type: String, default: "" }, outerclick: { type: Number, default: 0 } }, data() { return { showIframe: !1, iframeUrl: "", transferStyle: "", timeout: null, observer: null, active: !1, hasExpose: !1, iframeLoading: !0, iframeLoadTimeout: null }; }, watch: { loaded: { handler() { this.loaded && (this.showIframe = !0, this.iframeUrl = this.getCIframeUrl()); }, immediate: !0 }, cardtype() { this.isEditor && (this.iframeUrl = this.getBIframeUrl()); }, windowproduct() { this.isEditor && (this.iframeUrl = this.getBIframeUrl()); }, iframeUrl() { this.iframeLoading = !0, this.iframeLoadTimeout && clearTimeout(this.iframeLoadTimeout), this.iframeLoadTimeout = setTimeout(() => { window.WX_BJ_REPORT && window.WX_BJ_REPORT.BadJs && window.WX_BJ_REPORT.BadJs.report("load timeout", this.iframeUrl, { mid: "mmbizwap:product", view: "wap_business", _info: { url: location.href, productCount: document.getElementsByTagName("mp-common-product").length } }); }, 5e3); } }, computed: { isEditor() { return this.platform === "web" || this.platform === "app"; }, iframeStyle() { let B = {}; return this.platform === "web" ? [N.BIZ_CUSTOM_MENU_BSIDE, N.BIZ_AUTO_REPLY_BSIDE, N.BIZ_PRIVATE_MESSAGE_BSIDE].includes( this.req_scene ) ? B.width = "195px" : B.width = "350px" : B.width = "100%", B = Object.assign(B, JSON.parse(this.transferStyle || "{}")), B; } }, created() { this.isEditor && (this.showIframe = !0, this.iframeUrl = this.getBIframeUrl()); }, mounted() { this.extraInfo.window && this.extraInfo.window.addEventListener("message", this.handleMessage), this.extraInfo.window && this.extraInfo.window.addEventListener("click", this.handleDocumentClick), this.scrollBlur && this.extraInfo.window && this.extraInfo.window.addEventListener("scroll", this.handleScroll); }, beforeDestroy() { this.extraInfo.window && this.extraInfo.window.removeEventListener("message", this.handleMessage), this.extraInfo.window && this.extraInfo.window.removeEventListener("click", this.handleDocumentClick), this.scrollBlur && this.extraInfo.window && this.extraInfo.window.removeEventListener("scroll", this.handleScroll), this.observer && this.observer.disconnect(); }, methods: { handleScroll() { this.deActive(); }, handleDocumentClick(B) { this.$refs.js_custom_element.contains(B.target) || (this.deActive(), this.$emit("document-click", B)); }, deActive() { const B = this.$refs.iframeRef; B && B.contentWindow && this.active && (G(B.contentWindow, "webEvent", { type: "unclick" }), this.active = !1); }, exposureReport() { this.observer = new IntersectionObserver( (B) => { B.forEach((A) => { const E = this.$refs.iframeRef; if (A.isIntersecting && A.intersectionRatio >= 0.5) { this.$emit("expose", !this.hasExpose), this.hasExpose = !0; try { E && E.contentWindow && (this.timeout = setTimeout(() => { G(E.contentWindow, "webEvent", { type: "valid_expose" }); }, 500)); } catch (w) { console.error(w); } } else this.timeout && clearTimeout(this.timeout); }); }, { threshold: 0.5 } ), this.observer.observe(this.$refs.js_custom_element); }, handleMessage(B) { if (B.origin !== l) return; const A = this.$refs.iframeRef; if (A && B.source === A.contentWindow) { const { action: E, value: w } = L(B.data); switch (E) { case "changeFrameStyle": this.changeFrameStyle(B, w); break; case "onFrameReady": this.onFrameReady(B, A); break; case "webEvent": w.type === "click" ? this.clickProduct(B) : w.type === "toast" ? window.weui.toast(w.msg, { extClass: "weui-toast_text" }) : w.type === "dialog" && window.weui.dialog(w); break; } this.$emit("iframe-message", B); } }, onFrameReady(B, A) { this.iframeLoadTimeout && clearTimeout(this.iframeLoadTimeout), this.iframeLoading = !1, this.setProductData(B.source, A), this.extraInfo.window && G(this.extraInfo.window, "setPageData", { darkMode: this.extraInfo.window.matchMedia("(prefers-color-scheme: dark)").matches }), this.isEditor || this.exposureReport(); }, clickProduct(B) { this.extraInfo.window && this.extraInfo.window.clickedProductWin && B.source !== this.extraInfo.window.clickedProductWin && G(this.extraInfo.window.clickedProductWin, "webEvent", { type: "unclick" }), this.extraInfo.window && (this.extraInfo.window.clickedProductWin = B.source), this.active = !0; }, setProductData(B) { G(B, "setData", { infos: { scene: "edit" } }), this.immutable && G(B, "setPageData", { scene: "immutable" }); }, changeFrameStyle(B, A) { if (!(!A || typeof A != "object" || this.cardtype === 2)) try { this.transferStyle = JSON.stringify(A); } catch (E) { console.error(E); } }, getBIframeUrl() { const B = { productkey: this.windowproduct, reqScene: this.req_scene, ...this.urlParams }, A = window && window.wx && window.wx.data && window.wx.data.t || r$1(window.location.href).token || this.token; return A && (B.token = A), this.cardtype && (B.cardtype = this.cardtype), C$1(D, B); }, getCIframeUrl() { const B = { productkey: this.windowproduct, reqScene: this.req_scene, ...this.urlParams }; return this.exportkey && (B.exportkey = this.exportkey), this.wap_export_token && (B.wap_export_token = this.wap_export_token), this.ecsource && (B.ecsource = this.ecsource), this.cardtype && (B.cardtype = this.cardtype), typeof window.WX_BJ_REPORT < "u" && window.WX_BJ_REPORT.BadJs && window.WX_BJ_REPORT.BadJs.report(C$1(U, B), "no exportkey" + window.location.href, { mid: window.PAGE_MID, view: "wap_business" }), C$1(U, B); }, openShop() { const B = this.$refs.iframeRef; this.outerclick ? this.$emit("element-click", this.$refs.js_custom_element) : !this.isEditor && B && G(B.contentWindow, "webEvent", { type: "openShop", clickType: 0 }); } } }, z = d; var n = function() { var A = this, E = A._self._c; return A._self._setupProxy, A.cardtype === 2 ? E("span", { ref: "js_custom_element", staticClass: "product_card_text_wrp", style: A.wrpStyle }, [E("a", { staticClass: "product_text_link", style: A.isEditor ? "color: #576B95" : "", attrs: { href: "javascript:void(0);" }, on: { click: A.openShop } }, [A._v(A._s(A.title))]), A.showIframe ? E("iframe", { ref: "iframeRef", staticClass: "iframe_style", style: [A.iframeStyle, { display: "none" }], attrs: { src: A.iframeUrl, scrolling: "no", frameborder: "0" } }) : A._e()]) : A.cardtype === 4 ? E("div", { ref: "js_custom_element", staticClass: "activity_card_wrp", on: { click: A.openShop } }, [E("div", { staticClass: "activity_card_wrp__container" }, [E("img", { staticClass: "product_image", attrs: { src: A.productImage, alt: "" } }), E("transition", { attrs: { name: "fade" } }, [A.discountedPrice ? E("span", { staticClass: "discounted_price" }, [A._v("¥" + A._s(A.discountedPrice))]) : A._e()]), E("span", { key: A.discountedPrice, staticClass: "origin_price", class: { has_discount: A.discountedPrice } }, [A._v("¥" + A._s(A.originPrice))])], 1), A.showIframe ? E("iframe", { ref: "iframeRef", staticClass: "iframe_style", style: [A.iframeStyle, { display: "none" }], attrs: { src: A.iframeUrl, scrolling: "no", frameborder: "0" } }) : A._e()]) : A.cardtype === 5 ? E("div", { ref: "js_custom_element", staticClass: "s1s_card_wrp", on: { click: A.openShop } }, [E("img", { staticClass: "product-image", attrs: { src: A.productInfo.product_info.img_url, alt: "商品图片" } }), E("div", { staticClass: "product-info" }, [E("div", { staticClass: "product-title" }, [A._v(A._s(A.productInfo.product_info.title))]), E("div", { staticClass: "product-centercontainer" }, [E("span", { staticClass: "product-price" }, [A._v("¥" + A._s(A.productInfo.product_info.selling_price / 100))]), A.productInfo.product_info.friend_send_cnt ? E("div", { staticClass: "product-gifts" }, [A._v("朋友送过"), E("span", { staticClass: "product-gifts__num" }, [A._v(A._s(A.productInfo.product_info.friend_send_cnt))]), A._v("次 ")]) : A._e()]), E("div", { staticClass: "product-brand" }, [E("i", { staticClass: "product-logo" }), A._v(A._s(A.productInfo.shop_info.shop_window_profile_name)), E("i", { staticClass: "shop-verify-icon" })])]), A.showIframe ? E("iframe", { ref: "iframeRef", staticClass: "iframe_style", style: [A.iframeStyle, { display: "none" }], attrs: { src: A.iframeUrl, scrolling: "no", frameborder: "0" } }) : A._e()]) : E("div", { ref: "js_custom_element", class: [ "iframe_wrp", "wx_card_root", A.is_hover === 1 ? "wx_hover_card" : "", A.is_selected === 1 ? "wx_selected_card" : "" ], style: A.wrpStyle }, [A.showIframe ? E("iframe", { ref: "iframeRef", staticClass: "iframe_style", style: A.iframeStyle, attrs: { src: A.iframeUrl, scrolling: "no", frameborder: "0" } }) : A._e()]); }, S = [], y = T( z, n, S, !1, null, "bbb26799", null, null ); const j = y.exports, m = `body,.wx-root{--weui-BG-0: #EDEDED;--weui-BG-1: #F7F7F7;--weui-BG-2: #FFFFFF;--weui-BG-3: #F7F7F7;--weui-BG-4: #4C4C4C;--weui-BG-5: #FFFFFF;--weui-BLUE-100: #10AEFF;--weui-BLUE-120: #3FBEFF;--weui-BLUE-170: #B7E6FF;--weui-BLUE-80: #0C8BCC;--weui-BLUE-90: #0E9CE6;--weui-BLUE-BG-100: #48A6E2;--weui-BLUE-BG-110: #5AAFE4;--weui-BLUE-BG-130: #7FC0EA;--weui-BLUE-BG-90: #4095CB;--weui-BRAND-100: #07C160;--weui-BRAND-120: #38CD7F;--weui-BRAND-170: #B4ECCE;--weui-BRAND-80: #059A4C;--weui-BRAND-90: #06AE56;--weui-BRAND-BG-100: #2AAE67;--weui-BRAND-BG-110: #3EB575;--weui-BRAND-BG-130: #69C694;--weui-BRAND-BG-90: #259C5C;--weui-FG-0: rgba(0, 0, 0, .9);--weui-FG-0_5: rgba(0, 0, 0, .9);--weui-FG-1: rgba(0, 0, 0, .55);--weui-FG-2: rgba(0, 0, 0, .3);--weui-FG-3: rgba(0, 0, 0, .1);--weui-FG-4: rgba(0, 0, 0, .15);--weui-GLYPH-0: rgba(0, 0, 0, .9);--weui-GLYPH-1: rgba(0, 0, 0, .55);--weui-GLYPH-2: rgba(0, 0, 0, .3);--weui-GLYPH-WHITE-0: rgba(255, 255, 255, .8);--weui-GLYPH-WHITE-1: rgba(255, 255, 255, .5);--weui-GLYPH-WHITE-2: rgba(255, 255, 255, .3);--weui-GLYPH-WHITE-3: #FFFFFF;--weui-GREEN-100: #91D300;--weui-GREEN-120: #A7DB33;--weui-GREEN-170: #DEF1B3;--weui-GREEN-80: #74A800;--weui-GREEN-90: #82BD00;--weui-GREEN-BG-100: #96BE40;--weui-GREEN-BG-110: #A0C452;--weui-GREEN-BG-130: #B5D179;--weui-GREEN-BG-90: #86AA39;--weui-INDIGO-100: #1485EE;--weui-INDIGO-120: #439DF1;--weui-INDIGO-170: #B8DAF9;--weui-INDIGO-80: #106ABE;--weui-INDIGO-90: #1277D6;--weui-INDIGO-BG-100: #2B77BF;--weui-INDIGO-BG-110: #3F84C5;--weui-INDIGO-BG-130: #6BA0D2;--weui-INDIGO-BG-90: #266AAB;--weui-LIGHTGREEN-100: #95EC69;--weui-LIGHTGREEN-120: #AAEF87;--weui-LIGHTGREEN-170: #DEF9D1;--weui-LIGHTGREEN-80: #77BC54;--weui-LIGHTGREEN-90: #85D35E;--weui-LIGHTGREEN-BG-100: #72CF60;--weui-LIGHTGREEN-BG-110: #80D370;--weui-LIGHTGREEN-BG-130: #9CDD90;--weui-LIGHTGREEN-BG-90: #66B956;--weui-LINK-100: #576B95;--weui-LINK-120: #7888AA;--weui-LINK-170: #CCD2DE;--weui-LINK-80: #455577;--weui-LINK-90: #4E6085;--weui-LINKFINDER-100: #002666;--weui-MATERIAL-ATTACHMENTCOLUMN: rgba(245, 245, 245, .95);--weui-MATERIAL-NAVIGATIONBAR: rgba(237, 237, 237, .94);--weui-MATERIAL-REGULAR: rgba(247, 247, 247, .3);--weui-MATERIAL-THICK: rgba(247, 247, 247, .8);--weui-MATERIAL-THIN: rgba(255, 255, 255, .2);--weui-MATERIAL-TOOLBAR: rgba(246, 246, 246, .82);--weui-ORANGE-100: #FA9D3B;--weui-ORANGE-120: #FBB062;--weui-ORANGE-170: #FDE1C3;--weui-ORANGE-80: #C87D2F;--weui-ORANGE-90: #E08C34;--weui-ORANGE-BG-100: #EA7800;--weui-ORANGE-BG-110: #EC8519;--weui-ORANGE-BG-130: #F0A04D;--weui-ORANGE-BG-90: #D26B00;--weui-ORANGERED-100: #FF6146;--weui-OVERLAY: rgba(0, 0, 0, .5);--weui-OVERLAY-WHITE: rgba(242, 242, 242, .8);--weui-PURPLE-100: #6467F0;--weui-PURPLE-120: #8385F3;--weui-PURPLE-170: #D0D1FA;--weui-PURPLE-80: #5052C0;--weui-PURPLE-90: #595CD7;--weui-PURPLE-BG-100: #6769BA;--weui-PURPLE-BG-110: #7678C1;--weui-PURPLE-BG-130: #9496CE;--weui-PURPLE-BG-90: #5C5EA7;--weui-RED-100: #FA5151;--weui-RED-120: #FB7373;--weui-RED-170: #FDCACA;--weui-RED-80: #C84040;--weui-RED-90: #E14949;--weui-RED-BG-100: #CF5148;--weui-RED-BG-110: #D3625A;--weui-RED-BG-130: #DD847E;--weui-RED-BG-90: #B94840;--weui-SECONDARY-BG: rgba(0, 0, 0, .05);--weui-SEPARATOR-0: rgba(0, 0, 0, .1);--weui-SEPARATOR-1: rgba(0, 0, 0, .15);--weui-STATELAYER-HOVERED: rgba(0, 0, 0, .02);--weui-STATELAYER-PRESSED: rgba(0, 0, 0, .1);--weui-STATELAYER-PRESSEDSTRENGTHENED: rgba(0, 0, 0, .2);--weui-YELLOW-100: #FFC300;--weui-YELLOW-120: #FFCF33;--weui-YELLOW-170: #FFECB2;--weui-YELLOW-80: #CC9C00;--weui-YELLOW-90: #E6AF00;--weui-YELLOW-BG-100: #EFB600;--weui-YELLOW-BG-110: #F0BD19;--weui-YELLOW-BG-130: #F3CC4D;--weui-YELLOW-BG-90: #D7A400;--weui-FG-HALF: rgba(0, 0, 0, .9);--weui-RED: #FA5151;--weui-ORANGERED: #FF6146;--weui-ORANGE: #FA9D3B;--weui-YELLOW: #FFC300;--weui-GREEN: #91D300;--weui-LIGHTGREEN: #95EC69;--weui-TEXTGREEN: #06AE56;--weui-BRAND: #07C160;--weui-BLUE: #10AEFF;--weui-INDIGO: #1485EE;--weui-PURPLE: #6467F0;--weui-LINK: #576B95;--weui-TAG-TEXT-ORANGE: #FA9D3B;--weui-TAG-TEXT-GREEN: #06AE56;--weui-TAG-TEXT-BLUE: #10AEFF;--weui-REDORANGE: #FF6146;--weui-TAG-TEXT-BLACK: rgba(0, 0, 0, .5);--weui-TAG-BACKGROUND-BLACK: rgba(0, 0, 0, .05);--weui-WHITE: #FFFFFF;--weui-BG: #FFFFFF;--weui-FG: #000;--weui-FG-5: rgba(0, 0, 0, .05);--weui-TAG-BACKGROUND-ORANGE: rgba(250, 157, 59, .1);--weui-TAG-BACKGROUND-GREEN: rgba(6, 174, 86, .1);--weui-TAG-TEXT-RED: rgba(250, 81, 81, .6);--weui-TAG-BACKGROUND-RED: rgba(250, 81, 81, .1);--weui-TAG-BACKGROUND-BLUE: rgba(16, 174, 255, .1)}@media (prefers-color-scheme: dark){.wx-root:not([data-weui-theme=light]),body:not([data-weui-theme=light]){--weui-BG-0: #111111;--weui-BG-1: #1E1E1E;--weui-BG-2: #191919;--weui-BG-3: #202020;--weui-BG-4: #404040;--weui-BG-5: #2C2C2C;--weui-BLUE-100: #10AEFF;--weui-BLUE-120: #0C8BCC;--weui-BLUE-170: #04344D;--weui-BLUE-80: #3FBEFF;--weui-BLUE-90: #28B6FF;--weui-BLUE-BG-100: #48A6E2;--weui-BLUE-BG-110: #4095CB;--weui-BLUE-BG-130: #32749E;--weui-BLUE-BG-90: #5AAFE4;--weui-BRAND-100: #07C160;--weui-BRAND-120: #059A4C;--weui-BRAND-170: #023A1C;--weui-BRAND-80: #38CD7F;--weui-BRAND-90: #20C770;--weui-BRAND-BG-100: #2AAE67;--weui-BRAND-BG-110: #259C5C;--weui-BRAND-BG-130: #1D7A48;--weui-BRAND-BG-90: #3EB575;--weui-FG-0: rgba(255, 255, 255, .8);--weui-FG-0_5: rgba(255, 255, 255, .6);--weui-FG-1: rgba(255, 255, 255, .5);--weui-FG-2: rgba(255, 255, 255, .3);--weui-FG-3: rgba(255, 255, 255, .1);--weui-FG-4: rgba(255, 255, 255, .15);--weui-GLYPH-0: rgba(255, 255, 255, .8);--weui-GLYPH-1: rgba(255, 255, 255, .5);--weui-GLYPH-2: rgba(255, 255, 255, .3);--weui-GLYPH-WHITE-0: rgba(255, 255, 255, .8);--weui-GLYPH-WHITE-1: rgba(255, 255, 255, .5);--weui-GLYPH-WHITE-2: rgba(255, 255, 255, .3);--weui-GLYPH-WHITE-3: #FFFFFF;--weui-GREEN-100: #74A800;--weui-GREEN-120: #5C8600;--weui-GREEN-170: #233200;--weui-GREEN-80: #8FB933;--weui-GREEN-90: #82B01A;--weui-GREEN-BG-100: #789833;--weui-GREEN-BG-110: #6B882D;--weui-GREEN-BG-130: #65802B;--weui-GREEN-BG-90: #85A247;--weui-INDIGO-100: #1196FF;--weui-INDIGO-120: #0D78CC;--weui-INDIGO-170: #052D4D;--weui-INDIGO-80: #40ABFF;--weui-INDIGO-90: #28A0FF;--weui-INDIGO-BG-100: #0D78CC;--weui-INDIGO-BG-110: #0B6BB7;--weui-INDIGO-BG-130: #09548F;--weui-INDIGO-BG-90: #2585D1;--weui-LIGHTGREEN-100: #3EB575;--weui-LIGHTGREEN-120: #31905D;--weui-LIGHTGREEN-170: #123522;--weui-LIGHTGREEN-80: #64C390;--weui-LIGHTGREEN-90: #51BC83;--weui-LIGHTGREEN-BG-100: #31905D;--weui-LIGHTGREEN-BG-110: #2C8153;--weui-LIGHTGREEN-BG-130: #226541;--weui-LIGHTGREEN-BG-90: #31905D;--weui-LINK-100: #7D90A9;--weui-LINK-120: #647387;--weui-LINK-170: #252A32;--weui-LINK-80: #97A6BA;--weui-LINK-90: #899AB1;--weui-LINKFINDER-100: #DEE9FF;--weui-MATERIAL-ATTACHMENTCOLUMN: rgba(32, 32, 32, .93);--weui-MATERIAL-NAVIGATIONBAR: rgba(18, 18, 18, .9);--weui-MATERIAL-REGULAR: rgba(37, 37, 37, .6);--weui-MATERIAL-THICK: rgba(34, 34, 34, .9);--weui-MATERIAL-THIN: rgba(95, 95, 95, .4);--weui-MATERIAL-TOOLBAR: rgba(35, 35, 35, .93);--weui-ORANGE-100: #C87D2F;--weui-ORANGE-120: #A06425;--weui-ORANGE-170: #3B250E;--weui-ORANGE-80: #D39758;--weui-ORANGE-90: #CD8943;--weui-ORANGE-BG-100: #BB6000;--weui-ORANGE-BG-110: #A85600;--weui-ORANGE-BG-130: #824300;--weui-ORANGE-BG-90: #C1701A;--weui-ORANGERED-100: #FF6146;--weui-OVERLAY: rgba(0, 0, 0, .8);--weui-OVERLAY-WHITE: rgba(242, 242, 242, .8);--weui-PURPLE-100: #8183FF;--weui-PURPLE-120: #6768CC;--weui-PURPLE-170: #26274C;--weui-PURPLE-80: #9A9BFF;--weui-PURPLE-90: #8D8FFF;--weui-PURPLE-BG-100: #6768CC;--weui-PURPLE-BG-110: #5C5DB7;--weui-PURPLE-BG-130: #48498F;--weui-PURPLE-BG-90: #7677D1;--weui-RED-100: #FA5151;--weui-RED-120: #C84040;--weui-RED-170: #4B1818;--weui-RED-80: #FB7373;--weui-RED-90: #FA6262;--weui-RED-BG-100: #CF5148;--weui-RED-BG-110: #BA4940;--weui-RED-BG-130: #913832;--weui-RED-BG-90: #D3625A;--weui-SECONDARY-BG: rgba(255, 255, 255, .1);--weui-SEPARATOR-0: rgba(255, 255, 255, .05);--weui-SEPARATOR-1: rgba(255, 255, 255, .15);--weui-STATELAYER-HOVERED: rgba(0, 0, 0, .02);--weui-STATELAYER-PRESSED: rgba(255, 255, 255, .1);--weui-STATELAYER-PRESSEDSTRENGTHENED: rgba(255, 255, 255, .2);--weui-YELLOW-100: #CC9C00;--weui-YELLOW-120: #A37C00;--weui-YELLOW-170: #3D2F00;--weui-YELLOW-80: #D6AF33;--weui-YELLOW-90: #D1A519;--weui-YELLOW-BG-100: #BF9100;--weui-YELLOW-BG-110: #AB8200;--weui-YELLOW-BG-130: #866500;--weui-YELLOW-BG-90: #C59C1A;--weui-FG-HALF: rgba(255, 255, 255, .6);--weui-RED: #FA5151;--weui-ORANGERED: #FF6146;--weui-ORANGE: #C87D2F;--weui-YELLOW: #CC9C00;--weui-GREEN: #74A800;--weui-LIGHTGREEN: #3EB575;--weui-TEXTGREEN: #259C5C;--weui-BRAND: #07C160;--weui-BLUE: #10AEFF;--weui-INDIGO: #1196FF;--weui-PURPLE: #8183FF;--weui-LINK: #7D90A9;--weui-REDORANGE: #FF6146;--weui-TAG-TEXT-BLACK: rgba(255, 255, 255, .5);--weui-TAG-BACKGROUND-BLACK: rgba(255, 255, 255, .05);--weui-WHITE: rgba(255, 255, 255, .8);--weui-FG: #fff;--weui-BG: #000;--weui-FG-5: rgba(255, 255, 255, .1);--weui-TAG-BACKGROUND-ORANGE: rgba(250, 157, 59, .1);--weui-TAG-BACKGROUND-GREEN: rgba(6, 174, 86, .1);--weui-TAG-TEXT-RED: rgba(250, 81, 81, .6);--weui-TAG-BACKGROUND-RED: rgba(250, 81, 81, .1);--weui-TAG-BACKGROUND-BLUE: rgba(16, 174, 255, .1);--weui-TAG-TEXT-ORANGE: rgba(250, 157, 59, .6);--weui-TAG-TEXT-GREEN: rgba(6, 174, 86, .6);--weui-TAG-TEXT-BLUE: rgba(16, 174, 255, .6)}}.wx-root[data-weui-theme=dark],body[data-weui-theme=dark]{--weui-BG-0: #111111;--weui-BG-1: #1E1E1E;--weui-BG-2: #191919;--weui-BG-3: #202020;--weui-BG-4: #404040;--weui-BG-5: #2C2C2C;--weui-BLUE-100: #10AEFF;--weui-BLUE-120: #0C8BCC;--weui-BLUE-170: #04344D;--weui-BLUE-80: #3FBEFF;--weui-BLUE-90: #28B6FF;--weui-BLUE-BG-100: #48A6E2;--weui-BLUE-BG-110: #4095CB;--weui-BLUE-BG-130: #32749E;--weui-BLUE-BG-90: #5AAFE4;--weui-BRAND-100: #07C160;--weui-BRAND-120: #059A4C;--weui-BRAND-170: #023A1C;--weui-BRAND-80: #38CD7F;--weui-BRAND-90: #20C770;--weui-BRAND-BG-100: #2AAE67;--weui-BRAND-BG-110: #259C5C;--weui-BRAND-BG-130: #1D7A48;--weui-BRAND-BG-90: #3EB575;--weui-FG-0: rgba(255, 255, 255, .8);--weui-FG-0_5: rgba(255, 255, 255, .6);--weui-FG-1: rgba(255, 255, 255, .5);--weui-FG-2: rgba(255, 255, 255, .3);--weui-FG-3: rgba(255, 255, 255, .1);--weui-FG-4: rgba(255, 255, 255, .15);--weui-GLYPH-0: rgba(255, 255, 255, .8);--weui-GLYPH-1: rgba(255, 255, 255, .5);--weui-GLYPH-2: rgba(255, 255, 255, .3);--weui-GLYPH-WHITE-0: rgba(255, 255, 255, .8);--weui-GLYPH-WHITE-1: rgba(255, 255, 255, .5);--weui-GLYPH-WHITE-2: rgba(255, 255, 255, .3);--weui-GLYPH-WHITE-3: #FFFFFF;--weui-GREEN-100: #74A800;--weui-GREEN-120: #5C8600;--weui-GREEN-170: #233200;--weui-GREEN-80: #8FB933;--weui-GREEN-90: #82B01A;--weui-GREEN-BG-100: #789833;--weui-GREEN-BG-110: #6B882D;--weui-GREEN-BG-130: #65802B;--weui-GREEN-BG-90: #85A247;--weui-INDIGO-100: #1196FF;--weui-INDIGO-120: #0D78CC;--weui-INDIGO-170: #052D4D;--weui-INDIGO-80: #40ABFF;--weui-INDIGO-90: #28A0FF;--weui-INDIGO-BG-100: #0D78CC;--weui-INDIGO-BG-110: #0B6BB7;--weui-INDIGO-BG-130: #09548F;--weui-INDIGO-BG-90: #2585D1;--weui-LIGHTGREEN-100: #3EB575;--weui-LIGHTGREEN-120: #31905D;--weui-LIGHTGREEN-170: #123522;--weui-LIGHTGREEN-80: #64C390;--weui-LIGHTGREEN-90: #51BC83;--weui-LIGHTGREEN-BG-100: #31905D;--weui-LIGHTGREEN-BG-110: #2C8153;--weui-LIGHTGREEN-BG-130: #226541;--weui-LIGHTGREEN-BG-90: #31905D;--weui-LINK-100: #7D90A9;--weui-LINK-120: #647387;--weui-LINK-170: #252A32;--weui-LINK-80: #97A6BA;--weui-LINK-90: #899AB1;--weui-LINKFINDER-100: #DEE9FF;--weui-MATERIAL-ATTACHMENTCOLUMN: rgba(32, 32, 32, .93);--weui-MATERIAL-NAVIGATIONBAR: rgba(18, 18, 18, .9);--weui-MATERIAL-REGULAR: rgba(37, 37, 37, .6);--weui-MATERIAL-THICK: rgba(34, 34, 34, .9);--weui-MATERIAL-THIN: rgba(95, 95, 95, .4);--weui-MATERIAL-TOOLBAR: rgba(35, 35, 35, .93);--weui-ORANGE-100: #C87D2F;--weui-ORANGE-120: #A06425;--weui-ORANGE-170: #3B250E;--weui-ORANGE-80: #D39758;--weui-ORANGE-90: #CD8943;--weui-ORANGE-BG-100: #BB6000;--weui-ORANGE-BG-110: #A85600;--weui-ORANGE-BG-130: #824300;--weui-ORANGE-BG-90: #C1701A;--weui-ORANGERED-100: #FF6146;--weui-OVERLAY: rgba(0, 0, 0, .8);--weui-OVERLAY-WHITE: rgba(242, 242, 242, .8);--weui-PURPLE-100: #8183FF;--weui-PURPLE-120: #6768CC;--weui-PURPLE-170: #26274C;--weui-PURPLE-80: #9A9BFF;--weui-PURPLE-90: #8D8FFF;--weui-PURPLE-BG-100: #6768CC;--weui-PURPLE-BG-110: #5C5DB7;--weui-PURPLE-BG-130: #48498F;--weui-PURPLE-BG-90: #7677D1;--weui-RED-100: #FA5151;--weui-RED-120: #C84040;--weui-RED-170: #4B1818;--weui-RED-80: #FB7373;--weui-RED-90: #FA6262;--weui-RED-BG-100: #CF5148;--weui-RED-BG-110: #BA4940;--weui-RED-BG-130: #913832;--weui-RED-BG-90: #D3625A;--weui-SECONDARY-BG: rgba(255, 255, 255, .1);--weui-SEPARATOR-0: rgba(255, 255, 255, .05);--weui-SEPARATOR-1: rgba(255, 255, 255, .15);--weui-STATELAYER-HOVERED: rgba(0, 0, 0, .02);--weui-STATELAYER-PRESSED: rgba(255, 255, 255, .1);--weui-STATELAYER-PRESSEDSTRENGTHENED: rgba(255, 255, 255, .2);--weui-YELLOW-100: #CC9C00;--weui-YELLOW-120: #A37C00;--weui-YELLOW-170: #3D2F00;--weui-YELLOW-80: #D6AF33;--weui-YELLOW-90: #D1A519;--weui-YELLOW-BG-100: #BF9100;--weui-YELLOW-BG-110: #AB8200;--weui-YELLOW-BG-130: #866500;--weui-YELLOW-BG-90: #C59C1A;--weui-FG-HALF: rgba(255, 255, 255, .6);--weui-RED: #FA5151;--weui-ORANGERED: #FF6146;--weui-ORANGE: #C87D2F;--weui-YELLOW: #CC9C00;--weui-GREEN: #74A800;--weui-LIGHTGREEN: #3EB575;--weui-TEXTGREEN: #259C5C;--weui-BRAND: #07C160;--weui-BLUE: #10AEFF;--weui-INDIGO: #1196FF;--weui-PURPLE: #8183FF;--weui-LINK: #7D90A9;--weui-REDORANGE: #FF6146;--weui-TAG-TEXT-BLACK: rgba(255, 255, 255, .5);--weui-TAG-BACKGROUND-BLACK: rgba(255, 255, 255, .05);--weui-WHITE: rgba(255, 255, 255, .8);--weui-FG: #fff;--weui-BG: #000;--weui-FG-5: rgba(255, 255, 255, .1);--weui-TAG-BACKGROUND-ORANGE: rgba(250, 157, 59, .1);--weui-TAG-BACKGROUND-GREEN: rgba(6, 174, 86, .1);--weui-TAG-TEXT-RED: rgba(250, 81, 81, .6);--weui-TAG-BACKGROUND-RED: rgba(250, 81, 81, .1);--weui-TAG-BACKGROUND-BLUE: rgba(16, 174, 255, .1);--weui-TAG-TEXT-ORANGE: rgba(250, 157, 59, .6);--weui-TAG-TEXT-GREEN: rgba(6, 174, 86, .6);--weui-TAG-TEXT-BLUE: rgba(16, 174, 255, .6)}.wx-root[data-weui-mode=care],body[data-weui-mode=care]{--weui-BG-0: #EDEDED;--weui-BG-1: #F7F7F7;--weui-BG-2: #FFFFFF;--weui-BG-3: #F7F7F7;--weui-BG-4: #4C4C4C;--weui-BG-5: #FFFFFF;--weui-BLUE-100: #007DBB;--weui-BLUE-120: #3FBEFF;--weui-BLUE-170: #B7E6FF;--weui-BLUE-80: #0C8BCC;--weui-BLUE-90: #0E9CE6;--weui-BLUE-BG-100: #48A6E2;--weui-BLUE-BG-110: #5AAFE4;--weui-BLUE-BG-130: #7FC0EA;--weui-BLUE-BG-90: #4095CB;--weui-BRAND-100: #018942;--weui-BRAND-120: #38CD7F;--weui-BRAND-170: #B4ECCE;--weui-BRAND-80: #059A4C;--weui-BRAND-90: #06AE56;--weui-BRAND-BG-100: #2AAE67;--weui-BRAND-BG-110: #3EB575;--weui-BRAND-BG-130: #69C694;--weui-BRAND-BG-90: #259C5C;--weui-FG-0: #000000;--weui-FG-0_5: #000000;--weui-FG-1: rgba(0, 0, 0, .6);--weui-FG-2: rgba(0, 0, 0, .42);--weui-FG-3: rgba(0, 0, 0, .1);--weui-FG-4: rgba(0, 0, 0, .15);--weui-GLYPH-0: #000000;--weui-GLYPH-1: rgba(0, 0, 0, .6);--weui-GLYPH-2: rgba(0, 0, 0, .42);--weui-GLYPH-WHITE-0: rgba(255, 255, 255, .85);--weui-GLYPH-WHITE-1: rgba(255, 255, 255, .55);--weui-GLYPH-WHITE-2: rgba(255, 255, 255, .35);--weui-GLYPH-WHITE-3: #FFFFFF;--weui-GREEN-100: #4F8400;--weui-GREEN-120: #A7DB33;--weui-GREEN-170: #DEF1B3;--weui-GREEN-80: #74A800;--weui-GREEN-90: #82BD00;--weui-GREEN-BG-100: #96BE40;--weui-GREEN-BG-110: #A0C452;--weui-GREEN-BG-130: #B5D179;--weui-GREEN-BG-90: #86AA39;--weui-INDIGO-100: #0075E2;--weui-INDIGO-120: #439DF1;--weui-INDIGO-170: #B8DAF9;--weui-INDIGO-80: #106ABE;--weui-INDIGO-90: #1277D6;--weui-INDIGO-BG-100: #2B77BF;--weui-INDIGO-BG-110: #3F84C5;--weui-INDIGO-BG-130: #6BA0D2;--weui-INDIGO-BG-90: #266AAB;--weui-LIGHTGREEN-100: #2E8800;--weui-LIGHTGREEN-120: #AAEF87;--weui-LIGHTGREEN-170: #DEF9D1;--weui-LIGHTGREEN-80: #77BC54;--weui-LIGHTGREEN-90: #85D35E;--weui-LIGHTGREEN-BG-100: #72CF60;--weui-LIGHTGREEN-BG-110: #80D370;--weui-LIGHTGREEN-BG-130: #9CDD90;--weui-LIGHTGREEN-BG-90: #66B956;--weui-LINK-100: #576B95;--weui-LINK-120: #7888AA;--weui-LINK-170: #CCD2DE;--weui-LINK-80: #455577;--weui-LINK-90: #4E6085;--weui-LINKFINDER-100: #002666;--weui-MATERIAL-ATTACHMENTCOLUMN: rgba(245, 245, 245, .95);--weui-MATERIAL-NAVIGATIONBAR: rgba(237, 237, 237, .94);--weui-MATERIAL-REGULAR: rgba(247, 247, 247, .3);--weui-MATERIAL-THICK: rgba(247, 247, 247, .8);--weui-MATERIAL-THIN: rgba(255, 255, 255, .2);--weui-MATERIAL-TOOLBAR: rgba(246, 246, 246, .82);--weui-ORANGE-100: #E17719;--weui-ORANGE-120: #FBB062;--weui-ORANGE-170: #FDE1C3;--weui-ORANGE-80: #C87D2F;--weui-ORANGE-90: #E08C34;--weui-ORANGE-BG-100: #EA7800;--weui-ORANGE-BG-110: #EC8519;--weui-ORANGE-BG-130: #F0A04D;--weui-ORANGE-BG-90: #D26B00;--weui-ORANGERED-100: #D14730;--weui-OVERLAY: rgba(0, 0, 0, .5);--weui-OVERLAY-WHITE: rgba(242, 242, 242, .8);--weui-PURPLE-100: #6265F1;--weui-PURPLE-120: #8385F3;--weui-PURPLE-170: #D0D1FA;--weui-PURPLE-80: #5052C0;--weui-PURPLE-90: #595CD7;--weui-PURPLE-BG-100: #6769BA;--weui-PURPLE-BG-110: #7678C1;--weui-PURPLE-BG-130: #9496CE;--weui-PURPLE-BG-90: #5C5EA7;--weui-RED-100: #DC3636;--weui-RED-120: #FB7373;--weui-RED-170: #FDCACA;--weui-RED-80: #C84040;--weui-RED-90: #E14949;--weui-RED-BG-100: #CF5148;--weui-RED-BG-110: #D3625A;--weui-RED-BG-130: #DD847E;--weui-RED-BG-90: #B94840;--weui-SECONDARY-BG: rgba(0, 0, 0, .1);--weui-SEPARATOR-0: rgba(0, 0, 0, .1);--weui-SEPARATOR-1: rgba(0, 0, 0, .15);--weui-STATELAYER-HOVERED: rgba(0, 0, 0, .02);--weui-STATELAYER-PRESSED: rgba(0, 0, 0, .1);--weui-STATELAYER-PRESSEDSTRENGTHENED: rgba(0, 0, 0, .2);--weui-YELLOW-100: #BB8E00;--weui-YELLOW-120: #FFCF33;--weui-YELLOW-170: #FFECB2;--weui-YELLOW-80: #CC9C00;--weui-YELLOW-90: #E6AF00;--weui-YELLOW-BG-100: #EFB600;--weui-YELLOW-BG-110: #F0BD19;--weui-YELLOW-BG-130: #F3CC4D;--weui-YELLOW-BG-90: #D7A400;--weui-FG-HALF: #000000;--weui-RED: #DC3636;--weui-ORANGERED: #D14730;--weui-ORANGE: #E17719;--weui-YELLOW: #BB8E00;--weui-GREEN: #4F8400;--weui-LIGHTGREEN: #2E8800;--weui-TEXTGREEN: #06AE56;--weui-BRAND: #018942;--weui-BLUE: #007DBB;--weui-INDIGO: #0075E2;--weui-PURPLE: #6265F1;--weui-LINK: #576B95;--weui-TAG-TEXT-ORANGE: #E17719;--weui-TAG-TEXT-GREEN: #06AE56;--weui-TAG-TEXT-BLUE: #007DBB;--weui-REDORANGE: #D14730;--weui-TAG-TEXT-BLACK: rgba(0, 0, 0, .5);--weui-WHITE: #FFFFFF;--weui-BG: #FFFFFF;--weui-FG: #000;--weui-FG-5: rgba(0, 0, 0, .05);--weui-TAG-BACKGROUND-ORANGE: rgba(225, 119, 25, .1);--weui-TAG-BACKGROUND-GREEN: rgba(6, 174, 86, .1);--weui-TAG-TEXT-RED: rgba(250, 81, 81, .6);--weui-TAG-BACKGROUND-RED: rgba(250, 81, 81, .1);--weui-TAG-BACKGROUND-BLUE: rgba(0, 125, 187, .1);--weui-TAG-BACKGROUND-BLACK: rgba(0, 0, 0, .05)}@media (prefers-color-scheme: dark){.wx-root[data-weui-mode=care]:not([data-weui-theme=light]),body[data-weui-mode=care]:not([data-weui-theme=light]){--weui-BG-0: #111111;--weui-BG-1: #1E1E1E;--weui-BG-2: #191919;--weui-BG-3: #202020;--weui-BG-4: #404040;--weui-BG-5: #2C2C2C;--weui-BLUE-100: #10AEFF;--weui-BLUE-120: #0C8BCC;--weui-BLUE-170: #04344D;--weui-BLUE-80: #3FBEFF;--weui-BLUE-90: #28B6FF;--weui-BLUE-BG-100: #48A6E2;--weui-BLUE-BG-110: #4095CB;--weui-BLUE-BG-130: #32749E;--weui-BLUE-BG-90: #5AAFE4;--weui-BRAND-100: #07C160;--weui-BRAND-120: #059A4C;--weui-BRAND-170: #023A1C;--weui-BRAND-80: #38CD7F;--weui-BRAND-90: #20C770;--weui-BRAND-BG-100: #2AAE67;--weui-BRAND-BG-110: #259C5C;--weui-BRAND-BG-130: #1D7A48;--weui-BRAND-BG-90: #3EB575;--weui-FG-0: rgba(255, 255, 255, .85);--weui-FG-0_5: rgba(255, 255, 255, .65);--weui-FG-1: rgba(255, 255, 255, .55);--weui-FG-2: rgba(255, 255, 255, .35);--weui-FG-3: rgba(255, 255, 255, .1);--weui-FG-4: rgba(255, 255, 255, .15);--weui-GLYPH-0: rgba(255, 255, 255, .85);--weui-GLYPH-1: rgba(255, 255, 255, .55);--weui-GLYPH-2: rgba(255, 255, 255, .35);--weui-GLYPH-WHITE-0: rgba(255, 255, 255, .85);--weui-GLYPH-WHITE-1: rgba(255, 255, 255, .55);--weui-GLYPH-WHITE-2: rgba(255, 255, 255, .35);--weui-GLYPH-WHITE-3: #FFFFFF;--weui-GREEN-100: #74A800;--weui-GREEN-120: #5C8600;--weui-GREEN-170: #233200;--weui-GREEN-80: #8FB933;--weui-GREEN-90: #82B01A;--weui-GREEN-BG-100: #789833;--weui-GREEN-BG-110: #6B882D;--weui-GREEN-BG-130: #65802B;--weui-GREEN-BG-90: #85A247;--weui-INDIGO-100: #1196FF;--weui-INDIGO-120: #0D78CC;--weui-INDIGO-170: #052D4D;--weui-INDIGO-80: #40ABFF;--weui-INDIGO-90: #28A0FF;--weui-INDIGO-BG-100: #0D78CC;--weui-INDIGO-BG-110: #0B6BB7;--weui-INDIGO-BG-130: #09548F;--weui-INDIGO-BG-90: #2585D1;--weui-LIGHTGREEN-100: #3EB575;--weui-LIGHTGREEN-120: #31905D;--weui-LIGHTGREEN-170: #123522;--weui-LIGHTGREEN-80: #64C390;--weui-LIGHTGREEN-90: #51BC83;--weui-LIGHTGREEN-BG-100: #31905D;--weui-LIGHTGREEN-BG-110: #2C8153;--weui-LIGHTGREEN-BG-130: #226541;--weui-LIGHTGREEN-BG-90: #31905D;--weui-LINK-100: #7D90A9;--weui-LINK-120: #647387;--weui-LINK-170: #252A32;--weui-LINK-80: #97A6BA;--weui-LINK-90: #899AB1;--weui-LINKFINDER-100: #DEE9FF;--weui-MATERIAL-ATTACHMENTCOLUMN: rgba(32, 32, 32, .93);--weui-MATERIAL-NAVIGATIONBAR: rgba(18, 18, 18, .9);--weui-MATERIAL-REGULAR: rgba(37, 37, 37, .6);--weui-MATERIAL-THICK: rgba(34, 34, 34, .9);--weui-MATERIAL-THIN: rgba(245, 245, 245, .4);--weui-MATERIAL-TOOLBAR: rgba(35, 35, 35, .93);--weui-ORANGE-100: #C87D2F;--weui-ORANGE-120: #A06425;--weui-ORANGE-170: #3B250E;--weui-ORANGE-80: #D39758;--weui-ORANGE-90: #CD8943;--weui-ORANGE-BG-100: #BB6000;--weui-ORANGE-BG-110: #A85600;--weui-ORANGE-BG-130: #824300;--weui-ORANGE-BG-90: #C1701A;--weui-ORANGERED-100: #FF6146;--weui-OVERLAY: rgba(0, 0, 0, .8);--weui-OVERLAY-WHITE: rgba(242, 242, 242, .8);--weui-PURPLE-100: #8183FF;--weui-PURPLE-120: #6768CC;--weui-PURPLE-170: #26274C;--weui-PURPLE-80: #9A9BFF;--weui-PURPLE-90: #8D8FFF;--weui-PURPLE-BG-100: #6768CC;--weui-PURPLE-BG-110: #5C5DB7;--weui-PURPLE-BG-130: #48498F;--weui-PURPLE-BG-90: #7677D1;--weui-RED-100: #FA5151;--weui-RED-120: #C84040;--weui-RED-170: #4B1818;--weui-RED-80: #FB7373;--weui-RED-90: #FA6262;--weui-RED-BG-100: #CF5148;--weui-RED-BG-110: #BA4940;--weui-RED-BG-130: #913832;--weui-RED-BG-90: #D3625A;--weui-SECONDARY-BG: rgba(255, 255, 255, .15);--weui-SEPARATOR-0: rgba(255, 255, 255, .05);--weui-SEPARATOR-1: rgba(255, 255, 255, .15);--weui-STATELAYER-HOVERED: rgba(0, 0, 0, .02);--weui-STATELAYER-PRESSED: rgba(255, 255, 255, .1);--weui-STATELAYER-PRESSEDSTRENGTHENED: rgba(255, 255, 255, .2);--weui-YELLOW-100: #CC9C00;--weui-YELLOW-120: #A37C00;--weui-YELLOW-170: #3D2F00;--weui-YELLOW-80: #D6AF33;--weui-YELLOW-90: #D1A519;--weui-YELLOW-BG-100: #BF9100;--weui-YELLOW-BG-110: #AB8200;--weui-YELLOW-BG-130: #866500;--weui-YELLOW-BG-90: #C59C1A;--weui-FG-HALF: rgba(255, 255, 255, .65);--weui-RED: #FA5151;--weui-ORANGERED: #FF6146;--weui-ORANGE: #C87D2F;--weui-YELLOW: #CC9C00;--weui-GREEN: #74A800;--weui-LIGHTGREEN: #3EB575;--weui-TEXTGREEN: #259C5C;--weui-BRAND: #07C160;--weui-BLUE: #10AEFF;--weui-INDIGO: #1196FF;--weui-PURPLE: #8183FF;--weui-LINK: #7D90A9;--weui-REDORANGE: #FF6146;--weui-TAG-BACKGROUND-BLACK: rgba(255, 255, 255, .05);--weui-FG: #fff;--weui-WHITE: rgba(255, 255, 255, .8);--weui-FG-5: rgba(255, 255, 255, .1);--weui-TAG-BACKGROUND-ORANGE: rgba(250, 157, 59, .1);--weui-TAG-BACKGROUND-GREEN: rgba(6, 174, 86, .1);--weui-TAG-TEXT-RED: rgba(250, 81, 81, .6);--weui-TAG-BACKGROUND-RED: rgba(250, 81, 81, .1);--weui-TAG-BACKGROUND-BLUE: rgba(16, 174, 255, .1);--weui-TAG-TEXT-ORANGE: rgba(250, 157, 59, .6);--weui-BG: #000;--weui-TAG-TEXT-GREEN: rgba(6, 174, 86, .6);--weui-TAG-TEXT-BLUE: rgba(16, 174, 255, .6);--weui-TAG-TEXT-BLACK: rgba(255, 255, 255, .5)}}.wx-root[data-weui-mode=care][data-weui-theme=dark],body[data-weui-mode=care][data-weui-theme=dark]{--weui-BG-0: #111111;--weui-BG-1: #1E1E1E;--weui-BG-2: #191919;--weui-BG-3: #202020;--weui-BG-4: #404040;--weui-BG-5: #2C2C2C;--weui-BLUE-100: #10AEFF;--weui-BLUE-120: #0C8BCC;--weui-BLUE-170: #04344D;--weui-BLUE-80: #3FBEFF;--weui-BLUE-90: #28B6FF;--weui-BLUE-BG-100: #48A6E2;--weui-BLUE-BG-110: #4095CB;--weui-BLUE-BG-130: #32749E;--weui-BLUE-BG-90: #5AAFE4;--weui-BRAND-100: #07C160;--weui-BRAND-120: #059A4C;--weui-BRAND-170: #023A1C;--weui-BRAND-80: #38CD7F;--weui-BRAND-90: #20C770;--weui-BRAND-BG-100: #2AAE67;--weui-BRAND-BG-110: #259C5C;--weui-BRAND-BG-130: #1D7A48;--weui-BRAND-BG-90: #3EB575;--weui-FG-0: rgba(255, 255, 255, .85);--weui-FG-0_5: rgba(255, 255, 255, .65);--weui-FG-1: rgba(255, 255, 255, .55);--weui-FG-2: rgba(255, 255, 255, .35);--weui-FG-3: rgba(255, 255, 255, .1);--weui-FG-4: rgba(255, 255, 255, .15);--weui-GLYPH-0: rgba(255, 255, 255, .85);--weui-GLYPH-1: rgba(255, 255, 255, .55);--weui-GLYPH-2: rgba(255, 255, 255, .35);--weui-GLYPH-WHITE-0: rgba(255, 255, 255, .85);--weui-GLYPH-WHITE-1: rgba(255, 255, 255, .55);--weui-GLYPH-WHITE-2: rgba(255, 255, 255, .35);--weui-GLYPH-WHITE-3: #FFFFFF;--weui-GREEN-100: #74A800;--weui-GREEN-120: #5C8600;--weui-GREEN-170: #233200;--weui-GREEN-80: #8FB933;--weui-GREEN-90: #82B01A;--weui-GREEN-BG-100: #789833;--weui-GREEN-BG-110: #6B882D;--weui-GREEN-BG-130: #65802B;--weui-GREEN-BG-90: #85A247;--weui-INDIGO-100: #1196FF;--weui-INDIGO-120: #0D78CC;--weui-INDIGO-170: #052D4D;--weui-INDIGO-80: #40ABFF;--weui-INDIGO-90: #28A0FF;--weui-INDIGO-BG-100: #0D78CC;--weui-INDIGO-BG-110: #0B6BB7;--weui-INDIGO-BG-130: #09548F;--weui-INDIGO-BG-90: #2585D1;--weui-LIGHTGREEN-100: #3EB575;--weui-LIGHTGREEN-120: #31905D;--weui-LIGHTGREEN-170: #123522;--weui-LIGHTGREEN-80: #64C390;--weui-LIGHTGREEN-90: #51BC83;--weui-LIGHTGREEN-BG-100: #31905D;--weui-LIGHTGREEN-BG-110: #2C8153;--weui-LIGHTGREEN-BG-130: #226541;--weui-LIGHTGREEN-BG-90: #31905D;--weui-LINK-100: #7D90A9;--weui-LINK-120: #647387;--weui-LINK-170: #252A32;--weui-LINK-80: #97A6BA;--weui-LINK-90: #899AB1;--weui-LINKFINDER-100: #DEE9FF;--weui-MATERIAL-ATTACHMENTCOLUMN: rgba(32, 32, 32, .93);--weui-MATERIAL-NAVIGATIONBAR: rgba(18, 18, 18, .9);--weui-MATERIAL-REGULAR: rgba(37, 37, 37, .6);--weui-MATERIAL-THICK: rgba(34, 34, 34, .9);--weui-MATERIAL-THIN: rgba(245, 245, 245, .4);--weui-MATERIAL-TOOLBAR: rgba(35, 35, 35, .93);--weui-ORANGE-100: #C87D2F;--weui-ORANGE-120: #A06425;--weui-ORANGE-170: #3B250E;--weui-ORANGE-80: #D39758;--weui-ORANGE-90: #CD8943;--weui-ORANGE-BG-100: #BB6000;--weui-ORANGE-BG-110: #A85600;--weui-ORANGE-BG-130: #824300;--weui-ORANGE-BG-90: #C1701A;--weui-ORANGERED-100: #FF6146;--weui-OVERLAY: rgba(0, 0, 0, .8);--weui-OVERLAY-WHITE: rgba(242, 242, 242, .8);--weui-PURPLE-100: #8183FF;--weui-PURPLE-120: #6768CC;--weui-PURPLE-170: #26274C;--weui-PURPLE-80: #9A9BFF;--weui-PURPLE-90: #8D8FFF;--weui-PURPLE-BG-100: #6768CC;--weui-PURPLE-BG-110: #5C5DB7;--weui-PURPLE-BG-130: #48498F;--weui-PURPLE-BG-90: #7677D1;--weui-RED-100: #FA5151;--weui-RED-120: #C84040;--weui-RED-170: #4B1818;--weui-RED-80: #FB7373;--weui-RED-90: #FA6262;--weui-RED-BG-100: #CF5148;--weui-RED-BG-110: #BA4940;--weui-RED-BG-130: #913832;--weui-RED-BG-90: #D3625A;--weui-SECONDARY-BG: rgba(255, 255, 255, .15);--weui-SEPARATOR-0: rgba(255, 255, 255, .05);--weui-SEPARATOR-1: rgba(255, 255, 255, .15);--weui-STATELAYER-HOVERED: rgba(0, 0, 0, .02);--weui-STATELAYER-PRESSED: rgba(255, 255, 255, .1);--weui-STATELAYER-PRESSEDSTRENGTHENED: rgba(255, 255, 255, .2);--weui-YELLOW-100: #CC9C00;--weui-YELLOW-120: #A37C00;--weui-YELLOW-170: #3D2F00;--weui-YELLOW-80: #D6AF33;--weui-YELLOW-90: #D1A519;--weui-YELLOW-BG-100: #BF9100;--weui-YELLOW-BG-110: #AB8200;--weui-YELLOW-BG-130: #866500;--weui-YELLOW-BG-90: #C59C1A;--weui-FG-HALF: rgba(255, 255, 255, .65);--weui-RED: #FA5151;--weui-ORANGERED: #FF6146;--weui-ORANGE: #C87D2F;--weui-YELLOW: #CC9C00;--weui-GREEN: #74A800;--weui-LIGHTGREEN: #3EB575;--weui-TEXTGREEN: #259C5C;--weui-BRAND: #07C160;--weui-BLUE: #10AEFF;--weui-INDIGO: #1196FF;--weui-PURPLE: #8183FF;--weui-LINK: #7D90A9;--weui-REDORANGE: #FF6146;--weui-TAG-BACKGROUND-BLACK: rgba(255, 255, 255, .05);--weui-FG: #fff;--weui-WHITE: rgba(255, 255, 255, .8);--weui-FG-5: rgba(255, 255, 255, .1);--weui-TAG-BACKGROUND-ORANGE: rgba(250, 157, 59, .1);--weui-TAG-BACKGROUND-GREEN: rgba(6, 174, 86, .1);--weui-TAG-TEXT-RED: rgba(250, 81, 81, .6);--weui-TAG-BACKGROUND-RED: rgba(250, 81, 81, .1);--weui-TAG-BACKGROUND-BLUE: rgba(16, 174, 255, .1);--weui-TAG-TEXT-ORANGE: rgba(250, 157, 59, .6);--weui-BG: #000;--weui-TAG-TEXT-GREEN: rgba(6, 174, 86, .6);--weui-TAG-TEXT-BLUE: rgba(16, 174, 255, .6);--weui-TAG-TEXT-BLACK: rgba(255, 255, 255, .5)}.wx_hover_card:before{content:" ";position:absolute;top:0;left:0;right:0;bottom:0;border-radius:8px;box-sizing:border-box;border:1px solid rgba(7,193,96,.3);pointer-events:none;z-index:9}.wx_selected_card:before{content:" ";position:absolute;top:0;left:0;right:0;bottom:0;border-radius:8px;border:1.5px solid #07C160;box-sizing:border-box;background:rgba(7,193,96,.1);pointer-events:none;z-index:9}.product_card_text_wrp{display:inline;-webkit-user-select:none;-moz-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;font-family:PingFang SC}.iframe_wrp{display:flex;flex-direction:column;-webkit-user-select:none;-moz-user-select:none;user-select:none;align-items:center;position:relative}.iframe_style{height:0px}.product_wx_img_placeholder{width:100%;background:var(--weui-BG-3) url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg width='80px' height='80px' viewBox='0 0 80 80' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Ctitle%3E9.元素/加载/Black%3C/title%3E%3Cdefs%3E%3ClinearGradient x1='94.0869141%25' y1='0%25' x2='94.0869141%25' y2='90.559082%25' id='linearGradient-1'%3E%3Cstop stop-color='%23606060' stop-opacity='0' offset='0%25'%3E%3C/stop%3E%3Cstop stop-color='%23606060' stop-opacity='0.3' offset='100%25'%3E%3C/stop%3E%3C/linearGradient%3E%3ClinearGradient x1='100%25' y1='8.67370605%25' x2='100%25' y2='90.6286621%25' id='linearGradient-2'%3E%3Cstop stop-color='%23606060' offset='0%25'%3E%3C/stop%3E%3Cstop stop-color='%23606060' stop-opacity='0.3' offset='100%25'%3E%3C/stop%3E%3C/linearGradient%3E%3C/defs%3E%3Cg id='页面-1' stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' opacity='0.9'%3E%3Cg id='LoadingDefault'%3E%3Cpath d='M40,0 C62.09139,0 80,17.90861 80,40 C80,62.09139 62.09139,80 40,80 L40,73 C58.2253967,73 73,58.2253967 73,40 C73,21.7746033 58.2253967,7 40,7 L40,0 Z' id='路径' fill='url(%23linearGradient-1)'%3E%3C/path%3E%3Cpath d='M40,0 L40,7 C21.7746033,7 7,21.7746033 7,40 C7,58.2253967 21.7746033,73 40,73 L40,80 C17.90861,80 0,62.09139 0,40 C0,17.90861 17.90861,0 40,0 Z' id='路径' fill='url(%23linearGradient-2)'%3E%3C/path%3E%3Ccircle id='Oval' fill='%23606060' cx='40.5' cy='3.5' r='3.5'%3E%3C/circle%3E%3C/g%3E%3CanimateTransform attributeName='transform' begin='0s' dur='1s' type='rotate' values='0 40 40;360 40 40' repeatCount='indefinite'/%3E%3C/g%3E%3C/svg%3E%0A") no-repeat 50% 50%!important;background-size:16px!important;border-radius:8px}:root{--weui-FG-6: rgba(0, 0, 0, .05)}@media (prefers-color-scheme: dark){:root{--weui-FG-6: rgba(255, 255, 255, .05)}}.product_text_link{text-decoration:none;padding:2px 4px;color:var(--weui-LINK);cursor:default;-webkit-user-drag:none;border-radius:4px}.product_text_link:before{content:"";display:inline-block;mask-image:url("data:image/svg+xml,%3Csvg width='25' height='25' viewBox='0 0 25 25' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M5.798 13.728c-.32 0-.636-.032-.942-.096-1.792-.378-3.042-1.754-3.042-3.348 0-.426.088-.84.262-1.232l.008-.02 2.008-4.498a3.696 3.696 0 0 1 3.372-2.186h9.8A3.697 3.697 0 0 1 20.662 4.6l1.984 4.432c.178.402.268.82.268 1.248 0 1.596-1.252 2.974-3.044 3.348a4.63 4.63 0 0 1-2.176-.074c-.816-.23-1.514-.68-2.002-1.268-.798.846-2.018 1.368-3.326 1.368-1.308 0-2.52-.52-3.322-1.364-.488.59-1.188 1.042-2.014 1.274-.394.11-.808.168-1.23.168l-.002-.004zM3.46 9.632l-.01.022c-.09.2-.136.412-.136.63 0 .878.762 1.65 1.85 1.88.47.098.994.082 1.458-.048.766-.214 1.368-.728 1.576-1.34a1.43 1.43 0 0 0 .046-.158.748.748 0 1 1 1.448-.056l.026.07.012.03c.392.892 1.448 1.49 2.634 1.49s2.25-.602 2.636-1.498c.02-.046.034-.082.046-.12a.744.744 0 0 1 .754-.502.75.75 0 0 1 .688.588c.012.056.026.108.042.152.214.62.802 1.118 1.572 1.334.466.132.99.148 1.46.048 1.092-.228 1.852-1.002 1.852-1.88 0-.216-.046-.43-.138-.636l-1.988-4.44-.008-.018-.018-.036a2.19 2.19 0 0 0-1.998-1.296h-9.8c-.864 0-1.648.51-2 1.298-.008.016-.014.032-.022.046L3.46 9.634v-.002zM12.364 21.642c-4.142 0-7.566-2.634-7.794-5.996a.75.75 0 1 1 1.498-.102c.174 2.578 2.94 4.598 6.298 4.598s6.122-2.02 6.296-4.598a.75.75 0 1 1 1.498.102c-.228 3.362-3.652 5.996-7.794 5.996h-.002z' fill='%23576B95'/%3E%3C/svg%3E");-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='25' height='25' viewBox='0 0 25 25' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M5.798 13.728c-.32 0-.636-.032-.942-.096-1.792-.378-3.042-1.754-3.042-3.348 0-.426.088-.84.262-1.232l.008-.02 2.008-4.498a3.696 3.696 0 0 1 3.372-2.186h9.8A3.697 3.697 0 0 1 20.662 4.6l1.984 4.432c.178.402.268.82.268 1.248 0 1.596-1.252 2.974-3.044 3.348a4.63 4.63 0 0 1-2.176-.074c-.816-.23-1.514-.68-2.002-1.268-.798.846-2.018 1.368-3.326 1.368-1.308 0-2.52-.52-3.322-1.364-.488.59-1.188 1.042-2.014 1.274-.394.11-.808.168-1.23.168l-.002-.004zM3.46 9.632l-.01.022c-.09.2-.136.412-.136.63 0 .878.762 1.65 1.85 1.88.47.098.994.082 1.458-.048.766-.214 1.368-.728 1.576-1.34a1.43 1.43 0 0 0 .046-.158.748.748 0 1 1 1.448-.056l.026.07.012.03c.392.892 1.448 1.49 2.634 1.49s2.25-.602 2.636-1.498c.02-.046.034-.082.046-.12a.744.744 0 0 1 .754-.502.75.75 0 0 1 .688.588c.012.056.026.108.042.152.214.62.802 1.118 1.572 1.334.466.132.99.148 1.46.048 1.092-.228 1.852-1.002 1.852-1.88 0-.216-.046-.43-.138-.636l-1.988-4.44-.008-.018-.018-.036a2.19 2.19 0 0 0-1.998-1.296h-9.8c-.864 0-1.648.51-2 1.298-.008.016-.014.032-.022.046L3.46 9.634v-.002zM12.364 21.642c-4.142 0-7.566-2.634-7.794-5.996a.75.75 0 1 1 1.498-.102c.174 2.578 2.94 4.598 6.298 4.598s6.122-2.02 6.296-4.598a.75.75 0 1 1 1.498.102c-.228 3.362-3.652 5.996-7.794 5.996h-.002z' fill='%23576B95'/%3E%3C/svg%3E");background-color:currentColor;-webkit-mask-size:contain;mask-size:contain;vertical-align:middle;height:1.1em;width:1.1em;margin-right:2px;margin-top:-.16em}.product-logo{height:1.1em;width:1.1em;display:inline-block;mask-image:url("data:image/svg+xml,%3Csvg width='25' height='25' viewBox='0 0 25 25' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M5.798 13.728c-.32 0-.636-.032-.942-.096-1.792-.378-3.042-1.754-3.042-3.348 0-.426.088-.84.262-1.232l.008-.02 2.008-4.498a3.696 3.696 0 0 1 3.372-2.186h9.8A3.697 3.697 0 0 1 20.662 4.6l1.984 4.432c.178.402.268.82.268 1.248 0 1.596-1.252 2.974-3.044 3.348a4.63 4.63 0 0 1-2.176-.074c-.816-.23-1.514-.68-2.002-1.268-.798.846-2.018 1.368-3.326 1.368-1.308 0-2.52-.52-3.322-1.364-.488.59-1.188 1.042-2.014 1.274-.394.11-.808.168-1.23.168l-.002-.004zM3.46 9.632l-.01.022c-.09.2-.136.412-.136.63 0 .878.762 1.65 1.85 1.88.47.098.994.082 1.458-.048.766-.214 1.368-.728 1.576-1.34a1.43 1.43 0 0 0 .046-.158.748.748 0 1 1 1.448-.056l.026.07.012.03c.392.892 1.448 1.49 2.634 1.49s2.25-.602 2.636-1.498c.02-.046.034-.082.046-.12a.744.744 0 0 1 .754-.502.75.75 0 0 1 .688.588c.012.056.026.108.042.152.214.62.802 1.118 1.572 1.334.466.132.99.148 1.46.048 1.092-.228 1.852-1.002 1.852-1.88 0-.216-.046-.43-.138-.636l-1.988-4.44-.008-.018-.018-.036a2.19 2.19 0 0 0-1.998-1.296h-9.8c-.864 0-1.648.51-2 1.298-.008.016-.014.032-.022.046L3.46 9.634v-.002zM12.364 21.642c-4.142 0-7.566-2.634-7.794-5.996a.75.75 0 1 1 1.498-.102c.174 2.578 2.94 4.598 6.298 4.598s6.122-2.02 6.296-4.598a.75.75 0 1 1 1.498.102c-.228 3.362-3.652 5.996-7.794 5.996h-.002z' fill='%23576B95'/%3E%3C/svg%3E");-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='25' height='25' viewBox='0 0 25 25' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M5.798 13.728c-.32 0-.636-.032-.942-.096-1.792-.378-3.042-1.754-3.042-3.348 0-.426.088-.84.262-1.232l.008-.02 2.008-4.498a3.696 3.696 0 0 1 3.372-2.186h9.8A3.697 3.697 0 0 1 20.662 4.6l1.984 4.432c.178.402.268.82.268 1.248 0 1.596-1.252 2.974-3.044 3.348a4.63 4.63 0 0 1-2.176-.074c-.816-.23-1.514-.68-2.002-1.268-.798.846-2.018 1.368-3.326 1.368-1.308 0-2.52-.52-3.322-1.364-.488.59-1.188 1.042-2.014 1.274-.394.11-.808.168-1.23.168l-.002-.004zM3.46 9.632l-.01.022c-.09.2-.136.412-.136.63 0 .878.762 1.65 1.85 1.88.47.098.994.082 1.458-.048.766-.214 1.368-.728 1.576-1.34a1.43 1.43 0 0 0 .046-.158.748.748 0 1 1 1.448-.056l.026.07.012.03c.392.892 1.448 1.49 2.634 1.49s2.25-.602 2.636-1.498c.02-.046.034-.082.046-.12a.744.744 0 0 1 .754-.502.75.75 0 0 1 .688.588c.012.056.026.108.042.152.214.62.802 1.118 1.572 1.334.466.132.99.148 1.46.048 1.092-.228 1.852-1.002 1.852-1.88 0-.216-.046-.43-.138-.636l-1.988-4.44-.008-.018-.018-.036a2.19 2.19 0 0 0-1.998-1.296h-9.8c-.864 0-1.648.51-2 1.298-.008.016-.014.032-.022.046L3.46 9.634v-.002zM12.364 21.642c-4.142 0-7.566-2.634-7.794-5.996a.75.75 0 1 1 1.498-.102c.174 2.578 2.94 4.598 6.298 4.598s6.122-2.02 6.296-4.598a.75.75 0 1 1 1.498.102c-.228 3.362-3.652 5.996-7.794 5.996h-.002z' fill='%23576B95'/%3E%3C/svg%3E");background-color:currentColor;-webkit-mask-size:contain;mask-size:contain}.shop-verify-icon{height:1em;width:1em;display:inline-block;background-image:url("data:image/svg+xml,%3Csvg width='12' height='13' viewBox='0 0 12 13' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8.913 3.789l-.718-1.732a.352.352 0 0 0-.46-.19l-1.732.717-1.731-.718a.352.352 0 0 0-.46.191l-.718 1.732-1.732.717a.352.352 0 0 0-.19.46l.717 1.732-.717 1.732c-.074.18.01.386.19.46l1.732.717.718 1.732c.074.18.28.265.46.19l1.731-.717 1.732.718c.18.074.386-.011.46-.19l.718-1.733 1.732-.717a.352.352 0 0 0 .19-.46l-.717-1.732.717-1.732a.352.352 0 0 0-.19-.46L8.913 3.79z' fill='%23E0B584'/%3E%3Cpath d='M7.082 8.904l-1.496-1.8 1.496 1.8zm0 0l.009.01c.014.017.031.038.053.054.03.02.064.03.11.03h.526c.057 0 .11-.03.133-.081.024-.054.008-.116-.04-.167L6.306 7.004m.776 1.9l-.776-1.9m0 0c.382-.07.686-.21.9-.413.23-.221.351-.515.351-.87 0-.422-.153-.756-.446-.983-.292-.226-.716-.34-1.252-.34h-.97a.37.37 0 0 0-.27.096.37.37 0 0 0-.096.27v4.12c0 .03.01.06.032.081.021.022.05.032.08.032h.432c.03 0 .06-.01.081-.032a.113.113 0 0 0 .032-.081v-3.86c0-.008.003-.01.003-.01 0-.001.003-.003.01-.003h.634c.21 0 .479.022.692.125a.646.646 0 0 1 .262.219.673.673 0 0 1 .106.385c0 .222-.104.388-.288.512-.187.125-.455.206-.778.25l.485.502zm-.485-.502l-.095.012h-.001a.316.316 0 0 0-.17.072.235.235 0 0 0-.07.18v.07a.388.388 0 0 0 .101.267l.235-.601z' fill='%23fff' stroke='%23fff' stroke-width='.1'/%3E%3C/svg%3E");background-size:contain;background-position:center}.weui-toast{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background-color:#4c4c4c;border-radius:8px;color:#fff;font-size:14px;line-height:1.4;padding:0 20px}.discounted_price.fade-enter,.discounted_price.fade-leave-to{opacity:0;height:0}.discounted_price.fade-enter-to,.discounted_price.fade-leave{opacity:1;height:15px}.discounted_price.fade-enter-active,.discounted_price.fade-leave-active{transition:opacity .15s,height .15s}.activity_card_wrp{-webkit-user-select:none;-moz-user-select:none;user-select:none;width:-moz-fit-content;width:fit-content}.activity_card_wrp .activity_card_wrp__container{display:flex;flex-direction:column;align-items:center;background-color:#0000001a;-webkit-backdrop-filter:blur(50px);backdrop-filter:blur(50px);border-radius:8px;padding:10px}.activity_card_wrp .activity_card_wrp__container .product_image{width:52px;height:52px;border-radius:2px;margin-bottom:8px}.activity_card_wrp .discounted_price{overflow:hidden;font-weight:500;color:#e0b684;line-height:1;font-family:WeChatSansStd-Medium;line-height:normal;font-size:15px}@font-face{font-family:WeChatSansStd-Medium;src:url(data:application/octet-stream;base64,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AwYAAwABBAkABAAsA1oAAwABBAkABQAYA4YAAwABBAkABgAsA54AAwABBAkABwBMA8oAAwABBAkACAAWBBYAAwABBAkACQBGBCwAAwABBAkACwAwBHIAAwABBAkAEAAeBKIAAwABBAkAEQAMBMAAAwABBAkAEwAiBMwAAwABCAQAAABmBO4AAwABCAQAAQAsBVQAAwABCAQAAgAOBYAAAwABCAQABAAsBY4AAwABCAQABwBMBboAAwABCAQACAAWBgYAAwABCAQACQBGBhwAAwABCAQAEAAeBmIAAwABCAQAEQAMBoBDb3B5cmlnaHQgKGMpIDIwMTcgYnkgVGVuY2VudC4gQWxsIHJpZ2h0cyByZXNlcnZlZC5XZUNoYXQgU2FucyBTdGRNZWRpdW1IYW55aSBXZUNoYXQgU2FucyBTdGQtTWVkaXVtOyBWZXJzaW9uIDEuMDBXZUNoYXQgU2FucyBTdGQtTWVkaXVtVmVyc2lvbiAxLjAwV2VDaGF0LVNhbnMtU3RkLU1lZGl1bVdlQ2hhdCBTYW5zIGlzIGEgdHJhZGVtYXJrIG9mIFRlbmNlbnQuSGFueWkgRm9udHNaSEFORyBYdWFuLCBXQU5HIFRpYW5iaSwgTElVIFhpYW95dWh0dHA6Ly93d3cuaGFueWkuY29tLmNuL1dlQ2hhdCBTYW5zIFN0ZE1lZGl1bVdlQ2hhdCBTYW5zIFN0ZC1NZWRpdW3boiSjX7QKMTIzNDU2Nzg5MENvcHlyaWdodCAoYykgMjAxNyBieSBUZW5jZW50LiBBbGwgcmlnaHRzIHJlc2VydmVkLldlQ2hhdCBTYW5zIFN0ZE1lZGl1bUhhbnlpIFdlQ2hhdCBTYW5zIFN0ZC1NZWRpdW07IFZlcnNpb24gMS4wMFdlQ2hhdCBTYW5zIFN0ZC1NZWRpdW1WZXJzaW9uIDEuMDBXZUNoYXQtU2Fucy1TdGQtTWVkaXVtV2VDaGF0IFNhbnMgaXMgYSB0cmFkZW1hcmsgb2YgVGVuY2VudC5IYW55aSBGb250c1pIQU5HIFh1YW4sIFdBTkcgVGlhbmJpLCBMSVUgWGlhb3l1V2VDaGF0IFNhbnMgU3RkLU1lZGl1bQBDAG8AcAB5AHIAaQBnAGgAdAAgACgAYwApACAAMgAwADEANwAgAGIAeQAgAFQAZQBuAGMAZQBuAHQALgAgAEEAbABsACAAcgBpAGcAaAB0AHMAIAByAGUAcwBlAHIAdgBlAGQALgBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABTAHQAZAAgAE0AZQBkAGkAdQBtAFIAZQBnAHUAbABhAHIASABhAG4AeQBpACAAVwBlAEMAaABhAHQAIABTAGEAbgBzACAAUwB0AGQALQBNAGUAZABpAHUAbQA7ACAAVgBlAHIAcwBpAG8AbgAgADEALgAwADAAVwBlAEMAaABhAHQAIABTAGEAbgBzACAAUwB0AGQALQBNAGUAZABpAHUAbQBWAGUAcgBzAGkAbwBuACAAMQAuADAAMABXAGUAQwBoAGEAdAAtAFMAYQBuAHMALQBTAHQAZAAtAE0AZQBkAGkAdQBtAFcAZQBDAGgAYQB0ACAAUwBhAG4AcwAgAGkAcwAgAGEAIAB0AHIAYQBkAGUAbQBhAHIAawAgAG8AZgAgAFQAZQBuAGMAZQBuAHQALgBIAGEAbgB5AGkAIABGAG8AbgB0AHMAWgBIAEEATgBHACAAWAB1AGEAbgAsACAAVwBBAE4ARwAgAFQAaQBhAG4AYgBpACwAIABMAEkAVQAgAFgAaQBhAG8AeQB1AGgAdAB0AHAAOgAvAC8AdwB3AHcALgBoAGEAbgB5AGkALgBjAG8AbQAuAGMAbgAvAFcAZQBDAGgAYQB0ACAAUwBhAG4AcwAgAFMAdABkAE0AZQBkAGkAdQBtIKwAogAkAKMgqQClAAoAMQAyADMANAA1ADYANwA4ADkAMABDAG8AcAB5AHIAaQBnAGgAdAAgACgAYwApACAAMgAwADEANwAgAGIAeQAgAFQAZQBuAGMAZQBuAHQALgAgAEEAbABsACAAcgBpAGcAaAB0AHMAIAByAGUAcwBlAHIAdgBlAGQALgBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABTAHQAZAAgAE0AZQBkAGkAdQBtAFIAZQBnAHUAbABhAHIAVwBlAEMAaABhAHQAIABTAGEAbgBzACAAUwB0AGQALQBNAGUAZABpAHUAbQBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABpAHMAIABhACAAdAByAGEAZABlAG0AYQByAGsAIABvAGYAIABUAGUAbgBjAGUAbgB0AC4ASABhAG4AeQBpACAARgBvAG4AdABzAFoASABBAE4ARwAgAFgAdQBhAG4ALAAgAFcAQQBOAEcAIABUAGkAYQBuAGIAaQAsACAATABJAFUAIABYAGkAYQBvAHkAdQBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABTAHQAZABNAGUAZABpAHUAbQAAAAIAAAAAAAD/tQAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAYwAAAAMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQATABQAFQAWABcAGAAZABoAGwAcAA8AEQAQAQIBAwCEAQQAvQAHAQUBBgEHAQgBCQEKAQsBDAENAQ4BDwEQAREBEgCFARMBFAEVAJYBFgEXARgBGQEaAA4A7wd1bmkwRTNGB3VuaTIwQjUNY29sb25tb25ldGFyeQd1bmlGRTY5BGRvbmcERXVybwd1bmkyMEIyB3VuaTIwQjQHdW5pMjBBRAd1bmkyMEJFB3VuaTIwQkEHdW5pMjBCQwd1bmkyMEE2B3VuaTIwQjEHdW5pMjBCRAd1bmkyMEI5B3VuaTIwQUEHdW5pMjBCOAd1bmkyMEFFB3VuaTIwQTkHdW5pRkZFMAd1bmlGRjA0B3VuaUZGRTEHdW5pRkZFNgd1bmlGRkU1) format("truetype")}.activity_card_wrp .origin_price{font-weight:500;color:#fff;line-height:1;transition:font-size .15s,font-weight .15s,color .15s,-webkit-text-decoration .15s;transition:font-size .15s,font-weight .15s,color .15s,text-decoration .15s;transition:font-size .15s,font-weight .15s,color .15s,text-decoration .15s,-webkit-text-decoration .15s;font-family:WeChatSansStd-Medium;line-height:normal;font-size:15px}@font-face{font-family:WeChatSansStd-Medium;src:url(data:application/octet-stream;base64,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AwYAAwABBAkABAAsA1oAAwABBAkABQAYA4YAAwABBAkABgAsA54AAwABBAkABwBMA8oAAwABBAkACAAWBBYAAwABBAkACQBGBCwAAwABBAkACwAwBHIAAwABBAkAEAAeBKIAAwABBAkAEQAMBMAAAwABBAkAEwAiBMwAAwABCAQAAABmBO4AAwABCAQAAQAsBVQAAwABCAQAAgAOBYAAAwABCAQABAAsBY4AAwABCAQABwBMBboAAwABCAQACAAWBgYAAwABCAQACQBGBhwAAwABCAQAEAAeBmIAAwABCAQAEQAMBoBDb3B5cmlnaHQgKGMpIDIwMTcgYnkgVGVuY2VudC4gQWxsIHJpZ2h0cyByZXNlcnZlZC5XZUNoYXQgU2FucyBTdGRNZWRpdW1IYW55aSBXZUNoYXQgU2FucyBTdGQtTWVkaXVtOyBWZXJzaW9uIDEuMDBXZUNoYXQgU2FucyBTdGQtTWVkaXVtVmVyc2lvbiAxLjAwV2VDaGF0LVNhbnMtU3RkLU1lZGl1bVdlQ2hhdCBTYW5zIGlzIGEgdHJhZGVtYXJrIG9mIFRlbmNlbnQuSGFueWkgRm9udHNaSEFORyBYdWFuLCBXQU5HIFRpYW5iaSwgTElVIFhpYW95dWh0dHA6Ly93d3cuaGFueWkuY29tLmNuL1dlQ2hhdCBTYW5zIFN0ZE1lZGl1bVdlQ2hhdCBTYW5zIFN0ZC1NZWRpdW3boiSjX7QKMTIzNDU2Nzg5MENvcHlyaWdodCAoYykgMjAxNyBieSBUZW5jZW50LiBBbGwgcmlnaHRzIHJlc2VydmVkLldlQ2hhdCBTYW5zIFN0ZE1lZGl1bUhhbnlpIFdlQ2hhdCBTYW5zIFN0ZC1NZWRpdW07IFZlcnNpb24gMS4wMFdlQ2hhdCBTYW5zIFN0ZC1NZWRpdW1WZXJzaW9uIDEuMDBXZUNoYXQtU2Fucy1TdGQtTWVkaXVtV2VDaGF0IFNhbnMgaXMgYSB0cmFkZW1hcmsgb2YgVGVuY2VudC5IYW55aSBGb250c1pIQU5HIFh1YW4sIFdBTkcgVGlhbmJpLCBMSVUgWGlhb3l1V2VDaGF0IFNhbnMgU3RkLU1lZGl1bQBDAG8AcAB5AHIAaQBnAGgAdAAgACgAYwApACAAMgAwADEANwAgAGIAeQAgAFQAZQBuAGMAZQBuAHQALgAgAEEAbABsACAAcgBpAGcAaAB0AHMAIAByAGUAcwBlAHIAdgBlAGQALgBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABTAHQAZAAgAE0AZQBkAGkAdQBtAFIAZQBnAHUAbABhAHIASABhAG4AeQBpACAAVwBlAEMAaABhAHQAIABTAGEAbgBzACAAUwB0AGQALQBNAGUAZABpAHUAbQA7ACAAVgBlAHIAcwBpAG8AbgAgADEALgAwADAAVwBlAEMAaABhAHQAIABTAGEAbgBzACAAUwB0AGQALQBNAGUAZABpAHUAbQBWAGUAcgBzAGkAbwBuACAAMQAuADAAMABXAGUAQwBoAGEAdAAtAFMAYQBuAHMALQBTAHQAZAAtAE0AZQBkAGkAdQBtAFcAZQBDAGgAYQB0ACAAUwBhAG4AcwAgAGkAcwAgAGEAIAB0AHIAYQBkAGUAbQBhAHIAawAgAG8AZgAgAFQAZQBuAGMAZQBuAHQALgBIAGEAbgB5AGkAIABGAG8AbgB0AHMAWgBIAEEATgBHACAAWAB1AGEAbgAsACAAVwBBAE4ARwAgAFQAaQBhAG4AYgBpACwAIABMAEkAVQAgAFgAaQBhAG8AeQB1AGgAdAB0AHAAOgAvAC8AdwB3AHcALgBoAGEAbgB5AGkALgBjAG8AbQAuAGMAbgAvAFcAZQBDAGgAYQB0ACAAUwBhAG4AcwAgAFMAdABkAE0AZQBkAGkAdQBtIKwAogAkAKMgqQClAAoAMQAyADMANAA1ADYANwA4ADkAMABDAG8AcAB5AHIAaQBnAGgAdAAgACgAYwApACAAMgAwADEANwAgAGIAeQAgAFQAZQBuAGMAZQBuAHQALgAgAEEAbABsACAAcgBpAGcAaAB0AHMAIAByAGUAcwBlAHIAdgBlAGQALgBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABTAHQAZAAgAE0AZQBkAGkAdQBtAFIAZQBnAHUAbABhAHIAVwBlAEMAaABhAHQAIABTAGEAbgBzACAAUwB0AGQALQBNAGUAZABpAHUAbQBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABpAHMAIABhACAAdAByAGEAZABlAG0AYQByAGsAIABvAGYAIABUAGUAbgBjAGUAbgB0AC4ASABhAG4AeQBpACAARgBvAG4AdABzAFoASABBAE4ARwAgAFgAdQBhAG4ALAAgAFcAQQBOAEcAIABUAGkAYQBuAGIAaQAsACAATABJAFUAIABYAGkAYQBvAHkAdQBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABTAHQAZABNAGUAZABpAHUAbQAAAAIAAAAAAAD/tQAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAYwAAAAMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQATABQAFQAWABcAGAAZABoAGwAcAA8AEQAQAQIBAwCEAQQAvQAHAQUBBgEHAQgBCQEKAQsBDAENAQ4BDwEQAREBEgCFARMBFAEVAJYBFgEXARgBGQEaAA4A7wd1bmkwRTNGB3VuaTIwQjUNY29sb25tb25ldGFyeQd1bmlGRTY5BGRvbmcERXVybwd1bmkyMEIyB3VuaTIwQjQHdW5pMjBBRAd1bmkyMEJFB3VuaTIwQkEHdW5pMjBCQwd1bmkyMEE2B3VuaTIwQjEHdW5pMjBCRAd1bmkyMEI5B3VuaTIwQUEHdW5pMjBCOAd1bmkyMEFFB3VuaTIwQTkHdW5pRkZFMAd1bmlGRjA0B3VuaUZGRTEHdW5pRkZFNgd1bmlGRkU1) format("truetype")}.activity_card_wrp .origin_price.has_discount{font-weight:400;text-decoration:line-through;-webkit-text-decoration-color:#fff;text-decoration-color:#fff;color:#fff;opacity:.5;font-family:WeChatSansStd-Medium;line-height:normal;font-size:12px}@font-face{font-family:WeChatSansStd-Medium;src:url(data:application/octet-stream;base64,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AwYAAwABBAkABAAsA1oAAwABBAkABQAYA4YAAwABBAkABgAsA54AAwABBAkABwBMA8oAAwABBAkACAAWBBYAAwABBAkACQBGBCwAAwABBAkACwAwBHIAAwABBAkAEAAeBKIAAwABBAkAEQAMBMAAAwABBAkAEwAiBMwAAwABCAQAAABmBO4AAwABCAQAAQAsBVQAAwABCAQAAgAOBYAAAwABCAQABAAsBY4AAwABCAQABwBMBboAAwABCAQACAAWBgYAAwABCAQACQBGBhwAAwABCAQAEAAeBmIAAwABCAQAEQAMBoBDb3B5cmlnaHQgKGMpIDIwMTcgYnkgVGVuY2VudC4gQWxsIHJpZ2h0cyByZXNlcnZlZC5XZUNoYXQgU2FucyBTdGRNZWRpdW1IYW55aSBXZUNoYXQgU2FucyBTdGQtTWVkaXVtOyBWZXJzaW9uIDEuMDBXZUNoYXQgU2FucyBTdGQtTWVkaXVtVmVyc2lvbiAxLjAwV2VDaGF0LVNhbnMtU3RkLU1lZGl1bVdlQ2hhdCBTYW5zIGlzIGEgdHJhZGVtYXJrIG9mIFRlbmNlbnQuSGFueWkgRm9udHNaSEFORyBYdWFuLCBXQU5HIFRpYW5iaSwgTElVIFhpYW95dWh0dHA6Ly93d3cuaGFueWkuY29tLmNuL1dlQ2hhdCBTYW5zIFN0ZE1lZGl1bVdlQ2hhdCBTYW5zIFN0ZC1NZWRpdW3boiSjX7QKMTIzNDU2Nzg5MENvcHlyaWdodCAoYykgMjAxNyBieSBUZW5jZW50LiBBbGwgcmlnaHRzIHJlc2VydmVkLldlQ2hhdCBTYW5zIFN0ZE1lZGl1bUhhbnlpIFdlQ2hhdCBTYW5zIFN0ZC1NZWRpdW07IFZlcnNpb24gMS4wMFdlQ2hhdCBTYW5zIFN0ZC1NZWRpdW1WZXJzaW9uIDEuMDBXZUNoYXQtU2Fucy1TdGQtTWVkaXVtV2VDaGF0IFNhbnMgaXMgYSB0cmFkZW1hcmsgb2YgVGVuY2VudC5IYW55aSBGb250c1pIQU5HIFh1YW4sIFdBTkcgVGlhbmJpLCBMSVUgWGlhb3l1V2VDaGF0IFNhbnMgU3RkLU1lZGl1bQBDAG8AcAB5AHIAaQBnAGgAdAAgACgAYwApACAAMgAwADEANwAgAGIAeQAgAFQAZQBuAGMAZQBuAHQALgAgAEEAbABsACAAcgBpAGcAaAB0AHMAIAByAGUAcwBlAHIAdgBlAGQALgBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABTAHQAZAAgAE0AZQBkAGkAdQBtAFIAZQBnAHUAbABhAHIASABhAG4AeQBpACAAVwBlAEMAaABhAHQAIABTAGEAbgBzACAAUwB0AGQALQBNAGUAZABpAHUAbQA7ACAAVgBlAHIAcwBpAG8AbgAgADEALgAwADAAVwBlAEMAaABhAHQAIABTAGEAbgBzACAAUwB0AGQALQBNAGUAZABpAHUAbQBWAGUAcgBzAGkAbwBuACAAMQAuADAAMABXAGUAQwBoAGEAdAAtAFMAYQBuAHMALQBTAHQAZAAtAE0AZQBkAGkAdQBtAFcAZQBDAGgAYQB0ACAAUwBhAG4AcwAgAGkAcwAgAGEAIAB0AHIAYQBkAGUAbQBhAHIAawAgAG8AZgAgAFQAZQBuAGMAZQBuAHQALgBIAGEAbgB5AGkAIABGAG8AbgB0AHMAWgBIAEEATgBHACAAWAB1AGEAbgAsACAAVwBBAE4ARwAgAFQAaQBhAG4AYgBpACwAIABMAEkAVQAgAFgAaQBhAG8AeQB1AGgAdAB0AHAAOgAvAC8AdwB3AHcALgBoAGEAbgB5AGkALgBjAG8AbQAuAGMAbgAvAFcAZQBDAGgAYQB0ACAAUwBhAG4AcwAgAFMAdABkAE0AZQBkAGkAdQBtIKwAogAkAKMgqQClAAoAMQAyADMANAA1ADYANwA4ADkAMABDAG8AcAB5AHIAaQBnAGgAdAAgACgAYwApACAAMgAwADEANwAgAGIAeQAgAFQAZQBuAGMAZQBuAHQALgAgAEEAbABsACAAcgBpAGcAaAB0AHMAIAByAGUAcwBlAHIAdgBlAGQALgBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABTAHQAZAAgAE0AZQBkAGkAdQBtAFIAZQBnAHUAbABhAHIAVwBlAEMAaABhAHQAIABTAGEAbgBzACAAUwB0AGQALQBNAGUAZABpAHUAbQBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABpAHMAIABhACAAdAByAGEAZABlAG0AYQByAGsAIABvAGYAIABUAGUAbgBjAGUAbgB0AC4ASABhAG4AeQBpACAARgBvAG4AdABzAFoASABBAE4ARwAgAFgAdQBhAG4ALAAgAFcAQQBOAEcAIABUAGkAYQBuAGIAaQAsACAATABJAFUAIABYAGkAYQBvAHkAdQBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABTAHQAZABNAGUAZABpAHUAbQAAAAIAAAAAAAD/tQAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAYwAAAAMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQATABQAFQAWABcAGAAZABoAGwAcAA8AEQAQAQIBAwCEAQQAvQAHAQUBBgEHAQgBCQEKAQsBDAENAQ4BDwEQAREBEgCFARMBFAEVAJYBFgEXARgBGQEaAA4A7wd1bmkwRTNGB3VuaTIwQjUNY29sb25tb25ldGFyeQd1bmlGRTY5BGRvbmcERXVybwd1bmkyMEIyB3VuaTIwQjQHdW5pMjBBRAd1bmkyMEJFB3VuaTIwQkEHdW5pMjBCQwd1bmkyMEE2B3VuaTIwQjEHdW5pMjBCRAd1bmkyMEI5B3VuaTIwQUEHdW5pMjBCOAd1bmkyMEFFB3VuaTIwQTkHdW5pRkZFMAd1bmlGRjA0B3VuaUZGRTEHdW5pRkZFNgd1bmlGRkU1) format("truetype")}.s1s_card_wrp{font-family:PingFang SC;display:flex;align-items:center}.s1s_card_wrp .product-image{width:64px;height:64px;border-radius:2px;margin-right:12px}.s1s_card_wrp .product-info{flex:1;width:200px;line-height:1}.s1s_card_wrp .product-title{color:var(--weui-FG-0);font-size:15px;width:100%;font-weight:400;margin-bottom:5px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.s1s_card_wrp .product-price{color:var(--weui-ORANGERED-100);font-family:WeChatSansStd-Medium;line-height:normal;font-size:15px}@font-face{font-family:WeChatSansStd-Medium;src:url(data:application/octet-stream;base64,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AwYAAwABBAkABAAsA1oAAwABBAkABQAYA4YAAwABBAkABgAsA54AAwABBAkABwBMA8oAAwABBAkACAAWBBYAAwABBAkACQBGBCwAAwABBAkACwAwBHIAAwABBAkAEAAeBKIAAwABBAkAEQAMBMAAAwABBAkAEwAiBMwAAwABCAQAAABmBO4AAwABCAQAAQAsBVQAAwABCAQAAgAOBYAAAwABCAQABAAsBY4AAwABCAQABwBMBboAAwABCAQACAAWBgYAAwABCAQACQBGBhwAAwABCAQAEAAeBmIAAwABCAQAEQAMBoBDb3B5cmlnaHQgKGMpIDIwMTcgYnkgVGVuY2VudC4gQWxsIHJpZ2h0cyByZXNlcnZlZC5XZUNoYXQgU2FucyBTdGRNZWRpdW1IYW55aSBXZUNoYXQgU2FucyBTdGQtTWVkaXVtOyBWZXJzaW9uIDEuMDBXZUNoYXQgU2FucyBTdGQtTWVkaXVtVmVyc2lvbiAxLjAwV2VDaGF0LVNhbnMtU3RkLU1lZGl1bVdlQ2hhdCBTYW5zIGlzIGEgdHJhZGVtYXJrIG9mIFRlbmNlbnQuSGFueWkgRm9udHNaSEFORyBYdWFuLCBXQU5HIFRpYW5iaSwgTElVIFhpYW95dWh0dHA6Ly93d3cuaGFueWkuY29tLmNuL1dlQ2hhdCBTYW5zIFN0ZE1lZGl1bVdlQ2hhdCBTYW5zIFN0ZC1NZWRpdW3boiSjX7QKMTIzNDU2Nzg5MENvcHlyaWdodCAoYykgMjAxNyBieSBUZW5jZW50LiBBbGwgcmlnaHRzIHJlc2VydmVkLldlQ2hhdCBTYW5zIFN0ZE1lZGl1bUhhbnlpIFdlQ2hhdCBTYW5zIFN0ZC1NZWRpdW07IFZlcnNpb24gMS4wMFdlQ2hhdCBTYW5zIFN0ZC1NZWRpdW1WZXJzaW9uIDEuMDBXZUNoYXQtU2Fucy1TdGQtTWVkaXVtV2VDaGF0IFNhbnMgaXMgYSB0cmFkZW1hcmsgb2YgVGVuY2VudC5IYW55aSBGb250c1pIQU5HIFh1YW4sIFdBTkcgVGlhbmJpLCBMSVUgWGlhb3l1V2VDaGF0IFNhbnMgU3RkLU1lZGl1bQBDAG8AcAB5AHIAaQBnAGgAdAAgACgAYwApACAAMgAwADEANwAgAGIAeQAgAFQAZQBuAGMAZQBuAHQALgAgAEEAbABsACAAcgBpAGcAaAB0AHMAIAByAGUAcwBlAHIAdgBlAGQALgBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABTAHQAZAAgAE0AZQBkAGkAdQBtAFIAZQBnAHUAbABhAHIASABhAG4AeQBpACAAVwBlAEMAaABhAHQAIABTAGEAbgBzACAAUwB0AGQALQBNAGUAZABpAHUAbQA7ACAAVgBlAHIAcwBpAG8AbgAgADEALgAwADAAVwBlAEMAaABhAHQAIABTAGEAbgBzACAAUwB0AGQALQBNAGUAZABpAHUAbQBWAGUAcgBzAGkAbwBuACAAMQAuADAAMABXAGUAQwBoAGEAdAAtAFMAYQBuAHMALQBTAHQAZAAtAE0AZQBkAGkAdQBtAFcAZQBDAGgAYQB0ACAAUwBhAG4AcwAgAGkAcwAgAGEAIAB0AHIAYQBkAGUAbQBhAHIAawAgAG8AZgAgAFQAZQBuAGMAZQBuAHQALgBIAGEAbgB5AGkAIABGAG8AbgB0AHMAWgBIAEEATgBHACAAWAB1AGEAbgAsACAAVwBBAE4ARwAgAFQAaQBhAG4AYgBpACwAIABMAEkAVQAgAFgAaQBhAG8AeQB1AGgAdAB0AHAAOgAvAC8AdwB3AHcALgBoAGEAbgB5AGkALgBjAG8AbQAuAGMAbgAvAFcAZQBDAGgAYQB0ACAAUwBhAG4AcwAgAFMAdABkAE0AZQBkAGkAdQBtIKwAogAkAKMgqQClAAoAMQAyADMANAA1ADYANwA4ADkAMABDAG8AcAB5AHIAaQBnAGgAdAAgACgAYwApACAAMgAwADEANwAgAGIAeQAgAFQAZQBuAGMAZQBuAHQALgAgAEEAbABsACAAcgBpAGcAaAB0AHMAIAByAGUAcwBlAHIAdgBlAGQALgBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABTAHQAZAAgAE0AZQBkAGkAdQBtAFIAZQBnAHUAbABhAHIAVwBlAEMAaABhAHQAIABTAGEAbgBzACAAUwB0AGQALQBNAGUAZABpAHUAbQBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABpAHMAIABhACAAdAByAGEAZABlAG0AYQByAGsAIABvAGYAIABUAGUAbgBjAGUAbgB0AC4ASABhAG4AeQBpACAARgBvAG4AdABzAFoASABBAE4ARwAgAFgAdQBhAG4ALAAgAFcAQQBOAEcAIABUAGkAYQBuAGIAaQAsACAATABJAFUAIABYAGkAYQBvAHkAdQBXAGUAQwBoAGEAdAAgAFMAYQBuAHMAIABTAHQAZABNAGUAZABpAHUAbQAAAAIAAAAAAAD/tQAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAYwAAAAMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsAPAA9AEQARQBGAEcASABJAEoASwBMAE0ATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQATABQAFQAWABcAGAAZABoAGwAcAA8AEQAQAQIBAwCEAQQAvQAHAQUBBgEHAQgBCQEKAQsBDAENAQ4BDwEQAREBEgCFARMBFAEVAJYBFgEXARgBGQEaAA4A7wd1bmkwRTNGB3VuaTIwQjUNY29sb25tb25ldGFyeQd1bmlGRTY5BGRvbmcERXVybwd1bmkyMEIyB3VuaTIwQjQHdW5pMjBBRAd1bmkyMEJFB3VuaTIwQkEHdW5pMjBCQwd1bmkyMEE2B3VuaTIwQjEHdW5pMjBCRAd1bmkyMEI5B3VuaTIwQUEHdW5pMjBCOAd1bmkyMEFFB3VuaTIwQTkHdW5pRkZFMAd1bmlGRjA0B3VuaUZGRTEHdW5pRkZFNgd1bmlGRkU1) format("truetype")}.s1s_card_wrp .product-brand{color:var(--weui-FG-1);font-size:12px;display:flex;align-items:center}.s1s_card_wrp .product-brand .product-logo{margin-right:2px}.s1s_card_wrp .product-brand .shop-verify-icon{font-size:14px;margin-left:2px;position:relative;top:-.03em}.s1s_card_wrp .product-centercontainer{display:flex;align-items:center;margin-bottom:5px}.s1s_card_wrp .product-gifts{color:var(--weui-FG-2);font-size:12px;margin-left:4px}.s1s_card_wrp .product-gifts .product-gifts__num{margin:0 1px} `, R = { windowproduct: "data-windowproduct", customstyle: "data-customstyle", ecsource: "data-ecsource", exportkey: "data-exportkey", wap_export_token: "data-wap_export_token", loaded: "data-loaded", cardtype: "data-cardtype", is_hover: "data-is-hover", is_selected: "data-is-selected", token: "data-token", title: "data-title", immutable: "data-immutable", req_scene: "data-req-scene", urlParams: "data-url-params", extInfo: "data-ext-info", scrollBlur: "data-scroll-blur", wrpStyle: "data-wrp-style", type: "data-type", productImage: "data-product-image", originPrice: "data-origin-price", discountedPrice: "data-discounted-price", outerclick: "data-outerclick", productInfo: "data-product-info" }; function V(B, A = {}) { let E = {}; return E = o$1.call(this, R), E.loaded = Number(E.loaded || 0), E.cardtype = Number(E.cardtype || 0), E.is_hover = Number(E.is_hover || 0), E.is_selected = Number(E.is_selected || 0), E.immutable = Number(E.immutable || 0), E.req_scene = Number(E.req_scene || 0), E.urlParams = JSON.parse(E.urlParams || "{}"), E.extInfo = JSON.parse(E.extInfo || "{}"), E.productInfo = JSON.parse(E.productInfo || "{}"), E.scrollBlur = Number(E.scrollBlur || 0), E.originPrice = Number(E.originPrice || 0), E.discountedPrice = Number(E.discountedPrice || 0), E.outerclick = Number(E.outerclick || 0), { platform: B, extraInfo: A, ...E }; } function b(B) { k( Object.assign(B, { Component: B.isDev ? B.devComponent : j, styleText: B.isDev ? B.devStyleText : m, customName: B.customName || "mp-common-product", watchAttr: Object.values(R), getProps: V, eventName: ["iframe-message", "document-click", "expose", "element-click"] }) ); } var C = function() { var A = this, E = A._self._c; return E("section", { ref: "js_custom_element", staticClass: "wx-root red_package_cover_wrp", class: [{ disabled: A.disabled, small: A.smallCard }, A.platformClassname], attrs: { role: "option" } }, [E("section", { staticClass: "red_package_cover__inner wx_tap_card wx_card_root", class: [A.is_hover === 1 ? "wx_hover_card" : "", A.is_selected === 1 ? "wx_selected_card" : ""] }, [E("section", { staticClass: "red_package_cover__inner__main" }, [E("section", { staticClass: "red_package_cover__body" }, [A.openImgSrc ? E("span", { staticClass: "red_package_cover_img red_package_open_cover_img", style: { "background-image": `url(${A.openImgSrc})`, width: A.smallCard ? "" : A.openImgWidth, height: A.smallCard ? "" : A.openImgHeight }, attrs: { "data-notusecover": "1" } }) : E("span", { staticClass: "red_package_cover_img", class: { synthetic_cover_img: A.isSynthetic === 1 }, style: "background-image: url(" + A.imgSrc + ")", attrs: { "data-notusecover": "1" } }), A._v(" "), A.smallCard ? E("span", { staticClass: "title-wrp" }, [E("span", { staticClass: "title" }, [A._v(A._s(A.name) + '红包封面')]), A._v(" "), A.isPurchaseOrder === 1 ? E("span", { staticClass: "red_package_cover__purchase" }, [A._v('付费')]) : A._e()]) : A._e()]), A._v(" "), E("section", { staticClass: "red_package_cover__foot" }, [A.smallCard ? [A.status === 0 ? E("span", { staticClass: "weui-btn weui-btn_mini red_package_cover__access-link button" }, [A._v('领取')]) : A.status === 1 ? E("span", { staticClass: "red_package_cover__access-link correct disabled" }, [A._v('已领取')]) : A.status === 2 ? E("span", { staticClass: "red_package_cover__access-link disabled" }, [A._v('已领完')]) : A.status === 3 ? E("span", { staticClass: "red_package_cover__access-link disabled" }, [A._v('不可领取')]) : A._e()] : A.platform !== "wechat" ? [A.disabled ? E("span", { staticClass: "red_package_cover__access-link disabled" }, [A._v('红包封面不可用')]) : E("span", { staticClass: "red_package_cover__access-link" }, [A._v('领取' + A._s(A.name) + '红包封面')])] : [A.status === 0 ? E("span", { staticClass: "red_package_cover__access-link" }, [A._v('领取' + A._s(A.name) + '红包封面')]) : A.status === 1 ? E("span", { staticClass: "red_package_cover__access-link disabled" }, [A._v('已领取红包封面')]) : A.status === 2 ? E("span", { staticClass: "red_package_cover__access-link disabled" }, [A._v('红包封面已领取完')]) : A.status === 3 ? E("span", { staticClass: "red_package_cover__access-link disabled" }, [A._v('红包封面不可领取')]) : A._e()], A._v(" "), A.isPurchaseOrder === 1 && !A.smallCard ? E("section", { staticClass: "red_package_cover__purchase" }, [A._v('付费')]) : A._e()], 2)]), A._v(" "), A._m(0), A._v(" "), A.platform !== "wechat" && A.disabled ? E("section", { staticClass: "red_package_cover_disable_wording" }, [A._v('红包封面不可用')]) : A._e()])]); }, w = [function() { var g = this, A = g._self._c; return A("section", { staticClass: "red_package_cover__extend" }, [A("span", { staticClass: "red_package_cover__extend_icon" }), g._v(" "), A("span", { staticClass: "red_package_cover__extend_info" }, [g._v('微信红包封面')])]); }]; function a(g) { var A = typeof g == "function" ? g.options : g; return C && (A.render = C, A.staticRenderFns = w, A._compiled = !0), { exports: g, options: A }; } const r = { name: "mp-common-redpacket", template: a, mixins: [j$1], props: { errType: { type: String, default: "" }, is_hover: { type: Number, default: 0 }, is_selected: { type: Number, default: 0 }, name: { type: String, default: "" }, isSynthetic: { type: Number, default: 0 }, imgSrc: { type: String, default: "" }, openImgSrc: { type: String, default: "" }, status: { type: Number, default: 3 }, bizuin: { type: String, default: "" }, coveruri: { type: String, default: "" }, orderid: { type: String, default: "" }, isPurchaseOrder: { type: Number, default: 0 }, smallCard: { type: Number, default: 0 } }, data() { return { platformClassname: { web: "common-redpacket-web", app: "common-redpacket-app", wechat: "common-redpacket-webchat" }[this.platform], openImgWidth: "62.33%", openImgHeight: "108%" }; }, methods: { handleClick() { this.$emit("click"); }, calOpenImgWidth() { if (!this.openImgSrc) return; const g = new Image(); g.onload = () => { this.openImgWidth = `${(g.width / g.height * 108).toFixed(2)}%`; }, g.src = decodeURIComponent(this.openImgSrc); } }, computed: { disabled() { return this.errType * 1 > 0; } }, watch: { openImgSrc: function() { this.calOpenImgWidth(); } }, mounted() { this.calOpenImgWidth(); } }, t = `.wx-root,body{--weui-BG-COLOR-ACTIVE: #ececec}.wx-root[data-weui-theme=dark],body[data-weui-theme=dark]{--weui-BG-COLOR-ACTIVE: #373737}@media (prefers-color-scheme: dark){.wx-root:not([data-weui-theme=light]),body:not([data-weui-theme=light]){--weui-BG-COLOR-ACTIVE: #373737}}body,.wx-root,page{--weui-BTN-HEIGHT: 48;--weui-BTN-HEIGHT-MEDIUM: 40;--weui-BTN-HEIGHT-SMALL: 32}.wx-root,body{--weui-BTN-ACTIVE-MASK: rgba(0, 0, 0, .1)}.wx-root[data-weui-theme=dark],body[data-weui-theme=dark]{--weui-BTN-ACTIVE-MASK: rgba(255, 255, 255, .1)}@media (prefers-color-scheme: dark){.wx-root:not([data-weui-theme=light]),body:not([data-weui-theme=light]){--weui-BTN-ACTIVE-MASK: rgba(255, 255, 255, .1)}}.wx-root,body{--weui-BTN-DEFAULT-ACTIVE-BG: #e6e6e6}.wx-root[data-weui-theme=dark],body[data-weui-theme=dark]{--weui-BTN-DEFAULT-ACTIVE-BG: rgba(255, 255, 255, .126)}@media (prefers-color-scheme: dark){.wx-root:not([data-weui-theme=light]),body:not([data-weui-theme=light]){--weui-BTN-DEFAULT-ACTIVE-BG: rgba(255, 255, 255, .126)}}.wx-root,body{--weui-DIALOG-LINE-COLOR: rgba(0, 0, 0, .1)}.wx-root[data-weui-theme=dark],body[data-weui-theme=dark]{--weui-DIALOG-LINE-COLOR: rgba(255, 255, 255, .1)}@media (prefers-color-scheme: dark){.wx-root:not([data-weui-theme=light]),body:not([data-weui-theme=light]){--weui-DIALOG-LINE-COLOR: rgba(255, 255, 255, .1)}}.weui-btn{position:relative;display:block;width:184px;margin-left:auto;margin-right:auto;padding:12px 24px;box-sizing:border-box;font-weight:500;font-size:17px;text-align:center;text-decoration:none;color:#fff;line-height:1.41176471;border-radius:8px;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-user-select:none;-moz-user-select:none;user-select:none}.weui-btn:active:before{content:"";position:absolute;top:0;left:0;width:100%;height:100%;background-color:var(--weui-BTN-ACTIVE-MASK);border-radius:8px}.weui-btn:active.weui-btn_loading:before,.weui-btn:active.weui-btn_disabled:before,.weui-btn:active[disabled]:before{display:none}.weui-btn_block{width:auto}.weui-btn_inline{display:inline-block}.weui-btn_default{color:var(--weui-FG-0);background-color:var(--weui-FG-5)}.weui-btn_default:not(.weui-btn_disabled):visited{color:var(--weui-FG-0)}.weui-btn_primary{background-color:var(--weui-BRAND)}.weui-btn_primary:not(.weui-btn_disabled):visited{color:#fff}.weui-btn_warn{color:var(--weui-RED);background-color:var(--weui-FG-5)}.weui-btn_warn:not(.weui-btn_disabled):visited{color:var(--weui-RED)}.weui-btn_overlay{color:var(--weui-BRAND);background-color:#fff}.weui-btn_overlay:not(.weui-btn_disabled):visited{color:var(--weui-BRAND)}.weui-btn_disabled,.weui-btn[disabled]{color:var(--weui-FG-4);background-color:var(--weui-BG-1)}.weui-btn_loading .weui-loading{margin:-.2em 8px 0 0}.weui-btn_loading .weui-mask-loading{margin:-.2em 8px 0 0;color:currentColor}.weui-btn_loading .weui-primary-loading{margin:-.2em 8px 0 0;vertical-align:middle;color:currentColor}.weui-btn_loading .weui-primary-loading:before{content:""}.weui-btn_loading.weui-btn_primary{color:var(--weui-WHITE)}.weui-btn_cell{position:relative;display:block;margin-left:auto;margin-right:auto;box-sizing:border-box;font-size:17px;text-align:center;text-decoration:none;color:#fff;line-height:1.41176471;padding:16px;-webkit-tap-highlight-color:rgba(0,0,0,0);overflow:hidden;background-color:var(--weui-BG-5)}.weui-btn_cell+.weui-btn_cell{margin-top:16px}.weui-btn_cell:active{background-color:var(--weui-BG-COLOR-ACTIVE)}.weui-btn_cell__icon{display:inline-block;vertical-align:middle;width:24px;height:24px;margin:-.2em .34em 0 0}.weui-btn_cell-default{color:var(--weui-FG-0)}.weui-btn_cell-primary{color:var(--weui-LINK)}.weui-btn_cell-warn{color:var(--weui-RED)}.weui-bottom-fixed-opr-page{height:100%;display:flex;flex-direction:column}.weui-bottom-fixed-opr-page__content{min-height:0;flex:1;padding-bottom:80px;box-sizing:border-box;overflow-y:auto;-webkit-overflow-scrolling:touch}.weui-bottom-fixed-opr-page__tool{padding:16px 32px 24px;padding:16px calc(32px + constant(safe-area-inset-right)) calc(24px + constant(safe-area-inset-bottom)) calc(32px + constant(safe-area-inset-left));padding:16px calc(32px + env(safe-area-inset-right)) calc(24px + env(safe-area-inset-bottom)) calc(32px + env(safe-area-inset-left));background:#ffffff;position:relative;z-index:50}.weui-bottom-fixed-opr-page__tool:before{content:"";height:80px;background:linear-gradient(to top,#ffffff,rgba(255,255,255,0));position:absolute;bottom:calc(100% - 1px);left:0;right:0;transform:translateZ(0);pointer-events:none}.wx-root[data-weui-theme=dark] .weui-bottom-fixed-opr-page__tool,body[data-weui-theme=dark] .weui-bottom-fixed-opr-page__tool{background:#191919}@media (prefers-color-scheme: dark){.wx-root:not([data-weui-theme=light]) .weui-bottom-fixed-opr-page__tool,body:not([data-weui-theme=light]) .weui-bottom-fixed-opr-page__tool{background:#191919}}.wx-root[data-weui-theme=dark] .weui-bottom-fixed-opr-page__tool:before,body[data-weui-theme=dark] .weui-bottom-fixed-opr-page__tool:before{background:linear-gradient(to top,#191919,rgba(25,25,25,0))}@media (prefers-color-scheme: dark){.wx-root:not([data-weui-theme=light]) .weui-bottom-fixed-opr-page__tool:before,body:not([data-weui-theme=light]) .weui-bottom-fixed-opr-page__tool:before{background:linear-gradient(to top,#191919,rgba(25,25,25,0))}}.weui-bottom-fixed-opr-page__tips{margin-bottom:24px;padding:0 32px;text-align:center}.weui-bottom-fixed-opr-page .weui-bottom-fixed-opr{display:flex;align-items:center;justify-content:center}.weui-bottom-fixed-opr-page .weui-bottom-fixed-opr .weui-btn{width:184px;padding-left:16px;padding-right:16px}.weui-bottom-fixed-opr-page .weui-bottom-fixed-opr .weui-btn:nth-last-child(n+2),.weui-bottom-fixed-opr-page .weui-bottom-fixed-opr .weui-btn:nth-last-child(n+2)+.weui-btn{margin:0 8px;width:136px}.weui-bottom-fixed-opr-page .weui-bottom-fixed-opr .weui-btn:nth-last-child(n+2):first-child,.weui-bottom-fixed-opr-page .weui-bottom-fixed-opr .weui-btn:nth-last-child(n+2)+.weui-btn:first-child{margin-left:0}.weui-bottom-fixed-opr-page .weui-bottom-fixed-opr .weui-btn:nth-last-child(n+2):last-child,.weui-bottom-fixed-opr-page .weui-bottom-fixed-opr .weui-btn:nth-last-child(n+2)+.weui-btn:last-child{margin-right:0}.weui-bottom-fixed-opr-page_btn-wrap .weui-bottom-fixed-opr{flex-direction:column}.weui-bottom-fixed-opr-page_btn-wrap .weui-bottom-fixed-opr .weui-btn:nth-last-child(n+2),.weui-bottom-fixed-opr-page_btn-wrap .weui-bottom-fixed-opr .weui-btn:nth-last-child(n+2)+.weui-btn{width:184px;margin:16px 0 0}.weui-bottom-fixed-opr-page_btn-wrap .weui-bottom-fixed-opr .weui-btn:nth-last-child(n+2):first-child,.weui-bottom-fixed-opr-page_btn-wrap .weui-bottom-fixed-opr .weui-btn:nth-last-child(n+2)+.weui-btn:first-child{margin-top:0}.weui-bottom-fixed-opr-page.weui-form{padding-top:0}.weui-bottom-fixed-opr-page.weui-form .weui-form__bd{padding-top:56px;padding-top:calc(56px + constant(safe-area-inset-top));padding-top:calc(56px + env(safe-area-inset-top))}.weui-bottom-fixed-opr-page.weui-form .weui-form__ft{padding-bottom:0}.weui-bottom-fixed-opr-page.weui-form .weui-form__control-area{margin-bottom:0}.weui-bottom-fixed-opr-page.weui-half-screen-dialog{padding:0}.weui-bottom-fixed-opr-page.weui-half-screen-dialog .weui-half-screen-dialog__hd,.weui-bottom-fixed-opr-page.weui-half-screen-dialog .weui-half-screen-dialog__bd,.weui-bottom-fixed-opr-page.weui-half-screen-dialog .weui-half-screen-dialog__ft{padding-left:24px;padding-left:calc(24px + constant(safe-area-inset-left));padding-left:calc(24px + env(safe-area-inset-left));padding-right:24px;padding-right:calc(24px + constant(safe-area-inset-right));padding-right:calc(24px + env(safe-area-inset-right))}.weui-bottom-fixed-opr-page.weui-half-screen-dialog .weui-half-screen-dialog__bd{padding-bottom:80px}.weui-bottom-fixed-opr-page.weui-half-screen-dialog .weui-half-screen-dialog__ft{padding-bottom:64px;padding-bottom:calc(64px + constant(safe-area-inset-bottom));padding-bottom:calc(64px + env(safe-area-inset-bottom))}.weui-half-screen-dialog_bottom-fixed.weui-half-screen-dialog{padding:0}.weui-half-screen-dialog_bottom-fixed.weui-half-screen-dialog .weui-half-screen-dialog__hd{padding:0 24px;padding:0 calc(24px + constant(safe-area-inset-right)) 0 calc(24px + constant(safe-area-inset-left));padding:0 calc(24px + env(safe-area-inset-right)) 0 calc(24px + env(safe-area-inset-left))}.weui-half-screen-dialog_bottom-fixed.weui-half-screen-dialog .weui-half-screen-dialog__bd{padding-bottom:0;display:flex;flex-direction:column}.weui-half-screen-dialog_bottom-fixed.weui-half-screen-dialog .weui-half-screen-dialog__ft{padding:0}.weui-half-screen-dialog_bottom-fixed.weui-half-screen-dialog .weui-bottom-fixed-opr-page{flex:1;min-height:0}.weui-half-screen-dialog_bottom-fixed.weui-half-screen-dialog .weui-bottom-fixed-opr-page__content{padding:0 24px;padding:0 calc(24px + constant(safe-area-inset-right)) 0 calc(24px + constant(safe-area-inset-left));padding:0 calc(24px + env(safe-area-inset-right)) 0 calc(24px + env(safe-area-inset-left))}.weui-half-screen-dialog_bottom-fixed.weui-half-screen-dialog .weui-bottom-fixed-opr{padding:16px 0 64px;padding:16px 0 calc(64px + constant(safe-area-inset-bottom));padding:16px 0 calc(64px + env(safe-area-inset-bottom))}button.weui-btn,input.weui-btn{border-width:0;outline:0;-webkit-appearance:none}button.weui-btn:focus,input.weui-btn:focus{outline:0}button.weui-btn_inline,input.weui-btn_inline,button.weui-btn_mini,input.weui-btn_mini{width:auto}.weui-btn_medium{font-size:14px;padding:10px 24px;line-height:calc((var(--weui-BTN-HEIGHT-MEDIUM) - 20) / 14)}.weui-btn_mini{display:inline-block;width:auto;line-height:calc((32 - 12) / 14);padding:6px 12px;font-size:14px;border-radius:6px}.weui-btn_xmini{display:inline-block;width:auto;padding:4px 12px;line-height:calc((28 - 8) / 14);font-size:14px;font-weight:500;border-radius:4px}.weui-btn+.weui-btn{margin-top:16px}.weui-btn.weui-btn_mini+.weui-btn.weui-btn_mini{margin-top:auto}.weui-btn.weui-btn_xmini+.weui-btn.weui-btn_xmini{margin-top:auto}.weui-btn.weui-btn_inline+.weui-btn.weui-btn_inline{margin-left:16px}.weui-btn-area{margin:48px 16px 8px}.weui-btn-area_inline{display:flex}.weui-btn-area_inline .weui-btn{margin-top:auto;margin-right:16px;width:100%;flex:1}.weui-btn-area_inline .weui-btn:last-child{margin-right:0}.weui-btn_reset{background:transparent;border:0;padding:0;outline:0;font-size:inherit}.weui-btn_icon{background:transparent;border:0;padding:0;outline:0;font-size:0}.weui-btn_icon:active [class*=weui-icon-]{color:var(--weui-FG-1)}body,.wx-root{--weui-BG-0: #ededed;--weui-BG-1: #f7f7f7;--weui-BG-2: #fff;--weui-BG-3: #f7f7f7;--weui-BG-4: #4c4c4c;--weui-BG-5: #fff;--weui-RED: #fa5151;--weui-ORANGERED: #ff6146;--weui-ORANGE: #fa9d3b;--weui-YELLOW: #ffc300;--weui-GREEN: #91d300;--weui-LIGHTGREEN: #95ec69;--weui-BRAND: #07c160;--weui-BLUE: #10aeff;--weui-INDIGO: #1485ee;--weui-PURPLE: #6467f0;--weui-WHITE: #fff;--weui-LINK: #576b95;--weui-TEXTGREEN: #06ae56;--weui-BG: #fff;--weui-TAG-TEXT-ORANGE: #fa9d3b;--weui-TAG-TEXT-GREEN: #06ae56;--weui-TAG-TEXT-BLUE: #10aeff;--weui-REDORANGE: #ff6146;--weui-BG-0: #EDEDED;--weui-BG-1: #F7F7F7;--weui-BG-2: #FFFFFF;--weui-BG-3: #F7F7F7;--weui-BG-4: #4C4C4C;--weui-BG-5: #FFFFFF;--weui-BLUE-100: #10AEFF;--weui-BLUE-120: #3FBEFF;--weui-BLUE-170: #B7E6FF;--weui-BLUE-80: #0C8BCC;--weui-BLUE-90: #0E9CE6;--weui-BLUE-BG-100: #48A6E2;--weui-BLUE-BG-110: #5AAFE4;--weui-BLUE-BG-130: #7FC0EA;--weui-BLUE-BG-90: #4095CB;--weui-BRAND-100: #07C160;--weui-BRAND-120: #38CD7F;--weui-BRAND-170: #B4ECCE;--weui-BRAND-80: #059A4C;--weui-BRAND-90: #06AE56;--weui-BRAND-BG-100: #2AAE67;--weui-BRAND-BG-110: #3EB575;--weui-BRAND-BG-130: #69C694;--weui-BRAND-BG-90: #259C5C;--weui-FG-0: rgba(0, 0, 0, .9);--weui-FG-0_5: rgba(0, 0, 0, .9);--weui-FG-1: rgba(0, 0, 0, .55);--weui-FG-2: rgba(0, 0, 0, .3);--weui-FG-3: rgba(0, 0, 0, .1);--weui-FG-4: rgba(0, 0, 0, .15);--weui-GLYPH-0: rgba(0, 0, 0, .9);--weui-GLYPH-1: rgba(0, 0, 0, .55);--weui-GLYPH-2: rgba(0, 0, 0, .3);--weui-GLYPH-WHITE-0: rgba(255, 255, 255, .8);--weui-GLYPH-WHITE-1: rgba(255, 255, 255, .5);--weui-GLYPH-WHITE-2: rgba(255, 255, 255, .3);--weui-GLYPH-WHITE-3: #FFFFFF;--weui-GREEN-100: #91D300;--weui-GREEN-120: #A7DB33;--weui-GREEN-170: #DEF1B3;--weui-GREEN-80: #74A800;--weui-GREEN-90: #82BD00;--weui-GREEN-BG-100: #96BE40;--weui-GREEN-BG-110: #A0C452;--weui-GREEN-BG-130: #B5D179;--weui-GREEN-BG-90: #86AA39;--weui-INDIGO-100: #1485EE;--weui-INDIGO-120: #439DF1;--weui-INDIGO-170: #B8DAF9;--weui-INDIGO-80: #106ABE;--weui-INDIGO-90: #1277D6;--weui-INDIGO-BG-100: #2B77BF;--weui-INDIGO-BG-110: #3F84C5;--weui-INDIGO-BG-130: #6BA0D2;--weui-INDIGO-BG-90: #266AAB;--weui-LIGHTGREEN-100: #95EC69;--weui-LIGHTGREEN-120: #AAEF87;--weui-LIGHTGREEN-170: #DEF9D1;--weui-LIGHTGREEN-80: #77BC54;--weui-LIGHTGREEN-90: #85D35E;--weui-LIGHTGREEN-BG-100: #72CF60;--weui-LIGHTGREEN-BG-110: #80D370;--weui-LIGHTGREEN-BG-130: #9CDD90;--weui-LIGHTGREEN-BG-90: #66B956;--weui-LINK-100: #576B95;--weui-LINK-120: #7888AA;--weui-LINK-170: #CCD2DE;--weui-LINK-80: #455577;--weui-LINK-90: #4E6085;--weui-LINKFINDER-100: #002666;--weui-MATERIAL-ATTACHMENTCOLUMN: rgba(245, 245, 245, .95);--weui-MATERIAL-NAVIGATIONBAR: rgba(237, 237, 237, .94);--weui-MATERIAL-REGULAR: rgba(247, 247, 247, .3);--weui-MATERIAL-THICK: rgba(247, 247, 247, .8);--weui-MATERIAL-THIN: rgba(255, 255, 255, .2);--weui-MATERIAL-TOOLBAR: rgba(246, 246, 246, .82);--weui-ORANGE-100: #FA9D3B;--weui-ORANGE-120: #FBB062;--weui-ORANGE-170: #FDE1C3;--weui-ORANGE-80: #C87D2F;--weui-ORANGE-90: #E08C34;--weui-ORANGE-BG-100: #EA7800;--weui-ORANGE-BG-110: #EC8519;--weui-ORANGE-BG-130: #F0A04D;--weui-ORANGE-BG-90: #D26B00;--weui-ORANGERED-100: #FF6146;--weui-OVERLAY: rgba(0, 0, 0, .5);--weui-OVERLAY-WHITE: rgba(242, 242, 242, .8);--weui-PURPLE-100: #6467F0;--weui-PURPLE-120: #8385F3;--weui-PURPLE-170: #D0D1FA;--weui-PURPLE-80: #5052C0;--weui-PURPLE-90: #595CD7;--weui-PURPLE-BG-100: #6769BA;--weui-PURPLE-BG-110: #7678C1;--weui-PURPLE-BG-130: #9496CE;--weui-PURPLE-BG-90: #5C5EA7;--weui-RED-100: #FA5151;--weui-RED-120: #FB7373;--weui-RED-170: #FDCACA;--weui-RED-80: #C84040;--weui-RED-90: #E14949;--weui-RED-BG-100: #CF5148;--weui-RED-BG-110: #D3625A;--weui-RED-BG-130: #DD847E;--weui-RED-BG-90: #B94840;--weui-SECONDARY-BG: rgba(0, 0, 0, .05);--weui-SEPARATOR-0: rgba(0, 0, 0, .1);--weui-SEPARATOR-1: rgba(0, 0, 0, .15);--weui-STATELAYER-HOVERED: rgba(0, 0, 0, .02);--weui-STATELAYER-PRESSED: rgba(0, 0, 0, .1);--weui-STATELAYER-PRESSEDSTRENGTHENED: rgba(0, 0, 0, .2);--weui-YELLOW-100: #FFC300;--weui-YELLOW-120: #FFCF33;--weui-YELLOW-170: #FFECB2;--weui-YELLOW-80: #CC9C00;--weui-YELLOW-90: #E6AF00;--weui-YELLOW-BG-100: #EFB600;--weui-YELLOW-BG-110: #F0BD19;--weui-YELLOW-BG-130: #F3CC4D;--weui-YELLOW-BG-90: #D7A400;--weui-FG-HALF: rgba(0, 0, 0, .9);--weui-RED: #FA5151;--weui-ORANGERED: #FF6146;--weui-ORANGE: #FA9D3B;--weui-YELLOW: #FFC300;--weui-GREEN: #91D300;--weui-LIGHTGREEN: #95EC69;--weui-TEXTGREEN: #06AE56;--weui-BRAND: #07C160;--weui-BLUE: #10AEFF;--weui-INDIGO: #1485EE;--weui-PURPLE: #6467F0;--weui-LINK: #576B95;--weui-TAG-TEXT-ORANGE: #FA9D3B;--weui-TAG-TEXT-GREEN: #06AE56;--weui-TAG-TEXT-BLUE: #10AEFF;--weui-REDORANGE: #FF6146;--weui-TAG-TEXT-BLACK: rgba(0, 0, 0, .5);--weui-TAG-BACKGROUND-BLACK: rgba(0, 0, 0, .05);--weui-WHITE: #FFFFFF;--weui-BG: #FFFFFF;--weui-FG: #000;--weui-FG-5: rgba(0, 0, 0, .05);--weui-TAG-BACKGROUND-ORANGE: rgba(250, 157, 59, .1);--weui-TAG-BACKGROUND-GREEN: rgba(6, 174, 86, .1);--weui-TAG-TEXT-RED: rgba(250, 81, 81, .6);--weui-TAG-BACKGROUND-RED: rgba(250, 81, 81, .1);--weui-TAG-BACKGROUND-BLUE: rgba(16, 174, 255, .1)}@media (prefers-color-scheme: dark){.wx-root:not([data-weui-theme=light]),body:not([data-weui-theme=light]){--weui-BG-0: #111;--weui-BG-1: #1e1e1e;--weui-BG-5: #2c2c2c;--weui-RED: #fa5151;--weui-ORANGERED: #ff6146;--weui-ORANGE: #c87d2f;--weui-YELLOW: #cc9c00;--weui-GREEN: #74a800;--weui-LIGHTGREEN: #3eb575;--weui-BRAND: #07c160;--weui-BLUE: #10aeff;--weui-INDIGO: #1196ff;--weui-PURPLE: #8183ff;--weui-LINK: #7d90a9;--weui-TEXTGREEN: #259c5c;--weui-REDORANGE: #ff6146;--weui-BG-0: #111111;--weui-BG-1: #1E1E1E;--weui-BG-2: #191919;--weui-BG-3: #202020;--weui-BG-4: #404040;--weui-BG-5: #2C2C2C;--weui-BLUE-100: #10AEFF;--weui-BLUE-120: #0C8BCC;--weui-BLUE-170: #04344D;--weui-BLUE-80: #3FBEFF;--weui-BLUE-90: #28B6FF;--weui-BLUE-BG-100: #48A6E2;--weui-BLUE-BG-110: #4095CB;--weui-BLUE-BG-130: #32749E;--weui-BLUE-BG-90: #5AAFE4;--weui-BRAND-100: #07C160;--weui-BRAND-120: #059A4C;--weui-BRAND-170: #023A1C;--weui-BRAND-80: #38CD7F;--weui-BRAND-90: #20C770;--weui-BRAND-BG-100: #2AAE67;--weui-BRAND-BG-110: #259C5C;--weui-BRAND-BG-130: #1D7A48;--weui-BRAND-BG-90: #3EB575;--weui-FG-0: rgba(255, 255, 255, .8);--weui-FG-0_5: rgba(255, 255, 255, .6);--weui-FG-1: rgba(255, 255, 255, .5);--weui-FG-2: rgba(255, 255, 255, .3);--weui-FG-3: rgba(255, 255, 255, .1);--weui-FG-4: rgba(255, 255, 255, .15);--weui-GLYPH-0: rgba(255, 255, 255, .8);--weui-GLYPH-1: rgba(255, 255, 255, .5);--weui-GLYPH-2: rgba(255, 255, 255, .3);--weui-GLYPH-WHITE-0: rgba(255, 255, 255, .8);--weui-GLYPH-WHITE-1: rgba(255, 255, 255, .5);--weui-GLYPH-WHITE-2: rgba(255, 255, 255, .3);--weui-GLYPH-WHITE-3: #FFFFFF;--weui-GREEN-100: #74A800;--weui-GREEN-120: #5C8600;--weui-GREEN-170: #233200;--weui-GREEN-80: #8FB933;--weui-GREEN-90: #82B01A;--weui-GREEN-BG-100: #789833;--weui-GREEN-BG-110: #6B882D;--weui-GREEN-BG-130: #65802B;--weui-GREEN-BG-90: #85A247;--weui-INDIGO-100: #1196FF;--weui-INDIGO-120: #0D78CC;--weui-INDIGO-170: #052D4D;--weui-INDIGO-80: #40ABFF;--weui-INDIGO-90: #28A0FF;--weui-INDIGO-BG-100: #0D78CC;--weui-INDIGO-BG-110: #0B6BB7;--weui-INDIGO-BG-130: #09548F;--weui-INDIGO-BG-90: #2585D1;--weui-LIGHTGREEN-100: #3EB575;--weui-LIGHTGREEN-120: #31905D;--weui-LIGHTGREEN-170: #123522;--weui-LIGHTGREEN-80: #64C390;--weui-LIGHTGREEN-90: #51BC83;--weui-LIGHTGREEN-BG-100: #31905D;--weui-LIGHTGREEN-BG-110: #2C8153;--weui-LIGHTGREEN-BG-130: #226541;--weui-LIGHTGREEN-BG-90: #31905D;--weui-LINK-100: #7D90A9;--weui-LINK-120: #647387;--weui-LINK-170: #252A32;--weui-LINK-80: #97A6BA;--weui-LINK-90: #899AB1;--weui-LINKFINDER-100: #DEE9FF;--weui-MATERIAL-ATTACHMENTCOLUMN: rgba(32, 32, 32, .93);--weui-MATERIAL-NAVIGATIONBAR: rgba(18, 18, 18, .9);--weui-MATERIAL-REGULAR: rgba(37, 37, 37, .6);--weui-MATERIAL-THICK: rgba(34, 34, 34, .9);--weui-MATERIAL-THIN: rgba(95, 95, 95, .4);--weui-MATERIAL-TOOLBAR: rgba(35, 35, 35, .93);--weui-ORANGE-100: #C87D2F;--weui-ORANGE-120: #A06425;--weui-ORANGE-170: #3B250E;--weui-ORANGE-80: #D39758;--weui-ORANGE-90: #CD8943;--weui-ORANGE-BG-100: #BB6000;--weui-ORANGE-BG-110: #A85600;--weui-ORANGE-BG-130: #824300;--weui-ORANGE-BG-90: #C1701A;--weui-ORANGERED-100: #FF6146;--weui-OVERLAY: rgba(0, 0, 0, .8);--weui-OVERLAY-WHITE: rgba(242, 242, 242, .8);--weui-PURPLE-100: #8183FF;--weui-PURPLE-120: #6768CC;--weui-PURPLE-170: #26274C;--weui-PURPLE-80: #9A9BFF;--weui-PURPLE-90: #8D8FFF;--weui-PURPLE-BG-100: #6768CC;--weui-PURPLE-BG-110: #5C5DB7;--weui-PURPLE-BG-130: #48498F;--weui-PURPLE-BG-90: #7677D1;--weui-RED-100: #FA5151;--weui-RED-120: #C84040;--weui-RED-170: #4B1818;--weui-RED-80: #FB7373;--weui-RED-90: #FA6262;--weui-RED-BG-100: #CF5148;--weui-RED-BG-110: #BA4940;--weui-RED-BG-130: #913832;--weui-RED-BG-90: #D3625A;--weui-SECONDARY-BG: rgba(255, 255, 255, .1);--weui-SEPARATOR-0: rgba(255, 255, 255, .05);--weui-SEPARATOR-1: rgba(255, 255, 255, .15);--weui-STATELAYER-HOVERED: rgba(0, 0, 0, .02);--weui-STATELAYER-PRESSED: rgba(255, 255, 255, .1);--weui-STATELAYER-PRESSEDSTRENGTHENED: rgba(255, 255, 255, .2);--weui-YELLOW-100: #CC9C00;--weui-YELLOW-120: #A37C00;--weui-YELLOW-170: #3D2F00;--weui-YELLOW-80: #D6AF33;--weui-YELLOW-90: #D1A519;--weui-YELLOW-BG-100: #BF9100;--weui-YELLOW-BG-110: #AB8200;--weui-YELLOW-BG-130: #866500;--weui-YELLOW-BG-90: #C59C1A;--weui-FG-HALF: rgba(255, 255, 255, .6);--weui-RED: #FA5151;--weui-ORANGERED: #FF6146;--weui-ORANGE: #C87D2F;--weui-YELLOW: #CC9C00;--weui-GREEN: #74A800;--weui-LIGHTGREEN: #3EB575;--weui-TEXTGREEN: #259C5C;--weui-BRAND: #07C160;--weui-BLUE: #10AEFF;--weui-INDIGO: #1196FF;--weui-PURPLE: #8183FF;--weui-LINK: #7D90A9;--weui-REDORANGE: #FF6146;--weui-TAG-TEXT-BLACK: rgba(255, 255, 255, .5);--weui-TAG-BACKGROUND-BLACK: rgba(255, 255, 255, .05);--weui-WHITE: rgba(255, 255, 255, .8);--weui-FG: #fff;--weui-BG: #000;--weui-FG-5: rgba(255, 255, 255, .1);--weui-TAG-BACKGROUND-ORANGE: rgba(250, 157, 59, .1);--weui-TAG-BACKGROUND-GREEN: rgba(6, 174, 86, .1);--weui-TAG-TEXT-RED: rgba(250, 81, 81, .6);--weui-TAG-BACKGROUND-RED: rgba(250, 81, 81, .1);--weui-TAG-BACKGROUND-BLUE: rgba(16, 174, 255, .1);--weui-TAG-TEXT-ORANGE: rgba(250, 157, 59, .6);--weui-TAG-TEXT-GREEN: rgba(6, 174, 86, .6);--weui-TAG-TEXT-BLUE: rgba(16, 174, 255, .6)}}.wx-root[data-weui-theme=dark],body[data-weui-theme=dark]{--weui-BG-0: #111;--weui-BG-1: #1e1e1e;--weui-BG-5: #2c2c2c;--weui-RED: #fa5151;--weui-ORANGERED: #ff6146;--weui-ORANGE: #c87d2f;--weui-YELLOW: #cc9c00;--weui-GREEN: #74a800;--weui-LIGHTGREEN: #3eb575;--weui-BRAND: #07c160;--weui-BLUE: #10aeff;--weui-INDIGO: #1196ff;--weui-PURPLE: #8183ff;--weui-LINK: #7d90a9;--weui-TEXTGREEN: #259c5c;--weui-REDORANGE: #ff6146;--weui-BG-0: #111111;--weui-BG-1: #1E1E1E;--weui-BG-2: #191919;--weui-BG-3: #202020;--weui-BG-4: #404040;--weui-BG-5: #2C2C2C;--weui-BLUE-100: #10AEFF;--weui-BLUE-120: #0C8BCC;--weui-BLUE-170: #04344D;--weui-BLUE-80: #3FBEFF;--weui-BLUE-90: #28B6FF;--weui-BLUE-BG-100: #48A6E2;--weui-BLUE-BG-110: #4095CB;--weui-BLUE-BG-130: #32749E;--weui-BLUE-BG-90: #5AAFE4;--weui-BRAND-100: #07C160;--weui-BRAND-120: #059A4C;--weui-BRAND-170: #023A1C;--weui-BRAND-80: #38CD7F;--weui-BRAND-90: #20C770;--weui-BRAND-BG-100: #2AAE67;--weui-BRAND-BG-110: #259C5C;--weui-BRAND-BG-130: #1D7A48;--weui-BRAND-BG-90: #3EB575;--weui-FG-0: rgba(255, 255, 255, .8);--weui-FG-0_5: rgba(255, 255, 255, .6);--weui-FG-1: rgba(255, 255, 255, .5);--weui-FG-2: rgba(255, 255, 255, .3);--weui-FG-3: rgba(255, 255, 255, .1);--weui-FG-4: rgba(255, 255, 255, .15);--weui-GLYPH-0: rgba(255, 255, 255, .8);--weui-GLYPH-1: rgba(255, 255, 255, .5);--weui-GLYPH-2: rgba(255, 255, 255, .3);--weui-GLYPH-WHITE-0: rgba(255, 255, 255, .8);--weui-GLYPH-WHITE-1: rgba(255, 255, 255, .5);--weui-GLYPH-WHITE-2: rgba(255, 255, 255, .3);--weui-GLYPH-WHITE-3: #FFFFFF;--weui-GREEN-100: #74A800;--weui-GREEN-120: #5C8600;--weui-GREEN-170: #233200;--weui-GREEN-80: #8FB933;--weui-GREEN-90: #82B01A;--weui-GREEN-BG-100: #789833;--weui-GREEN-BG-110: #6B882D;--weui-GREEN-BG-130: #65802B;--weui-GREEN-BG-90: #85A247;--weui-INDIGO-100: #1196FF;--weui-INDIGO-120: #0D78CC;--weui-INDIGO-170: #052D4D;--weui-INDIGO-80: #40ABFF;--weui-INDIGO-90: #28A0FF;--weui-INDIGO-BG-100: #0D78CC;--weui-INDIGO-BG-110: #0B6BB7;--weui-INDIGO-BG-130: #09548F;--weui-INDIGO-BG-90: #2585D1;--weui-LIGHTGREEN-100: #3EB575;--weui-LIGHTGREEN-120: #31905D;--weui-LIGHTGREEN-170: #123522;--weui-LIGHTGREEN-80: #64C390;--weui-LIGHTGREEN-90: #51BC83;--weui-LIGHTGREEN-BG-100: #31905D;--weui-LIGHTGREEN-BG-110: #2C8153;--weui-LIGHTGREEN-BG-130: #226541;--weui-LIGHTGREEN-BG-90: #31905D;--weui-LINK-100: #7D90A9;--weui-LINK-120: #647387;--weui-LINK-170: #252A32;--weui-LINK-80: #97A6BA;--weui-LINK-90: #899AB1;--weui-LINKFINDER-100: #DEE9FF;--weui-MATERIAL-ATTACHMENTCOLUMN: rgba(32, 32, 32, .93);--weui-MATERIAL-NAVIGATIONBAR: rgba(18, 18, 18, .9);--weui-MATERIAL-REGULAR: rgba(37, 37, 37, .6);--weui-MATERIAL-THICK: rgba(34, 34, 34, .9);--weui-MATERIAL-THIN: rgba(95, 95, 95, .4);--weui-MATERIAL-TOOLBAR: rgba(35, 35, 35, .93);--weui-ORANGE-100: #C87D2F;--weui-ORANGE-120: #A06425;--weui-ORANGE-170: #3B250E;--weui-ORANGE-80: #D39758;--weui-ORANGE-90: #CD8943;--weui-ORANGE-BG-100: #BB6000;--weui-ORANGE-BG-110: #A85600;--weui-ORANGE-BG-130: #824300;--weui-ORANGE-BG-90: #C1701A;--weui-ORANGERED-100: #FF6146;--weui-OVERLAY: rgba(0, 0, 0, .8);--weui-OVERLAY-WHITE: rgba(242, 242, 242, .8);--weui-PURPLE-100: #8183FF;--weui-PURPLE-120: #6768CC;--weui-PURPLE-170: #26274C;--weui-PURPLE-80: #9A9BFF;--weui-PURPLE-90: #8D8FFF;--weui-PURPLE-BG-100: #6768CC;--weui-PURPLE-BG-110: #5C5DB7;--weui-PURPLE-BG-130: #48498F;--weui-PURPLE-BG-90: #7677D1;--weui-RED-100: #FA5151;--weui-RED-120: #C84040;--weui-RED-170: #4B1818;--weui-RED-80: #FB7373;--weui-RED-90: #FA6262;--weui-RED-BG-100: #CF5148;--weui-RED-BG-110: #BA4940;--weui-RED-BG-130: #913832;--weui-RED-BG-90: #D3625A;--weui-SECONDARY-BG: rgba(255, 255, 255, .1);--weui-SEPARATOR-0: rgba(255, 255, 255, .05);--weui-SEPARATOR-1: rgba(255, 255, 255, .15);--weui-STATELAYER-HOVERED: rgba(0, 0, 0, .02);--weui-STATELAYER-PRESSED: rgba(255, 255, 255, .1);--weui-STATELAYER-PRESSEDSTRENGTHENED: rgba(255, 255, 255, .2);--weui-YELLOW-100: #CC9C00;--weui-YELLOW-120: #A37C00;--weui-YELLOW-170: #3D2F00;--weui-YELLOW-80: #D6AF33;--weui-YELLOW-90: #D1A519;--weui-YELLOW-BG-100: #BF9100;--weui-YELLOW-BG-110: #AB8200;--weui-YELLOW-BG-130: #866500;--weui-YELLOW-BG-90: #C59C1A;--weui-FG-HALF: rgba(255, 255, 255, .6);--weui-RED: #FA5151;--weui-ORANGERED: #FF6146;--weui-ORANGE: #C87D2F;--weui-YELLOW: #CC9C00;--weui-GREEN: #74A800;--weui-LIGHTGREEN: #3EB575;--weui-TEXTGREEN: #259C5C;--weui-BRAND: #07C160;--weui-BLUE: #10AEFF;--weui-INDIGO: #1196FF;--weui-PURPLE: #8183FF;--weui-LINK: #7D90A9;--weui-REDORANGE: #FF6146;--weui-TAG-TEXT-BLACK: rgba(255, 255, 255, .5);--weui-TAG-BACKGROUND-BLACK: rgba(255, 255, 255, .05);--weui-WHITE: rgba(255, 255, 255, .8);--weui-FG: #fff;--weui-BG: #000;--weui-FG-5: rgba(255, 255, 255, .1);--weui-TAG-BACKGROUND-ORANGE: rgba(250, 157, 59, .1);--weui-TAG-BACKGROUND-GREEN: rgba(6, 174, 86, .1);--weui-TAG-TEXT-RED: rgba(250, 81, 81, .6);--weui-TAG-BACKGROUND-RED: rgba(250, 81, 81, .1);--weui-TAG-BACKGROUND-BLUE: rgba(16, 174, 255, .1);--weui-TAG-TEXT-ORANGE: rgba(250, 157, 59, .6);--weui-TAG-TEXT-GREEN: rgba(6, 174, 86, .6);--weui-TAG-TEXT-BLUE: rgba(16, 174, 255, .6)}.wx-root[data-weui-mode=care],body[data-weui-mode=care]{--weui-BG-0: #ededed;--weui-BG-1: #f7f7f7;--weui-BG-2: #fff;--weui-BG-3: #f7f7f7;--weui-BG-4: #4c4c4c;--weui-BG-5: #fff;--weui-RED: #dc3636;--weui-ORANGERED: #d14730;--weui-ORANGE: #e17719;--weui-YELLOW: #bb8e00;--weui-GREEN: #4f8400;--weui-LIGHTGREEN: #2e8800;--weui-BLUE: #007dbb;--weui-INDIGO: #0075e2;--weui-PURPLE: #6265f1;--weui-WHITE: #fff;--weui-LINK: #576b95;--weui-TEXTGREEN: #06ae56;--weui-BG: #fff;--weui-TAG-TEXT-ORANGE: #e17719;--weui-TAG-TEXT-GREEN: #06ae56;--weui-TAG-TEXT-BLUE: #007dbb;--weui-REDORANGE: #d14730;--weui-BG-0: #EDEDED;--weui-BG-1: #F7F7F7;--weui-BG-2: #FFFFFF;--weui-BG-3: #F7F7F7;--weui-BG-4: #4C4C4C;--weui-BG-5: #FFFFFF;--weui-BLUE-100: #007DBB;--weui-BLUE-120: #3FBEFF;--weui-BLUE-170: #B7E6FF;--weui-BLUE-80: #0C8BCC;--weui-BLUE-90: #0E9CE6;--weui-BLUE-BG-100: #48A6E2;--weui-BLUE-BG-110: #5AAFE4;--weui-BLUE-BG-130: #7FC0EA;--weui-BLUE-BG-90: #4095CB;--weui-BRAND-100: #018942;--weui-BRAND-120: #38CD7F;--weui-BRAND-170: #B4ECCE;--weui-BRAND-80: #059A4C;--weui-BRAND-90: #06AE56;--weui-BRAND-BG-100: #2AAE67;--weui-BRAND-BG-110: #3EB575;--weui-BRAND-BG-130: #69C694;--weui-BRAND-BG-90: #259C5C;--weui-FG-0: #000000;--weui-FG-0_5: #000000;--weui-FG-1: rgba(0, 0, 0, .6);--weui-FG-2: rgba(0, 0, 0, .42);--weui-FG-3: rgba(0, 0, 0, .1);--weui-FG-4: rgba(0, 0, 0, .15);--weui-GLYPH-0: #000000;--weui-GLYPH-1: rgba(0, 0, 0, .6);--weui-GLYPH-2: rgba(0, 0, 0, .42);--weui-GLYPH-WHITE-0: rgba(255, 255, 255, .85);--weui-GLYPH-WHITE-1: rgba(255, 255, 255, .55);--weui-GLYPH-WHITE-2: rgba(255, 255, 255, .35);--weui-GLYPH-WHITE-3: #FFFFFF;--weui-GREEN-100: #4F8400;--weui-GREEN-120: #A7DB33;--weui-GREEN-170: #DEF1B3;--weui-GREEN-80: #74A800;--weui-GREEN-90: #82BD00;--weui-GREEN-BG-100: #96BE40;--weui-GREEN-BG-110: #A0C452;--weui-GREEN-BG-130: #B5D179;--weui-GREEN-BG-90: #86AA39;--weui-INDIGO-100: #0075E2;--weui-INDIGO-120: #439DF1;--weui-INDIGO-170: #B8DAF9;--weui-INDIGO-80: #106ABE;--weui-INDIGO-90: #1277D6;--weui-INDIGO-BG-100: #2B77BF;--weui-INDIGO-BG-110: #3F84C5;--weui-INDIGO-BG-130: #6BA0D2;--weui-INDIGO-BG-90: #266AAB;--weui-LIGHTGREEN-100: #2E8800;--weui-LIGHTGREEN-120: #AAEF87;--weui-LIGHTGREEN-170: #DEF9D1;--weui-LIGHTGREEN-80: #77BC54;--weui-LIGHTGREEN-90: #85D35E;--weui-LIGHTGREEN-BG-100: #72CF60;--weui-LIGHTGREEN-BG-110: #80D370;--weui-LIGHTGREEN-BG-130: #9CDD90;--weui-LIGHTGREEN-BG-90: #66B956;--weui-LINK-100: #576B95;--weui-LINK-120: #7888AA;--weui-LINK-170: #CCD2DE;--weui-LINK-80: #455577;--weui-LINK-90: #4E6085;--weui-LINKFINDER-100: #002666;--weui-MATERIAL-ATTACHMENTCOLUMN: rgba(245, 245, 245, .95);--weui-MATERIAL-NAVIGATIONBAR: rgba(237, 237, 237, .94);--weui-MATERIAL-REGULAR: rgba(247, 247, 247, .3);--weui-MATERIAL-THICK: rgba(247, 247, 247, .8);--weui-MATERIAL-THIN: rgba(255, 255, 255, .2);--weui-MATERIAL-TOOLBAR: rgba(246, 246, 246, .82);--weui-ORANGE-100: #E17719;--weui-ORANGE-120: #FBB062;--weui-ORANGE-170: #FDE1C3;--weui-ORANGE-80: #C87D2F;--weui-ORANGE-90: #E08C34;--weui-ORANGE-BG-100: #EA7800;--weui-ORANGE-BG-110: #EC8519;--weui-ORANGE-BG-130: #F0A04D;--weui-ORANGE-BG-90: #D26B00;--weui-ORANGERED-100: #D14730;--weui-OVERLAY: rgba(0, 0, 0, .5);--weui-OVERLAY-WHITE: rgba(242, 242, 242, .8);--weui-PURPLE-100: #6265F1;--weui-PURPLE-120: #8385F3;--weui-PURPLE-170: #D0D1FA;--weui-PURPLE-80: #5052C0;--weui-PURPLE-90: #595CD7;--weui-PURPLE-BG-100: #6769BA;--weui-PURPLE-BG-110: #7678C1;--weui-PURPLE-BG-130: #9496CE;--weui-PURPLE-BG-90: #5C5EA7;--weui-RED-100: #DC3636;--weui-RED-120: #FB7373;--weui-RED-170: #FDCACA;--weui-RED-80: #C84040;--weui-RED-90: #E14949;--weui-RED-BG-100: #CF5148;--weui-RED-BG-110: #D3625A;--weui-RED-BG-130: #DD847E;--weui-RED-BG-90: #B94840;--weui-SECONDARY-BG: rgba(0, 0, 0, .1);--weui-SEPARATOR-0: rgba(0, 0, 0, .1);--weui-SEPARATOR-1: rgba(0, 0, 0, .15);--weui-STATELAYER-HOVERED: rgba(0, 0, 0, .02);--weui-STATELAYER-PRESSED: rgba(0, 0, 0, .1);--weui-STATELAYER-PRESSEDSTRENGTHENED: rgba(0, 0, 0, .2);--weui-YELLOW-100: #BB8E00;--weui-YELLOW-120: #FFCF33;--weui-YELLOW-170: #FFECB2;--weui-YELLOW-80: #CC9C00;--weui-YELLOW-90: #E6AF00;--weui-YELLOW-BG-100: #EFB600;--weui-YELLOW-BG-110: #F0BD19;--weui-YELLOW-BG-130: #F3CC4D;--weui-YELLOW-BG-90: #D7A400;--weui-FG-HALF: #000000;--weui-RED: #DC3636;--weui-ORANGERED: #D14730;--weui-ORANGE: #E17719;--weui-YELLOW: #BB8E00;--weui-GREEN: #4F8400;--weui-LIGHTGREEN: #2E8800;--weui-TEXTGREEN: #06AE56;--weui-BRAND: #018942;--weui-BLUE: #007DBB;--weui-INDIGO: #0075E2;--weui-PURPLE: #6265F1;--weui-LINK: #576B95;--weui-TAG-TEXT-ORANGE: #E17719;--weui-TAG-TEXT-GREEN: #06AE56;--weui-TAG-TEXT-BLUE: #007DBB;--weui-REDORANGE: #D14730;--weui-TAG-TEXT-BLACK: rgba(0, 0, 0, .5);--weui-WHITE: #FFFFFF;--weui-BG: #FFFFFF;--weui-FG: #000;--weui-FG-5: rgba(0, 0, 0, .05);--weui-TAG-BACKGROUND-ORANGE: rgba(225, 119, 25, .1);--weui-TAG-BACKGROUND-GREEN: rgba(6, 174, 86, .1);--weui-TAG-TEXT-RED: rgba(250, 81, 81, .6);--weui-TAG-BACKGROUND-RED: rgba(250, 81, 81, .1);--weui-TAG-BACKGROUND-BLUE: rgba(0, 125, 187, .1);--weui-TAG-BACKGROUND-BLACK: rgba(0, 0, 0, .05)}@media (prefers-color-scheme: dark){.wx-root[data-weui-mode=care]:not([data-weui-theme=light]),body[data-weui-mode=care]:not([data-weui-theme=light]){--weui-BG-0: #111;--weui-BG-1: #1e1e1e;--weui-BG-5: #2c2c2c;--weui-RED: #fa5151;--weui-ORANGERED: #ff6146;--weui-ORANGE: #c87d2f;--weui-YELLOW: #cc9c00;--weui-GREEN: #74a800;--weui-LIGHTGREEN: #3eb575;--weui-BRAND: #07c160;--weui-BLUE: #10aeff;--weui-INDIGO: #1196ff;--weui-PURPLE: #8183ff;--weui-LINK: #7d90a9;--weui-TEXTGREEN: #259c5c;--weui-REDORANGE: #ff6146;--weui-BG-0: #111111;--weui-BG-1: #1E1E1E;--weui-BG-2: #191919;--weui-BG-3: #202020;--weui-BG-4: #404040;--weui-BG-5: #2C2C2C;--weui-BLUE-100: #10AEFF;--weui-BLUE-120: #0C8BCC;--weui-BLUE-170: #04344D;--weui-BLUE-80: #3FBEFF;--weui-BLUE-90: #28B6FF;--weui-BLUE-BG-100: #48A6E2;--weui-BLUE-BG-110: #4095CB;--weui-BLUE-BG-130: #32749E;--weui-BLUE-BG-90: #5AAFE4;--weui-BRAND-100: #07C160;--weui-BRAND-120: #059A4C;--weui-BRAND-170: #023A1C;--weui-BRAND-80: #38CD7F;--weui-BRAND-90: #20C770;--weui-BRAND-BG-100: #2AAE67;--weui-BRAND-BG-110: #259C5C;--weui-BRAND-BG-130: #1D7A48;--weui-BRAND-BG-90: #3EB575;--weui-FG-0: rgba(255, 255, 255, .85);--weui-FG-0_5: rgba(255, 255, 255, .65);--weui-FG-1: rgba(255, 255, 255, .55);--weui-FG-2: rgba(255, 255, 255, .35);--weui-FG-3: rgba(255, 255, 255, .1);--weui-FG-4: rgba(255, 255, 255, .15);--weui-GLYPH-0: rgba(255, 255, 255, .85);--weui-GLYPH-1: rgba(255, 255, 255, .55);--weui-GLYPH-2: rgba(255, 255, 255, .35);--weui-GLYPH-WHITE-0: rgba(255, 255, 255, .85);--weui-GLYPH-WHITE-1: rgba(255, 255, 255, .55);--weui-GLYPH-WHITE-2: rgba(255, 255, 255, .35);--weui-GLYPH-WHITE-3: #FFFFFF;--weui-GREEN-100: #74A800;--weui-GREEN-120: #5C8600;--weui-GREEN-170: #233200;--weui-GREEN-80: #8FB933;--weui-GREEN-90: #82B01A;--weui-GREEN-BG-100: #789833;--weui-GREEN-BG-110: #6B882D;--weui-GREEN-BG-130: #65802B;--weui-GREEN-BG-90: #85A247;--weui-INDIGO-100: #1196FF;--weui-INDIGO-120: #0D78CC;--weui-INDIGO-170: #052D4D;--weui-INDIGO-80: #40ABFF;--weui-INDIGO-90: #28A0FF;--weui-INDIGO-BG-100: #0D78CC;--weui-INDIGO-BG-110: #0B6BB7;--weui-INDIGO-BG-130: #09548F;--weui-INDIGO-BG-90: #2585D1;--weui-LIGHTGREEN-100: #3EB575;--weui-LIGHTGREEN-120: #31905D;--weui-LIGHTGREEN-170: #123522;--weui-LIGHTGREEN-80: #64C390;--weui-LIGHTGREEN-90: #51BC83;--weui-LIGHTGREEN-BG-100: #31905D;--weui-LIGHTGREEN-BG-110: #2C8153;--weui-LIGHTGREEN-BG-130: #226541;--weui-LIGHTGREEN-BG-90: #31905D;--weui-LINK-100: #7D90A9;--weui-LINK-120: #647387;--weui-LINK-170: #252A32;--weui-LINK-80: #97A6BA;--weui-LINK-90: #899AB1;--weui-LINKFINDER-100: #DEE9FF;--weui-MATERIAL-ATTACHMENTCOLUMN: rgba(32, 32, 32, .93);--weui-MATERIAL-NAVIGATIONBAR: rgba(18, 18, 18, .9);--weui-MATERIAL-REGULAR: rgba(37, 37, 37, .6);--weui-MATERIAL-THICK: rgba(34, 34, 34, .9);--weui-MATERIAL-THIN: rgba(245, 245, 245, .4);--weui-MATERIAL-TOOLBAR: rgba(35, 35, 35, .93);--weui-ORANGE-100: #C87D2F;--weui-ORANGE-120: #A06425;--weui-ORANGE-170: #3B250E;--weui-ORANGE-80: #D39758;--weui-ORANGE-90: #CD8943;--weui-ORANGE-BG-100: #BB6000;--weui-ORANGE-BG-110: #A85600;--weui-ORANGE-BG-130: #824300;--weui-ORANGE-BG-90: #C1701A;--weui-ORANGERED-100: #FF6146;--weui-OVERLAY: rgba(0, 0, 0, .8);--weui-OVERLAY-WHITE: rgba(242, 242, 242, .8);--weui-PURPLE-100: #8183FF;--weui-PURPLE-120: #6768CC;--weui-PURPLE-170: #26274C;--weui-PURPLE-80: #9A9BFF;--weui-PURPLE-90: #8D8FFF;--weui-PURPLE-BG-100: #6768CC;--weui-PURPLE-BG-110: #5C5DB7;--weui-PURPLE-BG-130: #48498F;--weui-PURPLE-BG-90: #7677D1;--weui-RED-100: #FA5151;--weui-RED-120: #C84040;--weui-RED-170: #4B1818;--weui-RED-80: #FB7373;--weui-RED-90: #FA6262;--weui-RED-BG-100: #CF5148;--weui-RED-BG-110: #BA4940;--weui-RED-BG-130: #913832;--weui-RED-BG-90: #D3625A;--weui-SECONDARY-BG: rgba(255, 255, 255, .15);--weui-SEPARATOR-0: rgba(255, 255, 255, .05);--weui-SEPARATOR-1: rgba(255, 255, 255, .15);--weui-STATELAYER-HOVERED: rgba(0, 0, 0, .02);--weui-STATELAYER-PRESSED: rgba(255, 255, 255, .1);--weui-STATELAYER-PRESSEDSTRENGTHENED: rgba(255, 255, 255, .2);--weui-YELLOW-100: #CC9C00;--weui-YELLOW-120: #A37C00;--weui-YELLOW-170: #3D2F00;--weui-YELLOW-80: #D6AF33;--weui-YELLOW-90: #D1A519;--weui-YELLOW-BG-100: #BF9100;--weui-YELLOW-BG-110: #AB8200;--weui-YELLOW-BG-130: #866500;--weui-YELLOW-BG-90: #C59C1A;--weui-FG-HALF: rgba(255, 255, 255, .65);--weui-RED: #FA5151;--weui-ORANGERED: #FF6146;--weui-ORANGE: #C87D2F;--weui-YELLOW: #CC9C00;--weui-GREEN: #74A800;--weui-LIGHTGREEN: #3EB575;--weui-TEXTGREEN: #259C5C;--weui-BRAND: #07C160;--weui-BLUE: #10AEFF;--weui-INDIGO: #1196FF;--weui-PURPLE: #8183FF;--weui-LINK: #7D90A9;--weui-REDORANGE: #FF6146;--weui-TAG-BACKGROUND-BLACK: rgba(255, 255, 255, .05);--weui-FG: #fff;--weui-WHITE: rgba(255, 255, 255, .8);--weui-FG-5: rgba(255, 255, 255, .1);--weui-TAG-BACKGROUND-ORANGE: rgba(250, 157, 59, .1);--weui-TAG-BACKGROUND-GREEN: rgba(6, 174, 86, .1);--weui-TAG-TEXT-RED: rgba(250, 81, 81, .6);--weui-TAG-BACKGROUND-RED: rgba(250, 81, 81, .1);--weui-TAG-BACKGROUND-BLUE: rgba(16, 174, 255, .1);--weui-TAG-TEXT-ORANGE: rgba(250, 157, 59, .6);--weui-BG: #000;--weui-TAG-TEXT-GREEN: rgba(6, 174, 86, .6);--weui-TAG-TEXT-BLUE: rgba(16, 174, 255, .6);--weui-TAG-TEXT-BLACK: rgba(255, 255, 255, .5)}}.wx-root[data-weui-mode=care][data-weui-theme=dark],body[data-weui-mode=care][data-weui-theme=dark]{--weui-BG-0: #111;--weui-BG-1: #1e1e1e;--weui-BG-5: #2c2c2c;--weui-RED: #fa5151;--weui-ORANGERED: #ff6146;--weui-ORANGE: #c87d2f;--weui-YELLOW: #cc9c00;--weui-GREEN: #74a800;--weui-LIGHTGREEN: #3eb575;--weui-BRAND: #07c160;--weui-BLUE: #10aeff;--weui-INDIGO: #1196ff;--weui-PURPLE: #8183ff;--weui-LINK: #7d90a9;--weui-TEXTGREEN: #259c5c;--weui-REDORANGE: #ff6146;--weui-BG-0: #111111;--weui-BG-1: #1E1E1E;--weui-BG-2: #191919;--weui-BG-3: #202020;--weui-BG-4: #404040;--weui-BG-5: #2C2C2C;--weui-BLUE-100: #10AEFF;--weui-BLUE-120: #0C8BCC;--weui-BLUE-170: #04344D;--weui-BLUE-80: #3FBEFF;--weui-BLUE-90: #28B6FF;--weui-BLUE-BG-100: #48A6E2;--weui-BLUE-BG-110: #4095CB;--weui-BLUE-BG-130: #32749E;--weui-BLUE-BG-90: #5AAFE4;--weui-BRAND-100: #07C160;--weui-BRAND-120: #059A4C;--weui-BRAND-170: #023A1C;--weui-BRAND-80: #38CD7F;--weui-BRAND-90: #20C770;--weui-BRAND-BG-100: #2AAE67;--weui-BRAND-BG-110: #259C5C;--weui-BRAND-BG-130: #1D7A48;--weui-BRAND-BG-90: #3EB575;--weui-FG-0: rgba(255, 255, 255, .85);--weui-FG-0_5: rgba(255, 255, 255, .65);--weui-FG-1: rgba(255, 255, 255, .55);--weui-FG-2: rgba(255, 255, 255, .35);--weui-FG-3: rgba(255, 255, 255, .1);--weui-FG-4: rgba(255, 255, 255, .15);--weui-GLYPH-0: rgba(255, 255, 255, .85);--weui-GLYPH-1: rgba(255, 255, 255, .55);--weui-GLYPH-2: rgba(255, 255, 255, .35);--weui-GLYPH-WHITE-0: rgba(255, 255, 255, .85);--weui-GLYPH-WHITE-1: rgba(255, 255, 255, .55);--weui-GLYPH-WHITE-2: rgba(255, 255, 255, .35);--weui-GLYPH-WHITE-3: #FFFFFF;--weui-GREEN-100: #74A800;--weui-GREEN-120: #5C8600;--weui-GREEN-170: #233200;--weui-GREEN-80: #8FB933;--weui-GREEN-90: #82B01A;--weui-GREEN-BG-100: #789833;--weui-GREEN-BG-110: #6B882D;--weui-GREEN-BG-130: #65802B;--weui-GREEN-BG-90: #85A247;--weui-INDIGO-100: #1196FF;--weui-INDIGO-120: #0D78CC;--weui-INDIGO-170: #052D4D;--weui-INDIGO-80: #40ABFF;--weui-INDIGO-90: #28A0FF;--weui-INDIGO-BG-100: #0D78CC;--weui-INDIGO-BG-110: #0B6BB7;--weui-INDIGO-BG-130: #09548F;--weui-INDIGO-BG-90: #2585D1;--weui-LIGHTGREEN-100: #3EB575;--weui-LIGHTGREEN-120: #31905D;--weui-LIGHTGREEN-170: #123522;--weui-LIGHTGREEN-80: #64C390;--weui-LIGHTGREEN-90: #51BC83;--weui-LIGHTGREEN-BG-100: #31905D;--weui-LIGHTGREEN-BG-110: #2C8153;--weui-LIGHTGREEN-BG-130: #226541;--weui-LIGHTGREEN-BG-90: #31905D;--weui-LINK-100: #7D90A9;--weui-LINK-120: #647387;--weui-LINK-170: #252A32;--weui-LINK-80: #97A6BA;--weui-LINK-90: #899AB1;--weui-LINKFINDER-100: #DEE9FF;--weui-MATERIAL-ATTACHMENTCOLUMN: rgba(32, 32, 32, .93);--weui-MATERIAL-NAVIGATIONBAR: rgba(18, 18, 18, .9);--weui-MATERIAL-REGULAR: rgba(37, 37, 37, .6);--weui-MATERIAL-THICK: rgba(34, 34, 34, .9);--weui-MATERIAL-THIN: rgba(245, 245, 245, .4);--weui-MATERIAL-TOOLBAR: rgba(35, 35, 35, .93);--weui-ORANGE-100: #C87D2F;--weui-ORANGE-120: #A06425;--weui-ORANGE-170: #3B250E;--weui-ORANGE-80: #D39758;--weui-ORANGE-90: #CD8943;--weui-ORANGE-BG-100: #BB6000;--weui-ORANGE-BG-110: #A85600;--weui-ORANGE-BG-130: #824300;--weui-ORANGE-BG-90: #C1701A;--weui-ORANGERED-100: #FF6146;--weui-OVERLAY: rgba(0, 0, 0, .8);--weui-OVERLAY-WHITE: rgba(242, 242, 242, .8);--weui-PURPLE-100: #8183FF;--weui-PURPLE-120: #6768CC;--weui-PURPLE-170: #26274C;--weui-PURPLE-80: #9A9BFF;--weui-PURPLE-90: #8D8FFF;--weui-PURPLE-BG-100: #6768CC;--weui-PURPLE-BG-110: #5C5DB7;--weui-PURPLE-BG-130: #48498F;--weui-PURPLE-BG-90: #7677D1;--weui-RED-100: #FA5151;--weui-RED-120: #C84040;--weui-RED-170: #4B1818;--weui-RED-80: #FB7373;--weui-RED-90: #FA6262;--weui-RED-BG-100: #CF5148;--weui-RED-BG-110: #BA4940;--weui-RED-BG-130: #913832;--weui-RED-BG-90: #D3625A;--weui-SECONDARY-BG: rgba(255, 255, 255, .15);--weui-SEPARATOR-0: rgba(255, 255, 255, .05);--weui-SEPARATOR-1: rgba(255, 255, 255, .15);--weui-STATELAYER-HOVERED: rgba(0, 0, 0, .02);--weui-STATELAYER-PRESSED: rgba(255, 255, 255, .1);--weui-STATELAYER-PRESSEDSTRENGTHENED: rgba(255, 255, 255, .2);--weui-YELLOW-100: #CC9C00;--weui-YELLOW-120: #A37C00;--weui-YELLOW-170: #3D2F00;--weui-YELLOW-80: #D6AF33;--weui-YELLOW-90: #D1A519;--weui-YELLOW-BG-100: #BF9100;--weui-YELLOW-BG-110: #AB8200;--weui-YELLOW-BG-130: #866500;--weui-YELLOW-BG-90: #C59C1A;--weui-FG-HALF: rgba(255, 255, 255, .65);--weui-RED: #FA5151;--weui-ORANGERED: #FF6146;--weui-ORANGE: #C87D2F;--weui-YELLOW: #CC9C00;--weui-GREEN: #74A800;--weui-LIGHTGREEN: #3EB575;--weui-TEXTGREEN: #259C5C;--weui-BRAND: #07C160;--weui-BLUE: #10AEFF;--weui-INDIGO: #1196FF;--weui-PURPLE: #8183FF;--weui-LINK: #7D90A9;--weui-REDORANGE: #FF6146;--weui-TAG-BACKGROUND-BLACK: rgba(255, 255, 255, .05);--weui-FG: #fff;--weui-WHITE: rgba(255, 255, 255, .8);--weui-FG-5: rgba(255, 255, 255, .1);--weui-TAG-BACKGROUND-ORANGE: rgba(250, 157, 59, .1);--weui-TAG-BACKGROUND-GREEN: rgba(6, 174, 86, .1);--weui-TAG-TEXT-RED: rgba(250, 81, 81, .6);--weui-TAG-BACKGROUND-RED: rgba(250, 81, 81, .1);--weui-TAG-BACKGROUND-BLUE: rgba(16, 174, 255, .1);--weui-TAG-TEXT-ORANGE: rgba(250, 157, 59, .6);--weui-BG: #000;--weui-TAG-TEXT-GREEN: rgba(6, 174, 86, .6);--weui-TAG-TEXT-BLUE: rgba(16, 174, 255, .6);--weui-TAG-TEXT-BLACK: rgba(255, 255, 255, .5)}.wx-root{position:relative;pointer-events:auto;font-family:system-ui,-apple-system,BlinkMacSystemFont,Helvetica Neue,PingFang SC,Hiragino Sans GB,Microsoft YaHei UI,Microsoft YaHei,Arial,sans-serif}.wx_card_root{position:relative}.wxw_hide{display:none!important}.wx_uninteractive{pointer-events:none}:host(.wx_tap_highlight_active) .wx_tap_link{opacity:.5}:host(.wx_tap_highlight_active) .wx_tap_card{background-color:#f3f3f3}:host(.wx_tap_highlight_active) .wx_tap_cell{background-color:#0000000d}@media (prefers-color-scheme: dark){:host(.wx_tap_highlight_active) .wx_tap_card{background-color:#252525}:host(.wx_tap_highlight_active) .wx_tap_cell{background-color:#ffffff1a}}.wx_css_active :active{opacity:.5}.wx_hover_card:before{content:" ";position:absolute;top:0;left:0;right:0;bottom:0;border-radius:8px;box-sizing:border-box;border:1px solid rgba(7,193,96,.3);pointer-events:none;z-index:9}.wx_selected_card:before{content:" ";position:absolute;top:0;left:0;right:0;bottom:0;border-radius:8px;border:1.5px solid #07C160;box-sizing:border-box;background:rgba(7,193,96,.1);pointer-events:none;z-index:9}.wx-root,body{--weui-BG-6: rgba(0, 0, 0, .05)}.wx-root[data-weui-theme=dark],body[data-weui-theme=dark]{--weui-BG-6: rgba(255, 255, 255, .1)}@media (prefers-color-scheme: dark){.wx-root:not([data-weui-theme=light]),body:not([data-weui-theme=light]){--weui-BG-6: rgba(255, 255, 255, .1)}}.point_event_no{pointer-events:none}.red_package_cover_wrp{-webkit-user-select:none;-moz-user-select:none;user-select:none;display:block;font-size:0;text-align:center}.red_package_cover_wrp.disabled .red_package_cover__inner{position:relative;cursor:default}.red_package_cover_wrp.disabled .red_package_cover__inner:after{border-radius:inherit;position:absolute;top:0;bottom:0;left:0;right:0;content:" ";display:block;height:100%;background-color:var(--weui-FG-1)}.red_package_cover_wrp.disabled .red_package_cover_disable_wording{display:block;text-align:center}.red_package_cover_wrp.common-redpacket-web .red_package_cover__inner{max-width:273px}.red_package_cover_wrp .red_package_cover__inner{position:relative;cursor:pointer;display:inline-block;font-size:17px;background:var(--weui-BG-3);border-radius:8px;max-width:300px;width:77%}.red_package_cover_wrp .red_package_cover__inner.red_package_cover__inner__loading{position:relative}.red_package_cover_wrp .red_package_cover__inner.red_package_cover__inner__loading:before{position:absolute;top:50%;left:50%;margin-top:-8px;margin-left:-8px;content:" ";display:block;width:16px;height:16px}.red_package_cover_wrp .red_package_cover__inner.red_package_cover__inner__loading .red_package_cover__inner__main,.red_package_cover_wrp .red_package_cover__inner.red_package_cover__inner__loading .red_package_cover__extend{opacity:0}.red_package_cover_wrp .red_package_cover__inner__main{width:300px;width:100%;padding:13.6% 0 8%}.red_package_cover_wrp .red_package_cover_img{position:relative;display:block;width:196px;height:324px;border-radius:5px;background-size:cover;background-repeat:no-repeat;background-position:center;margin:0 auto;width:65.33%;height:initial;padding-bottom:108%}.red_package_cover_wrp .red_package_cover_img.red_package_cover_img_loading{background-color:#00000008;position:relative}.wx-root[data-weui-theme=dark] .red_package_cover_wrp .red_package_cover_img.red_package_cover_img_loading,body[data-weui-theme=dark] .red_package_cover_wrp .red_package_cover_img.red_package_cover_img_loading{background-color:#ffffff08}@media (prefers-color-scheme: dark){.wx-root:not([data-weui-theme=light]) .red_package_cover_wrp .red_package_cover_img.red_package_cover_img_loading,body:not([data-weui-theme=light]) .red_package_cover_wrp .red_package_cover_img.red_package_cover_img_loading{background-color:#ffffff08}}.red_package_cover_wrp .red_package_cover_img.red_package_cover_img_loading:before{position:absolute;top:50%;left:50%;margin-top:-8px;margin-left:-8px;content:" ";display:block;width:16px;height:16px}.red_package_cover_wrp .red_package_cover_img.red_package_cover_img_loading:after{display:none}.red_package_cover_wrp .red_package_cover_img:after{content:" ";display:block;position:absolute;bottom:0;left:0;right:0;height:100%;background:url(data:image/png;base64,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) no-repeat center bottom;background-size:100% auto}.red_package_cover_wrp .red_package_cover_img.synthetic_cover_img{width:62.33%}.red_package_cover_wrp .red_package_cover_img.synthetic_cover_img:after{content:" ";display:block;position:absolute;bottom:9.3%;left:8px;right:8px;height:100%;background:url(data:image/png;base64,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CCCAAAIIIIDA0ggQAF6at5IbQQABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBVRcgALzqvwHcPwIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIILI0AAeCleSu5EQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQWHUBAsCr/hvA/SOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAwNIIEABemreSG0EAAQQQQAABBBBAAAEE/v/27t9FrvMKA/D97khCO2vFkXCZIjiFAiZJEdQkIYWjiNiFUwQhgwmGOJX/gATyBxh3cZVSjjHG2iwprEBkZEUBg13YlRJcLLhw4VIi2CuthezdL/dbsWK0Wml/arV7zrPNzM7cmbnvc073cmcIECBAgAABAgQIECBAgAABAtkFFMDZN0B+AgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgTCCCiAw4xSEAIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEsgsogLNvgPwECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECIQRUACHGaUgBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhkF1AAZ98A+QkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQCCOgAA4zSkEIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEMguoADOvgHyEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAQRkABHGaUghAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgkF1AAZx9A+QnQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCCMgAI4zCgFIUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgu4ACOPsGyE+AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQBgBBXCYUQpCgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEB2AQVw9g2QnwABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBMAIK4DCjFIQAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgewCCuDsGyA/AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJhBBTAYUYpCAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEC2QUUwNk3QH4CBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBMIIKIDDjFIQAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgSyCyiAs2+A/AQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIhBFQAIcZpSAECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECGQXUABn3wD5CRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAII6AADjNKQQgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQyC6gAM6+AfITIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIBBGQAEcZpSCECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECCQXUABnH0D5CdAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAIIyAAjjMKAUhQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCC7gAI4+wbIT4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAGAEFcJhRCkKAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQHYBBXD2DZCfAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIEwAgrgMKMUhAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACB7AIK4OwbID8BAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAmEEFMBhRikIAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQLZBRTA2TdAfgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEwggogMOMUhACBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBLILKICzb4D8BAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAiEEVAAhxmlIAQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIZBdQAGffAPkJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEAgjoAAOM0pBCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDILqAAzr4B8hMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgEEZAARxmlIIQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIJBdQAGcfQPkJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgjIACOMwoBSFAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAILuAAjj7BshPgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEAYAQVwmFEKQoAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAdgEFcPYNkJ8AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgTACCuAwoxSEAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHsAgrg7BsgPwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECYQQUwGFGKQgBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAtkFFMDZN0B+AgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgTCCCiAw4xSEAIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEsgsogLNvgPwECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECIQRUACHGaUgBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhkF1AAZ98A+QkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQCCOgAA4zSkEIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEMguoADOvgHyEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAQRkABHGaUghAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgkF1AAZx9A+QnQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCCMgAI4zCgFIUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgu4ACOPsGyE+AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQBgBBXCYUQpCgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEB2AQVw9g2QnwABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBMAIK4DCjFIQAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgewCCuDsGyA/AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJhBBTAYUYpCAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEC2QUUwNk3QH4CBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBMIIKIDDjFIQAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgSyCyiAs2+A/AQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIhBFQAIcZpSAECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECGQXUABn3wD5CRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAII6AADjNKQQgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQyC6gAM6+AfITIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIBBGQAEcZpSCECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECCQXUABnH0D5CdAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAIIyAAjjMKAUhQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCC7gAI4+wbIT4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAGAEFcJhRCkKAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQHYBBXD2DZCfAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIEwAgrgMKMUhAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACB7AIK4OwbID8BAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAmEEFMBhRikIAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQLZBRTA2TdAfgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEwggogMOMUhACBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBLILKICzb4D8BAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAiEEVAAhxmlIAQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIZBdQAGffAPkJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEAgjoAAOM0pBCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDILqAAzr4B8hMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgEEZAARxmlIIQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIJBdQAGcfQPkJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgjIACOMwoBSFAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAILuAAjj7BshPgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEAYAQVwmFEKQoAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAdgEFcPYNkJ8AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgTACCuAwoxSEAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHsAgrg7BsgPwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECYQQUwGFGKQgBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAtkFFMDZN0B+AgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgTCCCiAw4xSEAIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEsgsogLNvgPwECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECIQRUACHGaUgBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhkF1AAZ98A+QkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQCCOgAA4zSkEIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEMguoADOvgHyEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAQRkABHGaUghAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgkF1AAZx9A+QnQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCCMgAI4zCgFIUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgu4ACOPsGyE+AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQBgBBXCYUQpCgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEB2AQVw9g2QnwABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBMAIK4DCjFIQAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgewCCuDsGyA/AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJhBBTAYUYpCAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAEC2QUUwNk3QH4CBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBMIIKIDDjFIQAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgSyCyiAs2+A/AQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIhBFQAIcZpSAECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECGQXUABn3wD5CRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAII6AADjNKQQgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQyCLmaNcAAA67SURBVC6gAM6+AfITIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIBBGQAEcZpSCECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECCQXUABnH0D5CdAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAIIyAAjjMKAUhQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCC7gAI4+wbIT4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAGAEFcJhRCkKAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQHYBBXD2DZCfAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIEwAgrgMKMUhAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACB7AIK4OwbID8BAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAmEEFMBhRikIAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQLZBRTA2TdAfgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEwggogMOMUhACBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBLILKICzb4D8BAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAiEEVAAhxmlIAQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIZBdQAGffAPkJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEAgjoAAOM0pBCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDILqAAzr4B8hMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgEEZAARxmlIIQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIJBdQAGcfQPkJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgjIACOMwoBSFAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAILuAAjj7BshPgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEAYAQVwmFEKQoAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAdgEFcPYNkJ8AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgTACCuAwoxSEAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHsAgrg7BsgPwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECYQT6UsqtMGkEIUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQFKB1v32tXbzSfOLTYAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgTACrfsdrgCuCuAwIxWEAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIGsAq377WtXFMBZN0BuAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgTCCLTuty/VFcBhJioIAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJpBVr3264A/jytgOAECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAIItC63750ZS5IHjEIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECCQVqB1v33fLSmA066A4AQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIRBFo3W+/dKBXAEeZqBwECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECKQVaN1vPx5PzZWuq2kVBCdAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMA+F2idb+t++3L2/HxXypV9nsfpEyBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAIK/A0Pm27rdvArV2/84rITkBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgT2t8BK57tcAJdRvby/4zh7AgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQI5BVY6XyXC+DxgUPvl1IW83JIToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgf0p0Lre1vm2s799BfBbF76sXf1gf8Zx1gQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEMgr0LreMnS+TWC5AG53Su3fbLf+CBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGD/CEx2vXcK4HGps6V0N/dPDGdKgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACB3AKt421d74rCnQK4zF76otZyfuUJtwQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECCwtwVax9u63pWzvFMAtwdKX95YecItAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECOxtgdUdb5k83TrUwzdOn/zv8NhTk4+7T4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJ7TuCT6dlLPyil1JUzu/sK4OGJUSmvrDzplgABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgT2pkDrdifL33aWdxXA7YHD3dGZ4aBP231/BAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQILD3BFqn27rd1Wd2TwFcZmcXh1741dUH+p8AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE9opA/+rtbvfu87mnAG5Pj7vH/1pKd+XuQ/1HgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAo9aoHW5rdNd6zzWLIBbU1xGo5dL1935seC1XuwxAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIENg9gdbhLne5y9/sfO/nrlkAt8PG5y5+2HXl9Xtf4hECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQeDQC5fXbXe7an37fArgdPj449cehBL629ks9SoAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQK7J1Cu3e5w7/+JDyyAy9v/uFpG3Uv3f7lnCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGA3BFp32zrcB33WAwvg9sLpmUvvdH157UFv4jkCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQeJgC5c/L3e06H7FuAdxeP/3tJ/9QSvfROu/laQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDYYYHW1U4fe3L4+d71/8r6h9w+4qvnf/XdxcWvP+5q98RGX+M4AgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIENiGQOmujkYHT0yde/ezjbzLhq4Abm/U3rD03bNDu3x9I2/sGAIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDYukDrZltHu9Hyt33ShgvgdvD0zL8+rn3/m+GDvm7/+yNAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBnRdonWzrZltHu5l331QB3N74sZn3LpbSvzh8d3TdzAc5lgABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgTWF2hdbOtkWze7/tF3H7HpAri9fPy3994uff+CK4HvxvQfAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEtiPQOtjWxbZOdivvM5THW/+7fuaXp8rS0t9r7R7b+rt4JQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgM5e/19rXPW7nyd0VvWwVwe5MbZ35xoi51/xy+EPqJlTd1S4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKbECjd1dJ3z272N39Xf8KWvgJ68k3aCYxGB08MbfRHk4+7T4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQLrC7SutXWu2y1/2ydtuwBubzJ17t3Pxke/97OuL6+1//0RIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwAYEho61da2tc93A0esesu2vgF79CTfOnPz18JXQZ7taj61+zv8ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAg0ATKtTLqXpqeufTOTnrsyBXAkyfUTnD6wNTx0pWzQ7tcJ59znwABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABApkFWofautTpg1Pf3+nyt7nu+BXAk8NaeP7UT+ri4l9q7X40+bj7BAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQyCYw/NbvlTIavTw+d/HDh5V9x68AnjzRduLj7tiPSxn9vpTy6eRz7hMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCCDQOtKW2fautOHWf42y4d6BfDksOrp06Ob3f/OLNb6p+Hxpyafc58AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIBBT4ZlfLK4e7oTJmdXdyNfLtWAK+EqbWWhTOnnqlL9cVS6nPD10MfXnnOLQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBPazwPA1zzeHSvR86csb45mLF4arf+tu5tn1AngyXD198vGFWk7XsvTb4YeOfzqUw6PJ590nQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAXhcYSt7F2tUPSu3fHJc6W2YvffGozvmRFsCToesLz3xr4ZtbP6+L5emhBH+6q90Phyp8z5zf5Lm6T4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAXoGhxKxDk/mf4Urfy2VUL48PHHq/vHXhy70gsmcL1vq7544sLHx1vP9m6fhS1x8fGvPjpavfqaUcGW6PDJhHhsunh9t6aC9AOgcCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBPa/wHA1763hZ2znh4tW54eWd77U5dvPh280nuu7pbmlA/3ceDw1V86en9+Laf8P5hVEd79xD5kAAAAASUVORK5CYII=) no-repeat center bottom;background-size:100% auto}.red_package_cover_wrp .red_package_cover_img.red_package_open_cover_img:after{display:none}.red_package_cover_wrp .red_package_cover__foot{text-align:center;padding:8% 16px 0}.red_package_cover_wrp .red_package_cover__access-link{font-size:17px;line-height:1.4;font-weight:500;color:var(--weui-RED)}.red_package_cover_wrp .red_package_cover__access-link.disabled{color:var(--weui-FG-2)}.red_package_cover_wrp .red_package_cover__access-link.disabled:after{display:none}.red_package_cover_wrp .red_package_cover__access-link:after{content:"";display:inline-block;font-size:10px;width:1.2em;height:2.4em;margin-left:4px;margin-top:-.3em;vertical-align:middle;background:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMTJweCIgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMTIgMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDYxLjIgKDg5NjUzKSAtIGh0dHBzOi8vc2tldGNoLmNvbSAtLT4KICAgIDx0aXRsZT7liIfniYc8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBkPSJNNy41ODc1MDg3MywxMi40Mjk4OTE2IEw2LjUyNjg0ODU2LDEzLjQ5MDU1MTggTDAuNzQ3OTUxNTI2LDcuNzExNjU0NzMgQzAuMzU3ODI2MjI3LDcuMzIxNTI5NDMgMC4zNTQzNjU3ODYsNi42OTI0NzE3OSAwLjc0Nzk1MTUyNiw2LjI5ODg4NjA1IEw2LjUyNjg0ODU2LDAuNTE5OTg5MDE0IEw3LjU4NzUwODczLDEuNTgwNjQ5MTkgTDIuMTYyODg3NTMsNy4wMDUyNzAzOSBMNy41ODc1MDg3MywxMi40Mjk4OTE2IFoiIGlkPSJwYXRoLTEiPjwvcGF0aD4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSIzLkljb25zL091dGxpbmVkL2Fycm93Ij4KICAgICAgICAgICAgPGcgaWQ9Ikdyb3VwIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyLjAwMDAwMCwgNS4wMDAwMDApIj4KICAgICAgICAgICAgICAgIDxtYXNrIGlkPSJtYXNrLTIiIGZpbGw9IndoaXRlIj4KICAgICAgICAgICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICAgICAgPC9tYXNrPgogICAgICAgICAgICAgICAgPHVzZSBpZD0i5Zu+5qCH6aKc6ImyIiBmaWxsPSIjRkE1MTUxIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0LjAyMDc4NCwgNy4wMDUyNzApIHJvdGF0ZSgtMTgwLjAwMDAwMCkgdHJhbnNsYXRlKC00LjAyMDc4NCwgLTcuMDA1MjcwKSAiIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICA8L2c+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4=) no-repeat center;background-size:cover}.red_package_cover_wrp .red_package_cover__purchase{font-size:14px;font-weight:400;color:var(--weui-FG-2);margin-top:4px}.red_package_cover_wrp .red_package_cover__extend{display:flex;align-items:center;position:relative;line-height:1.4;padding:8px 16px;font-size:14px;color:var(--weui-FG-1);text-align:left}.red_package_cover_wrp .red_package_cover__extend:before{content:" ";position:absolute;top:0;left:16px;right:16px;height:1px;background-color:var(--weui-FG-3);transform:scaleY(.5);transform-origin:0 0;-webkit-transform:scaleY(.5);-webkit-transform-origin:0 0}.red_package_cover_wrp .red_package_cover__extend_icon{display:inline-block;vertical-align:middle;font-size:10px;width:1.6em;height:1.6em;margin-right:4px;background:url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M13.5 8.75149H12.0311C12.1352 8.54415 12.1938 8.30977 12.1938 8.06133C12.1938 7.21422 11.5121 6.52993 10.6741 6.52993C10.259 6.52993 9.86934 6.69916 9.58508 6.99323C8.72588 7.85576 8.3398 8.24353 8.00001 8.58458L6.3806 6.95894C6.09366 6.68304 5.72113 6.52993 5.32607 6.52993C4.48806 6.52993 3.80619 7.21422 3.80619 8.06133C3.80619 8.30977 3.86495 8.54415 3.96891 8.75149H2.50001V2.96628C2.50001 2.57865 2.76965 2.12287 3.11454 1.95118C3.11454 1.95118 3.14324 1.9352 3.23554 1.89586C4.52227 1.34706 6.18193 1 8.00001 1C9.81582 1 11.4782 1.33491 12.7595 1.89368C12.8369 1.92741 12.8815 1.94927 12.8815 1.94927C13.2231 2.12341 13.5 2.57879 13.5 2.96628V8.75149ZM13.5 9.59145V14.3C13.5 14.6875 13.1943 15 12.812 15H3.18804C2.808 15 2.5 14.6873 2.5 14.3V9.59145H5.2614C5.28287 9.59241 5.30446 9.59282 5.32606 9.59282H6.99551C6.41345 10.1719 5.51816 10.9309 4.31259 11.8659L4.81241 12.534C6.06655 11.5614 6.99726 10.7707 7.60789 10.1579L8 9.76423C8.11617 9.88088 8.2467 10.0119 8.4007 10.1663C9.00932 10.7774 9.93721 11.5654 11.1877 12.5342L11.6873 11.8657C10.4797 10.93 9.5844 10.1711 9.00449 9.59282H10.6741C10.6958 9.59282 10.7173 9.59241 10.7387 9.59145H13.5ZM10.7182 8.75143H9.00887L10.1688 7.58691C10.3036 7.44745 10.4821 7.36987 10.6742 7.36987C11.0592 7.36987 11.3688 7.68088 11.3688 8.06127C11.3688 8.42732 11.0825 8.72876 10.7182 8.75143ZM5.28211 8.75143C4.91777 8.72876 4.63136 8.42718 4.63136 8.06127C4.63136 7.68088 4.94111 7.36987 5.32611 7.36987C5.50895 7.36987 5.67945 7.43994 5.80796 7.56341C6.35675 8.11426 6.71506 8.47417 6.99127 8.75143H5.28211Z' fill='%23FA5151'/%3E%3C/svg%3E%0A") no-repeat 50% 50%;background-size:cover}.red_package_cover_wrp .red_package_cover_disable_wording{display:block;text-align:center;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:1;width:100%;color:#fff}.red_package_cover_wrp.small{width:100%}.red_package_cover_wrp.small .red_package_cover__inner{width:100%;max-width:382px}.red_package_cover_wrp.small .red_package_cover__inner__main{display:flex;flex-direction:row;align-items:center;justify-content:space-between;width:100%;padding:16px 16px 16px 24px;box-sizing:border-box}.red_package_cover_wrp.small .red_package_cover__body{flex-shrink:1;display:flex;flex-direction:row;align-items:center;min-width:0}.red_package_cover_wrp.small .red_package_cover__body span.title-wrp{flex-shrink:1;display:block;margin-left:16px;min-width:0;text-align:left;line-height:1.4}.red_package_cover_wrp.small .red_package_cover__body span.title{display:block;word-break:break-all;font-size:15px;font-weight:500;text-align:left;color:var(--weui-FG-0)}.red_package_cover_wrp.small .red_package_cover__body span.red_package_cover__purchase{display:block;margin-top:2px;font-size:12px;font-weight:400;color:var(--weui-FG-1)}.red_package_cover_wrp.small .red_package_cover_img{flex-shrink:0;height:44px;width:26.4px;margin:0;padding-bottom:unset;border-radius:1px}.red_package_cover_wrp.small .red_package_cover__foot{flex-shrink:0;padding:0;margin-left:16px}.red_package_cover_wrp.small .red_package_cover__access-link{font-size:14px;font-weight:500}.red_package_cover_wrp.small .red_package_cover__access-link.button{color:#fff;background-color:var(--weui-ORANGERED-100);border-radius:6px}.red_package_cover_wrp.small .red_package_cover__access-link.correct:before{position:relative;display:inline-block;content:"";margin-right:2px;font-size:16px;width:1em;height:1em;vertical-align:sub;background-color:currentColor;-webkit-mask-image:url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M5.77124 12.29L2 8.51879L2.94281 7.57598L6.24264 10.8758L13.7851 3.33334L14.7279 4.27614L6.71405 12.29C6.4537 12.5504 6.03159 12.5504 5.77124 12.29Z' fill='black' /%3E%3C/svg%3E%0A");mask-image:url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M5.77124 12.29L2 8.51879L2.94281 7.57598L6.24264 10.8758L13.7851 3.33334L14.7279 4.27614L6.71405 12.29C6.4537 12.5504 6.03159 12.5504 5.77124 12.29Z' fill='black' /%3E%3C/svg%3E%0A");-webkit-mask-size:contain;mask-size:contain;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center}.red_package_cover_wrp.small .red_package_cover__access-link:after{display:none}.red_package_cover_wrp.small .red_package_cover__extend{display:none} `, I = { errType: "data-errortype", name: "data-name", isSynthetic: "data-synthetic", imgSrc: "data-receiveimg", openImgSrc: "data-openimg", orderid: "data-orderid", coveruri: "data-coveruri", bizuin: "data-bizuin", status: "data-status", is_hover: "data-is-hover", is_selected: "data-is-selected", isPurchaseOrder: "data-is-purchase-order", smallCard: "data-small-card" }; function u(g) { let A = {}; return A = o$1.call(this, I), Object.keys(I).forEach((B) => { A[B] = decodeURIComponent(A[B] || ""), ["smallCard", "isSynthetic", "status", "is_hover", "is_selected", "isPurchaseOrder"].indexOf(B) > -1 && (A[B] = A[B] * 1); }), { platform: g, ...A }; } function o(g = {}) { k(Object.assign(g, { Component: g.isDev ? g.devComponent : r, styleText: g.isDev ? g.devStyleText : t, customName: g.customName || "mp-common-redpacket", watchAttr: [ "data-errortype", "data-status", "data-receiveimg", "data-synthetic", "data-openimg", "data-is-hover", "data-is-selected" ], getProps: u })); } var onceListeners = {}; var permanentListeners = {}; function clean(event, all) { delete onceListeners[event]; if (all) { delete permanentListeners[event]; } } function on(event, callback, permanent) { if (typeof callback === 'function') { if (permanent) { if (!permanentListeners[event]) { permanentListeners[event] = []; } permanentListeners[event].push(callback); } else { if (!onceListeners[event]) { onceListeners[event] = []; } onceListeners[event].push(callback); } } } function emit(event) { for (var _len = arguments.length, params = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { params[_key - 1] = arguments[_key]; } if (permanentListeners[event]) { permanentListeners[event].forEach(function (callback) { if (typeof callback === 'function') { callback.apply(void 0, params); } }); } if (onceListeners[event]) { onceListeners[event].forEach(function (callback) { if (typeof callback === 'function') { callback.apply(void 0, params); } }); clean(event); } } function remove(event, callback, permanent) { if (typeof callback === 'function') { if (permanent && permanentListeners[event]) { var idx = permanentListeners[event].indexOf(callback); if (idx !== -1) { permanentListeners[event].splice(idx, 1); } } else if (onceListeners[event]) { var _idx = onceListeners[event].indexOf(callback); if (_idx !== -1) { onceListeners[event].splice(_idx, 1); } } } } var eventBus = { on: on, emit: emit, remove: remove, clean: clean }; window.__page_cls_ctrl__canRenderSilently = '__page_cls_ctrl__canRenderSilently' in window ? window.__page_cls_ctrl__canRenderSilently : true; window.__page_cls_ctrl__forceRenderSilentlyList = '__page_cls_ctrl__forceRenderSilentlyList' in window ? window.__page_cls_ctrl__forceRenderSilentlyList : []; window.__page_cls_ctrl__compRenderInfo = '__page_cls_ctrl__compRenderInfo' in window ? window.__page_cls_ctrl__compRenderInfo : {}; var compRenderInfoInner = {}; var hasReportIdKey = false; function getCompId(renderInfo) { if (renderInfo.subCompType) { return "".concat(renderInfo.compType, "-").concat(renderInfo.compIdx, "-").concat(renderInfo.subCompType); } return "".concat(renderInfo.compType, "-").concat(renderInfo.compIdx); } function setForceRenderSilentlyList(list) { if (Array.isArray(list)) { var _window$__page_cls_ct; (_window$__page_cls_ct = window.__page_cls_ctrl__forceRenderSilentlyList).push.apply(_window$__page_cls_ct, _toConsumableArray(list)); } else if (Object.prototype.toString.call(list).includes('Number')) { window.__page_cls_ctrl__forceRenderSilentlyList.forceRenderSilentScrollTop = list; } } function setRenderSilentlyReadyStatus(status) { window.__page_cls_ctrl__canRenderSilently = status; } function emitRenderNewHeightEvt() { eventBus.emit('cls-render-new-height'); } function setCompRenderInfo(renderInfo, diffHeight) { window.__page_cls_ctrl__compRenderInfo[getCompId(renderInfo)] = { dh: diffHeight, compEle: renderInfo.compEle }; } function renderCompSilentlyPreHandler(renderInfo) { var wrapper = renderInfo.wrapper || renderInfo.compEle.parentNode || { scrollHeight: 0 }; compRenderInfoInner[getCompId(renderInfo)] = { beforeHeight: wrapper.scrollHeight, boundingRectTop: renderInfo.compEle.getBoundingClientRect().top, beforeScrollTop: document.body.scrollTop || document.documentElement.scrollTop, wrapper: wrapper }; } function renderCompSilently(renderInfo) { var compId = getCompId(renderInfo); if (!compRenderInfoInner[compId] || compRenderInfoInner[compId].beforeHeight === compRenderInfoInner[compId].wrapper.scrollHeight || !('compIdx' in renderInfo) || renderInfo.compIdx < 0) { return; } var diffHeight = compRenderInfoInner[compId].wrapper.scrollHeight - compRenderInfoInner[compId].beforeHeight; var autoScrollHeight = (document.body.scrollTop || document.documentElement.scrollTop) - compRenderInfoInner[compId].beforeScrollTop; emitRenderNewHeightEvt(); if ((compRenderInfoInner[compId].boundingRectTop < 0 || window.__page_cls_ctrl__forceRenderSilentlyList.includes(compId) || window.scrollY + compRenderInfoInner[compId].boundingRectTop < window.__page_cls_ctrl__forceRenderSilentlyList.forceRenderSilentScrollTop ) && window.__page_cls_ctrl__canRenderSilently && Math.ceil(autoScrollHeight) !== diffHeight && Math.floor(autoScrollHeight) !== diffHeight) { document.body.scrollTop = document.body.scrollTop + diffHeight; document.documentElement.scrollTop = document.documentElement.scrollTop + diffHeight; window.__addIdKeyReport && window.__addIdKeyReport(330742, 2); !hasReportIdKey && window.__addIdKeyReport && window.__addIdKeyReport(330742, 3); hasReportIdKey = true; } window.__page_cls_ctrl__compRenderInfo[compId] = { dh: diffHeight, compEle: renderInfo.compEle }; var newScrollTop = document.body.scrollTop || document.documentElement.scrollTop; for (var i in compRenderInfoInner) { if (!window.__page_cls_ctrl__compRenderInfo[i]) { compRenderInfoInner[i].beforeScrollTop = newScrollTop; } } } var pageClsCtrl = { compRenderInfo: window.__page_cls_ctrl__compRenderInfo, setForceRenderSilentlyList: setForceRenderSilentlyList, setRenderSilentlyReadyStatus: setRenderSilentlyReadyStatus, renderCompSilentlyPreHandler: renderCompSilentlyPreHandler, renderCompSilently: renderCompSilently, emitRenderNewHeightEvt: emitRenderNewHeightEvt, setCompRenderInfo: setCompRenderInfo }; function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } var ua = navigator.userAgent; var is_ios = /(iPhone|iPad|iPod|iOS)/i.test(ua); var is_wp = /Windows\sPhone/i.test(ua); var is_android = /(Android)/i.test(ua); var is_wechat = /MicroMessenger\/([\d\.]+)/i.test(ua); var is_mac = /mac\sos/i.test(ua) && !is_ios; var is_windows = /windows\snt/i.test(ua) && !is_wp; var is_mpapp = /MPAPP\/([\d\.]+)/i.test(ua); var is_ipad = /iPad/i.test(ua); var is_windows_wechat = /WindowsWechat/i.test(ua); var is_mac_wechat = /MacWechat/i.test(ua) || /wechat.*mac os/i.test(ua); var is_prefetch = is_wechat && window.WeixinPrefecherJSBridge; var is_donut_app = /SAAASDK/i.test(ua); var is_harmony = /OpenHarmony|ArkWeb/i.test(ua); var is_in_miniProgram = is_android && /miniprogram/.test(ua.toLowerCase()) || window.__wxjs_environment == 'miniprogram'; var is_wx_work = /wxwork/i.test(ua); function getUrlParams() { var vars = location.search.substring(1).split('&'); var params = {}; var _iterator = _createForOfIteratorHelper(vars), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var ele = _step.value; var pair = ele.split('='); var key = decodeURIComponent(pair[0]); if (typeof params[key] === 'undefined') { params[key] = decodeURIComponent(pair[1]); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return params; } function get() { var reg = /MicroMessenger\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMac() { var reg = /MacWechat\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMacOS() { var reg = /Mac OS X ([\d_]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1].replace(/_/g, '.'); } return false; } function getWindows() { var reg = /WindowsWechat\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getWxWork() { var reg = /wxwork\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMpApp() { var appVersion = [2, 4, 5]; var match = navigator.userAgent.match(/MPAPP\/(\d+(\.\d+)*)/); if (match) { appVersion = match[1].split('.').map(function (v) { return Number(v); }); } return appVersion.join('.'); } function getUnifiedPcVer() { var versionInfo = navigator.userAgent.match(/UnifiedPC\w+Wechat\(0xf\w{2}(\w+?)\w{2}\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(0, 1)); var subVersion = getVersionNumber(version.slice(1, 2)); var subVersion2 = getVersionNumber(version.slice(2, 3)); return [mainVersion, subVersion, subVersion2].join('.'); } } function getVersionNumber(hexStr) { return Number(Number("0x".concat(hexStr)).toString(10)); } function getWindowsVersionFormat() { var versionInfo = navigator.userAgent.match(/WindowsWechat\(0x(\w+?)\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(1, 2)); var subVersion = getVersionNumber(version.slice(2, 4)); var subVersion2 = getVersionNumber(version.slice(4, 6)); return [mainVersion, subVersion, subVersion2].join('.'); } return false; } function getInner() { var reg = /MicroMessenger\/[\d\.]+\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1] && ret[1] != null) { return ret[1]; } if (!ret && /MicroMessenger\/[\d\.]+/i.test(ua)) { var urlParams = getUrlParams(); if (urlParams.version) { return urlParams.version; } } return false; } var opfunc = { 'cp-1': function cp1(a, b) { return a < b; }, cp0: function cp0(a, b) { return a === b; }, cp1: function cp1(a, b) { return a > b; } }; function cpVersion(ver, op, canEq, type) { var mmver = false; switch (type) { case 'mac': mmver = getMac(); break; case 'windows': mmver = getWindowsVersionFormat(); break; case 'wxwork': mmver = getWxWork(); break; case 'mpapp': mmver = getMpApp(); break; case 'unifiedpc': mmver = getUnifiedPcVer(); break; default: mmver = get(); break; } if (!mmver) { return; } var mmversion = mmver.split('.'); var version = ver.split('.'); if (!/\d+/g.test(mmversion[mmversion.length - 1])) { mmversion.pop(); } for (var i = 0, len = Math.max(mmversion.length, version.length); i < len; ++i) { var mmv = mmversion[i] || ''; var v = version[i] || ''; var mmvn = parseInt(mmv, 10) || 0; var vn = parseInt(v, 10) || 0; var eq = opfunc.cp0(mmvn, vn); if (eq) { continue; } var cp = opfunc["cp".concat(op)]; return cp(mmvn, vn); } return canEq || op === 0; } function eqVersion(version) { return cpVersion(version, 0); } function gtVersion(version, canEq) { return cpVersion(version, 1, canEq); } function ltVersion(version, canEq) { return cpVersion(version, -1, canEq); } function getPlatform() { if (is_ios) { return 'ios'; } if (is_android) { return 'android'; } if (is_mac) { return 'mac_os'; } if (is_windows) { return 'windows'; } return 'unknown'; } var is_google_play = false; var inner_ver_for_google_play_check = getInner(); if (is_android && inner_ver_for_google_play_check) { var v = "0x".concat(inner_ver_for_google_play_check.substr(-2)); if (parseInt(v) >= 64 && parseInt(v) <= 79) { is_google_play = true; } } var MMVersion = { get: get, getMac: getMac, getMacOS: getMacOS, getWindows: getWindows, getInner: getInner, getWxWork: getWxWork, getMpApp: getMpApp, cpVersion: cpVersion, eqVersion: eqVersion, gtVersion: gtVersion, ltVersion: ltVersion, getPlatform: getPlatform, getVersionNumber: getVersionNumber, isWp: is_wp, isIOS: is_ios, isAndroid: is_android, isHarmony: is_harmony, isHarmonyWechat: is_harmony && is_wechat && cpVersion('1.0.0', 1, true), isInMiniProgram: is_in_miniProgram, isWechat: is_wechat, isMac: is_mac, isWindows: is_windows, isMacWechat: is_mac_wechat, isWindowsWechat: is_windows_wechat, isWxWork: is_wx_work, isOnlyWechat: is_wechat && !is_wx_work, isMpapp: is_mpapp, isNewMpApp: false, isIPad: is_ipad, isGooglePlay: is_google_play, isPrefetch: is_prefetch, isDonutAPP: is_donut_app }; var Device = {}; function detect(ua) { var MQQBrowser = ua.match(/MQQBrowser\/(\d+\.\d+)/i); var MQQClient = ua.match(/QQ\/(\d+\.(\d+)\.(\d+)\.(\d+))/i) || ua.match(/V1_AND_SQ_([\d\.]+)/); var WeChat = ua.match(/MicroMessenger\/((\d+)\.(\d+))\.(\d+)/) || ua.match(/MicroMessenger\/((\d+)\.(\d+))/); var MacOS = ua.match(/Mac\sOS\sX\s(\d+[\.|_]\d+)/); var WinOS = ua.match(/Windows(\s+\w+)?\s+?(\d+\.\d+)/); var Linux = ua.match(/Linux\s/); var MiuiBrowser = ua.match(/MiuiBrowser\/(\d+\.\d+)/i); var M1 = ua.match(/MI-ONE/); var MIPAD = ua.match(/MI PAD/); var UC = ua.match(/UCBrowser\/(\d+\.\d+(\.\d+\.\d+)?)/) || ua.match(/\sUC\s/); var IEMobile = ua.match(/IEMobile(\/|\s+)(\d+\.\d+)/) || ua.match(/WPDesktop/); var ipod = ua.match(/(ipod).*\s([\d_]+)/i); var ipad = ua.match(/(ipad).*\s([\d_]+)/i); var iphone = ua.match(/(iphone)\sos\s([\d_]+)/i); var Chrome = ua.match(/Chrome\/(\d+\.\d+)/); var AndriodBrowser = ua.match(/Mozilla.*Linux.*Android.*AppleWebKit.*Mobile Safari/); var android = ua.match(/(android)\s([\d\.]+)/i); var harmony = ua.match(/(OpenHarmony)\s([\d\.]+)/i); Device.browser = Device.browser || {}, Device.os = Device.os || {}; if (window.ActiveXObject) { var vie = 6; (window.XMLHttpRequest || ua.indexOf('MSIE 7.0') > -1) && (vie = 7); (window.XDomainRequest || ua.indexOf('Trident/4.0') > -1) && (vie = 8); ua.indexOf('Trident/5.0') > -1 && (vie = 9); ua.indexOf('Trident/6.0') > -1 && (vie = 10); Device.browser.ie = true, Device.browser.version = vie; } else if (ua.indexOf('Trident/7.0') > -1) { Device.browser.ie = true, Device.browser.version = 11; } if (android) { Device.os.android = true; Device.os.version = android[2]; } if (harmony) { Device.os.harmony = true; Device.os.version = harmony[2]; } if (ipod) { Device.os.ios = Device.os.ipod = true; Device.os.version = ipod[2].replace(/_/g, '.'); } if (ipad) { Device.os.ios = Device.os.ipad = true; Device.os.version = ipad[2].replace(/_/g, '.'); } if (iphone) { Device.os.iphone = Device.os.ios = true; Device.os.version = iphone[2].replace(/_/g, '.'); } if (WinOS) Device.os.windows = true, Device.os.version = WinOS[2]; if (MacOS) Device.os.Mac = true, Device.os.version = MacOS[1]; if (Linux) Device.os.Linux = true; if (ua.indexOf('lepad_hls') > 0) Device.os.LePad = true; if (MIPAD) Device.os.MIPAD = true; if (MQQBrowser) Device.browser.MQQ = true, Device.browser.version = MQQBrowser[1]; if (MQQClient) Device.browser.MQQClient = true, Device.browser.version = MQQClient[1]; if (WeChat) Device.browser.WeChat = true, Device.browser.mmversion = Device.browser.version = WeChat[1]; if (MiuiBrowser) Device.browser.MIUI = true, Device.browser.version = MiuiBrowser[1]; if (UC) Device.browser.UC = true, Device.browser.version = UC[1] || NaN; if (IEMobile) Device.browser.IEMobile = true, Device.browser.version = IEMobile[2]; if (AndriodBrowser) { Device.browser.AndriodBrowser = true; } if (M1) { Device.browser.M1 = true; } if (Chrome) { Device.browser.Chrome = true, Device.browser.version = Chrome[1]; } if (Device.os.windows) { if (typeof navigator.platform !== "undefined" && navigator.platform.toLowerCase() == "win64") { Device.os.win64 = true; } else { Device.os.win64 = false; } } if (Device.os.Mac || Device.os.windows || Device.os.Linux) { Device.os.pc = true; } var osType = { iPad7: 'iPad; CPU OS 7', LePad: 'lepad_hls', XiaoMi: 'MI-ONE', SonyDTV: "SonyDTV", SamSung: 'SAMSUNG', HTC: 'HTC', VIVO: 'vivo' }; for (var os in osType) { Device.os[os] = ua.indexOf(osType[os]) !== -1; } Device.os.phone = Device.os.phone || /windows phone/i.test(ua); Device.os.getNumVersion = function () { return parseFloat(Device.os.version); }; Device.os.hasTouch = 'ontouchstart' in window; if (Device.os.hasTouch && Device.os.ios && Device.os.getNumVersion() < 6) { Device.os.hasTouch = false; } if (Device.browser.WeChat && Device.browser.version < 5.0) { Device.os.hasTouch = false; } Device.browser.getNumVersion = function () { return parseFloat(Device.browser.version); }; Device.browser.isFFCanOcx = function () { return !!Device.browser.firefox && Device.browser.getNumVersion() >= 3.0; }; Device.browser.isCanOcx = function () { return !!Device.os.windows && (!!Device.browser.ie || Device.browser.isFFCanOcx() || !!Device.browser.webkit); }; Device.browser.isNotIESupport = function () { return !!Device.os.windows && (!!Device.browser.webkit || Device.browser.isFFCanOcx()); }; Device.userAgent = {}; Device.userAgent.browserVersion = Device.browser.version; Device.userAgent.osVersion = Device.os.version; Device.os.unifiedPC = ua.match(/UnifiedPC/); delete Device.userAgent.version; } detect(window.navigator.userAgent); function canSupportH5Video() { var ua = window.navigator.userAgent, m = null; if (!!Device.os.android) { if (Device.browser.MQQ && Device.browser.getNumVersion() >= 4.2) { return true; } if (ua.indexOf('MI2') != -1) { return true; } if (Device.os.version >= '4' && (m = ua.match(/MicroMessenger\/((\d+)\.(\d+))\.(\d+)/))) { if (parseFloat(m[1]) >= 4.2) { return true; } } if (Device.os.version >= '4.1') { return true; } } return false; } function canSupportVideoMp4() { var video = document.createElement('video'); if (typeof video.canPlayType === 'function') { if (video.canPlayType('video/mp4; codecs="mp4v.20.8"') === 'probably') { return true; } if (video.canPlayType('video/mp4; codecs="avc1.42E01E"') === 'probably' || video.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"') === 'probably') { return true; } } return false; } function canSupportAutoPlay() { if (Device.os.ios && Device.os.getNumVersion() < 10) { return false; } return true; } function isLockdownMode() { if (!Device.os.ios || Device.os.getNumVersion() < 16) { return false; } if (typeof WebAssembly === 'undefined' && typeof OfflineAudioContext === 'undefined' && typeof WebGLRenderingContext === 'undefined') { return true; } return false; } Device.canSupportVideo = canSupportVideoMp4 || canSupportH5Video; Device.canSupportVideoMp4 = canSupportVideoMp4; Device.canSupportH5Video = canSupportH5Video; Device.canSupportAutoPlay = canSupportAutoPlay; Device.isLockdownMode = isLockdownMode; Device.cpVersion = function (version) { var cp = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; var canEqual = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; var nowVersionStr = Device.os.version; if (!nowVersionStr) return false; var versionArr = version.split('.'); var nowVersionArr = nowVersionStr.split('.'); for (var i = 0; i < Math.max(nowVersionArr.length, versionArr.length); i++) { var vi = +versionArr[i]; var nvi = +nowVersionArr[i]; if (vi === nvi) continue; if (cp > 0) return vi > nvi; if (cp < 0) return vi < nvi; } return canEqual || cp === 0; }; var isWp = MMVersion.isWp, isIOS = MMVersion.isIOS, isAndroid = MMVersion.isAndroid, isInMiniProgram = MMVersion.isInMiniProgram, isWechat = MMVersion.isWechat, isMac = MMVersion.isMac, isWindows = MMVersion.isWindows, isMacWechat = MMVersion.isMacWechat, isWindowsWechat = MMVersion.isWindowsWechat, isWxWork = MMVersion.isWxWork, isMpapp = MMVersion.isMpapp, isIPad = MMVersion.isIPad; var commonCompOpts = { platform: 'wechat', extraInfo: { system: { isWp: isWp, isIOS: isIOS, isAndroid: isAndroid, isInMiniProgram: isInMiniProgram, isWechat: isWechat, isMac: isMac, isWindows: isWindows, isMacWechat: isMacWechat, isWindowsWechat: isWindowsWechat, isWxWork: isWxWork, isMpapp: isMpapp, isIPad: isIPad }, device: Device.os }, beforeRender: function beforeRender(data) { pageClsCtrl.renderCompSilentlyPreHandler(data); }, afterRender: function afterRender(data) { pageClsCtrl.renderCompSilently(data); } }; var allRegisterdTags = []; function initOpts() { var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; if (opts.selector) { var selectors = opts.selector.split(','); allRegisterdTags.push.apply(allRegisterdTags, _toConsumableArray(selectors)); } return Object.assign(opts, commonCompOpts); } if (!customElements.get('mp-common-product')) { b(initOpts({ reflowProps: ['customstyle'] })); } if (!customElements.get('mp-common-redpacket')) { o(initOpts({ selector: 'mp-common-redpacket' })); } if (window.__listenMobileClick__) { window.__listenMobileClick__(allRegisterdTags); } else { window.__listenMobileClick__task__ = window.__listenMobileClick__task__ || []; window.__listenMobileClick__task__.push(allRegisterdTags); } })();</script><script type="text/javascript" nonce="1989770072" reportloaderror>(function () { 'use strict'; function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } var containers = [document.getElementById('page-content')]; var bgPlaceholder = 'url("data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==")'; var isCareMode = window.a_value_which_never_exists || '' * 1 || 0; var isCartoonCopyright = window.a_value_which_never_exists || '0' * 1 || 0; if (!window.__second_open__ && !isCareMode && !isCartoonCopyright) { containers.forEach(function (dom) { var containsBackground = dom.querySelectorAll('[style*="background-image"]'); _toConsumableArray(containsBackground).forEach(function (node) { if (node && node.style && typeof node.getAttribute === 'function' && !node.getAttribute('data-lazy-bgimg') && !window.__lazyload_detected) { var bgImg = node.style.backgroundImage; var bgImgUrl = bgImg && bgImg.match(/url\(['"]?(.*?)['"]?\)/); if (bgImgUrl && bgImgUrl[1]) { node.style.backgroundImage = bgImg.replace(/url\(['"]?.*?['"]?\)/, bgPlaceholder); node.setAttribute('data-lazy-bgimg', bgImgUrl[1]); node.classList.add('wx_imgbc_placeholder'); } } }); }); } })();</script><script type="text/javascript" nonce="1989770072" reportloaderror>var __INLINE_SCRIPT__ = (function () { 'use strict'; var __setTitle = function __setTitle(showTitle, dom) { var title = showTitle; if (showTitle.indexOf('——') > -1) { var replaceHtml = '<span style="letter-spacing:normal">——</span>'; showTitle = showTitle.replace(/——/g, replaceHtml); } if (dom) { dom.innerHTML = dom.innerHTML.replace(title, showTitle); } }; if (!window.__second_open__) { var title = '震惊!用 Redis+AI 模型实现秒级实时风控,这波操作太秀了'; __setTitle(title, document.getElementById('activity-name')); window.__setTitle = __setTitle; } return __setTitle; })();</script><script type="text/javascript" nonce="1989770072" reportloaderror>var __INLINE_SCRIPT__ = (function () { 'use strict'; var __setPubTime = function __setPubTime(svrTime, oriCreateTime, createTime, dom) { var oriTimestamp = oriCreateTime * 1; var dateObj = new Date(oriTimestamp * 1000); var padStart = function padStart(v) { return "0".concat(v).slice(-2); }; var year = dateObj.getFullYear(); var month = padStart(dateObj.getMonth() + 1); var date = padStart(dateObj.getDate()); var hour = padStart(dateObj.getHours()); var minute = padStart(dateObj.getMinutes()); var timeString = "".concat(hour, ":").concat(minute); var dateString = "".concat(year, "年").concat(month, "月").concat(date, "日"); var showDate = "".concat(dateString, " ").concat(timeString); if (dom) { dom.innerText = showDate; } }; if (!window.__second_open__) { var svrDate = '1743644973'; var oriCreateTime = '1743643844'; var createTime = '2025-04-03 09:30'; __setPubTime(svrDate, oriCreateTime, createTime, document.getElementById('publish_time')); window.__setPubTime = __setPubTime; } return __setPubTime; })();</script> <script type="text/javascript" nonce="1989770072" reportloaderror> if (!window.console) window.console = { log: function() {} }; if (typeof getComputedStyle == 'undefined') { if (document.body.currentStyle) { window.getComputedStyle = function(el) { return el.currentStyle; } } else { window.getComputedStyle = {}; } } (function(){ window.__zoom = 1; var ua = navigator.userAgent.toLowerCase(); var re = new RegExp("msie ([0-9]+[\.0-9]*)"); var version; if (re.exec(ua) != null) { version = parseInt(RegExp.$1); } var isIE = false; if (typeof version != 'undefined' && version >= 6 && version <= 9) { isIE = true; } var isAccessibilityKey = 'isMpUserAccessibility'; var isAccessMode = window.localStorage.getItem(isAccessibilityKey); var isCarton = isIE || '0' === '1' || '' === '1' || isAccessMode === '1'; var bodyWidth = '' * 1; if (bodyWidth) { var styles = getComputedStyle(document.getElementById('page-content')); bodyWidth - parseFloat(styles.paddingLeft) - parseFloat(styles.paddingRight); } var getMaxWith = function () { var container = document.getElementById('img-content'); var max_width = container.offsetWidth; !max_width && bodyWidth && (max_width = bodyWidth); var container_padding = 0; var container_style = getComputedStyle(container); container_padding = parseFloat(container_style.paddingLeft) + parseFloat(container_style.paddingRight); max_width -= container_padding; if (!max_width) { max_width = window.innerWidth - 30; } return max_width; }; var getParentWidth = function (dom) { var parent_width = 0; var parent = dom.parentNode; var outerWidth = 0; while (true) { if (!parent || parent.nodeType != 1) break; var parent_style = getComputedStyle(parent); if (!parent_style) break; parent_width = parent.clientWidth - parseFloat(parent_style.paddingLeft) - parseFloat(parent_style.paddingRight) - outerWidth; if (parent_width > 16) break; outerWidth += parseFloat(parent_style.paddingLeft) + parseFloat(parent_style.paddingRight) + parseFloat(parent_style.marginLeft) + parseFloat(parent_style.marginRight) + parseFloat(parent_style.borderLeftWidth) + parseFloat(parent_style.borderRightWidth); parent = parent.parentNode; } return parent_width; } var getOuterW = function (dom) { var style = getComputedStyle(dom), w = 0; if (!!style) { w = parseFloat(style.paddingLeft) + parseFloat(style.paddingRight) + parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth); } return w; }; var getOuterH = function (dom) { var style = getComputedStyle(dom), h = 0; if (!!style) { h = parseFloat(style.paddingTop) + parseFloat(style.paddingBottom) + parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth); } return h; }; var insertAfter = function (dom, afterDom) { var _p = afterDom.parentNode; if (!_p) { return; } if (_p.lastChild === afterDom) { _p.appendChild(dom); } else { _p.insertBefore(dom, afterDom.nextSibling); } }; var getQuery = function (name, url) { var u = arguments[1] || window.location.search, reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"), r = u.substr(u.indexOf("\?") + 1).match(reg); return r != null ? r[2] : ""; }; function setImgSize(item, widthNum, widthUnit, ratio, breakParentWidth) { setTimeout(function () { var img_padding_border = getOuterW(item) || 0; var img_padding_border_top_bottom = getOuterH(item) || 0; if (widthNum > getParentWidth(item) && !breakParentWidth) { widthNum = getParentWidth(item); } var height = (widthNum - img_padding_border) * ratio + img_padding_border_top_bottom; if (isCarton) { var url = item.getAttribute('src'); item.src = url; item.style.height = 'auto'; } else { widthNum !== 'auto' && (item.style.cssText += ";width: " + widthNum + widthUnit + " !important;"); widthNum !== 'auto' && (item.style.cssText += ";height: " + height + widthUnit + " !important;"); } }, 10); } window.__videoDefaultRatio = 16 / 9;//默认值是16/9 window.__getVideoWh = function (dom) { var max_width = getMaxWith(), width = max_width, ratio_ = dom.getAttribute('data-ratio') * 1,//mark16/9 arr = [4 / 3, 16 / 9], ret = arr[0], abs = Math.abs(ret - ratio_); if (!ratio_) { if (dom.getAttribute("data-mpvid")) { ratio_ = 16 / 9; } else { ratio_ = 4 / 3; } } else { for (var j = 1, jl = arr.length; j < jl; j++) { var _abs = Math.abs(arr[j] - ratio_); if (_abs < abs) { abs = _abs; ret = arr[j]; } } ratio_ = ret; } var parent_width = getParentWidth(dom) || max_width, width = width > parent_width ? parent_width : width, outerW = getOuterW(dom) || 0, outerH = getOuterH(dom) || 0, videoW = width - outerW, videoH = videoW / ratio_, speedDotH = 12, height = videoH + outerH + speedDotH; return { w: Math.ceil(width), h: Math.ceil(height), vh: videoH, vw: videoW, ratio: ratio_, sdh: speedDotH }; }; (function () { var iframe = document.getElementsByTagName('iframe'); for (var i = 0, il = iframe.length; i < il; i++) { if (window.__second_open__ && iframe[i].getAttribute('__sec_open_place_holder__')) { continue; } var a = iframe[i]; var src_ = a.getAttribute('src') || a.getAttribute('src') || ""; var vid = getQuery("vid", src_) || a.getAttribute('data-mpvid'); if (!vid) { continue; } vid = vid.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "");//清除前后空格 a.removeAttribute('src'); a.style.display = "none"; var obj = window.__getVideoWh(a), videoPlaceHolderSpan = document.createElement('span'); videoPlaceHolderSpan.className = "js_img_placeholder wx_widget_placeholder"; videoPlaceHolderSpan.setAttribute("data-vid", vid); videoPlaceHolderSpan.innerHTML = '<span class="weui-primary-loading"><span class="weui-primary-loading__dot"></span></span>'; videoPlaceHolderSpan.style.cssText = "width: " + obj.w + "px !important;"; insertAfter(videoPlaceHolderSpan, a); var mid = "" || "" || "2247616950"; var biz = "" || "MzU0OTk3ODQ3Ng=="; var sessionid = "" || "svr_5fc3db74245"; var idx = "" || "1"; var hitInfos = [ ]; (function setHitStyle(parentNode, copyIframe, index, vid) { var ret = (hitInfos || []).find(function (info) { return info.video_id === vid; } ); if (!ret) return; var ori = ret.ori_status; var hit_biz_headimg = ret.hit_biz_headimg + '/64'; var hit_nickname = ret.hit_nickname; var hit_username = ret.hit_username; var sourceBiz = ret.hit_bizuin; var selfUserName = "gh_6258c101a32a"; if (ori === 2 && selfUserName !== hit_username) { var videoBar = document.createElement('div'); var videoBarHtml = '<div class="wx-edui-video_source_link js_wx_tap_highlight wx_tap_card" id="' + (hit_username + index) + '" data-hit-username="' + hit_username + '" data-hit-biz="' + sourceBiz + '">'; videoBarHtml += '<div class="wx-edui-video_source_word">以下视频来源于</div>'; videoBarHtml += '<div class="wx-edui-video_account_info">'; videoBarHtml += '<div class="wx-edui-video_account_avatar" id="' + (hit_biz_headimg + index) + '" src="' + hit_biz_headimg + '"></div>'; videoBarHtml += '<div class="wx-edui-video_account_name">' + hit_nickname + '</div>'; videoBarHtml += '<i class="wx-edui-video_account_arrow"></i>'; videoBarHtml += '</div>'; videoBarHtml += '<div class="wx-edui-video_source_link__layer_mask"></div>'; videoBarHtml += '</div>'; videoBar.innerHTML = videoBarHtml; var spanContainer = document.getElementById('js_mp_video_container_' + index); if (spanContainer) { spanContainer.parentNode.insertBefore(videoBar, spanContainer); } else if (parentNode.contains && parentNode.contains(copyIframe)) { parentNode.insertBefore(videoBar, copyIframe); } else { parentNode.insertBefore(videoBar, parentNode.firstElementChild); } var avatorEle = document.getElementById(hit_biz_headimg + index); var avatorSrc = avatorEle.dataset.src; console.log('avatorSrc' + avatorSrc); if (ret.hit_biz_headimg) { avatorEle.style.backgroundImage = 'url(' + avatorSrc + ')'; } } })(a.parentNode, a, i, vid); a.style.cssText += ";width: " + obj.w + "px !important;"; a.setAttribute("width", obj.w); if (window.__zoom != 1) { a.style.display = "block"; videoPlaceHolderSpan.style.display = "none"; a.setAttribute("_ratio", obj.ratio); a.setAttribute("_vid", vid); } else { videoPlaceHolderSpan.style.cssText += "height: " + (obj.h - obj.sdh) + "px !important;margin-bottom: " + obj.sdh + "px !important;"; a.style.cssText += "height: " + obj.h + "px !important;"; a.setAttribute("height", obj.h); } a.setAttribute("data-vh", obj.vh); a.setAttribute("data-vw", obj.vw); if (a.getAttribute("data-mpvid")) { a.setAttribute("src", location.protocol + "//mp.weixin.qq.com/mp/readtemplate?t=pages/video_player_tmpl&auto=0&vid=" + vid); } else { a.setAttribute("src", location.protocol + "//v.qq.com/iframe/player.html?vid=" + vid + "&width=" + obj.vw + "&height=" + obj.vh + "&auto=0"); } } })(); (function () { if (window.__zoom != 1) { if (!window.__second_open__) { document.getElementById('page-content').style.zoom = window.__zoom; var a = document.getElementById('activity-name'); var b = document.getElementById('meta_content'); if (!!a) { a.style.zoom = 1 / window.__zoom; } if (!!b) { b.style.zoom = 1 / window.__zoom; } } var images = document.getElementsByTagName('img'); for (var i = 0, il = images.length; i < il; i++) { if (window.__second_open__ && images[i].getAttribute('__sec_open_place_holder__')) { continue; } images[i].style.zoom = 1 / window.__zoom; } var iframe = document.getElementsByTagName('iframe'); for (var i = 0, il = iframe.length; i < il; i++) { if (window.__second_open__ && iframe[i].getAttribute('__sec_open_place_holder__')) { continue; } var a = iframe[i]; a.style.zoom = 1 / window.__zoom; var src_ = a.getAttribute('src') || ""; if (!/^http(s)*\:\/\/v\.qq\.com\/iframe\/(preview|player)\.html\?/.test(src_) && !/^http(s)*\:\/\/mp\.weixin\.qq\.com\/mp\/readtemplate\?t=pages\/video_player_tmpl/.test(src_) ) { continue; } var ratio = a.getAttribute("_ratio"); var vid = a.getAttribute("_vid"); a.removeAttribute("_ratio"); a.removeAttribute("_vid"); var vw = a.offsetWidth - (getOuterW(a) || 0); var vh = vw / ratio; var h = vh + (getOuterH(a) || 0) a.style.cssText += "height: " + h + "px !important;" a.setAttribute("height", h); if (/^http(s)*\:\/\/v\.qq\.com\/iframe\/(preview|player)\.html\?/.test(src_)) { a.setAttribute("src", location.protocol + "//v.qq.com/iframe/player.html?vid=" + vid + "&width=" + vw + "&height=" + vh + "&auto=0"); } a.style.display = "none"; var parent = a.parentNode; if (!parent) { continue; } for (var j = 0, jl = parent.children.length; j < jl; j++) { var child = parent.children[j]; if (child.className.indexOf("js_img_placeholder") >= 0 && child.getAttribute("data-vid") == vid) { child.style.cssText += "height: " + h + "px !important;"; child.style.display = ""; } } } } })(); })(); var anchor_tree_msg = ''; </script> <script type="text/javascript" nonce="1989770072" reportloaderror>(function () { 'use strict'; var _Speed = {}; var _userDefine; var _imgurl = 'https://badjs.weixinbridge.com/frontend/reportspeed?'; function saveSpeeds$1(obj) { if (!obj.pid || !obj.speeds) { return -1; } if (!Array.isArray(obj.speeds)) { obj.speeds = [obj.speeds]; } if (obj.user_define) { _userDefine = obj.user_define; } var pid_uin_rid = _conbinUPRid(obj); for (var i = 0; i < obj.speeds.length; i++) { var os = obj.speeds[i]; os.time = Math.floor(+os.time); if (os.sid > 20 && os.time >= 0) _setSidTime(pid_uin_rid, os.sid, os.time); } } function send$1() { _doFunc(function () { setTimeout(function () { for (var item in _Speed) { _get({ pid_uin_rid: item, speeds: _Speed[item], user_define: _userDefine }, _imgurl); } _Speed = {}; }, 100); }); } function setFirstViewTime(obj) { _doFunc(function () { if (!obj.pid || !obj.time) return -1; var pid_uin_rid = _conbinUPRid(obj); _setSidTime(pid_uin_rid, 9, obj.time); }); } function setBasicTime$1(obj) { _doFunc(function () { var pid_uin_rid = _conbinUPRid(obj); if (!_Speed[pid_uin_rid]) _Speed[pid_uin_rid] = []; var performance = window.performance || window.msPerformance || window.webkitPerformance || {}; if (!!performance && !!performance.timing) { var timing = performance.timing || {}; _setSidTime(pid_uin_rid, 1, timing.domainLookupEnd - timing.domainLookupStart); _setSidTime(pid_uin_rid, 2, location.protocol == "https:" && timing.secureConnectionStart != 0 ? timing.connectEnd - timing.secureConnectionStart : 0); _setSidTime(pid_uin_rid, 3, timing.connectEnd - timing.connectStart); _setSidTime(pid_uin_rid, 4, timing.responseStart - timing.requestStart); _setSidTime(pid_uin_rid, 5, timing.responseEnd - timing.responseStart); _setSidTime(pid_uin_rid, 6, timing.domContentLoadedEventStart - timing.domLoading); _setSidTime(pid_uin_rid, 7, timing.domComplete == 0 ? 0 : timing.domComplete - timing.domLoading); _setSidTime(pid_uin_rid, 8, timing.loadEventEnd == 0 ? 0 : timing.loadEventEnd - timing.loadEventStart); (function (_Speed) { setTimeout(function () { if (timing.loadEventEnd) { _setSidTime(pid_uin_rid, 7, timing.domComplete == 0 ? 0 : timing.domComplete - timing.domLoading); _setSidTime(pid_uin_rid, 8, timing.loadEventEnd == 0 ? 0 : timing.loadEventEnd - timing.loadEventStart); } }, 0); })(); if (!_Speed[pid_uin_rid][9]) _setSidTime(pid_uin_rid, 9, timing.domContentLoadedEventStart - timing.navigationStart); _setSidTime(pid_uin_rid, 10, timing.redirectEnd - timing.redirectStart); _setSidTime(pid_uin_rid, 11, timing.domainLookupStart - timing.fetchStart); _setSidTime(pid_uin_rid, 12, timing.domLoading - timing.responseStart); } }); } function _setSidTime(pid_uin_rid, sid, time) { _Speed[pid_uin_rid] = _Speed[pid_uin_rid] || []; _Speed[pid_uin_rid][sid] = _Speed[pid_uin_rid][sid] || []; if (time < 0) return; if (sid < 21) _Speed[pid_uin_rid][sid][0] = time;else _Speed[pid_uin_rid][sid].push(time); } function _conbinUPRid(obj) { if (!obj || !obj.pid) { console && console.error('Must provide a pid'); return ''; } return "".concat(obj.pid, "_").concat(obj.uin || 0, "_").concat(obj.rid || 0); } function _get(obj, url) { var apur = obj.pid_uin_rid.split('_'); var spur = ''; if (apur.length == 3) { spur = "pid=".concat(apur[0], "&uin=").concat(apur[1], "&rid=").concat(apur[2]); } else { console && console.error('pid,uin,rid, invalid args'); return; } if (obj.user_define) { spur += "&user_define=".concat(obj.user_define); } var url1 = "".concat(url + spur, "&speeds="); var url2 = ''; var urlarr = []; for (var i = 1; i < obj.speeds.length; i++) { if (obj.speeds[i]) { for (var j = 0; j < obj.speeds[i].length; j++) { var s = "".concat(i, "_").concat(obj.speeds[i][j]); if (url1.length + url2.length + s.length < 1024) { url2 = "".concat(url2 + s, ";"); } else { if (url2.length) urlarr.push(url1 + url2.substring(0, url2.length - 1)); url2 = "".concat(s, ";"); } } if (i == obj.speeds.length - 1) { urlarr.push(url1 + url2.substring(0, url2.length - 1)); } } } for (var _i = 0; _i < urlarr.length; _i++) { new Image().src = urlarr[_i]; } } var cblist = []; function _doFunc(fnc) { if (document.readyState == "complete") { fnc(); } else { cblist.push(fnc); } } window.addEventListener('load', onLoad, false); function onLoad() { for (var i = 0; i < cblist.length; i++) { cblist[i](); } cblist = []; } var wxgsdk = { saveSpeeds: saveSpeeds$1, send: send$1, setFirstViewTime: setFirstViewTime, setBasicTime: setBasicTime$1 }; var reportLogs = []; var reportExtraLogs = []; var sendUrl = '/mp/jsmonitor?#wechat_redirect'; var monitor = {}; monitor._reportOptions = { idkey: {} }; function ObjWithoutProperty(source, exclude) { if (source === null) return {}; var target = {}; var sourceKeys = Object.keys(source); for (var i = 0; i < sourceKeys.length; i++) { var key = sourceKeys[i]; if (exclude.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function formatDataToString(data) { var reportData = []; for (var key in data) { if (Object.prototype.hasOwnProperty.call(data, key)) { reportData.push(key + '=' + encodeURIComponent(data[key])); } } return reportData.join('&'); } monitor.getReportData = function (opt) { opt = opt || {}; var idkey = monitor._reportOptions.idkey || {}; var key = null; var reportData = {}; var nextKey; try { for (key in idkey) { if (Object.prototype.hasOwnProperty.call(idkey, key) && idkey[key]) { reportLogs.push(key + '_' + idkey[key]); } } } catch (e) { return false; } if (reportLogs.length === 0) { return false; } if (reportExtraLogs.length) { reportData.lc = reportExtraLogs.length; reportExtraLogs.forEach(function (extraLog, index) { reportData["log".concat(index)] = extraLog; }); } try { var reportOptions = monitor._reportOptions; if (reportOptions !== null && reportOptions !== undefined) { for (nextKey in reportOptions) { if (Object.prototype.hasOwnProperty.call(reportOptions, nextKey)) { reportData[nextKey] = reportOptions[nextKey]; } } } } catch (e) { reportData = {}; } reportData.idkey = reportLogs.join(';'); reportData.t = Math.random(); if (opt.remove !== false) { reportLogs = []; reportExtraLogs = []; monitor._reportOptions = { idkey: {} }; } return reportData; }; monitor.setLogs = function (opt) { var id = opt.id; var key = opt.key; var value = opt.value; var extraLog = opt.log; var others = ObjWithoutProperty(opt, ['id', 'key', 'value', 'log']); var idkey = monitor._reportOptions.idkey || {}; var param = id + '_' + key; if (idkey[param]) { idkey[param] += value; } else { idkey[param] = value; } monitor._reportOptions.idkey = idkey; if (extraLog) { reportExtraLogs.push(extraLog); } try { if (others !== null && others !== undefined) { for (var otherKey in others) { if (Object.prototype.hasOwnProperty.call(others, otherKey)) { monitor._reportOptions[otherKey] = others[otherKey]; } } } } catch (e) { console.log(e); } return monitor; }; monitor.setAvg = function (id, key, value) { var idkey = monitor._reportOptions.idkey || {}; var param1 = id + '_' + key; var param2 = id + '_' + (key - 1); if (idkey[param1]) { idkey[param1] += value; } else { idkey[param1] = value; } if (idkey[param2]) { idkey[param2] += 1; } else { idkey[param2] = 1; } monitor._reportOptions.idkey = idkey; return monitor; }; monitor.setSum = function (id, key) { var value = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; var idkey = monitor._reportOptions.idkey; var param = id + '_' + key; if (idkey[param]) { idkey[param] += value; } else { idkey[param] = value; } monitor._reportOptions.idkey = idkey; return monitor; }; monitor.send = function (async, ajax, origin) { if (async !== false) { async = true; } var data = monitor.getReportData(); origin = origin || ''; if (!data) { return; } if (!!ajax && ajax instanceof Function) { ajax({ url: origin + sendUrl, type: 'POST', mayAbort: true, data: data, async: async, timeout: 2000 }); } else { new Image().src = origin + '/mp/jsmonitor?' + formatDataToString(data) + '#wechat_redirect'; } }; if (typeof window !== 'undefined' && window.__monitor) { monitor = window.__monitor; } else { typeof window !== 'undefined' && (window.__monitor = monitor); } var monitor$1 = monitor; function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var logList = []; var log = function log(msg) { logList.push(msg); }; var printLog = function printLog() { for (var i = 0, len = logList.length; i < len; ++i) { console.log("[RespType]".concat(logList[i])); } }; var isArray = function isArray(val) { return Object.prototype.toString.call(val) === '[object Array]'; }; var getValueType = function getValueType(value) { if (isArray(value)) { return 'array'; } return _typeof(value); }; var parseRtDesc = function parseRtDesc(rtDesc, k) { var type = 'mix'; var isRequired = false; var key = k; if (k) { var requireKeyWord = '_R'; var pos = k.indexOf(requireKeyWord); var len = k.length - requireKeyWord.length; isRequired = pos !== -1 && pos === len; key = isRequired ? k.substring(0, len) : k; } if (typeof rtDesc === 'string') { type = rtDesc; } else if (isArray(rtDesc)) { type = 'array'; } else if (_typeof(rtDesc) === 'object') { type = 'object'; } return { key: key, type: type, isRequired: isRequired }; }; var checkForArrayRtDesc = function checkForArrayRtDesc(arr, rtDescs) { if (!isArray(arr)) { return false; } for (var i = 0, len = arr.length; i < len; ++i) { var value = arr[i]; var rtDesc = void 0; var j = 0; var flag = rtDescs.length === 0; while (rtDesc = rtDescs[j++]) { if (checkForRtDesc(value, rtDesc)) { flag = true; break; } } if (!flag) { return false; } } return true; }; var checkForStringRtDesc = function checkForStringRtDesc(value, rtDesc) { var valueType = getValueType(value); var desc = parseRtDesc(rtDesc); var ret = desc.type === valueType; if (!ret) { log("miss match type : ".concat(valueType, " !== ").concat(desc.type)); } return ret; }; var checkForObjectRtDesc = function checkForObjectRtDesc(json, rtDesc) { if (_typeof(json) !== 'object' || isArray(json)) { log('must be object'); return false; } var rootJson = json; var nowCheckValue = json; for (var k in rtDesc) { if (rtDesc.hasOwnProperty(k)) { var nowCheckDesc = rtDesc[k]; var desc = parseRtDesc(nowCheckDesc, k); var key = desc.key; nowCheckValue = rootJson[key]; var valueType = getValueType(nowCheckValue); if (desc.isRequired && nowCheckValue === undefined) { log("is required @key=".concat(key)); return false; } if (nowCheckValue !== undefined) { if (valueType !== desc.type && desc.type !== 'mix') { log("miss match type : ".concat(valueType, " !== ").concat(desc.type, " @key=").concat(key)); return false; } if ((valueType === 'array' || valueType === 'object') && desc.type !== 'mix') { if (!checkForRtDesc(nowCheckValue, nowCheckDesc)) { return false; } } } } } return true; }; var checkForRtDesc = function checkForRtDesc(json, rtDesc) { if (isArray(rtDesc)) { return checkForArrayRtDesc(json, rtDesc); } if (_typeof(rtDesc) === 'object') { return checkForObjectRtDesc(json, rtDesc); } if (typeof rtDesc === 'string') { return checkForStringRtDesc(json, rtDesc); } return false; }; var _check = function check(json, rtDescs) { if (typeof json === 'string') { try { json = eval("(".concat(json, ")")); } catch (e) { log('parse json error'); return false; } } if (_typeof(json) !== 'object') { log('must be object'); return false; } if (!isArray(rtDescs)) { rtDescs = [rtDescs]; } var rtDesc; var i = 0; while (rtDesc = rtDescs[i++]) { if (checkForRtDesc(json, rtDesc)) { return true; } } return false; }; var RespTypes = { check: function check(json, rtDesc) { logList = []; try { var ret = _check(json, rtDesc); if (!ret) { printLog(); } return ret; } catch (e) { logList.push("[rtException]".concat(e.toString())); printLog(); return false; } }, getMsg: function getMsg() { return logList.join(';'); } }; function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray$1(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray$1(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$1(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen); } function _arrayLikeToArray$1(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } var ua = navigator.userAgent; var is_ios = /(iPhone|iPad|iPod|iOS)/i.test(ua); var is_wp = /Windows\sPhone/i.test(ua); var is_android = /(Android)/i.test(ua); var is_wechat = /MicroMessenger\/([\d\.]+)/i.test(ua); var is_mac = /mac\sos/i.test(ua) && !is_ios; var is_windows = /windows\snt/i.test(ua) && !is_wp; var is_mpapp = /MPAPP\/([\d\.]+)/i.test(ua); var is_ipad = /iPad/i.test(ua); var is_windows_wechat = /WindowsWechat/i.test(ua); var is_mac_wechat = /MacWechat/i.test(ua) || /wechat.*mac os/i.test(ua); var is_prefetch = is_wechat && window.WeixinPrefecherJSBridge; var is_donut_app = /SAAASDK/i.test(ua); var is_harmony = /OpenHarmony|ArkWeb/i.test(ua); var is_in_miniProgram = is_android && /miniprogram/.test(ua.toLowerCase()) || window.__wxjs_environment == 'miniprogram'; var is_wx_work = /wxwork/i.test(ua); function getUrlParams() { var vars = location.search.substring(1).split('&'); var params = {}; var _iterator = _createForOfIteratorHelper(vars), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var ele = _step.value; var pair = ele.split('='); var key = decodeURIComponent(pair[0]); if (typeof params[key] === 'undefined') { params[key] = decodeURIComponent(pair[1]); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return params; } function get() { var reg = /MicroMessenger\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMac() { var reg = /MacWechat\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMacOS() { var reg = /Mac OS X ([\d_]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1].replace(/_/g, '.'); } return false; } function getWindows() { var reg = /WindowsWechat\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getWxWork() { var reg = /wxwork\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMpApp() { var appVersion = [2, 4, 5]; var match = navigator.userAgent.match(/MPAPP\/(\d+(\.\d+)*)/); if (match) { appVersion = match[1].split('.').map(function (v) { return Number(v); }); } return appVersion.join('.'); } function getUnifiedPcVer() { var versionInfo = navigator.userAgent.match(/UnifiedPC\w+Wechat\(0xf\w{2}(\w+?)\w{2}\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(0, 1)); var subVersion = getVersionNumber(version.slice(1, 2)); var subVersion2 = getVersionNumber(version.slice(2, 3)); return [mainVersion, subVersion, subVersion2].join('.'); } } function getVersionNumber(hexStr) { return Number(Number("0x".concat(hexStr)).toString(10)); } function getWindowsVersionFormat() { var versionInfo = navigator.userAgent.match(/WindowsWechat\(0x(\w+?)\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(1, 2)); var subVersion = getVersionNumber(version.slice(2, 4)); var subVersion2 = getVersionNumber(version.slice(4, 6)); return [mainVersion, subVersion, subVersion2].join('.'); } return false; } function getInner() { var reg = /MicroMessenger\/[\d\.]+\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1] && ret[1] != null) { return ret[1]; } if (!ret && /MicroMessenger\/[\d\.]+/i.test(ua)) { var urlParams = getUrlParams(); if (urlParams.version) { return urlParams.version; } } return false; } var opfunc = { 'cp-1': function cp1(a, b) { return a < b; }, cp0: function cp0(a, b) { return a === b; }, cp1: function cp1(a, b) { return a > b; } }; function cpVersion(ver, op, canEq, type) { var mmver = false; switch (type) { case 'mac': mmver = getMac(); break; case 'windows': mmver = getWindowsVersionFormat(); break; case 'wxwork': mmver = getWxWork(); break; case 'mpapp': mmver = getMpApp(); break; case 'unifiedpc': mmver = getUnifiedPcVer(); break; default: mmver = get(); break; } if (!mmver) { return; } var mmversion = mmver.split('.'); var version = ver.split('.'); if (!/\d+/g.test(mmversion[mmversion.length - 1])) { mmversion.pop(); } for (var i = 0, len = Math.max(mmversion.length, version.length); i < len; ++i) { var mmv = mmversion[i] || ''; var v = version[i] || ''; var mmvn = parseInt(mmv, 10) || 0; var vn = parseInt(v, 10) || 0; var eq = opfunc.cp0(mmvn, vn); if (eq) { continue; } var cp = opfunc["cp".concat(op)]; return cp(mmvn, vn); } return canEq || op === 0; } function eqVersion(version) { return cpVersion(version, 0); } function gtVersion(version, canEq) { return cpVersion(version, 1, canEq); } function ltVersion(version, canEq) { return cpVersion(version, -1, canEq); } function getPlatform() { if (is_ios) { return 'ios'; } if (is_android) { return 'android'; } if (is_mac) { return 'mac_os'; } if (is_windows) { return 'windows'; } return 'unknown'; } var is_google_play = false; var inner_ver_for_google_play_check = getInner(); if (is_android && inner_ver_for_google_play_check) { var v = "0x".concat(inner_ver_for_google_play_check.substr(-2)); if (parseInt(v) >= 64 && parseInt(v) <= 79) { is_google_play = true; } } var mmversion = { get: get, getMac: getMac, getMacOS: getMacOS, getWindows: getWindows, getInner: getInner, getWxWork: getWxWork, getMpApp: getMpApp, cpVersion: cpVersion, eqVersion: eqVersion, gtVersion: gtVersion, ltVersion: ltVersion, getPlatform: getPlatform, getVersionNumber: getVersionNumber, isWp: is_wp, isIOS: is_ios, isAndroid: is_android, isHarmony: is_harmony, isHarmonyWechat: is_harmony && is_wechat && cpVersion('1.0.0', 1, true), isInMiniProgram: is_in_miniProgram, isWechat: is_wechat, isMac: is_mac, isWindows: is_windows, isMacWechat: is_mac_wechat, isWindowsWechat: is_windows_wechat, isWxWork: is_wx_work, isOnlyWechat: is_wechat && !is_wx_work, isMpapp: is_mpapp, isNewMpApp: false, isIPad: is_ipad, isGooglePlay: is_google_play, isPrefetch: is_prefetch, isDonutAPP: is_donut_app }; var Device = {}; function detect(ua) { var MQQBrowser = ua.match(/MQQBrowser\/(\d+\.\d+)/i); var MQQClient = ua.match(/QQ\/(\d+\.(\d+)\.(\d+)\.(\d+))/i) || ua.match(/V1_AND_SQ_([\d\.]+)/); var WeChat = ua.match(/MicroMessenger\/((\d+)\.(\d+))\.(\d+)/) || ua.match(/MicroMessenger\/((\d+)\.(\d+))/); var MacOS = ua.match(/Mac\sOS\sX\s(\d+[\.|_]\d+)/); var WinOS = ua.match(/Windows(\s+\w+)?\s+?(\d+\.\d+)/); var Linux = ua.match(/Linux\s/); var MiuiBrowser = ua.match(/MiuiBrowser\/(\d+\.\d+)/i); var M1 = ua.match(/MI-ONE/); var MIPAD = ua.match(/MI PAD/); var UC = ua.match(/UCBrowser\/(\d+\.\d+(\.\d+\.\d+)?)/) || ua.match(/\sUC\s/); var IEMobile = ua.match(/IEMobile(\/|\s+)(\d+\.\d+)/) || ua.match(/WPDesktop/); var ipod = ua.match(/(ipod).*\s([\d_]+)/i); var ipad = ua.match(/(ipad).*\s([\d_]+)/i); var iphone = ua.match(/(iphone)\sos\s([\d_]+)/i); var Chrome = ua.match(/Chrome\/(\d+\.\d+)/); var AndriodBrowser = ua.match(/Mozilla.*Linux.*Android.*AppleWebKit.*Mobile Safari/); var android = ua.match(/(android)\s([\d\.]+)/i); var harmony = ua.match(/(OpenHarmony)\s([\d\.]+)/i); Device.browser = Device.browser || {}, Device.os = Device.os || {}; if (window.ActiveXObject) { var vie = 6; (window.XMLHttpRequest || ua.indexOf('MSIE 7.0') > -1) && (vie = 7); (window.XDomainRequest || ua.indexOf('Trident/4.0') > -1) && (vie = 8); ua.indexOf('Trident/5.0') > -1 && (vie = 9); ua.indexOf('Trident/6.0') > -1 && (vie = 10); Device.browser.ie = true, Device.browser.version = vie; } else if (ua.indexOf('Trident/7.0') > -1) { Device.browser.ie = true, Device.browser.version = 11; } if (android) { Device.os.android = true; Device.os.version = android[2]; } if (harmony) { Device.os.harmony = true; Device.os.version = harmony[2]; } if (ipod) { Device.os.ios = Device.os.ipod = true; Device.os.version = ipod[2].replace(/_/g, '.'); } if (ipad) { Device.os.ios = Device.os.ipad = true; Device.os.version = ipad[2].replace(/_/g, '.'); } if (iphone) { Device.os.iphone = Device.os.ios = true; Device.os.version = iphone[2].replace(/_/g, '.'); } if (WinOS) Device.os.windows = true, Device.os.version = WinOS[2]; if (MacOS) Device.os.Mac = true, Device.os.version = MacOS[1]; if (Linux) Device.os.Linux = true; if (ua.indexOf('lepad_hls') > 0) Device.os.LePad = true; if (MIPAD) Device.os.MIPAD = true; if (MQQBrowser) Device.browser.MQQ = true, Device.browser.version = MQQBrowser[1]; if (MQQClient) Device.browser.MQQClient = true, Device.browser.version = MQQClient[1]; if (WeChat) Device.browser.WeChat = true, Device.browser.mmversion = Device.browser.version = WeChat[1]; if (MiuiBrowser) Device.browser.MIUI = true, Device.browser.version = MiuiBrowser[1]; if (UC) Device.browser.UC = true, Device.browser.version = UC[1] || NaN; if (IEMobile) Device.browser.IEMobile = true, Device.browser.version = IEMobile[2]; if (AndriodBrowser) { Device.browser.AndriodBrowser = true; } if (M1) { Device.browser.M1 = true; } if (Chrome) { Device.browser.Chrome = true, Device.browser.version = Chrome[1]; } if (Device.os.windows) { if (typeof navigator.platform !== "undefined" && navigator.platform.toLowerCase() == "win64") { Device.os.win64 = true; } else { Device.os.win64 = false; } } if (Device.os.Mac || Device.os.windows || Device.os.Linux) { Device.os.pc = true; } var osType = { iPad7: 'iPad; CPU OS 7', LePad: 'lepad_hls', XiaoMi: 'MI-ONE', SonyDTV: "SonyDTV", SamSung: 'SAMSUNG', HTC: 'HTC', VIVO: 'vivo' }; for (var os in osType) { Device.os[os] = ua.indexOf(osType[os]) !== -1; } Device.os.phone = Device.os.phone || /windows phone/i.test(ua); Device.os.getNumVersion = function () { return parseFloat(Device.os.version); }; Device.os.hasTouch = 'ontouchstart' in window; if (Device.os.hasTouch && Device.os.ios && Device.os.getNumVersion() < 6) { Device.os.hasTouch = false; } if (Device.browser.WeChat && Device.browser.version < 5.0) { Device.os.hasTouch = false; } Device.browser.getNumVersion = function () { return parseFloat(Device.browser.version); }; Device.browser.isFFCanOcx = function () { return !!Device.browser.firefox && Device.browser.getNumVersion() >= 3.0; }; Device.browser.isCanOcx = function () { return !!Device.os.windows && (!!Device.browser.ie || Device.browser.isFFCanOcx() || !!Device.browser.webkit); }; Device.browser.isNotIESupport = function () { return !!Device.os.windows && (!!Device.browser.webkit || Device.browser.isFFCanOcx()); }; Device.userAgent = {}; Device.userAgent.browserVersion = Device.browser.version; Device.userAgent.osVersion = Device.os.version; Device.os.unifiedPC = ua.match(/UnifiedPC/); delete Device.userAgent.version; } detect(window.navigator.userAgent); function canSupportH5Video() { var ua = window.navigator.userAgent, m = null; if (!!Device.os.android) { if (Device.browser.MQQ && Device.browser.getNumVersion() >= 4.2) { return true; } if (ua.indexOf('MI2') != -1) { return true; } if (Device.os.version >= '4' && (m = ua.match(/MicroMessenger\/((\d+)\.(\d+))\.(\d+)/))) { if (parseFloat(m[1]) >= 4.2) { return true; } } if (Device.os.version >= '4.1') { return true; } } return false; } function canSupportVideoMp4() { var video = document.createElement('video'); if (typeof video.canPlayType === 'function') { if (video.canPlayType('video/mp4; codecs="mp4v.20.8"') === 'probably') { return true; } if (video.canPlayType('video/mp4; codecs="avc1.42E01E"') === 'probably' || video.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"') === 'probably') { return true; } } return false; } function canSupportAutoPlay() { if (Device.os.ios && Device.os.getNumVersion() < 10) { return false; } return true; } function isLockdownMode() { if (!Device.os.ios || Device.os.getNumVersion() < 16) { return false; } if (typeof WebAssembly === 'undefined' && typeof OfflineAudioContext === 'undefined' && typeof WebGLRenderingContext === 'undefined') { return true; } return false; } Device.canSupportVideo = canSupportVideoMp4 || canSupportH5Video; Device.canSupportVideoMp4 = canSupportVideoMp4; Device.canSupportH5Video = canSupportH5Video; Device.canSupportAutoPlay = canSupportAutoPlay; Device.isLockdownMode = isLockdownMode; Device.cpVersion = function (version) { var cp = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; var canEqual = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; var nowVersionStr = Device.os.version; if (!nowVersionStr) return false; var versionArr = version.split('.'); var nowVersionArr = nowVersionStr.split('.'); for (var i = 0; i < Math.max(nowVersionArr.length, versionArr.length); i++) { var vi = +versionArr[i]; var nvi = +nowVersionArr[i]; if (vi === nvi) continue; if (cp > 0) return vi > nvi; if (cp < 0) return vi < nvi; } return canEqual || cp === 0; }; var initJsBridge = false; if (!window.JSAPIEventCallbackMap) { window.JSAPIEventCallbackMap = {}; } function connectWebViewJavascriptBridge(callback) { if (window.WebViewMPapp || window.WebViewJavascriptBridge) { return callback(window.WebViewMPapp || window.WebViewJavascriptBridge); } if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); } window.WVJBCallbacks = [callback]; if (!initJsBridge) { initJsBridge = true; var WVJBIframe = document.createElement('iframe'); WVJBIframe.style.display = 'none'; WVJBIframe.src = 'https://__bridge_loaded__'; document.body.appendChild(WVJBIframe); setTimeout(function () { initJsBridge = false; document.body.removeChild(WVJBIframe); }, 0); } return false; } function invoke$1(jsapiName, opt, callback) { connectWebViewJavascriptBridge(function (bridge) { try { if (typeof opt === 'function') { callback = opt; } if (_typeof(opt) !== 'object' && typeof opt !== 'string') { opt = {}; } bridge.callHandler(jsapiName, opt, function (res) { try { var ret = _typeof(res) === 'object' ? res : JSON.parse(res); var errMsg = ret.err_msg || ret.errMsg; console.info("[mpapp jsapi] invoke->".concat(jsapiName, " ").concat(opt.action || '', " ").concat(errMsg)); typeof callback === 'function' && callback(ret); } catch (e) { window.WX_BJ_REPORT.BadJs.report('invoke', "callback ".concat(jsapiName, " error:"), { mid: 'mmbizwebapp:js_brridge', _info: e }); console.error("[mpapp jsapi] ".concat(jsapiName, " ").concat(opt.action || ''), e, res); } }); } catch (e) { window.WX_BJ_REPORT.BadJs.report('invoke', 'callback error:', { mid: 'mmbizwebapp:js_brridge', _info: e }); console.error('[mpapp jsapi]', e); } }); } var doc$1 = {}; var isAcrossOrigin$1 = false; var __moon_report$1 = window.__moon_report || function () {}; var MOON_JSAPI_KEY_OFFSET = 8; try { doc$1 = top.window.document; } catch (e) { isAcrossOrigin$1 = true; } if (!window.JSAPIEventCallbackMap) { window.JSAPIEventCallbackMap = {}; } function ready(onBridgeReady) { var bridgeReady = function bridgeReady() { try { if (onBridgeReady) { window.onBridgeReadyTime = window.onBridgeReadyTime || Date.now(); onBridgeReady(); } } catch (e) { __moon_report$1([{ offset: MOON_JSAPI_KEY_OFFSET, log: 'ready', e: e }]); throw e; } window.jsapiReadyTime = Date.now(); }; if (!isAcrossOrigin$1 && (typeof top.window.WeixinJSBridge === 'undefined' || !top.window.WeixinJSBridge.invoke)) { if (doc$1.addEventListener) { doc$1.addEventListener('WeixinJSBridgeReady', bridgeReady, false); } else if (doc$1.attachEvent) { doc$1.attachEvent('WeixinJSBridgeReady', bridgeReady); doc$1.attachEvent('onWeixinJSBridgeReady', bridgeReady); } } else { bridgeReady(); } } function invoke(methodName, args, callback) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { invoke(methodName, args, callback); }); return; } ready(function () { if (isAcrossOrigin$1) return false; if (_typeof(top.window.WeixinJSBridge) !== 'object') { alert('请在微信中打开此链接'); return false; } top.window.WeixinJSBridge.invoke(methodName, args, function () { try { for (var _len = arguments.length, rets = new Array(_len), _key = 0; _key < _len; _key++) { rets[_key] = arguments[_key]; } var ret = rets[0]; var errMsg = ret && ret.err_msg ? ", err_msg-> ".concat(ret.err_msg) : ''; console.info('[system]', "[jsapi] invoke->".concat(methodName).concat(errMsg)); if (callback) { callback.apply(window, rets); } } catch (e) { __moon_report$1([{ offset: MOON_JSAPI_KEY_OFFSET, log: "invoke;methodName:".concat(methodName), e: e }]); throw e; } }); }); } function call(methodName) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { call(methodName); }); return; } ready(function () { if (isAcrossOrigin$1) return false; if (_typeof(top.window.WeixinJSBridge) !== 'object') { return false; } try { top.window.WeixinJSBridge.call(methodName); } catch (e) { __moon_report$1([{ offset: MOON_JSAPI_KEY_OFFSET, log: "call;methodName:".concat(methodName), e: e }]); throw e; } }); } function on(eventName, callback) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { on(eventName, callback); }); return; } ready(function () { if (isAcrossOrigin$1) return false; if (_typeof(top.window.WeixinJSBridge) !== 'object' || !top.window.WeixinJSBridge.on) { return false; } if (!window.JSAPIEventCallbackMap[eventName]) { window.JSAPIEventCallbackMap[eventName] = []; } window.JSAPIEventCallbackMap[eventName].push(callback); if (window.JSAPIEventCallbackMap[eventName].length > 1) { return false; } top.window.WeixinJSBridge.on(eventName, function () { try { for (var _len2 = arguments.length, rets = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { rets[_key2] = arguments[_key2]; } var ret = rets[0]; var errMsg = ret && ret.err_msg ? ", err_msg-> ".concat(ret.err_msg) : ''; console.info('[system]', "[jsapi] event->".concat(eventName).concat(errMsg)); if (window.JSAPIEventCallbackMap[eventName] && window.JSAPIEventCallbackMap[eventName].length) { var result; for (var i = 0; i < window.JSAPIEventCallbackMap[eventName].length; i++) { result = window.JSAPIEventCallbackMap[eventName][i].apply(window, rets); } return result; } } catch (e) { __moon_report$1([{ offset: MOON_JSAPI_KEY_OFFSET, log: "on;eventName:".concat(eventName), e: e }]); throw e; } }); }); } function remove(eventName, callback) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { remove(eventName, callback); }); return; } ready(function () { if (!window.JSAPIEventCallbackMap[eventName]) { return false; } var result = false; for (var i = window.JSAPIEventCallbackMap[eventName].length - 1; i >= 0; i--) { if (window.JSAPIEventCallbackMap[eventName][i] === callback) { window.JSAPIEventCallbackMap[eventName].splice(i, 1); result = true; } } return result; }); } var JSAPI = { ready: ready, invoke: invoke, call: call, on: on, remove: remove }; function parseUrl(url) { var len = url.length; var ques_pos = url.indexOf('?'); var hash_pos = url.indexOf('#'); hash_pos = hash_pos == -1 ? len : hash_pos; ques_pos = ques_pos == -1 ? hash_pos : ques_pos; var host = url.substring(0, ques_pos); var query_str = url.substring(ques_pos + 1, hash_pos); var hash = url.substring(hash_pos + 1); return { host: host, query_str: query_str, hash: hash }; } function join(url, args, noEncode) { var ret = parseUrl(url); var query_str = ret.query_str; var args_arr = []; if (_typeof(args) === 'object') { for (var key in args) { if (args.hasOwnProperty(key)) { args_arr.push("".concat(key, "=").concat(noEncode ? args[key] : encodeURIComponent(args[key]))); } } } else { args_arr.push(noEncode ? args : encodeURIComponent(args)); } if (args_arr.length > 0) { query_str += (query_str !== "" ? "&" : "") + args_arr.join("&"); } return ret.host + (query_str !== "" ? "?".concat(query_str) : "") + (ret.hash !== "" ? "#".concat(ret.hash) : ""); } function addParam(url, param, value, forceReplace) { url = url || location.href; var firstAndPos = url.indexOf("&"); var len = url.length; var reverseUrl = url.replace(/^[\w\d]+:[/\\]+/g, "").split("").reverse(); if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (searchElement, fromIndex) { var k; if (this == null) { throw new TypeError('"this" is null or not defined'); } var O = Object(this); var len = O.length >>> 0; if (len === 0) { return -1; } var n = fromIndex || 0; if (Math.abs(n) === Infinity) { n = 0; } if (n >= len) { return -1; } k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); while (k < len) { if (k in O && O[k] === searchElement) { return k; } k++; } return -1; }; } var lastSlashPos = len - 1 - reverseUrl.indexOf("/"); if (firstAndPos !== -1 && url.indexOf("?") == -1 && firstAndPos > lastSlashPos) { url = url.replace("&", "?"); } var reg = new RegExp("([\\?&]".concat(param, "=)[^&#]*")); if (!url.match(reg)) { var urlInfo = parseUrl(url); var hash = urlInfo.hash ? '#' + urlInfo.hash : ''; url = url.replace(hash, ''); var _pos = url.indexOf("?"); if (_pos == -1) { return "".concat(url, "?").concat(param, "=").concat(value).concat(hash); } if (_pos == url.length - 1) { return "".concat(url + param, "=").concat(value).concat(hash); } return "".concat(url, "&").concat(param, "=").concat(value).concat(hash); } if (forceReplace === true) { return url.replace(reg, "$1".concat(value)); } return url; } function addWxfrom(src, wxfrom) { var offset = window.service_type === 1 ? 10000 : 0; return addParam(src, 'wxfrom', offset + Number(wxfrom), true); } function removeParam(url, param) { var _URL = new URL(url), protocol = _URL.protocol, host = _URL.host, pathname = _URL.pathname, search = _URL.search, hash = _URL.hash; var queryParams = new URLSearchParams(search); queryParams["delete"](param); var newSearch = queryParams.toString(); var newUrl = new URL("".concat(protocol, "//").concat(host).concat(pathname).concat(newSearch ? "?".concat(decodeURIComponent(newSearch)) : "").concat(hash)); return newUrl.toString(); } function getQuery(name, url) { var u = url || window.location.search; var reg = new RegExp("(^|&)".concat(name, "=([^&]*)(&|$)")); var r = u.substring(u.indexOf('?') + 1).match(reg); return r !== null ? r[2] : ''; } function encodeBase64(value) { try { return window.btoa(value); } catch (e) { return ''; } } function decodeBase64(value) { try { return window.atob(value); } catch (e) { return ''; } } function joinUrl(url) { var obj = {}; if (typeof window.uin !== 'undefined') { obj.uin = window.uin; } if (typeof window.key !== 'undefined') { obj.key = window.key; } if (typeof window.pass_ticket !== 'undefined') { obj.pass_ticket = window.pass_ticket; } if (typeof window.wxtoken !== 'undefined') { obj.wxtoken = window.wxtoken; } if (typeof window.devicetype !== 'undefined') { obj.devicetype = window.devicetype; } if (typeof window.clientversion !== 'undefined') { obj.clientversion = window.clientversion || mmversion.getInner(); } obj.version = obj.clientversion; if (window.biz) { obj.__biz = window.biz; } if (getQuery('enterid')) { obj.enterid = getQuery('enterid'); } if (typeof window.appmsg_token !== 'undefined') { obj.appmsg_token = window.appmsg_token; } else if (url.indexOf('advertisement_report') > -1) { new Image().src = "".concat(location.protocol, "//mp.weixin.qq.com/mp/jsmonitor?idkey=68064_13_1&r=").concat(Math.random()); } obj.x5 = navigator.userAgent.indexOf('TBS/') !== -1 ? '1' : '0'; obj.f = 'json'; return join(url, obj); } function getA8keyQuery(name, url) { return new Promise(function (resolve) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { resolve(getQuery(name, url)); }); } else { resolve(getQuery(name, url)); } }); } var Url = { parseUrl: parseUrl, join: join, addParam: addParam, addWxfrom: addWxfrom, getQuery: getQuery, getA8keyQuery: getA8keyQuery, encodeBase64: encodeBase64, decodeBase64: decodeBase64, joinUrl: joinUrl, removeParam: removeParam }; function _log(level, msg) { if (level === 'log') { level = 'info'; msg = "[WechatFe]".concat(msg); } else { var prefix = "__wap__".concat(window.__second_open__ ? ' (sec)' : ''); msg = "".concat(prefix, " ").concat(msg, " location:[").concat(location.href, "]"); } msg += new Error().stack; if (mmversion.isMpapp) { invoke$1('WNNativeCallbackLog', msg); } else if (mmversion.isWechat) { if (mmversion.isAndroid) { console.warn('[system]', "[MicroMsg.JsApiLog][".concat(level, "] jslog : ").concat(msg)); } else if (mmversion.isIOS) { JSAPI.invoke('writeLog', { level: level, msg: msg }); } else { JSAPI.invoke('log', { level: level, msg: msg }); } } } var Log = { info: function info() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _log('info', args.join(' ')); }, warn: function warn() { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } _log('warn', args.join(' ')); }, error: function error() { for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { args[_key3] = arguments[_key3]; } _log('error', args.join(' ')); }, debug: function debug() { for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { args[_key4] = arguments[_key4]; } _log('debug', args.join(' ')); }, log: function log() { for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { args[_key5] = arguments[_key5]; } _log('info', args.join(' ')); } }; var html = function html(_str, encode) { if (!_str) return ''; var replace = ['`', '`', ''', '\'', '"', '"', ' ', ' ', '>', '>', '<', '<', '¥', '¥', '&', '&', '<', '<', '>', '>']; var replaceReverse = ['&', '&', '¥', '¥', '<', '<', '>', '>', ' ', ' ', '"', '"', '\'', ''', '`', '`']; var str = _str; var target; if (encode) { target = replaceReverse; } else { target = replace; } for (var i = 0; i < target.length; i += 2) { str = str.replace(new RegExp(target[i], 'g'), target[i + 1]); } return str; }; var htmlLite = function htmlLite(_str, encode) { if (!_str) return ''; var replace = ['`', '`', ''', '\'', '"', '"', '>', '>', '<', '<', '&', '&']; var replaceReverse = ['&', '&', '<', '<', '>', '>', '"', '"', '\'', ''', '`', '`']; var str = _str; var target; if (encode) { target = replaceReverse; } else { target = replace; } for (var i = 0; i < target.length; i += 2) { str = str.replace(new RegExp(target[i], 'g'), target[i + 1]); } return str; }; var htmlEncode = function htmlEncode(str) { return html(str, true); }; var htmlDecode = function htmlDecode(str) { return html(str, false); }; var htmlEncodeLite = function htmlEncodeLite(str) { return htmlLite(str, true); }; var htmlDecodeLite = function htmlDecodeLite(str) { return htmlLite(str, false); }; String.prototype.html = function (encode) { return html(this.toString(), encode); }; String.prototype.htmlEncode = function () { return htmlEncode(this.toString()); }; String.prototype.htmlDecode = function () { return htmlDecode(this.toString()); }; String.prototype.htmlLite = function (encode) { return htmlLite(this.toString(), encode); }; String.prototype.htmlEncodeLite = function () { return htmlEncodeLite(this.toString()); }; String.prototype.htmlDecodeLite = function () { return htmlDecodeLite(this.toString()); }; var _a; var METHOD_ENUM = { GET: 0, POST: 1 }; var __moon_report = window.__moon_report || function () {}; var MOON_AJAX_SUCCESS_OFFSET = 3; var MOON_AJAX_NETWORK_OFFSET = 4; var MOON_AJAX_ERROR_OFFSET = 5; var MOON_AJAX_TIMEOUT_OFFSET = 6; var MOON_AJAX_COMPLETE_OFFSET = 7; var LENGTH_LIMIT = 4096; var doc; var isAcrossOrigin = false; try { doc = (_a = window.top) === null || _a === void 0 ? void 0 : _a.window.document; } catch (e) { isAcrossOrigin = true; } function networkStartLog(item) { var _a, _b, _c; console.log('[system]', "< [request ".concat(item.requestType, "]"), item.method, item); if ((_a = window.vConsole) === null || _a === void 0 ? void 0 : _a.network) { try { return (_c = (_b = window.vConsole.network).add) === null || _c === void 0 ? void 0 : _c.call(_b, Object.assign({}, item, { startTime: Date.now(), endTime: Date.now(), status: 0, readyState: 2, response: '' })); } catch (err) {} } return Object.assign({}, item, { id: '__system_log__' }); } function networkEndLog(item) { var _a, _b, _c; console.log('[system]', "> [response ".concat(item.requestType, "]"), item.response, item); if (((_a = window.vConsole) === null || _a === void 0 ? void 0 : _a.network) && item.id !== '__system_log__') { try { return (_c = (_b = window.vConsole.network).update) === null || _c === void 0 ? void 0 : _c.call(_b, item.id, Object.assign({}, item, { readyState: 4 })); } catch (err) {} } } function reqType(obj, path) { return obj.url.indexOf(path) > -1 && obj.url.indexOf('action=') === -1 && (!obj.data || !obj.data.action); } function reportRtError(type, id, key, content) { var log = ''; var prefix = type === 'rt' ? 'rtCheckError' : 'Ajax Length Limit'; if (content === null || content === void 0 ? void 0 : content.length) { var loglen = 1000; var len = content.length; var lc = Math.ceil(len / loglen); log = ["&lc=".concat(lc)]; for (var i = 0; i < lc; ++i) { log.push("&log".concat(i, "=") + "[".concat(prefix, "][").concat(i, "]").concat(encodeURIComponent(content.substring(i * loglen, i * loglen + loglen)))); } log = log.join(''); } var data = "idkey=".concat(id, "_").concat(key, "_1").concat(log, "&r=").concat(Math.random()); var xmlobj = new XMLHttpRequest(); xmlobj.open('POST', "".concat(location.protocol, "//").concat(location.host, "/mp/jsmonitor?"), true); xmlobj.setRequestHeader('cache-control', 'no-cache'); xmlobj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); xmlobj.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xmlobj.send(data); if (type === 'ajaxLen') { monitor$1.setLogs({ id: id, key: key, value: 1, log: log }); } } function reportRt(id, key, content) { reportRtError('rt', id, key, content); } function reportAjaxLength(id, key, content) { reportRtError('ajaxLen', id, key, content); } function setCurrentMpInfo(ifShow) { var supportNewTopBar = mmversion.isIOS && mmversion.gtVersion('7.0.10', true) || mmversion.isAndroid && mmversion.gtVersion('7.0.12', true); var supportLiveStatus = mmversion.isIOS && mmversion.gtVersion('8.0.46', true) || mmversion.isAndroid && mmversion.gtVersion('8.0.46', true); JSAPI.invoke('currentMpInfo', { userName: window.user_name, brandName: !!supportNewTopBar && window.nickname === '' ? '未命名账号' : window.title, title: window.msg_title || '', brandIcon: window.hd_head_img.replace(/\/0$/, '/132'), itemShowType: window.item_show_type, isPaySubscribe: window.isPaySubscribe, topBarStyle: supportNewTopBar ? 1 : 0, topBarShowed: ifShow, disableShowFinderLiveTopBar: !ifShow && supportLiveStatus ? 1 : 0 }, function () {}); } function findAjaxScopeByConfig(url, config) { var pathname = new URL(url, location.href).pathname || ''; var scope = config[pathname.slice(1)]; if (scope) { Log.log('ajax transfer config: ', JSON.stringify(config)); return scope; } } function getAjaxScope(ajaxUrl) { if (Url.getQuery('no_transfer', location.href) !== '1' && mmversion.isWechat && !mmversion.isInMiniProgram && !mmversion.isWxWork && !mmversion.isMpapp && !isAcrossOrigin && window.__ajaxTransferConfig && _typeof(window.__ajaxTransferConfig) === 'object' && ( mmversion.isIOS && mmversion.getInner() >= '1800282f' || mmversion.isAndroid && mmversion.getInner() >= '28002234' || mmversion.isWindowsWechat && mmversion.cpVersion('3.9.5', 1, true, 'windows') || mmversion.isMacWechat && mmversion.cpVersion('3.8.4', 1, true, 'mac'))) { try { return findAjaxScopeByConfig(ajaxUrl, window.__ajaxTransferConfig); } catch (err) { } } } function setXhrHeader(xhr, type, opt) { if (opt.contentType) { xhr.setRequestHeader('Content-Type', opt.contentType); } else if (type === 'POST') { xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); } if (!opt.noXRequestedWidthHeader) { xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); } } function Ajax(obj) { if (obj.usePb) { obj.type = 'POST'; obj.data = { data: JSON.stringify(obj.data) }; } var ajaxScope = getAjaxScope(obj.url); var type = (obj.type || 'GET').toUpperCase(); var timer; var url; if (obj.notJoinUrl) { url = obj.url; } else { url = Url.joinUrl(obj.url); } if (obj.f === 'html') { url = url.replace('&f=json', ''); } var data = null; if (_typeof(obj.data) === 'object') { var d = obj.data; var ds = []; for (var k in d) { if (d.hasOwnProperty(k)) { ds.push("".concat(k, "=").concat(encodeURIComponent(d[k]))); } } data = ds.join('&'); } else { data = typeof obj.data === 'string' ? obj.data : null; } var beginTs; var beforeReq = function beforeReq() { if (reqType(obj, '/mp/getappmsgext')) { window.startGetAppmsgExtTime = Date.now(); Log.log('start get appmsgext, url: ', obj.url); } if (reqType(obj, '/mp/getappmsgad')) { window.startGetAppmsgAdTime = Date.now(); Log.log('start get appmsgad, url: ', obj.url); } beginTs = Date.now(); }; var beforeResp = function beforeResp(xhr) { if (reqType(obj, '/mp/getappmsgext')) { window.receiveGetAppmsgExt = "".concat(xhr.status, "|").concat(Date.now()); Log.log("receive appmsgext response, status: ".concat(xhr.status)); } if (reqType(obj, '/mp/getappmsgad')) { window.receiveGetAppmsgAd = "".concat(xhr.status, "|").concat(Date.now()); Log.log("receive appmsgad response, status: ".concat(xhr.status)); } if (Math.random() < 0.01 && window.WX_BJ_REPORT && window.WX_BJ_REPORT.BadJs) { try { var key = ajaxScope ? 'transfer' : 'xhr'; var interval = 250; var time = Date.now() - beginTs; var range = Math.floor(time / interval) * interval; var pathname = new URL(obj.url, location.href).pathname || ''; window.WX_BJ_REPORT.BadJs.report("".concat(key, "_perf:").concat(pathname), JSON.stringify({ status: xhr.status, time: "[".concat(range, "-").concat(range + interval, ")") }), { mid: 'mmbizwap:ajaxtransfer', view: 'wap_business' }); } catch (err) {} } }; var handleRespSucc = function handleRespSucc(xhr) { var _a; try { var responseText = xhr.responseText; var resp = responseText; if (obj.dataType === 'json') { try { if (JSON && JSON.parse) { resp = JSON.parse(resp); } else { resp = eval("(".concat(resp, ")")); monitor$1.setSum(523105, 127, 1).send(); } var rtId = obj.rtId; var rtKey = obj.rtKey || 0; var rtDesc = obj.rtDesc; if (rtId && rtDesc && RespTypes && !RespTypes.check(resp, rtDesc)) { reportRt(+rtId, +rtKey, "".concat(RespTypes.getMsg(), "[detail]").concat(responseText, ";").concat(obj.url)); } if (resp && resp.base_resp && ((_a = resp.base_resp) === null || _a === void 0 ? void 0 : _a.ret) !== 0 && typeof window.WX_BJ_REPORT !== 'undefined' && window.WX_BJ_REPORT.BadJs && Math.random() < 0.001) { var reportUrl = url; if (url.indexOf('?') !== -1) { reportUrl = url.substring(0, url.indexOf('?')); if (Url.getQuery('action', url)) { reportUrl = "".concat(reportUrl, "?action=").concat(Url.getQuery('action', url)); } } if (!((reportUrl === '/mp/getappmsgext' || reportUrl === '/mp/getappmsgad') && typeof resp.base_resp.ret === 'undefined')) { window.WX_BJ_REPORT.BadJs.report(reportUrl, "ret=".concat(resp.base_resp.ret), { mid: window.PAGE_MID, view: 'wap_retcode' }); } } } catch (e) { obj.error && obj.error(xhr, { type: 1, error: e, status: xhr.status }); return; } } obj.success && obj.success(resp); } catch (e) { __moon_report({ offset: MOON_AJAX_SUCCESS_OFFSET, e: e }); throw e; } }; var handleRespErr = function handleRespErr(xhr, error) { try { obj.error && obj.error(xhr, { type: 2, error: error, status: xhr.status }); } catch (e) { __moon_report({ offset: MOON_AJAX_ERROR_OFFSET, e: e }); throw e; } }; var handleRespComplete = function handleRespComplete() { clearTimeout(timer); try { obj.complete && obj.complete(); } catch (e) { __moon_report({ offset: MOON_AJAX_COMPLETE_OFFSET, e: e }); throw e; } obj.complete = null; }; var handleReqTimeout = function handleReqTimeout(xhr) { if (typeof obj.timeout !== 'undefined') { timer = setTimeout(function () { xhr.abort(); try { obj.complete && obj.complete(); } catch (e) { __moon_report({ offset: MOON_AJAX_COMPLETE_OFFSET, e: e }); throw e; } obj.complete = null; __moon_report({ offset: MOON_AJAX_TIMEOUT_OFFSET, log: "ajax_timeout_error: ".concat(url), e: '' }); }, obj.timeout); } }; var retryXhrFn = function retryXhrFn(res, isTimeout, reqLogItem) { var retryXhr = new XMLHttpRequest(); try { retryXhr._noVConsole = true; } catch (err) {} retryXhr.open(type, url); retryXhr.onreadystatechange = function () { if (isTimeout) return; if (retryXhr.readyState === 3) { obj.received && obj.received(retryXhr); } if (retryXhr.readyState === 4) { beforeResp(retryXhr); var retryStatus = retryXhr.status; if (retryStatus >= 200 && retryStatus < 400) { handleRespSucc(retryXhr); } else { handleRespErr(retryXhr, res); window.WX_BJ_REPORT && window.WX_BJ_REPORT.BadJs && window.WX_BJ_REPORT.BadJs.report('req_failure', JSON.stringify({ retryXhrStatus: retryStatus, transferRes: res }), { mid: 'mmbizwap:ajaxtransfer', view: 'wap_business' }); } reqLogItem.status = retryStatus; reqLogItem.endTime = Date.now(); reqLogItem.response = retryXhr.responseText; handleRespComplete(); networkEndLog(reqLogItem); } }; setXhrHeader(retryXhr, type, obj); retryXhr.send(data); }; if (ajaxScope) { var header = { 'User-Agent': navigator.userAgent, 'Cookie': (window.__test_env__ ? 'uniproxy_route=1; ' : '') + document.cookie, 'Referer': location.href }; if (obj.contentType) { header['Content-Type'] = obj.contentType; } else if (type === 'POST') { header['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; } if (!obj.noXRequestedWidthHeader) { header['X-Requested-With'] = 'XMLHttpRequest'; } var reqUrl = new URL(url, location.href).href; var method = METHOD_ENUM[type] || 0; var params = Device.os.pc ? { url: reqUrl, req_json: data || '', scope: ajaxScope, webcgi_method: method, webcgi_header: Object.keys(header).map(function (headerItemKey) { return Device.os.Mac ? _defineProperty({}, headerItemKey, header[headerItemKey]) : { key: headerItemKey, value: header[headerItemKey] }; }), cgi_type: 1 } : { reqUrl: reqUrl, reqBody: data, scope: ajaxScope, method: method, header: header }; var reqLogItem = networkStartLog({ method: type, url: url, postData: obj.data || {}, requestHeader: header, requestType: 'transfer' }); var isTimeout = false; handleReqTimeout({ abort: function abort() { isTimeout = true; reqLogItem.endTime = Date.now(); reqLogItem.response = 'timeout'; networkEndLog(reqLogItem); } }); Device.os.pc && monitor$1.setSum(115849, 69, 1); JSAPI.invoke(Device.os.pc ? 'H5ExtTransfer' : 'webTransfer', params, function (res) { var _a, _b, _c, _d, _e, _f; if (isTimeout) return; var status = 400; var result = ''; if (Device.os.pc) { try { var retFlag = res.base_resp.ret === 0 && res.jsapi_resp.ret === 0 && res.err_msg.indexOf(':ok') > -1; var respJsonFlag = res.jsapi_resp.resp_json; status = retFlag && respJsonFlag ? 200 : 400; result = res.jsapi_resp.resp_json; } catch (err) { console.error(err); } } else { status = res && res.errCode * 1 === 0 && typeof res.result === 'string' && res.result ? 200 : 400; result = res.result; } if (status >= 200 && status < 400) { obj.received && obj.received(null); beforeResp({ status: status }); handleRespSucc({ status: status, responseText: result }); reqLogItem.status = status; reqLogItem.endTime = Date.now(); reqLogItem.response = result; handleRespComplete(); networkEndLog(reqLogItem); } else if (window.__second_open__) { JSAPI.invoke('request', { url: reqUrl, method: type, data: data, header: header }, function (retryRes) { if (isTimeout) return; var retryStatus = retryRes.statusCode; obj.received && obj.received(null); beforeResp({ status: retryStatus }); if (retryRes.err_msg.indexOf(':ok') > -1 && retryStatus >= 200 && retryStatus < 400) { handleRespSucc({ status: retryStatus, responseText: retryRes.data }); } else { retryXhrFn(res, isTimeout, reqLogItem); handleRespErr({ status: retryStatus }, res); window.WX_BJ_REPORT && window.WX_BJ_REPORT.BadJs && window.WX_BJ_REPORT.BadJs.report('req_failure_sec_open', JSON.stringify({ retryReqJsapiRes: retryRes, transferRes: res, url: reqUrl }), { mid: 'mmbizwap:ajaxtransfer', view: 'wap_business' }); } reqLogItem.status = retryStatus; reqLogItem.endTime = Date.now(); reqLogItem.response = retryRes.data; handleRespComplete(); networkEndLog(reqLogItem); }); } else { retryXhrFn(res, isTimeout, reqLogItem); } if (Device.os.pc) { if (!res.err_msg.includes(':ok')) { (_b = (_a = window.WX_BJ_REPORT) === null || _a === void 0 ? void 0 : _a.BadJs) === null || _b === void 0 ? void 0 : _b.report("pc transfer res no ok: ".concat(res.err_msg), params.url || '', { mid: window.PAGE_MID, _info: "".concat(JSON.stringify(params), " || ").concat(JSON.stringify(res)) }); } try { if (res.jsapi_resp.resp_json && JSON.parse(res.jsapi_resp.resp_json).base_resp.ret !== 0 && JSON.parse(res.jsapi_resp.resp_json).base_resp.ret !== 190001 || res.base_resp.ret !== 0 || res.jsapi_resp.ret !== 0) { (_d = (_c = window.WX_BJ_REPORT) === null || _c === void 0 ? void 0 : _c.BadJs) === null || _d === void 0 ? void 0 : _d.report("pc transfer res invalid ret", params.url || '', { mid: window.PAGE_MID, _info: "".concat(JSON.stringify(params), " || ").concat(JSON.stringify(res)) }); } } catch (err) {} } else { try { if (res.errCode !== 0) { (_f = (_e = window.WX_BJ_REPORT) === null || _e === void 0 ? void 0 : _e.BadJs) === null || _f === void 0 ? void 0 : _f.report("mobile transfer res invalid ret", params.url || '', { mid: window.PAGE_MID, _info: "".concat(JSON.stringify(params), " || ").concat(JSON.stringify(res)) }); } } catch (err) {} } }); beforeReq(); return; } var xhr = new XMLHttpRequest(); var mayAbort = !!obj.mayAbort; var async = typeof obj.async === 'undefined' ? true : obj.async; var _onreadystatechange = xhr.onreadystatechange; xhr.open(type, url, async); xhr.onreadystatechange = function () { if (typeof _onreadystatechange === 'function') { _onreadystatechange.apply(xhr); } if (xhr.readyState === 3) { obj.received && obj.received(xhr); } if (xhr.readyState === 4) { beforeResp(xhr); xhr.onreadystatechange = null; var status = xhr.status; if (status >= 200 && status < 400) { handleRespSucc(xhr); } else { handleRespErr(xhr, 'status error'); if (!!status || !mayAbort) { var __ajaxtest = window.__ajaxtest || '0'; __moon_report({ offset: MOON_AJAX_NETWORK_OFFSET, log: "ajax_network_error[".concat(status, "][").concat(__ajaxtest, "]: ").concat(url, ";host:").concat(location.host), e: '' }); } } handleRespComplete(); } }; setXhrHeader(xhr, type, obj); handleReqTimeout(xhr); try { xhr.send(data); try { if (url && url.length > LENGTH_LIMIT) { reportAjaxLength(27613, 17, "ajax get limit[length: ".concat(url.length, "]").concat(url.substring(0, 1024))); } if (data && data.length > LENGTH_LIMIT) { reportAjaxLength(27613, 18, "ajax post limit[length: ".concat(data.length, "]").concat(data.substring(0, 1024))); } } catch (e) { } } catch (e) { obj.error && obj.error(xhr, { type: 3, error: e, status: 0 }); } beforeReq(); return xhr; } function AjaxWx(obj) { obj.url += obj.url.indexOf('?') === -1 ? '?fasttmplajax=1' : '&fasttmplajax=1'; if (getAjaxScope(obj.url)) { Ajax(obj); return; } if (obj.usePb) { obj.type = 'POST'; obj.data = { data: JSON.stringify(obj.data) }; } if (!/^(http:\/\/|https:\/\/|\/\/)/.test(obj.url)) { obj.url = "https://mp.weixin.qq.com/".concat(obj.url.replace(/^\//, '')); } else if (/^\/\//.test(obj.url)) { obj.url = "https:".concat(obj.url); } if (obj.f !== 'html' && (obj.url.indexOf('?f=json') === -1 || obj.url.indexOf('&f=json') === -1)) { obj.url += '&f=json'; } if (!obj.notJoinUrl && obj.f !== 'html') { obj.url = Url.joinUrl(obj.url); } var data = null; if (_typeof(obj.data) === 'object') { var d = obj.data; var ds = []; for (var k in d) { if (d.hasOwnProperty(k)) { ds.push("".concat(k, "=").concat(encodeURIComponent(d[k]))); } } data = ds.join('&'); } else { data = typeof obj.data === 'string' ? obj.data : null; } var header = { Cookie: document.cookie, referer: location.href }; var reqLogItem = networkStartLog({ method: obj.type || 'GET', url: obj.url, postData: obj.data || {}, requestHeader: header, requestType: 'jsapi' }); var retryTime = 1; var jsapiRequest = function jsapiRequest(obj, data) { return JSAPI.invoke('request', { url: obj.url, method: obj.type, data: data, header: header }, function (res) { var _a; if (res.err_msg.indexOf(':ok') > -1) { if (reqType(obj, '/mp/getappmsgext')) { window.receiveGetAppmsgExt = "".concat(res.statusCode, "|").concat(Date.now()); } if (reqType(obj, '/mp/getappmsgad')) { window.receiveGetAppmsgAd = "".concat(res.statusCode, "|").concat(Date.now()); } if (retryTime === 1) { obj.received && obj.received(null); } var resData = {}; if (res.data) { try { if (obj.dataType === 'json') { resData = JSON.parse(res.data); } else { resData = res.data; } if (resData && resData.base_resp && ((_a = resData.base_resp) === null || _a === void 0 ? void 0 : _a.ret) !== 0 && typeof window.WX_BJ_REPORT !== 'undefined' && window.WX_BJ_REPORT.BadJs && Math.random() < 0.001) { var reportUrl = obj.url; if (obj.url.indexOf('?') !== -1) { reportUrl = obj.url.substring(0, obj.url.indexOf('?')); if (Url.getQuery('action', obj.url)) { reportUrl = "".concat(reportUrl, "?action=").concat(Url.getQuery('action', obj.url)); } } if (!((reportUrl === '/mp/getappmsgext' || reportUrl === '/mp/getappmsgad') && typeof resData.base_resp.ret === 'undefined')) { window.WX_BJ_REPORT.BadJs.report(reportUrl, "ret=".concat(resData.base_resp.ret), { mid: window.PAGE_MID, view: 'wap_retcode' }); } } } catch (e) { console.error(e); obj.error && obj.error(null, { type: 1, error: e, status: res.statusCode }); obj.complete && obj.complete(); reqLogItem.endTime = Date.now(); reqLogItem.response = res; networkEndLog(reqLogItem); return; } } var tmpResData = {}; try { tmpResData = JSON.parse(res.data); } catch (e) {} if (tmpResData && tmpResData.base_resp && tmpResData.base_resp.ret === -3 && retryTime < 2 && (mmversion.isIOS || mmversion.isAndroid && mmversion.getInner() > '27000600')) { var _retryTime = retryTime++; JSAPI.invoke('updatePageAuth', {}, function (res) { console.log('[skeleton] updatePageAuth', res); monitor$1.setSum(112287, 3, 1); if (res && res.err_msg && res.err_msg.indexOf(':ok') > -1) { window.top.pass_ticket = encodeURIComponent(Url.getQuery('pass_ticket', res.fullUrl).html(false).replace(/\s/g, '+')); if (obj.pass_ticket) { obj.pass_ticket = window.top.pass_ticket; } console.warn('[skeleton] updatePageAuth resetTopbar'); var supportNewTopBar = mmversion.isIOS && mmversion.gtVersion('7.0.10', true); var showBottomBar = !!window.is_login; if (window.top.item_show_type === '0' && supportNewTopBar) { var _top = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop || 0; setCurrentMpInfo(_top > 40 && !showBottomBar); } try { obj.url = Url.addParam(obj.url, 'retry', _retryTime, true); } catch (err) { console.error(err); } jsapiRequest(obj, data); monitor$1.setSum(112287, 4, 1); } else { obj.success && obj.success(resData); obj.complete && obj.complete(); if (mmversion.isIOS) { monitor$1.setSum(112287, 35, 1); } else { monitor$1.setSum(112287, 36, 1); } reqLogItem.status = 200; reqLogItem.endTime = Date.now(); reqLogItem.response = resData; networkEndLog(reqLogItem); } }); } else { obj.success && obj.success(resData); obj.complete && obj.complete(); reqLogItem.status = 200; reqLogItem.endTime = Date.now(); reqLogItem.response = resData; networkEndLog(reqLogItem); } } else if (res.err_msg.indexOf('no permission') > -1 || !mmversion.isOnlyWechat) { Ajax(obj); if (res.err_msg.indexOf('no permission') > -1) { console.warn('[JSAPI Request] No permission'); monitor$1.setSum(112287, 31, 1); } reqLogItem.status = 302; reqLogItem.endTime = Date.now(); reqLogItem.response = res; networkEndLog(reqLogItem); } else { obj.error && obj.error(null, { type: 3, error: res, status: 0 }); obj.complete && obj.complete(); monitor$1.setSum(112287, 32, 1); var sample = 0.001; if (Math.random() < sample) { var msg = "request: ".concat(JSON.stringify(obj.type), " ").concat(JSON.stringify(obj.url), " ;;;; cookie: ").concat(JSON.stringify(document.cookie), " ;;;; data: ").concat(JSON.stringify(data), " ;;;; resp: ").concat(JSON.stringify(res)); if (window.WX_BJ_REPORT && window.WX_BJ_REPORT.BadJs) { window.WX_BJ_REPORT.BadJs.report('ajax_wx_request_error', msg, { mid: 'mmbizwap:Monitor' }); } } reqLogItem.status = 400; reqLogItem.endTime = Date.now(); reqLogItem.response = res; networkEndLog(reqLogItem); } }); }; if (reqType(obj, '/mp/getappmsgext')) { window.startGetAppmsgExtTime = Date.now(); } if (reqType(obj, '/mp/getappmsgad')) { window.startGetAppmsgAdTime = Date.now(); } return jsapiRequest(obj, data); } var ajax = function ajax(obj) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { ajax(obj); }); return; } if (!mmversion.isWxWork && (window.__second_open__ || !isAcrossOrigin && top.window.__second_open__) && window.__is_page_auth_return__) { return AjaxWx(obj); } return Ajax(obj); }; var timer = null; var jsmonitorReport = { setSum: function setSum(id, key, value) { throw new Error('Function not implemented.'); }, setAvg: function setAvg(id, key, value) { throw new Error('Function not implemented.'); }, setLogs: function setLogs(opt) { throw new Error('Function not implemented.'); }, send: function send(async) { throw new Error('Function not implemented.'); } }; window.__monitor_unload_has_done__ = false; jsmonitorReport.setSum = function (id, key, value) { monitor$1.setSum(id, key, value); return jsmonitorReport; }; jsmonitorReport.setAvg = function (id, key, value) { monitor$1.setAvg(id, key, value); return jsmonitorReport; }; jsmonitorReport.setLogs = function (opt) { monitor$1.setLogs(opt); return jsmonitorReport; }; jsmonitorReport.send = function (async) { if (async !== false) { async = true; } monitor$1.send(async, ajax); return jsmonitorReport; }; function reportInterval(fn, delay) { timer = window.setTimeout(function () { fn(); reportInterval(fn, delay); }, delay); } reportInterval(function () { jsmonitorReport.send(); }, 1 * 1000); window.addEventListener('unload', function () { if (window.__monitor_report_has_done__) return; window.__ajaxtest = '2'; if (timer) { window.clearTimeout(timer); timer = null; } jsmonitorReport.send(false); window.__monitor_unload_has_done__ = true; }, false); if (window.__jsmonitorReport) { jsmonitorReport = window.__jsmonitorReport; } else { window.__jsmonitorReport = jsmonitorReport; } var jsmonitorReport$1 = jsmonitorReport; function saveSpeeds(opt) { var sample = 0.001; if (typeof opt.sample === 'number') { sample = opt.sample; } var rand = Math.random(); if (rand < sample) { wxgsdk.saveSpeeds(opt); } } function setBasicTime(opt) { var sample = opt.sample || 0.001; var rand = Math.random(); if (rand < sample) { wxgsdk.setBasicTime(opt); } } function send() { wxgsdk.send(); } function jsmonitor(opt) { opt = opt || []; if (!Array.isArray(opt)) { var item = opt; opt = []; opt.push(item); } for (var i = 0; i < opt.length; i++) { var _item = opt[i]; var id = _item.id; var key = _item.key; var value = _item.value || 1; if (id !== undefined && key !== undefined) { jsmonitorReport$1.setSum(id, key, value); } } } var wxgspeedsdk = { saveSpeeds: saveSpeeds, setBasicTime: setBasicTime, send: send, jsmonitor: jsmonitor }; function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i["return"] && (_r = _i["return"](), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } var uuid = function uuid() { return ((1 + Math.random()) * 0x10000 | 0).toString(16).substring(1); }; var WRAP_TAG = 'span'; var IMG_TAG = 'IMG'; var NODE_TYPE = { text: 1, img: 2 }; var blockEleTagName = ['P', 'DIV', 'SECTION', 'LI', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'TABLE', 'PRE', 'BLOCKQUOTE']; var exceptEleClassName = ['js_product_container', 'js_blockquote_wrap']; var ignoreTagName = ['IFRAME', 'VIDEO', 'MPVOICE', 'MPGONGYI', 'QQMUSIC', 'MPSHOP', 'MP-WEAPP', 'MP-MINIPROGRAM', 'MPPRODUCT', 'MPCPS']; var ignoreEleId = ['js_mpvideo']; var ignoreEleClassName = ['js_product_container']; var TEMP_NODES = {}; var childNodesHasEle = function childNodesHasEle(element) { var tagNameList = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : blockEleTagName; if (!element || element.nodeType !== 1) { return false; } for (var i = 0; i < element.children.length; i++) { if (tagNameList.indexOf(element.children[i].tagName) !== -1) { return true; } } return false; }; function eleHasAttr(ele) { var attr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'className'; var AttrList = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : exceptEleClassName; for (var i = 0; i < AttrList.length; i++) { if (ele[attr] && typeof ele[attr] === 'string' && ele[attr].indexOf(AttrList[i]) > -1) { return true; } } return false; } var removeChildMedia = function removeChildMedia(element) { var parentNode = element.parentNode; element.parentNode.removeChild(element); if (parentNode.children && parentNode.children.length) { return false; } return true; }; var getParaList = function getParaList(element, _ref) { var _ref$getNestedStructu = _ref.getNestedStructure, getNestedStructure = _refgetNestedStructu, _ref$removeIgoreEle = _ref.removeIgoreEle, removeIgoreEle = _refremoveIgoreEle; var paraList = function getParaListWithIndex(ele, getNested) { var childNodes = ele.children; if (!childNodes) return []; if (!childNodes.length) { return childNodes; } var child; var paragraphList = []; for (var i = 0; i < childNodes.length; i++) { child = childNodes[i]; if (eleHasAttr(child, 'id', ignoreEleId) || eleHasAttr(child, 'className', ignoreEleClassName)) { if (removeIgoreEle) { child.parentNode.removeChild(child); i -= 1; } continue; } if (childNodesHasEle(child, ignoreTagName)) { if (removeIgoreEle) { removeChildMedia(child); i -= 1; } continue; } if (childNodesHasEle(child, blockEleTagName) && !eleHasAttr(child)) { paragraphList = paragraphList.concat(getParaListWithIndex(child, getNested)); if (getNested) { if (!child.getAttribute('data-index')) { paragraphList.push(child); } } } else { if (!child.getAttribute('data-index')) { paragraphList.push(child); } } } return paragraphList; }(element, getNestedStructure); return [].slice.call(paraList); }; getParaList.paragraphStartIdx = 1000000; var getSplitTextNode = function getSplitTextNode($textNode, startOffset, endOffset, paraIndex) { try { $textNode.splitText(startOffset); } catch (err) { if (typeof WX_BJ_REPORT !== 'undefined' && WX_BJ_REPORT.BadJs) { WX_BJ_REPORT.BadJs.report('ArticleMask:Error', 'splitText Error', { mid: 'mmbizwap:articlemask_Monitor', view: 'wap_business', _info: { type: 'getSplitTextNode textnode', startOffset: startOffset, endOffset: endOffset } }); } } var selectedNode = $textNode.nextSibling; try { selectedNode.splitText(endOffset - startOffset); } catch (e) { if (typeof WX_BJ_REPORT !== 'undefined' && WX_BJ_REPORT.BadJs) { WX_BJ_REPORT.BadJs.report('ArticleMask:Error', 'splitText Error', { mid: 'mmbizwap:articlemask_Monitor', view: 'wap_business', _info: { type: 'getSplitTextNode nextSibling', startOffset: startOffset, endOffset: endOffset } }); } } return [{ $node: selectedNode, type: NODE_TYPE.text, idx: paraIndex }]; }; var getBlockNode = function getBlockNode($node) { if (blockEleTagName.indexOf($node.tagName) !== -1 && typeof $node.dataset.index !== 'undefined') { return $node; } return getBlockNode($node.parentNode); }; var getPureBlockNode = function getPureBlockNode($node) { if (!$node) return $node; if (blockEleTagName.indexOf($node.tagName) !== -1) { return $node; } return getPureBlockNode($node.parentNode); }; var getNodesByDFS = function getNodesByDFS(range) { var start = range.start, end = range.end, container; var node, startOffset = start.offset; var node, endOffset = end.offset; var queue = []; var result = []; var withinSelectRange = false; var achiveSelectRangeEnd = false; var paraIndex = 0; queue.push($container); while (queue.length > 0) { var item = queue.pop(); var nodeType = item.nodeType, tagName = item.tagName; if (item.dataset && item.dataset.index) { paraIndex = +item.dataset.index; } if (withinSelectRange && !achiveSelectRangeEnd) { if (nodeType === 3) { result.push({ $node: item, type: NODE_TYPE.text, idx: paraIndex }); } if (tagName === IMG_TAG) { result.push({ $node: item, type: NODE_TYPE.img, idx: paraIndex }); } } if (item === $startNode) { if (nodeType === 3) { try { item.splitText(startOffset); } catch (e) { WX_BJ_REPORT.BadJs.report('ArticleMask:Error', 'splitText Error', { mid: 'mmbizwap:articlemask_Monitor', view: 'wap_business', _info: { type: 'getNodes startNode', startOffset: startOffset, endOffset: endOffset } }); } var $startTextNode = item.nextSibling; result.push({ startTextNode, type: NODE_TYPE.text, idx: paraIndex }); } else if (tagName === IMG_TAG) { result.push({ $node: item, type: NODE_TYPE.img, idx: paraIndex }); } else { result.push({ $node: item, type: NODE_TYPE.text, idx: paraIndex }); } withinSelectRange = true; } if (item === $endNode || achiveSelectRangeEnd) { if (!achiveSelectRangeEnd) { achiveSelectRangeEnd = true; } if (item === $endNode) result.pop(); if (nodeType === 3) { try { item.splitText(endOffset); } catch (e) { if (typeof WX_BJ_REPORT !== 'undefined' && WX_BJ_REPORT.BadJs) { WX_BJ_REPORT.BadJs.report('ArticleMask:Error', 'splitText Error', { mid: 'mmbizwap:articlemask_Monitor', view: 'wap_business', _info: { type: 'getSplitTextNode endNode', startOffset: startOffset, endOffset: endOffset } }); } } result.push({ $node: item, type: NODE_TYPE.text, idx: paraIndex }); break; } else if (tagName === IMG_TAG) { result.push({ $node: item, type: NODE_TYPE.img, idx: paraIndex }); break; } else { var _children = item.childNodes; for (var i = _children.length - 1; i >= 0; i--) { queue.push(_children[i]); } } } var children = item.childNodes; for (var _i = children.length - 1; _i >= 0; _i--) { queue.push(children[_i]); } } return result; }; var getSelectedNodes = function getSelectedNodes(range) { var start = range.start, end = range.end; var node, startOffset = start.offset; var node, endOffset = end.offset; if (endNode && $startNode instanceof Text) { return getSplitTextNode($startNode, startOffset, endOffset, start.paraIndex); } return getNodesByDFS(range); }; var checkTextNode = function checkTextNode($node) { return $node && (node.innerText); }; var connectSiblingText = function connectSiblingText(prev, next, target) { var $delete = target === prev ? next : prev; if (!checkTextNode(prev) || !checkTextNode(next)) { return $delete; } var text = (prev.nodeValue || prev.innerText) + (next.nodeValue || next.innerText); target.nodeValue = text; target.parentNode.removeChild($delete); return target; }; var getTextNodeByOffset = function getTextNodeByOffset($parentNode, offset) { var queue = []; var curOffset = 0; var startOffset = 0; var $curNode; queue.push($parentNode); while (queue.length > 0) { $curNode = queue.pop(); if ($curNode.nodeType === 3) { startOffset = offset - curOffset; curOffset += $curNode.textContent.length; if (curOffset >= offset) { break; } } var children = $curNode.childNodes; for (var i = children.length - 1; i >= 0; i--) { queue.push(children[i]); } } return { parentNode, curNode, offset: startOffset }; }; function getBlockOffset(_ref2) { var blockNode, node; if ($blockNode === null) { return null; } var queue = []; var offset = 0; queue.push($blockNode); while (queue.length > 0) { var item = queue.pop(); if (item.nodeType === 3 && item.nodeValue !== $node.nodeValue) { offset += item.textContent.length; } else if (item.nodeType === 1) { offset += 1; if (item === $node) break; } else if (item.nodeValue === $node.nodeValue) { offset += item.textContent.length; break; } var children = item.childNodes; for (var i = children.length - 1; i >= 0; i--) { queue.push(children[i]); } } return offset; } var getDomMeta = function getDomMeta(selection) { selection.$node; var parentNode; var parentIndex = Number($parentNode.dataset.index); var offset = getBlockOffset($parentNode); return { parentIndex: parentIndex, fromParentoffset: offset }; }; function nodeToSelection($node) { var $blockNode = getBlockNode($node); var paraIndex = +$blockNode.dataset.index; var offset = 0; var item = { blockNode, node, paraIndex: paraIndex, offset: offset }; var id = uuid(); return { start: item, end: item, id: id }; } var getSelection = function getSelection() { var selection = window.getSelection(); if (selection.anchorNode === null) { return null; } var selectionRange = selection.getRangeAt(0); if (!selectionRange || !selection.toString()) { return null; } var startContainer = selectionRange.startContainer, endContainer = selectionRange.endContainer, commonAncestorContainer = selectionRange.commonAncestorContainer, startOffset = selectionRange.startOffset, endOffset = selectionRange.endOffset; var $startBlockNode = getBlockNode(startContainer); var $endBlockNode = getBlockNode(endContainer); var startIndex = startBlockNode.dataset.index; var endIndex = endBlockNode.dataset.index; var start = { startBlockNode, $node: startContainer, offset: startOffset, paraIndex: Number(startIndex) }; var end = { endBlockNode, $node: endContainer, offset: endOffset, paraIndex: Number(endIndex) }; var $container = typeof commonAncestorContainer === 'string' ? commonAncestorContainer.parentNode : commonAncestorContainer; var id = uuid(); return { start: start, end: end, container, id: id }; }; var transferTextToElement = function transferTextToElement($node, id) { if (!$node) return null; if ($node.nodeType === 3) { var $wrap = document.createElement(WRAP_TAG); $wrap.setAttribute('data-splitid', id); $wrap.appendChild($node.cloneNode(false)); if ($node.parentNode) { $node.parentNode.replaceChild(node); } return $wrap; } return $node; }; var serialize = function serialize(selectionRange) { var start = selectionRange.start, end = selectionRange.end, id = selectionRange.id; var startParaOffset = getBlockOffset(start); var endParaOffset = start.node ? end.offset - start.offset + startParaOffset : getBlockOffset(end); var meta = { id: id, start: { para_offset: startParaOffset, para_index: start.paraIndex }, end: { para_offset: endParaOffset, para_index: end.paraIndex } }; return meta; }; var mapMetaToLocal = function mapMetaToLocal(paraList) { return function (meta) { var paraOffset = meta.para_offset, paraIndex = meta.para_index; var $blockNode = paraList[paraIndex]; var queue = []; var curOffset = 0; var offset = 0; var $curNode; queue.push($blockNode); while (queue.length > 0) { $curNode = queue.pop(); if ($curNode.nodeType === 3) { offset = paraOffset - curOffset; curOffset += $curNode.textContent.length; if (curOffset >= paraOffset) { break; } } if ($curNode.nodeType === 1) { offset = paraOffset - curOffset; curOffset += 1; if (curOffset >= paraOffset) { break; } } var children = $curNode.childNodes; for (var i = children.length - 1; i >= 0; i--) { queue.push(children[i]); } } return { blockNode, curNode, offset: offset, paraIndex: paraIndex }; }; }; var deSerialize = function deSerialize(meta, paraList, $container) { var desparaList = mapMetaToLocal(paraList); return { start: desparaList(meta.start), end: desparaList(meta.end), id: meta.id, container }; }; function getTextNode($node) { if (node.nodeType === 3) { return $node; } return $node.childNodes[0]; } var resetRange = function resetRange(selectionRange) { window.getSelection().removeAllRanges(); var selection = window.getSelection(); var range = document.createRange(); var $startnode = getTextNode(TEMP_NODES.start); var $endnode = getTextNode(TEMP_NODES.end); range.setStart($startnode, selectionRange.start.offset); range.setEnd($endnode, selectionRange.end.offset); selection.addRange(range); }; var getNodeIndex = function getNodeIndex(node) { var queue = []; var index = 0; queue.push($block); while (queue.length > 0) { var $item = queue.pop(); if (node) break; index++; var children = $item.children; for (var i = 0; i < children.length; i++) { queue.push(children[i]); } } return index; }; var getNodeByIndex = function getNodeByIndex($block, index) { var queue = []; var cursor = 0; var $result = null; queue.push($block); while (queue.length > 0) { var $item = queue.pop(); if (cursor === index) { item; break; } cursor++; var children = $item.children; for (var i = 0; i < children.length; i++) { queue.push(children[i]); } } return $result; }; var hasClass = function hasClass(cls, className) { if (cls && typeof cls === 'string' && cls.indexOf(className) !== -1) { return true; } return false; }; var inWhiteList = function inWhiteList(classAttr) { var classWhiteList = 'rich_pages,blockquote_info,blockquote_biz,blockquote_other,blockquote_article,js_jump_icon,h5_image_link,js_banner_container,js_list_container,js_cover,js_tx_video_container,js_product_err_container,js_product_loop_content,js_product_container,img_loading,list-paddingleft-1,list-paddingleft-2,list-paddingleft-3,selectTdClass,noBorderTable,ue-table-interlace-color-single,ue-table-interlace-color-double,__bg_gif,weapp_image_link,js_img_loading,wx_video_context,db,wx_video_thumb_primary,wx_video_play_btn,wx_video_mask,qqmusic_area,tc,tips_global,unsupport_tips,qqmusic_wrp,appmsg_card_context,appmsg_card_active,wx_tap_card,js_wx_tap_highlight,wx_tap_link,qqmusic_bd,play_area,icon_qqmusic_switch,pic_qqmusic_default,qqmusic_thumb,access_area,qqmusic_songname,qqmusic_singername,qqmusic_source,js_audio_frame,share_audio_context,flex_context,pages_reset,share_audio_switch,icon_share_audio_switch,share_audio_info,flex_bd,share_audio_title,share_audio_tips,share_audio_progress_wrp,share_audio_progress,share_audio_progress_inner,share_audio_progress_buffer,share_audio_progress_loading,share_audio_progress_loading_inner,share_audio_progress_handle,share_audio_desc,share_audio_length_current,share_audio_length_total,video_iframe,vote_iframe,js_editor_vote_card,res_iframe,card_iframe,js_editor_card,weapp_display_element,js_weapp_display_element,weapp_card,app_context,weapp_card_bd,weapp_card_profile,radius_avatar,weapp_card_avatar,weapp_card_nickname,weapp_card_info,weapp_card_title,weapp_card_thumb_wrp,weapp_card_ft,weapp_card_logo,js_pay_btn,pay,pay__mask,wx_video_loading,js_redpacketcover,js_uneditable,js_uneditablemouseover,js_editor_qqmusic,js_img_placeholder,js_editor_audio,ct_geography_loc_tip,js_poi_entry,js_mention_entry,product_text_link'.split(','); var qaClassPrefix = 'qa__'; var classWhiteListReg = [new RegExp('^weui'), new RegExp('^appmsg'), new RegExp('^audio'), new RegExp('^music'), new RegExp('^cps_inner'), new RegExp('^bizsvr_'), new RegExp('^code-snippet'), new RegExp('^' + qaClassPrefix), new RegExp('^wx-edui-'), new RegExp('^wx_'), new RegExp('^wx-'), new RegExp('^custom_select_card_') ]; if (!classAttr) return null; var classList = classAttr.split(/\s+/); var newClassList = []; for (var i = 0, len = classList.length; i < len; ++i) { var className = classList[i]; if (className && classWhiteList.indexOf(className) !== -1) { newClassList.push(className); } else { for (var j = 0, jl = classWhiteListReg.length; j < jl; j++) { if (classWhiteListReg[j].test(className)) { newClassList.push(className); break; } } } } var str = newClassList.join('.'); return str && '.' + str; }; var getNodeSelector = function getNodeSelector(node) { var selector = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; var root = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : document.body; if (!node || node === root) return selector; var id = node.getAttribute('id'); var className = node.getAttribute('class'); var tagName = node.tagName.toLowerCase(); var currentSelector = null; if (id && !hasClass(className, 'articlepart-selector-area_choice-button_wrap')) return selector ? "#".concat(id, ">").concat(selector) : "#".concat(id); var whiteClassName = inWhiteList(className); if (whiteClassName) { currentSelector = whiteClassName; } else if (hasClass(className, 'js_choice-img')) { currentSelector = '.js_choice-img'; } else if (hasClass(className, 'articlepart-selector-area_choice')) { currentSelector = node.dataset.splitid ? '' : tagName; } else { currentSelector = tagName; } return getNodeSelector(node.parentNode, [currentSelector, selector].filter(function (item) { return !!item; }).join('>'), root); }; var getNodeSelectorWrap = function getNodeSelectorWrap(node, root) { var selector = getNodeSelector(node, '', root); var collect = []; try { collect = root.querySelectorAll(selector); } catch (error) { console.log('get node selector wrap err', error); } var len = collect.length; var index = null; for (var i = 0; i < len; i++) { if (node === collect[i]) { index = i; break; } } if (index === null) { if (typeof WX_BJ_REPORT !== 'undefined' && WX_BJ_REPORT.BadJs) { WX_BJ_REPORT.BadJs.report('ArticleMask:Error', 'selector:node not find', { mid: 'mmbizwap:articlemask_Monitor', view: 'wap_business', _info: { selector: selector } }); } } var newSelector = (selector || '').replace('>.js_choice-img>', '>') + "|".concat(len, " ").concat(index || 0); return newSelector; }; var serializeToC = function serializeToC(nodes) { return ( nodes.map(function (item) { var node, type = item.type, idx = item.idx; var index = 0; var data = null; var meta = ''; var blockItem = getBlockNode($node); if (type === NODE_TYPE.text) { var nodeIndex = getNodeIndex(blockItem, $node.parentNode); if (node.data) { index = nodeIndex; data = $node.data; meta = node.previousSibling.data; } } else if (type === NODE_TYPE.img) { var imgs = blockItem.getElementsByTagName('img'); data = $node.src; index = Array.prototype.slice.call(imgs).slice(0).indexOf($node); } return { data: data, index: index, idx: idx, type: type, meta: meta }; }).filter(function (item) { return item.index > -1 && !!item.data; }) ); } ; var serializeToC2 = function serializeToC2(nodes, $container) { var root = $container || document.getElementById('js_content'); return nodes.map(function (item) { var node, type = item.type, idx = item.idx; var selector = null; var data = null; var meta = ''; if (type === NODE_TYPE.text) { if (node.data) { selector = getNodeSelectorWrap($node.parentNode, root); data = $node.data; meta = node.previousSibling.data; } } else if (type === NODE_TYPE.img) { selector = getNodeSelectorWrap($node, root); data = $node.src; } return { data: data, idx: idx, type: type, meta: meta, selector: selector }; }).filter(function (item) { return !!item.selector && !!item.data; }); }; function setProperty(el, name, value, priority) { if (!!el.style.setProperty) { priority = priority || null; el.style.setProperty(name, value, priority); } else if (typeof el.style.cssText !== 'undefined') { priority = priority ? '!' + priority : ''; el.style.cssText += ';' + name + ':' + value + priority + ';'; } } function hasImgNode($el) { if (!$el) return false; var nodeType = $el.nodeType, tagName = $el.tagName; if (nodeType === 3) { return false; } if (tagName === IMG_TAG) { return true; } return false; } function getContent(tree) { return tree.reduce(function (acc, cur, idx) { if (idx === 0) { if (cur.type === NODE_TYPE.text) { acc.text.push(cur.data); } else if (cur.type === NODE_TYPE.img) { acc.pic.push(cur.data); } return acc; } if (cur.type === NODE_TYPE.text) { if (tree[idx - 1].type === NODE_TYPE.text) { var text = acc.text.pop(); text += cur.data; acc.text.push(text); } else { acc.text.push(cur.data); } return acc; } if (cur.type === NODE_TYPE.img) { acc.pic.push(cur.data); } return acc; }, { audio: [], pic: [], video: [], text: [] }); } function saveNode($node, key) { TEMP_NODES[key] = $node; } function serializeNode(wrap) { var range = nodeToSelection($node); var anchorTree = serializeToC2([{ node, type: NODE_TYPE.img, idx: range.start.paraIndex }], $wrap); var anchorMeta = serialize(range); var anchorBrief = getContent(anchorTree); return { meta: { anchorTree: anchorTree, anchorMeta: anchorMeta, anchorBrief: anchorBrief }, range: range }; } function findChildIndex(parent, offset) { var childNodes = parent.childNodes; var realOffset = offset; var $node = null; var i = 0; for (i = 0; i < childNodes.length; i++) { $node = childNodes[i]; if ($node.nodeType === 3) { var len = $node.length; if (len > realOffset) { break; } else { realOffset -= len; } } } return { node, cursor: realOffset }; } var qs = function qs(selector, el) { return (el || document).querySelector(selector); }; var qsAll = function qsAll(selector, el) { return (el || document).querySelectorAll(selector); }; var dom = { getDomMeta: getDomMeta, getContent: getContent, getParaList: getParaList, getBlockNode: getBlockNode, getSelectedNodes: getSelectedNodes, connectSiblingText: connectSiblingText, getTextNodeByOffset: getTextNodeByOffset, getBlockOffset: getBlockOffset, getSelection: getSelection, transferTextToElement: transferTextToElement, serialize: serialize, deSerialize: deSerialize, resetRange: resetRange, serializeToC: serializeToC, setProperty: setProperty, hasImgNode: hasImgNode, nodeToSelection: nodeToSelection, saveNode: saveNode, serializeNode: serializeNode, getNodeByIndex: getNodeByIndex, findChildIndex: findChildIndex, serializeToC2: serializeToC2, blockEleTagName: blockEleTagName, getPureBlockNode: getPureBlockNode, qs: qs, qsAll: qsAll, hasClass: hasClass }; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } var paraList = []; var totalHit = 0; var STATUS = { auditing: 1, ban: 2 }; function keyby(arr, key) { return arr.reduce(function (acc, item) { if (typeof item[key] === 'undefined') return acc; if (!acc[item[key]]) acc[item[key]] = []; acc[item[key]].push(item); return acc; }, {}); } function getBannerWord(anchor) { return '以下内容存在争议 <a style="color: var(--weui-LINK);" target="_blank" href="https://mp.weixin.qq.com/s/_2kC-fXw7UjneZSrsC9CVQ">了解更多</a>'; } function addBanner(node, text) { var paraNode = _typeof(node) === 'object' ? node : paraList[node]; if (paraNode.dataset.hasBanner) return; var divNode = document.createElement('div'); divNode.dataset.hasBanner = 1; divNode.style = 'background-color: var(--weui-BG-1);font-size: 14px;color: var(--weui-FG-2);text-align: left;margin-top: 20px;margin-bottom: 4px;padding: 4px 8px 6px 8px;border-radius:4px;'; var iconNode = document.createElement('span'); iconNode.style = 'color: var(--weui-FG-0);padding: 2px;display: inline-block;vertical-align: middle; width: 20px;height: 20px;margin-right: 4px; background-size: cover;background-position: center center;-webkit-mask: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'20\' height=\'20\' viewBox=\'0 0 20 20\'%3E %3Cpath fill-opacity=\'.3\' fill-rule=\'evenodd\' d=\'M10 1.667a8.333 8.333 0 1 1 0 16.666 8.333 8.333 0 0 1 0-16.666zm-.004 11.115a.732.732 0 0 0-.746.735c0 .416.33.735.746.735a.73.73 0 0 0 .752-.735.73.73 0 0 0-.752-.735zm.638-7.669h-1.27l.091 6.33h1.088l.091-6.33z\'/%3E%3C/svg%3E") no-repeat 50% 50%;mask: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'20\' height=\'20\' viewBox=\'0 0 20 20\'%3E %3Cpath fill-opacity=\'.3\' fill-rule=\'evenodd\' d=\'M10 1.667a8.333 8.333 0 1 1 0 16.666 8.333 8.333 0 0 1 0-16.666zm-.004 11.115a.732.732 0 0 0-.746.735c0 .416.33.735.746.735a.73.73 0 0 0 .752-.735.73.73 0 0 0-.752-.735zm.638-7.669h-1.27l.091 6.33h1.088l.091-6.33z\'/%3E%3C/svg%3E") no-repeat 50% 50%;background-color: currentColor;'; var textNode = document.createElement('span'); textNode.style = 'display: inline-block;line-height: 14px;vertical-align: middle;'; textNode.innerHTML = text; divNode.appendChild(iconNode); divNode.appendChild(textNode); paraNode.parentNode.insertBefore(divNode, paraNode, null); paraNode.dataset.hasBanner = 1; } function maskText(data, domNode, cursor) { var len = data.length; var maskMat = _toConsumableArray(Array(len)).map(function () { return '〇'; }).join(''); var childNodes = domNode.childNodes; var newCursor = cursor; for (var i = 0; i < childNodes.length; i++) { var node = childNodes[i]; if (node.nodeType === 3) { if (newCursor > node.data.length) { newCursor -= node.data.length; } else { node.data = node.data.slice(0, newCursor).concat(maskMat).concat(node.data.slice(newCursor + len)); } } else if (node.nodeText === 1) { newCursor -= node.innerText && node.innerText.length || 0; } } } function disputeText(data, domNode, cursor) { var len = data.length; var _dom$findChildIndex = dom.findChildIndex(domNode, cursor), textNode = _domnode, realOffset = _dom$findChildIndex.realOffset; try { textNode.splitText(realOffset); } catch (e) { if (typeof WX_BJ_REPORT !== 'undefined' && WX_BJ_REPORT.BadJs) { WX_BJ_REPORT.BadJs.report('ArticleMask:Error', 'splitText Error', { mid: 'mmbizwap:articlemask_Monitor', view: 'wap_business', _info: { type: 'disputeText textNode', data: data, cursor: cursor } }); } } var repalcedNode = textNode.nextSibling; try { repalcedNode.splitText(len); } catch (e) { if (typeof WX_BJ_REPORT !== 'undefined' && WX_BJ_REPORT.BadJs) { WX_BJ_REPORT.BadJs.report('ArticleMask:Error', 'splitText Error', { mid: 'mmbizwap:articlemask_Monitor', view: 'wap_business', _info: { type: 'disputeText nextSibling', data: data, cursor: cursor } }); } } var spanNode = document.createElement('span'); spanNode.style = 'background-color: rgba(0,0,0,0.10);'; spanNode.appendChild(repalcedNode.cloneNode(true)); repalcedNode.parentNode.replaceChild(spanNode, repalcedNode); } function disputeImage(data, domNode) { var spanNode = document.createElement('span'); spanNode.style = 'position:relative;display: inline-block;'; var iconNode = document.createElement('span'); iconNode.style = "\n position: absolute;\n top: 4px;\n left: 4px;\n display: inline-block;\n vertical-align: middle;\n width: 24px;\n height: 24px;\n background-size: cover;\n background-image: url(\"data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E %3Cpath fill='%23FFF' fill-rule='evenodd' d='M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2zm-.004 13.339a.878.878 0 0 0-.896.882c0 .499.396.882.896.882.512 0 .902-.383.902-.882 0-.5-.39-.882-.902-.882zm.765-9.203h-1.524l.11 7.596h1.305l.11-7.596z'/%3E%3C/svg%3E\");\n "; var parent = domNode.parentNode; spanNode.appendChild(domNode.cloneNode(false)); parent.replaceChild(spanNode, domNode); spanNode.appendChild(iconNode); } function maskImage(data, domNode) { domNode.style.filter = 'blur(10px)'; domNode.style['-webkit-filter'] = 'blur(10px)'; } function hitMaskText(anchor, domNode) { var data = anchor.data, meta = anchor.meta, index = anchor.index, idx = anchor.idx; var wholeText = domNode.data; var prefixText = (meta || '') + data; if (wholeText.indexOf(prefixText) === -1) { return { hit: false }; } var itemNode = dom.getNodeByIndex(paraList[idx], index); if (itemNode) { totalHit++; } else { if (typeof WX_BJ_REPORT !== 'undefined' && WX_BJ_REPORT.BadJs) { WX_BJ_REPORT.BadJs.report('ArticleMask:Error', 'text node cannot find', { mid: 'mmbizwap:articlemask_Monitor', view: 'wap_business', _info: { anchor: anchor, wholeText: wholeText } }); } } var cursor = itemNode && itemNode.innerText.indexOf(prefixText) + (meta || '').length; return { hit: !!itemNode, $hitDom: itemNode, cursor: cursor }; } function hitMaskImage(anchor, domNode) { var index = anchor.index, idx = anchor.idx, data = anchor.data; var para = paraList[idx]; var allImgNode = para.querySelectorAll('img'); var hitItenNode = allImgNode[index]; var src = hitItenNode && (hitItenNode.getAttribute('src') || hitItenNode.getAttribute('src')); if (src === data) { totalHit++; return { hit: true, $hitDom: domNode, cursor: 0 }; } return { hit: false }; } function createMask(anchor, domNode) { return function (hitFn, maskFn, next) { var _hitFn = hitFn(anchor, domNode), hit = _hitFn.hit, hitDom, cursor = _hitFn.cursor; if (hit) { maskFn(anchor.data, $hitDom, cursor); next(); } }; } function maskAnchors(anchors, paraNode) { var queue = []; var cloneAnchors = _toConsumableArray(anchors); queue.push(paraNode); var anchor = null; var next = function next() { anchor = cloneAnchors.shift(); }; next(); while (queue.length > 0 && cloneAnchors.length >= 0 && anchor) { var itemNode = queue.pop(); if (!itemNode) continue; if (!anchor) continue; var nodeType = itemNode.nodeType, tagName = itemNode.tagName; var createMaskFn = createMask(anchor, itemNode); if (nodeType === 3) { if (anchor.type === NODE_TYPE.text) { createMaskFn(hitMaskText, anchor.status === STATUS.ban ? maskText : disputeText, next); } continue; } if (nodeType === 1 && tagName === IMG_TAG) { if (anchor.type === NODE_TYPE.img) { createMaskFn(hitMaskImage, anchor.status === STATUS.ban ? maskImage : disputeImage, next); } continue; } var children = itemNode.childNodes; for (var i = children.length - 1; i >= 0; i--) { queue.push(children[i]); } } } function parseSelector(selectorStr) { if (!selectorStr) return {}; var _selectorStr$split = selectorStr.split('|'), _selectorStr$split2 = _slicedToArray(_selectorStr$split, 2), selector = _selectorStr$split2[0], other = _selectorStr$split2[1]; var _other$split = other.split(' '), _other$split2 = _slicedToArray(_other$split, 2), total = _other$split2[0], index = _other$split2[1]; return { selector: selector.replace(/>/g, '>'), total: total * 1, index: index * 1 }; } function hitNode(node, anchor) { if (!node) return null; var type = anchor.type, data = anchor.data, meta = anchor.meta; if (type === NODE_TYPE.text) { var nodeText = node.innerText || node.innerHTML || ''; var prefixText = ((meta || '') + data).replace(/&/g, '&'); if (nodeText.indexOf(prefixText) !== -1) { var cursor = nodeText.indexOf(prefixText) + (meta || '').length; return { cursor: cursor, node: node }; } } if (type === NODE_TYPE.img) { var src = node && (node.getAttribute('src') || node.getAttribute('src')); if (src === data.replace(/&/g, '&')) { return { cursor: 0, node: node }; } } return null; } function maskNode(anchor, domNode, cursor) { var type = anchor.type, data = anchor.data, status = anchor.status; if (status !== STATUS.ban) return; if (type === NODE_TYPE.text) maskText(data, domNode, cursor); if (type === NODE_TYPE.img) maskImage(data, domNode); } function initOld(wrapNode, anchors) { paraList = dom.getParaList(wrapNode, { getNestedStructure: true, removeIgoreEle: false }); var formatAnchor = keyby(anchors, 'idx'); if (!paraList) return; (paraList || []).forEach(function (para, index) { var paraAnchors = formatAnchor[index]; if (paraAnchors && paraAnchors.length > 0) { addBanner(index, getBannerWord(paraAnchors[0])); maskAnchors(paraAnchors, para); } }); if (anchors && anchors.length !== totalHit) { if (typeof WX_BJ_REPORT !== 'undefined' && WX_BJ_REPORT.BadJs) { WX_BJ_REPORT.BadJs.report('ArticleMask:Error', 'totalHit', { mid: 'mmbizwap:articlemask_Monitor', view: 'wap_business', _info: { totalHit: totalHit, anchors: anchors } }); } } } function addChildBanner(node, anchor) { var blockNode = dom.getPureBlockNode(node); if (!blockNode) return; addBanner(blockNode, getBannerWord()); } function maskAnchors2(wrapNode, anchors) { var missNodes = []; var countList = []; var maskNodeList = []; var cacheSelector = {}; anchors.forEach(function (anchor, i) { var _parseSelector = parseSelector(anchor.selector), selector = _parseSelector.selector, index = _parseSelector.index, total = _parseSelector.total; var nodes = cacheSelector[selector] || []; if (nodes.length === 0) { try { nodes = wrapNode.querySelectorAll(selector); cacheSelector[selector] = nodes; } catch (e) { if (typeof WX_BJ_REPORT !== 'undefined' && WX_BJ_REPORT.BadJs) { WX_BJ_REPORT.BadJs.report('ArticleMask:Error', 'splitText Error', { mid: 'mmbizwap:articlemask_Monitor', view: 'wap_business', _info: { anchor: anchor } }); } } } var cursorLeft = index; var cursorRight = index; var queue = []; var node = null; var cursor = 0; var count = 0; queue.push(nodes[index]); while (queue.length) { var current = queue.pop(); var hitData = hitNode(current, anchor); count++; if (hitData && hitData.node) { node = hitData.node; cursor = hitData.cursor; break; } if (cursorLeft - 1 >= 0 && nodes[cursorLeft - 1]) { queue.push(nodes[cursorLeft - 1]); cursorLeft -= 1; } if (cursorRight + 1 < nodes.length && nodes[cursorRight + 1]) { queue.push(nodes[cursorRight + 1]); cursorRight += 1; } } if (node) { maskNodeList.push({ anchor: anchor, node: node, cursor: cursor }); addChildBanner(node); } else if (selector && selector.lastIndexOf('>') !== -1) { missNodes.push(_objectSpread(_objectSpread({}, anchor), {}, { selector: selector && selector.slice(0, selector.lastIndexOf('>')) + "|".concat(total, " ").concat(index) })); } countList[i] = count; }); maskNodeList.forEach(function (item) { maskNode(item.anchor, item.node, item.cursor); }); if (missNodes.length) { maskAnchors2(wrapNode, missNodes); if (typeof WX_BJ_REPORT !== 'undefined' && WX_BJ_REPORT.BadJs) { WX_BJ_REPORT.BadJs.report('ArticleMask:Error', 'missNodes', { mid: 'mmbizwap:articlemask_Monitor', view: 'wap_business', _info: { missNodes: missNodes } }); } } if (typeof WX_BJ_REPORT !== 'undefined' && WX_BJ_REPORT.BadJs) { WX_BJ_REPORT.BadJs.report('ArticleMask:Info', 'querycount', { mid: 'mmbizwap:articlemask_Monitor', view: 'wap_business', _info: { countList: countList } }); } } function init2(wrapNode, anchors) { maskAnchors2(wrapNode, anchors); } function init(wrapNode, anchors) { var oldAnchors = []; var newAnchors = []; anchors.forEach(function (anchor) { if (anchor.selector) { newAnchors.push(anchor); } else { oldAnchors.push(anchor); } }); init2(wrapNode, newAnchors); if (oldAnchors.length > 0) { initOld(wrapNode, oldAnchors); } } var complainPainter = { init: init }; try { if (window.anchor_tree_msg) { var start = Date.now(); var $wrap = document.getElementById('js_content'); var anchors = window.anchor_tree_msg ? JSON.parse(window.anchor_tree_msg).anchor_tree : []; var protocol = window.location.protocol; complainPainter.init($wrap, anchors); wxgspeedsdk.saveSpeeds({ sample: 1, uin: window.uin, pid: protocol == 'https:' ? 462 : 417, speeds: { sid: 38, time: Date.now() - start } }); wxgspeedsdk.send(); } } catch (error) { if (typeof WX_BJ_REPORT !== 'undefined' && window.WX_BJ_REPORT.BadJs) { window.WX_BJ_REPORT.BadJs.onError(error, { anchor_tree_msg: window.anchor_tree_msg }); } } })();</script><script type="text/javascript" nonce="1989770072" reportloaderror>(function () { 'use strict'; var AD_TYPE = { ANDROID_APP_PRODUCT_TYPE: 12, IOS_APP_PRODUCT_TYPE: 19, ADD_CONTACT_PRODUCT_TYPE: 23, MINI_GAME_PRODUCT_TYPE: 46, CARD_PRODUCT_TYPE: 36, SHOP_PRODUCT_TYPE: 30, WECHATCARD_PRODUCT_TYPE: 47, BRAND_WECHAT_PRODUCT_TYPE: 29, BRAND_GDT_PRODUCT_TYPE: 31 }; var AD_POS = { POS_BOTTOM: 0, POS_BOTTOM_PC: 38, POS_MID: 4, POS_MID_PC: 39, POS_SPONSOR: 3, POS_AD_BEFORE_VIDEO: 7, POS_AD_AFTER_VIDEO: 9, POS_AD_MID_VIDEO: 16, POS_AD_KEYWORD: 36 }; var AD_DEST_TYPE = { AD_DEST_TYPE: 0, OUTER_DEST_TYPE: 1, APPDETAIL_DEST_TYPE: 2, BIZ_DEST_TYPE: 3, APPINFO_PAGE_DEST_TYPE: 4, WECHAT_SHOP_DEST_TYPE: 5, WECHAT_APPLET_DEST_TYPE: 6, LEAF_DEST_TYPE: 7, CANVAS_AD_DEST_TYPE: 9 }; var AD_CACHE_TIME = 0.5 * 60 * 1000; var AD_JSAPI_WHITE_LIST = ['openUrlWithExtraWebview', 'openADCanvas', 'addContact', 'profile', 'getInstallState', 'installDownloadTask', 'addDownloadTask', 'pauseDownloadTask', 'resumeDownloadTask', 'queryDownloadTask', 'launchApplication', 'writeCommData', 'adDataReport', 'downloadAppInternal', 'wxdownload:progress_change', 'menu:share:appmessage', 'menu:share:timeline', 'menu:share:weibo', 'menu:share:facebook', 'menu:general:share', 'launch3rdApp', 'addDownloadTaskStraight', 'sendAppMessage', 'shareTimeline', 'getNetworkType', 'openBizChat', 'jumpToBizProfile', 'shareWeibo', 'shareFB', 'imagePreview', 'getBackgroundAudioState', 'openWeApp', 'openEmbeddedWeApp', 'preloadMiniProgramContacts', 'preloadMiniProgramEnv', 'calRqt', 'openCardDetail', 'batchAddCard', 'handleMPPageAction', 'makePhoneCall', 'getOAID', 'saveWaid', 'batchPreloadMiniProgram', 'onScreenShot', 'handleAdAction', 'activity:state_change', 'getAdIdInfo', 'onWebPageUrlExposed', 'openFinderView', 'predownloadMiniProgramPackage', 'openCustomerServiceChat', 'showOpenIMContactProfile', 'openWXSearchPage']; var AD_REQ_PATH_WHITE_LIST = [ '/mp/advertisement_report', '/mp/ad_report', '/mp/ad_video_report', '/mp/jsmonitor', '/mp/ad_complaint', '/mp/jsreport', '/tp/datacenter/report', '/mp/getappmsgad', '/mp/ad_biz_info', '/mp/appmsg_video_snap', '/mp/cps_product_info', '/mp/mini_drama_info']; var AD_WEB_COMPT_REQ_PATH_WHITE_LIST = [/(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/advertisement_report/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/ad_report/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/ad_video_report/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/jsmonitor/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/ad_complaint/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/jsreport/, /(https?:)?\/\/mp\.weixin\.qq\.com\/tp\/datacenter\/report/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/getappmsgad/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/ad_biz_info/, /(https?:)?\/\/mp\.weixin\.qq\.com\/tp\/goods_info/, /(https?:)?\/\/mp\.weixin\.qq\.com\/tp\/app_mobile/, /(https?:)?\/\/mp\.weixin\.qq\.com\/tp\/datareport\/report/, /(https?:)?\/\/mp\.weixin\.qq\.com\/promotion\/wxalandpage\/getcanvasinfo/]; var transformText = '转化按钮'; var extraText = '广告文案或辅助信息'; var defaultMidAdData = { hint_txt: '创意-20200827_1', url: 'https://ad.weixin.qq.com/guide/196?weixinadkey=59d5cf0b4fbf7d2f66cd90aaa82a5208057512dd06fcb64d7fd57e71ec15945e1744ac499e05a04999381c3bf30c21ca&gdt_vid=wx0clsqxat6lzly601&weixinadinfo=315019981.wx0clsqxat6lzly601.75.1', type: '0', rl: 'http://ad.wx.com:12638/cgi-bin/click?viewid=AQM1xOr6MFeZmWeZrowCvQcrvQUBUq4o8ER2yFgwF9grPdtUR9bIJQ8laqMAJjGlkGLuVbyABIPX6Eifa2%2FK%2Buq17IIT21tYcUnpeU4VqEEsEQhc5Pa7C7drAvl0Mz30CNepODMXeD%2BEdny8SmmxN7prV78e1L2S6oqhNjrnTqM1t40ZGU84httoAODXEjmE89IX0ncOiP1oTsgm1tYwahSkxN6HLZIb6bhxZrc5ba3mCKMZ5GV4UEyDuQCyySxtA5QTt0eQJJA%2FSgHe79yTxUrzzoGrtlhK0O3HussVeRjKcvLkE6w%2FpQBnropwT%2FmE23RT2bOoyw%2BVCMlWTtk%2Bvxh%2FIOFAmrWHYzDuNkDNRo3um26RD2TFpeyRasbZoFRAV7RA9k4P3REAH4vemxktbNq24rtuF6MFGEcXpcGOD%2FxZJlBmInM7rguFAhRQWvCy3nIpO7knN2rl2DZv%2FcfkuoP4bedzUMcxtrU2Wz%2B82EG9ULHJunGHT%2F%2BcWj%2Bv8n%2Fh9bUtAtk7Fr1HBQdkQ8SbYadhRDWWuSEC2iMfqpMyzNqLltdxhyXxMRpsruPb2p4WoHnSvuGfbnkXIKcDppOTLB38xStPIbbaaR4FC%2B4AOF1UqbtMor9JJQQNz3vspSngY%2F37uYiQXAKNYB2RAB%2BbfoYMSS2VcJvY%2B0lWH3%2BYFTmBs6%2BxixGTJmB4%2FXZZcNs4PgRs6OoIefEnLz%2FvwoAvrs%2FUPotqevoiHfq%2FlLILAzo28D%2FKSU9hOOHXrS4LrUYhK47WKSeoglnagaOZI5kGZa9iBcwj9V6FR4HEml51P9u5xaTOnPZjfEAx5l6BBxTT4379irAZCB2Zfcd6wBU2Eo5p9yXVSH%2FCH8yVAgIEsrJ9oeqpO%2FwozsQ2PkXw%2Bz77B56hYp1zYG7HK%2BCDjx1NSisa6g8PFa72xOb8wpjZ9Lao70oGSWshIjCH4kWfKX0P8uFJc22L%2FZihKj0J%2BqgC1LgiMc6SXmFHdvTSIxTRKm9GImpbVfLTN3xrT%2BGGutwMTfgWta7EDR7d6HXQBA1orNotnnK37GOw1jHud8fzQkfuMN%2F7DO6kW0wAXs4LDMhJpnHi2%2Ba4VjL8Yjh0wmTZkVy4iIPYDmYSAzuJ3aP3cXuGv%2B1JwF%2Fod7hCA6RBYwZN2fXvO5AUo7FdoRr8ssPB7eAiNhcFonMv5%2Bt8L1b7QLoXGlplvxh9Fz669q43xnDsEy8ucOfyush8RiYLPxGj4YFr2gy6%2BAV5u%2FMgZIShq149jRn42%2B%2BnmzPC8JdiiIe4p5Ec7KFFrv%2F302DcKBPI9lQDsC1xWAvIfJcnxC%2FqYgDikLE1SsurxV2PV1icS%2BpU706S2LmnpyAsZw%3D%3D', apurl: 'http://ad.wx.com:12638/cgi-bin/exposure?viewid=AQM1xOr6MFeZmWeZrowCvQcrvQUBUq4o8ER2yFgwF9grPdtUR9bIJQ8laqMAJjGlkGLuVbyABIPX6Eifa2%2FK%2Buq17IIT21tYcUnpeU4VqEEsEQhc5Pa7C7drAvl0Mz30CNepODMXeD%2BEdny8SmmxN7prV78e1L2S6oqhNjrnTqM1t40ZGU84httoAODXEjmE89IX0ncOiP1oTsgm1tYwahSkxN6HLZIb6bhxZrc5ba3mCKMZ5GV4UEyDuQCyySxtA5QTt0eQJJA%2FSgHe79yTxUrzzoGrtlhK0O3HussVeRjKcvLkE6w%2FpQBnropwT%2FmE23RT2bOoyw%2BVCMlWTtk%2Bvxh%2FIOFAmrWHYzDuNkDNRo3um26RD2TFpeyRasbZoFRAV7RA9k4P3REAH4vemxktbNq24rtuF6MFGEcXpcGOD%2FxZJlBmInM7rguFAhRQWvCy3nIpO7knN2rl2DZv%2FcfkuoP4bedzUMcxtrU2Wz%2B82EG9ULHJunGHT%2F%2BcWj%2Bv8n%2Fh9bUtAtk7Fr1HBQdkQ8SbYadhRDWWuSEC2iMfqpMyzNqLltdxhyXxMRpsruPb2p4WoHnSvuGfbnkXIKcDppOTLB38xStPIbbaaR4FC%2B4AOF1UqbtMor9JJQQNz3vspSngY%2F37uYiQXAKNYB2RAB%2BbfoYMSS2VcJvY%2B0lWH3%2BYFTmBs6%2BxixGTJmB4%2FXZZcNs4PgRs6OoIefEnLz%2FvwoAvrs%2FUPotqevoiHfq%2FlLILAzo28D%2FKSU9hOOHXrS4LrUYhK47WKSeoglnagaOZI5kGZa9iBcwj9V6FR4HEml51P9u5xaTOnPZjfEAx5l6BBxTT4379irAZCB2Zfcd6wBU2Eo5p9yXVSH%2FCH8yVAgIEsrJ9oeqpO%2FwozsQ2PkXw%2Bz77B56hYp1zYG7HK%2BCDjx1NSisa6g8PFa72xOb8wpjZ9Lao70oGSWshIjCH4kWfKX0P8uFJc22L%2FZihKj0J%2BqgC1LgiMc6SXmFHdvTSIxTRKm9GImpbVfLTN3xrT%2BGGutwMTfgWta7EDR7d6HXQBA1orNotnnK37GOw1jHud8fzQkfuMN%2F7DO6kW0wAXs4LDMhJpnHi2%2Ba4VjL8Yjh0wmTZkVy4iIPYDmYSAzuJ3aP3cXuGv%2B1JwF%2Fod7hCA6RBYwZN2fXvO5AUo7FdoRr8ssPB7eAiNhcFonMv5%2Bt8L1b7QLoXGlplvxh9Fz669q43xnDsEy8ucOfyush8RiYLPxGj4YFr2gy6%2BAV5u%2FMgZIShq149jRn42%2B%2BnmzPC8JdiiIe4p5Ec7KFFrv%2F302DcKBPI9lQDsC1xWAvIfJcnxC%2FqYgDikLE1SsurxV2PV1icS%2BpU706S2LmnpyAsZw%3D%3D', traceid: 'wx0clsqxat6lzly601', group_id: 'wx0clsqxat6lzly600_wx0clsqxat6lzly601', ticket: '', pt: 2, image_url: 'http://wxsnsdythumb.wxs.qq.com/141/20204/snscosdownload/SH/reserved/5f4604790009bfd700000000b3679d090000008d00004eec?m=1c9e9086c11018ef774e28ee3b744a67&ck=1c9e9086c11018ef774e28ee3b744a67', ad_desc: '', biz_appid: 'wx69618ae091cf2c76', biz_info: { user_name: 'gh_1e80bb81a1d2', nick_name: '微信广告', head_img: 'https://wxa.wxs.qq.com/res/images/bizsdk/preview/wxlogo.png', biz_uin: 3094043316, signature: '微信广告' }, pos_type: 4, watermark_type: 0, logo: '', is_cpm: 0, dest_type: 1, material_width: 960, material_height: 540, ad_width: 0, ad_height: 0, use_new_protocol: 2, product_type: 29, material_type: 0, crt_exp_tid: 0, crt_exp_info: '', flow_exp_info: '[{"exp_para":[{"name":94574,"value":"gb"},{"name":100036,"value":"1"}]}]', watermark_text: '活动推广', crt_size: '484', button_action: "{"button_text":"".concat(transformText, "","jump_type":1,"jump_url":"https:\\/\\/ad.weixin.qq.com\\/guide\\/196?weixinadkey=bd80a7a5a0e57a3b971b1c372bb06a3748f8f01c44f1bfe1a0aa4fe927e21037fc57ddfe77f5e0648611197259574f4b&gdt_vid=wx0clsqxat6lzly601&weixinadinfo=315019981.wx0clsqxat6lzly601.75.1","text_type":0}"), position_index: 21, shop_image: [], material_id_list: [], uxinfo: '315019981|wx0clsqxat6lzly601|289237697|0|1598496949|0|0|9020229299926746||AgI0AyUHOnPeccmEYhaAko8Pr4P95P7Vl6qjqKrxaR/CSGQ3e+STumguP/V43UuYT8o=|315020504', ext_info: '{}', ad_token: 'bf8463b9a4b692768c820c412bb705a73e8a9dd2c769f22549e4bb5aeaaeccc1358b60b6ce7546f95cfdf7f73d187572', crt_info: "[{"width":960,"height":540,"thumb_url":"http://wxsnsdythumb.wxs.qq.com/141/20204/snscosdownload/SH/reserved/5f4604790009bfd700000000b3679d090000008d00004eec?m=1c9e9086c11018ef774e28ee3b744a67&ck=1c9e9086c11018ef774e28ee3b744a67","image_url":"http://wxsnsdythumb.wxs.qq.com/141/20204/snscosdownload/SH/reserved/5f4604790009bfd700000000b3679d090000008d00004eec?m=1c9e9086c11018ef774e28ee3b744a67&ck=1c9e9086c11018ef774e28ee3b744a67","size":18323,"image_md5":"1c9e9086c11018ef774e28ee3b744a67","materialId":"112199640","card_info":{"mp_tag_type":2,"mp_brandeffect_isopen":0,"mp_tags":["".concat(extraText, ""]}}]"), reranking_ext_info: '{"tid":315020504}', ext_back_comm: '{"pctr":0.019999999553}' }; var CPS_GOODS_TYPE = { OLD_GOODS: 'mp', NEW_GOODS: 'cps-to-reader', IMAGE_GOODS: 'cps-to-image-reader', SHORT_PLAY: 'short-play', MINI_GAME: 'mini-game' }; var AD_CONFIG = { defaultMidAdData: defaultMidAdData, AD_TYPE: AD_TYPE, AD_POS: AD_POS, AD_CACHE_TIME: AD_CACHE_TIME, AD_DEST_TYPE: AD_DEST_TYPE, AD_FRAME_DOMAIN: 'https://wxa.wxs.qq.com', CPS_AD_FRAME_DOMAIN: 'https://file.daihuo.qq.com', INVALID_METHOD_NAME_MSG_PREFIX: 'Invalid methodName', INVALID_METHOD_TYPE_MSG_PREFIX: 'Invalid methodType', INVALID_ARGS_MSG_PREFIX: 'Invalid args', INVALID_REQ_PATH_MSG_PREFIX: 'Invalid request path', AD_IFRAME_HIDE_CLASS: 'iframe_ad_dn', AD_JSAPI_WHITE_LIST: AD_JSAPI_WHITE_LIST, AD_REQ_PATH_WHITE_LIST: AD_REQ_PATH_WHITE_LIST, AD_WEB_COMPT_REQ_PATH_WHITE_LIST: AD_WEB_COMPT_REQ_PATH_WHITE_LIST, FRAME_ERROR: 'onError', FRAME_READY: 'onFrameReadyV2', CHANGE_FRAME_STYLE: 'changeFrameStyle', PROXY_CONSOLE: 'consoleOnHostEnv', PROXY_ACTION: 'onProxyV2', PROXY_CALLBACK_ACTION: 'proxyCallbackV2', CLICK_OUTSIDE_ACTION: 'clickOutsideV2', CLICK_AD_ACTION: 'onAdClick', PAGE_SCROLL_ACTION: 'pageScrollV2', ORIGIN_VIDEO_VID_PREFIX: 'wxv', AD_VIDEO_FIN_ACTION: 'adVideoEnd', AD_VIDEO_PLAY_ACTION: 'onVideoPlayV2', AD_VIDEO_END_ACTION: 'onVideoEndV2', AD_PLAY_VIDEO_ACTION: 'playVideoV2', AD_EXPOSE_IMAGE_ACTION: 'exposeImage', AD_HIDE_IMAGE_ACTION: 'hideImage', AD_CHANGE_VIDEO_STATE: 'changeVideoPlayState', AD_VIDEO_SET_SCREEN_STATE_ACTION: 'setScreenState', AD_IMAGE_SET_EXPAND_STATE_ACTION: 'setImageExpandState', GET_APPMSGAD_READY_STATUS_ACTION: 'getAppmsgadReadyStatus', APPMSGAD_READY_ACTION: 'appmsgadReady', HAS_AD_DATA_QUERY_KEY: 'has_ad_data', GET_AD_DATA_AFTER_VIDEO_ACTION_NAME: 'getAdDataAfterVideo', SET_PAGE_DATA_ACTION_NAME: 'setPageDataV2', SET_AD_DATA_ACTION_NAME: 'setAdDataV2', SEND_AD_VID_ACTION: 'sendAdVid', GET_AD_VID_ACTION: 'getAdVid', CPS_GOODS_TYPE: CPS_GOODS_TYPE }; var g = { defaultContentTpl: '<span class="js_img_placeholder wx_widget_placeholder" style="width:#width# !important;height:#height#px !important;text-indent: 0"><span class="weui-primary-loading"><span class="weui-primary-loading__dot"></span></span>', config: [{ querySelector: 'redpacketcover', genId: function genId() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return decodeURIComponent(opt.node.getAttribute('data-coveruri') || ''); }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return opt.parentWidth * 0.7854; }, calH: function calH() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return this.calW({ parentWidth: opt.parentWidth }) / 0.73346 + 27 + 37; }, replaceContentCssText: '', outerContainerLeft: '', outerContainerRight: '' }, { querySelector: 'mppoi', genId: function genId() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return opt.node.getAttribute('data-id') || ''; }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return opt.parentWidth * 1; }, calH: function calH() { return 219; }, replaceContentCssText: '', appendContentCssText: 'diplay:block;', outerContainerLeft: '', outerContainerRight: '' }, { querySelector: 'mpsearch', genId: function genId() { return decodeURIComponent('mp-common-search'); }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return opt.parentWidth * 1; }, calH: function calH() { return 100; }, replaceContentCssText: '', appendContentCssText: 'diplay:block;', outerContainerLeft: '', outerContainerRight: '' }, { querySelector: 'mpvideosnap', genId: function genId() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var type = opt.node.getAttribute('data-type') || 'video'; if (type === 'live') { return decodeURIComponent(opt.node.getAttribute('data-noticeid') || ''); } return decodeURIComponent(opt.node.getAttribute('data-id') || ''); }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var type = opt.node.getAttribute('data-type') || 'video'; var width = opt.node.getAttribute('data-width') || ''; var height = opt.node.getAttribute('data-height') || ''; if (type === 'live' || type === 'topic') { return opt.parentWidth; } var ratio = 1; ratio = width / height; var computedHeight = 0; var computedWidth = 0; var isHorizontal = false; if (ratio === 1 || ratio === 3 / 4) ; else if (ratio === 4 / 3 || ratio === 16 / 9) { isHorizontal = true; } else if (ratio < 3 / 4) { ratio = 3 / 4; } else if (ratio > 1 && ratio < 4 / 3) { ratio = 1; } else if (ratio > 4 / 3) { isHorizontal = true; } else if (typeof ratio === 'number' && !Object.is(ratio, NaN)) ; else { ratio = 1; } opt.node.setAttribute('data-ratio', ratio); opt.node.setAttribute('data-isHorizontal', isHorizontal); if (isHorizontal === true) { computedWidth = opt.parentWidth; } else { if (window.innerWidth < 1024) { computedWidth = window.innerWidth * 0.65; } else { computedWidth = opt.parentWidth * 0.65; } } computedHeight = computedWidth / ratio; computedHeight = Math.round(computedHeight); computedWidth = Math.round(computedWidth); opt.node.setAttribute('data-computedWidth', computedWidth); opt.node.setAttribute('data-computedHeight', computedHeight); return computedWidth; }, calH: function calH() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var desc = opt.node.getAttribute('data-desc') || ''; var type = opt.node.getAttribute('data-type') || 'video'; var computedHeight = opt.node.getAttribute('data-computedHeight') || ''; switch (type) { case 'live': return desc ? 152 : 116; case 'topic': return 201; case 'image': case 'video': return parseFloat(computedHeight); } }, getBorderRadius: function getBorderRadius() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var type = opt.node.getAttribute('data-type') || 'video'; if (type === 'video') { return 4; } return 8; }, replaceContentCssText: '', appendContentCssText: 'display:flex;margin:0px auto;', outerContainerLeft: '', outerContainerRight: '' }, { querySelector: 'mp-wxaproduct', genId: function genId() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return decodeURIComponent(opt.node.getAttribute('data-wxaproduct-productid') || ''); }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return opt.parentWidth * 1 || '100%'; }, calH: function calH() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var cardtype = opt.node.getAttribute('data-wxaproduct-cardtype') || ''; return cardtype === 'mini' ? 124 : 466; }, replaceContentCssText: '', outerContainerLeft: '', outerContainerRight: '' }, { querySelector: 'mpprofile', genId: function genId(opt) { return opt.node.getAttribute('data-id') || ''; }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return opt.parentWidth * 1; }, calH: function calH() { return 143; }, replaceContentCssText: '', appendContentCssText: 'diplay:block;', outerContainerLeft: '', outerContainerRight: '' }, { querySelector: 'mp-common-product:not([data-cardtype="2"])', genId: function genId(opt) { return opt.node.getAttribute('data-windowproduct') || ''; }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; if (opt.node.getAttribute('data-cardtype') === "0") { return Math.min(opt.parentWidth, 400) * 1 || '100%'; } return opt.parentWidth * 1 || '100%'; }, calH: function calH(opt) { var customstyle = opt.node.getAttribute('data-customstyle') || '{}'; if (customstyle) { try { var _JSON$parse = JSON.parse(customstyle), display = _JSON$parse.display, height = _JSON$parse.height; if (display !== 'none') { var customHeight = parseInt(height, 10); var ratio; if (opt.node.getAttribute('data-cardtype') === "0") { ratio = Math.min(400, opt.parentWidth) / 350.0 || 1; } else { ratio = opt.parentWidth / 350.0 || 1; } customHeight = Math.round(customHeight * ratio); return customHeight; } return 0; } catch (err) { console.error(err); } } return 0; }, replaceContentCssText: '', appendContentCssText: 'diplay:block;', outerContainerLeft: '<div style="display: flex; margin: 0 auto 24px;justify-content: center;">', outerContainerRight: '</div>' }, { querySelector: 'mpcps:not([data-templateid="video-play"]),mp-common-cpsad:not([data-templateid="video-play"])', genId: function genId(opt) { var node = opt.node; var planId = node.getAttribute('data-planid'); var goodId = node.getAttribute('data-pid'); var traceId = node.getAttribute('data-traceid'); return goodId || planId || traceId || ''; }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var node = opt.node; var templateId = node.getAttribute('data-templateid'); var adType = node.getAttribute('data-adtype'); var width = 0; if (templateId === 'list') { width = '100%'; } else if (templateId === 'card') { if (adType === AD_CONFIG.CPS_GOODS_TYPE.SHORT_PLAY || adType === AD_CONFIG.CPS_GOODS_TYPE.MINI_GAME) { width = opt.parentWidth ? opt.parentWidth * 0.65 : '100%'; } else { width = '100%'; } } return width; }, calH: function calH(opt) { var node = opt.node; var templateId = node.getAttribute('data-templateid'); var adType = node.getAttribute('data-adtype'); var height = 0; if (templateId === 'list') { if (adType === AD_CONFIG.CPS_GOODS_TYPE.MINI_GAME) { height = 79; } else { height = 120; } } else if (templateId === 'card') { if (adType === AD_CONFIG.CPS_GOODS_TYPE.SHORT_PLAY) { var width = opt.parentWidth * 0.65; height = Math.ceil(width * (4 / 3)) + 68; } else if (adType === AD_CONFIG.CPS_GOODS_TYPE.MINI_GAME) { var _width = opt.parentWidth * 0.65; height = Math.ceil(_width * (4 / 3)) + 64; } else { height = Math.ceil(opt.parentWidth + 111); } } return height; }, replaceContentCssText: '', appendContentCssText: 'diplay:block;', outerContainerLeft: '<div style="display: flex; justify-content: center">', outerContainerRight: '</div>' } ] }; function preloadingInit() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; if (typeof document.querySelectorAll !== 'function') { return; } var g = { maxWith: document.getElementById('img-content').getBoundingClientRect().width, idAttr: 'data-preloadingid' }; for (var i = 0, il = opt.config.length; i < il; i++) { var a = opt.config[i]; var list = document.querySelectorAll(a.querySelector); for (var j = 0, jl = list.length; j < jl; j++) { var node = list[j]; var parentWidth = node.parentNode.getBoundingClientRect().width; parentWidth = Math.min(parentWidth, g.maxWith); if (node.getAttribute('has-insert-preloading')) { continue; } var nodeW = a.calW({ parentWidth: parentWidth, node: node }); var nodeH = a.calH({ parentWidth: parentWidth, node: node }); var nodeId = a.genId({ index: j, node: node }); var nodeBorderRadius = typeof a.getBorderRadius === 'function' ? a.getBorderRadius({ index: j, node: node }) : 8; if (typeof nodeW === 'number') { nodeW += 'px'; } var imgHtml = opt.defaultContentTpl.replace(/#height#/g, nodeH).replace(/#width#/g, nodeW).replace(/#borderRadius#/g, nodeBorderRadius); var tmpNode = document.createElement('div'); tmpNode.innerHTML = imgHtml; if (a.replaceContentCssText) { var replaceContentCssText = a.replaceContentCssText.replace(/#height#/g, nodeH).replace(/#width#/g, nodeW); tmpNode.firstChild.style.cssText = replaceContentCssText; } else if (a.appendContentCssText) { tmpNode.firstChild.style.cssText += a.appendContentCssText; } var html = (a.outerContainerLeft || '') + tmpNode.innerHTML + (a.outerContainerRight || ''); tmpNode.innerHTML = html; tmpNode.firstChild.setAttribute(g.idAttr, nodeId); node.parentNode.insertBefore(tmpNode.firstChild, node.nextSibling); node.setAttribute('has-insert-preloading', '1'); } } } function init() { preloadingInit(g); } function decode(str) { var replace = ["`", "`", "'", "'", """, '"', " ", " ", ">", ">", "<", "<", "¥", "¥", "&", "&"]; for (var i = 0; i < replace.length; i += 2) { str = str.replace(new RegExp(replace[i], 'g'), replace[i + 1]); } return str; } function getQuery(url) { url = url || 'http://qq.com/s?a=b#rd'; var tmp = url.split('?'), query = (tmp[1] || '').split('#')[0].split('&'), params = {}; for (var i = 0; i < query.length; i++) { var eqIndex = query[i].indexOf('='); if (eqIndex > -1) { var arg = query[i].substring(0, eqIndex); params[arg] = query[i].substring(eqIndex + 1); } } if (params['pass_ticket']) { params['pass_ticket'] = encodeURIComponent(decode(params['pass_ticket']).replace(/\s/g, '+')); } return params; } function insertAfter(dom, afterDom) { var _p = afterDom.parentNode; if (!_p) { return; } if (_p.lastChild === afterDom) { _p.appendChild(dom); } else { _p.insertBefore(dom, afterDom.nextSibling); } } if (typeof getComputedStyle === 'undefined') { if (document.body.currentStyle) { window.getComputedStyle = function (el) { return el.currentStyle; }; } else { window.getComputedStyle = {}; } } function getMaxWith() { var container = document.getElementById('img-content'); var max_width = container.offsetWidth; var container_padding = 0; var container_style = getComputedStyle(container); container_padding = parseFloat(container_style.paddingLeft) + parseFloat(container_style.paddingRight); max_width -= container_padding; if (!max_width) { max_width = window.innerWidth - 32; } return max_width; } function getParentWidth(dom) { var parent_width = 0; var parent = dom.parentNode; var outerWidth = 0; while (true) { if (!parent || parent.nodeType !== 1) break; var parent_style = getComputedStyle(parent); if (!parent_style) break; parent_width = parent.clientWidth - parseFloat(parent_style.paddingLeft) - parseFloat(parent_style.paddingRight) - outerWidth; if (parent_width > 16) break; outerWidth += parseFloat(parent_style.paddingLeft) + parseFloat(parent_style.paddingRight) + parseFloat(parent_style.marginLeft) + parseFloat(parent_style.marginRight) + parseFloat(parent_style.borderLeftWidth) + parseFloat(parent_style.borderRightWidth); parent = parent.parentNode; } if (parent_width < 0) { return 0; } return parent_width; } function getOuterW(dom) { var style = getComputedStyle(dom); var w = 0; if (!!style) { w = parseFloat(style.paddingLeft) + parseFloat(style.paddingRight) + parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth); } return w; } function getOuterH(dom) { var style = getComputedStyle(dom); var h = 0; if (!!style) { h = parseFloat(style.paddingTop) + parseFloat(style.paddingBottom) + parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth); } return h; } function getVideoWh(dom, vid, data) { var max_width = getMaxWith(); var width = max_width; var ratio_ = dom.getAttribute('data-ratio') * 1 || 4 / 3; if (data.video_page_infos && Array.isArray(data.video_page_infos) && data.video_page_infos.some(function (x) { return x.video_id === vid; })) { var videoData = data.video_page_infos.find(function (x) { return x.video_id === vid; }); if (Array.isArray(videoData.mp_video_trans_info) && videoData.mp_video_trans_info.length) { var transInfo = videoData.mp_video_trans_info[0]; if (!!transInfo.width && !!transInfo.height) { ratio_ = transInfo.width / transInfo.height; } } } var arr = [4 / 3, 16 / 9]; var ret = arr[0]; var abs = Math.abs(ret - ratio_); for (var j = 1, jl = arr.length; j < jl; j++) { var _abs = Math.abs(arr[j] - ratio_); if (_abs < abs) { abs = _abs; ret = arr[j]; } } ratio_ = ret; var parent_width = getParentWidth(dom) || max_width; var rwidth = width > parent_width ? parent_width : width; var outerW = getOuterW(dom) || 0; var outerH = getOuterH(dom) || 0; var videoW = rwidth - outerW; var videoH = videoW / ratio_; var speedDotH = 12; var rheight = videoH + outerH + speedDotH; return { w: Math.ceil(rwidth), h: Math.ceil(rheight), vh: videoH, vw: videoW, ratio: ratio_, sdh: speedDotH }; } function setImgSize(item, widthNum, widthUnit, ratio, breakParentWidth) { var imgPaddingBorder = getOuterW(item) || 0; var imgPaddingBorderTopBottom = getOuterH(item) || 0; if (widthNum > getParentWidth(item) && !breakParentWidth) { widthNum = getParentWidth(item); } var heightNum = (widthNum - imgPaddingBorder) * ratio + imgPaddingBorderTopBottom; widthNum !== 'auto' && (item.style.cssText += ";width: ".concat(widthNum).concat(widthUnit, " !important;")); widthNum !== 'auto' && (item.style.cssText += ";height: ".concat(heightNum).concat(widthUnit, " !important;")); } var isAccessibilityKey = 'isMpUserAccessibility'; var imgPlaceholderClass = 'js_img_placeholder'; var isAccessMode = window.localStorage.getItem(isAccessibilityKey); var imgSizeData; var validArr = ',' + [0.875, 1, 1.125, 1.25, 1.375].join(',') + ','; var match = window.location.href.match(/winzoom=(\d+(?:\.\d+)?)/); if (match && match[1]) { var winzoom = parseFloat(match[1]); if (validArr.indexOf(',' + winzoom + ',') >= 0) ; } function getImgSrcMainInfo(src) { var pathName = new URL(src).pathname; var lastIndex = pathName.lastIndexOf('/'); return lastIndex > 0 ? pathName.slice(0, lastIndex) : pathName; } function setSize(images, videos, data) { var bypassPreloading = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; var noWidth = !document.body.clientWidth || !document.getElementById('img-content') || !document.getElementById('img-content').offsetWidth; var _loop = function _loop() { if (noWidth) { return 0; } if (window.__second_open__ && videos[vi].getAttribute('__sec_open_place_holder__')) { return 1; } var a = videos[vi]; var src_ = a.getAttribute('src') || a.getAttribute('src') || ''; var vid = getQuery(src_).vid || a.getAttribute('data-mpvid'); if (!vid) { return 1; } vid = vid.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); a.removeAttribute('src'); a.style.display = 'none'; var obj = getVideoWh(a, vid, data); var videoPlaceHolderSpan = document.createElement('span'); videoPlaceHolderSpan.className = "".concat(imgPlaceholderClass, " wx_widget_placeholder"); videoPlaceHolderSpan.setAttribute('data-vid', vid); videoPlaceHolderSpan.innerHTML = '<span class="weui-primary-loading"><span class="weui-primary-loading__dot"></span></span>'; videoPlaceHolderSpan.style.cssText = "width: " + obj.w + "px !important;"; insertAfter(videoPlaceHolderSpan, a); a.style.cssText += ';width: ' + obj.w + 'px !important;'; a.setAttribute('width', obj.w); { videoPlaceHolderSpan.style.cssText += 'height: ' + (obj.h - obj.sdh) + 'px !important;margin-bottom: ' + obj.sdh + 'px !important;'; a.style.cssText += 'height: ' + obj.h + 'px !important;'; a.setAttribute('height', obj.h); } a.setAttribute('data-vh', obj.vh); a.setAttribute('data-vw', obj.vw); a.setAttribute('src', 'https://v.qq.com/iframe/player.html?vid=' + vid + '&width=' + obj.vw + '&height=' + obj.vh + '&auto=0'); a.setAttribute('__sec_open_place_holder__', true); var index = vi; (function setHitStyle() { var hitInfos = data.video_page_infos; var ret = (hitInfos || []).find(function (info) { return info.video_id === vid; }); if (!ret) return; var ori = ret.ori_status; var hit_biz_headimg = ret.hit_biz_headimg, hit_nickname = ret.hit_nickname, hit_username = ret.hit_username; var sourceBiz = ret.hit_bizuin; var selfUserName = data.user_name; if (ori === 2 && selfUserName !== hit_username) { var videoBar = document.createElement('div'); var videoBarHtml = "\n <div class=\"wx-edui-video_source_link js_wx_tap_highlight wx_tap_card\" id=\"".concat(hit_username).concat(index, "\" data-hit-username=\"").concat(hit_username, "\" data-hit-biz=\"").concat(sourceBiz, "\">\n <div class=\"wx-edui-video_source_word\">_(\"\u4EE5\u4E0B\u89C6\u9891\u6765\u6E90\u4E8E\")</div>\n <div class=\"wx-edui-video_account_info\">\n <div class=\"wx-edui-video_account_avatar\" id=\"").concat(hit_biz_headimg).concat(index, "\" src=\"").concat(hit_biz_headimg, "\"></div>\n <div class=\"wx-edui-video_account_name\">").concat(hit_nickname, "</div>\n <i class=\"wx-edui-video_account_arrow\"></i>\n </div>\n <div class=\"wx-edui-video_source_link__layer_mask\"></div>\n </div>"); videoBar.innerHTML = videoBarHtml; document.querySelectorAll('.video_iframe').forEach(function (item) { if (item.getAttribute('data-mpvid') === vid && item.getAttribute('data-hasSource') !== '1') { item.setAttribute('data-hasSource', 1); item.parentNode.insertBefore(videoBar, item); } }); var avatorEle = document.getElementById(hit_biz_headimg + index); var avatorSrc = avatorEle.dataset.src; if (ret.hit_biz_headimg) avatorEle.style.backgroundImage = "url(".concat(avatorSrc, ")"); } })(); }, _ret; for (var vi = 0, viLen = videos.length; vi < viLen; vi++) { _ret = _loop(); if (_ret === 0) break; if (_ret === 1) continue; } var isCarton = data.copyright_info.is_cartoon_copyright * 1 || data.user_info.is_care_mode * 1 || isAccessMode === '1'; var max_width = getMaxWith(); if (!imgSizeData) { imgSizeData = {}; data.picture_page_info_list = data.picture_page_info_list || []; var noWidthHeightCount = 0; var hasWidthHeightCount = 0; data.picture_page_info_list.forEach(function (imgData) { try { var width = Number(imgData.width); var height = Number(imgData.height); if (width && height) { imgSizeData[getImgSrcMainInfo(imgData.cdn_url)] = { ratio: height / width, width: width }; hasWidthHeightCount++; } else { noWidthHeightCount++; } } catch (err) { console.error(err); } }); if (Math.random() < 0.01 && Number(data.create_timestamp) > 1682352000) { hasWidthHeightCount && (new Image().src = "//mp.weixin.qq.com/mp/jsmonitor?idkey=330742_20_".concat(hasWidthHeightCount, "&r=").concat(Math.random())); noWidthHeightCount && (new Image().src = "//mp.weixin.qq.com/mp/jsmonitor?idkey=330742_21_".concat(noWidthHeightCount, "&r=").concat(Math.random())); if (!data.picture_page_info_list.length) { setTimeout(function () { noWidthHeightCount = document.querySelectorAll('#js_content img').length; noWidthHeightCount && (new Image().src = "//mp.weixin.qq.com/mp/jsmonitor?idkey=330742_21_".concat(noWidthHeightCount, "&r=").concat(Math.random())); }, 300); } } } for (var im = 0, imLen = images.length; im < imLen; im++) { if (window.__second_open__ && images[im].getAttribute('__sec_open_place_holder__')) { continue; } var img = images[im]; var imgDataSrc = img.getAttribute('src'); var realSrc = img.getAttribute('src'); if (!imgDataSrc || realSrc) continue; var imgStyle = img.getAttribute('style'); img.setAttribute('data-original-style', imgStyle); var width_ = img.dataset.w; var imgRatio = 1 * img.dataset.ratio; img.setAttribute('data-index', im); var width_num = 0; var width_unit = 'px'; try { var imgSizeFromBackend = imgSizeData[getImgSrcMainInfo(imgDataSrc)]; if (imgSizeFromBackend) { if (imgSizeFromBackend.ratio) { imgRatio = imgSizeFromBackend.ratio; img.setAttribute('data-ratio', imgSizeFromBackend.ratio); } if (imgSizeFromBackend.width) { width_ = imgSizeFromBackend.width; img.setAttribute('data-w', imgSizeFromBackend.width); } } } catch (err) { console.error(err); } if (imgRatio && imgRatio > 0) { if (!isCarton) { img.src = "data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg width='1px' height='1px' viewBox='0 0 1 1' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Ctitle%3E%3C/title%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' fill-opacity='0'%3E%3Cg transform='translate(-249.000000, -126.000000)' fill='%23FFFFFF'%3E%3Crect x='249' y='126' width='1' height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E"; if (noWidth) { var fallbackWidth = img.style.width || img.getAttribute('width') || width_; var fallbackMaxWidth = 360; fallbackWidth = parseFloat(fallbackWidth, 10) > fallbackMaxWidth ? fallbackMaxWidth : fallbackWidth; if (fallbackWidth === 'inherit') { fallbackWidth = fallbackMaxWidth; } if (fallbackWidth) { img.setAttribute('_width', !isNaN(fallbackWidth * 1) ? fallbackWidth + 'px' : fallbackWidth); } if (typeof fallbackWidth === 'string' && fallbackWidth.indexOf('%') !== -1) { fallbackWidth = parseFloat(fallbackWidth.replace('%', ''), 10) / 100 * fallbackMaxWidth; } if (fallbackWidth === 'auto') { fallbackWidth = width_; if (width_ === 'auto' || !width_) { fallbackWidth = fallbackMaxWidth; } else { fallbackWidth = width_; } } var fallbackRes = /^(\d+(?:\.\d+)?)([a-zA-Z%]+)?$/.exec(fallbackWidth); var fallbackLastWidth = fallbackRes && fallbackRes.length >= 2 ? fallbackRes[1] : 0; var fallbackUnit = fallbackRes && fallbackRes.length >= 3 && fallbackRes[2] ? fallbackRes[2] : 'px'; setImgSize(img, fallbackLastWidth, fallbackUnit, imgRatio, true); img.classList.add(imgPlaceholderClass, "wx_img_placeholder"); continue; } img.classList.add(imgPlaceholderClass, "wx_img_placeholder"); } var parent_width = getParentWidth(img) || max_width; var init_width = img.style.width || img.getAttribute('width') || width_ || parent_width; init_width = parseFloat(init_width, 10) > max_width ? max_width : init_width; if (init_width === 'inherit') { init_width = parent_width; } if (init_width) { img.setAttribute('_width', !isNaN(init_width * 1) ? init_width + 'px' : init_width); } if (typeof init_width === 'string' && init_width.indexOf('%') !== -1) { setImgSize(img, width_, 'px', imgRatio, true); parent_width = getParentWidth(img) || max_width; init_width = parseFloat(init_width.replace('%', ''), 10) / 100 * parent_width; } if (init_width === 'auto') { init_width = width_; if (width_ === 'auto' || !width_) { init_width = parent_width; } else { init_width = width_; } } var res = /^(\d+(?:\.\d+)?)([a-zA-Z%]+)?$/.exec(init_width); width_num = res && res.length >= 2 ? res[1] : 0; width_unit = res && res.length >= 3 && res[2] ? res[2] : 'px'; var imgWidth = width_num; if (isCarton) { img.src = imgDataSrc; img.style.height = 'auto'; } else { setImgSize(img, imgWidth, width_unit, imgRatio, true); setImgSize(img, imgWidth, width_unit, imgRatio, false); } } if (!data.is_h5_render) { img.setAttribute('__sec_open_place_holder__', true); } } if (!bypassPreloading) init(); } var ua = navigator.userAgent; /mac\sos/i.test(ua) && !/(iPhone|iPad|iPod|iOS)/i.test(ua) || /windows\snt/i.test(ua); var images = document.getElementsByTagName('img'); var videos = []; var user_name = "gh_6258c101a32a"; var isCartoonCopyright = '0'; var is_care_mode = ''; var createTimestamp = '1743643844'; var picturePageInfoList = "[]"; picturePageInfoList = picturePageInfoList.includes(',]') ? picturePageInfoList.replace(',]', ']') : picturePageInfoList; try { picturePageInfoList = JSON.parse(picturePageInfoList.replace(/'/g, '"')); } catch (err) { picturePageInfoList = []; console.error(err); } var data = { is_h5_render: true, user_name: user_name, copyright_info: { is_cartoon_copyright: isCartoonCopyright }, picture_page_info_list: picturePageInfoList, create_timestamp: createTimestamp, user_info: { is_care_mode: is_care_mode } }; setSize(images, videos, data); })();</script><script type="text/javascript" nonce="1989770072" reportloaderror>(function () { 'use strict'; var AD_TYPE = { ANDROID_APP_PRODUCT_TYPE: 12, IOS_APP_PRODUCT_TYPE: 19, ADD_CONTACT_PRODUCT_TYPE: 23, MINI_GAME_PRODUCT_TYPE: 46, CARD_PRODUCT_TYPE: 36, SHOP_PRODUCT_TYPE: 30, WECHATCARD_PRODUCT_TYPE: 47, BRAND_WECHAT_PRODUCT_TYPE: 29, BRAND_GDT_PRODUCT_TYPE: 31 }; var AD_POS = { POS_BOTTOM: 0, POS_BOTTOM_PC: 38, POS_MID: 4, POS_MID_PC: 39, POS_SPONSOR: 3, POS_AD_BEFORE_VIDEO: 7, POS_AD_AFTER_VIDEO: 9, POS_AD_MID_VIDEO: 16, POS_AD_KEYWORD: 36 }; var AD_DEST_TYPE = { AD_DEST_TYPE: 0, OUTER_DEST_TYPE: 1, APPDETAIL_DEST_TYPE: 2, BIZ_DEST_TYPE: 3, APPINFO_PAGE_DEST_TYPE: 4, WECHAT_SHOP_DEST_TYPE: 5, WECHAT_APPLET_DEST_TYPE: 6, LEAF_DEST_TYPE: 7, CANVAS_AD_DEST_TYPE: 9 }; var AD_CACHE_TIME = 0.5 * 60 * 1000; var AD_JSAPI_WHITE_LIST = ['openUrlWithExtraWebview', 'openADCanvas', 'addContact', 'profile', 'getInstallState', 'installDownloadTask', 'addDownloadTask', 'pauseDownloadTask', 'resumeDownloadTask', 'queryDownloadTask', 'launchApplication', 'writeCommData', 'adDataReport', 'downloadAppInternal', 'wxdownload:progress_change', 'menu:share:appmessage', 'menu:share:timeline', 'menu:share:weibo', 'menu:share:facebook', 'menu:general:share', 'launch3rdApp', 'addDownloadTaskStraight', 'sendAppMessage', 'shareTimeline', 'getNetworkType', 'openBizChat', 'jumpToBizProfile', 'shareWeibo', 'shareFB', 'imagePreview', 'getBackgroundAudioState', 'openWeApp', 'openEmbeddedWeApp', 'preloadMiniProgramContacts', 'preloadMiniProgramEnv', 'calRqt', 'openCardDetail', 'batchAddCard', 'handleMPPageAction', 'makePhoneCall', 'getOAID', 'saveWaid', 'batchPreloadMiniProgram', 'onScreenShot', 'handleAdAction', 'activity:state_change', 'getAdIdInfo', 'onWebPageUrlExposed', 'openFinderView', 'predownloadMiniProgramPackage', 'openCustomerServiceChat', 'showOpenIMContactProfile', 'openWXSearchPage']; var AD_REQ_PATH_WHITE_LIST = [ '/mp/advertisement_report', '/mp/ad_report', '/mp/ad_video_report', '/mp/jsmonitor', '/mp/ad_complaint', '/mp/jsreport', '/tp/datacenter/report', '/mp/getappmsgad', '/mp/ad_biz_info', '/mp/appmsg_video_snap', '/mp/cps_product_info', '/mp/mini_drama_info']; var AD_WEB_COMPT_REQ_PATH_WHITE_LIST = [/(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/advertisement_report/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/ad_report/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/ad_video_report/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/jsmonitor/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/ad_complaint/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/jsreport/, /(https?:)?\/\/mp\.weixin\.qq\.com\/tp\/datacenter\/report/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/getappmsgad/, /(https?:)?\/\/mp\.weixin\.qq\.com\/mp\/ad_biz_info/, /(https?:)?\/\/mp\.weixin\.qq\.com\/tp\/goods_info/, /(https?:)?\/\/mp\.weixin\.qq\.com\/tp\/app_mobile/, /(https?:)?\/\/mp\.weixin\.qq\.com\/tp\/datareport\/report/, /(https?:)?\/\/mp\.weixin\.qq\.com\/promotion\/wxalandpage\/getcanvasinfo/]; var transformText = '转化按钮'; var extraText = '广告文案或辅助信息'; var defaultMidAdData = { hint_txt: '创意-20200827_1', url: 'https://ad.weixin.qq.com/guide/196?weixinadkey=59d5cf0b4fbf7d2f66cd90aaa82a5208057512dd06fcb64d7fd57e71ec15945e1744ac499e05a04999381c3bf30c21ca&gdt_vid=wx0clsqxat6lzly601&weixinadinfo=315019981.wx0clsqxat6lzly601.75.1', type: '0', rl: 'http://ad.wx.com:12638/cgi-bin/click?viewid=AQM1xOr6MFeZmWeZrowCvQcrvQUBUq4o8ER2yFgwF9grPdtUR9bIJQ8laqMAJjGlkGLuVbyABIPX6Eifa2%2FK%2Buq17IIT21tYcUnpeU4VqEEsEQhc5Pa7C7drAvl0Mz30CNepODMXeD%2BEdny8SmmxN7prV78e1L2S6oqhNjrnTqM1t40ZGU84httoAODXEjmE89IX0ncOiP1oTsgm1tYwahSkxN6HLZIb6bhxZrc5ba3mCKMZ5GV4UEyDuQCyySxtA5QTt0eQJJA%2FSgHe79yTxUrzzoGrtlhK0O3HussVeRjKcvLkE6w%2FpQBnropwT%2FmE23RT2bOoyw%2BVCMlWTtk%2Bvxh%2FIOFAmrWHYzDuNkDNRo3um26RD2TFpeyRasbZoFRAV7RA9k4P3REAH4vemxktbNq24rtuF6MFGEcXpcGOD%2FxZJlBmInM7rguFAhRQWvCy3nIpO7knN2rl2DZv%2FcfkuoP4bedzUMcxtrU2Wz%2B82EG9ULHJunGHT%2F%2BcWj%2Bv8n%2Fh9bUtAtk7Fr1HBQdkQ8SbYadhRDWWuSEC2iMfqpMyzNqLltdxhyXxMRpsruPb2p4WoHnSvuGfbnkXIKcDppOTLB38xStPIbbaaR4FC%2B4AOF1UqbtMor9JJQQNz3vspSngY%2F37uYiQXAKNYB2RAB%2BbfoYMSS2VcJvY%2B0lWH3%2BYFTmBs6%2BxixGTJmB4%2FXZZcNs4PgRs6OoIefEnLz%2FvwoAvrs%2FUPotqevoiHfq%2FlLILAzo28D%2FKSU9hOOHXrS4LrUYhK47WKSeoglnagaOZI5kGZa9iBcwj9V6FR4HEml51P9u5xaTOnPZjfEAx5l6BBxTT4379irAZCB2Zfcd6wBU2Eo5p9yXVSH%2FCH8yVAgIEsrJ9oeqpO%2FwozsQ2PkXw%2Bz77B56hYp1zYG7HK%2BCDjx1NSisa6g8PFa72xOb8wpjZ9Lao70oGSWshIjCH4kWfKX0P8uFJc22L%2FZihKj0J%2BqgC1LgiMc6SXmFHdvTSIxTRKm9GImpbVfLTN3xrT%2BGGutwMTfgWta7EDR7d6HXQBA1orNotnnK37GOw1jHud8fzQkfuMN%2F7DO6kW0wAXs4LDMhJpnHi2%2Ba4VjL8Yjh0wmTZkVy4iIPYDmYSAzuJ3aP3cXuGv%2B1JwF%2Fod7hCA6RBYwZN2fXvO5AUo7FdoRr8ssPB7eAiNhcFonMv5%2Bt8L1b7QLoXGlplvxh9Fz669q43xnDsEy8ucOfyush8RiYLPxGj4YFr2gy6%2BAV5u%2FMgZIShq149jRn42%2B%2BnmzPC8JdiiIe4p5Ec7KFFrv%2F302DcKBPI9lQDsC1xWAvIfJcnxC%2FqYgDikLE1SsurxV2PV1icS%2BpU706S2LmnpyAsZw%3D%3D', apurl: 'http://ad.wx.com:12638/cgi-bin/exposure?viewid=AQM1xOr6MFeZmWeZrowCvQcrvQUBUq4o8ER2yFgwF9grPdtUR9bIJQ8laqMAJjGlkGLuVbyABIPX6Eifa2%2FK%2Buq17IIT21tYcUnpeU4VqEEsEQhc5Pa7C7drAvl0Mz30CNepODMXeD%2BEdny8SmmxN7prV78e1L2S6oqhNjrnTqM1t40ZGU84httoAODXEjmE89IX0ncOiP1oTsgm1tYwahSkxN6HLZIb6bhxZrc5ba3mCKMZ5GV4UEyDuQCyySxtA5QTt0eQJJA%2FSgHe79yTxUrzzoGrtlhK0O3HussVeRjKcvLkE6w%2FpQBnropwT%2FmE23RT2bOoyw%2BVCMlWTtk%2Bvxh%2FIOFAmrWHYzDuNkDNRo3um26RD2TFpeyRasbZoFRAV7RA9k4P3REAH4vemxktbNq24rtuF6MFGEcXpcGOD%2FxZJlBmInM7rguFAhRQWvCy3nIpO7knN2rl2DZv%2FcfkuoP4bedzUMcxtrU2Wz%2B82EG9ULHJunGHT%2F%2BcWj%2Bv8n%2Fh9bUtAtk7Fr1HBQdkQ8SbYadhRDWWuSEC2iMfqpMyzNqLltdxhyXxMRpsruPb2p4WoHnSvuGfbnkXIKcDppOTLB38xStPIbbaaR4FC%2B4AOF1UqbtMor9JJQQNz3vspSngY%2F37uYiQXAKNYB2RAB%2BbfoYMSS2VcJvY%2B0lWH3%2BYFTmBs6%2BxixGTJmB4%2FXZZcNs4PgRs6OoIefEnLz%2FvwoAvrs%2FUPotqevoiHfq%2FlLILAzo28D%2FKSU9hOOHXrS4LrUYhK47WKSeoglnagaOZI5kGZa9iBcwj9V6FR4HEml51P9u5xaTOnPZjfEAx5l6BBxTT4379irAZCB2Zfcd6wBU2Eo5p9yXVSH%2FCH8yVAgIEsrJ9oeqpO%2FwozsQ2PkXw%2Bz77B56hYp1zYG7HK%2BCDjx1NSisa6g8PFa72xOb8wpjZ9Lao70oGSWshIjCH4kWfKX0P8uFJc22L%2FZihKj0J%2BqgC1LgiMc6SXmFHdvTSIxTRKm9GImpbVfLTN3xrT%2BGGutwMTfgWta7EDR7d6HXQBA1orNotnnK37GOw1jHud8fzQkfuMN%2F7DO6kW0wAXs4LDMhJpnHi2%2Ba4VjL8Yjh0wmTZkVy4iIPYDmYSAzuJ3aP3cXuGv%2B1JwF%2Fod7hCA6RBYwZN2fXvO5AUo7FdoRr8ssPB7eAiNhcFonMv5%2Bt8L1b7QLoXGlplvxh9Fz669q43xnDsEy8ucOfyush8RiYLPxGj4YFr2gy6%2BAV5u%2FMgZIShq149jRn42%2B%2BnmzPC8JdiiIe4p5Ec7KFFrv%2F302DcKBPI9lQDsC1xWAvIfJcnxC%2FqYgDikLE1SsurxV2PV1icS%2BpU706S2LmnpyAsZw%3D%3D', traceid: 'wx0clsqxat6lzly601', group_id: 'wx0clsqxat6lzly600_wx0clsqxat6lzly601', ticket: '', pt: 2, image_url: 'http://wxsnsdythumb.wxs.qq.com/141/20204/snscosdownload/SH/reserved/5f4604790009bfd700000000b3679d090000008d00004eec?m=1c9e9086c11018ef774e28ee3b744a67&ck=1c9e9086c11018ef774e28ee3b744a67', ad_desc: '', biz_appid: 'wx69618ae091cf2c76', biz_info: { user_name: 'gh_1e80bb81a1d2', nick_name: '微信广告', head_img: 'https://wxa.wxs.qq.com/res/images/bizsdk/preview/wxlogo.png', biz_uin: 3094043316, signature: '微信广告' }, pos_type: 4, watermark_type: 0, logo: '', is_cpm: 0, dest_type: 1, material_width: 960, material_height: 540, ad_width: 0, ad_height: 0, use_new_protocol: 2, product_type: 29, material_type: 0, crt_exp_tid: 0, crt_exp_info: '', flow_exp_info: '[{"exp_para":[{"name":94574,"value":"gb"},{"name":100036,"value":"1"}]}]', watermark_text: '活动推广', crt_size: '484', button_action: "{"button_text":"".concat(transformText, "","jump_type":1,"jump_url":"https:\\/\\/ad.weixin.qq.com\\/guide\\/196?weixinadkey=bd80a7a5a0e57a3b971b1c372bb06a3748f8f01c44f1bfe1a0aa4fe927e21037fc57ddfe77f5e0648611197259574f4b&gdt_vid=wx0clsqxat6lzly601&weixinadinfo=315019981.wx0clsqxat6lzly601.75.1","text_type":0}"), position_index: 21, shop_image: [], material_id_list: [], uxinfo: '315019981|wx0clsqxat6lzly601|289237697|0|1598496949|0|0|9020229299926746||AgI0AyUHOnPeccmEYhaAko8Pr4P95P7Vl6qjqKrxaR/CSGQ3e+STumguP/V43UuYT8o=|315020504', ext_info: '{}', ad_token: 'bf8463b9a4b692768c820c412bb705a73e8a9dd2c769f22549e4bb5aeaaeccc1358b60b6ce7546f95cfdf7f73d187572', crt_info: "[{"width":960,"height":540,"thumb_url":"http://wxsnsdythumb.wxs.qq.com/141/20204/snscosdownload/SH/reserved/5f4604790009bfd700000000b3679d090000008d00004eec?m=1c9e9086c11018ef774e28ee3b744a67&ck=1c9e9086c11018ef774e28ee3b744a67","image_url":"http://wxsnsdythumb.wxs.qq.com/141/20204/snscosdownload/SH/reserved/5f4604790009bfd700000000b3679d090000008d00004eec?m=1c9e9086c11018ef774e28ee3b744a67&ck=1c9e9086c11018ef774e28ee3b744a67","size":18323,"image_md5":"1c9e9086c11018ef774e28ee3b744a67","materialId":"112199640","card_info":{"mp_tag_type":2,"mp_brandeffect_isopen":0,"mp_tags":["".concat(extraText, ""]}}]"), reranking_ext_info: '{"tid":315020504}', ext_back_comm: '{"pctr":0.019999999553}' }; var CPS_GOODS_TYPE = { OLD_GOODS: 'mp', NEW_GOODS: 'cps-to-reader', IMAGE_GOODS: 'cps-to-image-reader', SHORT_PLAY: 'short-play', MINI_GAME: 'mini-game' }; var AD_CONFIG = { defaultMidAdData: defaultMidAdData, AD_TYPE: AD_TYPE, AD_POS: AD_POS, AD_CACHE_TIME: AD_CACHE_TIME, AD_DEST_TYPE: AD_DEST_TYPE, AD_FRAME_DOMAIN: 'https://wxa.wxs.qq.com', CPS_AD_FRAME_DOMAIN: 'https://file.daihuo.qq.com', INVALID_METHOD_NAME_MSG_PREFIX: 'Invalid methodName', INVALID_METHOD_TYPE_MSG_PREFIX: 'Invalid methodType', INVALID_ARGS_MSG_PREFIX: 'Invalid args', INVALID_REQ_PATH_MSG_PREFIX: 'Invalid request path', AD_IFRAME_HIDE_CLASS: 'iframe_ad_dn', AD_JSAPI_WHITE_LIST: AD_JSAPI_WHITE_LIST, AD_REQ_PATH_WHITE_LIST: AD_REQ_PATH_WHITE_LIST, AD_WEB_COMPT_REQ_PATH_WHITE_LIST: AD_WEB_COMPT_REQ_PATH_WHITE_LIST, FRAME_ERROR: 'onError', FRAME_READY: 'onFrameReadyV2', CHANGE_FRAME_STYLE: 'changeFrameStyle', PROXY_CONSOLE: 'consoleOnHostEnv', PROXY_ACTION: 'onProxyV2', PROXY_CALLBACK_ACTION: 'proxyCallbackV2', CLICK_OUTSIDE_ACTION: 'clickOutsideV2', CLICK_AD_ACTION: 'onAdClick', PAGE_SCROLL_ACTION: 'pageScrollV2', ORIGIN_VIDEO_VID_PREFIX: 'wxv', AD_VIDEO_FIN_ACTION: 'adVideoEnd', AD_VIDEO_PLAY_ACTION: 'onVideoPlayV2', AD_VIDEO_END_ACTION: 'onVideoEndV2', AD_PLAY_VIDEO_ACTION: 'playVideoV2', AD_EXPOSE_IMAGE_ACTION: 'exposeImage', AD_HIDE_IMAGE_ACTION: 'hideImage', AD_CHANGE_VIDEO_STATE: 'changeVideoPlayState', AD_VIDEO_SET_SCREEN_STATE_ACTION: 'setScreenState', AD_IMAGE_SET_EXPAND_STATE_ACTION: 'setImageExpandState', GET_APPMSGAD_READY_STATUS_ACTION: 'getAppmsgadReadyStatus', APPMSGAD_READY_ACTION: 'appmsgadReady', HAS_AD_DATA_QUERY_KEY: 'has_ad_data', GET_AD_DATA_AFTER_VIDEO_ACTION_NAME: 'getAdDataAfterVideo', SET_PAGE_DATA_ACTION_NAME: 'setPageDataV2', SET_AD_DATA_ACTION_NAME: 'setAdDataV2', SEND_AD_VID_ACTION: 'sendAdVid', GET_AD_VID_ACTION: 'getAdVid', CPS_GOODS_TYPE: CPS_GOODS_TYPE }; var g = { defaultContentTpl: '<span class="js_img_placeholder wx_widget_placeholder" style="width:#width# !important;height:#height#px !important;text-indent: 0"><span class="weui-primary-loading"><span class="weui-primary-loading__dot"></span></span>', config: [{ querySelector: 'redpacketcover', genId: function genId() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return decodeURIComponent(opt.node.getAttribute('data-coveruri') || ''); }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return opt.parentWidth * 0.7854; }, calH: function calH() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return this.calW({ parentWidth: opt.parentWidth }) / 0.73346 + 27 + 37; }, replaceContentCssText: '', outerContainerLeft: '', outerContainerRight: '' }, { querySelector: 'mppoi', genId: function genId() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return opt.node.getAttribute('data-id') || ''; }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return opt.parentWidth * 1; }, calH: function calH() { return 219; }, replaceContentCssText: '', appendContentCssText: 'diplay:block;', outerContainerLeft: '', outerContainerRight: '' }, { querySelector: 'mpsearch', genId: function genId() { return decodeURIComponent('mp-common-search'); }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return opt.parentWidth * 1; }, calH: function calH() { return 100; }, replaceContentCssText: '', appendContentCssText: 'diplay:block;', outerContainerLeft: '', outerContainerRight: '' }, { querySelector: 'mpvideosnap', genId: function genId() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var type = opt.node.getAttribute('data-type') || 'video'; if (type === 'live') { return decodeURIComponent(opt.node.getAttribute('data-noticeid') || ''); } return decodeURIComponent(opt.node.getAttribute('data-id') || ''); }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var type = opt.node.getAttribute('data-type') || 'video'; var width = opt.node.getAttribute('data-width') || ''; var height = opt.node.getAttribute('data-height') || ''; if (type === 'live' || type === 'topic') { return opt.parentWidth; } var ratio = 1; ratio = width / height; var computedHeight = 0; var computedWidth = 0; var isHorizontal = false; if (ratio === 1 || ratio === 3 / 4) ; else if (ratio === 4 / 3 || ratio === 16 / 9) { isHorizontal = true; } else if (ratio < 3 / 4) { ratio = 3 / 4; } else if (ratio > 1 && ratio < 4 / 3) { ratio = 1; } else if (ratio > 4 / 3) { isHorizontal = true; } else if (typeof ratio === 'number' && !Object.is(ratio, NaN)) ; else { ratio = 1; } opt.node.setAttribute('data-ratio', ratio); opt.node.setAttribute('data-isHorizontal', isHorizontal); if (isHorizontal === true) { computedWidth = opt.parentWidth; } else { if (window.innerWidth < 1024) { computedWidth = window.innerWidth * 0.65; } else { computedWidth = opt.parentWidth * 0.65; } } computedHeight = computedWidth / ratio; computedHeight = Math.round(computedHeight); computedWidth = Math.round(computedWidth); opt.node.setAttribute('data-computedWidth', computedWidth); opt.node.setAttribute('data-computedHeight', computedHeight); return computedWidth; }, calH: function calH() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var desc = opt.node.getAttribute('data-desc') || ''; var type = opt.node.getAttribute('data-type') || 'video'; var computedHeight = opt.node.getAttribute('data-computedHeight') || ''; switch (type) { case 'live': return desc ? 152 : 116; case 'topic': return 201; case 'image': case 'video': return parseFloat(computedHeight); } }, getBorderRadius: function getBorderRadius() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var type = opt.node.getAttribute('data-type') || 'video'; if (type === 'video') { return 4; } return 8; }, replaceContentCssText: '', appendContentCssText: 'display:flex;margin:0px auto;', outerContainerLeft: '', outerContainerRight: '' }, { querySelector: 'mp-wxaproduct', genId: function genId() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return decodeURIComponent(opt.node.getAttribute('data-wxaproduct-productid') || ''); }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return opt.parentWidth * 1 || '100%'; }, calH: function calH() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var cardtype = opt.node.getAttribute('data-wxaproduct-cardtype') || ''; return cardtype === 'mini' ? 124 : 466; }, replaceContentCssText: '', outerContainerLeft: '', outerContainerRight: '' }, { querySelector: 'mpprofile', genId: function genId(opt) { return opt.node.getAttribute('data-id') || ''; }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return opt.parentWidth * 1; }, calH: function calH() { return 143; }, replaceContentCssText: '', appendContentCssText: 'diplay:block;', outerContainerLeft: '', outerContainerRight: '' }, { querySelector: 'mp-common-product:not([data-cardtype="2"])', genId: function genId(opt) { return opt.node.getAttribute('data-windowproduct') || ''; }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; if (opt.node.getAttribute('data-cardtype') === "0") { return Math.min(opt.parentWidth, 400) * 1 || '100%'; } return opt.parentWidth * 1 || '100%'; }, calH: function calH(opt) { var customstyle = opt.node.getAttribute('data-customstyle') || '{}'; if (customstyle) { try { var _JSON$parse = JSON.parse(customstyle), display = _JSON$parse.display, height = _JSON$parse.height; if (display !== 'none') { var customHeight = parseInt(height, 10); var ratio; if (opt.node.getAttribute('data-cardtype') === "0") { ratio = Math.min(400, opt.parentWidth) / 350.0 || 1; } else { ratio = opt.parentWidth / 350.0 || 1; } customHeight = Math.round(customHeight * ratio); return customHeight; } return 0; } catch (err) { console.error(err); } } return 0; }, replaceContentCssText: '', appendContentCssText: 'diplay:block;', outerContainerLeft: '<div style="display: flex; margin: 0 auto 24px;justify-content: center;">', outerContainerRight: '</div>' }, { querySelector: 'mpcps:not([data-templateid="video-play"]),mp-common-cpsad:not([data-templateid="video-play"])', genId: function genId(opt) { var node = opt.node; var planId = node.getAttribute('data-planid'); var goodId = node.getAttribute('data-pid'); var traceId = node.getAttribute('data-traceid'); return goodId || planId || traceId || ''; }, calW: function calW() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var node = opt.node; var templateId = node.getAttribute('data-templateid'); var adType = node.getAttribute('data-adtype'); var width = 0; if (templateId === 'list') { width = '100%'; } else if (templateId === 'card') { if (adType === AD_CONFIG.CPS_GOODS_TYPE.SHORT_PLAY || adType === AD_CONFIG.CPS_GOODS_TYPE.MINI_GAME) { width = opt.parentWidth ? opt.parentWidth * 0.65 : '100%'; } else { width = '100%'; } } return width; }, calH: function calH(opt) { var node = opt.node; var templateId = node.getAttribute('data-templateid'); var adType = node.getAttribute('data-adtype'); var height = 0; if (templateId === 'list') { if (adType === AD_CONFIG.CPS_GOODS_TYPE.MINI_GAME) { height = 79; } else { height = 120; } } else if (templateId === 'card') { if (adType === AD_CONFIG.CPS_GOODS_TYPE.SHORT_PLAY) { var width = opt.parentWidth * 0.65; height = Math.ceil(width * (4 / 3)) + 68; } else if (adType === AD_CONFIG.CPS_GOODS_TYPE.MINI_GAME) { var _width = opt.parentWidth * 0.65; height = Math.ceil(_width * (4 / 3)) + 64; } else { height = Math.ceil(opt.parentWidth + 111); } } return height; }, replaceContentCssText: '', appendContentCssText: 'diplay:block;', outerContainerLeft: '<div style="display: flex; justify-content: center">', outerContainerRight: '</div>' } ] }; function preloadingInit() { var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; if (typeof document.querySelectorAll !== 'function') { return; } var g = { maxWith: document.getElementById('img-content').getBoundingClientRect().width, idAttr: 'data-preloadingid' }; for (var i = 0, il = opt.config.length; i < il; i++) { var a = opt.config[i]; var list = document.querySelectorAll(a.querySelector); for (var j = 0, jl = list.length; j < jl; j++) { var node = list[j]; var parentWidth = node.parentNode.getBoundingClientRect().width; parentWidth = Math.min(parentWidth, g.maxWith); if (node.getAttribute('has-insert-preloading')) { continue; } var nodeW = a.calW({ parentWidth: parentWidth, node: node }); var nodeH = a.calH({ parentWidth: parentWidth, node: node }); var nodeId = a.genId({ index: j, node: node }); var nodeBorderRadius = typeof a.getBorderRadius === 'function' ? a.getBorderRadius({ index: j, node: node }) : 8; if (typeof nodeW === 'number') { nodeW += 'px'; } var imgHtml = opt.defaultContentTpl.replace(/#height#/g, nodeH).replace(/#width#/g, nodeW).replace(/#borderRadius#/g, nodeBorderRadius); var tmpNode = document.createElement('div'); tmpNode.innerHTML = imgHtml; if (a.replaceContentCssText) { var replaceContentCssText = a.replaceContentCssText.replace(/#height#/g, nodeH).replace(/#width#/g, nodeW); tmpNode.firstChild.style.cssText = replaceContentCssText; } else if (a.appendContentCssText) { tmpNode.firstChild.style.cssText += a.appendContentCssText; } var html = (a.outerContainerLeft || '') + tmpNode.innerHTML + (a.outerContainerRight || ''); tmpNode.innerHTML = html; tmpNode.firstChild.setAttribute(g.idAttr, nodeId); node.parentNode.insertBefore(tmpNode.firstChild, node.nextSibling); node.setAttribute('has-insert-preloading', '1'); } } } function init() { preloadingInit(g); } init(); })();</script> <script type="text/javascript" nonce="1989770072" reportloaderror> function htmlDecode(str) { return str .replace(/'/g, '\'') .replace(/<br\s*(\/)?\s*>/g, '\n') .replace(/ /g, ' ') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/&/g, '&') .replace(/ /g, ' '); } var uin = ''; var key = ''; var pass_ticket = ''; var new_appmsg = 1; var item_show_type = "0"; var real_item_show_type = "0"; var can_see_complaint = "0"; var tid = ""; var aid = ""; var clientversion = ""; var appuin = "" || "MzU0OTk3ODQ3Ng=="; var voiceid = ""; var create_time = "1743643844" * 1; var source = ""; var ascene = ""; var subscene = ""; var sessionid = "" || "svr_5fc3db74245"; var abtest_cookie = ""; var finder_biz_enter_id = "" * 1; var scene = 75; var itemidx = "" || ""; var appmsg_token = "" || ""; var _copyright_stat = "1"; var _ori_article_type = ""; var is_follow = ""; var nickname = htmlDecode("石杉的架构笔记"); var appmsg_type = "9"; var ct = "1743643844"; var user_name = "gh_6258c101a32a"; var fakeid = ""; var version = ""; var is_limit_user = "0"; var cps_article_data = ""; var round_head_img = "/upload/ac7ecb6e296202cc8a75f7993256decd.png"; var profile_signature = "一线大厂架构经验倾囊相授!"; var profile_signature_new = ""; var hd_head_img = "http://wx.qlogo.cn/mmhead/Q3auHgzwzM579hWFYlRZds9C3OXdbjfQeIxM7Svic6kP7YskDIVGQkg/0" || ""; var ori_head_img_url = "http://wx.qlogo.cn/mmhead/Q3auHgzwzM579hWFYlRZds9C3OXdbjfQeIxM7Svic6kP7YskDIVGQkg/132"; var msg_title = '震惊!用 Redis+AI 模型实现秒级实时风控,这波操作太秀了'.html(false); var msg_desc = htmlDecode(""); var msg_cdn_url = "https://mmbiz.qpic.cn/mmbiz_jpg/1J6IbIcPCLbPOV9sLvC7KdgGic4DpvbVe2Y95aaDWGYhjKA1Dxr7RUT58uEuk1MLGZAJWcwy3g6BZhAwzmBTt4g/0?wx_fmt=jpeg"; var cdn_url_1_1 = "https://mmbiz.qpic.cn/mmbiz_jpg/1J6IbIcPCLbPOV9sLvC7KdgGic4DpvbVexibehpBJel3H1FujV9j9Z1QRCApJb5cV9d0iaZdsX17ib7mtuWMMm9rSQ/0?wx_fmt=jpeg"; var cdn_url_235_1 = "https://mmbiz.qpic.cn/mmbiz_jpg/1J6IbIcPCLbPOV9sLvC7KdgGic4DpvbVe2Y95aaDWGYhjKA1Dxr7RUT58uEuk1MLGZAJWcwy3g6BZhAwzmBTt4g/0?wx_fmt=jpeg"; var msg_link = "https://mp.weixin.qq.com/s/3hbpQRAofG905lAt7Onq5g"; var user_uin = "" * 1; var msg_source_url = ''; var img_format = 'jpeg'; var srcid = ''; var req_id = '0309HjJfojOvcZCbK8cTrrZO'; var networkType; var appmsgid = "2247616950" || '' || ''; var comment_id = '3925979078456426516' || '0'; var mp_comment_id = "" || "" * 1; var comment_enabled = "" * 1; var open_fansmsg = "0" * 1; var is_https_res = ("" * 1) && (location.protocol == "https:"); var msg_daily_idx = "1" || ""; var profileReportInfo = "" || ""; var devicetype = ""; var source_encode_biz = ""; var source_username = ""; var reprint_ticket = ""; var source_mid = ""; var source_idx = ""; var source_biz = ""; var author = "儒猿团队"; var author_id = ""; var author_cancel = "" * 1 || 0; var reward_wording = ""; var extra_comment_id = '3925979090586353664' || '0'; var reward_author_head = ""; var reward_can_whisper = "" * 1 || 0; var reward_total_count = "" * 1 || 0; var optimizing_flag = "" * 1; var show_comment = ""; var __appmsgCgiData = { wxa_product: "" * 1, wxa_cps: "" * 1, show_msg_voice: "0" * 1, can_use_page: "" * 1, is_wxg_stuff_uin: "0" * 1, card_pos: "", copyright_stat: "1", source_biz: "", hd_head_img: "http://wx.qlogo.cn/mmhead/Q3auHgzwzM579hWFYlRZds9C3OXdbjfQeIxM7Svic6kP7YskDIVGQkg/0" || (window.location.protocol + "//" + window.location.host + "//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/pic/pic_rumor_link750ed3.jpg"), has_red_packet_cover: "0" * 1 || 0, minishopCardData: "" }; var _empty_v = "//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/audios/empty750ed3.mp3"; var publicTagInfo = [ ]; var appmsg_album_info = (function () { var curAlbumId = ''; for (var i = 0; i < publicTagInfo.length; i++) { if (curAlbumId) { if (curAlbumId === publicTagInfo[i].id) { return publicTagInfo[i]; } } else { if (publicTagInfo[i].continousReadOn) { return publicTagInfo[i]; } } } return {}; })(); var copyright_stat = "1" * 1; var hideSource = "" * 1; var pay_fee = "" * 1; var pay_timestamp = ""; var need_pay = "" * 1; var is_pay_subscribe = "0" * 1; var need_report_cost = "0" * 1; var use_tx_video_player = "0" * 1; var appmsg_fe_filter = "contenteditable"; var friend_read_source = "" || ""; var friend_read_version = "" || ""; var friend_read_class_id = "" || ""; var is_only_read = "1" * 1; var read_num = "" * 1; var read_num_new = '' * 1; var show_read_new = '' * 1; var like_num = "" * 1; var liked = "" == 'true' ? true : false; var is_temp_url = "" ? 1 : 0; var tempkey = ""; var send_time = ""; var icon_emotion_switch = "//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/icon/emotion/icon_emotion_switch750ed3.svg"; var icon_emotion_switch_active = "//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/icon/emotion/icon_emotion_switch_active750ed3.svg"; var icon_emotion_switch_primary = "//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/icon/emotion/icon_emotion_switch_primary750ed3.svg"; var icon_emotion_switch_active_primary = "//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/icon/emotion/icon_emotion_switch_active_primary750ed3.svg"; var icon_loading_white = "//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/icon/common/icon_loading_white750ed3.gif"; var icon_audio_unread = "//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/icon/audio/icon_audio_unread750ed3.png"; var icon_qqmusic_default = "//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/icon/audio/icon_qqmusic_default750ed3.png"; var icon_qqmusic_source = "//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/icon/audio/icon_qqmusic_source750ed3.svg"; var icon_kugou_source = "//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/icon/audio/icon_kugou_source750ed3.png"; var topic_default_img = '//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/pic/pic_book_thumb750ed3.png'; var comment_edit_icon = '//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/icon/common/icon_edit750ed3.png'; var comment_loading_img = '//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/icon/common/icon_loading_white750ed3.gif'; var comment_c2c_not_support_img = '//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/pic/pic_discuss_more750ed3.png'; var line_info = { }; var can_feedback = '' * 1; var yqj_info = { }; var frontend_exp_list = [ ]; var tts_is_ban = '' * 1 || 0; var tts_is_show = '' * 1 || 0; var tts_heard_person_cnt = '' * 1 || 0; var can_use_star = '' * 1 || 0;; var star_person_cnt = '' * 1 || 0; var voice_in_appmsg = { }; var voiceList = {}; voiceList={"voice_in_appmsg":[]} var reprint_style = '' * 1; var reprint_type = '' * 1; var wxa_img_alert = "" != 'false'; var weapp_sn_arr_json = "" || ""; var videoPageInfos = [ ]; window.__videoPageInfos = videoPageInfos; if ([1, 2].indexOf('0' * 1) !== -1) { var pageInfoList = []; for(var i = 0; i<videoPageInfos.length; i++){ if (videoPageInfos[i].mp_video_overseas_limit) { videoPageInfos[i].mp_video_trans_info = []; } pageInfoList.push(videoPageInfos[i]); } window.__videoPageInfos = pageInfoList; } var video_snap_json = "" || ""; var mp_profile = [ ]; var ban_scene = "0" * 1; var ban_jump_link = { }; var svr_time = "1743644973" * 1; var is_transfer_msg = "" * 1 || 0; var malicious_title_reason_id = "0" * 1; var malicious_content_type = "0" * 1; var modify_time = "" * 1; var modify_detail = []; var isprofileblock = "0"; var jumpInfo = [ ]; window.service_type = '0' * 1; var hasRelatedArticleInfo = '0' * 1 || 0; var relatedArticleFlag = '' * 1 || 0; var canUseAutoTypeSetting; canUseAutoTypeSetting = '3' * 1 || 0; var styleType = '3'; var originTypeSetting = ''; var originStyleType = ''; var reprintEditable = ''; var currentSvrStyleType, originSvrStyleType; if (!isNaN(parseInt(styleType)) && parseInt(styleType) > 0) { currentSvrStyleType = parseInt(styleType); } else if (!isNaN(parseInt(canUseAutoTypeSetting))) { currentSvrStyleType = parseInt(canUseAutoTypeSetting); } else { currentSvrStyleType = 0; } if (!isNaN(parseInt(originStyleType)) && parseInt(originStyleType) > 0) { originSvrStyleType = parseInt(originStyleType); } else if (!isNaN(parseInt(originTypeSetting))) { originSvrStyleType = parseInt(originTypeSetting); } else { originSvrStyleType = 0; } if (reprint_type > 0 && originSvrStyleType !== currentSvrStyleType && parseInt(reprintEditable) === 0) { var dc = document.getElementById('js_content').classList; dc.remove('autoTypeSetting'); dc.remove('autoTypeSetting24'); dc.remove('autoTypeSetting24psection'); var finalSetting = parseInt(originSvrStyleType); if (finalSetting === 1) { dc.add('autoTypeSetting'); } else if (finalSetting === 2) { dc.add('autoTypeSetting24'); } else if (finalSetting === 3) { dc.add('autoTypeSetting24psection'); } } window.wxtoken = "777"; window.is_login = '' * 1; var title = "石杉的架构笔记"; var is_new_msg = true; var is_wash = '' * 1; var topbarEnable = false; var enterid = "1743644973" * 1 || "1743644973" * 1 || "" * 1 || parseInt(Date.now() / 1000); var reloadid = '' * 1 || parseInt(Date.now() / 1000); var reloadseq = '' * 1 || 1; var miniprogram_appid = ""; var defaultAvatarUrl = '//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/icon/common/icon_avatar_default750ed3.svg'; document.addEventListener('DOMContentLoaded', function () { window.domCompleteTime = Date.now(); }); var hasRecommendMsg = 0; ; var isPayTopic = '' * 1; var payTopicPrice = '' * 1; var isRemovedFromPayTopic = '' * 1; var isPaySubscribe = '0' * 1; var isPaid = '0' * 1; var isRefund = '' * 1; var payShowIAPPrice = 1; var payProductId = '' || ''; var previewPercent = '0' || ''; var payGiftsCount = '0' * 1 || 0; var payDesc = htmlDecode(''); var payFreeGift = '' * 1 || 0; var is_finished_preview = 0; var jump2pay = '' * 1; var isFans; var can_reward = '0' * 1 || 0; var is_need_reward = (isPaySubscribe && !isPaid) ? 0 : "0" * 1; var rewardsn = ''; var rewardTimestamp = '' * 1 || 0; var is_teenager = '' * 1 || 0; var is_care_mode = '' * 1 || 0; var zhuge_user_limit = '' * 1 || 0; var segment_comment_id = '3925979091156779012'; var colorScheme = ''; var iapPriceInfo = { }; var productPayPackage = { iap_price_info: iapPriceInfo }; var isCartoonCopyright = '0' * 1; var show_msg_voice = '' * 1; var qnaCardData = ''; var exptype = '' || ''; var expsessionid = '' || ''; var goContentId = ''; var goReplyId = ''; var fromCommentShare = ''; var goAddedInfo = '' * 1; var goAddedInfoContentId = ''; var preload_comment_list = ''; var show_related_article = '' * 1; var wwdistype = ''; var refuteSourceUrl = ''; window.cgiData = { appImg: '//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/pic/pic_tencent_video750ed3.png', } window.ip_wording = { countryName: '中国', countryId: '156', provinceName: '江苏', provinceId: '', cityName: '', cityId: '' }; window.show_ip_wording = '1' * 1; window.source_appid = 'wx0f18d4b9ebb547af'; window.is_over_sea = '0' * 1; window.showAdMark = "0" * 1; window.isTitleModified = "" * 1; window.claim_source = { claim_source_type: '', claim_source: '', }; window.hideAdMarkOnCps = ("" || "0" * 1) ? 1 : 0; window.bar_version = '' * 1; window.appmsg_bar_data = { }; window.subcount_version = '' * 1; window.show_comment_bar = '' * 1; window.search_keywords = [ ]; window.s1s_keywords_exp_info = ''; var need_baike_preload = true; ; window.ad_keywords = [ ]; window.show_ad_keyword = 'false'; window.clear_desc_flag = "" * 1; window.mmlisten_playlist_info_buffer = ''; window.key_text = ''; window.merge_playlist_info_base64 = 'CgQxMDQwEBAYAiIM5pKt5pS+5YiX6KGoSAI='; window.star_playlist_info_base64 = 'CgQxMDM3EBAYAiIM5pKt5pS+5YiX6KGoSAI='; window.category_playlist_info_base64 = 'CgQxMDM1EBAYAiIJ56iN5ZCO5ZCsSAI='; if (window.isPaySubscribe) { function onWeixinJsBridgeReady() { window.WeixinJSBridge.invoke('hideMenuItems', { menuList: ['control:showButtonScreenShot'] }, function (res) {}); } if (typeof WeixinJSBridge === 'undefined') { if (document.addEventListener) { document.addEventListener('WeixinJSBridgeReady', onWeixinJsBridgeReady, false); } else if (document.attachEvent) { document.attachEvent('WeixinJSBridgeReady', onWeixinJsBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onWeixinJsBridgeReady); } } else { onWeixinJsBridgeReady(); } } </script> <script type="text/javascript" nonce="1989770072" reportloaderror>var __INLINE_SCRIPT__ = (function () { 'use strict'; function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } var ua = navigator.userAgent; var is_ios = /(iPhone|iPad|iPod|iOS)/i.test(ua); var is_wp = /Windows\sPhone/i.test(ua); var is_android = /(Android)/i.test(ua); var is_wechat = /MicroMessenger\/([\d\.]+)/i.test(ua); var is_mac = /mac\sos/i.test(ua) && !is_ios; var is_windows = /windows\snt/i.test(ua) && !is_wp; var is_mpapp = /MPAPP\/([\d\.]+)/i.test(ua); var is_ipad = /iPad/i.test(ua); var is_windows_wechat = /WindowsWechat/i.test(ua); var is_mac_wechat = /MacWechat/i.test(ua) || /wechat.*mac os/i.test(ua); var is_prefetch = is_wechat && window.WeixinPrefecherJSBridge; var is_donut_app = /SAAASDK/i.test(ua); var is_harmony = /OpenHarmony|ArkWeb/i.test(ua); var is_in_miniProgram = is_android && /miniprogram/.test(ua.toLowerCase()) || window.__wxjs_environment == 'miniprogram'; var is_wx_work = /wxwork/i.test(ua); function getUrlParams() { var vars = location.search.substring(1).split('&'); var params = {}; var _iterator = _createForOfIteratorHelper(vars), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var ele = _step.value; var pair = ele.split('='); var key = decodeURIComponent(pair[0]); if (typeof params[key] === 'undefined') { params[key] = decodeURIComponent(pair[1]); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return params; } function get() { var reg = /MicroMessenger\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMac() { var reg = /MacWechat\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMacOS() { var reg = /Mac OS X ([\d_]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1].replace(/_/g, '.'); } return false; } function getWindows() { var reg = /WindowsWechat\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getWxWork() { var reg = /wxwork\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMpApp() { var appVersion = [2, 4, 5]; var match = navigator.userAgent.match(/MPAPP\/(\d+(\.\d+)*)/); if (match) { appVersion = match[1].split('.').map(function (v) { return Number(v); }); } return appVersion.join('.'); } function getUnifiedPcVer() { var versionInfo = navigator.userAgent.match(/UnifiedPC\w+Wechat\(0xf\w{2}(\w+?)\w{2}\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(0, 1)); var subVersion = getVersionNumber(version.slice(1, 2)); var subVersion2 = getVersionNumber(version.slice(2, 3)); return [mainVersion, subVersion, subVersion2].join('.'); } } function getVersionNumber(hexStr) { return Number(Number("0x".concat(hexStr)).toString(10)); } function getWindowsVersionFormat() { var versionInfo = navigator.userAgent.match(/WindowsWechat\(0x(\w+?)\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(1, 2)); var subVersion = getVersionNumber(version.slice(2, 4)); var subVersion2 = getVersionNumber(version.slice(4, 6)); return [mainVersion, subVersion, subVersion2].join('.'); } return false; } function getInner() { var reg = /MicroMessenger\/[\d\.]+\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1] && ret[1] != null) { return ret[1]; } if (!ret && /MicroMessenger\/[\d\.]+/i.test(ua)) { var urlParams = getUrlParams(); if (urlParams.version) { return urlParams.version; } } return false; } var opfunc = { 'cp-1': function cp1(a, b) { return a < b; }, cp0: function cp0(a, b) { return a === b; }, cp1: function cp1(a, b) { return a > b; } }; function cpVersion(ver, op, canEq, type) { var mmver = false; switch (type) { case 'mac': mmver = getMac(); break; case 'windows': mmver = getWindowsVersionFormat(); break; case 'wxwork': mmver = getWxWork(); break; case 'mpapp': mmver = getMpApp(); break; case 'unifiedpc': mmver = getUnifiedPcVer(); break; default: mmver = get(); break; } if (!mmver) { return; } var mmversion = mmver.split('.'); var version = ver.split('.'); if (!/\d+/g.test(mmversion[mmversion.length - 1])) { mmversion.pop(); } for (var i = 0, len = Math.max(mmversion.length, version.length); i < len; ++i) { var mmv = mmversion[i] || ''; var v = version[i] || ''; var mmvn = parseInt(mmv, 10) || 0; var vn = parseInt(v, 10) || 0; var eq = opfunc.cp0(mmvn, vn); if (eq) { continue; } var cp = opfunc["cp".concat(op)]; return cp(mmvn, vn); } return canEq || op === 0; } function eqVersion(version) { return cpVersion(version, 0); } function gtVersion(version, canEq) { return cpVersion(version, 1, canEq); } function ltVersion(version, canEq) { return cpVersion(version, -1, canEq); } function getPlatform() { if (is_ios) { return 'ios'; } if (is_android) { return 'android'; } if (is_mac) { return 'mac_os'; } if (is_windows) { return 'windows'; } return 'unknown'; } var is_google_play = false; var inner_ver_for_google_play_check = getInner(); if (is_android && inner_ver_for_google_play_check) { var v = "0x".concat(inner_ver_for_google_play_check.substr(-2)); if (parseInt(v) >= 64 && parseInt(v) <= 79) { is_google_play = true; } } ({ get: get, getMac: getMac, getMacOS: getMacOS, getWindows: getWindows, getInner: getInner, getWxWork: getWxWork, getMpApp: getMpApp, cpVersion: cpVersion, eqVersion: eqVersion, gtVersion: gtVersion, ltVersion: ltVersion, getPlatform: getPlatform, getVersionNumber: getVersionNumber, isWp: is_wp, isIOS: is_ios, isAndroid: is_android, isHarmony: is_harmony, isHarmonyWechat: is_harmony && is_wechat && cpVersion('1.0.0', 1, true), isInMiniProgram: is_in_miniProgram, isWechat: is_wechat, isMac: is_mac, isWindows: is_windows, isMacWechat: is_mac_wechat, isWindowsWechat: is_windows_wechat, isWxWork: is_wx_work, isOnlyWechat: is_wechat && !is_wx_work, isMpapp: is_mpapp, isNewMpApp: false, isIPad: is_ipad, isGooglePlay: is_google_play, isPrefetch: is_prefetch, isDonutAPP: is_donut_app }); if (!window.JSAPIEventCallbackMap) { window.JSAPIEventCallbackMap = {}; } var doc = {}; try { doc = top.window.document; } catch (e) { } if (!window.JSAPIEventCallbackMap) { window.JSAPIEventCallbackMap = {}; } var setImmersiveMode = function setImmersiveMode(itemShowType) { var envStr = window.__wxWebEnv && typeof window.__wxWebEnv.getEnv === 'function' && window.__wxWebEnv.getEnv(); if (!envStr) return; var envObj = {}; if (!envStr) return; try { envObj = JSON.parse(envStr); } catch (err) { console.info(err); } var immersiveListMode = envObj.immersiveListMode || 0; window.__immersiveListMode = Number(immersiveListMode) === 1 ? 1 : 0; window.__test_immersive_list = 0; if (window.__test_immersive_list) { window.__immersiveListMode = 1; } var wxExpandArticleEle = document.getElementById('wx_expand_article'); document.getElementById('js_article'); var bottomLoadingTip = document.getElementById('js_network_msg_wrp'); if (!itemShowType && itemShowType !== 0) { itemShowType = window.item_show_type; } itemShowType = Number(itemShowType); if (window.__immersiveListMode) { try { var immersiveSafeBottom = localStorage.getItem('__immersivefeed_safe_bottom__'); if (immersiveSafeBottom) { document.documentElement.style.setProperty('--immersive-safe-bottom', immersiveSafeBottom); } } catch (error) { console.log(error); } if (wxExpandArticleEle) { wxExpandArticleEle.style.display = 'block'; } if (bottomLoadingTip) { bottomLoadingTip.style.display = 'none'; } if (itemShowType === 10 || itemShowType === 7) { document.body.classList.add('ellapse_short_content'); } else { document.body.classList.add('ellapse_stream_article'); } if (itemShowType === 0) { document.body.classList.add('article_extensive_background'); } else { document.body.classList.add('media_content_extensive_background'); } var interactionPlaceholderEle = document.getElementById('js_interaction_placeholder'); if (interactionPlaceholderEle) { interactionPlaceholderEle.style.display = 'block'; } } }; if (!window.__second_open__) { setImmersiveMode(); } return setImmersiveMode; })();</script><script type="text/javascript" nonce="1989770072" reportloaderror>var __INLINE_SCRIPT__ = (function () { 'use strict'; function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } var ua = navigator.userAgent; var is_ios = /(iPhone|iPad|iPod|iOS)/i.test(ua); var is_wp = /Windows\sPhone/i.test(ua); var is_android = /(Android)/i.test(ua); var is_wechat = /MicroMessenger\/([\d\.]+)/i.test(ua); var is_mac = /mac\sos/i.test(ua) && !is_ios; var is_windows = /windows\snt/i.test(ua) && !is_wp; var is_mpapp = /MPAPP\/([\d\.]+)/i.test(ua); var is_ipad = /iPad/i.test(ua); var is_windows_wechat = /WindowsWechat/i.test(ua); var is_mac_wechat = /MacWechat/i.test(ua) || /wechat.*mac os/i.test(ua); var is_prefetch = is_wechat && window.WeixinPrefecherJSBridge; var is_donut_app = /SAAASDK/i.test(ua); var is_harmony = /OpenHarmony|ArkWeb/i.test(ua); var is_in_miniProgram = is_android && /miniprogram/.test(ua.toLowerCase()) || window.__wxjs_environment == 'miniprogram'; var is_wx_work = /wxwork/i.test(ua); function getUrlParams() { var vars = location.search.substring(1).split('&'); var params = {}; var _iterator = _createForOfIteratorHelper(vars), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var ele = _step.value; var pair = ele.split('='); var key = decodeURIComponent(pair[0]); if (typeof params[key] === 'undefined') { params[key] = decodeURIComponent(pair[1]); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return params; } function get() { var reg = /MicroMessenger\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMac() { var reg = /MacWechat\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMacOS() { var reg = /Mac OS X ([\d_]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1].replace(/_/g, '.'); } return false; } function getWindows() { var reg = /WindowsWechat\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getWxWork() { var reg = /wxwork\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMpApp() { var appVersion = [2, 4, 5]; var match = navigator.userAgent.match(/MPAPP\/(\d+(\.\d+)*)/); if (match) { appVersion = match[1].split('.').map(function (v) { return Number(v); }); } return appVersion.join('.'); } function getUnifiedPcVer() { var versionInfo = navigator.userAgent.match(/UnifiedPC\w+Wechat\(0xf\w{2}(\w+?)\w{2}\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(0, 1)); var subVersion = getVersionNumber(version.slice(1, 2)); var subVersion2 = getVersionNumber(version.slice(2, 3)); return [mainVersion, subVersion, subVersion2].join('.'); } } function getVersionNumber(hexStr) { return Number(Number("0x".concat(hexStr)).toString(10)); } function getWindowsVersionFormat() { var versionInfo = navigator.userAgent.match(/WindowsWechat\(0x(\w+?)\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(1, 2)); var subVersion = getVersionNumber(version.slice(2, 4)); var subVersion2 = getVersionNumber(version.slice(4, 6)); return [mainVersion, subVersion, subVersion2].join('.'); } return false; } function getInner() { var reg = /MicroMessenger\/[\d\.]+\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1] && ret[1] != null) { return ret[1]; } if (!ret && /MicroMessenger\/[\d\.]+/i.test(ua)) { var urlParams = getUrlParams(); if (urlParams.version) { return urlParams.version; } } return false; } var opfunc = { 'cp-1': function cp1(a, b) { return a < b; }, cp0: function cp0(a, b) { return a === b; }, cp1: function cp1(a, b) { return a > b; } }; function cpVersion(ver, op, canEq, type) { var mmver = false; switch (type) { case 'mac': mmver = getMac(); break; case 'windows': mmver = getWindowsVersionFormat(); break; case 'wxwork': mmver = getWxWork(); break; case 'mpapp': mmver = getMpApp(); break; case 'unifiedpc': mmver = getUnifiedPcVer(); break; default: mmver = get(); break; } if (!mmver) { return; } var mmversion = mmver.split('.'); var version = ver.split('.'); if (!/\d+/g.test(mmversion[mmversion.length - 1])) { mmversion.pop(); } for (var i = 0, len = Math.max(mmversion.length, version.length); i < len; ++i) { var mmv = mmversion[i] || ''; var v = version[i] || ''; var mmvn = parseInt(mmv, 10) || 0; var vn = parseInt(v, 10) || 0; var eq = opfunc.cp0(mmvn, vn); if (eq) { continue; } var cp = opfunc["cp".concat(op)]; return cp(mmvn, vn); } return canEq || op === 0; } function eqVersion(version) { return cpVersion(version, 0); } function gtVersion(version, canEq) { return cpVersion(version, 1, canEq); } function ltVersion(version, canEq) { return cpVersion(version, -1, canEq); } function getPlatform() { if (is_ios) { return 'ios'; } if (is_android) { return 'android'; } if (is_mac) { return 'mac_os'; } if (is_windows) { return 'windows'; } return 'unknown'; } var is_google_play = false; var inner_ver_for_google_play_check = getInner(); if (is_android && inner_ver_for_google_play_check) { var v = "0x".concat(inner_ver_for_google_play_check.substr(-2)); if (parseInt(v) >= 64 && parseInt(v) <= 79) { is_google_play = true; } } ({ get: get, getMac: getMac, getMacOS: getMacOS, getWindows: getWindows, getInner: getInner, getWxWork: getWxWork, getMpApp: getMpApp, cpVersion: cpVersion, eqVersion: eqVersion, gtVersion: gtVersion, ltVersion: ltVersion, getPlatform: getPlatform, getVersionNumber: getVersionNumber, isWp: is_wp, isIOS: is_ios, isAndroid: is_android, isHarmony: is_harmony, isHarmonyWechat: is_harmony && is_wechat && cpVersion('1.0.0', 1, true), isInMiniProgram: is_in_miniProgram, isWechat: is_wechat, isMac: is_mac, isWindows: is_windows, isMacWechat: is_mac_wechat, isWindowsWechat: is_windows_wechat, isWxWork: is_wx_work, isOnlyWechat: is_wechat && !is_wx_work, isMpapp: is_mpapp, isNewMpApp: false, isIPad: is_ipad, isGooglePlay: is_google_play, isPrefetch: is_prefetch, isDonutAPP: is_donut_app }); if (!window.JSAPIEventCallbackMap) { window.JSAPIEventCallbackMap = {}; } var doc = {}; var isAcrossOrigin = false; var __moon_report = window.__moon_report || function () {}; var MOON_JSAPI_KEY_OFFSET = 8; try { doc = top.window.document; } catch (e) { isAcrossOrigin = true; } if (!window.JSAPIEventCallbackMap) { window.JSAPIEventCallbackMap = {}; } function ready(onBridgeReady) { var bridgeReady = function bridgeReady() { try { if (onBridgeReady) { window.onBridgeReadyTime = window.onBridgeReadyTime || Date.now(); onBridgeReady(); } } catch (e) { __moon_report([{ offset: MOON_JSAPI_KEY_OFFSET, log: 'ready', e: e }]); throw e; } window.jsapiReadyTime = Date.now(); }; if (!isAcrossOrigin && (typeof top.window.WeixinJSBridge === 'undefined' || !top.window.WeixinJSBridge.invoke)) { if (doc.addEventListener) { doc.addEventListener('WeixinJSBridgeReady', bridgeReady, false); } else if (doc.attachEvent) { doc.attachEvent('WeixinJSBridgeReady', bridgeReady); doc.attachEvent('onWeixinJSBridgeReady', bridgeReady); } } else { bridgeReady(); } } function invoke(methodName, args, callback) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { invoke(methodName, args, callback); }); return; } ready(function () { if (isAcrossOrigin) return false; if (_typeof(top.window.WeixinJSBridge) !== 'object') { alert('请在微信中打开此链接'); return false; } top.window.WeixinJSBridge.invoke(methodName, args, function () { try { for (var _len = arguments.length, rets = new Array(_len), _key = 0; _key < _len; _key++) { rets[_key] = arguments[_key]; } var ret = rets[0]; var errMsg = ret && ret.err_msg ? ", err_msg-> ".concat(ret.err_msg) : ''; console.info('[system]', "[jsapi] invoke->".concat(methodName).concat(errMsg)); if (callback) { callback.apply(window, rets); } } catch (e) { __moon_report([{ offset: MOON_JSAPI_KEY_OFFSET, log: "invoke;methodName:".concat(methodName), e: e }]); throw e; } }); }); } function call(methodName) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { call(methodName); }); return; } ready(function () { if (isAcrossOrigin) return false; if (_typeof(top.window.WeixinJSBridge) !== 'object') { return false; } try { top.window.WeixinJSBridge.call(methodName); } catch (e) { __moon_report([{ offset: MOON_JSAPI_KEY_OFFSET, log: "call;methodName:".concat(methodName), e: e }]); throw e; } }); } function on(eventName, callback) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { on(eventName, callback); }); return; } ready(function () { if (isAcrossOrigin) return false; if (_typeof(top.window.WeixinJSBridge) !== 'object' || !top.window.WeixinJSBridge.on) { return false; } if (!window.JSAPIEventCallbackMap[eventName]) { window.JSAPIEventCallbackMap[eventName] = []; } window.JSAPIEventCallbackMap[eventName].push(callback); if (window.JSAPIEventCallbackMap[eventName].length > 1) { return false; } top.window.WeixinJSBridge.on(eventName, function () { try { for (var _len2 = arguments.length, rets = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { rets[_key2] = arguments[_key2]; } var ret = rets[0]; var errMsg = ret && ret.err_msg ? ", err_msg-> ".concat(ret.err_msg) : ''; console.info('[system]', "[jsapi] event->".concat(eventName).concat(errMsg)); if (window.JSAPIEventCallbackMap[eventName] && window.JSAPIEventCallbackMap[eventName].length) { var result; for (var i = 0; i < window.JSAPIEventCallbackMap[eventName].length; i++) { result = window.JSAPIEventCallbackMap[eventName][i].apply(window, rets); } return result; } } catch (e) { __moon_report([{ offset: MOON_JSAPI_KEY_OFFSET, log: "on;eventName:".concat(eventName), e: e }]); throw e; } }); }); } function remove(eventName, callback) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { remove(eventName, callback); }); return; } ready(function () { if (!window.JSAPIEventCallbackMap[eventName]) { return false; } var result = false; for (var i = window.JSAPIEventCallbackMap[eventName].length - 1; i >= 0; i--) { if (window.JSAPIEventCallbackMap[eventName][i] === callback) { window.JSAPIEventCallbackMap[eventName].splice(i, 1); result = true; } } return result; }); } var JSAPI = { ready: ready, invoke: invoke, call: call, on: on, remove: remove }; function initBodyStyle() { window.scrollTo({ top: 0, behavior: 'smooth' }); setTimeout(function () { document.body.scrollTop = document.documentElement.scrollTop = 0; document.body.style.overflow = 'hidden'; }, 100); } var setRowImmersiveMode = function setRowImmersiveMode(itemShowType) { var envStr = window.__wxWebEnv && typeof window.__wxWebEnv.getEnv === 'function' && window.__wxWebEnv.getEnv(); if (!envStr) return; var envObj = {}; try { envObj = JSON.parse(envStr); } catch (err) { console.info(err); } var immersiveListMode = envObj.immersiveListMode || 0; window.__immersiveListMode = Number(immersiveListMode) === 1 ? 1 : 0; window.__rowImmersiveStream = Number(immersiveListMode) === 2 ? 1 : 0; console.log("iiiiiiimmersiveListMode", immersiveListMode, window.__immersiveListMode, window.__rowImmersiveStream); window.__test_row_immersive_list = 0; if (window.__test_row_immersive_list) { window.__rowImmersiveStream = 1; } if (window.__rowImmersiveStream) { initBodyStyle(); var rowImmersiveStreamWrap = document.getElementById('js_row_immersive_stream_wrap'); if (rowImmersiveStreamWrap) { rowImmersiveStreamWrap.style.display = 'block'; } var bottomBar = document.getElementById('js_article_bottom_bar'); if (bottomBar) { bottomBar.classList.add('row_immersive_bottom_bar'); } var immersiveStreamMask = document.getElementById('js_row_immersive_stream_mask'); var enterBigWebview = function enterBigWebview() { immersiveStreamMask.style.display = 'none'; document.body.style.overflow = 'auto'; if (bottomBar) { bottomBar.classList.add('row_immersive_bigview_bottom_bar'); } }; var exitBigWebview = function exitBigWebview() { initBodyStyle(); immersiveStreamMask.style.display = 'block'; if (bottomBar) { bottomBar.classList.remove('row_immersive_bigview_bottom_bar'); } }; immersiveStreamMask.addEventListener('click', function (e) { e.preventDefault(); e.stopPropagation(); JSAPI.invoke('handleImmersiveStream', { action: 'enterFullArticle', params: { enterTime: Date.now() } }, function (res) { console.log("[immersive] handleImmersiveStream:", res); if (res && res.err_msg && res.err_msg.includes('ok')) { enterBigWebview(); } if (window.__test_row_immersive_list) { setTimeout(function () { console.log("xxxxx ok"); enterBigWebview(); }, 2000); } }); }); JSAPI.on('immersiveStreamExposeArticle', function (res) { console.log("[immersive] immersiveStreamExposeArticle", res); }); JSAPI.on('immersiveStreamExitFullArticle', function (res) { console.log("[immersive] immersiveStreamExitFullArticle", res); exitBigWebview(); }); JSAPI.on('immersiveStreamEnterFullArticle', function (res) { console.log("[immersive] immersiveStreamEnterFullArticle", res); enterBigWebview(); }); JSAPI.on('immersiveStreamSlideOutArticle', function (res) { console.log("[immersive] immersiveStreamSlideOutArticle", res); exitBigWebview(); }); } }; if (!window.__second_open__) { setRowImmersiveMode(); } return setRowImmersiveMode; })();</script><script type="text/javascript" nonce="1989770072" reportloaderror>var __INLINE_SCRIPT__ = (function () { 'use strict'; var getIpWoridng = function getIpWoridng(ipConfig) { var ipWording = ''; if (parseInt(ipConfig.countryId, 10) === 156) { ipWording = ipConfig.provinceName; } else if (ipConfig.countryId) { ipWording = ipConfig.countryName; } return ipWording; }; var __setIpWording = function __setIpWording(ipConfig, userInfo, itemShowType) { var ipWrp = document.getElementById('js_ip_wording_wrp'); var ipWording = document.getElementById('js_ip_wording'); if (ipConfig) { window.ip_wording = { countryName: ipConfig.country_name, countryId: ipConfig.country_id, provinceName: ipConfig.province_name }; } if (userInfo && userInfo.isoversea) { window.is_over_sea = parseInt(userInfo.isoversea, 10); } if (window.ip_wording && ipWrp && ipWording && window.is_over_sea !== 1) { var ipWordingDisplay = getIpWoridng(window.ip_wording); if (ipWordingDisplay !== '') { ipWording.innerHTML = ipWordingDisplay; ipWrp.style.display = 'inline-block'; } } if (+itemShowType === 0) ipWrp && ipWrp.style.display == 'none' && ipWrp.parentNode.removeChild(ipWrp); }; if (!window.__second_open__) { var itemShowType = window.a_value_which_never_exists || '0'; __setIpWording(undefined, undefined, itemShowType); window.__setIpWording = __setIpWording; } return __setIpWording; })();</script><script type="text/javascript" nonce="1989770072" reportloaderror>var __INLINE_SCRIPT__ = (function () { 'use strict'; var __setTitleModify = function __setTitleModify(isTitleModified) { var wrp = document.getElementById('js_title_modify_wrp'); var titleModifyNode = document.getElementById('js_title_modify'); if (!wrp) return; if (isTitleModified || window.isTitleModified) { titleModifyNode.innerHTML = '标题已修改'; wrp.style.display = 'inline-block'; } else { wrp.parentNode.removeChild(wrp); } }; if (!window.__second_open__) { __setTitleModify(); window.__setTitleModify = __setTitleModify; } return __setTitleModify; })();</script><script type="text/javascript" nonce="1989770072" reportloaderror>var __INLINE_SCRIPT__ = (function () { 'use strict'; var dealLikeReadShow_en = function dealLikeReadShow_en(realNum) { if (typeof LANG === 'undefined' || !window.LANG) { return parseInt(realNum) === 0 ? '' : realNum; } if (window.LANG == 'en') { var showHTML = ''; if (parseInt(realNum) > 100000) { showHTML = 100 + 'k+'; } else if (parseInt(realNum) > 10000 && parseInt(realNum) <= 100000) { var num = '' + parseInt(realNum) / 1000; var dotIndex = num.indexOf('.'); if (dotIndex === -1) { showHTML = num + 'k'; } else { showHTML = num.substring(0, dotIndex) + '.' + num.charAt(dotIndex + 1) + 'k'; } } else if (parseInt(realNum) === 0) { showHTML = ''; } else { showHTML = realNum; } return showHTML; } return ''; }; var i18n = { dealLikeReadShow_en: dealLikeReadShow_en }; function getWordCount (dom) { if (!dom) return 0; var textContet = dom.textContent || ''; var fillCharReg = new RegExp("\u200B", 'g'); var bookmarkFillCharReg = new RegExp("\u200D", 'g'); return textContet.replace(fillCharReg, '') .replace(bookmarkFillCharReg, '') .replace(/(\b|^)\w+(\b|$)/g, '#') .replace(/\s/g, '') .length; } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } var ua = navigator.userAgent; var is_ios = /(iPhone|iPad|iPod|iOS)/i.test(ua); var is_wp = /Windows\sPhone/i.test(ua); var is_android = /(Android)/i.test(ua); var is_wechat = /MicroMessenger\/([\d\.]+)/i.test(ua); var is_mac = /mac\sos/i.test(ua) && !is_ios; var is_windows = /windows\snt/i.test(ua) && !is_wp; var is_mpapp = /MPAPP\/([\d\.]+)/i.test(ua); var is_ipad = /iPad/i.test(ua); var is_windows_wechat = /WindowsWechat/i.test(ua); var is_mac_wechat = /MacWechat/i.test(ua) || /wechat.*mac os/i.test(ua); var is_prefetch = is_wechat && window.WeixinPrefecherJSBridge; var is_donut_app = /SAAASDK/i.test(ua); var is_harmony = /OpenHarmony|ArkWeb/i.test(ua); var is_in_miniProgram = is_android && /miniprogram/.test(ua.toLowerCase()) || window.__wxjs_environment == 'miniprogram'; var is_wx_work = /wxwork/i.test(ua); function getUrlParams() { var vars = location.search.substring(1).split('&'); var params = {}; var _iterator = _createForOfIteratorHelper(vars), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var ele = _step.value; var pair = ele.split('='); var key = decodeURIComponent(pair[0]); if (typeof params[key] === 'undefined') { params[key] = decodeURIComponent(pair[1]); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return params; } function get() { var reg = /MicroMessenger\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMac() { var reg = /MacWechat\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMacOS() { var reg = /Mac OS X ([\d_]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1].replace(/_/g, '.'); } return false; } function getWindows() { var reg = /WindowsWechat\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getWxWork() { var reg = /wxwork\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMpApp() { var appVersion = [2, 4, 5]; var match = navigator.userAgent.match(/MPAPP\/(\d+(\.\d+)*)/); if (match) { appVersion = match[1].split('.').map(function (v) { return Number(v); }); } return appVersion.join('.'); } function getUnifiedPcVer() { var versionInfo = navigator.userAgent.match(/UnifiedPC\w+Wechat\(0xf\w{2}(\w+?)\w{2}\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(0, 1)); var subVersion = getVersionNumber(version.slice(1, 2)); var subVersion2 = getVersionNumber(version.slice(2, 3)); return [mainVersion, subVersion, subVersion2].join('.'); } } function getVersionNumber(hexStr) { return Number(Number("0x".concat(hexStr)).toString(10)); } function getWindowsVersionFormat() { var versionInfo = navigator.userAgent.match(/WindowsWechat\(0x(\w+?)\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(1, 2)); var subVersion = getVersionNumber(version.slice(2, 4)); var subVersion2 = getVersionNumber(version.slice(4, 6)); return [mainVersion, subVersion, subVersion2].join('.'); } return false; } function getInner$1() { var reg = /MicroMessenger\/[\d\.]+\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1] && ret[1] != null) { return ret[1]; } if (!ret && /MicroMessenger\/[\d\.]+/i.test(ua)) { var urlParams = getUrlParams(); if (urlParams.version) { return urlParams.version; } } return false; } var opfunc = { 'cp-1': function cp1(a, b) { return a < b; }, cp0: function cp0(a, b) { return a === b; }, cp1: function cp1(a, b) { return a > b; } }; function cpVersion(ver, op, canEq, type) { var mmver = false; switch (type) { case 'mac': mmver = getMac(); break; case 'windows': mmver = getWindowsVersionFormat(); break; case 'wxwork': mmver = getWxWork(); break; case 'mpapp': mmver = getMpApp(); break; case 'unifiedpc': mmver = getUnifiedPcVer(); break; default: mmver = get(); break; } if (!mmver) { return; } var mmversion = mmver.split('.'); var version = ver.split('.'); if (!/\d+/g.test(mmversion[mmversion.length - 1])) { mmversion.pop(); } for (var i = 0, len = Math.max(mmversion.length, version.length); i < len; ++i) { var mmv = mmversion[i] || ''; var v = version[i] || ''; var mmvn = parseInt(mmv, 10) || 0; var vn = parseInt(v, 10) || 0; var eq = opfunc.cp0(mmvn, vn); if (eq) { continue; } var cp = opfunc["cp".concat(op)]; return cp(mmvn, vn); } return canEq || op === 0; } function eqVersion(version) { return cpVersion(version, 0); } function gtVersion(version, canEq) { return cpVersion(version, 1, canEq); } function ltVersion(version, canEq) { return cpVersion(version, -1, canEq); } function getPlatform() { if (is_ios) { return 'ios'; } if (is_android) { return 'android'; } if (is_mac) { return 'mac_os'; } if (is_windows) { return 'windows'; } return 'unknown'; } var is_google_play = false; var inner_ver_for_google_play_check = getInner$1(); if (is_android && inner_ver_for_google_play_check) { var v = "0x".concat(inner_ver_for_google_play_check.substr(-2)); if (parseInt(v) >= 64 && parseInt(v) <= 79) { is_google_play = true; } } var mmVersion = { get: get, getMac: getMac, getMacOS: getMacOS, getWindows: getWindows, getInner: getInner$1, getWxWork: getWxWork, getMpApp: getMpApp, cpVersion: cpVersion, eqVersion: eqVersion, gtVersion: gtVersion, ltVersion: ltVersion, getPlatform: getPlatform, getVersionNumber: getVersionNumber, isWp: is_wp, isIOS: is_ios, isAndroid: is_android, isHarmony: is_harmony, isHarmonyWechat: is_harmony && is_wechat && cpVersion('1.0.0', 1, true), isInMiniProgram: is_in_miniProgram, isWechat: is_wechat, isMac: is_mac, isWindows: is_windows, isMacWechat: is_mac_wechat, isWindowsWechat: is_windows_wechat, isWxWork: is_wx_work, isOnlyWechat: is_wechat && !is_wx_work, isMpapp: is_mpapp, isNewMpApp: false, isIPad: is_ipad, isGooglePlay: is_google_play, isPrefetch: is_prefetch, isDonutAPP: is_donut_app }; var isIOS = mmVersion.isIOS, getInner = mmVersion.getInner, isAndroid = mmVersion.isAndroid; var formatReadNum = function formatReadNum(value) { if (window.LANG === 'en') { return i18n.dealLikeReadShow_en(value); } var result = ''; if (parseInt(value, 10) > 100000) { result = '10万+'; } else if (parseInt(value, 10) > 10000 && parseInt(value, 10) <= 100000) { var num = '' + parseInt(value, 10) / 10000; var dotIndex = num.indexOf('.'); if (dotIndex === -1) { result = num + '万'; } else { result = num.substr(0, dotIndex) + '.' + num.charAt(dotIndex + 1) + '万'; } } else if (parseInt(value, 10) === 0) { result = ''; } else { result = value || ''; } return result; }; var __setTingHeard = function __setTingHeard(container, dom, cnt, isTempUrl) { var articleWordCnt = getWordCount(container || document.querySelector('#js_content')); window.article_word_cnt = articleWordCnt; if (!dom || articleWordCnt <= 100 || isTempUrl) { dom && dom.parentNode.removeChild(dom); return; } if (isIOS && getInner() >= '18002622' || isAndroid && getInner() >= '2800253A') { if (cnt > 100000) { dom.innerText = "".concat(formatReadNum(cnt), ""); dom.setAttribute('aria-labelledby', 'js_ting_heard js_a11y_op_ting_heard'); } else if (cnt > 0) { dom.innerText = "".concat(formatReadNum(cnt), "人"); dom.setAttribute('aria-labelledby', 'js_ting_heard js_a11y_op_ting_heard'); } else { dom.innerText = "听全文"; dom.setAttribute('aria-labelledby', 'js_ting_heard'); } dom.style.removeProperty('display'); window.__hasClickedAudioPanelHandler = function () { window.__hasClickedAudioPanel = true; }; dom.addEventListener('click', window.__hasClickedAudioPanelHandler); } else { dom.parentNode.removeChild(dom); } }; if (!window.__second_open__) { var tempkey = window.tempkey || ''; var tingHeardDom = document.querySelector('#js_ting_heard'); document.querySelector('#js_a11y_op_ting_heard'); var tingIsShow = window.tts_is_show || ''; var tingHeardCnt = window.tts_heard_person_cnt || ''; console.log('tingIsShow, tingHeardCnt', tingIsShow, tingHeardCnt); !!(tingIsShow * 1) && __setTingHeard(document.querySelector('#js_content'), tingHeardDom, tingHeardCnt * 1, !!tempkey); window.__setTingHeard = __setTingHeard; } return __setTingHeard; })();</script><script type="text/javascript" nonce="1989770072" reportloaderror>var __INLINE_SCRIPT__ = (function (exports) { 'use strict'; function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray$1(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray$1(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$1(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen); } function _arrayLikeToArray$1(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } var ua = navigator.userAgent; var is_ios = /(iPhone|iPad|iPod|iOS)/i.test(ua); var is_wp = /Windows\sPhone/i.test(ua); var is_android = /(Android)/i.test(ua); var is_wechat = /MicroMessenger\/([\d\.]+)/i.test(ua); var is_mac = /mac\sos/i.test(ua) && !is_ios; var is_windows = /windows\snt/i.test(ua) && !is_wp; var is_mpapp = /MPAPP\/([\d\.]+)/i.test(ua); var is_ipad = /iPad/i.test(ua); var is_windows_wechat = /WindowsWechat/i.test(ua); var is_mac_wechat = /MacWechat/i.test(ua) || /wechat.*mac os/i.test(ua); var is_prefetch = is_wechat && window.WeixinPrefecherJSBridge; var is_donut_app = /SAAASDK/i.test(ua); var is_harmony = /OpenHarmony|ArkWeb/i.test(ua); var is_in_miniProgram = is_android && /miniprogram/.test(ua.toLowerCase()) || window.__wxjs_environment == 'miniprogram'; var is_wx_work = /wxwork/i.test(ua); function getUrlParams() { var vars = location.search.substring(1).split('&'); var params = {}; var _iterator = _createForOfIteratorHelper(vars), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var ele = _step.value; var pair = ele.split('='); var key = decodeURIComponent(pair[0]); if (typeof params[key] === 'undefined') { params[key] = decodeURIComponent(pair[1]); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return params; } function get() { var reg = /MicroMessenger\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMac() { var reg = /MacWechat\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMacOS() { var reg = /Mac OS X ([\d_]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1].replace(/_/g, '.'); } return false; } function getWindows() { var reg = /WindowsWechat\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getWxWork() { var reg = /wxwork\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMpApp() { var appVersion = [2, 4, 5]; var match = navigator.userAgent.match(/MPAPP\/(\d+(\.\d+)*)/); if (match) { appVersion = match[1].split('.').map(function (v) { return Number(v); }); } return appVersion.join('.'); } function getUnifiedPcVer() { var versionInfo = navigator.userAgent.match(/UnifiedPC\w+Wechat\(0xf\w{2}(\w+?)\w{2}\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(0, 1)); var subVersion = getVersionNumber(version.slice(1, 2)); var subVersion2 = getVersionNumber(version.slice(2, 3)); return [mainVersion, subVersion, subVersion2].join('.'); } } function getVersionNumber(hexStr) { return Number(Number("0x".concat(hexStr)).toString(10)); } function getWindowsVersionFormat() { var versionInfo = navigator.userAgent.match(/WindowsWechat\(0x(\w+?)\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(1, 2)); var subVersion = getVersionNumber(version.slice(2, 4)); var subVersion2 = getVersionNumber(version.slice(4, 6)); return [mainVersion, subVersion, subVersion2].join('.'); } return false; } function getInner$1() { var reg = /MicroMessenger\/[\d\.]+\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1] && ret[1] != null) { return ret[1]; } if (!ret && /MicroMessenger\/[\d\.]+/i.test(ua)) { var urlParams = getUrlParams(); if (urlParams.version) { return urlParams.version; } } return false; } var opfunc = { 'cp-1': function cp1(a, b) { return a < b; }, cp0: function cp0(a, b) { return a === b; }, cp1: function cp1(a, b) { return a > b; } }; function cpVersion(ver, op, canEq, type) { var mmver = false; switch (type) { case 'mac': mmver = getMac(); break; case 'windows': mmver = getWindowsVersionFormat(); break; case 'wxwork': mmver = getWxWork(); break; case 'mpapp': mmver = getMpApp(); break; case 'unifiedpc': mmver = getUnifiedPcVer(); break; default: mmver = get(); break; } if (!mmver) { return; } var mmversion = mmver.split('.'); var version = ver.split('.'); if (!/\d+/g.test(mmversion[mmversion.length - 1])) { mmversion.pop(); } for (var i = 0, len = Math.max(mmversion.length, version.length); i < len; ++i) { var mmv = mmversion[i] || ''; var v = version[i] || ''; var mmvn = parseInt(mmv, 10) || 0; var vn = parseInt(v, 10) || 0; var eq = opfunc.cp0(mmvn, vn); if (eq) { continue; } var cp = opfunc["cp".concat(op)]; return cp(mmvn, vn); } return canEq || op === 0; } function eqVersion(version) { return cpVersion(version, 0); } function gtVersion(version, canEq) { return cpVersion(version, 1, canEq); } function ltVersion(version, canEq) { return cpVersion(version, -1, canEq); } function getPlatform() { if (is_ios) { return 'ios'; } if (is_android) { return 'android'; } if (is_mac) { return 'mac_os'; } if (is_windows) { return 'windows'; } return 'unknown'; } var is_google_play = false; var inner_ver_for_google_play_check = getInner$1(); if (is_android && inner_ver_for_google_play_check) { var v = "0x".concat(inner_ver_for_google_play_check.substr(-2)); if (parseInt(v) >= 64 && parseInt(v) <= 79) { is_google_play = true; } } var mmVersion = { get: get, getMac: getMac, getMacOS: getMacOS, getWindows: getWindows, getInner: getInner$1, getWxWork: getWxWork, getMpApp: getMpApp, cpVersion: cpVersion, eqVersion: eqVersion, gtVersion: gtVersion, ltVersion: ltVersion, getPlatform: getPlatform, getVersionNumber: getVersionNumber, isWp: is_wp, isIOS: is_ios, isAndroid: is_android, isHarmony: is_harmony, isHarmonyWechat: is_harmony && is_wechat && cpVersion('1.0.0', 1, true), isInMiniProgram: is_in_miniProgram, isWechat: is_wechat, isMac: is_mac, isWindows: is_windows, isMacWechat: is_mac_wechat, isWindowsWechat: is_windows_wechat, isWxWork: is_wx_work, isOnlyWechat: is_wechat && !is_wx_work, isMpapp: is_mpapp, isNewMpApp: false, isIPad: is_ipad, isGooglePlay: is_google_play, isPrefetch: is_prefetch, isDonutAPP: is_donut_app }; var initJsBridge = false; if (!window.JSAPIEventCallbackMap) { window.JSAPIEventCallbackMap = {}; } function connectWebViewJavascriptBridge(callback) { if (window.WebViewMPapp || window.WebViewJavascriptBridge) { return callback(window.WebViewMPapp || window.WebViewJavascriptBridge); } if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); } window.WVJBCallbacks = [callback]; if (!initJsBridge) { initJsBridge = true; var WVJBIframe = document.createElement('iframe'); WVJBIframe.style.display = 'none'; WVJBIframe.src = 'https://__bridge_loaded__'; document.body.appendChild(WVJBIframe); setTimeout(function () { initJsBridge = false; document.body.removeChild(WVJBIframe); }, 0); } return false; } function invoke$1(jsapiName, opt, callback) { connectWebViewJavascriptBridge(function (bridge) { try { if (typeof opt === 'function') { callback = opt; } if (_typeof(opt) !== 'object' && typeof opt !== 'string') { opt = {}; } bridge.callHandler(jsapiName, opt, function (res) { try { var ret = _typeof(res) === 'object' ? res : JSON.parse(res); var errMsg = ret.err_msg || ret.errMsg; console.info("[mpapp jsapi] invoke->".concat(jsapiName, " ").concat(opt.action || '', " ").concat(errMsg)); typeof callback === 'function' && callback(ret); } catch (e) { window.WX_BJ_REPORT.BadJs.report('invoke', "callback ".concat(jsapiName, " error:"), { mid: 'mmbizwebapp:js_brridge', _info: e }); console.error("[mpapp jsapi] ".concat(jsapiName, " ").concat(opt.action || ''), e, res); } }); } catch (e) { window.WX_BJ_REPORT.BadJs.report('invoke', 'callback error:', { mid: 'mmbizwebapp:js_brridge', _info: e }); console.error('[mpapp jsapi]', e); } }); } var doc$1 = {}; var isAcrossOrigin$1 = false; var __moon_report$1 = window.__moon_report || function () {}; var MOON_JSAPI_KEY_OFFSET = 8; try { doc$1 = top.window.document; } catch (e) { isAcrossOrigin$1 = true; } if (!window.JSAPIEventCallbackMap) { window.JSAPIEventCallbackMap = {}; } function ready(onBridgeReady) { var bridgeReady = function bridgeReady() { try { if (onBridgeReady) { window.onBridgeReadyTime = window.onBridgeReadyTime || Date.now(); onBridgeReady(); } } catch (e) { __moon_report$1([{ offset: MOON_JSAPI_KEY_OFFSET, log: 'ready', e: e }]); throw e; } window.jsapiReadyTime = Date.now(); }; if (!isAcrossOrigin$1 && (typeof top.window.WeixinJSBridge === 'undefined' || !top.window.WeixinJSBridge.invoke)) { if (doc$1.addEventListener) { doc$1.addEventListener('WeixinJSBridgeReady', bridgeReady, false); } else if (doc$1.attachEvent) { doc$1.attachEvent('WeixinJSBridgeReady', bridgeReady); doc$1.attachEvent('onWeixinJSBridgeReady', bridgeReady); } } else { bridgeReady(); } } function invoke(methodName, args, callback) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { invoke(methodName, args, callback); }); return; } ready(function () { if (isAcrossOrigin$1) return false; if (_typeof(top.window.WeixinJSBridge) !== 'object') { alert('请在微信中打开此链接'); return false; } top.window.WeixinJSBridge.invoke(methodName, args, function () { try { for (var _len = arguments.length, rets = new Array(_len), _key = 0; _key < _len; _key++) { rets[_key] = arguments[_key]; } var ret = rets[0]; var errMsg = ret && ret.err_msg ? ", err_msg-> ".concat(ret.err_msg) : ''; console.info('[system]', "[jsapi] invoke->".concat(methodName).concat(errMsg)); if (callback) { callback.apply(window, rets); } } catch (e) { __moon_report$1([{ offset: MOON_JSAPI_KEY_OFFSET, log: "invoke;methodName:".concat(methodName), e: e }]); throw e; } }); }); } function call(methodName) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { call(methodName); }); return; } ready(function () { if (isAcrossOrigin$1) return false; if (_typeof(top.window.WeixinJSBridge) !== 'object') { return false; } try { top.window.WeixinJSBridge.call(methodName); } catch (e) { __moon_report$1([{ offset: MOON_JSAPI_KEY_OFFSET, log: "call;methodName:".concat(methodName), e: e }]); throw e; } }); } function on(eventName, callback) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { on(eventName, callback); }); return; } ready(function () { if (isAcrossOrigin$1) return false; if (_typeof(top.window.WeixinJSBridge) !== 'object' || !top.window.WeixinJSBridge.on) { return false; } if (!window.JSAPIEventCallbackMap[eventName]) { window.JSAPIEventCallbackMap[eventName] = []; } window.JSAPIEventCallbackMap[eventName].push(callback); if (window.JSAPIEventCallbackMap[eventName].length > 1) { return false; } top.window.WeixinJSBridge.on(eventName, function () { try { for (var _len2 = arguments.length, rets = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { rets[_key2] = arguments[_key2]; } var ret = rets[0]; var errMsg = ret && ret.err_msg ? ", err_msg-> ".concat(ret.err_msg) : ''; console.info('[system]', "[jsapi] event->".concat(eventName).concat(errMsg)); if (window.JSAPIEventCallbackMap[eventName] && window.JSAPIEventCallbackMap[eventName].length) { var result; for (var i = 0; i < window.JSAPIEventCallbackMap[eventName].length; i++) { result = window.JSAPIEventCallbackMap[eventName][i].apply(window, rets); } return result; } } catch (e) { __moon_report$1([{ offset: MOON_JSAPI_KEY_OFFSET, log: "on;eventName:".concat(eventName), e: e }]); throw e; } }); }); } function remove(eventName, callback) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { remove(eventName, callback); }); return; } ready(function () { if (!window.JSAPIEventCallbackMap[eventName]) { return false; } var result = false; for (var i = window.JSAPIEventCallbackMap[eventName].length - 1; i >= 0; i--) { if (window.JSAPIEventCallbackMap[eventName][i] === callback) { window.JSAPIEventCallbackMap[eventName].splice(i, 1); result = true; } } return result; }); } var JSAPI = { ready: ready, invoke: invoke, call: call, on: on, remove: remove }; function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i["return"] && (_r = _i["return"](), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var reportLogs = []; var reportExtraLogs = []; var sendUrl = '/mp/jsmonitor?#wechat_redirect'; var monitor = {}; monitor._reportOptions = { idkey: {} }; function ObjWithoutProperty(source, exclude) { if (source === null) return {}; var target = {}; var sourceKeys = Object.keys(source); for (var i = 0; i < sourceKeys.length; i++) { var key = sourceKeys[i]; if (exclude.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function formatDataToString(data) { var reportData = []; for (var key in data) { if (Object.prototype.hasOwnProperty.call(data, key)) { reportData.push(key + '=' + encodeURIComponent(data[key])); } } return reportData.join('&'); } monitor.getReportData = function (opt) { opt = opt || {}; var idkey = monitor._reportOptions.idkey || {}; var key = null; var reportData = {}; var nextKey; try { for (key in idkey) { if (Object.prototype.hasOwnProperty.call(idkey, key) && idkey[key]) { reportLogs.push(key + '_' + idkey[key]); } } } catch (e) { return false; } if (reportLogs.length === 0) { return false; } if (reportExtraLogs.length) { reportData.lc = reportExtraLogs.length; reportExtraLogs.forEach(function (extraLog, index) { reportData["log".concat(index)] = extraLog; }); } try { var reportOptions = monitor._reportOptions; if (reportOptions !== null && reportOptions !== undefined) { for (nextKey in reportOptions) { if (Object.prototype.hasOwnProperty.call(reportOptions, nextKey)) { reportData[nextKey] = reportOptions[nextKey]; } } } } catch (e) { reportData = {}; } reportData.idkey = reportLogs.join(';'); reportData.t = Math.random(); if (opt.remove !== false) { reportLogs = []; reportExtraLogs = []; monitor._reportOptions = { idkey: {} }; } return reportData; }; monitor.setLogs = function (opt) { var id = opt.id; var key = opt.key; var value = opt.value; var extraLog = opt.log; var others = ObjWithoutProperty(opt, ['id', 'key', 'value', 'log']); var idkey = monitor._reportOptions.idkey || {}; var param = id + '_' + key; if (idkey[param]) { idkey[param] += value; } else { idkey[param] = value; } monitor._reportOptions.idkey = idkey; if (extraLog) { reportExtraLogs.push(extraLog); } try { if (others !== null && others !== undefined) { for (var otherKey in others) { if (Object.prototype.hasOwnProperty.call(others, otherKey)) { monitor._reportOptions[otherKey] = others[otherKey]; } } } } catch (e) { console.log(e); } return monitor; }; monitor.setAvg = function (id, key, value) { var idkey = monitor._reportOptions.idkey || {}; var param1 = id + '_' + key; var param2 = id + '_' + (key - 1); if (idkey[param1]) { idkey[param1] += value; } else { idkey[param1] = value; } if (idkey[param2]) { idkey[param2] += 1; } else { idkey[param2] = 1; } monitor._reportOptions.idkey = idkey; return monitor; }; monitor.setSum = function (id, key) { var value = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; var idkey = monitor._reportOptions.idkey; var param = id + '_' + key; if (idkey[param]) { idkey[param] += value; } else { idkey[param] = value; } monitor._reportOptions.idkey = idkey; return monitor; }; monitor.send = function (async, ajax, origin) { if (async !== false) { async = true; } var data = monitor.getReportData(); origin = origin || ''; if (!data) { return; } if (!!ajax && ajax instanceof Function) { ajax({ url: origin + sendUrl, type: 'POST', mayAbort: true, data: data, async: async, timeout: 2000 }); } else { new Image().src = origin + '/mp/jsmonitor?' + formatDataToString(data) + '#wechat_redirect'; } }; if (typeof window !== 'undefined' && window.__monitor) { monitor = window.__monitor; } else { typeof window !== 'undefined' && (window.__monitor = monitor); } var monitor$1 = monitor; var logList = []; var log = function log(msg) { logList.push(msg); }; var printLog = function printLog() { for (var i = 0, len = logList.length; i < len; ++i) { console.log("[RespType]".concat(logList[i])); } }; var isArray = function isArray(val) { return Object.prototype.toString.call(val) === '[object Array]'; }; var getValueType = function getValueType(value) { if (isArray(value)) { return 'array'; } return _typeof(value); }; var parseRtDesc = function parseRtDesc(rtDesc, k) { var type = 'mix'; var isRequired = false; var key = k; if (k) { var requireKeyWord = '_R'; var pos = k.indexOf(requireKeyWord); var len = k.length - requireKeyWord.length; isRequired = pos !== -1 && pos === len; key = isRequired ? k.substring(0, len) : k; } if (typeof rtDesc === 'string') { type = rtDesc; } else if (isArray(rtDesc)) { type = 'array'; } else if (_typeof(rtDesc) === 'object') { type = 'object'; } return { key: key, type: type, isRequired: isRequired }; }; var checkForArrayRtDesc = function checkForArrayRtDesc(arr, rtDescs) { if (!isArray(arr)) { return false; } for (var i = 0, len = arr.length; i < len; ++i) { var value = arr[i]; var rtDesc = void 0; var j = 0; var flag = rtDescs.length === 0; while (rtDesc = rtDescs[j++]) { if (checkForRtDesc(value, rtDesc)) { flag = true; break; } } if (!flag) { return false; } } return true; }; var checkForStringRtDesc = function checkForStringRtDesc(value, rtDesc) { var valueType = getValueType(value); var desc = parseRtDesc(rtDesc); var ret = desc.type === valueType; if (!ret) { log("miss match type : ".concat(valueType, " !== ").concat(desc.type)); } return ret; }; var checkForObjectRtDesc = function checkForObjectRtDesc(json, rtDesc) { if (_typeof(json) !== 'object' || isArray(json)) { log('must be object'); return false; } var rootJson = json; var nowCheckValue = json; for (var k in rtDesc) { if (rtDesc.hasOwnProperty(k)) { var nowCheckDesc = rtDesc[k]; var desc = parseRtDesc(nowCheckDesc, k); var key = desc.key; nowCheckValue = rootJson[key]; var valueType = getValueType(nowCheckValue); if (desc.isRequired && nowCheckValue === undefined) { log("is required @key=".concat(key)); return false; } if (nowCheckValue !== undefined) { if (valueType !== desc.type && desc.type !== 'mix') { log("miss match type : ".concat(valueType, " !== ").concat(desc.type, " @key=").concat(key)); return false; } if ((valueType === 'array' || valueType === 'object') && desc.type !== 'mix') { if (!checkForRtDesc(nowCheckValue, nowCheckDesc)) { return false; } } } } } return true; }; var checkForRtDesc = function checkForRtDesc(json, rtDesc) { if (isArray(rtDesc)) { return checkForArrayRtDesc(json, rtDesc); } if (_typeof(rtDesc) === 'object') { return checkForObjectRtDesc(json, rtDesc); } if (typeof rtDesc === 'string') { return checkForStringRtDesc(json, rtDesc); } return false; }; var _check = function check(json, rtDescs) { if (typeof json === 'string') { try { json = eval("(".concat(json, ")")); } catch (e) { log('parse json error'); return false; } } if (_typeof(json) !== 'object') { log('must be object'); return false; } if (!isArray(rtDescs)) { rtDescs = [rtDescs]; } var rtDesc; var i = 0; while (rtDesc = rtDescs[i++]) { if (checkForRtDesc(json, rtDesc)) { return true; } } return false; }; var RespTypes = { check: function check(json, rtDesc) { logList = []; try { var ret = _check(json, rtDesc); if (!ret) { printLog(); } return ret; } catch (e) { logList.push("[rtException]".concat(e.toString())); printLog(); return false; } }, getMsg: function getMsg() { return logList.join(';'); } }; var Device = {}; function detect(ua) { var MQQBrowser = ua.match(/MQQBrowser\/(\d+\.\d+)/i); var MQQClient = ua.match(/QQ\/(\d+\.(\d+)\.(\d+)\.(\d+))/i) || ua.match(/V1_AND_SQ_([\d\.]+)/); var WeChat = ua.match(/MicroMessenger\/((\d+)\.(\d+))\.(\d+)/) || ua.match(/MicroMessenger\/((\d+)\.(\d+))/); var MacOS = ua.match(/Mac\sOS\sX\s(\d+[\.|_]\d+)/); var WinOS = ua.match(/Windows(\s+\w+)?\s+?(\d+\.\d+)/); var Linux = ua.match(/Linux\s/); var MiuiBrowser = ua.match(/MiuiBrowser\/(\d+\.\d+)/i); var M1 = ua.match(/MI-ONE/); var MIPAD = ua.match(/MI PAD/); var UC = ua.match(/UCBrowser\/(\d+\.\d+(\.\d+\.\d+)?)/) || ua.match(/\sUC\s/); var IEMobile = ua.match(/IEMobile(\/|\s+)(\d+\.\d+)/) || ua.match(/WPDesktop/); var ipod = ua.match(/(ipod).*\s([\d_]+)/i); var ipad = ua.match(/(ipad).*\s([\d_]+)/i); var iphone = ua.match(/(iphone)\sos\s([\d_]+)/i); var Chrome = ua.match(/Chrome\/(\d+\.\d+)/); var AndriodBrowser = ua.match(/Mozilla.*Linux.*Android.*AppleWebKit.*Mobile Safari/); var android = ua.match(/(android)\s([\d\.]+)/i); var harmony = ua.match(/(OpenHarmony)\s([\d\.]+)/i); Device.browser = Device.browser || {}, Device.os = Device.os || {}; if (window.ActiveXObject) { var vie = 6; (window.XMLHttpRequest || ua.indexOf('MSIE 7.0') > -1) && (vie = 7); (window.XDomainRequest || ua.indexOf('Trident/4.0') > -1) && (vie = 8); ua.indexOf('Trident/5.0') > -1 && (vie = 9); ua.indexOf('Trident/6.0') > -1 && (vie = 10); Device.browser.ie = true, Device.browser.version = vie; } else if (ua.indexOf('Trident/7.0') > -1) { Device.browser.ie = true, Device.browser.version = 11; } if (android) { Device.os.android = true; Device.os.version = android[2]; } if (harmony) { Device.os.harmony = true; Device.os.version = harmony[2]; } if (ipod) { Device.os.ios = Device.os.ipod = true; Device.os.version = ipod[2].replace(/_/g, '.'); } if (ipad) { Device.os.ios = Device.os.ipad = true; Device.os.version = ipad[2].replace(/_/g, '.'); } if (iphone) { Device.os.iphone = Device.os.ios = true; Device.os.version = iphone[2].replace(/_/g, '.'); } if (WinOS) Device.os.windows = true, Device.os.version = WinOS[2]; if (MacOS) Device.os.Mac = true, Device.os.version = MacOS[1]; if (Linux) Device.os.Linux = true; if (ua.indexOf('lepad_hls') > 0) Device.os.LePad = true; if (MIPAD) Device.os.MIPAD = true; if (MQQBrowser) Device.browser.MQQ = true, Device.browser.version = MQQBrowser[1]; if (MQQClient) Device.browser.MQQClient = true, Device.browser.version = MQQClient[1]; if (WeChat) Device.browser.WeChat = true, Device.browser.mmversion = Device.browser.version = WeChat[1]; if (MiuiBrowser) Device.browser.MIUI = true, Device.browser.version = MiuiBrowser[1]; if (UC) Device.browser.UC = true, Device.browser.version = UC[1] || NaN; if (IEMobile) Device.browser.IEMobile = true, Device.browser.version = IEMobile[2]; if (AndriodBrowser) { Device.browser.AndriodBrowser = true; } if (M1) { Device.browser.M1 = true; } if (Chrome) { Device.browser.Chrome = true, Device.browser.version = Chrome[1]; } if (Device.os.windows) { if (typeof navigator.platform !== "undefined" && navigator.platform.toLowerCase() == "win64") { Device.os.win64 = true; } else { Device.os.win64 = false; } } if (Device.os.Mac || Device.os.windows || Device.os.Linux) { Device.os.pc = true; } var osType = { iPad7: 'iPad; CPU OS 7', LePad: 'lepad_hls', XiaoMi: 'MI-ONE', SonyDTV: "SonyDTV", SamSung: 'SAMSUNG', HTC: 'HTC', VIVO: 'vivo' }; for (var os in osType) { Device.os[os] = ua.indexOf(osType[os]) !== -1; } Device.os.phone = Device.os.phone || /windows phone/i.test(ua); Device.os.getNumVersion = function () { return parseFloat(Device.os.version); }; Device.os.hasTouch = 'ontouchstart' in window; if (Device.os.hasTouch && Device.os.ios && Device.os.getNumVersion() < 6) { Device.os.hasTouch = false; } if (Device.browser.WeChat && Device.browser.version < 5.0) { Device.os.hasTouch = false; } Device.browser.getNumVersion = function () { return parseFloat(Device.browser.version); }; Device.browser.isFFCanOcx = function () { return !!Device.browser.firefox && Device.browser.getNumVersion() >= 3.0; }; Device.browser.isCanOcx = function () { return !!Device.os.windows && (!!Device.browser.ie || Device.browser.isFFCanOcx() || !!Device.browser.webkit); }; Device.browser.isNotIESupport = function () { return !!Device.os.windows && (!!Device.browser.webkit || Device.browser.isFFCanOcx()); }; Device.userAgent = {}; Device.userAgent.browserVersion = Device.browser.version; Device.userAgent.osVersion = Device.os.version; Device.os.unifiedPC = ua.match(/UnifiedPC/); delete Device.userAgent.version; } detect(window.navigator.userAgent); function canSupportH5Video() { var ua = window.navigator.userAgent, m = null; if (!!Device.os.android) { if (Device.browser.MQQ && Device.browser.getNumVersion() >= 4.2) { return true; } if (ua.indexOf('MI2') != -1) { return true; } if (Device.os.version >= '4' && (m = ua.match(/MicroMessenger\/((\d+)\.(\d+))\.(\d+)/))) { if (parseFloat(m[1]) >= 4.2) { return true; } } if (Device.os.version >= '4.1') { return true; } } return false; } function canSupportVideoMp4() { var video = document.createElement('video'); if (typeof video.canPlayType === 'function') { if (video.canPlayType('video/mp4; codecs="mp4v.20.8"') === 'probably') { return true; } if (video.canPlayType('video/mp4; codecs="avc1.42E01E"') === 'probably' || video.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"') === 'probably') { return true; } } return false; } function canSupportAutoPlay() { if (Device.os.ios && Device.os.getNumVersion() < 10) { return false; } return true; } function isLockdownMode() { if (!Device.os.ios || Device.os.getNumVersion() < 16) { return false; } if (typeof WebAssembly === 'undefined' && typeof OfflineAudioContext === 'undefined' && typeof WebGLRenderingContext === 'undefined') { return true; } return false; } Device.canSupportVideo = canSupportVideoMp4 || canSupportH5Video; Device.canSupportVideoMp4 = canSupportVideoMp4; Device.canSupportH5Video = canSupportH5Video; Device.canSupportAutoPlay = canSupportAutoPlay; Device.isLockdownMode = isLockdownMode; Device.cpVersion = function (version) { var cp = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; var canEqual = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; var nowVersionStr = Device.os.version; if (!nowVersionStr) return false; var versionArr = version.split('.'); var nowVersionArr = nowVersionStr.split('.'); for (var i = 0; i < Math.max(nowVersionArr.length, versionArr.length); i++) { var vi = +versionArr[i]; var nvi = +nowVersionArr[i]; if (vi === nvi) continue; if (cp > 0) return vi > nvi; if (cp < 0) return vi < nvi; } return canEqual || cp === 0; }; function parseUrl(url) { var len = url.length; var ques_pos = url.indexOf('?'); var hash_pos = url.indexOf('#'); hash_pos = hash_pos == -1 ? len : hash_pos; ques_pos = ques_pos == -1 ? hash_pos : ques_pos; var host = url.substring(0, ques_pos); var query_str = url.substring(ques_pos + 1, hash_pos); var hash = url.substring(hash_pos + 1); return { host: host, query_str: query_str, hash: hash }; } function join(url, args, noEncode) { var ret = parseUrl(url); var query_str = ret.query_str; var args_arr = []; if (_typeof(args) === 'object') { for (var key in args) { if (args.hasOwnProperty(key)) { args_arr.push("".concat(key, "=").concat(noEncode ? args[key] : encodeURIComponent(args[key]))); } } } else { args_arr.push(noEncode ? args : encodeURIComponent(args)); } if (args_arr.length > 0) { query_str += (query_str !== "" ? "&" : "") + args_arr.join("&"); } return ret.host + (query_str !== "" ? "?".concat(query_str) : "") + (ret.hash !== "" ? "#".concat(ret.hash) : ""); } function addParam(url, param, value, forceReplace) { url = url || location.href; var firstAndPos = url.indexOf("&"); var len = url.length; var reverseUrl = url.replace(/^[\w\d]+:[/\\]+/g, "").split("").reverse(); if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (searchElement, fromIndex) { var k; if (this == null) { throw new TypeError('"this" is null or not defined'); } var O = Object(this); var len = O.length >>> 0; if (len === 0) { return -1; } var n = fromIndex || 0; if (Math.abs(n) === Infinity) { n = 0; } if (n >= len) { return -1; } k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); while (k < len) { if (k in O && O[k] === searchElement) { return k; } k++; } return -1; }; } var lastSlashPos = len - 1 - reverseUrl.indexOf("/"); if (firstAndPos !== -1 && url.indexOf("?") == -1 && firstAndPos > lastSlashPos) { url = url.replace("&", "?"); } var reg = new RegExp("([\\?&]".concat(param, "=)[^&#]*")); if (!url.match(reg)) { var urlInfo = parseUrl(url); var hash = urlInfo.hash ? '#' + urlInfo.hash : ''; url = url.replace(hash, ''); var _pos = url.indexOf("?"); if (_pos == -1) { return "".concat(url, "?").concat(param, "=").concat(value).concat(hash); } if (_pos == url.length - 1) { return "".concat(url + param, "=").concat(value).concat(hash); } return "".concat(url, "&").concat(param, "=").concat(value).concat(hash); } if (forceReplace === true) { return url.replace(reg, "$1".concat(value)); } return url; } function addWxfrom(src, wxfrom) { var offset = window.service_type === 1 ? 10000 : 0; return addParam(src, 'wxfrom', offset + Number(wxfrom), true); } function removeParam(url, param) { var _URL = new URL(url), protocol = _URL.protocol, host = _URL.host, pathname = _URL.pathname, search = _URL.search, hash = _URL.hash; var queryParams = new URLSearchParams(search); queryParams["delete"](param); var newSearch = queryParams.toString(); var newUrl = new URL("".concat(protocol, "//").concat(host).concat(pathname).concat(newSearch ? "?".concat(decodeURIComponent(newSearch)) : "").concat(hash)); return newUrl.toString(); } function getQuery(name, url) { var u = url || window.location.search; var reg = new RegExp("(^|&)".concat(name, "=([^&]*)(&|$)")); var r = u.substring(u.indexOf('?') + 1).match(reg); return r !== null ? r[2] : ''; } function encodeBase64(value) { try { return window.btoa(value); } catch (e) { return ''; } } function decodeBase64(value) { try { return window.atob(value); } catch (e) { return ''; } } function joinUrl$1(url) { var obj = {}; if (typeof window.uin !== 'undefined') { obj.uin = window.uin; } if (typeof window.key !== 'undefined') { obj.key = window.key; } if (typeof window.pass_ticket !== 'undefined') { obj.pass_ticket = window.pass_ticket; } if (typeof window.wxtoken !== 'undefined') { obj.wxtoken = window.wxtoken; } if (typeof window.devicetype !== 'undefined') { obj.devicetype = window.devicetype; } if (typeof window.clientversion !== 'undefined') { obj.clientversion = window.clientversion || mmVersion.getInner(); } obj.version = obj.clientversion; if (window.biz) { obj.__biz = window.biz; } if (getQuery('enterid')) { obj.enterid = getQuery('enterid'); } if (typeof window.appmsg_token !== 'undefined') { obj.appmsg_token = window.appmsg_token; } else if (url.indexOf('advertisement_report') > -1) { new Image().src = "".concat(location.protocol, "//mp.weixin.qq.com/mp/jsmonitor?idkey=68064_13_1&r=").concat(Math.random()); } obj.x5 = navigator.userAgent.indexOf('TBS/') !== -1 ? '1' : '0'; obj.f = 'json'; return join(url, obj); } function getA8keyQuery(name, url) { return new Promise(function (resolve) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { resolve(getQuery(name, url)); }); } else { resolve(getQuery(name, url)); } }); } var Url = { parseUrl: parseUrl, join: join, addParam: addParam, addWxfrom: addWxfrom, getQuery: getQuery, getA8keyQuery: getA8keyQuery, encodeBase64: encodeBase64, decodeBase64: decodeBase64, joinUrl: joinUrl$1, removeParam: removeParam }; function _log(level, msg) { if (level === 'log') { level = 'info'; msg = "[WechatFe]".concat(msg); } else { var prefix = "__wap__".concat(window.__second_open__ ? ' (sec)' : ''); msg = "".concat(prefix, " ").concat(msg, " location:[").concat(location.href, "]"); } msg += new Error().stack; if (mmVersion.isMpapp) { invoke$1('WNNativeCallbackLog', msg); } else if (mmVersion.isWechat) { if (mmVersion.isAndroid) { console.warn('[system]', "[MicroMsg.JsApiLog][".concat(level, "] jslog : ").concat(msg)); } else if (mmVersion.isIOS) { JSAPI.invoke('writeLog', { level: level, msg: msg }); } else { JSAPI.invoke('log', { level: level, msg: msg }); } } } var Log = { info: function info() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _log('info', args.join(' ')); }, warn: function warn() { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } _log('warn', args.join(' ')); }, error: function error() { for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { args[_key3] = arguments[_key3]; } _log('error', args.join(' ')); }, debug: function debug() { for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { args[_key4] = arguments[_key4]; } _log('debug', args.join(' ')); }, log: function log() { for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { args[_key5] = arguments[_key5]; } _log('info', args.join(' ')); } }; var html = function html(_str, encode) { if (!_str) return ''; var replace = ['`', '`', ''', '\'', '"', '"', ' ', ' ', '>', '>', '<', '<', '¥', '¥', '&', '&', '<', '<', '>', '>']; var replaceReverse = ['&', '&', '¥', '¥', '<', '<', '>', '>', ' ', ' ', '"', '"', '\'', ''', '`', '`']; var str = _str; var target; if (encode) { target = replaceReverse; } else { target = replace; } for (var i = 0; i < target.length; i += 2) { str = str.replace(new RegExp(target[i], 'g'), target[i + 1]); } return str; }; var htmlLite = function htmlLite(_str, encode) { if (!_str) return ''; var replace = ['`', '`', ''', '\'', '"', '"', '>', '>', '<', '<', '&', '&']; var replaceReverse = ['&', '&', '<', '<', '>', '>', '"', '"', '\'', ''', '`', '`']; var str = _str; var target; if (encode) { target = replaceReverse; } else { target = replace; } for (var i = 0; i < target.length; i += 2) { str = str.replace(new RegExp(target[i], 'g'), target[i + 1]); } return str; }; var htmlEncode = function htmlEncode(str) { return html(str, true); }; var htmlDecode = function htmlDecode(str) { return html(str, false); }; var htmlEncodeLite = function htmlEncodeLite(str) { return htmlLite(str, true); }; var htmlDecodeLite = function htmlDecodeLite(str) { return htmlLite(str, false); }; String.prototype.html = function (encode) { return html(this.toString(), encode); }; String.prototype.htmlEncode = function () { return htmlEncode(this.toString()); }; String.prototype.htmlDecode = function () { return htmlDecode(this.toString()); }; String.prototype.htmlLite = function (encode) { return htmlLite(this.toString(), encode); }; String.prototype.htmlEncodeLite = function () { return htmlEncodeLite(this.toString()); }; String.prototype.htmlDecodeLite = function () { return htmlDecodeLite(this.toString()); }; var _a; var METHOD_ENUM = { GET: 0, POST: 1 }; var __moon_report = window.__moon_report || function () {}; var MOON_AJAX_SUCCESS_OFFSET = 3; var MOON_AJAX_NETWORK_OFFSET = 4; var MOON_AJAX_ERROR_OFFSET = 5; var MOON_AJAX_TIMEOUT_OFFSET = 6; var MOON_AJAX_COMPLETE_OFFSET = 7; var LENGTH_LIMIT = 4096; var doc; var isAcrossOrigin = false; try { doc = (_a = window.top) === null || _a === void 0 ? void 0 : _a.window.document; } catch (e) { isAcrossOrigin = true; } function networkStartLog(item) { var _a, _b, _c; console.log('[system]', "< [request ".concat(item.requestType, "]"), item.method, item); if ((_a = window.vConsole) === null || _a === void 0 ? void 0 : _a.network) { try { return (_c = (_b = window.vConsole.network).add) === null || _c === void 0 ? void 0 : _c.call(_b, Object.assign({}, item, { startTime: Date.now(), endTime: Date.now(), status: 0, readyState: 2, response: '' })); } catch (err) {} } return Object.assign({}, item, { id: '__system_log__' }); } function networkEndLog(item) { var _a, _b, _c; console.log('[system]', "> [response ".concat(item.requestType, "]"), item.response, item); if (((_a = window.vConsole) === null || _a === void 0 ? void 0 : _a.network) && item.id !== '__system_log__') { try { return (_c = (_b = window.vConsole.network).update) === null || _c === void 0 ? void 0 : _c.call(_b, item.id, Object.assign({}, item, { readyState: 4 })); } catch (err) {} } } function reqType(obj, path) { return obj.url.indexOf(path) > -1 && obj.url.indexOf('action=') === -1 && (!obj.data || !obj.data.action); } function reportRtError(type, id, key, content) { var log = ''; var prefix = type === 'rt' ? 'rtCheckError' : 'Ajax Length Limit'; if (content === null || content === void 0 ? void 0 : content.length) { var loglen = 1000; var len = content.length; var lc = Math.ceil(len / loglen); log = ["&lc=".concat(lc)]; for (var i = 0; i < lc; ++i) { log.push("&log".concat(i, "=") + "[".concat(prefix, "][").concat(i, "]").concat(encodeURIComponent(content.substring(i * loglen, i * loglen + loglen)))); } log = log.join(''); } var data = "idkey=".concat(id, "_").concat(key, "_1").concat(log, "&r=").concat(Math.random()); var xmlobj = new XMLHttpRequest(); xmlobj.open('POST', "".concat(location.protocol, "//").concat(location.host, "/mp/jsmonitor?"), true); xmlobj.setRequestHeader('cache-control', 'no-cache'); xmlobj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); xmlobj.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xmlobj.send(data); if (type === 'ajaxLen') { monitor$1.setLogs({ id: id, key: key, value: 1, log: log }); } } function reportRt(id, key, content) { reportRtError('rt', id, key, content); } function reportAjaxLength(id, key, content) { reportRtError('ajaxLen', id, key, content); } function setCurrentMpInfo(ifShow) { var supportNewTopBar = mmVersion.isIOS && mmVersion.gtVersion('7.0.10', true) || mmVersion.isAndroid && mmVersion.gtVersion('7.0.12', true); var supportLiveStatus = mmVersion.isIOS && mmVersion.gtVersion('8.0.46', true) || mmVersion.isAndroid && mmVersion.gtVersion('8.0.46', true); JSAPI.invoke('currentMpInfo', { userName: window.user_name, brandName: !!supportNewTopBar && window.nickname === '' ? '未命名账号' : window.title, title: window.msg_title || '', brandIcon: window.hd_head_img.replace(/\/0$/, '/132'), itemShowType: window.item_show_type, isPaySubscribe: window.isPaySubscribe, topBarStyle: supportNewTopBar ? 1 : 0, topBarShowed: ifShow, disableShowFinderLiveTopBar: !ifShow && supportLiveStatus ? 1 : 0 }, function () {}); } function findAjaxScopeByConfig(url, config) { var pathname = new URL(url, location.href).pathname || ''; var scope = config[pathname.slice(1)]; if (scope) { Log.log('ajax transfer config: ', JSON.stringify(config)); return scope; } } function getAjaxScope(ajaxUrl) { if (Url.getQuery('no_transfer', location.href) !== '1' && mmVersion.isWechat && !mmVersion.isInMiniProgram && !mmVersion.isWxWork && !mmVersion.isMpapp && !isAcrossOrigin && window.__ajaxTransferConfig && _typeof(window.__ajaxTransferConfig) === 'object' && ( mmVersion.isIOS && mmVersion.getInner() >= '1800282f' || mmVersion.isAndroid && mmVersion.getInner() >= '28002234' || mmVersion.isWindowsWechat && mmVersion.cpVersion('3.9.5', 1, true, 'windows') || mmVersion.isMacWechat && mmVersion.cpVersion('3.8.4', 1, true, 'mac'))) { try { return findAjaxScopeByConfig(ajaxUrl, window.__ajaxTransferConfig); } catch (err) { } } } function setXhrHeader(xhr, type, opt) { if (opt.contentType) { xhr.setRequestHeader('Content-Type', opt.contentType); } else if (type === 'POST') { xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); } if (!opt.noXRequestedWidthHeader) { xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); } } function Ajax(obj) { if (obj.usePb) { obj.type = 'POST'; obj.data = { data: JSON.stringify(obj.data) }; } var ajaxScope = getAjaxScope(obj.url); var type = (obj.type || 'GET').toUpperCase(); var timer; var url; if (obj.notJoinUrl) { url = obj.url; } else { url = Url.joinUrl(obj.url); } if (obj.f === 'html') { url = url.replace('&f=json', ''); } var data = null; if (_typeof(obj.data) === 'object') { var d = obj.data; var ds = []; for (var k in d) { if (d.hasOwnProperty(k)) { ds.push("".concat(k, "=").concat(encodeURIComponent(d[k]))); } } data = ds.join('&'); } else { data = typeof obj.data === 'string' ? obj.data : null; } var beginTs; var beforeReq = function beforeReq() { if (reqType(obj, '/mp/getappmsgext')) { window.startGetAppmsgExtTime = Date.now(); Log.log('start get appmsgext, url: ', obj.url); } if (reqType(obj, '/mp/getappmsgad')) { window.startGetAppmsgAdTime = Date.now(); Log.log('start get appmsgad, url: ', obj.url); } beginTs = Date.now(); }; var beforeResp = function beforeResp(xhr) { if (reqType(obj, '/mp/getappmsgext')) { window.receiveGetAppmsgExt = "".concat(xhr.status, "|").concat(Date.now()); Log.log("receive appmsgext response, status: ".concat(xhr.status)); } if (reqType(obj, '/mp/getappmsgad')) { window.receiveGetAppmsgAd = "".concat(xhr.status, "|").concat(Date.now()); Log.log("receive appmsgad response, status: ".concat(xhr.status)); } if (Math.random() < 0.01 && window.WX_BJ_REPORT && window.WX_BJ_REPORT.BadJs) { try { var key = ajaxScope ? 'transfer' : 'xhr'; var interval = 250; var time = Date.now() - beginTs; var range = Math.floor(time / interval) * interval; var pathname = new URL(obj.url, location.href).pathname || ''; window.WX_BJ_REPORT.BadJs.report("".concat(key, "_perf:").concat(pathname), JSON.stringify({ status: xhr.status, time: "[".concat(range, "-").concat(range + interval, ")") }), { mid: 'mmbizwap:ajaxtransfer', view: 'wap_business' }); } catch (err) {} } }; var handleRespSucc = function handleRespSucc(xhr) { var _a; try { var responseText = xhr.responseText; var resp = responseText; if (obj.dataType === 'json') { try { if (JSON && JSON.parse) { resp = JSON.parse(resp); } else { resp = eval("(".concat(resp, ")")); monitor$1.setSum(523105, 127, 1).send(); } var rtId = obj.rtId; var rtKey = obj.rtKey || 0; var rtDesc = obj.rtDesc; if (rtId && rtDesc && RespTypes && !RespTypes.check(resp, rtDesc)) { reportRt(+rtId, +rtKey, "".concat(RespTypes.getMsg(), "[detail]").concat(responseText, ";").concat(obj.url)); } if (resp && resp.base_resp && ((_a = resp.base_resp) === null || _a === void 0 ? void 0 : _a.ret) !== 0 && typeof window.WX_BJ_REPORT !== 'undefined' && window.WX_BJ_REPORT.BadJs && Math.random() < 0.001) { var reportUrl = url; if (url.indexOf('?') !== -1) { reportUrl = url.substring(0, url.indexOf('?')); if (Url.getQuery('action', url)) { reportUrl = "".concat(reportUrl, "?action=").concat(Url.getQuery('action', url)); } } if (!((reportUrl === '/mp/getappmsgext' || reportUrl === '/mp/getappmsgad') && typeof resp.base_resp.ret === 'undefined')) { window.WX_BJ_REPORT.BadJs.report(reportUrl, "ret=".concat(resp.base_resp.ret), { mid: window.PAGE_MID, view: 'wap_retcode' }); } } } catch (e) { obj.error && obj.error(xhr, { type: 1, error: e, status: xhr.status }); return; } } obj.success && obj.success(resp); } catch (e) { __moon_report({ offset: MOON_AJAX_SUCCESS_OFFSET, e: e }); throw e; } }; var handleRespErr = function handleRespErr(xhr, error) { try { obj.error && obj.error(xhr, { type: 2, error: error, status: xhr.status }); } catch (e) { __moon_report({ offset: MOON_AJAX_ERROR_OFFSET, e: e }); throw e; } }; var handleRespComplete = function handleRespComplete() { clearTimeout(timer); try { obj.complete && obj.complete(); } catch (e) { __moon_report({ offset: MOON_AJAX_COMPLETE_OFFSET, e: e }); throw e; } obj.complete = null; }; var handleReqTimeout = function handleReqTimeout(xhr) { if (typeof obj.timeout !== 'undefined') { timer = setTimeout(function () { xhr.abort(); try { obj.complete && obj.complete(); } catch (e) { __moon_report({ offset: MOON_AJAX_COMPLETE_OFFSET, e: e }); throw e; } obj.complete = null; __moon_report({ offset: MOON_AJAX_TIMEOUT_OFFSET, log: "ajax_timeout_error: ".concat(url), e: '' }); }, obj.timeout); } }; var retryXhrFn = function retryXhrFn(res, isTimeout, reqLogItem) { var retryXhr = new XMLHttpRequest(); try { retryXhr._noVConsole = true; } catch (err) {} retryXhr.open(type, url); retryXhr.onreadystatechange = function () { if (isTimeout) return; if (retryXhr.readyState === 3) { obj.received && obj.received(retryXhr); } if (retryXhr.readyState === 4) { beforeResp(retryXhr); var retryStatus = retryXhr.status; if (retryStatus >= 200 && retryStatus < 400) { handleRespSucc(retryXhr); } else { handleRespErr(retryXhr, res); window.WX_BJ_REPORT && window.WX_BJ_REPORT.BadJs && window.WX_BJ_REPORT.BadJs.report('req_failure', JSON.stringify({ retryXhrStatus: retryStatus, transferRes: res }), { mid: 'mmbizwap:ajaxtransfer', view: 'wap_business' }); } reqLogItem.status = retryStatus; reqLogItem.endTime = Date.now(); reqLogItem.response = retryXhr.responseText; handleRespComplete(); networkEndLog(reqLogItem); } }; setXhrHeader(retryXhr, type, obj); retryXhr.send(data); }; if (ajaxScope) { var header = { 'User-Agent': navigator.userAgent, 'Cookie': (window.__test_env__ ? 'uniproxy_route=1; ' : '') + document.cookie, 'Referer': location.href }; if (obj.contentType) { header['Content-Type'] = obj.contentType; } else if (type === 'POST') { header['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; } if (!obj.noXRequestedWidthHeader) { header['X-Requested-With'] = 'XMLHttpRequest'; } var reqUrl = new URL(url, location.href).href; var method = METHOD_ENUM[type] || 0; var params = Device.os.pc ? { url: reqUrl, req_json: data || '', scope: ajaxScope, webcgi_method: method, webcgi_header: Object.keys(header).map(function (headerItemKey) { return Device.os.Mac ? _defineProperty({}, headerItemKey, header[headerItemKey]) : { key: headerItemKey, value: header[headerItemKey] }; }), cgi_type: 1 } : { reqUrl: reqUrl, reqBody: data, scope: ajaxScope, method: method, header: header }; var reqLogItem = networkStartLog({ method: type, url: url, postData: obj.data || {}, requestHeader: header, requestType: 'transfer' }); var isTimeout = false; handleReqTimeout({ abort: function abort() { isTimeout = true; reqLogItem.endTime = Date.now(); reqLogItem.response = 'timeout'; networkEndLog(reqLogItem); } }); Device.os.pc && monitor$1.setSum(115849, 69, 1); JSAPI.invoke(Device.os.pc ? 'H5ExtTransfer' : 'webTransfer', params, function (res) { var _a, _b, _c, _d, _e, _f; if (isTimeout) return; var status = 400; var result = ''; if (Device.os.pc) { try { var retFlag = res.base_resp.ret === 0 && res.jsapi_resp.ret === 0 && res.err_msg.indexOf(':ok') > -1; var respJsonFlag = res.jsapi_resp.resp_json; status = retFlag && respJsonFlag ? 200 : 400; result = res.jsapi_resp.resp_json; } catch (err) { console.error(err); } } else { status = res && res.errCode * 1 === 0 && typeof res.result === 'string' && res.result ? 200 : 400; result = res.result; } if (status >= 200 && status < 400) { obj.received && obj.received(null); beforeResp({ status: status }); handleRespSucc({ status: status, responseText: result }); reqLogItem.status = status; reqLogItem.endTime = Date.now(); reqLogItem.response = result; handleRespComplete(); networkEndLog(reqLogItem); } else if (window.__second_open__) { JSAPI.invoke('request', { url: reqUrl, method: type, data: data, header: header }, function (retryRes) { if (isTimeout) return; var retryStatus = retryRes.statusCode; obj.received && obj.received(null); beforeResp({ status: retryStatus }); if (retryRes.err_msg.indexOf(':ok') > -1 && retryStatus >= 200 && retryStatus < 400) { handleRespSucc({ status: retryStatus, responseText: retryRes.data }); } else { retryXhrFn(res, isTimeout, reqLogItem); handleRespErr({ status: retryStatus }, res); window.WX_BJ_REPORT && window.WX_BJ_REPORT.BadJs && window.WX_BJ_REPORT.BadJs.report('req_failure_sec_open', JSON.stringify({ retryReqJsapiRes: retryRes, transferRes: res, url: reqUrl }), { mid: 'mmbizwap:ajaxtransfer', view: 'wap_business' }); } reqLogItem.status = retryStatus; reqLogItem.endTime = Date.now(); reqLogItem.response = retryRes.data; handleRespComplete(); networkEndLog(reqLogItem); }); } else { retryXhrFn(res, isTimeout, reqLogItem); } if (Device.os.pc) { if (!res.err_msg.includes(':ok')) { (_b = (_a = window.WX_BJ_REPORT) === null || _a === void 0 ? void 0 : _a.BadJs) === null || _b === void 0 ? void 0 : _b.report("pc transfer res no ok: ".concat(res.err_msg), params.url || '', { mid: window.PAGE_MID, _info: "".concat(JSON.stringify(params), " || ").concat(JSON.stringify(res)) }); } try { if (res.jsapi_resp.resp_json && JSON.parse(res.jsapi_resp.resp_json).base_resp.ret !== 0 && JSON.parse(res.jsapi_resp.resp_json).base_resp.ret !== 190001 || res.base_resp.ret !== 0 || res.jsapi_resp.ret !== 0) { (_d = (_c = window.WX_BJ_REPORT) === null || _c === void 0 ? void 0 : _c.BadJs) === null || _d === void 0 ? void 0 : _d.report("pc transfer res invalid ret", params.url || '', { mid: window.PAGE_MID, _info: "".concat(JSON.stringify(params), " || ").concat(JSON.stringify(res)) }); } } catch (err) {} } else { try { if (res.errCode !== 0) { (_f = (_e = window.WX_BJ_REPORT) === null || _e === void 0 ? void 0 : _e.BadJs) === null || _f === void 0 ? void 0 : _f.report("mobile transfer res invalid ret", params.url || '', { mid: window.PAGE_MID, _info: "".concat(JSON.stringify(params), " || ").concat(JSON.stringify(res)) }); } } catch (err) {} } }); beforeReq(); return; } var xhr = new XMLHttpRequest(); var mayAbort = !!obj.mayAbort; var async = typeof obj.async === 'undefined' ? true : obj.async; var _onreadystatechange = xhr.onreadystatechange; xhr.open(type, url, async); xhr.onreadystatechange = function () { if (typeof _onreadystatechange === 'function') { _onreadystatechange.apply(xhr); } if (xhr.readyState === 3) { obj.received && obj.received(xhr); } if (xhr.readyState === 4) { beforeResp(xhr); xhr.onreadystatechange = null; var status = xhr.status; if (status >= 200 && status < 400) { handleRespSucc(xhr); } else { handleRespErr(xhr, 'status error'); if (!!status || !mayAbort) { var __ajaxtest = window.__ajaxtest || '0'; __moon_report({ offset: MOON_AJAX_NETWORK_OFFSET, log: "ajax_network_error[".concat(status, "][").concat(__ajaxtest, "]: ").concat(url, ";host:").concat(location.host), e: '' }); } } handleRespComplete(); } }; setXhrHeader(xhr, type, obj); handleReqTimeout(xhr); try { xhr.send(data); try { if (url && url.length > LENGTH_LIMIT) { reportAjaxLength(27613, 17, "ajax get limit[length: ".concat(url.length, "]").concat(url.substring(0, 1024))); } if (data && data.length > LENGTH_LIMIT) { reportAjaxLength(27613, 18, "ajax post limit[length: ".concat(data.length, "]").concat(data.substring(0, 1024))); } } catch (e) { } } catch (e) { obj.error && obj.error(xhr, { type: 3, error: e, status: 0 }); } beforeReq(); return xhr; } function AjaxWx(obj) { obj.url += obj.url.indexOf('?') === -1 ? '?fasttmplajax=1' : '&fasttmplajax=1'; if (getAjaxScope(obj.url)) { Ajax(obj); return; } if (obj.usePb) { obj.type = 'POST'; obj.data = { data: JSON.stringify(obj.data) }; } if (!/^(http:\/\/|https:\/\/|\/\/)/.test(obj.url)) { obj.url = "https://mp.weixin.qq.com/".concat(obj.url.replace(/^\//, '')); } else if (/^\/\//.test(obj.url)) { obj.url = "https:".concat(obj.url); } if (obj.f !== 'html' && (obj.url.indexOf('?f=json') === -1 || obj.url.indexOf('&f=json') === -1)) { obj.url += '&f=json'; } if (!obj.notJoinUrl && obj.f !== 'html') { obj.url = Url.joinUrl(obj.url); } var data = null; if (_typeof(obj.data) === 'object') { var d = obj.data; var ds = []; for (var k in d) { if (d.hasOwnProperty(k)) { ds.push("".concat(k, "=").concat(encodeURIComponent(d[k]))); } } data = ds.join('&'); } else { data = typeof obj.data === 'string' ? obj.data : null; } var header = { Cookie: document.cookie, referer: location.href }; var reqLogItem = networkStartLog({ method: obj.type || 'GET', url: obj.url, postData: obj.data || {}, requestHeader: header, requestType: 'jsapi' }); var retryTime = 1; var jsapiRequest = function jsapiRequest(obj, data) { return JSAPI.invoke('request', { url: obj.url, method: obj.type, data: data, header: header }, function (res) { var _a; if (res.err_msg.indexOf(':ok') > -1) { if (reqType(obj, '/mp/getappmsgext')) { window.receiveGetAppmsgExt = "".concat(res.statusCode, "|").concat(Date.now()); } if (reqType(obj, '/mp/getappmsgad')) { window.receiveGetAppmsgAd = "".concat(res.statusCode, "|").concat(Date.now()); } if (retryTime === 1) { obj.received && obj.received(null); } var resData = {}; if (res.data) { try { if (obj.dataType === 'json') { resData = JSON.parse(res.data); } else { resData = res.data; } if (resData && resData.base_resp && ((_a = resData.base_resp) === null || _a === void 0 ? void 0 : _a.ret) !== 0 && typeof window.WX_BJ_REPORT !== 'undefined' && window.WX_BJ_REPORT.BadJs && Math.random() < 0.001) { var reportUrl = obj.url; if (obj.url.indexOf('?') !== -1) { reportUrl = obj.url.substring(0, obj.url.indexOf('?')); if (Url.getQuery('action', obj.url)) { reportUrl = "".concat(reportUrl, "?action=").concat(Url.getQuery('action', obj.url)); } } if (!((reportUrl === '/mp/getappmsgext' || reportUrl === '/mp/getappmsgad') && typeof resData.base_resp.ret === 'undefined')) { window.WX_BJ_REPORT.BadJs.report(reportUrl, "ret=".concat(resData.base_resp.ret), { mid: window.PAGE_MID, view: 'wap_retcode' }); } } } catch (e) { console.error(e); obj.error && obj.error(null, { type: 1, error: e, status: res.statusCode }); obj.complete && obj.complete(); reqLogItem.endTime = Date.now(); reqLogItem.response = res; networkEndLog(reqLogItem); return; } } var tmpResData = {}; try { tmpResData = JSON.parse(res.data); } catch (e) {} if (tmpResData && tmpResData.base_resp && tmpResData.base_resp.ret === -3 && retryTime < 2 && (mmVersion.isIOS || mmVersion.isAndroid && mmVersion.getInner() > '27000600')) { var _retryTime = retryTime++; JSAPI.invoke('updatePageAuth', {}, function (res) { console.log('[skeleton] updatePageAuth', res); monitor$1.setSum(112287, 3, 1); if (res && res.err_msg && res.err_msg.indexOf(':ok') > -1) { window.top.pass_ticket = encodeURIComponent(Url.getQuery('pass_ticket', res.fullUrl).html(false).replace(/\s/g, '+')); if (obj.pass_ticket) { obj.pass_ticket = window.top.pass_ticket; } console.warn('[skeleton] updatePageAuth resetTopbar'); var supportNewTopBar = mmVersion.isIOS && mmVersion.gtVersion('7.0.10', true); var showBottomBar = !!window.is_login; if (window.top.item_show_type === '0' && supportNewTopBar) { var _top = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop || 0; setCurrentMpInfo(_top > 40 && !showBottomBar); } try { obj.url = Url.addParam(obj.url, 'retry', _retryTime, true); } catch (err) { console.error(err); } jsapiRequest(obj, data); monitor$1.setSum(112287, 4, 1); } else { obj.success && obj.success(resData); obj.complete && obj.complete(); if (mmVersion.isIOS) { monitor$1.setSum(112287, 35, 1); } else { monitor$1.setSum(112287, 36, 1); } reqLogItem.status = 200; reqLogItem.endTime = Date.now(); reqLogItem.response = resData; networkEndLog(reqLogItem); } }); } else { obj.success && obj.success(resData); obj.complete && obj.complete(); reqLogItem.status = 200; reqLogItem.endTime = Date.now(); reqLogItem.response = resData; networkEndLog(reqLogItem); } } else if (res.err_msg.indexOf('no permission') > -1 || !mmVersion.isOnlyWechat) { Ajax(obj); if (res.err_msg.indexOf('no permission') > -1) { console.warn('[JSAPI Request] No permission'); monitor$1.setSum(112287, 31, 1); } reqLogItem.status = 302; reqLogItem.endTime = Date.now(); reqLogItem.response = res; networkEndLog(reqLogItem); } else { obj.error && obj.error(null, { type: 3, error: res, status: 0 }); obj.complete && obj.complete(); monitor$1.setSum(112287, 32, 1); var sample = 0.001; if (Math.random() < sample) { var msg = "request: ".concat(JSON.stringify(obj.type), " ").concat(JSON.stringify(obj.url), " ;;;; cookie: ").concat(JSON.stringify(document.cookie), " ;;;; data: ").concat(JSON.stringify(data), " ;;;; resp: ").concat(JSON.stringify(res)); if (window.WX_BJ_REPORT && window.WX_BJ_REPORT.BadJs) { window.WX_BJ_REPORT.BadJs.report('ajax_wx_request_error', msg, { mid: 'mmbizwap:Monitor' }); } } reqLogItem.status = 400; reqLogItem.endTime = Date.now(); reqLogItem.response = res; networkEndLog(reqLogItem); } }); }; if (reqType(obj, '/mp/getappmsgext')) { window.startGetAppmsgExtTime = Date.now(); } if (reqType(obj, '/mp/getappmsgad')) { window.startGetAppmsgAdTime = Date.now(); } return jsapiRequest(obj, data); } var ajax = function ajax(obj) { if (window.__second_open_wait_a8key__ && window.__second_open_wait_a8key_task__) { window.__second_open_wait_a8key_task__.push(function () { ajax(obj); }); return; } if (!mmVersion.isWxWork && (window.__second_open__ || !isAcrossOrigin && top.window.__second_open__) && window.__is_page_auth_return__) { return AjaxWx(obj); } return Ajax(obj); }; var isx5 = navigator.userAgent.indexOf('TBS/') !== -1; var getDataFunc = []; var reportData = []; var specificData = {}; function joinUrl(url) { var obj = {}; if (typeof window.uin !== 'undefined') { obj.uin = window.uin; } if (typeof window.key !== 'undefined') { obj.key = window.key; } if (typeof window.pass_ticket !== 'undefined') { obj.pass_ticket = window.pass_ticket; } if (typeof window.wxtoken !== 'undefined') { obj.wxtoken = window.wxtoken; } if (typeof window.devicetype !== 'undefined') { obj.devicetype = window.devicetype; } if (typeof window.clientversion !== 'undefined') { obj.clientversion = window.clientversion; } if (typeof window.appmsg_token !== 'undefined') { obj.appmsg_token = window.appmsg_token; } else if (url.indexOf('advertisement_report') > -1) { new Image().src = "".concat(location.protocol, "//mp.weixin.qq.com/mp/jsmonitor?idkey=68064_13_1&r=").concat(Math.random()); } obj.x5 = isx5 ? '1' : '0'; obj.f = 'json'; return Url.join(url, obj); } function isObj(obj) { return obj && _typeof(obj) === 'object'; } function assign(target, source) { if (isObj(target) && isObj(source)) { for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } } function assembleReportData(initiative) { var leaveReportLog = []; leaveReportLog.push({ content: "[LeaveReport] specificData keys: ".concat(Object.keys(specificData)), timestamp: Date.now() }); Log.log("[LeaveReport] specificData keys: ".concat(Object.keys(specificData))); console.log("[LeaveReport] specificData keys: ".concat(Object.keys(specificData))); var allReportData = {}; for (var reportField in specificData) { if (!allReportData[reportField]) { allReportData[reportField] = {}; } for (var i = 0; i < specificData[reportField].length; i++) { var param = specificData[reportField][i]; if (typeof param === 'function') { try { assign(allReportData[reportField], param(initiative)); } catch (err) { leaveReportLog.push({ content: "[LeaveReport] specificData exec error: ".concat(param.toString().substring(0, 50)), timestamp: Date.now() }); Log.error("[LeaveReport] specificData exec error: ".concat(param.toString().substring(0, 50))); console.error("[LeaveReport] specificData exec error: ".concat(param.toString().substring(0, 50))); } } else if (isObj(param)) { assign(allReportData[reportField], param); } } } leaveReportLog.push({ content: "[LeaveReport] reportData.length: ".concat(reportData.length), timestamp: Date.now() }); Log.log("[LeaveReport] reportData.length: ".concat(reportData.length)); console.log("[LeaveReport] reportData.length: ".concat(reportData.length)); leaveReportLog.push({ content: "[LeaveReport] getDataFunc.length: ".concat(getDataFunc.length), timestamp: Date.now() }); Log.log("[LeaveReport] getDataFunc.length: ".concat(getDataFunc.length)); console.log("[LeaveReport] getDataFunc.length: ".concat(getDataFunc.length)); for (var _i = 0; _i < getDataFunc.length; _i++) { try { var data = getDataFunc[_i](initiative); if (isObj(data)) { reportData.push(data); } } catch (err) { leaveReportLog.push({ content: "[LeaveReport] getDataFunc exec error: ".concat(getDataFunc[_i].toString().substring(0, 50)), timestamp: Date.now() }); Log.error("[LeaveReport] getDataFunc exec error: ".concat(getDataFunc[_i].toString().substring(0, 50))); console.error("[LeaveReport] getDataFunc exec error: ".concat(getDataFunc[_i].toString().substring(0, 50))); } } for (var _i2 = 0; _i2 < reportData.length; _i2++) { if (reportData[_i2].reportUrl) { reportData[_i2].reportUrl = joinUrl(reportData[_i2].reportUrl); } } allReportData.data = { 'requestList': reportData }; leaveReportLog.push({ content: "[LeaveReport] final reportData.length: ".concat(reportData.length, ", data=").concat(JSON.stringify(reportData)), timestamp: Date.now() }); Log.log("[LeaveReport] final reportData.length: ".concat(reportData.length)); console.log("[LeaveReport] final reportData.length: ".concat(reportData.length)); allReportData.info = leaveReportLog; return allReportData; } function addReport(param) { if (typeof param === 'function') { getDataFunc.push(param); } else if (isObj(param)) { reportData.push(param); } } function addSpecificReport(reportField, param) { if (!specificData[reportField]) { specificData[reportField] = []; } specificData[reportField].push(param); } function reportNow(callback) { var allReportData = assembleReportData(true); JSAPI.invoke('handleMPPageAction', { action: 'reportByLeaveForMPGateway', reportData: allReportData }, function (res) { if (res && res.err_msg && res.err_msg.indexOf(':ok') !== -1) { getDataFunc = []; reportData = []; specificData = {}; typeof callback === 'function' && callback(res); } else { getDataFunc = []; reportData = []; var len = allReportData.data.requestList.length; allReportData.data.requestList.forEach(function (req) { if (req.reportUrl) { ajax({ type: req.method || 'GET', url: req.reportUrl, data: req.reportData, async: false, success: function success(resp) { if (--len < 0) { typeof callback === 'function' && callback({ err_msg: 'handleMPPageAction:ok', fallback: true, resp: resp }); } }, error: function error(xhr, err) { if (--len < 0) { typeof callback === 'function' && callback({ err_msg: 'handleMPPageAction:fail', fallback: true, err: err }); } } }); } }); } }); } var leaveReport = { reportNow: reportNow, addReport: addReport, addSpecificReport: addSpecificReport }; var _leaveReport = (function () { var doc = {}; var isCrossOrigin = false; try { doc = top.window.document; } catch (e) { isCrossOrigin = true; } if (!isCrossOrigin && top.window.__leaveReport) { return top.window.__leaveReport; } if (window.__leaveReport) { return window.__leaveReport; } JSAPI.on('reportOnLeaveForMP', function () { return assembleReportData(false); }); return window.__leaveReport = leaveReport; })(); var getReportJson = function getReportJson(logId, rawData) { var data = JSON.parse(JSON.stringify(rawData)); data.log_id = Number(logId); data.TimeStamp = Math.round(Date.now() / 1000); console.log('[comm_report] reportjson: ', data); return JSON.stringify(data); }; var getSuccessHandler = function getSuccessHandler(logId, data, opt) { return function (res) { if (res && res.err_code !== 0) { console.warn("[comm_report] report ".concat(logId, " fail: "), res.err_msg, data); } if (typeof opt.success === 'function') { opt.success(res); } }; }; var getErrorHandler = function getErrorHandler(logId, data, opt) { return function (xhr, info) { console.error("[comm_report] report ".concat(logId, " error: "), info, data); if (typeof opt.error === 'function') { opt.error(xhr, info); } }; }; var batchReportDataArr = []; var blackLogId = [25587, 18832, 28208, 25574, 29139, 10945]; var BATCH_SIZE = 4; var BATCH_TIME = 1000; var getRepeatedReportJson = function getRepeatedReportJson() { if (!batchReportDataArr || !batchReportDataArr.length) return false; var reportData = { count: 0 }; reportData.count = batchReportDataArr.length; batchReportDataArr.forEach(function (data, index) { reportData["reportjson".concat(index)] = data; }); batchReportDataArr = []; console.log('[reportData]: ', reportData); return reportData; }; var timeOutId; function batchReport() { if (!batchReportDataArr || !batchReportDataArr.length) return; var repeatedReportJson = getRepeatedReportJson(); if (!repeatedReportJson) return; ajax({ type: 'POST', dataType: 'json', url: '/mp/wapcommreport?action=batch_report', data: repeatedReportJson, success: function success(res) { if (res && res.err_code) { console.warn("[comm_report] batch report fail: ", res.err_msg, batchReportDataArr); } }, error: function error(xhr, info) { console.error("[comm_report] batch report error: ", info, batchReportDataArr); } }); } function batchReportThrottle(logId, rawData) { var reportJsonData = getReportJson(logId, rawData); if (!reportJsonData) return; batchReportDataArr.push(reportJsonData); if (batchReportDataArr.length >= BATCH_SIZE) { batchReport(); } else { if (!timeOutId) { timeOutId = setTimeout(function () { batchReport(); clearTimeout(timeOutId); timeOutId = null; }, BATCH_TIME); } } } _leaveReport.addReport(function () { var repeatedReportJson = getRepeatedReportJson(); if (!repeatedReportJson) return false; var reportData = []; for (var _i = 0, _Object$entries = Object.entries(repeatedReportJson); _i < _Object$entries.length; _i++) { var _Object_i = _slicedToArray(_Object$entries[_i], 2), key = _Object_i[0], value = _Object_i[1]; reportData.push("".concat(key, "=").concat(encodeURIComponent(value))); } return { reportUrl: 'https://mp.weixin.qq.com/mp/wapcommreport?action=batch_report', reportData: reportData.join('&'), method: 'POST' }; }); var commReport = { report: function report(logId, rawData, rawOpt) { var opt = rawOpt || {}; if (!opt.realTime && !blackLogId.includes(logId)) { batchReportThrottle(logId, rawData); } else { ajax({ type: 'POST', dataType: 'json', url: '/mp/wapcommreport', data: { reportjson: getReportJson(logId, rawData) }, async: opt.async, success: getSuccessHandler(logId, rawData, opt), error: getErrorHandler(logId, rawData, opt) }); } }, leaveReport: function leaveReport(logId, rawData) { _leaveReport.addReport(function () { var data = typeof rawData === 'function' ? rawData() : rawData; if (!data) { return false; } return { reportUrl: 'https://mp.weixin.qq.com/mp/wapcommreport', reportData: "reportjson=".concat(encodeURIComponent(getReportJson(logId, data))), method: 'POST' }; }); }, reportByBeacon: function reportByBeacon(logId, rawData) { try { if (!Device.os.android && !Device.os.ios) { var data = typeof rawData === 'function' ? rawData() : rawData; if (!data) { return false; } var url = '/mp/wapcommreport'; var reportJsonData = encodeURIComponent(getReportJson(logId, data)); console.log("reportByBeacon", JSON.stringify(reportJsonData)); navigator.sendBeacon(Url.joinUrl(url), "reportjson=".concat(reportJsonData)); } else { _leaveReport.addReport(function () { var data = typeof rawData === 'function' ? rawData() : rawData; if (!data) { return false; } return { reportUrl: 'https://mp.weixin.qq.com/mp/wapcommreport', reportData: "reportjson=".concat(encodeURIComponent(getReportJson(logId, data))), method: 'POST' }; }); } } catch (error) { console.log(error); } } }; var isIOS = mmVersion.isIOS, getInner = mmVersion.getInner, isAndroid = mmVersion.isAndroid; var renderDom = function renderDom(dom, cnt, hasStar) { if (dom) { if (hasStar) { dom.innerText = "已星标"; } else { dom.innerText = "星标"; } if (hasStar) { dom.classList.add('rich_media_meta_star'); dom.classList.remove('rich_media_meta_star_cancel'); } else { dom.classList.add('rich_media_meta_star_cancel'); dom.classList.remove('rich_media_meta_star'); } dom.style.removeProperty('display'); var feedBack = document.querySelector('#js_problem_feedback'); feedBack && feedBack.parentNode.removeChild(feedBack); } }; var __setStar = function __setStar(dom, cnt, statStatus) { var hasReportExpose = false; var hasStar = statStatus; var realCnt = cnt; function addStar() { var dispatchEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; localStorage.setItem('star_info', JSON.stringify({ mid: window.mid, has_star: true })); hasStar = 1; realCnt = realCnt + 1; console.log('realCnt' + realCnt); renderDom(dom, realCnt, hasStar); if (dispatchEvent) window.dispatchEvent(new CustomEvent('star')); } function cancelStar() { var dispatchEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; console.log('cancelStar'); localStorage.setItem('star_info', JSON.stringify({ mid: window.mid, has_star: false })); hasStar = 0; realCnt = realCnt - 1; console.log('realCnt' + realCnt); renderDom(dom, realCnt, hasStar); if (dispatchEvent) window.dispatchEvent(new CustomEvent('cancel-star')); } if (dom) { renderDom(dom, cnt, statStatus); var clickHander = function clickHander() { if (hasStar === 0) { JSAPI.invoke('operateStar', { opType: 'addStar' }, function (res) { if (res.err_msg && /:ok$/.test(res.err_msg)) addStar(); }); } else { JSAPI.invoke('operateStar', { opType: 'cancelStar' }, function (res) { if (res.err_msg && /:ok$/.test(res.err_msg)) cancelStar(); }); } var data = { BizUin: window.biz, AppMsgID: window.mid * 1, ItemIndex: window.idx * 1, Scene: window.scene, SubScene: window.subscene * 1, EnterId: window.enterid, SessionId: "".concat(window.sessionid), Event: hasStar ? 8 : 7, ItemShowType: window.item_show_type * 1 }; commReport.report(17335, data); }; var exposeHandler = function exposeHandler() { if (hasReportExpose) return; var data = { BizUin: window.biz, AppMsgID: window.mid * 1, ItemIndex: window.idx * 1, Scene: window.scene, SubScene: window.subscene * 1, EnterId: window.enterid, SessionId: "".concat(window.sessionid), Event: 6, ItemShowType: window.item_show_type * 1 }; commReport.report(17335, data); hasReportExpose = true; }; dom.addEventListener('click', clickHander); JSAPI.on('onPageStarStateChanged', function (res) { console.log('onPageStarStateChanged', res); if (res.state) addStar();else cancelStar(); }); var intersectionObserver = new IntersectionObserver(exposeHandler); intersectionObserver.observe(dom); window.addEventListener('star', function (e) { if (e && e.detail && e.detail.from === 'frontend') addStar(false); }); window.addEventListener('cancel-star', function (e) { if (e && e.detail && e.detail.from === 'frontend') cancelStar(false); }); } }; if (!window.__second_open__) { var starDom = document.querySelector('#js_star'); var canUseStar = window.canUseStar || isIOS && getInner() >= '18003623' || isAndroid && getInner() >= '28003630'; var startPersonCnt = window.star_person_cnt || ''; console.log('canUseStar, startPersonCnt', canUseStar, startPersonCnt); if (!!(canUseStar * 1)) { var starSwitch = localStorage.getItem('mp_star_switch'); if (starSwitch === 'true') { var starInfo = localStorage.getItem('star_info'); var hasStar = 0; if (starInfo) { var parseStarInfo = JSON.parse(starInfo); if (Number(parseStarInfo.mid) === Number(window.mid) && parseStarInfo.has_star) { hasStar = 1; } } starDom && renderDom(starDom, startPersonCnt * 1, hasStar); var spanElement = document.getElementById('meta_content_hide_info'); spanElement && spanElement.classList.remove('rich_media_meta_padding'); } else { starDom && starDom.parentNode.removeChild(starDom); } } else { starDom && starDom.parentNode.removeChild(starDom); } window.__setStar = __setStar; } exports.__setStar = __setStar; exports.renderDom = renderDom; Object.defineProperty(exports, '__esModule', { value: true }); return exports; })({});</script><script type="text/javascript" nonce="1989770072" reportloaderror>var __INLINE_SCRIPT__ = (function () { 'use strict'; function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } var ua = navigator.userAgent; var is_ios = /(iPhone|iPad|iPod|iOS)/i.test(ua); var is_wp = /Windows\sPhone/i.test(ua); var is_android = /(Android)/i.test(ua); var is_wechat = /MicroMessenger\/([\d\.]+)/i.test(ua); var is_mac = /mac\sos/i.test(ua) && !is_ios; var is_windows = /windows\snt/i.test(ua) && !is_wp; var is_mpapp = /MPAPP\/([\d\.]+)/i.test(ua); var is_ipad = /iPad/i.test(ua); var is_windows_wechat = /WindowsWechat/i.test(ua); var is_mac_wechat = /MacWechat/i.test(ua) || /wechat.*mac os/i.test(ua); var is_prefetch = is_wechat && window.WeixinPrefecherJSBridge; var is_donut_app = /SAAASDK/i.test(ua); var is_harmony = /OpenHarmony|ArkWeb/i.test(ua); var is_in_miniProgram = is_android && /miniprogram/.test(ua.toLowerCase()) || window.__wxjs_environment == 'miniprogram'; var is_wx_work = /wxwork/i.test(ua); function getUrlParams() { var vars = location.search.substring(1).split('&'); var params = {}; var _iterator = _createForOfIteratorHelper(vars), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var ele = _step.value; var pair = ele.split('='); var key = decodeURIComponent(pair[0]); if (typeof params[key] === 'undefined') { params[key] = decodeURIComponent(pair[1]); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return params; } function get() { var reg = /MicroMessenger\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMac() { var reg = /MacWechat\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMacOS() { var reg = /Mac OS X ([\d_]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1].replace(/_/g, '.'); } return false; } function getWindows() { var reg = /WindowsWechat\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getWxWork() { var reg = /wxwork\/([\d\.]+)/i; var ret = ua.match(reg); if (ret && ret[1]) { return ret[1]; } return false; } function getMpApp() { var appVersion = [2, 4, 5]; var match = navigator.userAgent.match(/MPAPP\/(\d+(\.\d+)*)/); if (match) { appVersion = match[1].split('.').map(function (v) { return Number(v); }); } return appVersion.join('.'); } function getUnifiedPcVer() { var versionInfo = navigator.userAgent.match(/UnifiedPC\w+Wechat\(0xf\w{2}(\w+?)\w{2}\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(0, 1)); var subVersion = getVersionNumber(version.slice(1, 2)); var subVersion2 = getVersionNumber(version.slice(2, 3)); return [mainVersion, subVersion, subVersion2].join('.'); } } function getVersionNumber(hexStr) { return Number(Number("0x".concat(hexStr)).toString(10)); } function getWindowsVersionFormat() { var versionInfo = navigator.userAgent.match(/WindowsWechat\(0x(\w+?)\)/); if (versionInfo && versionInfo.length === 2) { var version = versionInfo[1]; var mainVersion = getVersionNumber(version.slice(1, 2)); var subVersion = getVersionNumber(version.slice(2, 4)); var subVersion2 = getVersionNumber(version.slice(4, 6)); return [mainVersion, subVersion, subVersion2].join('.'); } return false; } function getInner() { var reg = /MicroMessenger\/[\d\.]+\(0x(.+?)\)/i; var ret = ua.match(reg); if (ret && ret[1] && ret[1] != null) { return ret[1]; } if (!ret && /MicroMessenger\/[\d\.]+/i.test(ua)) { var urlParams = getUrlParams(); if (urlParams.version) { return urlParams.version; } } return false; } var opfunc = { 'cp-1': function cp1(a, b) { return a < b; }, cp0: function cp0(a, b) { return a === b; }, cp1: function cp1(a, b) { return a > b; } }; function cpVersion(ver, op, canEq, type) { var mmver = false; switch (type) { case 'mac': mmver = getMac(); break; case 'windows': mmver = getWindowsVersionFormat(); break; case 'wxwork': mmver = getWxWork(); break; case 'mpapp': mmver = getMpApp(); break; case 'unifiedpc': mmver = getUnifiedPcVer(); break; default: mmver = get(); break; } if (!mmver) { return; } var mmversion = mmver.split('.'); var version = ver.split('.'); if (!/\d+/g.test(mmversion[mmversion.length - 1])) { mmversion.pop(); } for (var i = 0, len = Math.max(mmversion.length, version.length); i < len; ++i) { var mmv = mmversion[i] || ''; var v = version[i] || ''; var mmvn = parseInt(mmv, 10) || 0; var vn = parseInt(v, 10) || 0; var eq = opfunc.cp0(mmvn, vn); if (eq) { continue; } var cp = opfunc["cp".concat(op)]; return cp(mmvn, vn); } return canEq || op === 0; } function eqVersion(version) { return cpVersion(version, 0); } function gtVersion(version, canEq) { return cpVersion(version, 1, canEq); } function ltVersion(version, canEq) { return cpVersion(version, -1, canEq); } function getPlatform() { if (is_ios) { return 'ios'; } if (is_android) { return 'android'; } if (is_mac) { return 'mac_os'; } if (is_windows) { return 'windows'; } return 'unknown'; } var is_google_play = false; var inner_ver_for_google_play_check = getInner(); if (is_android && inner_ver_for_google_play_check) { var v = "0x".concat(inner_ver_for_google_play_check.substr(-2)); if (parseInt(v) >= 64 && parseInt(v) <= 79) { is_google_play = true; } } var mmversion = { get: get, getMac: getMac, getMacOS: getMacOS, getWindows: getWindows, getInner: getInner, getWxWork: getWxWork, getMpApp: getMpApp, cpVersion: cpVersion, eqVersion: eqVersion, gtVersion: gtVersion, ltVersion: ltVersion, getPlatform: getPlatform, getVersionNumber: getVersionNumber, isWp: is_wp, isIOS: is_ios, isAndroid: is_android, isHarmony: is_harmony, isHarmonyWechat: is_harmony && is_wechat && cpVersion('1.0.0', 1, true), isInMiniProgram: is_in_miniProgram, isWechat: is_wechat, isMac: is_mac, isWindows: is_windows, isMacWechat: is_mac_wechat, isWindowsWechat: is_windows_wechat, isWxWork: is_wx_work, isOnlyWechat: is_wechat && !is_wx_work, isMpapp: is_mpapp, isNewMpApp: false, isIPad: is_ipad, isGooglePlay: is_google_play, isPrefetch: is_prefetch, isDonutAPP: is_donut_app }; function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } var prefix = '__WXLS__'; var localStorage$1 = window.localStorage || { getItem: function getItem() {}, setItem: function setItem() {}, removeItem: function removeItem() {}, key: function key() {}, clear: function clear() { var _a, _b; (_b = (_a = window.localStorage) === null || _a === void 0 ? void 0 : _a.clear) === null || _b === void 0 ? void 0 : _b.call(_a); }, length: 0 }; var evictionPolicies = { noeviction: function noeviction(data) { return data; }, 'allkeys-random': function allkeysRandom(data, size) { var keys = Object.keys(data); var memCnt = 0; while (memCnt < size) { var len = keys.length; var randomKeyIdx = Math.floor(Math.random() * len); var randomKey = keys[randomKeyIdx]; memCnt += JSON.stringify(data[randomKey]).length; delete data[randomKey]; keys = Object.keys(data); } return data; }, 'volatile-ttl': function volatileTtl(data, size) { var keys = Object.keys(data); keys = keys.sort(function (key1, key2) { var d1 = data[key1]; var d2 = data[key2]; if (d1.exp < d2.exp) return -1; if (d1.exp > d2.exp) return 1; return 0; }); var memCnt = 0; for (var i = 0; i < keys.length; i++) { if (memCnt >= size) break; var key = keys[i]; memCnt += JSON.stringify(data[key]).length; delete data[key]; } return data; }, 'clear-all': function clearAll() { localStorage$1.clear(); return {}; } }; function formatLogMsg(str) { return "[WXLS] ".concat(str); } var LS = function () { function LS(func, evictionPolicy, logger) { _classCallCheck(this, LS); this.logger = function () {}; if (!func) throw 'require function name.'; this.evictionPolicy = 'noeviction'; this.key = func; if (typeof logger === 'function') { this.logger = function (str, type) { return logger(formatLogMsg(str), type); }; } if (evictionPolicy && Object.keys(evictionPolicies).indexOf(evictionPolicy) !== -1) { this.evictionPolicy = evictionPolicy; } this.init(); } _createClass(LS, [{ key: "init", value: function init() { var _a, _b; this.check(); if (Math.random() * 1000 < 1) { (_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, "LSlen: ".concat(((_b = window === null || window === void 0 ? void 0 : window.localStorage) === null || _b === void 0 ? void 0 : _b.length) || localStorage$1.length), 'report'); } } }, { key: "getData", value: function getData() { var data = LS.getItem(this.key) || '{}'; try { data = JSON.parse(data); } catch (e) { this.logger("getData error: ".concat(e), 'error'); localStorage$1.removeItem(prefix + this.key); data = {}; } return data; } }, { key: "check", value: function check(isReturn) { var data = this.getData(); var temp = {}; var now = +new Date(); var key; var val; for (key in data) { val = data[key]; if (+val.exp > now) { temp[key] = val; } } this.logger("check info: isReturn:".concat(isReturn, " data:").concat(JSON.stringify(temp)), 'info'); if (isReturn) return temp; LS.setItem(this.key, JSON.stringify(temp), this.logger); } }, { key: "set", value: function set(key, val, exp) { var _a, _b; var data = this.check(true); data[key] = { val: val, exp: exp || +new Date() }; try { if (localStorage$1.getItem(prefix + this.key)) localStorage$1.removeItem(prefix + this.key); localStorage$1.setItem(prefix + this.key, JSON.stringify(data)); this.logger("first set success: LSlen:".concat((_a = window === null || window === void 0 ? void 0 : window.localStorage) === null || _a === void 0 ? void 0 : _a.length, " key:").concat(prefix + this.key, " data:").concat(JSON.stringify(data)), 'success'); } catch (e) { this.logger("first set error: LSlen:".concat((_b = window === null || window === void 0 ? void 0 : window.localStorage) === null || _b === void 0 ? void 0 : _b.length, " error:").concat(e, " key:").concat(prefix + this.key, " data:").concat(JSON.stringify(data), " k:").concat(key, " v:").concat(val, " exp:").concat(exp), 'error'); localStorage$1.clear(); LS.setItem(this.key, JSON.stringify(_defineProperty({}, key, { val: val, exp: exp || +new Date() })), this.logger); } } }, { key: "get", value: function get(key) { var data = this.getData(); data = data[key]; return data ? data.val || null : null; } }, { key: "remove", value: function remove(key) { var data = this.getData(); if (data[key]) delete data[key]; LS.setItem(this.key, JSON.stringify(data), this.logger); } }], [{ key: "getItem", value: function getItem(key) { key = prefix + key; return localStorage$1.getItem(key); } }, { key: "setItem", value: function setItem(key, val, logger) { var _a, _b; key = prefix + key; var n = 3; while (n--) { try { if (localStorage$1.getItem(key)) localStorage$1.removeItem(key); localStorage$1.setItem(key, val); typeof logger === 'function' && logger("setItem success: LSlen:".concat((_a = window === null || window === void 0 ? void 0 : window.localStorage) === null || _a === void 0 ? void 0 : _a.length, " key:").concat(key, " val:").concat(val), 'success'); break; } catch (e) { typeof logger === 'function' && logger("setItem error: LSlen:".concat((_b = window === null || window === void 0 ? void 0 : window.localStorage) === null || _b === void 0 ? void 0 : _b.length, " error:").concat(e, " key:").concat(key, " val:").concat(val), 'error'); LS.clear(); } } } }, { key: "clear", value: function clear() { var i; var k; for (i = localStorage$1.length - 1; i >= 0; i--) { k = localStorage$1.key(i); if (k.indexOf(prefix) == 0) { localStorage$1.removeItem(k); } } } }, { key: "getSupportEvicationPolicy", value: function getSupportEvicationPolicy() { return Object.keys(evictionPolicies); } }]); return LS; }(); var key = 'stream_last_read_pos'; new LS(key); var interactionStatusLS = new LS('bottom_interaction_status'); function getInteractionStatus(opt) { var biz = opt.biz || window.biz; var sn = opt.sn || window.sn; var mid = opt.mid || window.mid; var idx = opt.idx || window.idx; var interactionStatusKey = [biz, sn, mid, idx].join('_'); var interactionStatusInfo = interactionStatusLS.get(interactionStatusKey); if (Object.prototype.toString.call(interactionStatusInfo) !== '[object Object]') { interactionStatusInfo = {}; } return interactionStatusInfo; } var __setBarData = function __setBarData(appmsgBarData, cgiData) { if (!appmsgBarData) { return; } function formatReadNum(value) { var unit = '万'; if (window.LANG === 'en') { unit = 'k'; } var result = ''; if (parseInt(value, 10) > 100000) { result = 10 + unit + '+'; } else if (parseInt(value, 10) > 10000 && parseInt(value, 10) <= 100000) { var num = '' + parseInt(value, 10) / 10000; var dotIndex = num.indexOf('.'); if (dotIndex === -1) { result = num + unit; } else { result = num.substr(0, dotIndex) + '.' + num.charAt(dotIndex + 1) + unit; } } else if (parseInt(value, 10) === 0) { result = ''; } else { result = value || ''; } return result; } try { var bottomBarSafeBottomKey = '__bottom_bar_safe_bottom__'; var bottomBarSafeBottom = localStorage.getItem(bottomBarSafeBottomKey); if (bottomBarSafeBottom) { document.documentElement.style.setProperty('--immersive-safe-bottom', bottomBarSafeBottom); } var barOldlikeBtn = document.getElementById('js_bar_oldlike_btn'); var barShareBtn = document.getElementById('js_bar_share_btn'); var barLikeBtn = document.getElementById('js_bar_like_btn'); var barCommentBtn = document.getElementById('js_bar_comment_btn'); var barCollectBtn = document.getElementById('js_bar_collect_btn'); var barSubscribeBtn = document.getElementById('js_bar_subscribe_btn'); var oldLikeEl = barOldlikeBtn && barOldlikeBtn.parentElement; var likeEl = barLikeBtn && barLikeBtn.parentElement; var interactionStatus = getInteractionStatus({ biz: cgiData.biz, mid: cgiData.mid, sn: cgiData.sn, idx: cgiData.idx }); if (interactionStatus.is_my_old_like) { oldLikeEl && oldLikeEl.classList.add('praised'); } if (interactionStatus.is_my_like) { likeEl && (appmsgBarData.show_friend_seen === 2 ? likeEl.classList.add('love_btn_loved') : likeEl.classList.add('like_btn_liked')); } var old_like_count = interactionStatus.old_like_count * 1 ? Math.max(interactionStatus.old_like_count * 1, appmsgBarData.old_like_count) : appmsgBarData.old_like_count || 0; var share_count = interactionStatus.share_count * 1 ? Math.max(interactionStatus.share_count * 1, appmsgBarData.share_count) : appmsgBarData.share_count || 0; var like_count = interactionStatus.like_count * 1 ? Math.max(interactionStatus.like_count * 1, appmsgBarData.like_count) : appmsgBarData.like_count || 0; var comment_count = appmsgBarData.comment_count || 0; var collect_count = appmsgBarData.collect_count || 0; if (old_like_count && barOldlikeBtn) { barOldlikeBtn.innerText = formatReadNum(old_like_count); } if (share_count && barShareBtn) { barShareBtn.innerText = formatReadNum(share_count); } if (like_count && barLikeBtn) { barLikeBtn.innerText = formatReadNum(like_count); } if (comment_count && barCommentBtn) { barCommentBtn.innerText = formatReadNum(comment_count); } if (collect_count && barCollectBtn) { barCollectBtn.innerText = formatReadNum(collect_count); } if (mmversion.isInMiniProgram) { if (barShareBtn) { barShareBtn.style.display = 'none'; } if (barLikeBtn) { barLikeBtn.style.display = 'none'; } } var tempbarPraiseBtn = document.getElementById('js_temp_sns_sc_praise_btn'); var tempbarShareBtn = document.getElementById('js_temp_sns_sc_share_btn'); var tempbarCollectBtn = document.getElementById('js_temp_sns_sc_collect_btn'); var tempbarLikeBtn = document.getElementById('js_temp_sns_sc_like_btn'); var tempbarCommentBtn = document.getElementById('js_temp_sns_sc_comment_btn'); var handleTempClick = function handleTempClick(_ref) { var type = _ref.type, val = _ref.val, sucCb = _ref.sucCb, failCb = _ref.failCb; if (typeof window.__click_temp_btm_bar_cb__ === 'function') { window.__click_temp_btm_bar_cb__({ type: type, val: val, sucCb: sucCb, failCb: failCb }); } else { if (!window.__wait_click_temp_btm_bar_cb__) window.__wait_click_temp_btm_bar_cb__ = []; window.__wait_click_temp_btm_bar_cb__.push(function () { window.__click_temp_btm_bar_cb__({ type: type, val: val, sucCb: sucCb, failCb: failCb }); }); } }; tempbarPraiseBtn && barOldlikeBtn && oldLikeEl && tempbarPraiseBtn.addEventListener('click', function () { var newPraiseStatus = !oldLikeEl.classList.contains('praised'); handleTempClick({ type: 'praise', val: newPraiseStatus, sucCb: function sucCb() { var readNum = 0; if (newPraiseStatus) { oldLikeEl.classList.add('praised'); readNum = formatReadNum(interactionStatus.is_my_old_like ? old_like_count : old_like_count + 1); } else { oldLikeEl.classList.remove('praised'); readNum = formatReadNum(interactionStatus.is_my_old_like ? Math.max(0, old_like_count - 1) : old_like_count); } barOldlikeBtn.innerText = readNum ? readNum : '赞'; } }); }); tempbarLikeBtn && barLikeBtn && likeEl && tempbarLikeBtn.addEventListener('click', function () { var newRecommendStatus = appmsgBarData.show_friend_seen === 2 ? !likeEl.classList.contains('love_btn_loved') : !likeEl.classList.contains('like_btn_liked'); handleTempClick({ type: 'recommend', val: newRecommendStatus, sucCb: function sucCb() { var recommendNum = 0; if (newRecommendStatus) { appmsgBarData.show_friend_seen === 2 ? likeEl.classList.add('love_btn_loved') : likeEl.classList.add('like_btn_liked'); recommendNum = formatReadNum(interactionStatus.is_my_like ? like_count : like_count + 1); } else { appmsgBarData.show_friend_seen === 2 ? likeEl.classList.remove('love_btn_loved') : likeEl.classList.remove('like_btn_liked'); recommendNum = formatReadNum(interactionStatus.is_my_like ? Math.max(0, like_count - 1) : like_count); } if (recommendNum) { barLikeBtn.innerText = recommendNum; } else { barLikeBtn.innerText = appmsgBarData.show_friend_seen === 2 ? '推荐' : '在看'; } } }); }); tempbarShareBtn && barShareBtn && tempbarShareBtn.addEventListener('click', function () { handleTempClick({ type: 'share' }); }); tempbarCollectBtn && barCollectBtn && tempbarCollectBtn.addEventListener('click', function () { handleTempClick({ type: 'collect' }); }); tempbarCommentBtn && barCommentBtn && tempbarCommentBtn.addEventListener('click', function () { handleTempClick({ type: 'comment' }); }); barSubscribeBtn && barSubscribeBtn.addEventListener('click', function () { handleTempClick({ type: 'subscribe' }); }); } catch (error) { console.log(error); } }; if (!window.__second_open__) { var tmpAppmsgBarData = { show_like: '' * 1, like_count: '' * 1, show_share: '' * 1, share_count: '' * 1, show_old_like: '' * 1, old_like_count: '' * 1, comment_enabled: '' * 1, comment_count: '' * 1, show_collect: '' * 1, collect_count: '' * 1, show_friend_seen: '' * 1, is_subscribed: '' * 1, verify_status: '' * 1, original_content_num: '$user_info.appmsg_bar_data.original_content_num.DATA$' * 1, friend_subscribe_count: '' * 1 }; var cgiData = { idx: '' , biz: '' , mid: '' , sn: '' , subcount_version: '' }; __setBarData(tmpAppmsgBarData, cgiData); window.__setBarData = __setBarData; } return __setBarData; })();</script><script type="text/javascript" nonce="1989770072" reportloaderror>(function () { 'use strict'; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } var classWhiteList = ['rich_pages', 'blockquote_info', 'blockquote_biz', 'blockquote_other', 'blockquote_article', 'h5_image_link', 'img_loading', 'list-paddingleft-1', 'list-paddingleft-2', 'list-paddingleft-3', 'selectTdClass', 'noBorderTable', 'ue-table-interlace-color-single', 'ue-table-interlace-color-double', '__bg_gif', 'weapp_text_link', 'weapp_image_link', 'qqmusic_area', 'tc', 'tips_global', 'unsupport_tips', 'qqmusic_wrp', 'appmsg_card_context', 'appmsg_card_active', 'qqmusic_bd', 'play_area', 'icon_qqmusic_switch', 'pic_qqmusic_default', 'qqmusic_thumb', 'access_area', 'qqmusic_songname', 'qqmusic_singername', 'qqmusic_source', 'share_audio_context', 'flex_context', 'pages_reset', 'share_audio_switch', 'icon_share_audio_switch', 'share_audio_info', 'flex_bd', 'share_audio_title', 'share_audio_tips', 'share_audio_progress_wrp', 'share_audio_progress', 'share_audio_progress_inner', 'share_audio_progress_buffer', 'share_audio_progress_loading', 'share_audio_progress_loading_inner', 'share_audio_progress_handle', 'share_audio_desc', 'share_audio_length_current', 'share_audio_length_total', 'video_iframe', 'vote_iframe', 'res_iframe', 'card_iframe', 'weapp_display_element', 'weapp_card', 'app_context', 'weapp_card_bd', 'weapp_card_profile', 'radius_avatar', 'weapp_card_avatar', 'weapp_card_nickname', 'weapp_card_info', 'weapp_card_title', 'weapp_card_thumb_wrp', 'weapp_card_ft', 'weapp_card_logo', 'pay', 'pay__mask', 'ct_geography_loc_tip', 'subsc_context', 'subsc_btn', 'reset_btn', 'icon_subsc', 'weui-primary-loading', 'weui-primary-loading__dot', 'wxw-img', 'mp-caret', 'appmsg_poi_iframe', 'cpc_iframe', 'channels_iframe_wrp', 'channels_iframe', 'videosnap_video_iframe', 'videosnap_live_iframe', 'videosnap_image_iframe', 'channels_live_iframe', 'minishop_iframe_wrp', 'minishop_iframe', 'mp_profile_iframe', 'mp_profile_iframe_wrp', 'mp_search_iframe_wrp', 'appmsg_search_iframe_wrp', 'appmsg_search_iframe', 'vote_area', 'vote_iframe', 'mp_vote_iframe_wrp', 'mp_vote_iframe', 'qqmusic_iframe', 'blockquote_iframe', 'blockquote_tips_iframe', 'video_iframe', 'shopcard_iframe', 'topic_iframe', 'weapp_app_iframe', 'img_fail_iframe', 'mp_miniprogram_iframe', 'appmsg_cpslink_iframe', 'js_editor_mpcpslink', 'mp-cpslink-iframe-wrp', 'mp_common_sticker_iframe', 'mp_common_sticker_iframe_wrp', 'mp_common_product_iframe', 'mp_common_product_iframe_wrp', 'new_cps_iframe', 'redpackage_iframe', 'mp_redpacket_iframe_wrp', 'product_text_link', 'clmusic_iframe', 'clalbum_iframe', 'mp_common_custom_iframe_wrp', 'mp_common_custom_iframe']; var classWhiteListReg = [new RegExp('^editor__content__'), new RegExp('^wxw'), new RegExp('^js_'), new RegExp('^cps_inner'), new RegExp('^bizsvr_'), new RegExp('^code-snippet'), new RegExp('^wx_(?!text_underline)'), new RegExp('^wx-'), new RegExp('^icon_emoji_'), new RegExp('^custom_select_card') ]; var contentStyle = { classWhiteList: classWhiteList, classWhiteListReg: classWhiteListReg }; function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function DomFilter (cgiOptData) { return function (Plugin) { var isMMVersionSetted = false; var contentDom = document.getElementById('js_content'); var classWhiteList = contentStyle.classWhiteList, classWhiteListReg = contentStyle.classWhiteListReg; var removeClassByWhiteList = function removeClassByWhiteList(node) { var classAttr = node.getAttribute('class'); if (classAttr) { var classList = classAttr.split(/\s+/); var newClassList = []; for (var i = 0, len = classList.length; i < len; ++i) { var className = classList[i]; if (className && classWhiteList.indexOf(className) != -1) { newClassList.push(className); } else { for (var j = 0, jl = classWhiteListReg.length; j < jl; j++) { if (classWhiteListReg[j].test(className)) { newClassList.push(className); break; } } } } node.setAttribute('class', newClassList.join(' ')); } }; var langBlackList = ['zh-cn', 'en-us']; var removeLangByBlackList = function removeLangByBlackList(node) { var langAttr = node.getAttribute('lang'); if (langAttr) { var lang = langAttr.toLowerCase(); for (var i = 0; i < langBlackList.length; i++) { if (lang === langBlackList[i]) { node.removeAttribute('lang'); return; } } } }; var isAccessMode = window.localStorage.getItem('isMpUserAccessibility'); var isCarton = (cgiOptData === null || cgiOptData === void 0 ? void 0 : cgiOptData.copyright_info.is_cartoon_copyright) || (cgiOptData === null || cgiOptData === void 0 ? void 0 : cgiOptData.user_info.is_care_mode) || isAccessMode === '1'; var bgPlaceholder = 'url("data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==")'; var lazyloadBackgroundImage = function lazyloadBackgroundImage(node) { if (window.__second_open__ && !isCarton && node && node.style && typeof node.getAttribute === 'function' && !node.getAttribute('data-lazy-bgimg')) { var bgImg = node.style.backgroundImage; var bgImgUrl = bgImg && bgImg.match(/url\(['"]?(.*?)['"]?\)/); if (bgImgUrl && bgImgUrl[1]) { node.style.backgroundImage = bgImg.replace(/url\(['"]?.*?['"]?\)/, bgPlaceholder); node.setAttribute('data-lazy-bgimg', bgImgUrl[1]); node.classList.add('wx_imgbc_placeholder'); } } }; return function (_Plugin) { _inherits(_class, _Plugin); function _class() { _classCallCheck(this, _class); return _callSuper(this, _class, arguments); } _createClass(_class, [{ key: "beforeConvertNode", value: function beforeConvertNode(el) { if (el && el.tagName) { var tagName = el.tagName.toLowerCase(); if (tagName !== 'iframe') { removeClassByWhiteList(el); removeLangByBlackList(el); lazyloadBackgroundImage(el); } else { if (el.getAttribute('class') === 'video_ad_iframe') { el.setAttribute('class', ''); } } } } }, { key: "afterConvertNode", value: function afterConvertNode(el) { if (!isMMVersionSetted) { var ua = navigator.userAgent; /(iPhone|iPad|iPod|iOS|mac\sos)/i.test(ua) ? contentDom.classList.add('fix_apple_default_style') : null; isMMVersionSetted = true; } if (el.style && el.style.webkitTextSizeAdjust !== '' && el.style.webkitTextSizeAdjust !== 'none') { el.style.webkitTextSizeAdjust = 'inherit'; } if (el.tagName === 'animate' && el.getAttribute('attributeName') === 'height') { var repeatCountVal = el.getAttribute('repeatCount'); if (repeatCountVal === 'indefinite' || repeatCountVal > '10') { if (el.getAttribute('begin') !== 'click' && el.getAttribute('end') !== 'click') { el.setAttribute('repeatCount', 'undefined'); el.setAttribute('attributeName', 'undefined'); new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=306525_1_1'; } } } if (el.tagName === 'OL') { if ((el.parentNode === document.getElementById('js_content') || el.parentNode.getAttribute('id') === 'js_secopen_content') && el.getAttribute('style') && el.getAttribute('style').indexOf('padding-left') < 0) { if (el.childNodes.length >= 10 && el.childNodes.length < 100) { el.classList.add('extra-list-padding-level1'); el.style.paddingLeft = '2.2em'; } else if (el.childNodes.length > 100) { el.classList.add('extra-list-padding-level2'); el.style.paddingLeft = '3.2em'; } } } if (el.tagName === 'MP-STYLE-TYPE') { var styleType = parseInt(el.getAttribute('data-value'), 10); if (styleType === 3) { if (el.parentNode && el.parentNode.previousSibling) { var realLastP = el.parentNode.previousSibling; if ((realLastP.tagName === 'P' || realLastP.tagName === 'SECTION') && realLastP.style && !realLastP.style.marginBottom) { realLastP.style.marginBottom = '0'; } } } } } }]); return _class; }(Plugin); }; } if (!window.__second_open__ && window.Darkmode) { var cost = 0; window.Darkmode.extend([DomFilter()]); window.Darkmode.run(document.querySelectorAll('#js_content *'), { mode: '', defaultDarkBgColor: '', error: function error() { new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_0_1'; }, begin: function begin(isSwitch) { new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_2_1'; isSwitch && (new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_4_1'); cost = new Date() * 1; }, showFirstPage: function showFirstPage() { document.getElementById('js_content').style.removeProperty('opacity'); cost = new Date() * 1 - cost; var isTop = (document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop) === 0; if (cost <= 10) { new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_6_1'; isTop && (new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_13_1'); } else if (cost > 10 && cost <= 20) { new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_7_1'; isTop && (new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_14_1'); } else if (cost > 20 && cost <= 30) { new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_8_1'; isTop && (new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_15_1'); } else if (cost > 30 && cost <= 40) { new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_9_1'; isTop && (new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_16_1'); } else if (cost > 40 && cost <= 50) { new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_10_1'; isTop && (new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_17_1'); } else if (cost > 50 && cost <= 60) { new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_11_1'; isTop && (new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_18_1'); } else { new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_12_1'; isTop && (new Image().src = 'https://mp.weixin.qq.com/mp/jsmonitor?idkey=125617_19_1'); } } }); document.getElementById('js_content').style.removeProperty('visibility'); } })();</script><script type="text/javascript" nonce="1989770072" reportloaderror>var __INLINE_SCRIPT__ = (function (exports) { 'use strict'; function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _arrayLikeToArray$1(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray$1(arr); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _unsupportedIterableToArray$1(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$1(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray$1(arr) || _nonIterableSpread(); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function updateProfileAttr(profiles, infos) { if (!profiles || !Array.isArray(profiles) || !infos || !Array.isArray(infos)) { return; } var _iterator = _createForOfIteratorHelper(profiles), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var profile = _step.value; var profileId = profile.getAttribute('data-id'); var profileInfo = findBizCardInfo(infos, profileId); if (profileInfo) { var is_biz_ban = profileInfo.is_biz_ban, original_num = profileInfo.original_num, biz_account_status = profileInfo.biz_account_status; profile.setAttribute('data-origin_num', original_num * 1); profile.setAttribute('data-is_biz_ban', is_biz_ban * 1); profile.setAttribute('data-isban', is_biz_ban * 1); profile.setAttribute('data-biz_account_status', biz_account_status * 1); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } function findBizCardInfo(infos, id) { return infos.find(function (info) { return info.fakeid === id; }); } function dealWithProfileData(data) { var _data$biz_card; if (!window.__second_open__) { return data; } var profileData = (data === null || data === void 0 ? void 0 : (_data$biz_card = data.biz_card) === null || _databiz_card.list) || []; profileData.map(function (item) { return item['original_num'] = item['orignal_num']; }); return profileData; } function updateCustomElementAttrs(dom, data) { if (!dom || !data) return; var profiles = dom.querySelectorAll('mp-common-profile'); updateProfileAttr(Array.from(profiles), dealWithProfileData(data)); } function preprocessMpAudios(dom, data) { var voiceList = window.__second_open__ ? data === null || data === void 0 ? void 0 : data.voice_in_appmsg_list_json : data.voiceList; if (typeof voiceList === 'string') { try { voiceList = JSON.parse(voiceList); } catch (e) { return; } } if (!dom || !voiceList) return; var albumlist = []; if (voiceList.voice_in_appmsg && voiceList.voice_in_appmsg.length > 0) { albumlist = voiceList.voice_in_appmsg; } var mpvoices = _toConsumableArray(dom.querySelectorAll('mpvoice')); mpvoices.forEach(function (mpvoice) { var mpaudio = document.createElement('mp-common-mpaudio'); var attrs = mpvoice.getAttributeNames().reduce(function (acc, name) { if (name === 'data-trans_state' || name === 'err_tips') return acc; return _objectSpread(_objectSpread({}, acc), {}, _defineProperty({}, name, mpvoice.getAttribute(name))); }, {}); for (var key in attrs) { mpaudio.setAttribute(key, attrs[key]); } mpaudio.setAttribute('data-trans_state', 1); mpvoice.parentNode.replaceChild(mpaudio, mpvoice); }); var mpaudios = _toConsumableArray(dom.querySelectorAll('mp-common-mpaudio')); mpaudios.forEach(function (mpaudio) { mpaudio.style.opacity = 0; mpaudio.setAttribute('author', data.nick_name || ''); var album = albumlist.find(function (a) { var voice_encode_fileid = mpaudio.getAttribute('voice_encode_fileid'); try { voice_encode_fileid = decodeURIComponent(voice_encode_fileid); } catch (e) {} return a.voice_id === voice_encode_fileid && a.appmsgalbuminfo; }); if (album) { mpaudio.setAttribute('data-topic_id', album.appmsgalbuminfo.album_id || 0); mpaudio.setAttribute('data-topic_name', album.appmsgalbuminfo.title || ''); mpaudio.setAttribute('data-topic_link', album.appmsgalbuminfo.link.html(false).replace('#wechat_redirect', '') + '#wechat_redirect'); mpaudio.setAttribute('data-topic_num', album.appmsgalbuminfo.tag_content_num || 0); } }); var claudios = _toConsumableArray(dom.querySelectorAll('mp-common-claudio')); claudios.forEach(function (claudio) { claudio.style.opacity = 0; }); } function handleTagReplacement(ele, newTagName) { var newTag = document.createElement(newTagName); var _iterator2 = _createForOfIteratorHelper(ele.attributes), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var attr = _step2.value; newTag.setAttribute(attr.name, attr.value); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } newTag.innerHTML = ele.innerHTML; ele.parentNode.replaceChild(newTag, ele); return newTag; } function preprocessMpMusic(root) { var qqmusicEles = _toConsumableArray(root.querySelectorAll('qqmusic')); qqmusicEles.forEach(function (ele) { return handleTagReplacement(ele, 'mp-common-qqmusic'); }); } if (!window.__second_open__) { updateCustomElementAttrs(window.document, window.mp_profile); preprocessMpAudios(window.document, { voiceList: window.voiceList, nick_name: window.nickname }); preprocessMpMusic(window.document); } exports.preprocessMpAudios = preprocessMpAudios; exports.preprocessMpMusic = preprocessMpMusic; exports.updateCustomElementAttrs = updateCustomElementAttrs; exports.updateProfileAttr = updateProfileAttr; Object.defineProperty(exports, '__esModule', { value: true }); return exports; })({});</script><script type="text/javascript" nonce="1989770072" reportloaderror>var __INLINE_SCRIPT__ = (function (exports) { 'use strict'; function setProfileName() { var ua = window.navigator.userAgent; if (/wxwork/i.test(ua)) { var profileName = document.getElementById('js_name'); var authorName = document.getElementById('js_author_name'); var accountNames = document.getElementsByClassName('account_nickname_inner'); if (profileName) { profileName.classList.add('tips_global_primary'); } if (authorName) { authorName.classList.add('tips_global_primary'); } if (accountNames && accountNames.length) { accountNames[0].classList.add('tips_global_primary'); } } } if (!window.__second_open__) { setProfileName(); } exports.setProfileName = setProfileName; Object.defineProperty(exports, '__esModule', { value: true }); return exports; })({});</script><script type="text/javascript" nonce="1989770072" reportloaderror>var __INLINE_SCRIPT__ = (function () { 'use strict'; function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } var prefix = '__WXLS__'; var localStorage = window.localStorage || { getItem: function getItem() {}, setItem: function setItem() {}, removeItem: function removeItem() {}, key: function key() {}, clear: function clear() { var _a, _b; (_b = (_a = window.localStorage) === null || _a === void 0 ? void 0 : _a.clear) === null || _b === void 0 ? void 0 : _b.call(_a); }, length: 0 }; var evictionPolicies = { noeviction: function noeviction(data) { return data; }, 'allkeys-random': function allkeysRandom(data, size) { var keys = Object.keys(data); var memCnt = 0; while (memCnt < size) { var len = keys.length; var randomKeyIdx = Math.floor(Math.random() * len); var randomKey = keys[randomKeyIdx]; memCnt += JSON.stringify(data[randomKey]).length; delete data[randomKey]; keys = Object.keys(data); } return data; }, 'volatile-ttl': function volatileTtl(data, size) { var keys = Object.keys(data); keys = keys.sort(function (key1, key2) { var d1 = data[key1]; var d2 = data[key2]; if (d1.exp < d2.exp) return -1; if (d1.exp > d2.exp) return 1; return 0; }); var memCnt = 0; for (var i = 0; i < keys.length; i++) { if (memCnt >= size) break; var key = keys[i]; memCnt += JSON.stringify(data[key]).length; delete data[key]; } return data; }, 'clear-all': function clearAll() { localStorage.clear(); return {}; } }; function formatLogMsg(str) { return "[WXLS] ".concat(str); } var LS = function () { function LS(func, evictionPolicy, logger) { _classCallCheck(this, LS); this.logger = function () {}; if (!func) throw 'require function name.'; this.evictionPolicy = 'noeviction'; this.key = func; if (typeof logger === 'function') { this.logger = function (str, type) { return logger(formatLogMsg(str), type); }; } if (evictionPolicy && Object.keys(evictionPolicies).indexOf(evictionPolicy) !== -1) { this.evictionPolicy = evictionPolicy; } this.init(); } _createClass(LS, [{ key: "init", value: function init() { var _a, _b; this.check(); if (Math.random() * 1000 < 1) { (_a = this.logger) === null || _a === void 0 ? void 0 : _a.call(this, "LSlen: ".concat(((_b = window === null || window === void 0 ? void 0 : window.localStorage) === null || _b === void 0 ? void 0 : _b.length) || localStorage.length), 'report'); } } }, { key: "getData", value: function getData() { var data = LS.getItem(this.key) || '{}'; try { data = JSON.parse(data); } catch (e) { this.logger("getData error: ".concat(e), 'error'); localStorage.removeItem(prefix + this.key); data = {}; } return data; } }, { key: "check", value: function check(isReturn) { var data = this.getData(); var temp = {}; var now = +new Date(); var key; var val; for (key in data) { val = data[key]; if (+val.exp > now) { temp[key] = val; } } this.logger("check info: isReturn:".concat(isReturn, " data:").concat(JSON.stringify(temp)), 'info'); if (isReturn) return temp; LS.setItem(this.key, JSON.stringify(temp), this.logger); } }, { key: "set", value: function set(key, val, exp) { var _a, _b; var data = this.check(true); data[key] = { val: val, exp: exp || +new Date() }; try { if (localStorage.getItem(prefix + this.key)) localStorage.removeItem(prefix + this.key); localStorage.setItem(prefix + this.key, JSON.stringify(data)); this.logger("first set success: LSlen:".concat((_a = window === null || window === void 0 ? void 0 : window.localStorage) === null || _a === void 0 ? void 0 : _a.length, " key:").concat(prefix + this.key, " data:").concat(JSON.stringify(data)), 'success'); } catch (e) { this.logger("first set error: LSlen:".concat((_b = window === null || window === void 0 ? void 0 : window.localStorage) === null || _b === void 0 ? void 0 : _b.length, " error:").concat(e, " key:").concat(prefix + this.key, " data:").concat(JSON.stringify(data), " k:").concat(key, " v:").concat(val, " exp:").concat(exp), 'error'); localStorage.clear(); LS.setItem(this.key, JSON.stringify(_defineProperty({}, key, { val: val, exp: exp || +new Date() })), this.logger); } } }, { key: "get", value: function get(key) { var data = this.getData(); data = data[key]; return data ? data.val || null : null; } }, { key: "remove", value: function remove(key) { var data = this.getData(); if (data[key]) delete data[key]; LS.setItem(this.key, JSON.stringify(data), this.logger); } }], [{ key: "getItem", value: function getItem(key) { key = prefix + key; return localStorage.getItem(key); } }, { key: "setItem", value: function setItem(key, val, logger) { var _a, _b; key = prefix + key; var n = 3; while (n--) { try { if (localStorage.getItem(key)) localStorage.removeItem(key); localStorage.setItem(key, val); typeof logger === 'function' && logger("setItem success: LSlen:".concat((_a = window === null || window === void 0 ? void 0 : window.localStorage) === null || _a === void 0 ? void 0 : _a.length, " key:").concat(key, " val:").concat(val), 'success'); break; } catch (e) { typeof logger === 'function' && logger("setItem error: LSlen:".concat((_b = window === null || window === void 0 ? void 0 : window.localStorage) === null || _b === void 0 ? void 0 : _b.length, " error:").concat(e, " key:").concat(key, " val:").concat(val), 'error'); LS.clear(); } } } }, { key: "clear", value: function clear() { var i; var k; for (i = localStorage.length - 1; i >= 0; i--) { k = localStorage.key(i); if (k.indexOf(prefix) == 0) { localStorage.removeItem(k); } } } }, { key: "getSupportEvicationPolicy", value: function getSupportEvicationPolicy() { return Object.keys(evictionPolicies); } }]); return LS; }(); var key = 'stream_last_read_pos'; new LS(key); var interactionStatusLS = new LS('bottom_interaction_status'); function getInteractionStatus(opt) { var biz = opt.biz || window.biz; var sn = opt.sn || window.sn; var mid = opt.mid || window.mid; var idx = opt.idx || window.idx; var interactionStatusKey = [biz, sn, mid, idx].join('_'); var interactionStatusInfo = interactionStatusLS.get(interactionStatusKey); if (Object.prototype.toString.call(interactionStatusInfo) !== '[object Object]') { interactionStatusInfo = {}; } return interactionStatusInfo; } var formatReadNum = function formatReadNum(value) { var result = ''; var unit = window.LANG === 'en' ? 'k' : '万'; if (parseInt(value, 10) > 100000) { result = 10 + unit + '+'; } else if (parseInt(value, 10) > 10000 && parseInt(value, 10) <= 100000) { var num = "".concat(parseInt(value, 10) / (unit === 'k' ? 1000 : 10000)); var dotIndex = num.indexOf('.'); if (dotIndex === -1) { result = "".concat(num).concat(unit); } else { result = "".concat(num.substr(0, dotIndex), ".").concat(num.charAt(dotIndex + 1)).concat(unit); } } else if (parseInt(value, 10) === 0) { result = ''; } else { result = value || ''; } return result; }; var formatTime = function formatTime(value) { var time = new Date(value * 1000); var year = time.getFullYear(); var month = time.getMonth() + 1; var day = time.getDate(); return year + '年' + "".concat(month > 9 ? month : '0' + month) + '月' + "".concat(day > 9 ? day : '0' + day) + '日'; }; var __setPageContentBottomData = function __setPageContentBottomData(cgiData) { if (!cgiData) return; try { var tempReadNum = document.getElementById('js_btm_temp_read_num'); var tempModifyTime = document.getElementById('js_btm_temp_modify_time'); var interactionStatus = getInteractionStatus({ biz: cgiData.biz, mid: cgiData.mid, sn: cgiData.sn, idx: cgiData.idx }); var readNum = interactionStatus.read_num * 1 ? Math.max(interactionStatus.read_num * 1, cgiData.read_num) : cgiData.read_num || 0; if (readNum && tempReadNum) { tempReadNum.innerText = formatReadNum(readNum); } if (cgiData.modify_time && tempModifyTime) { tempModifyTime.innerText = formatTime(cgiData.modify_time); } } catch (error) { console.log(error); } }; if (!window.__second_open__) { var cgiData = { modify_time: '' * 1, read_num: '' * 1, idx: '' , biz: '' , mid: '' , sn: '' }; __setPageContentBottomData(cgiData); window.__setPageContentBottomData = __setPageContentBottomData; } return __setPageContentBottomData; })();</script> <script type="text/javascript" nonce="1989770072" reportloaderror> (function(_g){ _g.appmsg_like_type = "2" * 1 ? "2" * 1 : 1; _g.clientversion = ""; _g.passparam = ""; if(!_g.msg_link) { _g.msg_link = "https://mp.weixin.qq.com/s/3hbpQRAofG905lAt7Onq5g"; } _g.appmsg_type = "9"; _g.devicetype = ""; _g.kanyikan_video_educate_pic = "//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/pic/pic_like_comment_primary750ed3.png"; _g.kanyikan_educate_pic = "//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/images/pic/pic_like_comment750ed3.png"; })(window); </script> <script type="text/javascript" nonce="1989770072" reportloaderror> (function() { var ua = navigator.userAgent; if (ua.indexOf("MicroMessenger") != -1 && ua.indexOf("Android") != -1){ var script = document.createElement('script'); var head = document.getElementsByTagName('head')[0]; script.type = 'text/javascript'; script.src = "https://midas.gtimg.cn/h5sdk/js/api/h5sdk.js"; head.appendChild(script); } })(); </script> <script type="text/javascript" nonce="1989770072" reportloaderror> var real_show_page_time = +new Date(); if (!!window.addEventListener){ window.addEventListener("load", function(){ window.onload_endtime = +new Date(); }); } </script> <script type="text/javascript" nonce="1989770072" reportloaderror> (function() { const ua = navigator.userAgent; const is_ios = /(iPhone|iPad|iPod|iOS)/i.test(ua); const is_wp = /Windows\sPhone/i.test(ua); const is_mac = /mac\sos/i.test(ua) && !is_ios; const is_windows = /windows\snt/i.test(ua) && !is_wp; if ((is_mac && !is_ios) || (is_windows && !is_wp)) { var script = document.createElement('script'); var head = document.getElementsByTagName('head')[0]; script.type = 'text/javascript'; script.src = "https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxopensdk.js"; head.appendChild(script); } })(); </script> <script nomodule nonce="1989770072" reportloaderror>new Image().src='https://mp.weixin.qq.com/mp/jsmonitor?idkey=66881_111_1&t='+Math.random();</script> <script nomodule nonce="1989770072" reportloaderror>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script> <script nomodule crossorigin id="vite-legacy-polyfill" src="//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/assets/polyfills-legacy.m8zs8dx7a6217755.js" nonce="1989770072" reportloaderror></script> <script nomodule crossorigin id="vite-legacy-entry" src="//res.wx.qq.com/mmbizappmsg/zh_CN/htmledition/js/assets/appmsg-legacy.m8zs8dx751963a44.js" nonce="1989770072" reportloaderror>System.import(document.getElementById('vite-legacy-entry').getAttribute('src'))</script> </object></span></code></pre> </section>
作者:微信小助手
<section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100000353" data-s="300,640" src="/upload/f1f76b2bfe3e59b2d198c669c508c0d1.png" data-type="png" type="block"> </section> <section data-tool="人言兑.md-公众号排版编辑器" data-website="https://md.axiaoxin.com" style="font-size: 16px;color: black;padding: 0;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;word-wrap: break-word;text-align: left;font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Noto Sans SC', 'Source Han Sans SC', 'WenQuanYi Micro Hei', 'Microsoft JhengHei', system-ui, sans-serif, Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-rendering: optimizeLegibility;line-height: 1.75;" data-pm-slice="0 0 []"> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">大家好!今天我要带你们走进一个让人惊叹的科技世界,主角就是来自字节跳动的最新语音黑科技——</span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">MegaTTS 3</span></strong><span leaf="">。这项技术不仅在语音合成领域掀起了一场革命,还凭借超强的实用性和惊艳的表现,彻底刷新了我们对“人造声音”的认知。想知道它有多厉害?别急,接下来我将带你从头到尾解锁MegaTTS 3的秘密,保证让你看完直呼“太牛了”!</span></p> <hr style="margin-top: 10px;margin-bottom: 10px;border: none;border-top: 1px solid black;border-style: solid;border-width: 2px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);height: 0.4em;margin: 1.5em 0;"> <h2 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;font-size: 20.8px;display: table;padding: 0.3em 1em;margin: 4em auto 2em;color: #fff;background: #FA5151;font-weight: bold;border-radius: 8px;box-shadow: 0 4px 6px rgba(0,0,0,0.1);"><span style="display: none;"></span><span><span leaf="">一、MegaTTS 3是什么?“文字变声”的超级魔法</span></span><span></span></h2> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">简单来说,</span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">MegaTTS 3</span></strong><span leaf="">是字节跳动推出的一款语音合成神器。它的核心任务就是把枯燥的文字变成自然流畅的声音,听起来就像真人说话一样。想象一下,你输入一段文字,点一下按钮,几秒钟后,一个带着情感、语调抑扬顿挫的声音就传出来了——这就是MegaTTS 3的“魔法”。</span></p> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">相比传统的语音合成技术,MegaTTS 3简直是开了挂。它不仅音质更清晰,语调更自然,还能在情感表达上做到细腻入微。无论是读新闻、讲故事,还是模仿你的声音,它都能轻松驾驭。字节跳动这次真的把语音技术玩出了新高度!</span></p> <hr style="margin-top: 10px;margin-bottom: 10px;border: none;border-top: 1px solid black;border-style: solid;border-width: 2px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);height: 0.4em;margin: 1.5em 0;"> <h2 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;font-size: 20.8px;display: table;padding: 0.3em 1em;margin: 4em auto 2em;color: #fff;background: #FA5151;font-weight: bold;border-radius: 8px;box-shadow: 0 4px 6px rgba(0,0,0,0.1);"><span style="display: none;"></span><span><span leaf="">二、MegaTTS 3的四大“杀手锏”</span></span><span></span></h2> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">MegaTTS 3到底有多强?我们直接来看它的四大核心优势,绝对让你服气!</span></p> <h3 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;line-height: 1.2;font-size: 17.6px;display: table;padding: 4px 8px;border-bottom: 4px solid #FA5151;border-radius: 4px;margin: 2em auto 1em;color: hsl(0 0% 3.9%);font-weight: bold;"><span style="display: none;"></span><span><span leaf="">1. </span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">轻量高效:小身材,大能量</span></strong></span><span style="display: none;"></span></h3> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">MegaTTS 3的“心脏”是一个叫</span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">TTS Diffusion Transformer</span></strong><span leaf="">的网络,参数量只有</span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">0.45B(4.5亿)</span></strong><span leaf="">。别看数字不大,它的性能却一点不含糊。轻量化设计意味着它占用的计算资源更少,运行起来更快更省力。不管是部署到服务器还是个人设备,MegaTTS 3都能轻松上岗,效率拉满!</span></p> <h3 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;line-height: 1.2;font-size: 17.6px;display: table;padding: 4px 8px;border-bottom: 4px solid #FA5151;border-radius: 4px;margin: 2em auto 1em;color: hsl(0 0% 3.9%);font-weight: bold;"><span style="display: none;"></span><span><span leaf="">2. </span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">超高质量的声音克隆:复制你的声音不是梦</span></strong></span><span style="display: none;"></span></h3> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">如果你觉得“模仿”只是小打小闹,那MegaTTS 3会让你彻底改观。它在</span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">声音克隆</span></strong><span leaf="">上的表现简直可以用“逆天”来形容。通过官方的演示视频,你会发现它能几乎完美复制一个人的声音特征——语调、语速、甚至连细微的情感起伏都不放过。</span></p> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">更厉害的是,MegaTTS 3在</span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">Seed测试集</span></strong><span leaf="">上的表现吊打了一众竞品,数据表格里它的成绩亮眼得像个“学霸”。想试试自己的声音被克隆成什么样?可以去官方提供的</span><span style="color: #1e6bb8;font-weight: bold;"><span leaf="">Google Drive链接</span></span><sup style="line-height: 0;color: #1e6bb8;font-weight: bold;"><span leaf="">[1]</span></sup><span leaf="">提交样本,很快就能拿到专属的“声音克隆文件”哦!</span></p> <h3 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;line-height: 1.2;font-size: 17.6px;display: table;padding: 4px 8px;border-bottom: 4px solid #FA5151;border-radius: 4px;margin: 2em auto 1em;color: hsl(0 0% 3.9%);font-weight: bold;"><span style="display: none;"></span><span><span leaf="">3. </span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">双语支持:中英切换无缝丝滑</span></strong></span><span style="display: none;"></span></h3> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">MegaTTS 3还有个让人拍手叫绝的功能——</span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">中英文双语支持</span></strong><span leaf="">。不管你是想让它读中文故事,还是念英文新闻,它都能轻松搞定。更牛的是,它还能在两种语言间无缝切换(code-switching),比如一句中文夹着英文单词,它照样说得顺畅自然。对于需要处理多语言内容的小伙伴来说,这简直是“神器”级别的好帮手!</span></p> <h3 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;line-height: 1.2;font-size: 17.6px;display: table;padding: 4px 8px;border-bottom: 4px solid #FA5151;border-radius: 4px;margin: 2em auto 1em;color: hsl(0 0% 3.9%);font-weight: bold;"><span style="display: none;"></span><span><span leaf="">4. </span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">超强可控性:你想要的声音它都能调</span></strong></span><span style="display: none;"></span></h3> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">MegaTTS 3不仅会说话,还能“听话”。它支持</span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">口音强度控制</span></strong><span leaf="">,你可以决定让声音保留多少原汁原味的口音,或者变得更标准。更厉害的是,官方还透露,未来会上线</span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">细粒度发音和时长调整</span></strong><span leaf="">功能。到时候,你甚至能精确控制每个字的发音和停顿时长,想让声音听起来更温柔还是更激昂,全都由你说了算!</span></p> <hr style="margin-top: 10px;margin-bottom: 10px;border: none;border-top: 1px solid black;border-style: solid;border-width: 2px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);height: 0.4em;margin: 1.5em 0;"> <h2 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;font-size: 20.8px;display: table;padding: 0.3em 1em;margin: 4em auto 2em;color: #fff;background: #FA5151;font-weight: bold;border-radius: 8px;box-shadow: 0 4px 6px rgba(0,0,0,0.1);"><span style="display: none;"></span><span><span leaf="">三、MegaTTS 3的“黑科技”揭秘</span></span><span></span></h2> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">说了这么多优点,你是不是很好奇MegaTTS 3是怎么做到的?别急,接下来我们稍微“硬核”一点,聊聊它的技术细节。不过放心,我会尽量用大白话解释,保证你看得懂!</span></p> <h3 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;line-height: 1.2;font-size: 17.6px;display: table;padding: 4px 8px;border-bottom: 4px solid #FA5151;border-radius: 4px;margin: 2em auto 1em;color: hsl(0 0% 3.9%);font-weight: bold;"><span style="display: none;"></span><span><span leaf="">1. </span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">安装和使用:小白也能上手</span></strong></span><span style="display: none;"></span></h3> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">想体验MegaTTS 3的魅力?首先得把它装起来。具体步骤很简单:</span></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);"> <strong style="color: #FA5151;font-weight: bold;"><span leaf="">环境准备</span></strong><span leaf="">:需要一个Python 3.9的环境,可以用conda创建(</span><code style="word-wrap: break-word;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 90%;color: #d14;background: rgba(27,31,35,.05);padding: 3px 5px;border-radius: 4px;"><span leaf="">conda create -n megatts3-env python=3.9</span></code><span leaf="">),然后安装依赖包(</span><code style="word-wrap: break-word;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 90%;color: #d14;background: rgba(27,31,35,.05);padding: 3px 5px;border-radius: 4px;"><span leaf="">pip install -r requirements.txt</span></code><span leaf="">)。</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);"> <strong style="color: #FA5151;font-weight: bold;"><span leaf="">设置路径</span></strong><span leaf="">:根据你的系统(Linux/Mac或Windows),设置好PYTHONPATH指向MegaTTS 3的根目录。</span> </section></li> </ul> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">装好环境后,你就可以开始玩转它了!</span></p> <h3 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;line-height: 1.2;font-size: 17.6px;display: table;padding: 4px 8px;border-bottom: 4px solid #FA5151;border-radius: 4px;margin: 2em auto 1em;color: hsl(0 0% 3.9%);font-weight: bold;"><span style="display: none;"></span><span><span leaf="">2. </span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">模型下载:核心部件哪里找?</span></strong></span><span style="display: none;"></span></h3> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">MegaTTS 3的预训练模型(checkpoints)可以从</span><span style="color: #1e6bb8;font-weight: bold;"><span leaf="">Google Drive</span></span><sup style="line-height: 0;color: #1e6bb8;font-weight: bold;"><span leaf="">[2]</span></sup><span leaf="">或</span><span style="color: #1e6bb8;font-weight: bold;"><span leaf="">Huggingface</span></span><sup style="line-height: 0;color: #1e6bb8;font-weight: bold;"><span leaf="">[3]</span></sup><span leaf="">下载。下载后,把这些文件放进</span><code style="word-wrap: break-word;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 90%;color: #d14;background: rgba(27,31,35,.05);padding: 3px 5px;border-radius: 4px;"><span leaf="">./checkpoints/xxx</span></code><span leaf="">目录下就行。</span></p> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">不过有个小提醒:出于安全考虑,</span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">WaveVAE编码器</span></strong><span leaf="">的参数没直接提供。你得用官方预提取的latents文件(从</span><span style="color: #1e6bb8;font-weight: bold;"><span leaf="">这个链接</span></span><sup style="line-height: 0;color: #1e6bb8;font-weight: bold;"><span leaf="">[4]</span></sup><span leaf="">下载)来推理。想给某个特定的人合成语音?那你得准备好他的音频文件(比如“A.wav”)和对应的latents文件(“A.npy”),放在同一个目录下。</span></p> <h3 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;line-height: 1.2;font-size: 17.6px;display: table;padding: 4px 8px;border-bottom: 4px solid #FA5151;border-radius: 4px;margin: 2em auto 1em;color: hsl(0 0% 3.9%);font-weight: bold;"><span style="display: none;"></span><span><span leaf="">3. </span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">推理实战:一句话变声音</span></strong></span><span style="display: none;"></span></h3> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">安装好模型后,怎么让MegaTTS 3“开口说话”?最简单的方法是用命令行操作。比如,想让它读一段中文:</span></p> <pre data-tool="人言兑.md-公众号排版编辑器" style="margin: 10px 8px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span leaf="">CUDA_VISIBLE_DEVICES=0 python tts/infer_cli.py --input_wav </span><span style="color: #50a14f;line-height: 26px;"><span leaf="">'assets/Chinese_prompt.wav'</span></span><span leaf=""> --input_text </span><span style="color: #50a14f;line-height: 26px;"><span leaf="">"另一边的桌上,一位读书人嗤之以鼻道,'佛子三藏,神子燕小鱼是什么样的人物,李家的那个李子夜如何与他们相提并论?'"</span></span><span leaf=""> --output_dir ./gen</span><br></code></pre> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">或者来一段英文:</span></p> <pre data-tool="人言兑.md-公众号排版编辑器" style="margin: 10px 8px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span leaf="">CUDA_VISIBLE_DEVICES=0 python tts/infer_cli.py --input_wav </span><span style="color: #50a14f;line-height: 26px;"><span leaf="">'assets/English_prompt.wav'</span></span><span leaf=""> --input_text </span><span style="color: #50a14f;line-height: 26px;"><span leaf="">'As his long promised tariff threat turned into reality this week, top human advisers began fielding a wave of calls from business leaders, particularly in the automotive sector, along with lawmakers who were sounding the alarm.'</span></span><span leaf=""> --output_dir ./gen --p_w 2.0 --t_w 3.0</span><br></code></pre> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">这里有两个参数可以调:</span></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);"> <strong style="color: #FA5151;font-weight: bold;"><span leaf="">p_w(清晰度权重)</span></strong><span leaf="">:影响发音的清晰程度,值越大越标准。</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);"> <strong style="color: #FA5151;font-weight: bold;"><span leaf="">t_w(相似度权重)</span></strong><span leaf="">:控制声音和原音频的相似度,值越高越像本人。</span> </section></li> </ul> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">如果你想保留口音,可以把p_w调低,比如:</span></p> <pre data-tool="人言兑.md-公众号排版编辑器" style="margin: 10px 8px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span leaf="">CUDA_VISIBLE_DEVICES=0 python tts/infer_cli.py --input_wav </span><span style="color: #50a14f;line-height: 26px;"><span leaf="">'assets/English_prompt.wav'</span></span><span leaf=""> --input_text </span><span style="color: #50a14f;line-height: 26px;"><span leaf="">'这是一条有口音的音频。'</span></span><span leaf=""> --output_dir ./gen --p_w 1.0 --t_w 3.0</span><br></code></pre> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">还有个更懒人化的选择——用</span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">Web UI</span></strong><span leaf="">操作:</span></p> <pre data-tool="人言兑.md-公众号排版编辑器" style="margin: 10px 8px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span leaf="">CUDA_VISIBLE_DEVICES=0 python tts/gradio_api.py</span><br></code></pre> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">不过如果用CPU跑,可能得等30秒左右(10步推理),建议有GPU的小伙伴直接上显卡加速!</span></p> <hr style="margin-top: 10px;margin-bottom: 10px;border: none;border-top: 1px solid black;border-style: solid;border-width: 2px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);height: 0.4em;margin: 1.5em 0;"> <h2 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;font-size: 20.8px;display: table;padding: 0.3em 1em;margin: 4em auto 2em;color: #fff;background: #FA5151;font-weight: bold;border-radius: 8px;box-shadow: 0 4px 6px rgba(0,0,0,0.1);"><span style="display: none;"></span><span><span leaf="">四、MegaTTS 3的“隐藏彩蛋”:三大子模块</span></span><span></span></h2> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">除了语音合成,MegaTTS 3还自带三个超实用的子模块,简直是“买一送三”的福利!</span></p> <h3 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;line-height: 1.2;font-size: 17.6px;display: table;padding: 4px 8px;border-bottom: 4px solid #FA5151;border-radius: 4px;margin: 2em auto 1em;color: hsl(0 0% 3.9%);font-weight: bold;"><span style="display: none;"></span><span><span leaf="">1. </span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">Aligner:语音和文字的完美搭档</span></strong></span><span style="display: none;"></span></h3> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="color: #FA5151;font-weight: bold;"><span leaf="">Aligner</span></strong><span leaf="">是一个语音-文本对齐神器,通过大量MFA专家模型生成的伪标签训练而成。它能干啥?</span></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);"> <span leaf="">帮你准备微调数据集;</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);"> <span leaf="">过滤掉杂乱的大型语音数据集(对不齐的音频八成是噪音);</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);"> <span leaf="">做音素识别和语音分割。</span> </section></li> </ul> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">有了它,处理语音数据就像切菜一样简单!</span></p> <h3 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;line-height: 1.2;font-size: 17.6px;display: table;padding: 4px 8px;border-bottom: 4px solid #FA5151;border-radius: 4px;margin: 2em auto 1em;color: hsl(0 0% 3.9%);font-weight: bold;"><span style="display: none;"></span><span><span leaf="">2. </span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">Graphme-to-Phoneme Model:文字变音素的魔法师</span></strong></span><span style="display: none;"></span></h3> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">这个子模块基于</span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">Qwen2.5-0.5B</span></strong><span leaf="">模型微调,能把文字(grapheme)稳稳当当转成音素(phoneme)。不管多复杂的发音,它都能处理得妥妥帖帖。</span></p> <h3 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;line-height: 1.2;font-size: 17.6px;display: table;padding: 4px 8px;border-bottom: 4px solid #FA5151;border-radius: 4px;margin: 2em auto 1em;color: hsl(0 0% 3.9%);font-weight: bold;"><span style="display: none;"></span><span><span leaf="">3. </span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">WaveVAE:声音压缩与重建的高手</span></strong></span><span style="display: none;"></span></h3> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><strong style="color: #FA5151;font-weight: bold;"><span leaf="">WaveVAE</span></strong><span leaf="">是个波形变分自编码器,能把24kHz的高清语音压缩到25Hz的声学latent,几乎无损还原原始波形。它有三大用途:</span></p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);"> <span leaf="">给语音合成模型提供更紧凑的训练目标,加速收敛;</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);"> <span leaf="">用于声音转换;</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);"> <span leaf="">做高质量的vocoder。</span> </section></li> </ul> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">官方还贴心地给出了WaveVAE的性能表格,数据证明它在音质还原上的实力无人能敌!</span></p> <hr style="margin-top: 10px;margin-bottom: 10px;border: none;border-top: 1px solid black;border-style: solid;border-width: 2px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);height: 0.4em;margin: 1.5em 0;"> <h2 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;font-size: 20.8px;display: table;padding: 0.3em 1em;margin: 4em auto 2em;color: #fff;background: #FA5151;font-weight: bold;border-radius: 8px;box-shadow: 0 4px 6px rgba(0,0,0,0.1);"><span style="display: none;"></span><span><span leaf="">五、安全性与许可:放心用,别乱搞</span></span><span></span></h2> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">MegaTTS 3虽然强大,但安全第一。如果你在使用中发现任何潜在问题,记得通过字节跳动的</span><span style="color: #1e6bb8;font-weight: bold;"><span leaf="">安全中心</span></span><sup style="line-height: 0;color: #1e6bb8;font-weight: bold;"><span leaf="">[5]</span></sup><span leaf="">或邮箱(sec@bytedance.com)反馈。别在GitHub上公开讨论哦,避免不必要的麻烦。</span></p> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">另外,MegaTTS 3用的是</span><strong style="color: #FA5151;font-weight: bold;"><span leaf="">Apache-2.0许可协议</span></strong><span leaf="">,大家可以自由使用和修改,但得遵守条款,别拿去干坏事就行!</span></p> <hr style="margin-top: 10px;margin-bottom: 10px;border: none;border-top: 1px solid black;border-style: solid;border-width: 2px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);height: 0.4em;margin: 1.5em 0;"> <h2 data-tool="人言兑.md-公众号排版编辑器" style="margin-top: 30px;margin-bottom: 15px;text-align: center;font-size: 20.8px;display: table;padding: 0.3em 1em;margin: 4em auto 2em;color: #fff;background: #FA5151;font-weight: bold;border-radius: 8px;box-shadow: 0 4px 6px rgba(0,0,0,0.1);"><span style="display: none;"></span><span><span leaf="">六、写在最后:MegaTTS 3的未来值得期待</span></span><span></span></h2> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">从轻量高效到超高质量的声音克隆,再到双语支持和强大可控性,MegaTTS 3用实力证明了字节跳动在语音技术领域的“王者地位”。它不仅是个学术研究的利器,更是商业应用的超级助手。官方还透露,未来会有更多功能上线,比如细粒度调整和更多数据集支持,简直让人迫不及待!</span></p> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">想体验MegaTTS 3的魅力?赶紧动手试试吧!无论是模仿朋友的声音讲笑话,还是给自己的文字作品配上专业播音,MegaTTS 3都能帮你实现。期待你在使用过程中发现更多惊喜,也欢迎随时留言分享你的体验!</span></p> <hr style="margin-top: 10px;margin-bottom: 10px;border: none;border-top: 1px solid black;border-style: solid;border-width: 2px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);height: 0.4em;margin: 1.5em 0;"> <p data-tool="人言兑.md-公众号排版编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;"><span leaf="">好了,以上就是关于MegaTTS 3的全部介绍。看完这篇3000多字的“硬核科普”,你是不是也对这项黑科技心动了?快去试试吧,下一秒,你的文字就能“开口说话”啦!</span></p> <p data-tool="人言兑.md-公众号排版编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;margin-top: 48px;margin-bottom: 5px;font-weight: bold;font-size: 16px;"><span style="display: block;color: #FA5151;"><span leaf="">参考资料</span></span></p> <section data-tool="人言兑.md-公众号排版编辑器"> <span style="display: block;"><span style="display: inline;background: none;font-size: 14px;opacity: 0.6;line-height: 26px;font-family: ptima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"><span leaf="">[1] </span></span><p style="padding-top: 8px;padding-bottom: 8px;display: inline;font-size: 14px;padding: 0px;margin: 0px 0px 0px 5px;line-height: 26px;color: black;word-break: break-all;"><span leaf="">Google Drive链接: </span><em style="font-style: italic;color: black;"><span leaf="">https://drive.google.com/drive/folders/1gCWL1y_2xu9nIFhUX_OW5MbcFuB7J5Cl?usp=sharing</span></em></p></span><span style="display: block;"><span style="display: inline;background: none;font-size: 14px;opacity: 0.6;line-height: 26px;font-family: ptima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"><span leaf="">[2] </span></span><p style="padding-top: 8px;padding-bottom: 8px;display: inline;font-size: 14px;padding: 0px;margin: 0px 0px 0px 5px;line-height: 26px;color: black;word-break: break-all;"><span leaf="">Google Drive: </span><em style="font-style: italic;color: black;"><span leaf="">https://drive.google.com/drive/folders/1CidiSqtHgJTBDAHQ746_on_YR0boHDYB?usp=sharing</span></em></p></span><span style="display: block;"><span style="display: inline;background: none;font-size: 14px;opacity: 0.6;line-height: 26px;font-family: ptima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"><span leaf="">[3] </span></span><p style="padding-top: 8px;padding-bottom: 8px;display: inline;font-size: 14px;padding: 0px;margin: 0px 0px 0px 5px;line-height: 26px;color: black;word-break: break-all;"><span leaf="">Huggingface: </span><em style="font-style: italic;color: black;"><span leaf="">https://huggingface.co/ByteDance/MegaTTS3</span></em></p></span><span style="display: block;"><span style="display: inline;background: none;font-size: 14px;opacity: 0.6;line-height: 26px;font-family: ptima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"><span leaf="">[4] </span></span><p style="padding-top: 8px;padding-bottom: 8px;display: inline;font-size: 14px;padding: 0px;margin: 0px 0px 0px 5px;line-height: 26px;color: black;word-break: break-all;"><span leaf="">这个链接: </span><em style="font-style: italic;color: black;"><span leaf="">https://drive.google.com/drive/folders/1QhcHWcy20JfqWjgqZX1YM3I6i9u4oNlr?usp=sharing</span></em></p></span><span style="display: block;"><span style="display: inline;background: none;font-size: 14px;opacity: 0.6;line-height: 26px;font-family: ptima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"><span leaf="">[5] </span></span><p style="padding-top: 8px;padding-bottom: 8px;display: inline;font-size: 14px;padding: 0px;margin: 0px 0px 0px 5px;line-height: 26px;color: black;word-break: break-all;"><span leaf="">安全中心: </span><em style="font-style: italic;color: black;"><span leaf="">https://security.bytedance.com/src</span></em></p></span> </section> </section> <section> <span leaf=""><br></span> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<p data-pm-slice="0 0 []" style="text-indent: 2em;"><span style="font-size: 16px;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(252, 252, 252);color: rgba(0, 0, 0, 0.9);font-family: " pingfang sc, -apple-system, blinkmacsystemfont, segoe ui, roboto, ubuntu, helvetica neue, helvetica, arial, hiragino sans gb, microsoft yahei yahei, source han cn, sans-serif;font-variant-caps: normal;font-variant-ligatures: normal;><span leaf=""><span textstyle="" style="font-size: 17px;">以为把AI变成"教育通"只需要喂题库?当RAG技术遭遇"基本经济制度"和"基本政治制度"的0.94相似度陷阱时,开发者才会惊觉:教育领域的知识检索,远非向量匹配那般简单。在这片看似题库铺就的坦途上,Embedding模型正在经历着比高考数学压轴题更严酷的语义辨析考验——当两个专业术语的余弦相似度突破0.9,人类教师秒懂的差异,AI却要经历"Embedding初筛+Reranker精排"的双重淬炼才能勉强分辨。今天,让我们撕开RAG在教育领域"即插即用"的伪装,直面那隐藏在768维向量空间里的技术深渊。</span></span></span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100003360" data-ratio="0.5641677255400254" data-s="300,640" src="/upload/b9e20004d1c996bafb09d163939d5a50.png" data-type="png" data-w="787" type="block"> </section> <p><span style="font-size: 12pt;color: rgba(0, 0, 0, 0.9);font-family: " pingfang sc;></span></p> <h2><span leaf=""><span textstyle="" style="font-size: 20px;font-weight: bold;">一、为什么RAG在教育行业如鱼得水?</span></span></h2> <p style="text-indent: 2em;"><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">教育行业有一个天然优势:</span></span></span><span style="font-weight: bold;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">题库资源</span></span></span><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">。</span></span></span><span style="font-size: unset;color: unset;font-family: unset;"><span leaf=""><span textstyle="" style="font-size: 17px;">互联网上存在海量的题目、答案和解析,而且这些资源已经按照明确的知识结构被组织好了。每个题目对应一个答案和解析,这种天然的一对一关系,为RAG技术提供了绝佳的应用场景。</span></span></span></p> <p style="text-indent: 2em;"><span style="font-size: unset;color: unset;font-family: unset;font-weight: bold;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">RAG技术简述</span></span></span><span style="font-size: unset;color: unset;font-family: unset;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">:RAG结合了检索系统和生成式AI的优势,先从知识库中检索相关信息,再基于检索结果生成回答,保证AI回答既有创造性,又有事实依据。</span></span></span></p> <p style="text-indent: 2em;"><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">与其他行业相比,教育行业的知识片段不需要复杂的切分和整理工作。当学生提出问题时,系统只需识别出对应的题目,就能立即找到相关的答案和解析,进而生成高质量的回复。</span></span></span><span style="font-size: unset;color: unset;font-family: unset;"><span leaf=""><span textstyle="" style="font-size: 17px;">即使面对复杂的数学公式,现代多模态模型(如GPT-4o)也能将图片转化为文字版本,进而实现知识检索。这意味着,无论是文字题、数学公式,还是物理图表,RAG技术都能驾驭自如。</span></span></span></p> <p style="text-indent: 2em;"><span style="font-size: unset;color: unset;font-family: unset;"><span leaf=""><br></span></span></p> <h2><span leaf=""><span textstyle="" style="font-size: 20px;font-weight: bold;">二、RAG技术在教育中的"滑铁卢"</span></span></h2> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100003365" data-ratio="0.5523809523809524" data-s="300,640" src="/upload/5c25b0fe1077907f33fb431ebe0ddaf1.png" data-type="png" data-w="945" type="block"> </section> <p><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">然而,技术从不是完美无缺的。</span></span></span></p> <p><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;font-weight: bold;">以下面这个初中政治知识的真实案例为例:</span></span></span></p> <p><span style="font-weight: bold;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">问题</span></span></span><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">:我国社会主义初级阶段的基本经济制度是什么?这一制度的确立有什么意义?</span></span></span></p> <p><span style="font-weight: bold;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">检索结果Top3</span></span></span><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">:</span></span></span></p> <ol class="list-paddingleft-1"> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">我国社会主义初级阶段的基本政治制度是人民代表大会制度。它体现了人民当家作主的社会主义民主政治本质,保障了广大人民群众的民主权利。(相似度0.94)</span></span></p></li> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">公有制为主体、多种所有制经济共同发展是我国社会主义初级阶段的基本经济制度。这一制度的确立有利于解放和发展社会生产力,促进经济持续健康发展。(相似度0.89)</span></span></p></li> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">我国的基本经济制度是在社会主义条件下发展市场经济,处理好政府与市场的关系,更好发挥政府作用。(相似度0.86)</span></span></p></li> </ol> <p><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">看到问题了吗?正确答案(公有制为主体、多种所有制经济共同发展)排在了第二位!而排名第一的答案虽然文字相似度高达0.94,但实际上回答的是"基本政治制度"而非"基本经济制度",完全是不同的知识点。</span></span></span></p> <p><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;font-weight: bold;">这就是RAG技术在实际应用中的典型问题:</span></span></span></p> <ol class="list-paddingleft-1"> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">相似文本的语义区分困难</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">:在"基本经济制度"和"基本政治制度"这样的概念中,Embedding模型难以区分关键的语义差异。</span></span></p></li> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">知识库大小的悖论</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">:直觉上,知识库越大,覆盖场景越多,回答准确率应该越高。但实际情况却往往相反 —— 随着知识片段增多,检索准确率反而下降了。</span></span></p><p><span leaf=""><br></span></p></li> </ol> <h2><span leaf=""><span textstyle="" style="font-size: 20px;font-weight: bold;">三、为何会出现这些问题?Embedding模型的秘密</span></span></h2> <p><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100003343" data-ratio="0.7726819541375872" src="/upload/f467acf513e25f673b1012793d9f9551.png" data-type="png" data-w="1003"></span></p> <p style="text-indent: 2em;"><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">要理解RAG的局限性,我们需要了解Embedding模型的工作原理。</span></span></span></p> <p><span style="font-weight: bold;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">Embedding模型</span></span></span><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">也是基于Transformer架构的语言模型,它与GPT等生成模型在理解语义方面的原理相似。但有一个关键区别:</span></span></span><span style="font-weight: bold;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">训练目标更简单,参数规模更小</span></span></span><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">。</span></span></span></p> <p><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;font-weight: bold;">Embedding模型的核心目标是:</span></span></span></p> <ul class="list-paddingleft-1"> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">让语义相似的文本映射为高相似度的向量</span></span></p></li> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">让语义不同的文本映射为低相似度的向量</span></span></p></li> </ul> <p><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;font-weight: bold;">它通过数亿条三元组数据训练而成,每条数据包含:</span></span></span></p> <ul class="list-paddingleft-1"> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">Anchor(锚点)</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">:核心文本</span></span></p></li> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">Positive(正例)</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">:与锚点语义相似的文本</span></span></p></li> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">Negative(负例)</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">:与锚点语义不同的文本</span></span></p></li> </ul> <p><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">然而,正是这种相对简单的训练方式,导致模型在处理细微语义差异时力不从心。当知识库规模扩大,包含更多相似但语义不同的内容时,准确率自然下降。</span></span></span></p> <p><span style="-en-paragraph:true;"><span leaf=""><br></span></span></p> <h2 style="text-align: left;"><span leaf=""><span textstyle="" style="font-size: 20px;font-weight: bold;">四、解决之道:Embedding+Reranker双模型协作</span></span></h2> <p><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100003341" data-ratio="0.5970443349753695" src="/upload/5782b07f690df969ca695c82eee7657f.png" data-type="png" data-w="1015"></span></p> <p style="text-indent: 2em;"><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">面对RAG的局限性,业内已经形成了一种共识:</span></span></span><span style="font-weight: bold;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">双模型协作</span></span></span><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">是提升检索质量的有效方法。</span></span></span></p> <h3><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">1、Embedding模型:快速初筛</span></span></span></h3> <p style="text-indent: 2em;"><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">Embedding模型负责高效率、高速度的初步检索。它能在千万级知识库中秒级返回相似度较高的Top-K结果。</span></span></span></p> <h3><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">2、Reranker模型:精确排序</span></span></span></h3> <p style="text-indent: 2em;"><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">Reranker模型则负责对初筛结果进行更严谨、更深入的语义分析和重新排序。它通常使用Cross Attention机制,能更准确地捕捉查询与候选片段之间的语义关联。</span></span></span></p> <p><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">目前市场上有多种优秀的模型可选:</span></span></span></p> <ul class="list-paddingleft-1"> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">智源人工智能研究院:</span></span><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">BGE</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">(BAAI General Embedding)</span></span></p></li> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">网易:</span></span><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">BCE</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">(Bilingual and Crosslingual Embedding)</span></span></p></li> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">阿里:</span></span><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">Qwen GTE</span></span></span></p></li> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">腾讯:</span></span><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">Conan-embedding</span></span></span></p><p><span style="font-weight: bold;"><span leaf=""><br></span></span></p></li> </ul> <h2><span leaf=""><span textstyle="" style="font-size: 20px;font-weight: bold;">五、技术进阶:如何持续提升RAG效果?</span></span></h2> <p><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100003340" data-ratio="0.5812053115423902" src="/upload/aebcd6815c86cc507f96b5a5a1fc4358.png" data-type="png" data-w="979"></span></p> <p style="text-indent: 2em;"><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">即使应用了双模型方案,我们仍然面临两个核心挑战:</span></span></span></p> <h3><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">1. 召回率不足</span></span></span></h3> <p style="text-indent: 2em;"><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">如果Embedding模型初次召回的Top-K结果中根本不包含正确答案,那么Reranker再强也无济于事。</span></span></span></p> <h3><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">2. 难负例挖掘</span></span></span></h3> <p style="text-indent: 2em;"><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">简单负例(如"社会主义经济制度"vs"资本主义政治制度")容易区分,但难负例则考验模型能力。例如:</span></span></span></p> <p><span style="font-weight: bold;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">难负例示例</span></span></span><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">:</span></span></span></p> <ul class="list-paddingleft-1"> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">Anchor</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">: 我国社会主义初级阶段的基本经济制度是公有制为主体、多种所有制经济共同发展。</span></span></p></li> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">正例</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">: 在我国社会主义初级阶段,公有制经济为主体、多种所有制经济共同发展构成了我国的基本经济制度,这有利于解放和发展生产力。</span></span></p></li> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">难负例</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">: 我国社会主义初级阶段的基本分配制度是按劳分配为主体、多种分配方式并存,这与我国的基本经济制度相适应,共同促进社会公平和经济发展。</span></span></p></li> </ul> <p><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">注意这个难负例同样涉及"社会主义初级阶段"和"基本制度"的概念,但指的是"分配制度"而非"经济制度",这类细微差异往往难以被模型准确识别。</span></span></span></p> <p><span style="-en-paragraph:true;"><b><span leaf=""><span textstyle="" style="font-size: 17px;">解决方案:</span></span></b></span></p> <p><span style="font-weight: bold;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">1)、预训练阶段</span></span></span><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">:使用7.5亿对多样化数据(包括标题-内容对、问答对等)</span></span></span></p> <p><span style="font-weight: bold;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">2)、微调阶段</span></span></span><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">:采用动态难负例策略</span></span></span></p> <ul class="list-paddingleft-1"> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">筛选与查询相似度高的负例</span></span></p></li> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">为每个查询动态生成更多难负例</span></span></p></li> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">不断更新训练数据,提升模型判别能力</span></span></p><p><span leaf=""><br></span></p></li> </ul> <h2><span leaf=""><span textstyle="" style="font-size: 20px;font-weight: bold;">六、垂直领域的Embedding微调</span></span></h2> <p style="text-indent: 2em;"><span style="font-size: 16px;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(252, 252, 252);color: rgba(0, 0, 0, 0.9);font-family: " pingfang sc, -apple-system, blinkmacsystemfont, segoe ui, roboto, ubuntu, helvetica neue, helvetica, arial, hiragino sans gb, microsoft yahei yahei, source han cn, sans-serif;font-variant-caps: normal;font-variant-ligatures: normal;><span leaf=""><span textstyle="" style="font-size: 17px;">通过领域特定数据强化语义关联,提升检索精度(如教育题库匹配、医疗诊断精准度),</span></span></span><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">对于教育等垂直领域,领域适应性的Embedding模型尤为重要。</span></span></span></p> <p><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">微调的核心在于</span></span></span><span style="font-weight: bold;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">关联性数据</span></span></span><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">:</span></span></span></p> <ul class="list-paddingleft-1"> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">教育领域:题目-解析对</span></span></p></li> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">医疗领域:症状-诊断方法对</span></span></p></li> <li><p><span leaf=""><span textstyle="" style="font-size: 17px;">法律领域:案情-判决对</span></span></p></li> </ul> <p><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">与对话式模型相比,Embedding模型的微调安全性更高,不会产生不当内容,这对教育行业尤为重要。</span></span></span><span style="-en-paragraph:true;"><span leaf=""><br></span></span></p> <p><span style="-en-paragraph:true;"><span leaf=""><br></span></span></p> <p><span style="-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 20px;font-weight: bold;">七、总结</span></span></span></p> <p style="text-indent: 2em;"><span style="font-size: 16px;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(252, 252, 252);color: rgba(0, 0, 0, 0.9);font-family: " pingfang sc, -apple-system, blinkmacsystemfont, segoe ui, roboto, ubuntu, helvetica neue, helvetica, arial, hiragino sans gb, microsoft yahei yahei, source han cn, sans-serif;font-variant-caps: normal;font-variant-ligatures: normal;><span leaf=""><span textstyle="" style="font-size: 17px;">那些宣称"三天搭建智能答疑系统"的方案,往往在真实教学场景中暴露出惊人的脆弱性——就像在政治例题中,系统可能把"基本经济制度"和"基本政治制度"混为一谈,而这种错误在考试中将是致命的。教育AI的真正突围,需要开发者深入理解动态难负例挖掘的奥秘,掌握Cross Attention机制的精准调控,更要懂得如何让7.5亿训练对数据在垂直领域焕发生机。当你在GitHub上轻松clone某个RAG项目时,请记住:</span><span textstyle="" style="font-size: 17px;font-weight: bold;">RAG的知识服务,从来都不是简单的向量游戏,而是一场关于语义粒度的纳米级战争。</span></span></span></p> <p style="display: none;"> <mp-style-type data-value="10000"></mp-style-type></p>
作者:微信小助手
<section label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="box-sizing: border-box;" data-pm-slice="0 0 []"> <section label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="box-sizing: border-box;"> <section label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="box-sizing: border-box;text-align: center;"> <section label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="display: inline-block;vertical-align: top;padding: 8px 5px 5px 3px;width: 50%;box-sizing: border-box;border-right: 1px solid #66CCC5;"> <section style="box-sizing: border-box;"> <section label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;"> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="502125774" data-ratio="1" data-s="300,640" src="/upload/6603674999b334bf1c4f4472fe241b90.jpg" data-type="jpeg" data-w="1080" style="width:95px;height:95px;" type="block"> </section> <p><span style="font-size: 14px;color: #66CCC5;line-height: 1.6;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">韦东东 </span></span></p> </section> </section> </section> <section label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="display: inline-block;vertical-align: top;padding: 6px;width: 50%;box-sizing: border-box;"> <section style="box-sizing: border-box;border:1px solid #66CCC5;padding: 8px 5px 8px 5px;width: 120px;color:#66CCC5;border-radius: 2px;margin: auto;line-height: 20px;font-size: 14px;border-radius: 4px;"> <p><span leaf="">读完需要</span></p> <section style="font-size: 30px;color:#666;line-height: 32px;"> <span leaf="">10</span> </section><span leaf="">分钟</span> <p style="font-size: 11px;color:#aaa;padding-top:3px;"><span leaf="">速读仅需 4 分钟</span></p> </section> </section> </section> </section> </section> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;" data-pm-slice="0 0 []"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">企业在落地 RAG 知识库时,<span textstyle="" style="font-weight: bold;font-style: italic;"> Dify 和 RAGFlow 这两个开源框架应该选择哪个?</span></span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;" data-pm-slice="0 0 []"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">这也是我一直以来做RAG咨询时,经常被企业方问到的问题之一。一般来说,如果需要处理特别复杂的文档和非结构化数据,RAGFlow 是优选。而对于需要多模型协作和复杂业务流程的场景,Dify 更为适合。</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;" data-pm-slice="0 0 []"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">但</span><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="" data-pm-slice="1 1 [" para,{tagname:p,attributes:{label:converted by knb formatter from jason ng https: knb.im mp,style:margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;,data-pm-slice:0 0 []},namespaceuri:http: www.w3.org 1999 xhtml},node,{tagname:span,attributes:{style:max-width: 100%;line-height: 28px;box-sizing: !important;letter-spacing:1px;font-size:15px;font-family: pingfangsc-light,sans-serif;},namespaceuri:http: xhtml}]>这并非是个,非此即彼的问题。</span></span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf=""><span textstyle="" style="font-weight: bold;">这篇试图说清:</span></span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px 10px;max-width: 100%;min-height: 1em;color: rgb(43, 43, 43);text-align: justify;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;background-color: rgb(238, 253, 247);border-left: 10px solid #49c895;padding: 16px;border-right: 2px solid #6bdeb0;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf=""><span textstyle="" style="font-weight: normal;">如何将 Dify 作为主框架使用其 agent 和工作流组件,同时通过 API 调用 RAGFlow 的知识库组件。从而将 Dify 的用户友好界面和工作流能力与 RAGFlow 的深度文档处理能力结合起来。</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf=""><span textstyle="" style="font-size: 12px;color: rgb(136, 136, 136);">注:除了 Dify+RAGFlow 的组合外,也可以结合具体业务场景选择添加更多开源框架,如 LlamaIndex、LigthtRAG 等。</span></span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">以下,enjoy:</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(41, 148, 128);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;box-sizing: border-box !important;padding-left:4px;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">1</span></span></em></strong></p> <h2 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;font-family: PingfangSC-LIGHT,sans-serif;line-height: 9px;color: white;border-radius: 10px;background:linear-gradient(to right,rgb(41, 148, 128) 16.67%,rgb(73, 200, 149) 10%);"><span leaf=""> </span></h2> <p style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"> <jncounttag></jncounttag><span leaf="">从优势互补说起</span></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">1.1 </span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">Dify 的主要优势:</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">易用性高,无需花费大量时间阅读文档就能快速上手</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">快速部署,可在 30 分钟内部署原型</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">模块化设计,便于开发者进行二次开发</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">支持丰富的外部拓展工具和任务流编排,类似 Coze,但拓展性更好</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">跨知识库检索支持,能自动选择合适的知识库,这点 RAGFlow 目前不支持</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">1.2</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">RAGFlow 主要的优势</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">文件精细解析能力强,在处理 PDF、扫描件、表格等复杂文档方面表现出色</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">拥有 DeepDoc 技术,可以处理非结构化文档</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">支持 OCR、内置多种文档切分模板</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">对延迟敏感的应用时表现出色,可以轻松应对繁重的工作负载</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">1.3</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">优势互补的好处</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">通过 Dify+RAGFlow 的混合架构,可以实现如下好处:</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">利用 Dify 强大的工作流编排和 Agent 能力构建复杂应用</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">同时获得 RAGFlow 优秀的文档处理和解析能力</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">通过 API 集成保持系统的灵活性和可扩展性</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(41, 148, 128);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;box-sizing: border-box !important;padding-left:4px;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">2</span></span></em></strong></p> <h2 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;font-family: PingfangSC-LIGHT,sans-serif;line-height: 9px;color: white;border-radius: 10px;background:linear-gradient(to right,rgb(41, 148, 128) 33.33%,rgb(73, 200, 149) 10%);"><span leaf=""> </span></h2> <p style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"> <jncounttag></jncounttag><span leaf="">端口修改的准备工作</span></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">2.1</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">端口概念解析</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">在 Docker Compose 的端口映射中,格式为 A:B,其中 A 代表宿主机端口,B 代表容器内部端口。因此,80:80 表示宿主机的 80 端口映射到容器的 80 端口,443:443 则表示宿主机的 443 端口映射到容器的 443 端口。通常,容器中的 80 端口就是用来处理 HTTP 请求,而 443 端口处理 HTTPS 请求。</span></span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="502125841" data-ratio="0.6351851851851852" data-s="300,640" src="/upload/15d117a1f1f790301c03f88a7059646d.png" data-type="png" data-w="1080" type="block"> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">2.2</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">端口修改</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">RAGFlow 和 Dify 官方都推荐使用 Docker 部署,为了防止与 Dify 发生端口冲突,建议把 RAGFlow 的宿主机的端口修改为其他值,而保留容器端口不变。比如,可以将 80:80 改为 8080:80,即将原有的 80 端口映射改为 8080(宿主机)对 80(容器);同理,将 443:443 改为 8443:443。</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf=""><img class="rich_pages wxw-img" data-backh="280" data-backw="538" data-imgfileid="502125843" data-ratio="0.5208772669759595" data-s="300,640" src="/upload/3b8aa9970160a344e11504bb5e20fa60.jpg" data-type="png" data-w="2371" style="width:100%;" type="block"></span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">注意修改的是左侧的数字(宿主机端口),但要确保新端口未被其他程序占用。此外,修改后需要保存 docker-compose.yml 文件,并重启容器,使新配置生效。通常可以使用 docker-compose down 和 docker-compose up -d 重新启动服务。</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">这种方法可以确保你同时部署 Ragflow 和 Dify 时,不会出现宿主机端口冲突,同时内部服务依然使用原有的 HTTP/HTTPS 端口设置。</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf=""><span textstyle="" style="font-size: 12px;color: rgb(136, 136, 136);">注:有盆友可能会疑问 Ragflow 和 Dify 都有 Redis 服务,是否也需要对应修改 RAGFlow 的端口号。回答是不用的。Dify 的 Redis 仅仅在内部使用,即其 Redis 容器没有将服务端口映射到宿主机,因此仅供其它容器访问,不会与外部产生端口冲突。</span></span></span></p> <section> <span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">2.3</span></span></em></strong></span> </section> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">Dify启动命令修改</span></span></strong></span></strong></p> <section style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span leaf="" style="max-width: 100%;line-height: 28px;letter-spacing: 1px;font-size: 15px;font-family: PingfangSC-LIGHT, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">因为Docker Compose 使用项目名称来隔离不同的项目环境。 默认情况下,项目名称是docker-compose.yml文件所在目录的名称。由于Ragflow和Dify的docker-compose.yml目录的docker目录下,导致两个服务的容器未能被有效隔离,从而引发冲突。</span> </section> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="502125864" data-ratio="0.41203703703703703" data-s="300,640" src="/upload/191430586299c695b6d5448ccc3e68db.png" data-type="png" data-w="1080" type="block"> </section> <section> <span leaf="" style="font-size:15px;font-family:PingfangSC-LIGHT, sans-serif;letter-spacing:1px;">解决方案也很简单,RAGFlow基础docker服务启动方式不变。但是Dify启动时候要通过﹣p参数显式指定项目名称。参考图示中的docker compose -p dify_docker up -d。</span> </section> <section> <span leaf=""><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="502125842" data-ratio="0.3015625" data-s="300,640" src="/upload/fbb0cd3b86f5c237a8cf291603b08eda.png" data-type="png" data-w="1280" type="block"></span> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">2.4</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">修改验证</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">在浏览器中访问 http://localhost:8080 ,检査 RAGFlow 是否正常运行。如果服务正常启动,你应该能够看到 RAGFlow 的 Web 界面。 完成以上步骤后,RAGFlow 的默认端口将从 80 修改为 8080。</span></span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="502125844" data-ratio="0.6944444444444444" data-s="300,640" src="/upload/b0f367ee6a63c1bffd8bdfe0e49ea8a2.png" data-type="png" data-w="1080" type="block"> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">需要注意的是,在我上篇介绍的在 RAGFlow 中通过图片服务器容器化实现问答中渲染本地图片的脚本,因为上述修改的 RAGFlow 端口号,所以需要修改 ragflow_build.py中初始化 RAGFlow 客户端的代码,默认 base_url 参数是"http://localhost" , 没有指定端口号。由于已将原来的 80 端口映射修改为 8080:80,现在需要相应更新 base_url 参数。</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf=""><a style="" href="https://mp.weixin.qq.com/s?__biz=MzI1ODIxNjk1OQ==&mid=2649609485&idx=1&sn=50d60efc5aac3f33226f8ce51a999ddc&scene=21#wechat_redirect" textvalue="RAGFlow如何实现图片问答:原理分析+详细步骤(附源码)" data-itemshowtype="0" target="_blank" linktype="text" data-linktype="2">RAGFlow如何实现图片问答:原理分析+详细步骤(附源码)</a> </span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="502125845" data-ratio="0.4061433447098976" data-s="300,640" src="/upload/8a5491d4e8d48a0892b0c62bf99a24a5.png" data-type="png" data-w="879" type="block"></span></span></p> <section style="text-align: center;"> <span style="max-width: 100%;line-height: 28px;letter-spacing: 1px;font-size: 15px;font-family: PingfangSC-LIGHT, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span leaf="" data-pm-slice="1 1 [" para,{tagname:p,attributes:{label:converted by knb formatter from jason ng https: knb.im mp,style:margin: 20px; max-width: 100%; min-height: 1em; white-space: pre-wrap; color: rgb(43, 43, 43); text-align: justify; line-height: 1.5; box-sizing: border-box !important; word-wrap: break-word !important;},namespaceuri:http: www.w3.org 1999 xhtml},node,{tagname:span,attributes:{style:max-width: 28px; letter-spacing:1px; font-size:15px; font-family: pingfangsc-light,sans-serif;},namespaceuri:http: xhtml}]><span textstyle="" style="font-size: 14px;color: rgb(136, 136, 136);font-weight: normal;">需要查看源代码的请移步知识星球,加入后请后台私信我进会员群。</span></span></span> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(41, 148, 128);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;box-sizing: border-box !important;padding-left:4px;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">3</span></span></em></strong></p> <h2 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;font-family: PingfangSC-LIGHT,sans-serif;line-height: 9px;color: white;border-radius: 10px;background:linear-gradient(to right,rgb(41, 148, 128) 50%,rgb(73, 200, 149) 10%);"><span leaf=""> </span></h2> <p style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"> <jncounttag></jncounttag><span leaf="">详细操作步骤</span></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">3.1</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">URL 配置注意</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">在 Dify 中配置 RAGFlow 的知识库时,需要在 RAGFlow 的基础 Base url 后增加 “api/v1/dify”,这是 Dify 特定的 API 路径,它承担版本控制、模块划分等作用。当然这也很符合 RESTful 的设计思想。</span></span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="502125847" data-ratio="0.3387241689128482" data-s="300,640" src="/upload/5041fd9d66dbcd11f6b45a1bb1ec98cd.png" data-type="png" data-w="1113" type="block"> </section> <section style="text-align: center;" nodeleaf=""> <img src="/upload/2b96a511ce686ec7fdd96e738d15189a.png" class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.4740740740740741" data-s="300,640" data-type="png" data-w="1080" type="block" data-imgfileid="502125846"> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">3.2</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">创建知识库</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">完成 Dify 和 RAGFlow 的 API 连接之后,就可以紧接着创建知识库,需要注意的是,需要点击的是“连接外部知识库”这个按钮。下一步会提示需要输入外部知识库 ID,这个信息需要在大家 RAGFlow 对应的知识库页面,在浏览器的地址后缀上能看到完整的 ID 数字,直接复制过来填下。</span></span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="502125848" data-ratio="0.2851851851851852" data-s="300,640" src="/upload/943230e54f2dc7eef256e3f499e55d9b.png" data-type="png" data-w="1080" type="block"> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">3.3</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">连通测试</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">在创建完知识库后,可以大家这个知识库进行召回测试,这个类似 RAGFlow 的检索测试功能,主要是为了检验下上述的两步配置是否成功。需要注意的是,在这一步还不需要配置 LLM 即可进行测试。</span></span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" src="https://mmbiz.qpic.cn/mmbiz_png/3OZeSOuRw3eEp4CEIlzyoasqmiaAtd21ibGKPNdNGcMbicm0AicwsiciaL3y387liaXWn87piadVyHl3nBZR8X8M9oek1w/0?wx_fmt=png&from=appmsg" data-cropx2="1280" data-cropy2="367.61245674740485" data-imgfileid="502125849" data-ratio="0.28671875" data-s="300,640" src="/upload/d90490baff65644d96da1ba9f2b1f51a.jpg" data-type="png" data-w="1280" style="width:578px;height:166px;" type="block"> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">3.4</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">模型供应商配置</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">在创建具体的 ChatBot 之前,我们需要现在设置页面配置 LLM 的来源。这里既可以选择 Ollama 本地部署的模型,也可以直接选择商业 API。</span></span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="502125851" data-ratio="0.4740740740740741" data-s="300,640" src="/upload/7496372c26d6bdd8acd14542011ca1a2.png" data-type="png" data-w="1080" type="block"> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">这里需要提示的是,为了后续更好进行分块和检索策略的调优,如果你的电脑上没有部署</span><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="" data-pm-slice="1 1 [" para,{tagname:p,attributes:{label:converted by knb formatter from jason ng https: knb.im mp,style:margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;},namespaceuri:http: www.w3.org 1999 xhtml},node,{tagname:span,attributes:{style:max-width: 100%;line-height: 28px;box-sizing: !important;letter-spacing:1px;font-size:15px;font-family: pingfangsc-light,sans-serif;},namespaceuri:http: xhtml}]>DeepSeek-R1-Distill-Qwen-32B或同等水平的开源模型,建议这一步还是先用商业 API。</span></span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">3.5</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">创建 ChatBot</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">这一步很简单,就是输入系统提示词,绑定上述的第二步创建的知识库,再在右上角选择使用的相关模型即可进行问答测试。我这里为了测试效果,输入的提示词和 RAGFlow 中的保持一致,大家可以做个参考。单就 ChatBot 功能,初步测试下来准确率没有明显差别,图片也能正常显示。</span></span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="502125852" data-ratio="0.4740740740740741" data-s="300,640" src="/upload/660cdd950f3c20d95792f3182152d6ee.png" data-type="png" data-w="1080" type="block"> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">但有所不同的是,Dify 中的 ChatBot 提供了更丰富的配置选项。比如为了测试不同问答模型的回答效果,可以同时添加多个 LLM 进行同一个问题的对比回答。但是这个入口其实有点小深,各位参考图示操作。</span></span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" src="https://mmbiz.qpic.cn/mmbiz_png/3OZeSOuRw3eEp4CEIlzyoasqmiaAtd21ibIyzOoh2pTQ8DS8pPGiayVb0uNNZ0HXfDPOSxRT6e8u1r9JIgUEqialdg/0?wx_fmt=png&from=appmsg" data-cropx2="1260.0692041522493" data-cropy2="403.044982698962" data-imgfileid="502125856" data-ratio="0.3198412698412698" data-s="300,640" src="/upload/88c6a4d0a70f71047795c24124bcbb64.jpg" data-type="png" data-w="1260" style="width:569px;height:182px;" type="block"> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">我这里是测试了 DeepSeek-R1-Distill-Qwen-32B 和 Qwen2.5-32B-Instruct 两个模型,测试了几个问题后,回答速度和效果基本没有明显差别,都还够用。</span></span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="502125853" data-ratio="0.4740740740740741" data-s="300,640" src="/upload/a35c8c35d12abad9e6b5dcffa5ebd1bb.png" data-type="png" data-w="1080" type="block"> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">这里也解释下为啥要用这两个开源模型,虽然我并不推荐中小企业在 POC 阶段刚过早的做 LLM 的本地化部署,但是实际真的要部署这两个尺寸的开源模型也基本够用了。所以我日常在给一些企业方做项目 Demo 的时候也会倾向于直接使用这两款来进行测试,从而保证实际本地部署后的效果一致性。</span></span></p> <section style="text-align: center;" nodeleaf=""> <img src="/upload/6cb1cb3e02b0f7bdb5b419385cfac1fb.png" class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.4740740740740741" data-s="300,640" data-type="png" data-w="1080" type="block" data-imgfileid="502125854"> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">另外这个 ChatBot 还有个特性是,你可以根据业务需求增加更多的个性化功能,例如 Conversation Opener、Follow-up、Text to Speech、Speech to Text 等,具体大家可以自行测试。需要说明的是,Citations and Attributions 这个回答的出处引用是默认打开的。</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(41, 148, 128);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;box-sizing: border-box !important;padding-left:4px;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">4</span></span></em></strong></p> <h2 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;font-family: PingfangSC-LIGHT,sans-serif;line-height: 9px;color: white;border-radius: 10px;background:linear-gradient(to right,rgb(41, 148, 128) 66.67%,rgb(73, 200, 149) 10%);"><span leaf=""> </span></h2> <p style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"> <jncounttag></jncounttag><span leaf="">创建工作流</span></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">Dify 中 Studio 模块提供了 Chatbot、Agent、Completion、Chatflow、Workflow 等多种选择,然后在工作流中又包含了很多 Blocks 和 tools 的选项,这些看起来似乎让人眼花缭乱。</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">4.1</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">应用类型比较</span></span></strong></span></strong></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="502125855" data-ratio="0.24074074074074073" data-s="300,640" src="/upload/354baf90dc3c5d39b90572c51ce93b68.png" data-type="png" data-w="1080" type="block"> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Chatbot</span></strong><span leaf="">:基础聊天助手,适合简单的问答交互</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Chatflow</span></strong><span leaf="">:面向对话类情境,支持多步逻辑和对话历史记忆,包括客户服务、语义搜索等场景</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Workflow</span></strong><span leaf="">:面向自动化和批处理场景,适合高质量翻译、数据分析、内容生成、电子邮件自动化等</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Agent</span></strong><span leaf="">:智能助手,能自主对复杂任务进行规划、拆解、工具调用和迭代</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">Chatflow 相比 Workflow 增加了对话特性支持,如对话历史记忆、标注回复和 Answer 节点等。Workflow 则专注于复杂业务逻辑处理,提供丰富逻辑节点和定时/事件触发能力。</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">4.2</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">功能块(Block)解析</span></span></strong></span></strong></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="502125858" data-ratio="0.47685185185185186" data-s="300,640" src="/upload/5235e8ecb161edfbba9b780bd8a7c261.png" data-type="png" data-w="1080" type="block"> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">LLM</span></strong><span leaf="">:核心处理节点,利用大语言模型处理各类任务</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Knowledge Retrieval</span></strong><span leaf="">:从知识库检索与用户问题相关的内容</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Answer</span></strong><span leaf="">:定义回复内容的格式和展示</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Agent</span></strong><span leaf="">:智能助手节点,可自主规划和执行任务</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Question Understand</span></strong><span leaf="">:理解用户意图</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Question Classifier</span></strong><span leaf="">:对问题进行分类,引导不同处理逻辑</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">IF/ELSE</span></strong><span leaf="">:条件分支节点,基于条件将工作流分为两个分支</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Iteration/Loop</span></strong><span leaf="">:循环处理节点</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Code</span></strong><span leaf="">:执行自定义代码逻辑的节点</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Template</span></strong><span leaf="">:使用 Jinja2 模板进行数据转换</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Variable Aggregator</span></strong><span leaf="">:聚合多分支变量</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">Parameter Extractor</span></strong><span leaf="">:从自然语言提取结构化参数</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">4.3</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">工具(Tool)组件解析</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf=""><img src="/upload/252de6300542c4329bb25356c983b8a4.png" class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.47421875" data-s="300,640" data-type="png" data-w="1280" type="block" data-imgfileid="502125859"></span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">第一方工具</span></strong><span leaf="">:Dify 生态提供的内置工具,如 Audio、Code Interpreter、CurrentTime、WebScraper 等</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><strong style="background: linear-gradient(to right,rgb(73, 200, 149),rgb(38, 198, 218));color: white;white-space: pre-wrap;border-width: 0.25em 0;display: inline;font-weight: normal;padding: 2px 4px 2px 4px;"><span leaf="">自定义工具</span></strong><span leaf="">:可导入符合 OpenAPI/Swagger 或 OpenAI Plugin 规范的自定义 API 工具</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">这些工具可以扩展 LLM 的能力,如联网搜索、科学计算、绘图等,使 AI 应用能连接外部世界。通过自定义工具,还可以实现内容审查、敏感词过滤等功能。有一说一,自定义工具这个很强,后续我考虑专门出一期内容介绍这个。</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(41, 148, 128);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;box-sizing: border-box !important;padding-left:4px;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">5</span></span></em></strong></p> <h2 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;font-family: PingfangSC-LIGHT,sans-serif;line-height: 9px;color: white;border-radius: 10px;background:linear-gradient(to right,rgb(41, 148, 128) 83.33%,rgb(73, 200, 149) 10%);"><span leaf=""> </span></h2> <p style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"> <jncounttag></jncounttag><span leaf="">工作流应用示例</span></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">泵作为工厂常见通用设备,其突发故障往往会导致整条生产线停摆,造成重大经济损失。下面介绍一个我近期实施过的泵类设备预测性维护智能系统,其中充分利用了 Dify 的各种功能模块和工具节点,整合静态知识库、MCP 链接外部数据源、问答分类和维保报告生成功能。</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">5.1</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">系统架构图</span></span></strong></span></strong></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="diff"><code><span leaf=""><span class="code-snippet__addition">+----------------------------------+</span></span></code><code><span leaf="">| 用户界面层 |</span></code><code><span leaf="">| Web界面 | 移动App | 企业微信集成 |</span></code><code><span leaf=""><span class="code-snippet__addition">+----------------------------------+</span></span></code><code><span leaf=""> |</span></code><code><span leaf=""><span class="code-snippet__addition">+----------------------------------+</span></span></code><code><span leaf="">| Dify核心平台层 |</span></code><code><span leaf="">| 工作流编排 | Agent | RAG | 知识库 |</span></code><code><span leaf=""><span class="code-snippet__addition">+----------------------------------+</span></span></code><code><span leaf=""> | |</span></code><code><span leaf=""><span class="code-snippet__addition">+----------------+ +------------------+</span></span></code><code><span leaf="">| MCP连接层 | | 外部系统集成 |</span></code><code><span leaf="">| 数据收集接口 | | ERP | MES | CMMS |</span></code><code><span leaf=""><span class="code-snippet__addition">+----------------+ +------------------+</span></span></code><code><span leaf=""> |</span></code><code><span leaf=""><span class="code-snippet__addition">+----------------------------------+</span></span></code><code><span leaf="">| 设备物联网层 |</span></code><code><span leaf="">| 振动传感器 | 温度传感器 | 压力传感器 |</span></code><code><span leaf=""><span class="code-snippet__addition">+----------------------------------+</span></span></code></pre> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">5.2</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">工作流程设计</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 16px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">A. 状态监控工作流</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">该工作流通过传感器持续监控泵的振动、温度、压力等参数,使用 IF/ELSE 节点对异常状态进行判断,发现异常时触发告警。 </span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 16px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">B. 故障预测工作流</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">将收集的数据与历史故障模式进行比对,使用 LLM 和 Knowledge Retrieval 节点分析数据趋势,预测可能的故障时间和类型。 </span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 16px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">C. 维保建议工作流</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">根据预测结果,生成具体的维护建议和计划,包括所需备件、维修时长和最佳维修时间窗口,通过 Template 节点生成标准化工单。</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 16px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">D. 闭环反馈工作流</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">收集实际维修结果与预测的对比,通过 Agent 节点分析差异并不断优化模型,形成闭环反馈,持续提升预测准确性。 </span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><span style="margin-left: 10px;max-width: 100%;color: rgb(26, 149, 165);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;padding-left:4px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">5.3</span></span></em></strong></span></p> <h3 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;line-height: 5px;background:linear-gradient(to right,rgb(26, 149, 165) ,rgb(38, 198, 218));"><span leaf=""> </span></h3> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(137, 137, 137);font-size: 18px;line-height: 1.5;white-space: normal;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">关键节点配置示例</span></span></strong></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">设备状态监控节点配置:</span></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="bash"><code><span leaf="">- HTTP Request节点:</span></code><code><span leaf=""> 接口URL: http://iot-platform/api/pump/status</span></code><code><span leaf=""> 参数: {<span class="code-snippet__string">"pumpId"</span>: <span class="code-snippet__string">"{{pumpId}}"</span>, <span class="code-snippet__string">"timeRange"</span>: <span class="code-snippet__string">"{{timeRange}}"</span>}</span></code><code><span leaf=""><br></span></code><code><span leaf="">- Code节点(数据处理):</span></code><code><span leaf=""> 处理振动、温度等数据,计算偏差值</span></code><code><span leaf=""><br></span></code><code><span leaf="">- IF/ELSE节点:</span></code><code><span leaf=""> 条件: vibration > threshold || temperature > <span class="code-snippet__built_in">limit</span></span></code><code><span leaf=""> 是分支: 触发告警流程</span></code><code><span leaf=""> 否分支: 正常记录数据</span></code></pre> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">故障预测 LLM 节点提示词:</span></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="makefile"><code><span leaf=""><span class="code-snippet__section">系统提示: 你是一位专业的泵类设备故障预测专家。根据以下设备参数和历史数据,分析可能存在的故障风险,预测故障类型和可能的发生时间。</span></span></code><code><span leaf=""><br></span></code><code><span leaf=""><span class="code-snippet__section">用户输入: </span></span></code><code><span leaf=""><span class="code-snippet__section">设备ID: {{pumpId}}</span></span></code><code><span leaf=""><span class="code-snippet__section">当前振动值: {{vibration}}</span></span></code><code><span leaf=""><span class="code-snippet__section">当前温度: {{temperature}}</span></span></code><code><span leaf=""><span class="code-snippet__section">当前压力: {{pressure}}</span></span></code><code><span leaf=""><span class="code-snippet__section">历史故障模式: {{historyFailures}}</span></span></code></pre> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">维保报告生成节点:</span></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="css"><code><span leaf="">- Template节点:</span></code><code><span leaf=""> 设备巡检报告</span></code><code><span leaf=""> 设备ID: {{pumpId}}</span></code><code><span leaf=""> 巡检时间: {{inspectionTime}}</span></code><code><span leaf=""><br></span></code><code><span leaf=""> 设备状态: {{status}}</span></code><code><span leaf=""> 预测寿命: {{remainingLife}}</span></code><code><span leaf=""><br></span></code><code><span leaf=""> 异常项:</span></code><code><span leaf=""> {% for issue in issues %}</span></code><code><span leaf=""> - {{issue<span class="code-snippet__selector-class">.name</span>}}: {{issue<span class="code-snippet__selector-class">.description</span>}}</span></code><code><span leaf=""> {% endfor %}</span></code><code><span leaf=""><br></span></code><code><span leaf=""> 维护建议:</span></code><code><span leaf=""> {{maintenanceSuggestions}}</span></code><code><span leaf=""><br></span></code><code><span leaf=""> 下次计划维护时间: {{nextMaintenanceDate}}</span></code></pre> </section> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="line-height: 25.6px;min-height: 1em;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(62, 62, 62);box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(41, 148, 128);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 24px;box-sizing: border-box !important;padding-left:4px;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"><span leaf="">6</span></span></em></strong></p> <h2 label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin-top: -10px;font-family: PingfangSC-LIGHT,sans-serif;line-height: 9px;color: white;border-radius: 10px;background:linear-gradient(to right,rgb(41, 148, 128) 100%,rgb(73, 200, 149) 10%);"><span leaf=""> </span></h2> <p style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(137, 137, 137);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(62, 62, 62);line-height: 25.6px;min-height: 1em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 20px;box-sizing: border-box !important;word-wrap: break-word !important;font-family: PingFangSC-Semibold,sans-serif;"> <jncounttag></jncounttag><span leaf="">写在最后</span></span></strong></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">RAG 自从 2020 年由 Meta 提出,23 年春 Nvidia GTC 大会后火热之后,一直面临着来自“微调”和“长上下文 LLM”的对比争议。不过两年下来,共识已经基本形成:</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: justify;line-height: 1.5;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;box-sizing: border-box !important;word-wrap: break-word !important;letter-spacing:1px;font-size:15px;font-family: PingfangSC-LIGHT,sans-serif;"><span leaf="">一方面是从成本和实时性角度,RAG 具有压倒性优势,而效果上相差也并不大,即使需要微调介入的场景,RAG 通常也不可或缺。另一方面,长上下文 LLM 依然面临在上下文段落增加时准确率不断下降的事实。所以,在任何情况下,提供高精度的搜索系统(RAG)都是极有价值的,RAG 当前也已经是一种事实上的落地标准架构。</span></span></p> <p label="Converted by KNB Formatter from Jason Ng https://knb.im/mp" style="margin: 20px;max-width: 100%;min-height: 1em;white-space: pre-wrap;color: rgb(43, 43, 43);text-align: left;line-height: 1.5;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;line-height: 28px;letter-spacing: 1px;font-size: 15px;font-family: PingfangSC-LIGHT, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span leaf="">RAG技术目前正处于快速发展期,各垂直场景的最佳实践仍待探索。欢迎在一线参与实践的盆友加入我的知识星球,和各行业的积极行动者们一起交流学习。<img class="rich_pages wxw-img" data-imgfileid="502125703" data-ratio="0.4542124542124542" data-s="300,640" src="/upload/6b0955be81e42a40c8cc94764efb3812.jpg" data-type="jpeg" data-w="819" type="block"></span></span></p> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<p data-pm-slice="0 0 []" style="text-indent: 2em;"><span leaf=""><span textstyle="" style="font-size: 17px;">最好的学习时间是昨天,其次是现在。清明节的第一天,窗外春风拂面,阳光洒满大地,大家是不是已经迫不及待想放松一下心情了?不如趁着假期,我们一起来聊聊RAG!如果你已经完全掌握了RAG原理,请帮我看看我讲的和你理解的是否一致。</span></span><span style="white-space: pre-wrap;"><span leaf=""><span textstyle="" style="font-size: 17px;">最近,像 coze 和 dify 这样的低代码平台把 RAG 功能做得越来越亲民,但想要真正玩转它,搞清楚背后的流程可是关键,不做</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">文档搬运工</span></span><span style="white-space: pre-wrap;"><span leaf=""><span textstyle="" style="font-size: 17px;">。今天,我就带你一步步拆解 RAG 系统,用最轻松的方式告诉你,它是怎么让大语言模型(LLM)变得更聪明、更贴心的。</span></span></span></p> <p><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100003402" data-ratio="0.4185185185185185" src="/upload/ce26d670467ff535f3e9622f120a04a7.png" data-type="png" data-w="1080"></span><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><br></span></span></p> <h2><b><span leaf=""><br></span></b></h2> <h2><b><span leaf=""><span textstyle="" style="font-size: 20px;">一、RAG系统:智能问答的秘密武器</span></span></b></h2> <p style="text-indent: 2em;"><span style="white-space: pre-wrap;"><span leaf=""><span textstyle="" style="font-size: 17px;">RAG 系统是什么?简单来说,它就像一个超级能干的“知识管家”:一边从海量的外部资料里翻出你需要的“干货”,一边用大语言模型的“语言魔法”把这些干货整理成清晰、自然的回答。RAG 的魅力——“检索+生成”双剑合璧,让智能问答不再是冷冰冰的机器回复,而是温暖又靠谱的对话体验。</span></span></span><span style="color: unset;font-family: unset;font-size: unset;"><span leaf=""><span textstyle="" style="font-size: 17px;">接下来,我们就来拆开 RAG 的“魔法书”,看看它到底是怎么一步步施展魔法的。</span></span></span></p> <p><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100003401" data-ratio="0.5851851851851851" src="/upload/e6c5af35d27025736732c6fb34ca1479.png" data-type="png" data-w="1080"></span></p> <h2><b><span leaf=""><br></span></b></h2> <h2><b><span leaf=""><span textstyle="" style="font-size: 20px;">二、RAG系统的核心环节</span></span></b></h2> <p style="text-indent: 2em;"><span style="white-space: pre-wrap;"><span leaf=""><span textstyle="" style="font-size: 17px;">简单来说,RAG 系统就是一种“检索+生成”的组合拳。它能从海量的外部知识中挖出有用的信息,再借助大语言模型的语言天赋,把这些信息整理成清晰、自然的回答。想象一下,它就像一个知识渊博又会讲故事的朋友,既能找到你需要的内容,还能用最舒服的方式讲给你听。</span></span></span></p> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">下面,我们就来拆解 RAG 系统的工作流程,看看每个环节是怎么串起来的。</span></span></span></p> <h3><b><span leaf=""><span textstyle="" style="font-size: 17px;">1. 文本分块:把大书拆成小页</span></span></b></h3> <p><b><span leaf=""><img src="/upload/cacc5fea32defb7c097d9992a7ee13dc.png" class="rich_pages wxw-img" data-ratio="0.2685589519650655" data-type="png" data-w="916" data-imgfileid="100003399"></span></b></p> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">假设你有一本超级厚的书,里面全是知识,但每次查东西都要翻完整本书,太麻烦了。所以,第一步就是把这本书拆成一页一页的小块,也就是“文本分块”。</span></span></span></p> <p><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100003398" data-ratio="0.23846153846153847" src="/upload/d6804506e45b5923cf185726bfcfc43f.png" data-type="png" data-w="910"></span><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><br></span></span></p> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><b><span leaf=""><span textstyle="" style="font-size: 17px;">为什么要这么做呢?有三个原因:</span></span></b></span></p> <ul class="list-paddingleft-1"> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">文档太大不好处理</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">:有些资料可能有几百页,直接扔进去分析,电脑也吃不消。</span></span></p></li> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">模型有长度限制</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">:就像我们吃饭得一口一口来,嵌入模型也只能一次处理有限的文字量。</span></span></p></li> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">方便找重点</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">:如果整本书只有一个标签,查东西时就很难精准找到相关内容。</span></span></p></li> </ul> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">所以,文本分块就像是给知识“切片”,让后续步骤更顺利。</span></span></span></p> <h3><b><span leaf=""><span textstyle="" style="font-size: 17px;">2. 生成嵌入:给每页书贴上“标签”</span></span></b></h3> <p><b><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100003400" data-ratio="0.381936887921654" src="/upload/88c32f72eb8464520833eb84d1fd0808.png" data-type="png" data-w="919"></span></b></p> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">分好块之后,我们需要给每个文本块贴上一个特殊的“标签”,这个标签其实是一串数字,叫“嵌入向量”。生成这个向量的工具就是嵌入模型,它能把文字的意思浓缩成数字形式。</span></span></span></p> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">举个例子,这就像给每页书打上一个独一无二的“指纹”,通过这个指纹,我们就能快速判断这页书讲的是什么。后面找资料的时候,靠这些指纹就能快速匹配。</span></span></span></p> <h3><b><span leaf=""><span textstyle="" style="font-size: 17px;">3. 向量数据库存储:建一个“记忆仓库”</span></span></b></h3> <p><b><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100003407" data-ratio="0.484118291347207" src="/upload/81dd6e2ba385f2452e7df283060398c3.png" data-type="png" data-w="913"></span></b></p> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">有了这些数字指纹,我们得找个地方存起来,这就用到了向量数据库。你可以把它想象成 RAG 系统的“记忆仓库”,里面装满了所有文本块的指纹和原始内容。</span></span></span></p> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">这个仓库不只是个储物柜,它还能随时接收新资料,保持知识的更新。以后用户提问时,系统就会从这里翻出最相关的“记忆”来回答。</span></span></span><span style="color: unset;font-family: unset;font-size: unset;"><span leaf=""><span textstyle="" style="font-size: 17px;">向量数据库里不仅存了数字指纹,还保留了原始文本和一些附加信息,方便随时调用。</span></span></span></p> <h3><b><span leaf=""><span textstyle="" style="font-size: 17px;">4. 用户输入查询:提问时间到!</span></span></b></h3> <p><b><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100003403" data-ratio="0.3277027027027027" src="/upload/5b00f07e15c6842f831232fff01e8517.png" data-type="png" data-w="888"></span></b></p> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">好了,准备工作做完了,现在轮到用户上场了。用户输入一个问题,比如“RAG 系统是啥?”——这就正式开启了查询阶段。</span></span></span></p> <h3><b><span leaf=""><span textstyle="" style="font-size: 17px;">5. 查询向量化:问题也得有“指纹”</span></span></b></h3> <p><b><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100003404" data-ratio="0.2931937172774869" src="/upload/4775fab27096fbb3634fc43026d4ccce.png" data-type="png" data-w="955"></span></b></p> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">为了找到答案,我们得把用户的问题也变成数字指纹。用的还是那个嵌入模型,这样问题和数据库里的文本块就有了“共同语言”,可以互相匹配了。</span></span></span></p> <h3><b><span leaf=""><span textstyle="" style="font-size: 17px;">6. 检索相似块:翻出最相关的资料</span></span></b></h3> <p><b><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100003406" data-ratio="0.4102272727272727" src="/upload/45c5dc988320fdb93e48c24539c54ccf.png" data-type="png" data-w="880"></span></b></p> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">接下来,系统会拿着问题的指纹,在向量数据库里找“最像”的文本块。</span></span></span></p> <p><span leaf=""><img src="/upload/41c600122604fff4b205f373e8b96b81.png" class="rich_pages wxw-img" data-ratio="0.44685466377440347" data-type="png" data-w="922" data-imgfileid="100003405"></span><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><br></span></span></p> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">具体来说,它会挑出 K 个最相似的块(K 是提前设好的数量),这些块里很可能藏着问题的答案。这一步通常会用一种叫“近似最近邻搜索”的方法,速度快得像闪电。</span></span></span></p> <h3><b><span leaf=""><span textstyle="" style="font-size: 17px;">7. 结果重排序(可选):再精挑细选一下</span></span></b></h3> <p><b><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100003408" data-ratio="0.3557692307692308" src="/upload/9e56bbff66181acc71dcc08833e06a44.png" data-type="png" data-w="936"></span></b></p> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">有时候,为了让答案更靠谱,系统会对找出来的文本块再排个序。这就像从一堆答案里挑出最贴切的几个,通常会用更厉害的模型(比如交叉编码器)来打分排序。不过,不是所有 RAG 系统都会这么做,很多直接用上一步的相似度结果就够了。</span></span></span></p> <section class="mp_common_product_iframe_wrp" nodeleaf=""> <mp-common-product data-windowproduct="v2=HCOrtyVbdzOL6MsOVNk6GNSwCZuq9XpHGMbCuD79ejOlknKYxTt6FghMlsPiUP4fdA" data-customstyle="{" display:block,height:169px} data-cardtype="1" data-title="智能体设计指南:成为提示词高手和AI Agent设计师" data-type="1"></mp-common-product> </section> <h3><b><span leaf=""><span textstyle="" style="font-size: 17px;">8. 生成最终响应:答案新鲜出炉</span></span></b></h3> <p><b><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100003409" data-ratio="0.3333333333333333" src="/upload/0f7adc5689f68d8cadfc48c007f8ac72.png" data-type="png" data-w="918"></span></b></p> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">最后,把挑好的文本块交给大语言模型。模型会根据一个模板,把用户的问题和这些资料糅合在一起,生成一个既准确又自然的回答。整个过程就像厨师炒菜,原料是检索来的知识,火候是大语言模型的语言功底,最后端上桌的就是一道美味的答案。</span></span></span><span leaf=""><br></span></p> <p><b style="color: unset;font-family: unset;font-size: unset;"><span leaf=""><br></span></b></p> <p><b style="color: unset;font-family: unset;font-size: unset;"><span leaf=""><span textstyle="" style="font-size: 20px;">三、总结</span></span></b><span leaf=""><br></span></p> <p style="text-indent: 2em;"><span style="white-space: pre-wrap;"><span leaf=""><span textstyle="" style="font-size: 17px;">看完这8个步骤,RAG 系统的全貌是不是清晰多了</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">它通过文本分块、嵌入生成、向量存储和检索生成这几步,把外部知识和大语言模型的能力完美结合了起来。结果呢?用户不仅能得到答案,还能收获更全面、更贴心的信息。</span></span></p> <h4><span leaf=""><span textstyle="" style="font-size: 17px;font-weight: bold;">RAG的三大杀手锏</span></span></h4> <ul class="list-paddingleft-1"> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">知识新鲜</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">:随时更新数据库,答案永远不过时。</span></span></p></li> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">回答靠谱</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">:检索机制确保不胡说八道。</span></span></p></li> <li><p><span style="font-weight: bold;"><span leaf=""><span textstyle="" style="font-size: 17px;">用途超广</span></span></span><span leaf=""><span textstyle="" style="font-size: 17px;">:智能客服、学习助手,哪儿都能用!</span></span></p></li> </ul> <p><span style="white-space: pre-wrap;-en-paragraph:true;"><span leaf=""><span textstyle="" style="font-size: 17px;">希望下次聊到智能问答,你也能拍胸脯说:“这我熟!”,你不仅会操作还能讲原理。</span></span></span></p> <p style="display: none;"> <mp-style-type data-value="10000"></mp-style-type></p>
作者:微信小助手
<p style="margin-bottom: 0px;"><span style=""><span leaf="">点击上方🔺公众号🔺关注我✅</span></span></p> <p style="margin-bottom: 0px;"><span style=""><span leaf=""><br></span></span></p> <p style="margin-bottom: 0px;"><span style=""><span leaf="">您好,我是小白。见字如面。衷心感谢您的阅读,期待我们的下一次邂逅。</span></span></p> <p style="margin-bottom: 0px;"><span style=""><span leaf=""><br></span></span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001244" data-s="300,640" src="/upload/fa4ecdb858675815c7c5b266013da416.png" data-type="png" type="block"> </section> <section style=" line-height: 1.8;font-size: 15px;text-align: left; ; "> <h2 style="font-size: 22px;background: linear-gradient(45deg, #4299e1, #667eea);-webkit-background-clip: text;-webkit-text-fill-color: transparent;margin: 24px 0 12px;font-weight: bold;color: #4299e1;"><span leaf="">一、旅行规划的痛点:太折磨人了!</span></h2> <p style="font-size: 15px;color: #4a5568;margin: 20px 0;line-height: 1.8;"><span leaf="">每次计划旅行时,你是不是也这样?</span></p> <ul style="font-size: 15px;list-style: disc;padding-left: 2em;margin-bottom: 16px;" class="list-paddingleft-1"> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">打开十几个浏览器标签页,攻略看到怀疑人生</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">在小红书翻4小时,看得眼花缭乱</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">好不容易定下景点,又要考虑交通、天气、餐饮...</span> </section></li> </ul> <p style="font-size: 15px;color: #4a5568;margin: 20px 0;line-height: 1.8;"><span leaf=""><span textstyle="" style="font-weight: bold;">好消息来了!</span>现在用AI+高德地图MCP,10分钟就能生成一份完美行程,包含天气、景点、餐饮、交通等所有信息!</span></p> <h2 style="font-size: 22px;background: linear-gradient(45deg, #4299e1, #667eea);-webkit-background-clip: text;-webkit-text-fill-color: transparent;margin: 24px 0 12px;font-weight: bold;color: #4299e1;"><span leaf="">二、神器初体验:云南一日游案例</span></h2> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001245" data-s="300,640" src="/upload/7bd8b36f1da30aa1959908c76a93c821.png" data-type="png" type="block"> </section> <p style="font-size: 15px;color: #4a5568;margin: 20px 0;line-height: 1.8;"><span leaf="">我昨天用这个工具做了份上海一日游攻略,朋友们看到后都疯狂求教程!来看看它能做什么:</span></p> <ol style="font-size: 15px;list-style: decimal;padding-left: 2em;margin-bottom: 16px;" class="list-paddingleft-1"> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"><strong style="color: #4299e1;font-weight: bold;"><span leaf="">实时地理数据</span></strong> <section> <span leaf="">精确计算景点间距离和最优路线</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"><strong style="color: #4299e1;font-weight: bold;"><span leaf="">天气自适应</span></strong> <section> <span leaf="">遇到下雨天?自动调整为室内方案!</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"><strong style="color: #4299e1;font-weight: bold;"><span leaf="">一站式规划</span></strong> <section> <span leaf="">游玩地点+吃饭地点+交通方式全搞定</span> </section></li> </ol> <h2 style="font-size: 22px;background: linear-gradient(45deg, #4299e1, #667eea);-webkit-background-clip: text;-webkit-text-fill-color: transparent;margin: 24px 0 12px;font-weight: bold;color: #4299e1;"><span leaf="">三、四步上手教程:小白也能轻松学会</span></h2> <h3 style="font-size: 18px;background: linear-gradient(45deg, #4299e1, #667eea);-webkit-background-clip: text;-webkit-text-fill-color: transparent;margin: 20px 0 10px;font-weight: bold;color: #4299e1;"><span leaf="">第一步:获取高德地图MCP授权(免费)</span></h3> <ol style="font-size: 15px;list-style: decimal;padding-left: 2em;margin-bottom: 16px;" class="list-paddingleft-1"> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">访问高德开放平台官网</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">用支付宝扫码登录并完成身份验证</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">创建新应用(类型选"出行")</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">添加Web服务Key(相当于门禁卡)</span> </section></li> </ol> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001246" data-s="300,640" src="/upload/c78c2321f2798f250efbd022bfafcffb.png" data-type="png" type="block"> </section> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001247" data-s="300,640" src="/upload/52a20301806fc61b9380cf3d828e970f.png" data-type="png" type="block"> </section> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001248" data-s="300,640" src="/upload/446ccbde0a4b5aa6f8286d79f4d4058a.png" data-type="png" type="block"> </section> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001249" data-s="300,640" src="/upload/d6f4b51b5958c51ef1046d7fa8eadf90.png" data-type="png" type="block"> </section> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001250" data-s="300,640" src="/upload/67bd98a7b76e1657405b106a411ea6b6.png" data-type="png" type="block"> </section> <h3 style="font-size: 18px;background: linear-gradient(45deg, #4299e1, #667eea);-webkit-background-clip: text;-webkit-text-fill-color: transparent;margin: 20px 0 10px;font-weight: bold;color: #4299e1;"><span leaf="">第二步:设置Cursor工具</span></h3> <ol style="font-size: 15px;list-style: decimal;padding-left: 2em;margin-bottom: 16px;" class="list-paddingleft-1"> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">打开Cursor软件</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">在设置中添加MCP服务器配置</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">粘贴高德地图的Key到配置文件中</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">检查连接状态(变绿就成功了!)</span> </section></li> </ol> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001251" data-s="300,640" src="/upload/32a497a5bac55b7dcd6a238d90538cc1.png" data-type="png" type="block"> </section> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001252" data-s="300,640" src="/upload/302b8f0bfe35614d3c443c0d9b3c4a5f.png" data-type="png" type="block"> </section> <p style="font-size: 15px;color: #4a5568;margin: 20px 0;line-height: 1.8;"><span leaf="">我们把下面的代码,粘贴到mcp.json文件里</span><br><strong style="color: #4299e1;font-weight: bold;"><span leaf="">macos:</span></strong></p> <pre style="background: #272822;color: #f8f8f2;"><code><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">1</span></span><span style=""><span leaf="">{</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">2</span></span><span leaf=""> </span><span style=""><span leaf="">"mcpServers"</span></span><span style="color: #f92672;"><span leaf="">:</span></span><span leaf=""> </span><span style=""><span leaf="">{</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">3</span></span><span leaf=""> </span><span style=""><span leaf="">"amap-maps"</span></span><span style="color: #f92672;"><span leaf="">:</span></span><span leaf=""> </span><span style=""><span leaf="">{</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">4</span></span><span leaf=""> </span><span style=""><span leaf="">"command"</span></span><span style="color: #f92672;"><span leaf="">:</span></span><span leaf=""> </span><span style="color: #e6db74;"><span leaf="">"npx"</span></span><span style=""><span leaf="">,</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">5</span></span><span leaf=""> </span><span style=""><span leaf="">"args"</span></span><span style="color: #f92672;"><span leaf="">:</span></span><span leaf=""> </span><span style=""><span leaf="">[</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">6</span></span><span leaf=""> </span><span style="color: #e6db74;"><span leaf="">"-y"</span></span><span style=""><span leaf="">,</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">7</span></span><span leaf=""> </span><span style="color: #e6db74;"><span leaf="">"@amap/amap-maps-mcp-server"</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">8</span></span><span leaf=""> </span><span style=""><span leaf="">]</span></span><span style=""><span leaf="">,</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">9</span></span><span leaf=""> </span><span style=""><span leaf="">"env"</span></span><span style="color: #f92672;"><span leaf="">:</span></span><span leaf=""> </span><span style=""><span leaf="">{</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">10</span></span><span leaf=""> </span><span style=""><span leaf="">"AMAP_MAPS_API_KEY"</span></span><span style="color: #f92672;"><span leaf="">:</span></span><span leaf=""> </span><span style="color: #e6db74;"><span leaf="">"这里这里!!!粘贴您在高德官网上申请的key"</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">11</span></span><span leaf=""> </span><span style=""><span leaf="">}</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">12</span></span><span leaf=""> </span><span style=""><span leaf="">}</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">13</span></span><span leaf=""> </span><span style=""><span leaf="">}</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">14</span></span><span style=""><span leaf="">}</span></span></p></code></pre> <p style="font-size: 15px;color: #4a5568;margin: 20px 0;line-height: 1.8;"><strong style="color: #4299e1;font-weight: bold;"><span leaf="">Windows:</span></strong></p> <pre style="background: #272822;color: #f8f8f2;"><code><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">1</span></span><span style=""><span leaf="">{</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">2</span></span><span leaf=""> </span><span style=""><span leaf="">"mcpServers"</span></span><span style="color: #f92672;"><span leaf="">:</span></span><span leaf=""> </span><span style=""><span leaf="">{</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">3</span></span><span leaf=""> </span><span style=""><span leaf="">"amap-maps"</span></span><span style="color: #f92672;"><span leaf="">:</span></span><span leaf=""> </span><span style=""><span leaf="">{</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">4</span></span><span leaf=""> </span><span style=""><span leaf="">"command"</span></span><span style="color: #f92672;"><span leaf="">:</span></span><span leaf=""> </span><span style="color: #e6db74;"><span leaf="">"cmd"</span></span><span style=""><span leaf="">,</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">5</span></span><span leaf=""> </span><span style=""><span leaf="">"args"</span></span><span style="color: #f92672;"><span leaf="">:</span></span><span leaf=""> </span><span style=""><span leaf="">[</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">6</span></span><span leaf=""> </span><span style="color: #e6db74;"><span leaf="">"/c"</span></span><span style=""><span leaf="">,</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">7</span></span><span leaf=""> </span><span style="color: #e6db74;"><span leaf="">"npx"</span></span><span style=""><span leaf="">,</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">8</span></span><span leaf=""> </span><span style="color: #e6db74;"><span leaf="">"-y"</span></span><span style=""><span leaf="">,</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">9</span></span><span leaf=""> </span><span style="color: #e6db74;"><span leaf="">"@amap/amap-maps-mcp-server"</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">10</span></span><span leaf=""> </span><span style=""><span leaf="">]</span></span><span style=""><span leaf="">,</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">11</span></span><span leaf=""> </span><span style=""><span leaf="">"env"</span></span><span style="color: #f92672;"><span leaf="">:</span></span><span leaf=""> </span><span style=""><span leaf="">{</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">12</span></span><span leaf=""> </span><span style=""><span leaf="">"AMAP_MAPS_API_KEY"</span></span><span style="color: #f92672;"><span leaf="">:</span></span><span leaf=""> </span><span style="color: #e6db74;"><span leaf="">"这里这里!!!粘贴您在高德官网上申请的key"</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">13</span></span><span leaf=""> </span><span style=""><span leaf="">}</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">14</span></span><span leaf=""> </span><span style=""><span leaf="">}</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">15</span></span><span leaf=""> </span><span style=""><span leaf="">}</span></span></p><br><p><span style="width:36px;color:#999;padding-right:1em;text-align:right;display:inline-block;user-select:none;"><span leaf="">16</span></span><span style=""><span leaf="">}</span></span></p></code></pre> <p style="font-size: 15px;color: #4a5568;margin: 20px 0;line-height: 1.8;"><span leaf="">⚠️然后替换一下刚才复制的高德地图key</span></p> <h3 style="font-size: 18px;background: linear-gradient(45deg, #4299e1, #667eea);-webkit-background-clip: text;-webkit-text-fill-color: transparent;margin: 20px 0 10px;font-weight: bold;color: #4299e1;"><span leaf="">第三步:开始智能对话</span></h3> <p style="font-size: 15px;color: #4a5568;margin: 20px 0;line-height: 1.8;"><span leaf="">直接输入你的需求,比如:</span><br><span leaf="">"用高德MCP,做云南一天旅游指南"</span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001253" data-s="300,640" src="/upload/0b338006d548b05b0f3b670b3df257aa.png" data-type="png" type="block"> </section> <p style="font-size: 15px;color: #4a5568;margin: 20px 0;line-height: 1.8;"><span leaf="">AI就会自动生成完整行程,包含:</span></p> <ul style="font-size: 15px;list-style: disc;padding-left: 2em;margin-bottom: 16px;" class="list-paddingleft-1"> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">景点推荐及游玩时间</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">交通路线规划</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">当地特色美食推荐</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">实用旅行小贴士</span> </section></li> </ul> <h3 style="font-size: 18px;background: linear-gradient(45deg, #4299e1, #667eea);-webkit-background-clip: text;-webkit-text-fill-color: transparent;margin: 20px 0 10px;font-weight: bold;color: #4299e1;"><span leaf="">第四步:美化行程页面(可选)</span></h3> <p style="font-size: 15px;color: #4a5568;margin: 20px 0;line-height: 1.8;"><span leaf="">使用提供的专业提示词,让AI帮你:</span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001254" data-s="300,640" src="/upload/2642f67f5443922967a4bc1a897ed47f.png" data-type="png" type="block"> </section> <ol style="font-size: 15px;list-style: decimal;padding-left: 2em;margin-bottom: 16px;" class="list-paddingleft-1"> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">生成可直接打印的A4行程单</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">设计美观的旅游指南网页</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">添加地图、时间轴等可视化元素</span> </section></li> </ol> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001255" data-s="300,640" src="/upload/7bd8b36f1da30aa1959908c76a93c821.png" data-type="png" type="block"> </section> <section> <span leaf=""><br></span> </section> <section> <span leaf="">关注回复“高德MCP网页提示词”获取美化界面提示词!</span> </section> <h2 style="font-size: 22px;background: linear-gradient(45deg, #4299e1, #667eea);-webkit-background-clip: text;-webkit-text-fill-color: transparent;margin: 24px 0 12px;font-weight: bold;color: #4299e1;"><span leaf="">四、个性化定制:说出你的需求</span></h2> <p style="font-size: 15px;color: #4a5568;margin: 20px 0;line-height: 1.8;"><span leaf="">想让行程更符合你的需求?试试这些提示语:</span></p> <ul style="font-size: 15px;list-style: disc;padding-left: 2em;margin-bottom: 16px;" class="list-paddingleft-1"> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">"我想体验当地特色小吃,越地道越好"</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">"我带着70岁的父母和5岁的孩子,需要适合全家人的行程"</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">"我对摄影很感兴趣,希望能去一些适合拍照的地方"</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">"我预算有限,希望找到性价比高的路线"</span> </section></li> </ul> <h2 style="font-size: 22px;background: linear-gradient(45deg, #4299e1, #667eea);-webkit-background-clip: text;-webkit-text-fill-color: transparent;margin: 24px 0 12px;font-weight: bold;color: #4299e1;"><span leaf="">五、立即体验旅行规划革命</span></h2> <p style="font-size: 15px;color: #4a5568;margin: 20px 0;line-height: 1.8;"><span leaf="">想象一下:</span></p> <ul style="font-size: 15px;list-style: disc;padding-left: 2em;margin-bottom: 16px;" class="list-paddingleft-1"> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">不再为旅行规划头疼</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">几分钟获得个性化完美攻略</span> </section></li> <li style="font-size: 15px;margin-bottom: 8px;display: list-item;"> <section> <span leaf="">带着它轻松探索世界!</span> </section></li> </ul> <p style="font-size: 15px;color: #4a5568;margin: 20px 0;line-height: 1.8;"><span leaf=""><span textstyle="" style="font-weight: bold;">现在就来试试这个神器吧!</span></span></p> </section> <p style="margin-bottom: 0px;"><span style=""><span leaf=""><br></span></span></p> <p style="margin-bottom: 0px;"><span leaf="">如果你有什么想要交流的,欢迎在评论区留下你的想法。</span></p> <p style="margin-bottom: 0px;"><span leaf="">那么我们下一篇再见!</span></p> <p style="margin-bottom: 0px;"><span leaf=""><br></span></p> <section> <span leaf=""><br></span> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<section data-tool="MD编辑器" data-website="https://www.tooltt.com" style="" data-pm-slice="0 0 []"> <p data-tool="MD编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><span leaf="">你是否费尽心思写脚本、整集成,一周才能搞定一个简单的自动化流程?用闭源的扣子?有更好的选择吗?</span></p> <figure data-tool="MD编辑器" style="margin-top: 10px;margin-bottom: 10px;margin: 10px 0px;padding: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/4f7f5cf021fdb8137dc3a4b752e37519.png" class="rich_pages wxw-img" data-ratio="0.3814814814814815" data-type="png" data-w="1080" style="display: block;max-width: 100%;width: 100%;margin: 0 auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;" data-imgfileid="100018681"></span> </figure> <p data-tool="MD编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><strong style="font-weight: bold;color: black;"><span leaf="">n8n,一款兼具代码灵活性和可视化简单操作的开源神器</span></strong><span leaf="">,让这些事情分分钟搞定!它支持 400+ 应用和服务,内置 AI 能力,既能拖拽完成任务,也能用代码搞定复杂逻辑,还能自托管,掌控所有数据。</span></p> <h4 data-tool="MD编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;margin: 30px 0px 15px;padding: 0px;display: flex;color: #666;"><span style="display: none;"></span><span style="font-size: 18px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">什么是 n8n</span></span><span style="display: none;"></span></h4> <figure data-tool="MD编辑器" style="margin-top: 10px;margin-bottom: 10px;margin: 10px 0px;padding: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/bb213e9eb7a6b2a12f304cdfb8c64310.png" class="rich_pages wxw-img" data-ratio="0.5796296296296296" data-type="png" data-w="1080" style="display: block;max-width: 100%;width: 100%;margin: 0 auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;" data-imgfileid="100018683"></span> </figure> <blockquote style="display: block;font-size: 0.9em;overflow: auto;overflow-scrolling: touch;background: rgba(0, 0, 0, 0.05);padding-top: 10px;padding-bottom: 10px;padding-left: 15px;padding-right: 10px;margin-bottom: 20px;margin-top: 20px;border-left: 4px solid #42b983;padding: 10px 15px;color: #777;background-color: rgba(66, 185, 131, .1);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 26px;color: #999;padding: 3px 0;"><strong style="font-weight: bold;color: black;"><span leaf="">n8n 是一个灵活的开源自动化平台</span></strong><span leaf="">,支持 400+ 应用和服务集成,拥有强大的自定义代码能力,同时支持拖拽式操作,再复杂的流程都能轻松打造。更棒的是,</span><strong style="font-weight: bold;color: black;"><span leaf="">DeepSeek</span></strong><span leaf=""> 的加入将其 AI 功能提升到新高度!</span></p> </blockquote> <p data-tool="MD编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><span leaf="">DeepSeek 提供两种核心模型:</span></p> <ul style="margin-top: 8px;margin-bottom: 8px;list-style-type: disc;margin: 8px 0px;color: rgb(0, 0, 0);padding-left: 20px;" class="list-paddingleft-1"> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <strong style="font-weight: bold;color: black;"><span leaf="">DeepSeek V3 (Chat):</span></strong><span leaf=""> 专注高效互动,适合实时应用,成本极低。</span> </section></li> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <strong style="font-weight: bold;color: black;"><span leaf="">DeepSeek R1 (Reasoning):</span></strong><span leaf=""> 专为复杂推理任务设计,提供深度分析能力。</span> </section></li> </ul> <p data-tool="MD编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><span leaf="">结合 n8n,你可以在工作流中轻松嵌入 AI,并自托管保护数据安全,彻底解放生产力!</span></p> <h4 data-tool="MD编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;margin: 30px 0px 15px;padding: 0px;display: flex;color: #666;"><span style="display: none;"></span><span style="font-size: 18px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">开源成就</span></span><span style="display: none;"></span></h4> <ul style="margin-top: 8px;margin-bottom: 8px;list-style-type: disc;margin: 8px 0px;color: rgb(0, 0, 0);padding-left: 20px;" class="list-paddingleft-1"> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <span leaf=""><span textstyle="" style="font-weight: bold;">GitHub Star 数</span>:74.7k(处于全球最受欢迎的开源项目 Top 150!)</span><span leaf=""><br></span><span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100018679" data-ratio="0.5166666666666667" src="/upload/7df60b35f8d487e34026de4fd797cc56.png" data-type="png" data-w="1080" style="display: block;max-width: 100%;width: 100%;margin: 0 auto;"></span> </section></li> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <span leaf=""><span textstyle="" style="font-weight: bold;">开发语言</span>:90% TypeScript,8% Vue,极具现代化支持。</span> </section></li> </ul> <h4 data-tool="MD编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;margin: 30px 0px 15px;padding: 0px;display: flex;color: #666;"><span style="display: none;"></span><span style="font-size: 18px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">核心功能</span></span><span style="display: none;"></span></h4> <figure data-tool="MD编辑器" style="margin-top: 10px;margin-bottom: 10px;margin: 10px 0px;padding: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img class="rich_pages wxw-img" data-imgfileid="100018680" data-ratio="0.5444444444444444" src="/upload/9457e39be6e48c27a00641a368b1deee.png" data-type="png" data-w="1080" style="display: block;max-width: 100%;width: 100%;margin: 0 auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;"></span> </figure> <p data-tool="MD编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><strong style="font-weight: bold;color: black;"><span leaf="">完美结合——代码与可视化</span></strong></p> <ul style="margin-top: 8px;margin-bottom: 8px;list-style-type: disc;margin: 8px 0px;color: rgb(0, 0, 0);padding-left: 20px;" class="list-paddingleft-1"> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <span leaf="">写 JavaScript 或 Python,随意添加 npm 包,突破标准化工具的限制。</span> </section></li> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <span leaf="">无需从头写代码!通过拖拽界,组合出多层次的自动化组合,让繁琐任务自动完成。</span> </section></li> </ul> <p data-tool="MD编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><strong style="font-weight: bold;color: black;"><span leaf="">内置前沿 AI 能力</span></strong></p> <ul style="margin-top: 8px;margin-bottom: 8px;list-style-type: disc;margin: 8px 0px;color: rgb(0, 0, 0);padding-left: 20px;" class="list-paddingleft-1"> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <span leaf="">基于 LangChain 构建 AI 工作流,轻松整合 LLM(如DeepSeek, OpenAI GPT 模型)。</span> </section></li> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <span leaf="">让 AI 动起来!支持从外部系统提取数据、自动汇总分析和生成答案。<img class="rich_pages wxw-img" data-imgfileid="100018682" data-ratio="0.5361111111111111" src="/upload/09bf3fc460d48d42fcb269aa0b19e709.png" data-type="png" data-w="1080" style="display: block;max-width: 100%;width: 100%;margin: 0 auto;"></span> </section></li> </ul> <p data-tool="MD编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><strong style="font-weight: bold;color: black;"><span leaf="">企业级支持</span></strong></p> <ul style="margin-top: 8px;margin-bottom: 8px;list-style-type: disc;margin: 8px 0px;color: rgb(0, 0, 0);padding-left: 20px;" class="list-paddingleft-1"> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <span leaf="">高级权限管理:SSO、RBAC 权限控制,支持闭环企业环境部署。</span> </section></li> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <span leaf="">审计日志追踪、自动化版本控制,轻松追溯和回滚。</span> </section></li> </ul> <p data-tool="MD编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><strong style="font-weight: bold;color: black;"><span leaf="">自托管 + 云部署可选</span></strong></p> <ul style="margin-top: 8px;margin-bottom: 8px;list-style-type: disc;margin: 8px 0px;color: rgb(0, 0, 0);padding-left: 20px;" class="list-paddingleft-1"> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <strong style="font-weight: bold;color: black;"><span leaf="">绝对自由!</span></strong><span leaf=""> 你可选择托管在自己的服务器上,保护敏感数据。</span> </section></li> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <span leaf="">更喜欢省事?使用 n8n 的官方云服务也是妥妥的选择。</span> </section></li> </ul> <p data-tool="MD编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><strong style="font-weight: bold;color: black;"><span leaf="">开源的力量</span></strong></p> <ul style="margin-top: 8px;margin-bottom: 8px;list-style-type: disc;margin: 8px 0px;color: rgb(0, 0, 0);padding-left: 20px;" class="list-paddingleft-1"> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><span leaf="">高度可扩展:随时添加自定义节点或功能,打造独一无二的解决方案。</span></p> </section></li> <li style="color: #666;"> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);font-size: 15px;letter-spacing: 0em;text-align: left;font-weight: normal;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><span leaf="">400+ 即插即用的连接器,支持几乎所有主流应用工具(如 Slack、MySQL、GitHub)。</span></p> <figure style="margin-top: 10px;margin-bottom: 10px;margin: 10px 0px;padding: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/4c173acd948fef47f055a0add89424f2.png" class="rich_pages wxw-img" data-ratio="0.25092592592592594" data-type="png" data-w="1080" style="display: block;max-width: 100%;width: 100%;margin: 0 auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;" data-imgfileid="100018686"></span> </figure> </section></li> </ul> <h4 data-tool="MD编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;margin: 30px 0px 15px;padding: 0px;display: flex;color: #666;"><span style="display: none;"></span><span style="font-size: 18px;line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">快速上手指南</span></span><span style="display: none;"></span></h4> <p data-tool="MD编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><strong style="font-weight: bold;color: black;"><span leaf="">使用 npx 快速体验</span></strong></p> <pre data-tool="MD编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 1px 3px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #fff;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg iahdqiccc5vbqjzbdisoikdelkmqwp83buaibuyygpibmv9vztglwc7iabx6rjk0yseia1uiygzsilz1dxiaribjfqejdc13nohc4qvd 640?wx_fmt="svg&from=appmsg");""></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;width: 100%;padding-top: 15px;padding-bottom: 15px;background: #fff;border-radius: 5px;"><span leaf="">npx n8n</span><span leaf=""><br></span></code></pre> <p data-tool="MD编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><strong style="font-weight: bold;color: black;"><span leaf="">用 Docker 自托管</span></strong></p> <pre data-tool="MD编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 1px 3px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #fff;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg iahdqiccc5vbqjzbdisoikdelkmqwp83buaibuyygpibmv9vztglwc7iabx6rjk0yseia1uiygzsilz1dxiaribjfqejdc13nohc4qvd 640?wx_fmt="svg&from=appmsg");""></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;width: 100%;padding-top: 15px;padding-bottom: 15px;background: #fff;border-radius: 5px;"><span leaf="">docker volume create n8n_data</span><span leaf=""><br></span><span leaf="">docker run -it --rm --name n8n -p 5678:5678 -v n8n_data:/home/node/.n8n docker.n8n.io/n8nio/n8n</span><span leaf=""><br></span></code></pre> <p data-tool="MD编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><span leaf="">启动后访问http://localhost:5678,即可进入可视化界面!</span></p> <figure data-tool="MD编辑器" style="margin-top: 10px;margin-bottom: 10px;margin: 10px 0px;padding: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/bb6589a3b7f56983245755daf7ae7ffb.png" class="rich_pages wxw-img" data-ratio="0.6435185185185185" data-type="png" data-w="1080" style="display: block;max-width: 100%;width: 100%;margin: 0 auto;border-style: none;border-width: 3px;border-color: rgba(0, 0, 0, 0.4);border-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;" data-imgfileid="100018687"></span> </figure> <blockquote style="display: block;font-size: 0.9em;overflow: auto;overflow-scrolling: touch;background: rgba(0, 0, 0, 0.05);padding-top: 10px;padding-bottom: 10px;padding-left: 15px;padding-right: 10px;margin-bottom: 20px;margin-top: 20px;border-left: 4px solid #42b983;padding: 10px 15px;color: #777;background-color: rgba(66, 185, 131, .1);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 26px;color: #999;padding: 3px 0;"><span leaf="">n8n 的强大与灵活,</span><strong style="font-weight: bold;color: black;"><span leaf="">结合 DeepSeek 的极速 AI 推动</span></strong><span leaf="">,让你的自动化能力全面升级。不论是聊天助手、业务流程自动化,还是复杂数据分析,n8n+DeepSeek 都能轻松处理,简化工作流,提高效率。更重要的是,自托管方案让你完全掌控数据,低成本的 DeepSeek 模型为企业节省开支,堪称技术团队的必备工具。</span></p> </blockquote> <p data-tool="MD编辑器" style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: #666;"><span leaf=""><span textstyle="" style="font-size: 15px;">开源地址https://github.com/n8n-io/n8n</span></span></p> <table> <tbody> <tr> <td data-colwidth="576"></td> </tr> </tbody> </table> </section>
作者:微信小助手
<section style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;> <span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">经过很长时间的研究,借助多个大模型,终于搞明白AI大模型中语音对话经常提到的双流输出的技术实现方案了。</span> </section> <section style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;> <span leaf=""><img class="rich_pages wxw-img" data-imgfileid="502850698" src="/upload/6e78d97d9f673b3b8981eee491783989.png" data-type="png"></span> </section> <section style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;> <span leaf=""><span textstyle="" style="font-size: 14px;font-weight: bold;">图片来自gpt-4o,没想到它的中文能力都这么强了。</span></span> </section> <section style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;> <span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span> </section> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">什么是双流输出?</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">双流输出指的是在系统生成回复的过程中,同时以流式的方式输出文本和语音:</span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">文本流</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:逐步显示生成的文字内容。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">语音流</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:逐步将生成的文字转化为音频并播放。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">即使大模型每次输出的文本不长,双流输出仍然有其必要性,主要原因在于提升用户体验和交互的流畅性。</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">为什么需要双流输出?</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">1. </span></span></span></span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">提供实时反馈</span></span></span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">文本流式输出</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:即使每次输出的文本很短,用户也能立刻看到系统正在生成内容。这种逐步显示的过程让用户感觉到系统在“思考”并逐步给出答案,避免了长时间的空白等待。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">语音流式输出</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:用户可以听到系统“边说边想”的效果。在语音对话场景中,语音播放需要时间,流式输出能让用户尽早听到回复开头,减少等待感。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">2. </span></span></span></span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">模拟自然对话</span></span></span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">在现实生活中,人们通常是边思考边说话,而不是一次性说完所有内容。双流输出能模拟这种自然的对话模式,让交互更接近人类对话,提升用户体验。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">特别是在你的语音对话场景中,用户更希望系统像人一样逐步说出回复,而不是等待完整内容生成后再一次性播放。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">3. </span></span></span></span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">减少感知延迟</span></span></span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">即使每次输出的文本不长,累积生成整个回复仍需一定时间。通过双流输出,用户可以尽早接收和处理信息,从而减少感知到的延迟。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">举例</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:假设系统生成一个包含 3 句话的回复,每句话生成耗时 1 秒,语音播放每句话耗时 2 秒:</span></span></span></p></li> <ul style="display: block;padding-inline-start: 2em;margin-block: 0.75em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">一次性输出</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:用户等待 3 秒后看到完整文本,然后系统开始播放语音,用户在接下来的 6 秒内听完,总计等待 3 秒。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">双流输出</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:系统生成第一句话(1 秒)后立即显示并播放,用户在第 1 秒开始听到内容,第 2 秒听到第二句话,以此类推。用户从第 1 秒就获得反馈,整体体验更流畅。</span></span></span></p></li> </ul> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">4. </span></span></span></span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">技术上的可行性</span></span></span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">现代大语言模型(LLM)和文本转语音(TTS)技术都支持流式生成,因此实现双流输出在技术上没有太大障碍。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">WebRTC 和 Web Audio API 也为实时音频传输和播放提供了强有力的支持。</span></span></span></p></li> </ul> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">为什么不采用一次性输出?</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果采用一次性输出,用户需要等待整个回复生成完毕后才能看到文本和听到语音。这种方式会带来明显的延迟感,尤其在语音对话中,会让交互显得不自然。即使每次输出的文本不长,累积的生成和播放时间仍可能让用户感到等待时间过长,破坏对话的流畅性。</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">实现双流输出的具体建议:</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">1. </span></span></span></span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">后端流式生成</span></span></span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">配置大模型为流式模式,逐个 token 或按短语生成文本。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">通过 WebSocket 或 Server-Sent Events (SSE) 将生成的文本流实时发送到前端。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">2. </span></span></span></span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">前端处理</span></span></span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">文本显示</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:前端接收到文本流后,实时更新聊天界面,逐步展示生成的文字。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">语音合成</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:将接收到的文本分块(例如按句子)传递给 TTS 模型(可在后端或前端实现),生成音频片段。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">音频播放</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:使用 Web Audio API 播放这些音频片段,确保播放过程流畅无明显中断。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">3. </span></span></span></span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">WebRTC 的作用</span></span></span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果 TTS 在后端生成音频,可以通过 WebRTC 将音频流实时传输到前端。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果 TTS 在前端实现(例如使用浏览器内置的 TTS API),则无需 WebRTC,直接用 Web Audio API 播放即可。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">双流输出的时候,我应该什么时候让文本开始转语音</span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">最佳时机:尽早但有逻辑地开始</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">你应该在大模型生成了一定长度的文本片段后,立即将该片段传递给文本转语音(TTS)系统进行转换和播放。具体来说:</span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">时机</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:当生成一个完整的短语或句子时(例如,遇到句号、问号或感叹号),就开始转语音。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">原因</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:TTS需要时间处理和生成音频,如果等到整个回复生成完毕,用户会感到延迟;而逐字传递又可能导致语音断断续续,影响听感。按逻辑单元分块可以在实时性和流畅性之间取得平衡。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">如何分块传递文本</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">为了让语音输出自然且语义完整,建议按以下方式处理文本:</span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li style="font-weight:bold;"><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">按标点符号分隔</span></span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">:</span></span></span></span></p></li> <ul style="display: block;padding-inline-start: 2em;margin-block: 0.75em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">当大模型生成到句号(</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">.</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)、问号(</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">?</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)或感叹号(</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">!</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)时,将该句子传递给TTS。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">示例:对于回复“今天天气很好,适合出门散步。”,可以分成:</span></span></span></p></li> </ul> <ol style="display: block;padding-inline-start: 2em;margin-block: 0.75em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">“今天天气很好,” → 立即转语音。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">“适合出门散步。” → 随后转语音。</span></span></span></p></li> </ol> <li style="font-weight:bold;"><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">最小长度限制</span></span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">:</span></span></span></span></p></li> <ul style="display: block;padding-inline-start: 2em;margin-block: 0.75em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li style="font-weight:bold;"><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">如果句子较短或生成速度很快,可以设置一个最小文本长度(如5-10个字),达到该长度时传递给TTS。</span></span></span></span></p></li> </ul> <li style="font-weight:bold;"><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">避免逐字传递</span></span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">:</span></span></span></span></p></li> <ul style="display: block;padding-inline-start: 2em;margin-block: 0.75em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">逐字或逐token转语音会导致语音输出不连贯,影响用户体验。</span></span></span></p></li> </ul> </ul> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">为什么这么做</span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">减少延迟</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:尽早开始TTS转换,用户可以在看到文本的同时听到语音,感知到的等待时间更短。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">保证流畅性</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:按句子或短语分块,确保TTS生成的语音自然、语调连贯。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">语义完整</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:避免在句子中间截断,让用户听到的每段语音都有完整含义。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">一个具体例子</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">假设大模型生成以下回复:“今天天气很好,适合出门散步。你觉得呢?” </span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">分块过程</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:</span></span></span></p></li> <ol style="display: block;padding-inline-start: 2em;margin-block: 0.75em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">生成到“今天天气很好,”时,立即将这部分传递给TTS,生成并播放语音。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">生成到“适合出门散步。”时,再传递给TTS。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">生成到“你觉得呢?”时,最后传递给TTS。</span></span></span></p></li> </ol> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">用户体验</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:</span></span></span></p></li> <ul style="display: block;padding-inline-start: 2em;margin-block: 0.75em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">用户在屏幕上看到“今天天气很好,”的同时,听到对应的语音。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">随着文本逐步显示,后续的语音也接连播放,整体流畅自然。</span></span></span></p></li> </ul> </ul> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">技术实现要点</span></span></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">为了支持这种策略,你需要:</span></span></span></span></p> <ol style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">流式生成文本</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:配置大模型以流式模式输出,逐段生成文本。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">实时传递</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:将分好的文本块实时发送给支持流式合成的TTS系统。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">音频播放</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:在前端使用Web Audio API等技术,接收并播放TTS生成的音频片段,确保无缝衔接。</span></span></span></p></li> </ol> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">本地局域网实现案例</span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">方案概述</span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">技术栈</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:Dify(前端框架) + Ollama(模型服务) + DeepSeek(语言模型)</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">目标</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:通过分块传递文本,实现流式文本显示和语音输出。</span></span></span></p></li> </ul> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">分块传递文本给 TTS</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">为了实现流式语音输出,我们需要将生成的文本按逻辑单元分块,并传递给 TTS(文本转语音)系统。</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">步骤</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:</span></span></span></span></p> <ol style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li style="font-weight:bold;"><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">文本分块逻辑</span></span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;"> </span></span></span></span></p></li> <ul style="display: block;padding-inline-start: 2em;margin-block: 0.75em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">在后端处理流式生成的文本,累积 token,直到形成一个完整的句子(以句尾标点如 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">.</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">、</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">?</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">、</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">!</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 为标志)。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">设置一个最小长度阈值(例如 5-10 个字符),避免分块过短。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">示例(伪代码):</span></span></span></p><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">python</span></span></p><p></p><p> <svg viewbox="0 0 24 24" aria-hidden="true" style="color: black;background-color: transparent;font-family: sans-serif;"> <g style="color: black;background-color: transparent;font-family: sans-serif;"> <path d="M19.5 2C20.88 2 22 3.12 22 4.5v11c0 1.21-.86 2.22-2 2.45V4.5c0-.28-.22-.5-.5-.5H6.05c.23-1.14 1.24-2 2.45-2h11zm-4 4C16.88 6 18 7.12 18 8.5v11c0 1.38-1.12 2.5-2.5 2.5h-11C3.12 22 2 20.88 2 19.5v-11C2 7.12 3.12 6 4.5 6h11zM4 19.5c0 .28.22.5.5.5h11c.28 0 .5-.22.5-.5v-11c0-.28-.22-.5-.5-.5h-11c-.28 0-.5.22-.5.5v11z" style="color: black;background-color: transparent;font-family: sans-serif;"></path> </g> </svg><span style="border-bottom: 2px solid rgb(239, 243, 244);color: black;background-color: transparent;font-family: sans-serif;"></span></p><p></p><pre style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><code><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">buffer</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">=</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">""</span></span><span style="color: black;background-color: transparent;font-family: monospace;font-size: 10pt;"><br></span><span style="color: black;background-color: transparent;font-family: monospace;font-size: 10pt;"></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">for</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> chunk </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">in</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> response</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:</span></span><span style="color: black;background-color: transparent;font-family: monospace;font-size: 10pt;"><br></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">buffer</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">+=</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> chunk</span><br></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">if</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">buffer</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">.</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">endswith</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">'.'</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">,</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">'?'</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">,</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">'!'</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">and</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">len</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">buffer</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">>=</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">5</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:</span></span><span style="color: black;background-color: transparent;font-family: monospace;font-size: 10pt;"><br></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> send_to_tts</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">buffer</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)</span></span><span style="color: black;background-color: transparent;font-family: monospace;font-size: 10pt;"><br></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">buffer</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">=</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">""</span></span></code></pre></li> </ul> <li style="font-weight:bold;"><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">TTS 集成</span></span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;"> </span></span></span></span></p></li> <ul style="display: block;padding-inline-start: 2em;margin-block: 0.75em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">选择一个支持流式合成的 TTS 系统,例如 MegaTTS3。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">将分好的文本块实时发送给 TTS 模型,生成对应的音频片段。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">确保 TTS 模型支持中英文混合输入(DeepSeek 输出可能是多语言的)。</span></span></span></p></li> </ul> <li style="font-weight:bold;"><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">音频传输与播放</span></span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;"> </span></span></span></span></p></li> <ul style="display: block;padding-inline-start: 2em;margin-block: 0.75em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">使用 WebRTC 将生成的音频流传输到前端。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">在 Dify 前端,使用 Web Audio API 接收音频片段并播放。例如:</span></span></span></p><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">javascript</span></span></p><p></p><p> <svg viewbox="0 0 24 24" aria-hidden="true" style="color: black;background-color: transparent;font-family: sans-serif;"> <g style="color: black;background-color: transparent;font-family: sans-serif;"> <path d="M19.5 2C20.88 2 22 3.12 22 4.5v11c0 1.21-.86 2.22-2 2.45V4.5c0-.28-.22-.5-.5-.5H6.05c.23-1.14 1.24-2 2.45-2h11zm-4 4C16.88 6 18 7.12 18 8.5v11c0 1.38-1.12 2.5-2.5 2.5h-11C3.12 22 2 20.88 2 19.5v-11C2 7.12 3.12 6 4.5 6h11zM4 19.5c0 .28.22.5.5.5h11c.28 0 .5-.22.5-.5v-11c0-.28-.22-.5-.5-.5h-11c-.28 0-.5.22-.5.5v11z" style="color: black;background-color: transparent;font-family: sans-serif;"></path> </g> </svg><span style="border-bottom: 2px solid rgb(239, 243, 244);color: black;background-color: transparent;font-family: sans-serif;"></span></p><p></p><pre style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><code><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">const</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> audioContext </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">=</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">new</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">AudioContext</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">;</span></span><span style="color: black;background-color: transparent;font-family: monospace;font-size: 10pt;"><br></span><span style="color: black;background-color: transparent;font-family: monospace;font-size: 10pt;"></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">const</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> source </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">=</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> audioContext</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">.</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">createBufferSource</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">;</span></span><span style="color: black;background-color: transparent;font-family: monospace;font-size: 10pt;"><br></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">source</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">.</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">buffer </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">=</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> audioBuffer</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">;</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">// 从 WebRTC 接收的音频数据</span></span><span style="color: black;background-color: transparent;font-family: monospace;font-size: 10pt;"><br></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">source</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">.</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">connect</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">audioContext</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">.</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">destination</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">;</span></span><span style="color: black;background-color: transparent;font-family: monospace;font-size: 10pt;"><br></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">source</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">.</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">start</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">;</span></span></code></pre></li> </ul> </ol> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">优化用户体验</span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">减少延迟</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:调整分块大小(例如每 10-20 个字符或一个句子)和 TTS 响应速度,确保语音紧跟文本显示。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">错误处理</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:在流式输出中,加入网络中断或模型错误的处理逻辑,保证系统稳定。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">声音自然性</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:如果需要更真实的声音,可以为 TTS 配置声音克隆功能,预加载目标声音模型。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">TTS方案:</span></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">提供的 MegaTTS3 GitHub 地址是 </span></span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">https://github.com/bytedance/MegaTTS3/tree/main</span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">。</span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">MegaTTS3 是字节推出的开源的文本转语音(TTS)模型,支持中英文语音生成和声音克隆。然而,根据官方文档和代码分析,MegaTTS3 本身并不直接支持流式音频输出(即逐帧生成并实时传输音频)。它基于扩散模型(Diffusion Model),通常生成完整的音频序列。不过,你可以通过一些方法模拟流式输出的效果,在本地部署中实现音频流输出。</span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">方法概述</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">由于 MegaTTS3 原生不支持流式生成,我们可以通过以下方式实现近似流式输出:</span></span></span></span></p> <ol style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">文本分块</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:将输入文本分割成小块(例如按句子或短语)。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">逐块生成音频</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:使用 MegaTTS3 为每个文本块生成音频片段。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">流式传输和播放</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:将生成的音频片段逐步传输到前端并实时播放。</span></span></span></p></li> </ol> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">这种方法虽然不是真正的流式生成(因为扩散模型需要生成完整序列),但通过快速生成和传输小块音频,可以为用户提供近乎实时的音频流体验。以下是详细的实现步骤。</span></span></span></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="python"><code><span leaf=""><span class="code-snippet__comment"># Copyright 2025 ByteDance and/or its affiliates.</span></span></code><code><span leaf=""><span class="code-snippet__comment">#</span></span></code><code><span leaf=""><span class="code-snippet__comment"># Licensed under the Apache License, Version 2.0 (the "License");</span></span></code><code><span leaf=""><span class="code-snippet__comment"># you may not use this file except in compliance with the License.</span></span></code><code><span leaf=""><span class="code-snippet__comment"># You may obtain a copy of the License at</span></span></code><code><span leaf=""><span class="code-snippet__comment">#</span></span></code><code><span leaf=""><span class="code-snippet__comment"># http://www.apache.org/licenses/LICENSE-2.0</span></span></code><code><span leaf=""><span class="code-snippet__comment">#</span></span></code><code><span leaf=""><span class="code-snippet__comment"># Unless required by applicable law or agreed to in writing, software</span></span></code><code><span leaf=""><span class="code-snippet__comment"># distributed under the License is distributed on an "AS IS" BASIS,</span></span></code><code><span leaf=""><span class="code-snippet__comment"># WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></span></code><code><span leaf=""><span class="code-snippet__comment"># See the License for the specific language governing permissions and</span></span></code><code><span leaf=""><span class="code-snippet__comment"># limitations under the License.</span></span></code><code><span leaf=""><span class="code-snippet__keyword">import</span> os</span></code><code><span leaf=""><span class="code-snippet__keyword">import</span> torch</span></code><code><span leaf=""><span class="code-snippet__keyword">from</span> flask <span class="code-snippet__keyword">import</span> Flask, Response, request</span></code><code><span leaf=""><span class="code-snippet__keyword">import</span> numpy <span class="code-snippet__keyword">as</span> np</span></code><code><span leaf=""><span class="code-snippet__keyword">import</span> soundfile <span class="code-snippet__keyword">as</span> sf</span></code><code><span leaf=""><span class="code-snippet__keyword">import</span> io</span></code><code><span leaf=""><span class="code-snippet__keyword">from</span> tts.infer_cli <span class="code-snippet__keyword">import</span> MegaTTS3DiTInfer, convert_to_wav, cut_wav</span></code><code><span leaf=""><span class="code-snippet__comment"># 配置路径</span></span></code><code><span leaf="">BASE_DIR = os.path.dirname(os.path.abspath(__file__))</span></code><code><span leaf="">CHECKPOINTS_DIR = os.path.join(BASE_DIR, <span class="code-snippet__string">'checkpoints'</span>)</span></code><code><span leaf="">ASSETS_DIR = os.path.join(BASE_DIR, <span class="code-snippet__string">'assets'</span>)</span></code><code><span leaf="">app = Flask(__name__)</span></code><code><span leaf=""><span class="code-snippet__comment"># 初始化 MegaTTS3 模型</span></span></code><code><span leaf="">device = <span class="code-snippet__string">'cuda'</span> <span class="code-snippet__keyword">if</span> torch.cuda.is_available() <span class="code-snippet__keyword">else</span> <span class="code-snippet__string">'cpu'</span></span></code><code><span leaf="">infer_pipe = MegaTTS3DiTInfer(</span></code><code><span leaf=""> device=device,</span></code><code><span leaf=""> ckpt_root=CHECKPOINTS_DIR,</span></code><code><span leaf=""> dit_exp_name=<span class="code-snippet__string">'diffusion_transformer'</span>,</span></code><code><span leaf=""> frontend_exp_name=<span class="code-snippet__string">'aligner_lm'</span>,</span></code><code><span leaf=""> wavvae_exp_name=<span class="code-snippet__string">'wavvae'</span>,</span></code><code><span leaf=""> dur_ckpt_path=<span class="code-snippet__string">'duration_lm'</span>,</span></code><code><span leaf=""> g2p_exp_name=<span class="code-snippet__string">'g2p'</span></span></code><code><span leaf="">)</span></code><code><span leaf=""><span class="code-snippet__comment"># 默认参考音频和潜在文件路径</span></span></code><code><span leaf="">DEFAULT_REF_WAV = os.path.join(ASSETS_DIR, <span class="code-snippet__string">'Chinese_prompt.wav'</span>)</span></code><code><span leaf="">DEFAULT_REF_NPY = os.path.join(ASSETS_DIR, <span class="code-snippet__string">'Chinese_prompt.npy'</span>)</span></code><code><span leaf=""><span class="code-snippet__keyword">def</span> <span class="code-snippet__title">generate_audio_stream</span>(<span class="code-snippet__params">text, ref_wav=DEFAULT_REF_WAV, ref_npy=DEFAULT_REF_NPY, time_step=</span><span class="code-snippet__params"><span class="code-snippet__number">32</span></span><span class="code-snippet__params">, p_w=</span><span class="code-snippet__params"><span class="code-snippet__number">1.6</span></span><span class="code-snippet__params">, t_w=</span><span class="code-snippet__params"><span class="code-snippet__number">2.5</span></span>):</span></code><code><span leaf=""> <span class="code-snippet__string">"""</span></span></code><code><span leaf=""> 生成音频流,按句子分块处理并返回 WAV 数据。</span></code><code><span leaf=""> """</span></code><code><span leaf=""> <span class="code-snippet__keyword">try</span>:</span></code><code><span leaf=""> <span class="code-snippet__comment"># 确保参考音频是 WAV 格式并裁剪</span></span></code><code><span leaf=""> convert_to_wav(ref_wav)</span></code><code><span leaf=""> wav_path = os.path.splitext(ref_wav)[<span class="code-snippet__number">0</span>] + <span class="code-snippet__string">'.wav'</span></span></code><code><span leaf=""> cut_wav(wav_path, max_len=<span class="code-snippet__number">28</span>)</span></code><code><span leaf=""> <span class="code-snippet__comment"># 读取参考音频</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">with</span> <span class="code-snippet__built_in">open</span>(wav_path, <span class="code-snippet__string">'rb'</span>) <span class="code-snippet__keyword">as</span> file:</span></code><code><span leaf=""> file_content = file.read()</span></code><code><span leaf=""> <span class="code-snippet__comment"># 预处理参考音频</span></span></code><code><span leaf=""> resource_context = infer_pipe.preprocess(file_content, latent_file=ref_npy)</span></code><code><span leaf=""> <span class="code-snippet__comment"># 分块生成音频</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">def</span> <span class="code-snippet__title">audio_chunks</span>():</span></code><code><span leaf=""> <span class="code-snippet__comment"># 按句子分割文本</span></span></code><code><span leaf=""> sentences = text.split(<span class="code-snippet__string">'。'</span>) <span class="code-snippet__keyword">if</span> <span class="code-snippet__string">'。'</span> <span class="code-snippet__keyword">in</span> text <span class="code-snippet__keyword">else</span> [text]</span></code><code><span leaf=""> <span class="code-snippet__keyword">for</span> sentence <span class="code-snippet__keyword">in</span> sentences:</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> sentence.strip():</span></code><code><span leaf=""> <span class="code-snippet__comment"># 生成音频</span></span></code><code><span leaf=""> wav_bytes = infer_pipe.forward(</span></code><code><span leaf=""> resource_context, sentence, time_step=time_step, p_w=p_w, t_w=t_w</span></code><code><span leaf=""> )</span></code><code><span leaf=""> <span class="code-snippet__comment"># 将字节流转换为 WAV 格式的音频数据</span></span></code><code><span leaf=""> wav_data, _ = sf.read(io.BytesIO(wav_bytes))</span></code><code><span leaf=""> <span class="code-snippet__keyword">with</span> io.BytesIO() <span class="code-snippet__keyword">as</span> buf:</span></code><code><span leaf=""> sf.write(buf, wav_data, infer_pipe.sr, <span class="code-snippet__built_in">format</span>=<span class="code-snippet__string">'WAV'</span>)</span></code><code><span leaf=""> <span class="code-snippet__keyword">yield</span> buf.getvalue()</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> audio_chunks()</span></code><code><span leaf=""> <span class="code-snippet__keyword">except</span> Exception <span class="code-snippet__keyword">as</span> e:</span></code><code><span leaf=""> <span class="code-snippet__built_in">print</span>(<span class="code-snippet__string">f"Error generating audio: </span><span class="code-snippet__string"><span class="code-snippet__subst">{</span></span><span class="code-snippet__string"><span class="code-snippet__subst"><span class="code-snippet__built_in">str</span></span></span><span class="code-snippet__string"><span class="code-snippet__subst">(e)}</span></span><span class="code-snippet__string">"</span>)</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> <span class="code-snippet__literal">None</span></span></code><code><span leaf=""><span class="code-snippet__meta">@app.route(</span><span class="code-snippet__meta"><span class="code-snippet__params"><span class="code-snippet__string">'/stream'</span></span></span><span class="code-snippet__meta"><span class="code-snippet__params">, methods=[</span></span><span class="code-snippet__meta"><span class="code-snippet__params"><span class="code-snippet__string">'GET'</span></span></span><span class="code-snippet__meta"><span class="code-snippet__params">]</span></span><span class="code-snippet__meta">)</span></span></code><code><span leaf=""><span class="code-snippet__keyword">def</span> <span class="code-snippet__title">stream_audio</span>():</span></code><code><span leaf=""> <span class="code-snippet__string">"""</span></span></code><code><span leaf=""> HTTP 流式音频接口,接收文本并返回音频流。</span></code><code><span leaf=""> """</span></code><code><span leaf=""> text = request.args.get(<span class="code-snippet__string">'text'</span>, <span class="code-snippet__string">'你好,这是一段测试语音。'</span>)</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> <span class="code-snippet__keyword">not</span> text:</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> Response(<span class="code-snippet__string">"No text provided"</span>, status=<span class="code-snippet__number">400</span>)</span></code><code><span leaf=""> audio_chunks = generate_audio_stream(text)</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> audio_chunks <span class="code-snippet__keyword">is</span> <span class="code-snippet__literal">None</span>:</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> Response(<span class="code-snippet__string">"Audio generation failed"</span>, status=<span class="code-snippet__number">500</span>)</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> Response(audio_chunks, mimetype=<span class="code-snippet__string">'audio/wav'</span>)</span></code><code><span leaf=""><span class="code-snippet__keyword">if</span> __name__ == <span class="code-snippet__string">'__main__'</span>:</span></code><code><span leaf=""> <span class="code-snippet__comment"># 确保资产目录存在</span></span></code><code><span leaf=""> os.makedirs(ASSETS_DIR, exist_ok=<span class="code-snippet__literal">True</span>)</span></code><code><span leaf=""> </span></code><code><span leaf=""> <span class="code-snippet__comment"># 检查默认参考文件是否存在</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> <span class="code-snippet__keyword">not</span> os.path.exists(DEFAULT_REF_WAV):</span></code><code><span leaf=""> <span class="code-snippet__built_in">print</span>(<span class="code-snippet__string">f"Warning: Default reference WAV file not found at </span><span class="code-snippet__string"><span class="code-snippet__subst">{DEFAULT_REF_WAV}</span></span><span class="code-snippet__string">"</span>)</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> <span class="code-snippet__keyword">not</span> os.path.exists(DEFAULT_REF_NPY):</span></code><code><span leaf=""> <span class="code-snippet__built_in">print</span>(<span class="code-snippet__string">f"Warning: Default reference NPY file not found at </span><span class="code-snippet__string"><span class="code-snippet__subst">{DEFAULT_REF_NPY}</span></span><span class="code-snippet__string">"</span>)</span></code><code><span leaf=""> <span class="code-snippet__comment"># 启动 Flask 服务</span></span></code><code><span leaf=""> app.run(host=<span class="code-snippet__string">'0.0.0.0'</span>, port=<span class="code-snippet__number">5000</span>, debug=<span class="code-snippet__literal">True</span>)</span></code></pre> </section> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">使用方法</span></span></span></span></span></p> <ol style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">准备环境</span></span></span></span></span></p></li> <ul style="display: block;padding-inline-start: 2em;margin-block: 0.75em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">确保 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">checkpoints</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 目录包含所有必要的模型文件(</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">diffusion_transformer</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">、</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">aligner_lm</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 等)。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">将参考音频(</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">Chinese_prompt.wav</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)和潜在文件(</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">Chinese_prompt.npy</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)放入 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">assets</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 目录。</span></span></span></p></li> </ul> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">运行后端</span></span></span></span></span></p><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">bash</span></span></p><p></p><p> <svg viewbox="0 0 24 24" aria-hidden="true" style="color: black;background-color: transparent;font-family: sans-serif;"> <g style="color: black;background-color: transparent;font-family: sans-serif;"> <path d="M19.5 2C20.88 2 22 3.12 22 4.5v11c0 1.21-.86 2.22-2 2.45V4.5c0-.28-.22-.5-.5-.5H6.05c.23-1.14 1.24-2 2.45-2h11zm-4 4C16.88 6 18 7.12 18 8.5v11c0 1.38-1.12 2.5-2.5 2.5h-11C3.12 22 2 20.88 2 19.5v-11C2 7.12 3.12 6 4.5 6h11zM4 19.5c0 .28.22.5.5.5h11c.28 0 .5-.22.5-.5v-11c0-.28-.22-.5-.5-.5h-11c-.28 0-.5.22-.5.5v11z" style="color: black;background-color: transparent;font-family: sans-serif;"></path> </g> </svg><span style="border-bottom: 2px solid rgb(239, 243, 244);color: black;background-color: transparent;font-family: sans-serif;"></span></p><p></p><pre style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><code><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">python main.py</span></span></code></pre><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">服务将在 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">http://localhost:5000</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 上运行。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">前端调用</span></span></span></span></span></p></li> <ul style="display: block;padding-inline-start: 2em;margin-block: 0.75em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">前端代码无需修改,直接调用 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">http://localhost:5000/stream?text=...</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 即可接收音频流。</span></span></span></p></li> </ul> </ol> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">前端实现</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1. 前端代码(</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">src/App.jsx</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">以下是完整的 React 前端代码:</span></span></span></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="javascript"><code><span leaf=""><span class="code-snippet__keyword">import</span> <span class="code-snippet__title">React</span>, { useState, useRef } <span class="code-snippet__keyword">from</span> <span class="code-snippet__string">'react'</span>;</span></code><code><span leaf=""><span class="code-snippet__keyword">import</span> axios <span class="code-snippet__keyword">from</span> <span class="code-snippet__string">'axios'</span>;</span></code><code><span leaf=""><span class="code-snippet__keyword">const</span> <span class="code-snippet__title">App</span> = () => {</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> [inputText, setInputText] = <span class="code-snippet__title">useState</span>(<span class="code-snippet__string">''</span>);</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> [messages, setMessages] = <span class="code-snippet__title">useState</span>([]);</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> [isLoading, setIsLoading] = <span class="code-snippet__title">useState</span>(<span class="code-snippet__literal">false</span>);</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> audioContextRef = <span class="code-snippet__title">useRef</span>(<span class="code-snippet__keyword">new</span> <span class="code-snippet__title">AudioContext</span>());</span></code><code><span leaf=""> <span class="code-snippet__comment">// 处理文本输入</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> <span class="code-snippet__title">handleInputChange</span> = (<span class="code-snippet__params">e</span>) => <span class="code-snippet__title">setInputText</span>(e.<span class="code-snippet__property">target</span>.<span class="code-snippet__property">value</span>);</span></code><code><span leaf=""> <span class="code-snippet__comment">// 调用 Dify 接口并处理流式文本</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> <span class="code-snippet__title">fetchStreamText</span> = <span class="code-snippet__keyword">async</span> (<span class="code-snippet__params">text</span>) => {</span></code><code><span leaf=""> <span class="code-snippet__title">setIsLoading</span>(<span class="code-snippet__literal">true</span>);</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> response = <span class="code-snippet__keyword">await</span> <span class="code-snippet__title">fetch</span>(<span class="code-snippet__string">'http://localhost:5001/v1/chat-messages'</span>, {</span></code><code><span leaf=""> <span class="code-snippet__attr">method</span>: <span class="code-snippet__string">'POST'</span>,</span></code><code><span leaf=""> <span class="code-snippet__attr">headers</span>: {</span></code><code><span leaf=""> <span class="code-snippet__string">'Content-Type'</span>: <span class="code-snippet__string">'application/json'</span>,</span></code><code><span leaf=""> <span class="code-snippet__string">'Authorization'</span>: <span class="code-snippet__string">'Bearer YOUR_DIFY_API_KEY'</span>, <span class="code-snippet__comment">// 替换为你的 Dify API Key</span></span></code><code><span leaf=""> },</span></code><code><span leaf=""> <span class="code-snippet__attr">body</span>: <span class="code-snippet__title">JSON</span>.<span class="code-snippet__title">stringify</span>({</span></code><code><span leaf=""> <span class="code-snippet__attr">inputs</span>: { text },</span></code><code><span leaf=""> <span class="code-snippet__attr">query</span>: text,</span></code><code><span leaf=""> <span class="code-snippet__attr">response_mode</span>: <span class="code-snippet__string">'streaming'</span>,</span></code><code><span leaf=""> <span class="code-snippet__attr">user</span>: <span class="code-snippet__string">'user123'</span>,</span></code><code><span leaf=""> }),</span></code><code><span leaf=""> });</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> reader = response.<span class="code-snippet__property">body</span>.<span class="code-snippet__title">getReader</span>();</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> decoder = <span class="code-snippet__keyword">new</span> <span class="code-snippet__title">TextDecoder</span>();</span></code><code><span leaf=""> <span class="code-snippet__keyword">let</span> buffer = <span class="code-snippet__string">''</span>;</span></code><code><span leaf=""> <span class="code-snippet__keyword">while</span> (<span class="code-snippet__literal">true</span>) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> { done, value } = <span class="code-snippet__keyword">await</span> reader.<span class="code-snippet__title">read</span>();</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (done) <span class="code-snippet__keyword">break</span>;</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> chunk = decoder.<span class="code-snippet__title">decode</span>(value);</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> lines = chunk.<span class="code-snippet__title">split</span>(<span class="code-snippet__string">'\n'</span>);</span></code><code><span leaf=""> <span class="code-snippet__keyword">for</span> (<span class="code-snippet__keyword">const</span> line <span class="code-snippet__keyword">of</span> lines) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (line.<span class="code-snippet__title">startsWith</span>(<span class="code-snippet__string">'data: '</span>)) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> data = <span class="code-snippet__title">JSON</span>.<span class="code-snippet__title">parse</span>(line.<span class="code-snippet__title">slice</span>(<span class="code-snippet__number">6</span>));</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (data.<span class="code-snippet__property">event</span> === <span class="code-snippet__string">'message'</span>) {</span></code><code><span leaf=""> buffer += data.<span class="code-snippet__property">answer</span>;</span></code><code><span leaf=""> <span class="code-snippet__comment">// 检查是否到达句子结束</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (<span class="code-snippet__regexp">/[。!?]/</span>.<span class="code-snippet__title">test</span>(buffer)) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> sentences = buffer.<span class="code-snippet__title">split</span>(<span class="code-snippet__regexp">/(?<=[。!?])/</span>);</span></code><code><span leaf=""> <span class="code-snippet__keyword">for</span> (<span class="code-snippet__keyword">let</span> i = <span class="code-snippet__number">0</span>; i < sentences.<span class="code-snippet__property">length</span> - <span class="code-snippet__number">1</span>; i++) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> sentence = sentences[i];</span></code><code><span leaf=""> <span class="code-snippet__title">setMessages</span>(<span class="code-snippet__function">(</span><span class="code-snippet__function"><span class="code-snippet__params">prev</span></span><span class="code-snippet__function">) =></span> [...prev, { <span class="code-snippet__attr">text</span>: sentence, <span class="code-snippet__attr">isUser</span>: <span class="code-snippet__literal">false</span> }]);</span></code><code><span leaf=""> <span class="code-snippet__keyword">await</span> <span class="code-snippet__title">fetchAudio</span>(sentence); <span class="code-snippet__comment">// 调用 MegaTTS3 生成音频</span></span></code><code><span leaf=""> }</span></code><code><span leaf=""> buffer = sentences[sentences.<span class="code-snippet__property">length</span> - <span class="code-snippet__number">1</span>];</span></code><code><span leaf=""> }</span></code><code><span leaf=""> }</span></code><code><span leaf=""> }</span></code><code><span leaf=""> }</span></code><code><span leaf=""> }</span></code><code><span leaf=""> <span class="code-snippet__comment">// 处理剩余的缓冲区内容</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (buffer) {</span></code><code><span leaf=""> <span class="code-snippet__title">setMessages</span>(<span class="code-snippet__function">(</span><span class="code-snippet__function"><span class="code-snippet__params">prev</span></span><span class="code-snippet__function">) =></span> [...prev, { <span class="code-snippet__attr">text</span>: buffer, <span class="code-snippet__attr">isUser</span>: <span class="code-snippet__literal">false</span> }]);</span></code><code><span leaf=""> <span class="code-snippet__keyword">await</span> <span class="code-snippet__title">fetchAudio</span>(buffer);</span></code><code><span leaf=""> }</span></code><code><span leaf=""> <span class="code-snippet__title">setIsLoading</span>(<span class="code-snippet__literal">false</span>);</span></code><code><span leaf=""> };</span></code><code><span leaf=""> <span class="code-snippet__comment">// 调用 MegaTTS3 接口生成音频并播放</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> <span class="code-snippet__title">fetchAudio</span> = <span class="code-snippet__keyword">async</span> (<span class="code-snippet__params">text</span>) => {</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> response = <span class="code-snippet__keyword">await</span> <span class="code-snippet__title">fetch</span>(<span class="code-snippet__string">`http://localhost:5000/stream?text=</span><span class="code-snippet__string"><span class="code-snippet__subst">${</span></span><span class="code-snippet__string"><span class="code-snippet__subst"><span class="code-snippet__built_in">encodeURIComponent</span></span></span><span class="code-snippet__string"><span class="code-snippet__subst">(text)}</span></span><span class="code-snippet__string">`</span>);</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> reader = response.<span class="code-snippet__property">body</span>.<span class="code-snippet__title">getReader</span>();</span></code><code><span leaf=""> <span class="code-snippet__keyword">let</span> audioBufferQueue = [];</span></code><code><span leaf=""> <span class="code-snippet__keyword">let</span> isPlaying = <span class="code-snippet__literal">false</span>;</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> <span class="code-snippet__title">processChunk</span> = <span class="code-snippet__keyword">async</span> () => {</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> { done, value } = <span class="code-snippet__keyword">await</span> reader.<span class="code-snippet__title">read</span>();</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (done) <span class="code-snippet__keyword">return</span>;</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> audioBuffer = <span class="code-snippet__keyword">await</span> audioContextRef.<span class="code-snippet__property">current</span>.<span class="code-snippet__title">decodeAudioData</span>(value.<span class="code-snippet__property">buffer</span>);</span></code><code><span leaf=""> audioBufferQueue.<span class="code-snippet__title">push</span>(audioBuffer);</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (!isPlaying) {</span></code><code><span leaf=""> <span class="code-snippet__title">playNextBuffer</span>();</span></code><code><span leaf=""> }</span></code><code><span leaf=""> <span class="code-snippet__title">processChunk</span>();</span></code><code><span leaf=""> };</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> <span class="code-snippet__title">playNextBuffer</span> = () => {</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (audioBufferQueue.<span class="code-snippet__property">length</span> > <span class="code-snippet__number">0</span>) {</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> buffer = audioBufferQueue.<span class="code-snippet__title">shift</span>();</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> source = audioContextRef.<span class="code-snippet__property">current</span>.<span class="code-snippet__title">createBufferSource</span>();</span></code><code><span leaf=""> source.<span class="code-snippet__property">buffer</span> = buffer;</span></code><code><span leaf=""> source.<span class="code-snippet__title">connect</span>(audioContextRef.<span class="code-snippet__property">current</span>.<span class="code-snippet__property">destination</span>);</span></code><code><span leaf=""> source.<span class="code-snippet__property">onended</span> = playNextBuffer;</span></code><code><span leaf=""> source.<span class="code-snippet__title">start</span>();</span></code><code><span leaf=""> isPlaying = <span class="code-snippet__literal">true</span>;</span></code><code><span leaf=""> } <span class="code-snippet__keyword">else</span> {</span></code><code><span leaf=""> isPlaying = <span class="code-snippet__literal">false</span>;</span></code><code><span leaf=""> }</span></code><code><span leaf=""> };</span></code><code><span leaf=""> <span class="code-snippet__title">processChunk</span>();</span></code><code><span leaf=""> };</span></code><code><span leaf=""> <span class="code-snippet__comment">// 处理发送按钮点击</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> <span class="code-snippet__title">handleSend</span> = () => {</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> (!inputText.<span class="code-snippet__title">trim</span>()) <span class="code-snippet__keyword">return</span>;</span></code><code><span leaf=""> <span class="code-snippet__title">setMessages</span>(<span class="code-snippet__function">(</span><span class="code-snippet__function"><span class="code-snippet__params">prev</span></span><span class="code-snippet__function">) =></span> [...prev, { <span class="code-snippet__attr">text</span>: inputText, <span class="code-snippet__attr">isUser</span>: <span class="code-snippet__literal">true</span> }]);</span></code><code><span leaf=""> <span class="code-snippet__title">fetchStreamText</span>(inputText);</span></code><code><span leaf=""> <span class="code-snippet__title">setInputText</span>(<span class="code-snippet__string">''</span>);</span></code><code><span leaf=""> };</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> (</span></code><code><span leaf=""> <span class="code-snippet__tag"><</span><span class="code-snippet__tag"><span class="code-snippet__name">div</span></span><span class="code-snippet__tag"> </span><span class="code-snippet__tag"><span class="code-snippet__attr">className</span></span><span class="code-snippet__tag">=</span><span class="code-snippet__tag"><span class="code-snippet__string">"min-h-screen bg-gradient-to-br from-blue-100 to-purple-100 flex items-center justify-center p-4"</span></span><span class="code-snippet__tag">></span></span></code><code><span leaf=""> <span class="code-snippet__tag"><</span><span class="code-snippet__tag"><span class="code-snippet__name">div</span></span><span class="code-snippet__tag"> </span><span class="code-snippet__tag"><span class="code-snippet__attr">className</span></span><span class="code-snippet__tag">=</span><span class="code-snippet__tag"><span class="code-snippet__string">"w-full max-w-2xl bg-white rounded-lg shadow-xl p-6"</span></span><span class="code-snippet__tag">></span></span></code><code><span leaf=""> <span class="code-snippet__tag"><</span><span class="code-snippet__tag"><span class="code-snippet__name">h1</span></span><span class="code-snippet__tag"> </span><span class="code-snippet__tag"><span class="code-snippet__attr">className</span></span><span class="code-snippet__tag">=</span><span class="code-snippet__tag"><span class="code-snippet__string">"text-3xl font-bold text-center text-gray-800 mb-6"</span></span><span class="code-snippet__tag">></span>语音对话助手<span class="code-snippet__tag"><!--/</span--><span class="code-snippet__tag"><span class="code-snippet__name">h1</span></span><span class="code-snippet__tag">></span></span></span></code><code><span leaf=""> {/* 消息显示区域 */}</span></code><code><span leaf=""> <span class="code-snippet__tag"><</span><span class="code-snippet__tag"><span class="code-snippet__name">div</span></span><span class="code-snippet__tag"> </span><span class="code-snippet__tag"><span class="code-snippet__attr">className</span></span><span class="code-snippet__tag">=</span><span class="code-snippet__tag"><span class="code-snippet__string">"h-96 overflow-y-auto mb-4 p-4 bg-gray-50 rounded-lg border border-gray-200"</span></span><span class="code-snippet__tag">></span></span></code><code><span leaf=""> {messages.map((msg, index) => (</span></code><code><span leaf=""> <span class="code-snippet__tag"><</span><span class="code-snippet__tag"><span class="code-snippet__name">div</span></span></span></code><code><span leaf=""> <span class="code-snippet__attr">key</span>=<span class="code-snippet__string">{index}</span></span></code><code><span leaf=""> <span class="code-snippet__attr">className</span>=<span class="code-snippet__string">{</span>`<span class="code-snippet__attr">mb-2</span> <span class="code-snippet__attr">p-3</span> <span class="code-snippet__attr">rounded-lg</span> <span class="code-snippet__attr">max-w-</span>[<span class="code-snippet__attr">80</span>%] ${</span></code><code><span leaf=""> <span class="code-snippet__attr">msg.isUser</span></span></code><code><span leaf=""> ? '<span class="code-snippet__attr">bg-blue-500</span> <span class="code-snippet__attr">text-white</span> <span class="code-snippet__attr">ml-auto</span>'</span></code><code><span leaf=""> <span class="code-snippet__attr">:</span> '<span class="code-snippet__attr">bg-gray-200</span> <span class="code-snippet__attr">text-gray-800</span> <span class="code-snippet__attr">mr-auto</span>'</span></code><code><span leaf=""> }`}</span></code><code><span leaf=""> ></span></code><code><span leaf=""> {msg.text}</span></code><code><span leaf=""> <span class="code-snippet__tag"><!--/</span--><span class="code-snippet__tag"><span class="code-snippet__name">div</span></span><span class="code-snippet__tag">></span></span></span></code><code><span leaf=""> ))}</span></code><code><span leaf=""> {isLoading && (</span></code><code><span leaf=""> <span class="code-snippet__tag"><</span><span class="code-snippet__tag"><span class="code-snippet__name">div</span></span><span class="code-snippet__tag"> </span><span class="code-snippet__tag"><span class="code-snippet__attr">className</span></span><span class="code-snippet__tag">=</span><span class="code-snippet__tag"><span class="code-snippet__string">"text-gray-500 text-center"</span></span><span class="code-snippet__tag">></span>正在生成...<span class="code-snippet__tag"><!--/</span--><span class="code-snippet__tag"><span class="code-snippet__name">div</span></span><span class="code-snippet__tag">></span></span></span></code><code><span leaf=""> )}</span></code><code><span leaf=""> <span class="code-snippet__tag"><!--/</span--><span class="code-snippet__tag"><span class="code-snippet__name">div</span></span><span class="code-snippet__tag">></span></span></span></code><code><span leaf=""> {/* 输入框和发送按钮 */}</span></code><code><span leaf=""> <span class="code-snippet__tag"><</span><span class="code-snippet__tag"><span class="code-snippet__name">div</span></span><span class="code-snippet__tag"> </span><span class="code-snippet__tag"><span class="code-snippet__attr">className</span></span><span class="code-snippet__tag">=</span><span class="code-snippet__tag"><span class="code-snippet__string">"flex gap-2"</span></span><span class="code-snippet__tag">></span></span></code><code><span leaf=""> <span class="code-snippet__tag"><</span><span class="code-snippet__tag"><span class="code-snippet__name">input</span></span></span></code><code><span leaf=""> <span class="code-snippet__attr">type</span>=<span class="code-snippet__string">"text"</span></span></code><code><span leaf=""> <span class="code-snippet__attr">value</span>=<span class="code-snippet__string">{inputText}</span></span></code><code><span leaf=""> <span class="code-snippet__attr">onChange</span>=<span class="code-snippet__string">{handleInputChange}</span></span></code><code><span leaf=""> <span class="code-snippet__attr">placeholder</span>=<span class="code-snippet__string">"输入你的消息..."</span></span></code><code><span leaf=""> <span class="code-snippet__attr">className</span>=<span class="code-snippet__string">"flex-1 p-3 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500"</span></span></code><code><span leaf=""> <span class="code-snippet__attr">onKeyPress</span>=<span class="code-snippet__string">{(e)</span> => e.key === 'Enter' && handleSend()}</span></code><code><span leaf=""> /></span></code><code><span leaf=""> <span class="code-snippet__tag"><</span><span class="code-snippet__tag"><span class="code-snippet__name">button</span></span></span></code><code><span leaf=""> <span class="code-snippet__attr">onClick</span>=<span class="code-snippet__string">{handleSend}</span></span></code><code><span leaf=""> <span class="code-snippet__attr">disabled</span>=<span class="code-snippet__string">{isLoading}</span></span></code><code><span leaf=""> <span class="code-snippet__attr">className</span>=<span class="code-snippet__string">"px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:bg-gray-400 transition-colors"</span></span></code><code><span leaf=""> ></span></code><code><span leaf=""> 发送</span></code><code><span leaf=""> <span class="code-snippet__tag"><!--/</span--><span class="code-snippet__tag"><span class="code-snippet__name">button</span></span><span class="code-snippet__tag">></span></span></span></code><code><span leaf=""> <span class="code-snippet__tag"><!--/</span--><span class="code-snippet__tag"><span class="code-snippet__name">div</span></span><span class="code-snippet__tag">></span></span></span></code><code><span leaf=""> <span class="code-snippet__tag"><!--/</span--><span class="code-snippet__tag"><span class="code-snippet__name">div</span></span><span class="code-snippet__tag">></span></span></span></code><code><span leaf=""> <span class="code-snippet__tag"><!--/</span--><span class="code-snippet__tag"><span class="code-snippet__name">div</span></span><span class="code-snippet__tag">></span></span></span></code><code><span leaf=""> );</span></code><code><span leaf="">};</span></code><code><span leaf=""><span class="code-snippet__keyword">export</span> <span class="code-snippet__keyword">default</span> <span class="code-snippet__title">App</span>;</span></code></pre> </section> <p><span style="color: black;background-color: transparent;font-family: monospace;font-size: 10pt;"><span leaf=""><br></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">4. 修改 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">src/index.js</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">确保 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">App</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 组件正确渲染:</span></span></span></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="javascript"><code><span leaf=""><span class="code-snippet__keyword">import</span> <span class="code-snippet__title">React</span> <span class="code-snippet__keyword">from</span> <span class="code-snippet__string">'react'</span>;</span></code><code><span leaf=""><span class="code-snippet__keyword">import</span> <span class="code-snippet__title">ReactDOM</span> <span class="code-snippet__keyword">from</span> <span class="code-snippet__string">'react-dom'</span>;</span></code><code><span leaf=""><span class="code-snippet__keyword">import</span> <span class="code-snippet__string">'./index.css'</span>;</span></code><code><span leaf=""><span class="code-snippet__keyword">import</span> <span class="code-snippet__title">App</span> <span class="code-snippet__keyword">from</span> <span class="code-snippet__string">'./App'</span>;</span></code><code><span leaf=""><span class="code-snippet__title">ReactDOM</span>.<span class="code-snippet__title">render</span>(</span></code><code><span leaf=""> <span class="code-snippet__tag"><</span><span class="code-snippet__tag"><span class="code-snippet__name">React.StrictMode</span></span><span class="code-snippet__tag">></span></span></code><code><span leaf=""> <span class="code-snippet__tag"><</span><span class="code-snippet__tag"><span class="code-snippet__name">App</span></span><span class="code-snippet__tag"> /></span></span></code><code><span leaf=""> <span class="code-snippet__tag"><!--/</span--><span class="code-snippet__tag"><span class="code-snippet__name">React.StrictMode</span></span><span class="code-snippet__tag">></span>,</span></span></code><code><span leaf=""> <span class="code-snippet__variable">document</span>.<span class="code-snippet__title">getElementById</span>(<span class="code-snippet__string">'root'</span>)</span></code><code><span leaf="">);</span></code></pre> </section> <p><span style="color: black;background-color: transparent;font-family: monospace;font-size: 10pt;"><span leaf=""><br></span></span></p> <hr style="margin-top: 3em;margin-bottom: 3em;border-color: rgb(62, 65, 68);color: black;background-color: transparent;font-family: sans-serif;"> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">后端实现</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">Dify 接口</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">假设你已经在本地运行 Dify 服务(默认端口 5001),并配置了 DeepSeek 模型。Dify 的流式接口为 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">/v1/chat-messages</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">,支持 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">response_mode: streaming</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">。你需要替换 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">YOUR_DIFY_API_KEY</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 为实际的 API Key。</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">MegaTTS3 接口</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">参考之前提供的 Flask 后端代码(运行在 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">http://localhost:5000/stream</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">),确保它能接收文本并返回音频流。</span></span></span></span></p> <hr style="margin-top: 3em;margin-bottom: 3em;border-color: rgb(62, 65, 68);color: black;background-color: transparent;font-family: sans-serif;"> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">界面说明</span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">整体布局</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:使用 Tailwind CSS 创建了一个渐变背景,中心是一个白色卡片,包含标题、消息区域和输入框。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">消息显示</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:用户消息显示为蓝色气泡(靠右),系统消息为灰色气泡(靠左),支持滚动。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">输入框和按钮</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:输入框带有圆角和焦点效果,发送按钮为蓝色,禁用时变灰。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">响应式设计</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:适配不同屏幕大小,最大宽度限制为 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">max-w-2xl</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">。</span></span></span></p></li> </ul> <hr style="margin-top: 3em;margin-bottom: 3em;border-color: rgb(62, 65, 68);color: black;background-color: transparent;font-family: sans-serif;"> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">使用方法</span></span></span></span></span></p> <ol style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">启动 Dify 服务(假设在 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">localhost:5001</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">启动 MegaTTS3 的 Flask 服务(参考之前代码,运行在 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">localhost:5000</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">)。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">运行 React 项目:</span></span></span></p><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">bash</span></span></p><p></p><p> <svg viewbox="0 0 24 24" aria-hidden="true" style="color: black;background-color: transparent;font-family: sans-serif;"> <g style="color: black;background-color: transparent;font-family: sans-serif;"> <path d="M19.5 2C20.88 2 22 3.12 22 4.5v11c0 1.21-.86 2.22-2 2.45V4.5c0-.28-.22-.5-.5-.5H6.05c.23-1.14 1.24-2 2.45-2h11zm-4 4C16.88 6 18 7.12 18 8.5v11c0 1.38-1.12 2.5-2.5 2.5h-11C3.12 22 2 20.88 2 19.5v-11C2 7.12 3.12 6 4.5 6h11zM4 19.5c0 .28.22.5.5.5h11c.28 0 .5-.22.5-.5v-11c0-.28-.22-.5-.5-.5h-11c-.28 0-.5.22-.5.5v11z" style="color: black;background-color: transparent;font-family: sans-serif;"></path> </g> </svg><span style="border-bottom: 2px solid rgb(239, 243, 244);color: black;background-color: transparent;font-family: sans-serif;"></span></p><p></p><pre style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><code><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">npm</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> start</span></span></code></pre></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">打开浏览器(</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">http://localhost:3000</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">),输入文本并点击“发送”,即可看到流式文本和听到音频。</span></span></span></p></li> </ol> <hr style="margin-top: 3em;margin-bottom: 3em;border-color: rgb(62, 65, 68);color: black;background-color: transparent;font-family: sans-serif;"> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">注意事项</span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">API Key</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:确保在 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">fetchStreamText</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 中填入正确的 Dify API Key。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">端口冲突</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:确认 Dify 和 MegaTTS3 的服务端口与代码一致。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">音频格式</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:MegaTTS3 返回的音频应为 WAV 格式,前端才能正确解码。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">错误处理</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:当前代码未包含详细的错误处理,建议根据实际需求添加。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">这个实现结合了流式文本生成和音频播放,界面简洁美观,符合你的要求。如果需要进一步调整样式或功能,请告诉我!</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">WebRTC实现方案</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">后端实现</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">在后端,我们需要搭建一个 WebRTC 服务器来处理音频流的生成和传输。这里以 Python 为例,使用 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">aiortc</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 库(一个支持 WebRTC 的 Python 实现)来完成。</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1. 安装依赖</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">首先,安装必要的库:</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">bash</span></span></p> <p></p> <p> <svg viewbox="0 0 24 24" aria-hidden="true" style="color: black;background-color: transparent;font-family: sans-serif;"> <g style="color: black;background-color: transparent;font-family: sans-serif;"> <path d="M19.5 2C20.88 2 22 3.12 22 4.5v11c0 1.21-.86 2.22-2 2.45V4.5c0-.28-.22-.5-.5-.5H6.05c.23-1.14 1.24-2 2.45-2h11zm-4 4C16.88 6 18 7.12 18 8.5v11c0 1.38-1.12 2.5-2.5 2.5h-11C3.12 22 2 20.88 2 19.5v-11C2 7.12 3.12 6 4.5 6h11zM4 19.5c0 .28.22.5.5.5h11c.28 0 .5-.22.5-.5v-11c0-.28-.22-.5-.5-.5h-11c-.28 0-.5.22-.5.5v11z" style="color: black;background-color: transparent;font-family: sans-serif;"></path> </g> </svg><span style="border-bottom: 2px solid rgb(239, 243, 244);color: black;background-color: transparent;font-family: sans-serif;"></span></p> <p></p> <pre style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><code><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">pip </span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">install</span></span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> aiortc</span></span></code></pre> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">aiortc</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 提供了 WebRTC 的核心功能,支持实时音频和视频传输。</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">2. 设置 WebRTC 服务器</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">创建一个简单的 WebRTC 服务器,用于接收前端的连接请求并返回音频流。以下是基本代码示例:</span></span></span></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="python"><code><span leaf=""><span class="code-snippet__keyword">import</span> asyncio</span></code><code><span leaf=""><span class="code-snippet__keyword">import</span> json</span></code><code><span leaf=""><span class="code-snippet__keyword">from</span> aiohttp <span class="code-snippet__keyword">import</span> web</span></code><code><span leaf=""><span class="code-snippet__keyword">from</span> aiortc <span class="code-snippet__keyword">import</span> RTCPeerConnection, RTCSessionDescription</span></code><code><span leaf="">pcs = <span class="code-snippet__built_in">set</span>()</span></code><code><span leaf=""><span class="code-snippet__keyword">async</span> <span class="code-snippet__keyword">def</span> <span class="code-snippet__title">offer</span>(<span class="code-snippet__params">request</span>):</span></code><code><span leaf=""> params = <span class="code-snippet__keyword">await</span> request.json()</span></code><code><span leaf=""> offer = RTCSessionDescription(sdp=params[<span class="code-snippet__string">"sdp"</span>], <span class="code-snippet__built_in">type</span>=params[<span class="code-snippet__string">"type"</span>])</span></code><code><span leaf=""> <span class="code-snippet__comment"># 创建 PeerConnection</span></span></code><code><span leaf=""> pc = RTCPeerConnection()</span></code><code><span leaf=""> pcs.add(pc)</span></code><code><span leaf=""> <span class="code-snippet__comment"># 设置远程描述并生成应答</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">await</span> pc.setRemoteDescription(offer)</span></code><code><span leaf=""> answer = <span class="code-snippet__keyword">await</span> pc.createAnswer()</span></code><code><span leaf=""> <span class="code-snippet__keyword">await</span> pc.setLocalDescription(answer)</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> web.Response(</span></code><code><span leaf=""> content_type=<span class="code-snippet__string">"application/json"</span>,</span></code><code><span leaf=""> text=json.dumps({</span></code><code><span leaf=""> <span class="code-snippet__string">"sdp"</span>: pc.localDescription.sdp,</span></code><code><span leaf=""> <span class="code-snippet__string">"type"</span>: pc.localDescription.<span class="code-snippet__built_in">type</span></span></code><code><span leaf=""> })</span></code><code><span leaf=""> )</span></code><code><span leaf=""><span class="code-snippet__keyword">async</span> <span class="code-snippet__keyword">def</span> <span class="code-snippet__title">on_shutdown</span>(<span class="code-snippet__params">app</span>):</span></code><code><span leaf=""> <span class="code-snippet__comment"># 关闭所有连接</span></span></code><code><span leaf=""> coros = [pc.close() <span class="code-snippet__keyword">for</span> pc <span class="code-snippet__keyword">in</span> pcs]</span></code><code><span leaf=""> <span class="code-snippet__keyword">await</span> asyncio.gather(*coros)</span></code><code><span leaf=""> pcs.clear()</span></code><code><span leaf="">app = web.Application()</span></code><code><span leaf="">app.on_shutdown.append(on_shutdown)</span></code><code><span leaf="">app.router.add_post(<span class="code-snippet__string">"/offer"</span>, offer)</span></code><code><span leaf=""><span class="code-snippet__keyword">if</span> __name__ == <span class="code-snippet__string">"__main__"</span>:</span></code><code><span leaf=""> web.run_app(app, host=<span class="code-snippet__string">"0.0.0.0"</span>, port=<span class="code-snippet__number">8080</span>)</span></code></pre> </section> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">这个服务器监听 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">/offer</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 路由,接收前端的 WebRTC offer,并返回 answer。下一步是添加音频流。</span></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">3. 生成和编码音频流</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">假设你使用的是 MegaTTS3(或其他文本转语音模型)生成音频,生成的音频通常是 PCM 格式(原始音频数据)。WebRTC 默认使用 Opus 编解码器,因此需要将 PCM 数据编码为 Opus 格式。可以用 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">ffmpeg</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 工具实现编码:</span></span></span></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="python"><code><span leaf=""><span class="code-snippet__keyword">import</span> subprocess</span></code><code><span leaf=""><span class="code-snippet__keyword">def</span> <span class="code-snippet__title">encode_to_opus</span>(<span class="code-snippet__params">pcm_data, sample_rate=</span><span class="code-snippet__params"><span class="code-snippet__number">16000</span></span>):</span></code><code><span leaf=""> command = [</span></code><code><span leaf=""> <span class="code-snippet__string">'ffmpeg'</span>,</span></code><code><span leaf=""> <span class="code-snippet__string">'-f'</span>, <span class="code-snippet__string">'s16le'</span>, <span class="code-snippet__comment"># 输入格式为 16 位 PCM</span></span></code><code><span leaf=""> <span class="code-snippet__string">'-ar'</span>, <span class="code-snippet__built_in">str</span>(sample_rate), <span class="code-snippet__comment"># 采样率</span></span></code><code><span leaf=""> <span class="code-snippet__string">'-i'</span>, <span class="code-snippet__string">'pipe:0'</span>, <span class="code-snippet__comment"># 从管道读取输入</span></span></code><code><span leaf=""> <span class="code-snippet__string">'-c:a'</span>, <span class="code-snippet__string">'libopus'</span>, <span class="code-snippet__comment"># 使用 Opus 编码</span></span></code><code><span leaf=""> <span class="code-snippet__string">'-b:a'</span>, <span class="code-snippet__string">'16k'</span>, <span class="code-snippet__comment"># 比特率</span></span></code><code><span leaf=""> <span class="code-snippet__string">'-f'</span>, <span class="code-snippet__string">'opus'</span>, <span class="code-snippet__comment"># 输出格式</span></span></code><code><span leaf=""> <span class="code-snippet__string">'pipe:1'</span> <span class="code-snippet__comment"># 输出到管道</span></span></code><code><span leaf=""> ]</span></code><code><span leaf=""> process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)</span></code><code><span leaf=""> opus_data, _ = process.communicate(<span class="code-snippet__built_in">input</span>=pcm_data)</span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> opus_data</span></code></pre> </section> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">将 MegaTTS3 生成的音频(例如 numpy 数组)转换为 PCM 字节流后,调用此函数即可得到 Opus 数据。</span></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">4. 创建音频轨道</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">WebRTC 使用 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">MediaStreamTrack</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 对象表示音频流。我们需要自定义一个音频轨道,从 MegaTTS3 实时生成音频并传输:</span></span></span></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="python"><code><span leaf=""><span class="code-snippet__keyword">from</span> aiortc <span class="code-snippet__keyword">import</span> MediaStreamTrack</span></code><code><span leaf=""><span class="code-snippet__keyword">import</span> asyncio</span></code><code><span leaf=""><span class="code-snippet__keyword">import</span> numpy <span class="code-snippet__keyword">as</span> np</span></code><code><span leaf=""><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">MegaTTS3AudioTrack</span>(<span class="code-snippet__title">MediaStreamTrack</span>):</span></code><code><span leaf=""> kind = <span class="code-snippet__string">"audio"</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">def</span> <span class="code-snippet__title">__init__</span>(<span class="code-snippet__params">self, model, text, ref_wav</span>):</span></code><code><span leaf=""> <span class="code-snippet__built_in">super</span>().__init__()</span></code><code><span leaf=""> self.model = model <span class="code-snippet__comment"># MegaTTS3 模型</span></span></code><code><span leaf=""> self.text = text <span class="code-snippet__comment"># 输入文本</span></span></code><code><span leaf=""> self.ref_wav = ref_wav <span class="code-snippet__comment"># 参考音频</span></span></code><code><span leaf=""> self.queue = asyncio.Queue()</span></code><code><span leaf=""> asyncio.create_task(self.generate_audio())</span></code><code><span leaf=""> <span class="code-snippet__keyword">async</span> <span class="code-snippet__keyword">def</span> <span class="code-snippet__title">generate_audio</span>(<span class="code-snippet__params">self</span>):</span></code><code><span leaf=""> <span class="code-snippet__comment"># 按句子分块生成音频,实现流式输出</span></span></code><code><span leaf=""> sentences = self.text.split(<span class="code-snippet__string">'。'</span>)</span></code><code><span leaf=""> <span class="code-snippet__keyword">for</span> sentence <span class="code-snippet__keyword">in</span> sentences:</span></code><code><span leaf=""> <span class="code-snippet__keyword">if</span> sentence.strip():</span></code><code><span leaf=""> audio = self.model.inference(sentence, self.ref_wav) <span class="code-snippet__comment"># 生成音频</span></span></code><code><span leaf=""> pcm_data = (audio * <span class="code-snippet__number">32767</span>).astype(np.int16).tobytes() <span class="code-snippet__comment"># 转换为 PCM</span></span></code><code><span leaf=""> opus_data = encode_to_opus(pcm_data) <span class="code-snippet__comment"># 编码为 Opus</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">await</span> self.queue.put(opus_data) <span class="code-snippet__comment"># 放入队列</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">async</span> <span class="code-snippet__keyword">def</span> <span class="code-snippet__title">recv</span>(<span class="code-snippet__params">self</span>):</span></code><code><span leaf=""> <span class="code-snippet__comment"># 从队列中获取数据</span></span></code><code><span leaf=""> opus_data = <span class="code-snippet__keyword">await</span> self.queue.get()</span></code><code><span leaf=""> <span class="code-snippet__comment"># 这里需要将 Opus 数据封装为 WebRTC 所需的格式</span></span></code><code><span leaf=""> <span class="code-snippet__comment"># 具体实现可能需要借助 aiortc 的内部工具,暂略</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">return</span> opus_data</span></code></pre> </section> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">将此轨道添加到 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">RTCPeerConnection</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 中(在 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">offer</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 函数中添加 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">pc.addTrack(MegaTTS3AudioTrack(model, text, ref_wav))</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">),即可向前端传输音频。</span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">前端实现</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">在前端,使用 WebRTC API 与后端建立连接并接收音频流。</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1. 建立 WebRTC 连接</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">以下是一个简单的 JavaScript 示例:</span></span></span></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="javascript"><code><span leaf=""><span class="code-snippet__keyword">async</span> <span class="code-snippet__keyword">function</span> <span class="code-snippet__title">start</span>() {</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> pc = <span class="code-snippet__keyword">new</span> <span class="code-snippet__title">RTCPeerConnection</span>();</span></code><code><span leaf=""> <span class="code-snippet__comment">// 创建并设置本地 offer</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> offer = <span class="code-snippet__keyword">await</span> pc.<span class="code-snippet__title">createOffer</span>();</span></code><code><span leaf=""> <span class="code-snippet__keyword">await</span> pc.<span class="code-snippet__title">setLocalDescription</span>(offer);</span></code><code><span leaf=""> <span class="code-snippet__comment">// 发送 offer 到后端</span></span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> response = <span class="code-snippet__keyword">await</span> <span class="code-snippet__title">fetch</span>(<span class="code-snippet__string">'http://localhost:8080/offer'</span>, {</span></code><code><span leaf=""> <span class="code-snippet__attr">method</span>: <span class="code-snippet__string">'POST'</span>,</span></code><code><span leaf=""> <span class="code-snippet__attr">headers</span>: { <span class="code-snippet__string">'Content-Type'</span>: <span class="code-snippet__string">'application/json'</span> },</span></code><code><span leaf=""> <span class="code-snippet__attr">body</span>: <span class="code-snippet__title">JSON</span>.<span class="code-snippet__title">stringify</span>({</span></code><code><span leaf=""> <span class="code-snippet__attr">sdp</span>: pc.<span class="code-snippet__property">localDescription</span>.<span class="code-snippet__property">sdp</span>,</span></code><code><span leaf=""> <span class="code-snippet__attr">type</span>: pc.<span class="code-snippet__property">localDescription</span>.<span class="code-snippet__property">type</span></span></code><code><span leaf=""> })</span></code><code><span leaf=""> });</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> answer = <span class="code-snippet__keyword">await</span> response.<span class="code-snippet__title">json</span>();</span></code><code><span leaf=""> <span class="code-snippet__keyword">await</span> pc.<span class="code-snippet__title">setRemoteDescription</span>(<span class="code-snippet__keyword">new</span> <span class="code-snippet__title">RTCSessionDescription</span>(answer));</span></code><code><span leaf=""> <span class="code-snippet__comment">// 监听音频流并播放</span></span></code><code><span leaf=""> pc.<span class="code-snippet__property">ontrack</span> = <span class="code-snippet__function">(</span><span class="code-snippet__function"><span class="code-snippet__params">event</span></span><span class="code-snippet__function">) =></span> {</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> stream = event.<span class="code-snippet__property">streams</span>[<span class="code-snippet__number">0</span>];</span></code><code><span leaf=""> <span class="code-snippet__keyword">const</span> audio = <span class="code-snippet__variable">document</span>.<span class="code-snippet__title">createElement</span>(<span class="code-snippet__string">'audio'</span>);</span></code><code><span leaf=""> audio.<span class="code-snippet__property">srcObject</span> = stream;</span></code><code><span leaf=""> audio.<span class="code-snippet__property">autoplay</span> = <span class="code-snippet__literal">true</span>;</span></code><code><span leaf=""> <span class="code-snippet__variable">document</span>.<span class="code-snippet__property">body</span>.<span class="code-snippet__title">appendChild</span>(audio);</span></code><code><span leaf=""> };</span></code><code><span leaf="">}</span></code><code><span leaf=""><span class="code-snippet__title">start</span>();</span></code></pre> </section> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">此代码创建了一个 WebRTC 连接,发送 offer 到后端,接收 answer,并自动播放后端传来的音频流。</span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">webrtc的方式肯定比之前的方式延时低吗</span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">1. HTTP 流方式的延迟特性</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">在之前的方案中(例如使用 Flask 和 Web Audio API),音频流是通过 HTTP 协议传输的。这种方式的延迟主要来源于以下几个方面:</span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">生成延迟</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:MegaTTS3 等模型生成音频片段需要时间,尤其是基于扩散模型的 TTS,通常需要一次性生成完整音频片段(即使分块处理,也需要等待每个块生成完成)。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">传输延迟</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:HTTP 流(例如通过 </span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">Response</span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 对象返回音频数据)依赖 TCP 协议,涉及三次握手和数据分包传输。每次传输都需要客户端请求和服务器响应,可能会引入额外的网络往返时间(RTT)。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">缓冲延迟</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:前端接收音频数据后,通常需要缓冲一定量的数据才能开始播放(例如等待一个完整的 WAV 文件头或足够的数据块),这会增加感知延迟。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">典型延迟</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:在本地网络中,延迟可能在 100-500 毫秒之间;在广域网中,可能达到 1-2 秒甚至更高,具体取决于网络状况和分块大小。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">优点</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:</span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">实现简单,适合快速原型开发。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">不需要复杂的信令协议或服务器端支持。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">缺点</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:</span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">延迟较高,尤其是跨网络传输时。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">不适合需要极低延迟的实时交互场景。</span></span></span></p></li> </ul> <hr style="margin-top: 3em;margin-bottom: 3em;border-color: rgb(62, 65, 68);color: black;background-color: transparent;font-family: sans-serif;"> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">2. WebRTC 方式的延迟特性</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">WebRTC 是一种专为实时通信设计的协议,广泛用于视频会议和语音通话。它的延迟特性如下:</span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">生成延迟</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:与 HTTP 方式相同,仍然受限于 TTS 模型的生成速度。如果 MegaTTS3 不支持真正的流式生成(逐帧输出),WebRTC 也无法完全消除这部分延迟。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">传输延迟</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:WebRTC 使用 UDP 协议(而不是 TCP),避免了三次握手和重传的开销。它通过 RTP(实时传输协议)传输音频数据,能够以极低的延迟发送小块数据(通常 20-40 毫秒一帧)。此外,WebRTC 支持动态调整码率和丢包补偿,进一步优化传输效率。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">缓冲延迟</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:WebRTC 的设计目标是低延迟播放,通常只需要缓冲非常少的数据(几十毫秒)即可开始播放,前端可以几乎实时解码和播放收到的音频帧。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">典型延迟</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:在本地网络中,端到端延迟通常在 20-100 毫秒;在广域网中,可能在 100-300 毫秒,具体取决于网络抖动和带宽。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">优点</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:</span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">传输延迟极低,适合实时性要求高的场景。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">支持动态调整,适应网络变化。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">内置 Opus 编码,音频压缩效率高。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">缺点</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:</span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">实现复杂,需要处理信令(offer/answer)、ICE 候选协商等。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">对 TTS 模型的流式支持要求更高(如果模型本身不流式,WebRTC 的优势会被削弱)。</span></span></span></p></li> </ul> <section style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important; nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="502850691" data-ratio="0.3946731234866828" data-s="300,640" src="/upload/0faab4a9674b3f3dcf49cb5b1ae236e7.png" data-type="png" data-w="826" type="block"> </section> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">关键结论</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:</span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">理论上</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:WebRTC 的延迟通常比 HTTP 流低,因为它使用 UDP 和 RTP 优化了传输效率,并且缓冲需求更少。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">实际中</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:延迟差距是否显著,取决于以下因素:</span></span></span></p></li> <ol style="display: block;padding-inline-start: 2em;margin-block: 0.75em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">TTS 模型的生成速度</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:如果 MegaTTS3 生成一个音频块需要 500 毫秒,那么即使 WebRTC 传输只需 20 毫秒,总延迟仍以生成时间为主(500ms vs 520ms,差距不大)。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">网络环境</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:在本地网络中,HTTP 和 WebRTC 的延迟差异可能不明显(例如 100ms vs 50ms);在高延迟或丢包的广域网中,WebRTC 的优势更明显。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">分块策略</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:HTTP 流如果分块过大(例如等待完整句子),延迟会显著高于 WebRTC 的逐帧传输。</span></span></span></p></li> </ol> </ul> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">4. WebRTC 是否一定延迟更低?</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">不一定。以下是具体判断依据:</span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果 TTS 模型不支持真正的流式生成</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(例如 MegaTTS3 每次生成完整音频块),WebRTC 的低延迟传输优势会被生成延迟掩盖。此时,WebRTC 的总延迟可能仅比 HTTP 流低几十毫秒,感知差异不大。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果网络条件较差</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(高丢包或抖动),WebRTC 的自适应机制(丢包补偿、码率调整)会比 HTTP 流更稳定,延迟优势更明显。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果实现得当</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">(例如 TTS 模型支持逐帧输出,WebRTC 配置优化),WebRTC 的端到端延迟可以低至 50-100 毫秒,远优于 HTTP 流的数百毫秒。</span></span></span></p></li> </ul> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">5. 建议</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">为了确保 WebRTC 带来更低的延迟,你需要:</span></span></span></span></p> <ol style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">优化 TTS 模型</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:选择或改造一个支持真正流式输出的 TTS 模型(例如逐帧生成音频,而不是完整块)。MegaTTS3 如果不支持,可以考虑其他流式 TTS(如 VALL-E X 或 StreamSpeech)。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">测试实际延迟</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:在你的具体场景中(本地或广域网)对比 HTTP 流和 WebRTC 的端到端延迟,量化两者的差异。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">结合分块策略</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">:即使使用 WebRTC,也需要合理分块(例如按短语或句子),避免生成和传输之间的瓶颈。</span></span></span></p></li> </ol> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">总结</span></span></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">即使大模型每次输出的文本不长,采用双流输出(文本和语音同时流式输出)仍然能显著提升用户体验,减少感知延迟,并让对话更自然、更流畅。在你的 Web 应用方案中,通过后端的流式生成、前端的实时处理,以及 WebRTC(如果需要)的支持,完全可以实现这一功能。</span></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">在双流输出中,你应该在大模型生成一个完整短语或句子(通常以标点符号为界)时,立即将该文本片段传递给TTS系统开始转语音。这样可以实现文本显示和语音播放的同步,提供实时、自然的对话体验。如果生成速度较快,也可以结合时间窗口(如每0.5秒)或最小长度来分块,确保流畅性和效率的平衡。</span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">WebRTC 在传输和缓冲上的延迟通常比 HTTP 流低,尤其在实时性要求高的场景中优势明显。然而,如果 TTS 模型的生成延迟占主导(例如 MegaTTS3 的扩散模型特性),WebRTC 的总体延迟降低可能有限。因此,建议你先测试 MegaTTS3 的生成速度,再决定是否投入精力实现 WebRTC。如果生成速度足够快,WebRTC 确实能显著降低延迟,值得一试!</span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="color: #f00;font-weight: bold;">哪些开源模型支持流式输出的 TTS 服务</span></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></p> <p data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">以下是一些支持流式输出的开源 TTS(文本转语音)模型的列表。这些模型能够逐步生成音频,非常适合实时应用场景,例如语音助手或实时翻译等。以下是详细介绍:</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">1. MegaTTS3</span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">简介</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">: 由字节跳动开源的轻量级 TTS 模型,主干模型仅有 0.45 亿参数。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">特点</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">: 支持中英文及中英混读,具备口音强度控制功能。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">流式输出</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">: 支持实时生成音频,非常适用于需要快速响应的应用场景。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">2. Orpheus</span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">简介</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">: 一个多语种的开源 TTS 模型,兼顾生成速度和音质。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">特点</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">: 支持微调,开发者可以快速上手并根据需求进行定制。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">流式输出</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">: 具备流式输出能力,适合实时语音生成。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">3. F5-TTS</span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">简介</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">: 开源 TTS 模型,支持零样本声音克隆,生成的语音自然且富有表现力。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">特点</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">: 推理实时率优于现有的基于扩散的 TTS 模型,支持控制语音速度,同时保持声音的自然度。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">流式输出</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">: 支持逐步生成音频,适用于实时应用。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">4. Kokoro TTS</span></span></span></span></span></p> <ul style="display: block;padding-inline-start: 2em;margin-block: 0px 1.25em;color: black;background-color: transparent;font-family: sans-serif;" class="list-paddingleft-1"> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">简介</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">: 一个专注于实时应用的开源 TTS 模型。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">特点</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">: 设计简洁,易于集成到各种系统中。</span></span></span></p></li> <li><p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">流式输出</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">: 支持流式输出,能够满足实时音频生成需求。</span></span></span></p></li> </ul> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span textstyle="" style="font-weight: bold;">总结</span></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">上述模型——</span></span></span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">MegaTTS3</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">、</span></span></span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">Orpheus</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">、</span></span></span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">F5-TTS</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 和 </span></span></span><span><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">Kokoro TTS</span></span></span></span></span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">——均是开源的 TTS 模型,支持流式输出功能。开发者可以根据具体需求(如语言支持、音质要求或推理速度)选择合适的模型进行开发和集成。这些模型的开源特性使其免费且可修改,非常适合研究人员和开发者使用。</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">上述方案都来自grok。所以可能存在一些不足的地方,代码可能也有些小问题。但可以通过多个AI结合修复。通过借鉴上述方案,我的数字人的语音方案正在做重构,争取得到延时最低。下面是根据上述方案实验效果:</span></span></span></span></p> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <section nodeleaf=""> <iframe src="https://mp.weixin.qq.com/mp/readtemplate?t=pages/video_player_tmpl&action=mpvideo&auto=0&vid=wxv_3930162770800345100" data-mpvid="wxv_3930162770800345100" data-vidtype="2" data-cover="http%3A%2F%2Fmmbiz.qpic.cn%2Fmmbiz_jpg%2FJu7VaP4zbQic1DtL3lB18hucNm3z5ZNuyaetIVua0T9QxMicEm6rMqdfhb4kuqC1KFybcB1zCQKOCBEKfr2088cQ%2F0%3Fwx_fmt%3Djpeg" class="video_iframe rich_pages"></iframe> </section> <p style="-webkit-tap-highlight-color: transparent;margin: 0px 8px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: left;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;><span><span><span><span leaf="" style="font-size: 15px;visibility: visible;-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></span></span></span></p> <p><span style="color: black;background-color: transparent;font-family: sans-serif;"><span style="color: black;background-color: transparent;font-family: sans-serif;"><span style="color: black;background-color: transparent;font-family: sans-serif;"><span leaf=""><br></span></span></span></span></p> <section class="js_darkmode__33" data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px 8px 0em;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: 0.544px;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;background-color: rgb(255, 255, 255);color: rgb(62, 62, 62);text-align: -webkit-center;font-size: 16px;font-family: -apple-system, system-ui, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;visibility: visible;line-height: 1.75em;> <span class="js_darkmode__34" style="-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;color: rgb(255, 0, 0);font-size: 15px;"><strong style="-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible;"><span leaf="" style="-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">加入知识星球可添加作者微信随时沟通。</span></strong></span> </section>
作者:微信小助手
<section style="text-indent: 2em;"> <span leaf="" style="color: rgba(0, 0, 0, 0.9);font-size: 17px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;line-height: 1.6;letter-spacing: 0.034em;font-style: normal;font-weight: normal;><span textstyle="" style="font-size: 16px;">紧随百度地图mcp的发布,高德地图也发布了mcp服务。这次我们用高德地图mcp做一个旅行攻略。</span></span><span data-pm-slice="0 0 []"><span leaf="" style="color: rgba(0, 0, 0, 0.9);font-size: 17px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;line-height: 1.6;letter-spacing: 0.034em;font-style: normal;font-weight: normal;><br></span></span> </section> <section style="text-indent: 2em;"> <span data-pm-slice="0 0 []"><span leaf="" style="color: rgba(0, 0, 0, 0.9);font-size: 17px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;line-height: 1.6;letter-spacing: 0.034em;font-style: normal;font-weight: normal;><span textstyle="" style="font-size: 16px;">据高德官网介绍,高德地图MCP Server覆盖12大核心接口,提供全场景覆盖的地理信息服务,包括地理编码、逆地理编码、IP定位、天气查询、骑行路径规划、步行路径规划、驾车路径规划、公交路径规划、距离测量、关键词搜索、周边搜索、详情搜索等。</span></span></span> </section> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 0px;color: rgb(10, 10, 10);font-family: ui-sans-serif, system-ui, sans-serif, " apple color emoji, segoe ui symbol, noto emoji;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 0px;line-height: 0; data-pm-slice="0 0 []"><span leaf=""> </span></p> <section style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(10, 10, 10);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 16px;> <h3 data-heading="true" style="box-sizing: border-box;border-width: 0px 0px 0px 3px;border-style: solid;border-left-color: rgb(15, 76, 129);font-size: 17.6px;font-weight: bold;margin: 0px 8px 0.75em 0px;text-align: left;line-height: 1.2;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;padding-left: 8px;color: rgb(63, 63, 63);><span leaf="">1. 获取 key,在 windsurf中配置 mcp</span></h3> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 16px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">从</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 16px;color: rgb(87, 107, 149);><span leaf="">高德开放平台</span></span><span leaf="">申请应用的 key,配置到windsurf的mcp中</span></p> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;background: rgb(43, 43, 43);color: rgb(248, 248, 242);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 16px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span leaf=""> "amap-maps": {</span><span leaf=""><br></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf=""> "command": "npx",</span><span leaf=""><br></span><span leaf=""> "args": ["-y", "@amap/amap-maps-mcp-server"],</span><span leaf=""><br></span><span leaf=""> "env": {</span><span leaf=""><br></span><span leaf=""> "AMAP_MAPS_API_KEY": "高德的key"</span><span leaf=""><br></span><span leaf=""> }</span><span leaf=""><br></span><span leaf=""> }</span></span></code></pre> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 16px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">配置成功后</span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100000805" data-ratio="0.7029702970297029" data-s="300,640" src="/upload/bdb53c30a84df2e26ee0ad00cbb7dd14.png" data-type="png" data-w="808" type="block"> </section> <h3 data-heading="true" style="box-sizing: border-box;border-width: 0px 0px 0px 3px;border-style: solid;border-left-color: rgb(15, 76, 129);font-size: 17.6px;font-weight: bold;margin: 2em 8px 0.75em 0px;text-align: left;line-height: 1.2;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;padding-left: 8px;color: rgb(63, 63, 63);><span leaf="">2. 使用Agent自动编码,展示网页效果</span></h3> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 16px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14.4px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">1.</span></code><span leaf="">输入口令:用高德MCP,生成一个清明杭州旅游攻略,规划出具体的路线,时间点,注意事项。</span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100000806" data-ratio="1.3217665615141956" data-s="300,640" src="/upload/73231bfe67f4528269851262db79e31a.png" data-type="png" data-w="1268" type="block"> </section> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 16px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14.4px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">2.</span></code><span leaf="">让 ai自动编码生成展示网页</span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100000807" data-ratio="0.31433224755700323" data-s="300,640" src="/upload/b1c33326c33611e3128af9176bd28cfa.png" data-type="png" data-w="1228" type="block"> </section> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 16px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14.4px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">3.</span></code><span leaf="">最终展示成果</span></p> </section> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 0px;color: rgb(10, 10, 10);font-family: ui-sans-serif, system-ui, sans-serif, " apple color emoji, segoe ui symbol, noto emoji;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 0px;line-height: 0;><span leaf=""> </span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100000808" data-ratio="1.88828125" data-s="300,640" src="/upload/e6d6ea822183e36fa1b9591682b0f72b.png" data-type="png" data-w="1280" type="block"> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-size: 20px;-webkit-line-clamp: unset;max-height: unset; data-pm-slice="0 0 []"><em data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;font-style: italic;"><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">本文对 Llama Factory、Unsloth 和 Hugging Face 在微调大型语言模型方面的全面性能分析!</span></font></font></font></em></p> <h1 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 1.95em 0px -0.28em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;line-height: 30px;letter-spacing: -0.016em;font-weight: 600;font-size: 24px;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><strong data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-weight: inherit;"><span leaf="">1. 简介 </span></strong><span leaf="">🌟</span></font></font></font></h1> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 0.94em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">大型语言模型(LLMs)的领域已经发生了巨大变化,微调已成为将这些模型部署到特定应用中的关键步骤。虽然预训练通过在大量文本语料库上使用自监督学习构建模型的基础知识,但监督式微调(SFT)则使用标记数据将这些预训练模型适应特定任务。</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">将预训练视为给模型提供关于世界的通用知识,而微调则像是教它一个特定职业。这个过程的专业化至关重要,因为它:</span></font></font></font></p> <ul style="box-sizing: inherit;margin: 0px;padding: 0px;list-style: none none;" class="list-paddingleft-1"> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 2.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">🎯 使模型与特定用例保持一致</span></font></font></font></li> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 1.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">📈 提高特定领域任务的性能</span></font></font></font></li> </ul> <h1 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 1.95em 0px -0.28em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;line-height: 30px;letter-spacing: -0.016em;font-weight: 600;font-size: 24px;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">2. 微调背后的科学:文献综述 📚</span></font></font></font></h1> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 0.94em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">现代 SFT 方法利用了几个关键技术,每个技术都基于突破性的研究:</span></font></font></font></p> <h2 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;margin: 1.72em 0px -0.31em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;letter-spacing: 0px;font-weight: 600;line-height: 24px;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><strong data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-weight: inherit;"><em data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;font-style: inherit;"><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">i. 参数高效微调(PEFT)</span></font></font></font></em></strong></h2> <ul style="box-sizing: inherit;margin: 0px;padding: 0px;list-style: none none;" class="list-paddingleft-1"> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 0.94em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><strong data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-weight: 700;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;><em data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-style: italic;"><span leaf="">LoRA(低秩自适应)</span></em></strong><span leaf="">— </span><span leaf="">https://arxiv.org/abs/2106.09685</span></font></font></font> <section> <span leaf=""><br></span><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">- </span><em data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-style: italic;"><span leaf="">通过将权重更新分解为低秩矩阵来减少训练参数</span></em></font></font></font> </section></li> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 1.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><strong data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-weight: 700;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;><em data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-style: italic;"><span leaf="">QLoRA(量化 LoRA)</span></em></strong><span leaf="">— </span><span leaf="">“QLoRA:高效量化LLMs微调”</span></font></font></font> <section> <span leaf=""><br></span><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">- </span><em data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-style: italic;"><span leaf="">将量化与 LoRA 结合,实现更高的内存效率</span></em></font></font></font> </section></li> </ul> <h2 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;margin: 1.72em 0px -0.31em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;letter-spacing: 0px;font-weight: 600;line-height: 24px;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><strong data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-weight: inherit;"><em data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;font-style: inherit;"><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">ii. 优化技术</span></font></font></font></em></strong></h2> <ul style="box-sizing: inherit;margin: 0px;padding: 0px;list-style: none none;" class="list-paddingleft-1"> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 0.94em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><strong data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-weight: 700;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;><em data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-style: italic;"><span leaf="">混合精度训练 </span></em></strong><span leaf="">—</span><span leaf="">“混合精度训练”</span></font></font></font> <section> <span leaf=""><br></span><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">- </span><em data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-style: italic;"><span leaf="">使用 16 位和 32 位浮点运算</span></em></font></font></font> </section></li> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 1.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><strong data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-weight: 700;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;><em data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-style: italic;"><span leaf="">Flash Attention</span></em></strong><span leaf=""> — </span><span leaf="">“FlashAttention:具有 IO 感知的快速且内存高效的精确注意力”</span></font></font></font> <section> <span leaf=""><br></span><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">- </span><em data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-style: italic;"><span leaf="">优化注意力计算以获得更好的内存效率</span></em></font></font></font> </section></li> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 1.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><strong data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-weight: 700;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;><em data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-style: italic;"><span leaf="">Flash Attention 2</span></em></strong><span leaf="">— </span><span leaf="">“Flash Attention-2:更快的注意力与更好的并行性”</span></font></font></font> <section> <span leaf=""><br></span><em data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;font-style: italic;"><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">进一步提高注意力计算的速度和效率</span></font></font></font></em> </section></li> </ul> <h1 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 1.95em 0px -0.28em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;line-height: 30px;letter-spacing: -0.016em;font-weight: 600;font-size: 24px;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">大模型微调库对比</span></font></font></font></h1> <p><span leaf=""><br></span></p> <figure data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;margin: 56px auto 0px;clear: both;"> <p> <picture data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;"> <span leaf=""><img src="/upload/255721987dc03cc6568a9a2004c64c52.png" class="rich_pages wxw-img" data-ratio="0.9651162790697675" data-type="png" data-w="344" height="332" style="box-sizing: inherit;vertical-align: middle;background-color: rgb(255, 255, 255);width: 344px;max-width: 100%;height: auto;" width="344" data-imgfileid="100058990"></span> </picture></p> <figcaption data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;font-weight: 400;line-height: 20px;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;font-size: 14px;color: rgb(107, 107, 107);margin-left: auto;margin-right: auto;margin-top: 10px;text-align: center;max-width: 728px;> <font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">Hugging Face</span></font></font></font> </figcaption> </figure> <p><span leaf=""><br></span></p> <ol style="box-sizing: inherit;margin: 0px;padding: 0px;list-style: none none;" class="list-paddingleft-1"> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;margin-left: 30px;padding-left: 0px;list-style-type: decimal;font-size: 20px;margin-top: 2.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><strong data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-weight: 700;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;><span leaf="">Hugging Face Transformers</span></strong><span leaf="">🤗</span></font></font></font></li> </ol> <ul style="box-sizing: inherit;margin: 0px;padding: 0px;list-style: none none;" class="list-paddingleft-1"> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 2.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">🌟 机器学习模型行业标准</span></font></font></font></li> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 1.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">📚 完善的文档和社区支持</span></font></font></font></li> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 1.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">🌐 广泛的生态系统和模型库</span></font></font></font></li> </ul> <p><span leaf=""><br></span></p> <figure data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;margin: 56px auto 0px;clear: both;"> <p> <picture data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;"> <span leaf=""><img src="/upload/1fa2e491f19eea67a6f61ba2a3d8888d.png" class="rich_pages wxw-img" data-ratio="0.6666666666666666" data-type="png" data-w="480" height="320" style="box-sizing: inherit;vertical-align: middle;background-color: rgb(255, 255, 255);width: 480px;max-width: 100%;height: auto;" width="480" data-imgfileid="100058991"></span> </picture></p> <figcaption data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;font-weight: 400;line-height: 20px;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;font-size: 14px;color: rgb(107, 107, 107);margin-left: auto;margin-right: auto;margin-top: 10px;text-align: center;max-width: 728px;> <font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">羊驼工厂</span></font></font></font> </figcaption> </figure> <p><span leaf=""><br></span></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">2.</span><strong data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-weight: 700;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;><span leaf=""> </span><span leaf="" data-pm-slice="0 0 []">Llama Factory</span></strong></font></font></font></p> <ul style="box-sizing: inherit;margin: 0px;padding: 0px;list-style: none none;" class="list-paddingleft-1"> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 2.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">🚀 高效的多 GPU 支持</span></font></font></font></li> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 1.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">⚙️ 简化配置(yaml 文件或 UI 界面)</span></font></font></font></li> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 1.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">仓库: </span><span leaf="">github.com/hiyouga/LLaMA-Factory</span></font></font></font></li> </ul> <p><span leaf=""><br></span></p> <figure data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;margin: 56px auto 0px;clear: both;"> <p> <picture data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;"> <span leaf=""><img src="/upload/662298c2f53e2d3540cea82031b7587c.png" class="rich_pages wxw-img" data-ratio="1.0114942528735633" data-type="png" data-w="174" height="177" style="box-sizing: inherit;vertical-align: middle;background-color: rgb(255, 255, 255);width: 174px;max-width: 100%;height: auto;" width="174" data-imgfileid="100058989"></span> </picture></p> <figcaption data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;font-weight: 400;line-height: 20px;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;font-size: 14px;color: rgb(107, 107, 107);margin-left: auto;margin-right: auto;margin-top: 10px;text-align: center;max-width: 728px;> <font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">无需翻译</span></font></font></font> </figcaption> </figure> <p><span leaf=""><br></span></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">3.</span><strong data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;font-weight: 700;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;><span leaf="">Unsloth</span></strong></font></font></font></p> <ul style="box-sizing: inherit;margin: 0px;padding: 0px;list-style: none none;" class="list-paddingleft-1"> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 2.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">⚡ 新晋参与者,专注于速度优化</span></font></font></font></li> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 1.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">💪 单 GPU 优化</span></font></font></font></li> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 1.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">🧠 高级内存管理</span></font></font></font></li> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 1.14em;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">仓库: </span><span leaf="">github.com/unslothai/unsloth</span></font></font></font></li> </ul> <h1 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 1.95em 0px -0.28em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;line-height: 30px;letter-spacing: -0.016em;font-weight: 600;font-size: 24px;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">实验设置 🧪</span></font></font></font></h1> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 0.94em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">为了进行公平的比较,我们进行了广泛的测试,使用以下方法:</span></font></font></font></p> <h1 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 1.95em 0px -0.28em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;line-height: 30px;letter-spacing: -0.016em;font-weight: 600;font-size: 24px;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">- 硬件配置 🖥️</span></font></font></font></h1> <blockquote style="box-sizing: inherit;margin: 0px 0px 0px -20px;box-shadow: rgb(36, 36, 36) 3px 0px 0px 0px inset;padding-left: 23px;"> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">🏭 Llama Factory:2 块 NVIDIA A100 80GB GPU</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">🚀 Unsloth:1 块 NVIDIA A100 80GB GPU</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">🤗 Hugging Face:1 块 NVIDIA A100 80GB GPU</span></font></font></font></p> </blockquote> <h1 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 1.95em 0px -0.28em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;line-height: 30px;letter-spacing: -0.016em;font-weight: 600;font-size: 24px;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">- 数据集规格 📊</span></font></font></font></h1> <blockquote style="box-sizing: inherit;margin: 0px 0px 0px -20px;box-shadow: rgb(36, 36, 36) 3px 0px 0px 0px inset;padding-left: 23px;"> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">💬 大约94,000次对话</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">📝 总计 3500 万个 token</span></font></font></font></p> </blockquote> <h1 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 1.95em 0px -0.28em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;line-height: 30px;letter-spacing: -0.016em;font-weight: 600;font-size: 24px;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">- 模型和训练参数 ⚙️</span></font></font></font></h1> <blockquote style="box-sizing: inherit;margin: 0px 0px 0px -20px;box-shadow: rgb(36, 36, 36) 3px 0px 0px 0px inset;padding-left: 23px;"> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">基础模型:🦙 Llama 3.1 8B Instruct</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">LoRA 配置:</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">🎯 排名:42</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">🎮 Alpha:72</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">💧 Dropout:0.1</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">不同超参数:</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">📏 最大序列长度:256,512,1024,2048</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">📦 批处理大小:4,8,16,32,64</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">🔄 迭代次数:15</span></font></font></font></p> </blockquote> <h1 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 1.95em 0px -0.28em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;line-height: 30px;letter-spacing: -0.016em;font-weight: 600;font-size: 24px;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">结果与分析</span></font></font></font></h1> <p><span leaf=""><br></span></p> <figure data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;margin: 56px 0px 0px;clear: both;padding-top: 5px;padding-bottom: 5px;"> <p> <picture data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;"> <span leaf=""><img src="/upload/634628e4688a95f8c065c39aa5440e18.png" class="rich_pages wxw-img" data-ratio="0.6666666666666666" data-type="png" data-w="1080" height="667" style="box-sizing: inherit;vertical-align: middle;background-color: rgb(255, 255, 255);width: 1192px;max-width: 100%;height: auto;" width="1000" data-imgfileid="100058992"></span> </picture></p> <figcaption data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;font-weight: 400;line-height: 20px;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;font-size: 14px;color: rgb(107, 107, 107);margin-left: auto;margin-right: auto;margin-top: 10px;text-align: center;max-width: 728px;> <font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">图 1:使用 HuggingFace、Unsloth 和 Llama Factory 的训练时间持续时间</span></font></font></font> </figcaption> </figure> <p><span leaf=""><br></span></p> <h1 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 1.95em 0px -0.28em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;line-height: 30px;letter-spacing: -0.016em;font-weight: 600;font-size: 24px;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">训练时间分析 📊</span></font></font></font></h1> <ul style="box-sizing: inherit;margin: 0px;padding: 0px;list-style: none none;" class="list-paddingleft-1"> <li style="box-sizing: inherit;font-weight: 400;color: rgb(36, 36, 36);font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;margin-bottom: -0.46em;list-style-type: disc;margin-left: 30px;padding-left: 0px;font-size: 20px;margin-top: 0.94em;><strong data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;font-weight: 700;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">序列长度影响 ⚡</span></font></font></font></strong></li> </ul> <blockquote style="box-sizing: inherit;margin: 0px 0px 0px -20px;box-shadow: rgb(36, 36, 36) 3px 0px 0px 0px inset;padding-left: 23px;"> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">所有曲线的上升趋势都表明序列长度对训练时间的影响非常显著。这主要是因为注意力机制的二次复杂度(n²)——当序列长度加倍时,计算成本会翻四倍。这解释了为什么当我们从 256 个令牌增加到 2048 个令牌时,训练时间的增加会更加陡峭。🔄</span></font></font></font></p> </blockquote> <h1 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 1.95em 0px -0.28em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;line-height: 30px;letter-spacing: -0.016em;font-weight: 600;font-size: 24px;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">相对性能 📈</span></font></font></font></h1> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 0.94em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">Llama Factory 双 GPU 演示:</span></font></font></font></p> <blockquote style="box-sizing: inherit;margin: 0px 0px 0px -20px;box-shadow: rgb(36, 36, 36) 3px 0px 0px 0px inset;padding-left: 23px;"> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">⚡ 比 Unsloth 快 33%</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">🔥 比 Hugging Face 快 54%</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">💪 更好的扩展性,支持更大的批量大小</span></font></font></font></p> </blockquote> <h1 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" style="box-sizing: inherit;margin: 1.95em 0px -0.28em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;line-height: 30px;letter-spacing: -0.016em;font-weight: 600;font-size: 24px;><strong data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;font-weight: inherit;"><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">内存管理 🧠</span></font></font></font></strong></h1> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 0.94em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">Unsloth 在内存效率方面表现出特别令人印象深刻的性能:</span></font></font></font></p> <blockquote style="box-sizing: inherit;margin: 0px 0px 0px -20px;box-shadow: rgb(36, 36, 36) 3px 0px 0px 0px inset;padding-left: 23px;"> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">💪 可保持至批大小32的稳定性,序列长度可达2048</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">🚀 仅在批大小64时出现内存不足,序列长度1024+</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">⭐ 比 HF 表现更优,HF 在批大小 32、序列长度 1024 时更早出现内存不足</span></font></font></font></p> </blockquote> <h1 data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 1.95em 0px -0.28em;font-family: sohne, " helvetica neue, helvetica, arial, sans-serif;color: rgb(36, 36, 36);font-style: normal;line-height: 30px;letter-spacing: -0.016em;font-weight: 600;font-size: 24px;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">结论 🎯</span></font></font></font></h1> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 0.94em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;font-style: normal;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf="">我们的综合分析为从业者提供了一条简单明了的建议:</span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf=""><span textstyle="" style="font-weight: bold;">单 GPU 配置:💪 选择 Unsloth,因其卓越的内存效率和有竞争力的性能</span></span></font></font></font></p> <p data-selectable-paragraph="" data-immersive-translate-walked="007d119b-bff2-4785-a153-e363a803d6b3" data-immersive-translate-paragraph="1" style="box-sizing: inherit;margin: 2.14em 0px -0.46em;font-weight: 400;color: rgb(36, 36, 36);word-break: break-word;line-height: 32px;letter-spacing: -0.003em;font-family: source-serif-pro, Georgia, Cambria, " times new roman, times, serif;font-style: italic;font-size: 20px;-webkit-line-clamp: unset;max-height: unset;><font data-immersive-translate-translation-element-mark="1" lang="zh-CN" style="box-sizing: inherit;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;margin: 0px !important;"><font data-immersive-translate-translation-element-mark="1" style="box-sizing: inherit;font-family: inherit;"><span leaf=""><span textstyle="" style="font-weight: bold;">多 GPU 配置:🚀 选择 Llama Factory 以利用其出色的分布式训练能力</span></span></font></font></font></p> <section class="mp_profile_iframe_wrp" nodeleaf=""> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-nickname="算法进阶" data-alias="AiAlgorithms" data-from="0" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/eyibF6kJBjTtW95z3IJIDlSJdq38YRPVdsN0M5weHYKeMiaPXRiaFJAxMibWflabB6UfaGqTKS6SHCa9sPdoiauAbpQ/0?wx_fmt=png" data-signature="关注我,领略AI前沿技术!专注Python人工智能、机器学习及深度学习算法分享!" data-id="MzI4MDE1NjExMQ==" data-is_biz_ban="0" data-service_type="1"></mp-common-profile> </section> <section> <span leaf=""><br></span> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>