+ {{ t('settings.pages.connection.qr-scan.description') }} +
++ {{ t('settings.pages.connection.qr.token-hint') }} +
++ {{ errorMessage }} +
+OLLAMA_HOST 详情,请检查 Ollama 集成指南。
+ 很抱歉,Ollama 连接检查失败。不要担心,如果是 Ollama,需要额外配置才能通过 Ollama。
+ 您需要在启动 Olama 应用程序或 Ollama CLI 服务器时明确设置
+ OLLAMA_HOST 详情,请检查 Ollama
+ 集成指南。
common:
continueAnyway: 仍然继续
- goToModelSelection: '选择模型→'
+ goToModelSelection: 选择模型→
fields:
field:
api-key:
@@ -666,14 +672,11 @@ pages:
helpinfo:
title: 开始之前
description:
- part1: >-
- 虽然 Anthropic 最近宣布他们正在提供对 OpenAI SDK 兼容性的 Beta 版支持
- part2: '(您可以在此处阅读更多信息)'
+ part1: 虽然 Anthropic 最近宣布他们正在提供对 OpenAI SDK 兼容性的 Beta 版支持
+ part2: (您可以在此处阅读更多信息)
part3: 但由于实现细节附带
- part4: >-
- 与 OpenAI SDK 不一致,目前无法在浏览器中使用此提供程序。
- part5: >-
- 如果您确实需要使用此提供程序,则需要一个专用的代理后端,例如在
+ part4: 与 OpenAI SDK 不一致,目前无法在浏览器中使用此提供程序。
+ part5: 如果您确实需要使用此提供程序,则需要一个专用的代理后端,例如在
part6: 上运行的Serverless Function,或者一些绕过 CORS 的服务,以绕过 CORS 限制。
cloudflare-workers-ai:
description: Cloudflare.com
@@ -758,8 +761,7 @@ pages:
description: 较小的模型加载更快,但质量可能略有下降。
models:
fp32-webgpu:
- description: >-
- 基于 WebGPU 的全精度模型 - 建议在支持的设备上使用
+ description: 基于 WebGPU 的全精度模型 - 建议在支持的设备上使用
fp32:
description: 全精度模型
fp16:
@@ -911,17 +913,44 @@ pages:
placeholder: ws://localhost:6121/ws
server-hostname:
label: Expose On Network
- description: Choose whether the AIRI gateway only listens on this device or can be reached from your local network.
+ description: >-
+ Choose whether the AIRI gateway only listens on this device or can be
+ reached from your local network.
advanced-label: Bind Hostname
- advanced-description: Use a specific hostname or IP address when you need manual network binding.
+ advanced-description: >-
+ Use a specific hostname or IP address when you need manual network
+ binding.
options:
this-device: This device
all: All
advanced: Advanced
server-auth-token:
label: Auth Token
- description: Security token required by remote clients that connect to this gateway. When left empty, AIRI generates a new token automatically.
+ description: >-
+ Security token required by remote clients that connect to this gateway.
+ When left empty, AIRI generates a new token automatically.
placeholder: Auto-generate
+ qr:
+ title: 显示二维码
+ description: 口袋 AIRI 可通过二维码快速连接到本机
+ refresh: 刷新
+ image-alt: AIRI 主脑连接二维码
+ candidates: 候选地址
+ token-hint: 二维码包含认证 token,用于让 Stage Pocket 连接后完成认证。不要公开分享。
+ errors:
+ title: 无法生成二维码
+ unavailable: 无法准备连接二维码。
+ qr-scan:
+ title: 快速连接
+ description: 扫描 Tamagotchi 上的二维码来快速连接主脑
+ instructions: 将摄像头对准 AIRI 连接二维码。
+ action: 扫描
+ success:
+ title: 连接成功!
+ description: 使用的连接地址:{url}
+ errors:
+ title: 扫码失败
+ failed: 无法通过此二维码扫码或连接。
scene:
description: 配置角色所在环境
title: 场景
@@ -981,8 +1010,7 @@ pages:
title: 拍立得
description: 拍摄模型照片的工具
context-flow:
- description: >-
- 检查传入的上下文更新和传出的聊天流事件
+ description: 检查传入的上下文更新和传出的聊天流事件
websocket-inspector:
title: WebSocket 检查器
description: 检查原始 WebSocket 流量
@@ -991,11 +1019,10 @@ pages:
description: 测试颜色提取
providers-transcription-realtime-aliyun-nls:
title: 阿里云实时转写
- description: >-
- 将麦克风音频流式传输到阿里云 NLS 并检查实时转写
+ description: 将麦克风音频流式传输到阿里云 NLS 并检查实时转写
performance-playground:
title: 性能测试场地
- description: 'VRM 表情 + TTS lip sync 实验平台'
+ description: VRM 表情 + TTS lip sync 实验平台
theme-presets:
presets:
default:
@@ -1061,8 +1088,7 @@ pages:
color-6: 金黄色
color-7: 天蓝色
color-8: 赭黄色
- description: >-
- 中国传统色彩,源自古代纺织品、瓷器和绘画
+ description: 中国传统色彩,源自古代纺织品、瓷器和绘画
title: 中国传统颜色
title: 预设
title: 系统
@@ -1127,9 +1153,7 @@ vrm:
skybox-specular-mix: 漫反射/镜面反射混合系数
websocket-secure-enabled:
title: 启用安全WebSocket (WSS)
- description: >-
- 启用 WSS (WebSocket Secure) 以便在开发模式下允许移动设备(Pocket) 连接HTTPS 。这将自动生成一个自签名证书。
+ description: 启用 WSS (WebSocket Secure) 以便在开发模式下允许移动设备(Pocket) 连接HTTPS 。这将自动生成一个自签名证书。
wip:
title: 正在开发中
- description: >-
- 此功能正在开发中,尚未公开发布。请在未来的更新中再次查看此功能。
+ description: 此功能正在开发中,尚未公开发布。请在未来的更新中再次查看此功能。
diff --git a/packages/stage-shared/package.json b/packages/stage-shared/package.json
index ef2449527..99bcb808c 100644
--- a/packages/stage-shared/package.json
+++ b/packages/stage-shared/package.json
@@ -18,6 +18,7 @@
".": "./src/index.ts",
"./auth": "./src/auth/index.ts",
"./beat-sync": "./src/beat-sync/index.ts",
+ "./server-channel-qr": "./src/server-channel-qr.ts",
"./electron-renderer": "./src/electron-renderer.d.ts",
"./composables": "./src/composables/index.ts"
},
@@ -27,6 +28,7 @@
"dependencies": {
"@vueuse/core": "catalog:",
"pinia": "catalog:",
+ "valibot": "catalog:",
"vue": "catalog:"
},
"devDependencies": {
diff --git a/packages/stage-shared/src/server-channel-qr.ts b/packages/stage-shared/src/server-channel-qr.ts
new file mode 100644
index 000000000..cc9b4fc78
--- /dev/null
+++ b/packages/stage-shared/src/server-channel-qr.ts
@@ -0,0 +1,44 @@
+import type { InferInput, InferOutput } from 'valibot'
+
+import { array, check, literal, minLength, object, parse, pipe, string, transform } from 'valibot'
+
+export const SERVER_CHANNEL_QR_PAYLOAD_TYPE = 'airi:server-channel'
+export const SERVER_CHANNEL_QR_PAYLOAD_VERSION = 1
+
+function isWebSocketUrl(value: string) {
+ try {
+ const url = new URL(value)
+ return (url.protocol === 'ws:' || url.protocol === 'wss:') && !!url.hostname
+ }
+ catch {
+ return false
+ }
+}
+
+function normalizeWebSocketUrl(value: string) {
+ return new URL(value).toString()
+}
+
+export const ServerChannelQrUrlSchema = pipe(
+ string(),
+ check(isWebSocketUrl, 'Expected a ws or wss URL.'),
+ transform(normalizeWebSocketUrl),
+)
+
+export const ServerChannelQrPayloadSchema = object({
+ type: literal(SERVER_CHANNEL_QR_PAYLOAD_TYPE),
+ version: literal(SERVER_CHANNEL_QR_PAYLOAD_VERSION),
+ urls: pipe(array(ServerChannelQrUrlSchema), minLength(1)),
+ authToken: string(),
+})
+
+export type ServerChannelQrPayloadInput = InferInput