From cde047af1986dfd58183d254a6dd901560a82b9d Mon Sep 17 00:00:00 2001 From: Del Wang Date: Sun, 11 May 2025 11:34:42 +0800 Subject: [PATCH] =?UTF-8?q?feat(migpt):=20=E6=96=B0=E5=A2=9E=20Docker=20?= =?UTF-8?q?=E4=B8=80=E9=94=AE=E8=BF=90=E8=A1=8C=E9=95=9C=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 19 ++++++++ README.md | 6 +-- examples/migpt/Cargo.lock | 6 +-- examples/migpt/Dockerfile | 64 ++++++++++++++++++++++++ examples/migpt/README.md | 89 ++++++++++++++++++++-------------- examples/migpt/config.ts | 72 +++++++++++++++++++++++++++ examples/migpt/migpt/index.ts | 25 +--------- examples/migpt/migpt/xiaoai.ts | 2 +- examples/migpt/tsconfig.json | 2 +- packages/client-rust/README.md | 3 -- 10 files changed, 218 insertions(+), 70 deletions(-) create mode 100644 .dockerignore create mode 100644 examples/migpt/Dockerfile create mode 100644 examples/migpt/config.ts diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6e5ed24 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,19 @@ +# 排除全部文件 +**/* + +# 只保留构建相关的文件 +!examples/migpt/src +!examples/migpt/migpt +!examples/migpt/config.ts +!examples/migpt/package.json +!examples/migpt/pnpm-lock.yaml +!examples/migpt/Cargo.toml +!examples/migpt/Cargo.lock +!examples/migpt/tsconfig.json +examples/migpt/migpt/open-xiaoai.node + +!packages/client-rust/src +!packages/client-rust/Cargo.toml +!packages/client-rust/Cargo.lock + + diff --git a/README.md b/README.md index 6f7bfb7..ca6225c 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ - 它能执行命令,却不会主动思考 - 它有千万用户,却只有一套思维 -我们曾幻想中的"贾维斯"级人工智能,在现实场景中沦为"闹钟+音乐播放器"。 +我们曾幻想中的"贾维斯"级人工智能,在现实场景中沦为"天气预报+音乐播放器"。 **真正的智能不应被预设的代码逻辑所束缚,而应像生命体般在交互中进化。** @@ -50,10 +50,10 @@ 3. 运行以下演示程序,体验小爱音箱的全新能力 ✨ - 👉 [小爱音箱接入小智 AI](examples/xiaozhi/README.md) - 👉 [小爱音箱自定义唤醒词](examples/kws/README.md) - - 👉 [小爱音箱接入 MiGPT-Next](examples/migpt/README.md) + - 👉 [小爱音箱接入 MiGPT(完美版)](examples/migpt/README.md) - 👉 [小爱音箱接入 Gemini Live API](examples/gemini/README.md) -以上皆为抛砖引玉,你也可以亲手编写自己想要的功能,一切由你定义! +以上皆为抛砖引玉,你也可以亲手编写自己想要的功能(比如:Airplay、DLNA、开启 DTS 音效等),一切由你定义! ## 相关项目 diff --git a/examples/migpt/Cargo.lock b/examples/migpt/Cargo.lock index 1b65d21..2b95abd 100644 --- a/examples/migpt/Cargo.lock +++ b/examples/migpt/Cargo.lock @@ -390,6 +390,7 @@ name = "open-xiaoai" version = "1.0.0" dependencies = [ "futures", + "rand", "serde", "serde_json", "tokio", @@ -480,13 +481,12 @@ checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha", "rand_core", - "zerocopy", ] [[package]] diff --git a/examples/migpt/Dockerfile b/examples/migpt/Dockerfile new file mode 100644 index 0000000..274ca10 --- /dev/null +++ b/examples/migpt/Dockerfile @@ -0,0 +1,64 @@ +FROM ubuntu:22.04 AS builder + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +WORKDIR /app + +COPY examples/migpt . +COPY packages/client-rust ./client-rust + +# 更新源 +RUN apt update && apt install curl build-essential -y + +# 安装 Rust +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + +# Create a script file sourced by both interactive and non-interactive bash shells +ENV BASH_ENV=/root/.bash_env +RUN touch "$BASH_ENV" +RUN echo '. "$BASH_ENV"' >> "$HOME/.bashrc" +RUN echo '[ -s "$HOME/.cargo/env" ] && . "$HOME/.cargo/env"' >> "$BASH_ENV" + +# nvm +RUN echo 'export NVM_DIR="$HOME/.nvm"' >> "$BASH_ENV" +RUN echo '[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"' >> "$BASH_ENV" +RUN echo '[ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"' >> "$BASH_ENV" + +# 安装 Node.js +RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash \ + && \. $NVM_DIR/nvm.sh && \. $NVM_DIR/bash_completion \ + && nvm install 22 + +# 安装依赖 +RUN npm install -g corepack \ + && corepack enable && corepack install \ + && pnpm install + +# 构建 Rust Server +RUN sed -i 's/\.\.\/\.\.\/packages\///g' Cargo.toml \ + && pnpm build + + + + +FROM ubuntu:22.04 AS runner + +WORKDIR /app + +COPY --from=builder /app/migpt /app/migpt +COPY --from=builder /app/package.json /app/package.json +COPY --from=builder /app/tsconfig.json /app/tsconfig.json +COPY --from=builder /app/node_modules /app/node_modules + +# 更新源 +RUN apt update && apt install curl build-essential -y + +ENV NVM_DIR=/root/.nvm + +# 安装 Node.js +RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash \ + && bash -c "source $NVM_DIR/nvm.sh && nvm install 22" + +ENTRYPOINT ["bash", "-c", "source $NVM_DIR/nvm.sh && exec \"$@\"", "--"] + +CMD ["npm", "run", "start"] diff --git a/examples/migpt/README.md b/examples/migpt/README.md index 58dbbe0..311f11b 100644 --- a/examples/migpt/README.md +++ b/examples/migpt/README.md @@ -1,18 +1,65 @@ # Open-XiaoAI x MiGPT-Next -[Open-XiaoAI](https://github.com/idootop/open-xiaoai) 的 Node.js 版 Server 端,用来演示小爱音箱接入[MiGPT-Next](https://github.com/idootop/migpt-next)。 +[Open-XiaoAI](https://github.com/idootop/open-xiaoai) 的 Node.js 版 Server 端,用来演示小爱音箱接入[MiGPT](https://github.com/idootop/mi-gpt)(完美版)。 -## 环境准备 +相比原版的 `MiGPT` 和 `MiGPT-Next` 项目,该版本可以完美打断小爱音箱的回复,响应延迟更低,效果更完美 👍 + +## 快速开始 + +> [!NOTE] +> 继续下面的操作之前,你需要先在小爱音箱上启动运行 Rust 补丁程序 [👉 教程](../../packages/client-rust/README.md) + +首先,克隆仓库代码到本地。 + +```shell +# 克隆代码 +git clone https://github.com/idootop/open-xiaoai.git + +# 进入当前项目根目录 +cd examples/migpt +``` + +然后把 `config.ts` 文件里的配置修改成你自己的。 + +```typescript +export const kOpenXiaoAIConfig = { + openai: { + model: "gpt-4.1-mini", + baseURL: "https://api.openai.com/v1", + apiKey: "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx", + }, + prompt: { + system: "你是一个智能助手,请根据用户的问题给出回答。", + }, + async onMessage(engine, { text }) { + if (text === "测试") { + return { text: "你好,很高兴认识你!" }; + } + }, +}; +``` + +### Docker 运行 + +[![Docker Image Version](https://img.shields.io/docker/v/idootop/open-xiaoai-migpt?color=%23086DCD&label=docker%20image)](https://hub.docker.com/r/idootop/open-xiaoai-migpt) + +推荐新手小白使用以下命令,直接 Docker 一键运行。 + +```shell +docker run -it --rm -p 4399:4399 -v $(pwd)/config.ts:/app/config.ts idootop/open-xiaoai-migpt:latest +``` + +### 编译运行 + +> [!TIP] +> 如果你是一名开发者,想要修改源代码实现自己想要的功能,可以按照下面的步骤,自行编译运行该项目。 为了能够正常编译运行该项目,你需要安装以下依赖环境: - Node.js v22.x: https://nodejs.org/zh-cn/download - Rust: https://www.rust-lang.org/learn/get-started -## 编译运行 - -> [!NOTE] -> 请先确认你已经将小爱音箱刷机成功,并安装运行了 Rust 补丁程序 [👉 教程](../../packages/client-rust/README.md) +准备好开发环境后,按以下步骤即可正常启动该项目。 ```bash # 启用 PNPM 包管理工具 @@ -25,36 +72,6 @@ pnpm install pnpm dev ``` -首次运行你需要先配置自己的大模型服务,才能正常获取 AI 回复。 - -> [!NOTE] -> 你可以在下面的 `onMessage` 函数中,自定义你想要的回复逻辑,更多配置参考 👉 [MiGPT-Next](https://github.com/idootop/migpt-next/tree/main/apps/next) - -```typescript -// packages/server-node/migpt/index.ts -import { sleep } from "@mi-gpt/utils"; -import { OpenXiaoAI } from "./xiaoai.js"; - -async function main() { - await OpenXiaoAI.start({ - openai: { - model: "gpt-4o-mini", - baseURL: "https://api.openai.com/v1", - apiKey: "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", - }, - async onMessage(_engine, { text }) { - if (text.startsWith("你好")) { - await sleep(1000); - return { text: "你好,很高兴认识你!" }; - } - }, - }); - process.exit(0); -} - -main(); -``` - ## 注意事项 1. 默认 Server 服务端口为 `4399`(比如 ws://192.168.31.227:4399),运行前请确保该端口未被其他程序占用。 diff --git a/examples/migpt/config.ts b/examples/migpt/config.ts new file mode 100644 index 0000000..0d49f1d --- /dev/null +++ b/examples/migpt/config.ts @@ -0,0 +1,72 @@ +import { sleep } from "@mi-gpt/utils"; +import { OpenXiaoAIConfig } from "./migpt/xiaoai.js"; + +export const kOpenXiaoAIConfig: OpenXiaoAIConfig = { + openai: { + /** + * 你的大模型服务提供商的接口地址 + * + * 支持兼容 OpenAI 接口的大模型服务,比如:DeepSeek V3 等 + * + * 注意:一般以 /v1 结尾,不包含 /chat/completions 部分 + * - ✅ https://api.openai.com/v1 + * - ❌ https://api.openai.com/v1/(最后多了一个 / + * - ❌ https://api.openai.com/v1/chat/completions(不需要加 /chat/completions) + */ + baseURL: "https://api.openai.com/v1", + /** + * API 密钥 + */ + apiKey: "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx", + /** + * 模型名称 + */ + model: "gpt-4.1-mini", + }, + prompt: { + /** + * 系统提示词,如需关闭可设置为:''(空字符串) + */ + system: "你是一个智能助手,请根据用户的问题给出回答。", + }, + context: { + /** + * 每次对话携带的最大历史消息数(如需关闭可设置为:0) + */ + historyMaxLength: 10, + }, + /** + * 只回答以下关键词开头的消息: + * + * - 请问地球为什么是圆的? + * - 你知道世界上跑的最快的动物是什么吗? + */ + callAIKeywords: ["请", "你"], + /** + * 自定义消息回复 + */ + async onMessage(engine, { text }) { + if (text === "测试播放文字") { + return { text: "你好,很高兴认识你!" }; + } + + if (text === "测试播放音乐") { + return { url: "https://example.com/hello.mp3" }; + } + + if (text === "测试其他能力") { + // 打断原来小爱的回复 + await engine.speaker.abortXiaoAI(); + + // 播放文字 + await sleep(2000); // 打断小爱后需要等待 2 秒,使其恢复运行后才能继续 TTS + await engine.speaker.play({ text: "你好,很高兴认识你!", blocking: true }); + + // 播放音频链接 + await engine.speaker.play({ url: "https://example.com/hello.mp3" }); + + // 告诉 MiGPT 已经处理过这条消息了,不再使用默认的 AI 回复 + return { handled: true }; + } + }, +}; diff --git a/examples/migpt/migpt/index.ts b/examples/migpt/migpt/index.ts index d923125..b8670d8 100644 --- a/examples/migpt/migpt/index.ts +++ b/examples/migpt/migpt/index.ts @@ -1,29 +1,8 @@ -import { sleep } from "@mi-gpt/utils"; +import { kOpenXiaoAIConfig } from "config.js"; import { OpenXiaoAI } from "./xiaoai.js"; async function main() { - await OpenXiaoAI.start({ - openai: { - model: "gpt-4o-mini", - baseURL: "https://api.openai.com/v1", - apiKey: "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", - }, - /** - * 默认只会处理以下关键词开头的消息,你也可以自定义: - * - 请问地球为什么是圆的? - * - 你知道世界上跑的最快的动物是什么吗? - */ - callAIKeywords: ["请", "你"], - /** - * 自定义消息回调 - */ - async onMessage(_engine, { text }) { - if (text.startsWith("你好")) { - await sleep(1000); - return { text: "你好,很高兴认识你!" }; - } - }, - }); + await OpenXiaoAI.start(kOpenXiaoAIConfig); process.exit(0); } diff --git a/examples/migpt/migpt/xiaoai.ts b/examples/migpt/migpt/xiaoai.ts index b108710..ea1348c 100644 --- a/examples/migpt/migpt/xiaoai.ts +++ b/examples/migpt/migpt/xiaoai.ts @@ -6,7 +6,7 @@ import { RustServer } from "./open-xiaoai.js"; import { OpenXiaoAISpeaker } from "./speaker.js"; import { randomUUID } from "node:crypto"; -type OpenXiaoAIConfig = Prettify>; +export type OpenXiaoAIConfig = Prettify>; const kDefaultOpenXiaoAIConfig: OpenXiaoAIConfig = { // diff --git a/examples/migpt/tsconfig.json b/examples/migpt/tsconfig.json index 07665a5..2add43b 100644 --- a/examples/migpt/tsconfig.json +++ b/examples/migpt/tsconfig.json @@ -6,6 +6,6 @@ "@/*": ["migpt/*"] } }, - "include": ["migpt"], + "include": ["migpt", "config.ts"], "exclude": ["node_modules"] } diff --git a/packages/client-rust/README.md b/packages/client-rust/README.md index 7df6ef6..71f21fa 100644 --- a/packages/client-rust/README.md +++ b/packages/client-rust/README.md @@ -45,9 +45,6 @@ curl -L -o /data/init.sh https://gitee.com/idootop/artifacts/releases/download/o 为了构建能够在小爱音箱上运行的 ARMv7 应用,你还需要安装 `cross` 👉 [传送门](https://github.com/cross-rs/cross) ```shell -# 安装依赖 -cargo fetch - # 交叉编译 cross build --release --target armv7-unknown-linux-gnueabihf ```