中文 | English
该 Demo 是端云交互的最简 Demo:端侧发消息到云侧,云侧收到后直接返回。消息通道采用 ngrok。
没有真正的云端服务器,也没有固定公网 IP。用本地电脑模拟云端;用 ngrok 把本机端口映射成固定公网地址,模拟固定 IP。
- 端侧:
client/(Android arm64-v8a 手机 App) - 云侧:
server/(本机回显进程,经 ngrok 对外表现为固定 HTTPS 入口)
云侧(本机 Agent) |
端侧(Client) |
语音输入与 android-vad-asr-demo 相同,使用端侧 sherpa-onnx。model.int8.onnx 等模型未随仓库提供;不下载模型则不支持语音输入,界面只保留文字输入和发送。个人域名也不在仓库里。克隆后只改下面这些,真实域名不要提交。
| 序号 | 改什么 | 文件 / 变量 | 怎么改 |
|---|---|---|---|
| 1 | 语音模型(可选) | client/app/src/main/assets/sherpa-onnx-paraformer-zh-2023-09-14/model.int8.onnx、tokens.txt;JNI:client/app/src/main/jniLibs/arm64-v8a/ |
按 android-vad-asr-demo 下载放入。不放则无语音,只留文字输入和发送 |
| 2 | 个人 ngrok 域名(云侧) | server/start.sh 里的 DEFAULT_NGROK_URL |
申请预留域名后改为 https://xxxx.ngrok-free.dev。也可不改文件,启动时带 NGROK_URL=... |
| 2 | 个人 ngrok 域名(端侧) | client/app/src/main/res/values/strings.xml 里的 default_server_url |
填同一条地址,App 打开即预填。不改则每次在输入框粘贴 |
ngrok authtoken 不写进仓库,本机执行一次 ngrok config add-authtoken <your-token>。
端侧发出一句话,云侧原样返回,手机屏幕显示同一段文字。不跑产品 Agent,只验证通道是否通。
端侧(client)
- 文字输入后点「发送」。
- 若已放入语音模型:点麦克风,本地转写成文字再发送(不上传音频)。未放入模型时,只显示文字输入和发送。
- 在输入框填入自己的 ngrok 地址(形如
https://xxxx.ngrok-free.dev),点「连接」。
云侧(server)
- 没有云主机:
echo_server.py跑在本机,监听127.0.0.1:17890,POST /chat收到 JSON 后直接返回。 - 没有固定 IP:ngrok 把 17890 映射到你自己预留的域名(形如
https://xxxx.ngrok-free.dev),对外当作固定入口。个人域名不要写入仓库。 GET /health探活;POST /session/online|heartbeat|offline记录上线、心跳、下线。- 手机无需 USB,也无需和电脑同一 Wi-Fi。
端侧经 ngrok 把消息送到本机上的「云侧」,本机原样回写。没有真云、没有固定 IP,ngrok 只负责把本机端口扮成固定入口。数据路径:
手机 App --HTTPS POST /chat--> ngrok 公网域名
│
ngrok 隧道
▼
电脑 echo_server <--listen-- 127.0.0.1:17890
│
原样返回 JSON
▼
手机界面显示服务端返回的 text
消息是一行 UTF-8 JSON:
{"type":"chat","text":"你好"}语音只在手机本地转成这段 text,线上没有音频。ngrok 在本机和公网之间开一条隧道:外面访问你的 ngrok 域名,等于访问电脑的 http://127.0.0.1:17890。
不要使用目录里旧的 policy.yaml(它会把所有请求拦成 Hello, World,回显就失效)。
手机要和电脑上的服务对话,常见接法如下。本 Demo 选用 ngrok 隧道。
| 方式 | 做法 | 优势 | 劣势 |
|---|---|---|---|
USB + adb reverse |
数据线连接,电脑把本机端口转到手机的 127.0.0.1 |
不暴露公网、调试简单、延迟低 | 必须插 USB、依赖 adb,不能给真实用户用 |
| 同一局域网 | 手机访问电脑的局域网 IP + 端口 | 不依赖第三方、实现直接 | 必须同一 Wi-Fi;IP 常变;防火墙/隔离 AP 会拦;一般没有现成 HTTPS |
| ngrok 隧道(本 Demo) | 本机端口映射到固定公网 HTTPS | 任意网络可连、有 HTTPS、不用 USB、不用同一 Wi-Fi | 依赖 ngrok 账号与额度;免费域名有拦截页,App 需带跳过 Header |
| 自建隧道(frp / Cloudflare Tunnel / Tailscale) | 自己搭或用其它穿透服务,效果类似 ngrok | 可控性更高,可走内网或自有域名 | 要额外部署或账号;接入成本比现成 ngrok 高 |
| 公网云端服务 | 把服务部署到云主机 / API 网关,手机直连 | 接近产品形态,可多用户、可扩展 | 不再是「电脑上的本地 Agent」;要部署、证书和运维 |
| WebSocket / 长连接 | 在上述任一通道上改为服务端推送 | 服务端可主动推进度、流式结果 | 协议和会话管理更复杂;本 Demo 的回显用 HTTP POST 即可 |
语音识别在手机本地完成,方案与 android-vad-asr-demo 一致:sherpa-onnx + Paraformer 中文模型。未放入 model.int8.onnx 时,运行期关闭语音入口。
- 安装:https://ngrok.com/download
- 在 ngrok Dashboard 复制 authtoken(只放在本机,不要写入仓库)
- 执行一次:
ngrok config add-authtoken <your-token>配置会写到本机 ~/Library/Application Support/ngrok/ngrok.yml。
chmod +x server/start.sh
NGROK_URL=https://xxxx.ngrok-free.dev ./server/start.sh把 xxxx.ngrok-free.dev 换成你在 ngrok Dashboard 预留的域名,不要把真实地址写进仓库。
脚本会:
- 在
17890拉起echo_server.py(无需 sudo) - 执行
ngrok http 17890 --url "$NGROK_URL"
只测本机回显(不经过 ngrok):
python3 server/echo_server.py --port 17890
curl -s http://127.0.0.1:17890/health
curl -s -X POST http://127.0.0.1:17890/chat \
-H 'Content-Type: application/json' \
-d '{"type":"chat","text":"你好"}'应返回 {"type":"chat","text":"你好"}。
用 Android Studio 打开 client/,连 arm64 真机 Run。
- 把电脑端同一条 ngrok 地址粘贴到输入框(形如
https://xxxx.ngrok-free.dev) - 点「连接」(内部请求
GET /health) - 输入文字,点「发送」(
POST /chat) - 下方应出现服务端原样返回的文字
手机能连上公网,是因为 Manifest 已声明 INTERNET,请求带 ngrok-skip-browser-warning(避免免费域名的浏览器提示页挡住 App),连接对象是 ngrok 的 HTTPS 主机而不是 127.0.0.1,因此不需要 adb reverse。
语音输入与 android-vad-asr-demo 相同。模型下载与 .so 放置见该仓库说明。
model.int8.onnx 约 232MB,不纳入本仓库。需要语音时,按该 Demo 把模型放到:
client/app/src/main/assets/sherpa-onnx-paraformer-zh-2023-09-14/model.int8.onnx
client/app/src/main/assets/sherpa-onnx-paraformer-zh-2023-09-14/tokens.txt
JNI 库放到 client/app/src/main/jniLibs/arm64-v8a/。
不下载模型则不支持语音输入:启动时若 assets 中没有 model.int8.onnx 或其它 .onnx,界面只展示文字输入和发送。
ngrok/
├── README.md # 中文说明
├── README.en.md # English
├── server/
│ ├── echo_server.py # 本地 HTTP 回显
│ └── start.sh # 回显 + ngrok http
└── client/ # Android 工程

