feat: establish v0.70 platform milestone
ci / verify (push) Canceled after 0s

This commit is contained in:
Codex Local
2026-08-29 21:56:51 +08:00
parent d97bbf7cf5
commit e652516147
133 changed files with 12907 additions and 801 deletions
+26 -3
View File
@@ -10,6 +10,21 @@
.\deploy\local-rtc\configure.ps1
```
如果还要同时验证方舟大模型总结,可改用:
```powershell
.\deploy\local-rtc\configure.ps1 -EnableArkSummary
```
该模式会额外隐藏读取方舟API Key和内容模型Endpoint ID,并通过只读密钥文件传给Worker。
如果 RTC 配置已经存在,只需要补充大模型总结,不必使用`-Force`重录全部密钥。先在[方舟 API Key 控制台](https://console.volcengine.com/ark/region:ark+cn-beijing/apikey)创建密钥,再运行:
```powershell
.\deploy\local-rtc\configure-ark-summary.ps1
```
该脚本只更新`ark-api-key`、`CONTENT_GENERATOR`和`ARK_CONTENT_MODEL`,不会修改已有RTC、语音或设备凭据。当前Chat API既支持模型Model ID,也支持Endpoint ID;脚本默认使用`doubao-seed-2-0-lite-260215`,如果账号未开通该模型,可在提示中填写已开通的Model ID或Endpoint ID。
脚本会以隐藏输入方式依次读取:
- RTC AppKey;
@@ -34,8 +49,16 @@
1. 保持默认本地平台地址、设备 ID 和本地测试设备密钥;
2. 点击“检测平台和音频设备”;
3. 选择麦克风和扬声器;
4. 点击“开始语音聊天”;
5. 看到“豆包语音任务已激活”后直接说话;
6. 点击“结束通话”验证`StopVoiceChat`和RTC离房。
4. 确认同一个RTC AppID已在RTC控制台的“实时字幕”功能中启用流式语音识别;
5. 点击“开始语音聊天”;
6. 看到“RTC 实时字幕已启动”和“豆包语音任务已激活”后直接说话;
7. 确认“实时字幕与上传”区域同时出现长者和豆包话轮;
8. 点击“结束通话”验证字幕补交、`StopVoiceChat`和RTC离房。
实时字幕要求先在豆包语音控制台创建服务类型为“流式语音识别”的应用,再在RTC控制台的实时字幕配置中填写该应用的APP ID、Access Token和Cluster ID。未开通或配置不匹配时SDK返回`ServiceAccessDenied`;这与“实时对话式AI > 回调设置”无关,不需要为字幕上传填写回调URL。
通话结束后,Worker会根据最终话轮生成通话摘要、关键词、开放话题和待审核故事。只有人工确认故事后才会进入长期记忆,这是既有授权与审核边界,模拟器不会绕过审核自动写入长期记忆。本地默认`CONTENT_GENERATOR=local`仅用于确定性闭环验证;要验证真实大模型总结,必须另外为Worker配置`CONTENT_GENERATOR=ark`、`ARK_API_KEY_FILE`和`ARK_CONTENT_MODEL`。
当新通话冻结快照中的`story_extraction`和`personalized_memory`授权均有效时,平台会把最近3次已完成通话的就绪摘要作为短期连续上下文注入豆包;S2S-O模式使用`dialog.system_role`,无需开启供应商侧`dialog_id`历史留存。长者档案中的“避免主动提及”话题也会从下一次开房起一并生效。
RTC AppKey、火山 AK/SK 和豆包 Access Token 均不进入模拟器安装包,也不会通过渲染页面读取。
+5
View File
@@ -21,7 +21,12 @@ services:
# Quote date-shaped API versions so YAML does not coerce them into timestamps.
VOLC_RTC_API_VERSION: "2024-12-01"
VOLC_VOICE_CHAT_TEMPLATE_FILE: /run/secrets/local-rtc/voice-chat-template.json
CONTENT_GENERATOR: ${CONTENT_GENERATOR:-local}
ARK_API_KEY: ""
ARK_API_KEY_FILE: /run/secrets/local-rtc/ark-api-key
ARK_CONTENT_MODEL: ${ARK_CONTENT_MODEL:-}
volumes:
- ./deploy/local-rtc/runtime/volc-access-key-id:/run/secrets/local-rtc/volc-access-key-id:ro
- ./deploy/local-rtc/runtime/volc-secret-access-key:/run/secrets/local-rtc/volc-secret-access-key:ro
- ./deploy/local-rtc/runtime/voice-chat-template.json:/run/secrets/local-rtc/voice-chat-template.json:ro
- ./deploy/local-rtc/runtime/ark-api-key:/run/secrets/local-rtc/ark-api-key:ro
@@ -0,0 +1,52 @@
[CmdletBinding()]
param(
[string]$Model = "doubao-seed-2-0-lite-260215"
)
$ErrorActionPreference = "Stop"
$scriptDirectory = Split-Path -Parent $MyInvocation.MyCommand.Path
$runtimeDirectory = Join-Path $scriptDirectory "runtime"
$environmentFile = Join-Path $runtimeDirectory "local-rtc.env"
$apiKeyFile = Join-Path $runtimeDirectory "ark-api-key"
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
if (-not (Test-Path -LiteralPath $environmentFile -PathType Leaf)) {
throw "Run .\deploy\local-rtc\configure.ps1 before configuring Ark summaries."
}
$secureKey = Read-Host "Ark API Key (input is hidden)" -AsSecureString
$pointer = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureKey)
try {
$apiKey = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($pointer)
}
finally {
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($pointer)
}
if ([string]::IsNullOrWhiteSpace($apiKey)) {
throw "Ark API Key is required."
}
$selectedModel = Read-Host "Ark content Model ID or Endpoint ID [$Model]"
if ([string]::IsNullOrWhiteSpace($selectedModel)) {
$selectedModel = $Model
}
$selectedModel = $selectedModel.Trim()
if ([string]::IsNullOrWhiteSpace($selectedModel)) {
throw "Ark content model is required."
}
$settings = [ordered]@{}
foreach ($line in Get-Content -LiteralPath $environmentFile) {
if ($line -match '^([^#=][^=]*)=(.*)$') {
$settings[$matches[1].Trim()] = $matches[2]
}
}
$settings["CONTENT_GENERATOR"] = "ark"
$settings["ARK_CONTENT_MODEL"] = $selectedModel
$environmentContent = ($settings.GetEnumerator() | ForEach-Object { "$($_.Key)=$($_.Value)" }) -join "`n"
[IO.File]::WriteAllText($apiKeyFile, $apiKey.Trim(), $utf8NoBom)
[IO.File]::WriteAllText($environmentFile, $environmentContent + "`n", $utf8NoBom)
Write-Host "Ark summary configuration updated. Existing RTC and voice credentials were not changed." -ForegroundColor Green
Write-Host "Next: .\deploy\local-rtc\start.ps1" -ForegroundColor Green
+9 -1
View File
@@ -1,6 +1,8 @@
[CmdletBinding()]
param(
[string]$RtcAppId = "6a8f92ca43726c017d34cce1",
[switch]$EnableArkSummary,
[string]$ArkContentModel = "",
[switch]$Force
)
@@ -57,6 +59,11 @@ $volcSecretAccessKey = Read-RequiredSecret "火山引擎 Secret AccessKey"
$doubaoAppId = Read-RequiredText "豆包端到端语音 APP ID"
$doubaoAccessToken = Read-RequiredSecret "豆包端到端语音 Access Token"
$speaker = Read-RequiredText "豆包音色 ID" "zh_female_vv_jupiter_bigtts"
$arkApiKey = ""
if ($EnableArkSummary) {
$arkApiKey = Read-RequiredSecret "方舟 API Key"
$ArkContentModel = Read-RequiredText "方舟内容模型 Endpoint ID" $ArkContentModel
}
$template = [ordered]@{
schema_version = "voice-chat-template-bundle-v1"
@@ -103,6 +110,7 @@ $template = [ordered]@{
Write-SecretFile "rtc-app-key" $rtcAppKey
Write-SecretFile "volc-access-key-id" $volcAccessKeyId
Write-SecretFile "volc-secret-access-key" $volcSecretAccessKey
Write-SecretFile "ark-api-key" $arkApiKey
[IO.File]::WriteAllText(
(Join-Path $runtimeDirectory "voice-chat-template.json"),
($template | ConvertTo-Json -Depth 20),
@@ -110,7 +118,7 @@ Write-SecretFile "volc-secret-access-key" $volcSecretAccessKey
)
[IO.File]::WriteAllText(
(Join-Path $runtimeDirectory "local-rtc.env"),
"RTC_APP_ID=$RtcAppId`n",
"RTC_APP_ID=$RtcAppId`nCONTENT_GENERATOR=$(if ($EnableArkSummary) { 'ark' } else { 'local' })`nARK_CONTENT_MODEL=$ArkContentModel`n",
$utf8NoBom
)
+7 -6
View File
@@ -10,13 +10,14 @@ $requiredFiles = @(
"rtc-app-key",
"volc-access-key-id",
"volc-secret-access-key",
"ark-api-key",
"voice-chat-template.json",
"local-rtc.env"
)
foreach ($name in $requiredFiles) {
if (-not (Test-Path -LiteralPath (Join-Path $runtimeDirectory $name) -PathType Leaf)) {
throw "缺少 $name,请先运行 .\deploy\local-rtc\configure.ps1"
throw "Missing $name. Run .\deploy\local-rtc\configure.ps1 first."
}
}
@@ -35,9 +36,9 @@ try {
"callbacks", "mock-alert-receiver", "mock-provider", "api", "worker"
)
& docker @arguments
if ($LASTEXITCODE -ne 0) { throw "Docker Compose 启动失败" }
if ($LASTEXITCODE -ne 0) { throw "Docker Compose startup failed." }
Write-Host "`n等待本地 API 就绪..." -ForegroundColor Cyan
Write-Host "`nWaiting for local API readiness..." -ForegroundColor Cyan
$deadline = [DateTime]::UtcNow.AddMinutes(3)
do {
Start-Sleep -Seconds 2
@@ -48,9 +49,9 @@ try {
catch { }
} while ([DateTime]::UtcNow -lt $deadline)
if (-not $health) { throw "本地 API 未在三分钟内就绪,请检查 docker compose logs api worker" }
Write-Host "本地真实 RTC 后端已就绪:http://localhost:58080" -ForegroundColor Green
Write-Host "现在可以启动 Windows 语音终端模拟器。" -ForegroundColor Green
if (-not $health) { throw "Local API did not become ready within three minutes. Check docker compose logs api worker." }
Write-Host "Local real RTC backend is ready: http://localhost:58080" -ForegroundColor Green
Write-Host "You can now start the Windows voice device simulator." -ForegroundColor Green
}
finally {
Pop-Location