内容总览
{{stats.cat1_total||0}}
一级大类
{{stats.cat2_total||0}}
二级类别
{{stats.scene_total||0}}
子场景(上架 {{stats.scene_online||0}})
{{stats.sentence_total||0}}
语句总数
{{stats.sentence_pending||0}}
待审核
{{stats.sentence_published||0}}
已发布
{{stats.sentence_with_audio||0}}
已有音频的句子
{{stats.audio_count||0}}
音频文件数(多音色)
{{stats.user_total||0}}
用户数
{{stats.read_total||0}}
跟读次数
{{stats.avg_score||0}}
平均跟读分
语句难度分布
已发布 / 总数
{{v.published}}/{{v.all}}
{{k}} · 待审 {{v.pending}}
子场景管理
子场景是语句的容器;难度在语句层,AI 生成语句以「场景背景 + 难度」为依据
场景分类
共 {{tree.length}} 个大类 · {{cat2Count}} 个类别 · {{sceneCount}} 个子场景
难度不在这一层:同一个子场景下可以有 入门 / 进阶 / 高级 三套语句;
点每行的「语句」进入该子场景,按难度分别生成与审核。
⚡ 一键生成 / ☁ 腾讯版:只能用在一条语句都没有的空子场景上,一次生成 3 套 (入门 10、进阶 10、高级 10,共 30 句)并自动发布; 中途失败只回滚那一套,已做好的套保留,点「继续生成」接着做。
两个按钮流程完全一样,只有音频引擎不同: 「⚡ 一键生成」用本机引擎(Kokoro 示范音 / Qwen3 讲解), 「☁ 腾讯版」用腾讯云 TTS(大模型音色 501009/501008 + 601005/601006), 不依赖本机 agent 开机,但会产生 TTS 费用。
⚡ 一键生成 / ☁ 腾讯版:只能用在一条语句都没有的空子场景上,一次生成 3 套 (入门 10、进阶 10、高级 10,共 30 句)并自动发布; 中途失败只回滚那一套,已做好的套保留,点「继续生成」接着做。
两个按钮流程完全一样,只有音频引擎不同: 「⚡ 一键生成」用本机引擎(Kokoro 示范音 / Qwen3 讲解), 「☁ 腾讯版」用腾讯云 TTS(大模型音色 501009/501008 + 601005/601006), 不依赖本机 agent 开机,但会产生 TTS 费用。
未归类的子场景({{orphan.length}})
这些场景没有挂到任何二级类别下,点「编辑归类」补上
| 编码 | 子场景 | 操作 |
|---|---|---|
| {{s.code||'—'}} | {{s.title}} |
还没有分类数据,点右上角「+ 新建一级大类」开始
{{sceneName(filter.scene_id)}}:同一子场景下入门 / 进阶 / 高级三套语句分别生成与审核
请在上方选择子场景,按难度分组查看和管理语句
老师讲解 · 固定话术
视角老师
{{ localStatText() }}
这些话术是讲解页里老师的「口头语」:开场(跟我读)、跟读后的评价、
收尾结论(85 分及以上「可以进行下一句」/ 85 分以下「建议再读一遍」)。
2026-10-04 起:音频由本机 Qwen3-TTS 生成(9201 女 / 9202 男),不走腾讯云;
老音频(601005 / 601006)仍然有效,新旧互不影响。
改完文案会自动排队重新合成(每位老师一条,任务标 engine=1 交给本机 agent)——
不用再手动点合成,但**要求本机 agent 正在运行**。
还没生成完时,客户端会自动退回手机自带语音朗读**新文案**:音色不如本地,但内容绝不会说错。
各老师缺口(这位老师没有可用音频的话术条数;默认老师可复用主表那份历史音频):
{{phraseTeacherLabel(k)}} {{n}}
{{phraseVoiceNote}}
{{phraseInfo}}
句子情景讲解
视角老师
{{ localStatText() }}
讲解页现在**先让老师把句子读一遍,再讲这句话怎么用**:什么时候说、对谁说、什么意思、
什么语气、关键词是谁。这一层与用户读得怎么样无关,所以每句只生成一份、所有用户共享,
App 里是秒开的(讲稿与音频都离线生成好,运行时只读缓存)。
当前视角:{{seTeacherName()}}(中文音色 {{seVoiceType}})——
默认老师:没有专属音频时回落主表那套历史音频(老客户端读的也是它)。
**非默认老师:只看专属音频**,没生成的那几句,App 里会退回手机本地音色(一听就知道不一样)。
各老师缺口(没有可用音频的句数,含还没讲稿的)
{{seTeacherLabel(k)}} {{n}}
云端音频总开关已关(explain_audio_enabled=0)
它和「逐词纠音」是**两层,两层都要**:这一层讲用法、词义与语气,跟读**前**播;
逐词纠音讲读错的那个词怎么发音,跟读**后**播。所以这一层里**不要写发音/音标**
—— 两边都讲发音,用户同一轮会听到两遍相似的话。
{{seVoiceNote}}
{{seInfo}}
有 {{seMissing}} 句还没有讲稿:App 里这些句子会**跳过情景讲解**直接进跟读
(不报错,但也没讲解)。跑一次 tp5/scripts/gen_sentence_explain_cache.php,
或在下面逐句点「生成讲稿」。
词条讲解
跟读后逐词纠音的音频:按单词缓存,所有用户共用一份
{{ localStatText() }}
纠音引擎
合成模式
实际音色 —— 本机 9201/9202(女/男)·
edge {{weEngineVoices.edge.female}}/{{weEngineVoices.edge.male}} ·
腾讯云 {{weEngineVoices.cloud.female}}/{{weEngineVoices.cloud.male}}
edge-tts {{weEdgeOk ? '可用' : '未找到(查 edge_tts_bin)'}}
只影响「跟读完的逐词纠音」这一条链路,英文示范音 / 句子讲稿 / 固定话术 / 单词朗读一律不变。
纠音引擎:本机 Qwen3=9201/9202(要 Mac 的 oral_agent 在跑)· 服务器 edge-tts=9401/9402(装在本服务器,不依赖本机、不产生费用)· 腾讯云=601005/601006(老链路保留)。
合成模式:
· 预生成(默认)= 音频由离线队列提前做好存着,用户读错时立刻响、0 延迟; 代价是要提前把词做出来(全站 4000 多个词,多数做了用不上),没做过的词这次只能听手机本地合成音。
· 实时合成= 用户读错那一刻当场合成,且完全不看预生成的音频 (不查"这个词做过没有"、也不管库里是什么音色),直接把文本发给当前引擎; 一次最多 3 个词并发,约等 4~7 秒; 合成结果不落库 —— 同一个词每次读错都会重新合成一遍(每次都等 4~7 秒)。 代价:每次跟读占用一个 PHP 进程几秒,并发高峰会拖慢站点。 ⚠️ 实时合成只对 edge / 腾讯云 有效 —— 本机 Qwen3 装在 Mac 上,服务器调不到,会自动退回预生成。
⚠️ 两项设置都只对以后新生成的音频生效:已有音频按行内音色判定仍然有效, 要换声音请点上面的「★ 用 edge 重做全部词条」。
纠音引擎:本机 Qwen3=9201/9202(要 Mac 的 oral_agent 在跑)· 服务器 edge-tts=9401/9402(装在本服务器,不依赖本机、不产生费用)· 腾讯云=601005/601006(老链路保留)。
合成模式:
· 预生成(默认)= 音频由离线队列提前做好存着,用户读错时立刻响、0 延迟; 代价是要提前把词做出来(全站 4000 多个词,多数做了用不上),没做过的词这次只能听手机本地合成音。
· 实时合成= 用户读错那一刻当场合成,且完全不看预生成的音频 (不查"这个词做过没有"、也不管库里是什么音色),直接把文本发给当前引擎; 一次最多 3 个词并发,约等 4~7 秒; 合成结果不落库 —— 同一个词每次读错都会重新合成一遍(每次都等 4~7 秒)。 代价:每次跟读占用一个 PHP 进程几秒,并发高峰会拖慢站点。 ⚠️ 实时合成只对 edge / 腾讯云 有效 —— 本机 Qwen3 装在 Mac 上,服务器调不到,会自动退回预生成。
⚠️ 两项设置都只对以后新生成的音频生效:已有音频按行内音色判定仍然有效, 要换声音请点上面的「★ 用 edge 重做全部词条」。
{{weWordTotal}}
词条总数
{{wePhraseTotal}}
其中短语(不参与纠音)
{{weMissText.length}}
缺讲解文本
{{weMissAudio[t.id]||0}}
{{t.name}} 缺音频
{{weQueue.pending}}
队列待处理
{{weQueue.failed}}
队列失败
⚠️ 这些音频**不在请求里生成**(放请求里用户要等十几秒)。
2026-10-04 起:音频任务(engine=1)由本机 agent 生成 ——
讲解走本机 Qwen3(一条约 1~2 分钟),英文示范音走 Kokoro(秒级);
服务器 worker 只负责生成**文案**(大模型,一条 1~2 秒)。
点「一键补齐」只是把缺口排进队列,本机 agent 会按「示范音 → 词条 → 讲稿 → 话术」的顺序生成,
顶栏右侧能看到**本机队列**的排队/生成中数量。
注意「一键补齐」只补缺口:已有可用音频的不重排(包括老腾讯云音频)。 要把已有音频**换成本地音色**,用上面的「★ 本地重做全部词条」。
2026-09-27 起这个按钮是全量的:句子示范音(男女声)、讲稿文案与音频、 词条文案与音频、固定话术音频(每位老师)—— 一处点完,全库缺口都排上。 单条发布 / 保存时会自动只排"那一条",且插到队首优先跑(见语句页的进度窗)。
2026-10-05 起:短语(含空格,如 would like / split the bill)不计入缺口 —— 语音评测只按单词报错,短语永远不进错词列表,本来就不需要纠音音频 (它们只有词义,走「重点单词」链路)。当前词条里有 {{wePhraseTotal}} 条短语。
注意「一键补齐」只补缺口:已有可用音频的不重排(包括老腾讯云音频)。 要把已有音频**换成本地音色**,用上面的「★ 本地重做全部词条」。
2026-09-27 起这个按钮是全量的:句子示范音(男女声)、讲稿文案与音频、 词条文案与音频、固定话术音频(每位老师)—— 一处点完,全库缺口都排上。 单条发布 / 保存时会自动只排"那一条",且插到队首优先跑(见语句页的进度窗)。
2026-10-05 起:短语(含空格,如 would like / split the bill)不计入缺口 —— 语音评测只按单词报错,短语永远不进错词列表,本来就不需要纠音音频 (它们只有词义,走「重点单词」链路)。当前词条里有 {{wePhraseTotal}} 条短语。
有 {{weStale}} 个词条改过讲解文案、音频还是旧的:词条音频的文件名不含文本指纹,
改文案**不会**自动失效(见 common.php 的 cos_key_explain_word 注释),需要手动重做。
{{weInfo}}
云端讲解音频总开关已关(explain_audio_enabled=0):补齐也不会下发,客户端全走本地合成。
用户管理
禁用后该账号所有接口立即失效(等同强制下线);「踢下线」只清登录态、不禁用
{{userStat.total||0}}
注册用户
{{userStat.today||0}}
今日新增
{{userStat.week||0}}
近 7 天新增
{{userStat.active_week||0}}
近 7 天活跃
{{userStat.disabled||0}}
已禁用
{{userStat.points_sum||0}}
积分余额合计
{{userStat.read_total||0}}
跟读总次数
渠道分布:手机号 {{userStat.channel.mobile}} · 邮箱 {{userStat.channel.email}} · Apple {{userStat.channel.apple}} · 微信 {{userStat.channel.wechat}}
(同一账号可绑多个渠道,合计可能大于总人数)
用户反馈
用户在 App「我的 → 设置 → 意见反馈」提交的留言;回复后会推送给用户
消息推送
iOS 走苹果 APNs,安卓走阿里云移动推送(EMAS)
{{pushStat.total||0}}
已绑定设备
{{pushStat.ios||0}}
iOS
{{pushStat.android||0}}
安卓
{{pushStat.push_enabled?'开':'关'}}
推送总开关
{{pushStat.ali_configured?'已配置':'未配置'}}
阿里推送密钥
⚠️ 安卓设备需在客户端集成阿里云移动推送 SDK 后才会出现在这里。
AppKey 在服务端 application/extra/oral.php(ali_push_app_key),AppSecret 与 AccessKey 在 oral_secret.php。
AppKey 在服务端 application/extra/oral.php(ali_push_app_key),AppSecret 与 AccessKey 在 oral_secret.php。
发送通知
用于联调测试与应急公告
将推送给所有已绑定设备且状态有效的用户
AI 生图
腾讯云 TokenHub · hy-image-v3.5-preview
同步生成 · 约 10~30 秒/张 · 约 0.15 元/张
{{ (imgForm.prompt||'').length }} / {{imgMaxPrompt}} 字。
写清「主体 + 场景 + 风格 + 光线」出图更稳;不要要求画面里出现文字或字母(模型写出来的字通常是歪的)。
出图后会自动转成 JPEG 存进我们自己的 COS 桶 ——
腾讯给的原始链接只有 12 小时有效,不转存就再也拿不到了。
⚠️ 服务端生图开关当前是关的(oral.php 的 bg_gen_enabled)
⚠️ 服务端生图开关当前是关的(oral.php 的 bg_gen_enabled)
生成中…
腾讯这边通常 10~30 秒出图
腾讯这边通常 10~30 秒出图
{{imgResult.size}} · {{imgResult.size_kb}} KB · 耗时 {{imgResult.cost_s}} 秒
· seed {{imgResult.seed}}
{{imgResult.prompt}}
还没有生成过
左边写好提示词,点「生成图片」
左边写好提示词,点「生成图片」
生成历史
共 {{imgTotal}} 张
还没有生成记录
第 {{imgPage}} / {{Math.ceil(imgTotal/imgPageSize)}} 页
定制学习说明
游客点进来看到的整屏文案;改完立即生效,App 下次进入页面就会拿到
顶部
主标题和副标题都支持换行(回车就会换行)
{{ g.title || ('分组 ' + (gi+1)) }}
当前样式:{{ g.kind==='step' ? '带序号的步骤' : (g.kind==='feature' ? '带图标的功能项' : '打勾的一句话') }}
第 {{ ii + 1 }} 条
底部
按钮文字 + 按钮下面那行灰字(支持换行)
积分计费
改完立即生效 —— App 下次请求就会拿到新值,不用发新版本
拍照学英语
分析成功才扣;识别不出内容 / 分析失败一分不扣
0 = 免费。App 上「每次消耗 N 积分」显示的就是这个值。
0 = 不限次数(当前口径:只按积分收费)。
同一用户两次分析之间的最短间隔,防连点。
跟读
一次完整跟读(情景讲解 → 跟读 → 判分 → 讲解)扣一次,不是每个环节各扣;
没真正跟读就不扣;拍照学英语里的跟读不扣
0 = 免费(App 不弹扣费提示)。App 上「每次跟读消耗 N 积分」显示的就是这个值。
客户端按下「跟读」就拦下并给充值入口;服务端也不发评测签名、不落判分,
所以余额不够时既读不了、也不会产生评测费用。
文件默认(extra/oral.php):拍照 {{phFileDefault.enabled ? '开' : '关'}}/
{{phFileDefault.cost}} 积分 ·
跟读 {{phFileDefault.readCost}} 积分 ·
{{phFileDefault.dailyLimit > 0 ? phFileDefault.dailyLimit + ' 次/天' : '不限次数'}} ·
间隔 {{phFileDefault.minInterval}} 秒
拍照记录
共 {{phStat.total || 0}} 条 · 今日 {{phStat.today || 0}} 条 ·
累计消耗 {{phStat.points_total || 0}} 积分(今日 {{phStat.points_today || 0}})
| ID | 用户 | 照片 | 识别出的英文(摘要) | 生成内容 | 消耗积分 | 时间 | 状态 | 操作 |
|---|---|---|---|---|---|---|---|---|
| {{it.id}} |
{{it.nickname}}
uid {{it.uid}}
|
|
{{it.ocr_text}} | 词 {{it.word_count}} · 句 {{it.sentence_count}} · 题 {{it.quiz_count}} | {{it.points_cost}} 未扣费 免费 | {{it.create_time}} | 正常 已删除 | |
| 还没有拍照记录 | ||||||||
第 {{phPage}} / {{Math.ceil(phTotal/phPageSize)}} 页
付费管理
苹果内购 + 安卓微信/支付宝的订单、营收、商品档位与支付开关
微信/支付宝:{{revCfg.pay_enabled ? '已开启' : '已关闭(安卓无法充值)'}}
苹果内购:{{revCfg.iap_enabled ? '已开启' : '已关闭'}}
苹果环境:{{revCfg.iap_environment==='production' ? '正式' : '沙盒(不产生真实收入)'}}
微信商户参数:{{revCfg.wx_configured ? '已配置' : '未配置'}}
支付宝参数:{{revCfg.ali_configured ? '已配置' : '未配置'}}
苹果密钥:{{revCfg.iap_key_configured ? '已配置' : '未配置'}}
另有沙盒订单 {{revStat.sandbox.orders}} 笔
({{money(revStat.sandbox.cny_fen,'CNY')}} + {{money(revStat.sandbox.fx_fen,'USD')}}),
不计入下面任何营收数字,只在订单列表里标「沙盒」。
营收概览
只统计正式环境、已入账的订单;沙盒单与退款单不计入
{{revNow}}
{{money(revStat.today.cny_fen,'CNY')}}
今日实收 · {{revStat.today.orders||0}} 单 / {{revStat.today.payers||0}} 人
{{money(revStat.week.cny_fen,'CNY')}}
近 7 天 · {{revStat.week.orders||0}} 单 / {{revStat.week.payers||0}} 人
{{money(revStat.month.cny_fen,'CNY')}}
近 30 天 · {{revStat.month.orders||0}} 单 / {{revStat.month.payers||0}} 人
{{money(revStat.all.cny_fen,'CNY')}}
累计 · {{revStat.all.orders||0}} 单 / {{revStat.all.payers||0}} 人
美元订单单独统计(与人民币不能相加):今日 {{money(revStat.today.fx_fen,'USD')}} · 近 30 天 {{money(revStat.month.fx_fen,'USD')}} · 累计 {{money(revStat.all.fx_fen,'USD')}}。
累计退款 {{revStat.all.refund_count||0}} 笔 / {{money(revStat.all.refund_cny_fen,'CNY')}},已扣回 {{revStat.all.refund_points||0}} 积分。
近 30 天共发放 {{revStat.month.points||0}} 积分。
近 30 天实收趋势
柱子越高金额越大,橙色为当天有单
渠道分布正式环境已入账
| 渠道 | 单数 | 实收 | 积分 |
|---|---|---|---|
| {{c.text}} | {{c.orders}} | {{money(c.cny_fen,'CNY')}} | {{c.points}} |
| 还没有正式环境的付费订单 | |||
商品销量排行按单数
| 商品 | 单数 | 实收 | 积分 |
|---|---|---|---|
| {{t.title}} | {{t.orders}} | {{money(t.cny_fen,'CNY')}} | {{t.points}} |
| 还没有正式环境的付费订单 | |||
充值订单
苹果内购与微信/支付宝合并显示,共 {{revTotal}} 笔
| 下单时间 | 用户 | 渠道 | 商品 | 金额 | 积分 | 状态 | 环境 | 操作 |
|---|---|---|---|---|---|---|---|---|
| {{r.create_time}} 付 {{r.paid_time}} |
{{r.nickname || ('#' + r.uid)}}
UID {{r.uid}} · {{r.mobile}}
|
{{r.channel_text}} |
{{r.product_title}}
{{r.product_id}}
|
{{money(r.amount_fen, r.currency)}} | {{r.points}} | {{r.status_text}} | 沙盒 正式 | |
| 没有符合条件的订单 | ||||||||
第 {{revPage}} / {{Math.ceil(revTotal/revLimit)}} 页
「退款」只做两件事:把订单标记为已退款、按用户当前余额扣回积分。不会真的把钱退回去 ——
苹果订单要到 App Store Connect 退,微信/支付宝要到商户后台退。扣不回来的差额会写在返回提示里。
商品档位
iOS 端价格以 App Store Connect 配置为准;这里的人民币价格是安卓微信/支付宝实际扣款金额
| ID | 商品 ID | 展示名 | 积分 | 赠送 | 人民币价 | 苹果参考价 | 累计销量 | 排序 | 状态 | 操作 |
|---|---|---|---|---|---|---|---|---|---|---|
| {{p.id}} | {{p.product_id}} |
{{p.title}} | {{p.points}} | {{p.bonus_points}} | {{money(p.price_cny,'CNY')}} | {{money(p.price_cents,'CNY')}} | {{p.sold_orders}} 单 · {{p.sold_points}} 分 | {{p.sort}} | 上架 下架 | |
| 还没有商品档位 | ||||||||||
销量只统计正式环境已入账订单。下架的商品不会出现在 App 的充值页,也不会被新订单购买(已付款的回调仍会正常入账)。
支付设置
改完立即生效,App 下次请求就会拿到新值
安卓微信 / 支付宝
商户参数:微信 {{revCfg && revCfg.wx_configured ? '已配置' : '未配置'}} ·
支付宝 {{revCfg && revCfg.ali_configured ? '已配置' : '未配置'}}
苹果内购
密钥:{{revCfg && revCfg.iap_key_configured ? '已配置' : '未配置'}} · Bundle ID:{{revCfg ? revCfg.iap_bundle_id : ''}}
苹果环境
服务端向苹果复核交易时先问这个环境,查不到会再问另一个
密钥类配置(微信 API 密钥、商户证书、支付宝私钥/公钥、苹果 .p8)不在后台可改范围,
只显示「已配置 / 未配置」。要换密钥请改服务器 application/extra/oral_secret.php 后重载 php-fpm。
| 项目 | 当前值 |
|---|---|
| 微信 AppID | {{(revCfg && revCfg.wxpay_app_id) || '未配置'}} |
| 微信商户号 | {{(revCfg && revCfg.wxpay_mch_id) || '未配置'}} |
| 支付宝 AppID | {{(revCfg && revCfg.alipay_app_id) || '未配置'}} |
| 微信回调地址 | {{revCfg ? revCfg.wx_notify_url : ''}} |
| 支付宝回调地址 | {{revCfg ? revCfg.ali_notify_url : ''}} |
| 苹果服务器通知地址 | {{revCfg ? revCfg.iap_notify_url : ''}} |
订单详情 {{revDetail.order.order_no}}
| 渠道 | {{revDetail.channel_text}} |
| 状态 | {{revDetail.order.status_text}}沙盒 |
| 用户 | {{revDetail.user.nickname || ('#' + revDetail.user.id)}} · UID {{revDetail.user.id}} · {{revDetail.user.mobile}} |
| 当前积分 / 累计获得 | {{revDetail.user.points}} / {{revDetail.user.points_total}} |
| 商品 | {{revDetail.order.product_title}}({{revDetail.order.product_id}}) |
| 金额 | {{money(revDetail.order.amount_fen, revDetail.order.currency)}} |
| 积分 | {{revDetail.order.points}} · 已扣回 {{revDetail.order.refund_points}} |
| 第三方交易号 | {{revDetail.order.transaction_id || '-'}} |
| 下单 / 更新时间 | {{revDetail.order.create_time}} / {{revDetail.order.update_time}} |
| 微信预支付单号 | {{revDetail.order.prepay_id}} |
| 苹果账号令牌 | {{revDetail.order.app_account_token}} |
积分流水按订单号关联
| 时间 | 变动 | 余额 | 说明 |
|---|---|---|---|
| {{l.create_time}} | {{l.change_points}} | {{l.balance_after}} | {{l.title}} · {{l.type}} · {{l.remark}} |
| 没有关联流水 | |||
{{revDetail.raw.label}}共 {{revDetail.raw.len}} 字符
{{revDetail.raw.text || '(空)'}}
苹果交易核对
| 项目 | 苹果 | 本地 |
|---|---|---|
| 交易号 | {{revSyncResult.apple.transaction_id}} | {{revSyncResult.local.transaction_id || '-'}} |
| 商品 ID | {{revSyncResult.apple.product_id}} | {{revSyncResult.local.product_id}} |
| 环境 | {{revSyncResult.apple.environment}} | {{revSyncResult.local.environment}} |
| 金额 | {{money(revSyncResult.apple.price_cents, revSyncResult.apple.currency)}} | {{money(revSyncResult.local.price_cents, revSyncResult.local.currency)}} |
| 币种 | {{revSyncResult.apple.currency}} | {{revSyncResult.local.currency}} |
| 购买时间 | {{revSyncResult.apple.purchase_date || '-'}} | {{revSyncResult.local.create_time || '-'}} |
| 苹果退款时间 | {{revSyncResult.apple.revocation_date || '未退款'}} | {{revSyncResult.local.status_text}} |
· {{w}}
苹果与本地记录一致。
{{revProductIsNew ? '新建商品档位' : ('编辑商品 #' + revProductForm.id)}}
商品 ID 必须与 App Store Connect 里创建的内购项目 ID 完全一致(iOS 靠它取商品)。
100 = 1 元。安卓微信/支付宝按这个金额扣款;上架商品必须大于 0。
只用于后台展示,实际以 App Store Connect 为准。
越大越靠前。
用户详情 #{{userForm.id}} {{userForm.nickname}}
加载中…
UID{{userDetail.user.id}}
昵称{{userDetail.user.nickname || '—'}}
状态{{userDetail.user.status==1?'正常':'已禁用'}}
登录态{{userDetail.user.token_set?'已登录':'未登录'}}
登录渠道
未绑定
{{c}}
手机号{{userDetail.user.mobile || '—'}}
邮箱{{userDetail.user.email || '—'}}
Apple{{userDetail.user.apple_id || '—'}}
微信{{userDetail.user.wx_openid || '—'}}
积分{{userDetail.user.points}}(累计获得 {{userDetail.user.points_total}})
年级{{userDetail.user.grade || '—'}}
生日{{userDetail.user.birthday || '—'}}
注册时间{{userDetail.user.create_time || '—'}}
最后活跃{{userDetail.user.last_active || '—'}}
句子标记不熟 {{userDetail.marks.sentence.unfamiliar}} · 已会 {{userDetail.marks.sentence.familiar}}
单词标记不熟 {{userDetail.marks.word.unfamiliar}} · 已会 {{userDetail.marks.word.familiar}}
学习进度
练过 {{userDetail.progress.scene_count}} 个场景 · 通过 {{userDetail.progress.done_sum}} 句 · 最高分 {{userDetail.progress.best_score}}
| 场景 | 进度 | 最高分 | 平均分 | 更新时间 |
|---|---|---|---|---|
| {{p.scene_title}} | {{p.done_count}} / {{p.total_count}} | {{p.best_score}} | {{p.avg_score}} | {{p.update_time}} |
还没有学习记录
跟读记录
共 {{userDetail.read.count}} 次,下面是最新 {{userDetail.read.shown}} 条
| 句子 | 得分 | 第几次 | 扣积分 | 时间 | 录音 |
|---|---|---|---|---|---|
|
{{r.en || '—'}}
{{r.zh}}
|
{{r.suggested_score}} | {{r.repeat_count}} | {{r.points_cost}} | {{r.create_time}} | 播放— |
还没有跟读记录
积分流水
余额 {{userDetail.points.balance}} · 累计获得 {{userDetail.points.total}} · 收入 {{userDetail.points.earn_sum}} / 支出 {{userDetail.points.spend_sum}} · 共 {{userPtTotal}} 笔
| 变动 | 余额 | 类型 | 说明 | 时间 |
|---|---|---|---|---|
| {{p.change_points>0?'+':''}}{{p.change_points}} | {{p.balance_after}} | {{p.type}} |
{{p.title}}
{{p.remark}}
|
{{p.create_time}} |
还没有积分流水
第 {{userPtPage}} / {{Math.ceil(userPtTotal/userPtLimit)}} 页
解锁记录共 {{userDetail.unlocks.length}} 条
| 场景 | 类型 | 难度 / 套 | 支付积分 | 状态 | 到期时间 |
|---|---|---|---|---|---|
| {{x.scene_title}} | {{x.kind_text}} | {{x.level || '—'}} 第 {{x.set_no}} 套 | {{x.points_paid}} | {{x.status==1?'已完成':(x.status==0?'处理中':'失败')}} | {{x.expire_time}} |
没有解锁记录
内购订单最近 {{userDetail.orders.length}} 笔
| 订单号 / 交易号 | 商品 | 积分 | 金额 | 状态 | 时间 |
|---|---|---|---|---|---|
|
{{o.order_no}}
{{o.transaction_id}}
|
{{o.product_id}} | {{o.points}} | {{(o.price_cents/100).toFixed(2)}} {{o.currency}} | {{hhOrderStatus(o.status)}} | {{o.create_time}} |
没有内购订单
绑定设备推送用(iOS 走 APNs,安卓走阿里云移动推送)
| 平台 | 环境 | 版本 | 设备令牌 | 状态 | 更新时间 |
|---|---|---|---|---|---|
| {{d.platform}} | {{d.platform==='ios' ? (d.env==2?'沙箱':'生产') : '—'}} | {{d.app_version || '—'}} | {{d.token_short}} | {{d.state==1?'有效':'失效'}} | {{d.update_time}} |
没有绑定设备
意见反馈最近 {{userDetail.feedbacks.length}} 条
用户 · {{f.create_time}} · {{f.status==1?'已回复':'待回复'}}
{{f.content}}
客服 · {{f.reply_time}}
{{f.reply}}
没有提交过反馈
调整积分 #{{ptForm.id}} {{ptForm.nickname}}
当前余额 {{ptForm.balance}} 积分;扣减后不能为负数,单次最多 ±100 万。
会写进积分流水(title 字段),用户在「我的 → 积分明细」能看到。
回复用户反馈 #{{fbForm.id}}
{{fbForm.content}}
最多 500 字。回复后状态变为「已回复」,用户端「意见反馈」会出现红点。
{{cat1Form.id?'编辑一级大类':'新建一级大类'}}
1~2 个大写字母
当前封面({{cat1Form.cover_id}},{{cat1Form.cover_w}}×{{cat1Form.cover_h}})。
客户端按这张图的比例整行铺满显示,图上已经烘好的文字不会被裁。
还没配封面 → 客户端首屏显示的还是原来的文字行
选好即上传(不用先点保存)。服务端自动转 JPEG(q88) 并把宽度压到 1440 以内。
客户端按图片自身比例铺满整行、不再叠任何文字,所以文字请直接做在图里。
新建大类请先保存,再回来配封面图。
{{cat2Form.id?'编辑二级类别':'新建二级类别'}}
前缀须与大类一致
{{sceneForm.id?'编辑子场景':'新建子场景'}}
前缀须与类别一致
单套合计 {{modalTicket.sum_points}} 分,通票要低于它才有意义
0=不出售;单套在「语句」页按套设
跟读页背景图 · {{bgForm.level}} · 第 {{bgForm.set_no}} 套
{{sceneName(filter.scene_id)}}
一"套" = 场景 + 难度 + 套号,背景图按这个粒度存;这一套没配图时,
客户端显示的是下面的「兜底图」,不会出现空背景。
本套自己的图({{bgForm.current_id}})
本套还没配图,客户端显示的是兜底图
连全局兜底图也没配 → 客户端只能用打包在 App 里的那张
选好即上传,服务端会自动转 JPEG(q88)并把宽度压到 1440 以内,不用自己压图。
跟读页是竖屏整屏显示,建议用竖图;横图会被按锚点裁掉两侧。
提示词按当前子场景自动拼
按「当前子场景 + 本套套号」自动拼提示词,生成竖版环境图后
直接替换本套背景图(不满意就再点一次,每次都是新图)。约 0.15 元/张。
⚠️ 需先在腾讯云控制台 → TokenHub → 在线推理服务,为
⚠️ 需先在腾讯云控制台 → TokenHub → 在线推理服务,为
hy-image-v3.5-preview 开启后付费,
否则会提示「尚未开启后付费」。
{{sentenceForm.id?'编辑语句':'手动新增语句'}} · {{sentenceForm.level}} · 第 {{sentenceForm.set_no}} 套
单词数:{{wordCount(sentenceForm.en)}}(腾讯云 SOE 句子模式上限 30 词)
复制语句(浏览器未允许自动写入剪贴板)
下面是该难度下全部套的语句,一行一句「英文 | 中文」。
点「全选」后按 ⌘ / Ctrl + C 复制。
批量录入语句 · {{batchForm.level}} · 第 {{batchForm.set_no}} 套
{{sceneName(filter.scene_id)}}
只补空着的字段——你自己写了中文或关键词的句子不会被覆盖;会调用大模型,20 句约几秒
格式:英文 | 中文 | 关键词(后两段可省略,用竖线分隔;全角 | 也可以)
超过 30 个单词的行会跳过(腾讯云 SOE 上限);与该场景已有句子重复的也会跳过。
当前已输入 {{batchLineCount}} 行。
录入后为「待审核」,确认无误再发布,然后合成音频。
超过 30 个单词的行会跳过(腾讯云 SOE 上限);与该场景已有句子重复的也会跳过。
当前已输入 {{batchLineCount}} 行。
录入后为「待审核」,确认无误再发布,然后合成音频。
{{batchInfo}}
AI 生成语句 · {{aiForm.level}} · 第 {{aiForm.set_no}} 套
{{sceneName(filter.scene_id)}}
每次只生成一个难度
生成的内容会以「待审核」状态入库(标 待审核),确认无误后再发布。
难度按可数的硬指标控制(如入门=每句不超过 6 个单词);
同一子场景下 入门 / 进阶 / 高级 三套语句各自独立,互不覆盖。
难度按可数的硬指标控制(如入门=每句不超过 6 个单词);
同一子场景下 入门 / 进阶 / 高级 三套语句各自独立,互不覆盖。
{{aiInfo}}
批量合成音频{{ttsForm.level ? ' · ' + ttsForm.level + ' · 第 ' + ttsForm.set_no + ' 套' : ''}}
{{sceneName(filter.scene_id)}}
只处理「{{ttsForm.level}}」难度 · 第 {{ttsForm.set_no}} 套的语句
当前是「全部场景」视图:只合成你勾选的 {{ttsForm.ids.split(',').length}} 句,
不会处理别的场景。要按「场景 + 难度 + 套」整批合成,请先在页面上选好子场景。
每句会为所选音色各生成一份音频,全部上传到 COS。多音色时句数 × 音色数 = 音频数。
自动分批循环,避免单次请求超时
{{ttsInfo}}
{{ttsInfo}}
一键生成并发布{{gsCloud?'(腾讯版)':''}} · {{gsTitle}}
共 3 套 30 句(入门 10、进阶 10、高级 10)。
句子文稿全部生成成功之后才会发布、才开始合成语音 ——
生成阶段全程「未发布」、不排任何语音任务;某一套失败只会回滚那一套,
已经做好的套保留,点「继续生成」从断点接着做(不用重头来)。
音频引擎:{{gsCloud?'腾讯云 TTS(大模型音色,会产生费用)':'本机引擎(Kokoro 示范音 / Qwen3 讲解)'}}
音频引擎:{{gsCloud?'腾讯云 TTS(大模型音色,会产生费用)':'本机引擎(Kokoro 示范音 / Qwen3 讲解)'}}
{{gsInfo}}
本次已生成 {{gsMade}} 句
语音(示范音 / 讲稿 / 词条音频)在发布后才排队生成:
{{gsCloud?'由服务器 worker 直接调腾讯云 TTS(不等本机 agent)':'由本机 agent 生成(需本机 oral_agent 在跑)'}};
进度可以在「词条讲解」页的队列里看;「语句」页能逐句看示范音 / 讲解有没有齐。
生成进度(示范音 / 讲稿 / 词条)
{{gpInfo}}
任务已排进生成队列:文案由服务器 worker 生成,音频由本机 agent 生成
(讲解约 1~2 分钟/条,比腾讯云慢,但不消耗配额、音色与全站一致),本窗每 5 秒刷新一次;
关掉窗口不影响生成(本机 agent 要开着),进度随时可以在「词条讲解」页的队列里看。
| 句ID | 英文 | {{s.name}} | |||||
|---|---|---|---|---|---|---|---|
| {{it.sentence_id}} | {{it.en}} | {{s.ready}}/{{s.total}} | |||||
| 查询中… | |||||||
有生成失败的任务:去「词条讲解」页点「重试失败」(先看失败原因再重试)。
编辑话术 · {{phraseForm.title}}
{{phraseForm.phrase_key}}
客户端按这个标识取用这句话术,**不要改**(改了客户端找不到,只能用兜底文案)。
保存后音频即失效,需要点「重新合成」才会用新文案的声音。
没有可用音频:文案改动过,或还没合成过。保存后用「重新合成」生成。
编辑讲解 · 句{{seForm.sentence_id}}
{{seForm.en}}
{{seForm.zh}}
页面显示的是上面 5 点,而音频念的是这一段 —— 所以要把 5 点的信息揉成
**一段自然口语**(建议 80~130 字,约 20~30 秒),不要写「第一、第二」这种条目。
这里不写、或写得像念清单,用户听到的就是一口机器味。
没有可用音频:讲稿改动过,或还没合成过。保存后用「重新合成」生成。
广告(穿山甲)
改完立即生效 —— App 下次请求就拿到新值,不用发新版本
激励视频(看视频得积分)
积分只在「服务端回调」到达时发放;客户端上报的交易号只用来查询到账没有,不能凭空发分
开启后仍需下面「代码位ID」非空才真正下发;代码位留空一律按关闭处理。
App 里 SDK 初始化用的是客户端硬编码的同值(必须早于网络请求),这里只是留档 + 供客户端核对;
换应用时必须同时改客户端与这里。
穿山甲后台「代码位」里那条激励视频的 ID。
每看完一条视频加多少积分。0 = 不发(等于关闭)。
按服务器自然日统计,只算已发放的次数;被上限挡掉的不计入。
发分校验方式
上线前必须改成「只认服务端回调」,否则等于把发分权交给了客户端
选「仅联调」时,只有下面白名单里的 uid 能拿到分,其他人一律返回"奖励正在处理"。
多个 uid 用英文逗号分隔;保存时自动去重、只保留数字。
怀疑验签算法对不上时切「观察模式」跑一次真实回调,再去 php_err 日志看真实参数与算出的签名。
状态:{{ adSsvSet ? '已配置' : '未配置(此时一切回调都会被拒绝)' }}
密钥放在
穿山甲后台「服务端验证」要填的回调地址:
密钥放在
application/extra/oral_secret.php 的 ad_ssv_secret
(刻意不开放后台编辑,避免一处疏忽把密钥覆盖掉)。穿山甲后台「服务端验证」要填的回调地址:
{{ adCallbackUrl }}
开屏广告(客户端尚未接入)
本轮只做了配置项:等客户端代码补完后,在这里填上代码位并打开开关即可生效,不必再改服务端
超时没拉到广告就直接进首页,不卡启动。1~10 秒,非法值回落 3。
「看视频得积分」页文案
显示在「看视频得积分」页,用于活动说明、规则提醒等。
今日:发放 {{ adStat.granted || 0 }} 笔 / 未发放 {{ adStat.denied || 0 }} 笔 / 入账中 {{ adStat.pending || 0 }} 笔,
共发出 {{ adStat.points || 0 }} 积分(上限 {{ adStat.limit }} 次/人/天,每次 {{ adStat.reward_points || 0 }} 分)
奖励记录
每一笔回调 / 上报都留痕;「未发放」多为超过每日上限或验签失败
| ID | uid | 交易号 | 代码位 | 积分 | 状态 | 来源 | 说明 | 时间 |
|---|---|---|---|---|---|---|---|---|
| 暂无记录 | ||||||||
| {{r.id}} | {{r.uid}} | {{r.trans_id}} | {{r.slot_id}} | {{r.points}} | {{hhAdStatus(r.status)}} | {{hhAdSource(r.source)}} | {{r.message}} | {{r.create_time}} |
共 {{adTotal}} 条
① AI 陪练 · 总开关与全局兜底
下面这份只在「② 陪练老师」列表为空时才生效
0.06 元/分钟(含 ASR/TTS,不含大模型)· 改完立即生效,不用发版也不用重启
开关与开场
全局兜底
开场白是「进页面后数字人主动说的第一句」—— 不配这句,它只会等用户先开口。
下面这一段只在「老师列表为空」时才生效;正常情况每位老师用自己的开场白与时长(见上方老师列表)。
关闭后 /api/lingmou/start 直接拒绝,不会产生任何阿里云费用。
SDK 只认这两个值,填别的数字人会一声不吭(踩过坑)。
transcript = 固定台词;prompt = 更自然但内容不可控。
transcript = 固定台词;prompt = 更自然但内容不可控。
建议开头留两三个字做垫音(如「你好,」):实测三端入会刚完成时音频路由还在切换,
开头约 0.5 秒可能被吞掉,垫音能把损失挡在正文之外。
用量与成本控制
全局兜底
计费从「接通」算到「关闭」、精确到秒 —— 这两项是唯一能控住成本的地方。老师列表为空时才用这里
0 = 不限。到点由 App 自动挂断。
换算:5 分钟 ≈ 0.30 元 · 15 分钟 ≈ 0.90 元 · 30 分钟 ≈ 1.80 元。
换算:5 分钟 ≈ 0.30 元 · 15 分钟 ≈ 0.90 元 · 30 分钟 ≈ 1.80 元。
2026-10-11 开始计费。不满 1 分钟按 1 分钟算:进页面先扣 1 分钟,之后每分钟补一次。
0 = 免费(不扣也不拦)。余额不够 1 分钟直接进不去;练习中余额耗尽 App 会自动挂断。
0 = 免费(不扣也不拦)。余额不够 1 分钟直接进不去;练习中余额耗尽 App 会自动挂断。
0 = 不限。超出后 App 提示「明天再来」。在调阿里云之前就拦掉,不花钱。
进入页面的提示文案(可选)
留空则不显示。
今日:{{ aiStat.users || 0 }} 人 / {{ aiStat.count || 0 }} 次会话 / 共 {{ aiStat.minutes || 0 }} 分钟,
预估费用 {{ aiStat.cost || 0 }} 元({{ aiStat.unit_price || 0.06 }} 元/分钟)
· 其中 {{ aiStat.failed }} 次创建失败
② 陪练老师(每位老师一套)
要交给阿里云的只有「项目 ID」与「模型ID」;实例 ID / license 全站共用一份,不用每位都填
人设怎么才能真正生效:在阿里云控制台把这位老师的「人设 → 语言模型」选成 自研模型,
再把下表「模型ID」这一栏的值原样填进控制台那栏 —— 网关收到请求时靠它认出"现在说话的是哪位老师",
才能套上他的人设。不填就只能走全局人设(下面「全局兜底」那份)。
| 头像 | 老师 | 模型ID | 项目 ID / 实例 | 时长 · 次数 | 今日 / 累计 | 状态 | 操作 |
|---|---|---|---|---|---|---|---|
|
无
|
{{ t.name }}默认
{{ t.title || '—' }}
|
{{ t.gateway_model || '—' }} |
{{ t.project_id || '—' }}
{{ t.instance_own ? t.instance_id : '实例:沿用全局' }}
|
{{ t.max_minutes > 0 ? (t.max_minutes + ' 分钟') : '不限' }} {{ t.daily_limit > 0 ? (t.daily_limit + ' 次/天') : '不限' }} |
{{ t.today_count }} / {{ t.total_count }} |
{{ t.ready ? '可开课' : '没配全' }}
{{ t.status ? '已上架' : '已下架' }}
|
|
| 还没有老师。点右上角「+ 新建老师」加一位;表里为空时接口会退回用下面「全局兜底」那套配置, 所以不会因为没有老师就直接不可用。 | |||||||
改造前的历史会话(没有老师归属):{{ aiTeacherMeta.legacy_sessions || 0 }} 条 ·
网关基址:{{ aiTeacherMeta.gateway_base || '—' }}
· 项目文件里有 license({{ aiTeacherMeta.file_license_len }} 字符),新老师 license 留空时会用它
· ⚠️ 项目文件里也没有 license
③ 接入方(项目)
每个项目一把独立密钥 + 自己能用哪些老师;对端只能调用本项目绑定的老师
对接新项目三步:① 这里新建项目(自动生成密钥)→ ② 点「可用老师」勾它能调的数字人 → ③ 把密钥配到对端服务端。
数字人是共享资源池,新项目不用另外向阿里云申请实例;对端调 internalStart / internalTeachers / internalEnd 三件套即可。
| 项目 | 标识 / 来源 | 密钥 | 可用老师 | 时长 · 次数 | 今日 | 状态 | 操作 |
|---|---|---|---|---|---|---|---|
|
{{ a.name }}自家
{{ a.tip ? ('提示:' + a.tip) : '无项目级提示' }}
{{ a.remark }}
|
{{ a.code }}
source = {{ a.source }}
IP:{{ a.ip_whitelist || '默认本机' }}
|
{{ a.key_set ? a.internal_key : '(自家不走密钥)' }}
|
{{ a.teacher_count }} 位
默认:{{ a.default_teacher_name || '按排序首位' }}
|
{{ a.max_minutes > 0 ? (a.max_minutes + ' 分钟') : '用老师配置' }} {{ a.daily_limit > 0 ? (a.daily_limit + ' 次/天') : '用老师配置' }} |
{{ a.today_count }} 次 | {{ a.status ? '启用' : '已停用' }} |
|
| 还没有接入方。正常情况下至少有一条「自家」;没有的话说明迁移没做全,先查 oral_ai_app 表。 | |||||||
对端调用地址:{{ aiGatewayBase || '/index.php' }}/api/lingmou/internalStart
(必带 internal_key,且来源 IP 必须在项目的白名单里)
已绑定的老师即使全部下架,项目也只会「没有可用老师」,不会去拿别的项目的老师。
已绑定的老师即使全部下架,项目也只会「没有可用老师」,不会去拿别的项目的老师。
④ 自研模型 —— 阿里云那一屏照下表填
阿里云没开放改人设的接口;切成自研模型后,它发过来的 system 消息会被我们替换成下面这份
阿里云控制台:人设 → 语言模型 = 自研模型 → 弹出的表单共 5 栏
逐栏照下表填,每栏都能在本页找到对应的地方
| 阿里云那栏 | 填什么 | 在我们后台哪里配 |
|---|---|---|
| System Prompt | 留空即可(人设由我们下发,会覆盖阿里云那段) | 本卡片下方「人设 prompt」 |
| 模型ID | 每位老师一个,与后台逐字符一致(如 speakcue-001) | ② 陪练老师 → 编辑老师 → 模型ID |
| API-KEY | 复制本卡片「API-KEY」那格的值 | 本卡片「API-KEY」输入框 |
| BaseUrl | {{ aiGatewayBase }} | 只读,点一下即全选复制 |
| Api | /v1/chat/completions | 只读,直接抄 |
我们网关这边
可改的只有「API-KEY」与「上游模型」;模型ID 在 ② 里按老师配
完整地址:{{ aiGatewayUrl }}
填一串随机字符,原样填进阿里云控制台;以后改这里,阿里云那边也要同步改。
留空 = 用工程配置的 {{ aiLlmFileModel || '(未配置)' }}
备用链:{{ aiLlmFallbacks || '(无)' }}
日志里若出现 401008 / 402 这类额度错误,把这里换成账号里能用的模型名。
备用链:{{ aiLlmFallbacks || '(无)' }}
日志里若出现 401008 / 402 这类额度错误,把这里换成账号里能用的模型名。
人设 prompt
这一份会替换掉阿里云控制台里的那段(上限 {{ aiPromptLimit }} 字,因为控制台那栏也是 5000)
想把 prompt 完全握在自己手里就选 override。
{{ (aiForm.prompt || '').length }} / {{ aiPromptLimit }}
已超限,保存会被拒绝
自测结果:HTTP {{ aiTestResult.http_code }} · 首字节 {{ aiTestResult.first_byte_ms }}ms · 总耗时 {{ aiTestResult.total_ms }}ms
数字人回答:{{ aiTestResult.answer || '(空)' }}
原始片段:{{ aiTestResult.raw_head }}
原始片段:{{ aiTestResult.raw_head }}
每张卡片底部的保存按钮存的是同一份配置(本页共 3 处)
④ 实例与项目 · 全局兜底
老师没填时用这里
⚠️ 改错会让所有会话创建失败;每位老师各自的「项目 ID」在 ② 里填,这里通常不用动
文件默认值:{{ aiFile.ai_instance_id || '(未配置)' }} · 阿里云「我的订单 → 订单详情」里查。
文件默认值:{{ aiFile.ai_project_id || '(未配置)' }}
⚠️ 必须是「2D 端渲染全链路」那个项目;云渲染项目会报 HA15110000000706。
⚠️ 必须是「2D 端渲染全链路」那个项目;云渲染项目会报 HA15110000000706。
接入点 {{ aiEndpoint || '-' }} ·
license {{ aiLicenseSet ? ('已配置(' + aiLicenseLen + ' 字符)') : '未配置' }} ·
AK {{ aiAkSet ? '已配置' : '未配置' }}
license 里含 RSA 私钥(端渲染资产包解密用),属敏感凭据,只显示长度、不回显内容。
{{ ateIsNew ? '新建陪练老师' : ('编辑老师 · ' + (ateForm.name || '')) }}
未上传
上传即生效;新老师请先保存再传头像
阿里云数字人参数
真正每位老师不同的只有「项目 ID」;实例 ID 与 license 全站公用一份
{{ aiTeacherMeta.global_instance_id || '(还没配:去下面「全局兜底」里填)' }}
同一个阿里云实例下所有老师共用这一个值,不必每位抄一遍;要换实例去下方「全局兜底」改。
必须是「2D 端渲染全链路」那个项目,云渲染项目会报 HA15110000000706。
{{ aiTeacherMeta.file_license_set ? ('已配置(' + (aiTeacherMeta.file_license_len || 0) + ' 字符),所有老师共用这一份') : '未配置 —— 端渲染拿不到 license,会话会失败' }}
敏感凭据、跟实例绑定、全站同一份,本页面不编辑。
每位老师必须唯一。网关全靠它认出"现在说话的是哪位老师"、再套上他的人设;
不填 = 走下面的全局人设。
控制台里 BaseUrl 填 {{ aiGatewayBase || '/index.php' }}, Api 填 /v1/chat/completions。
控制台里 BaseUrl 填 {{ aiGatewayBase || '/index.php' }}, Api 填 /v1/chat/completions。
开场白与人设
用量控制与状态0 = 不限
设为默认会自动把它改成上架。
{{ appIsNew ? '新建接入方(项目)' : ('编辑项目 · ' + (appForm.name || '')) }}
一个项目 = 一把密钥 + 一批可用的数字人老师 + 自己的时长/次数/提示。
密钥只放对端服务端,绝不能下发客户端、也不要提交到公开仓库。
仅用于后台辨认与排查;自家项目的标识不允许改。
多个用英文逗号分隔。只放对端服务端的出口 IP;两家在同一台机器就填 127.0.0.1。
只为兼容历史流水的旧 source 字段(jiajiao211 = 1);真正的归属看项目 id,所以填错影响不大。
0 = 用老师配置。最终上限取「老师 / 项目 / 对端传入」三者最小,所以对端传大了也压得住成本。
0 = 用老师配置;这里填了就以这里为准(按该项目 + 对端用户分别统计)。
随会话创建接口下发给该项目客户端;留空则回落「① AI 陪练 · 总开关与全局兜底」里的那条。
可用老师 · {{ atBindApp.name || '' }}
勾选这个项目能调用的老师。勾选顺序 = 列表返回顺序(越靠前越优先);
「项目默认」= 对端不传 teacher_id 时用哪位。
一位数字人可以同时绑给多个项目,互不影响;不绑定任何老师 = 该项目没有可用老师,不会退回全部老师。
一位数字人可以同时绑给多个项目,互不影响;不绑定任何老师 = 该项目没有可用老师,不会退回全部老师。
| 勾选 | 老师 | 上架 | 顺序 | 项目默认 |
|---|---|---|---|---|
|
{{ t.name }}
{{ t.title || '—' }}
|
{{ t.status ? '在架' : '已下架' }} |
第 {{ atBindOrder.indexOf(t.id) + 1 }} 位
未勾选
|
已勾选 {{ atBindOrder.length }} 位
{{toast.msg}}