mirror of
https://github.com/idootop/mi-gpt.git
synced 2026-06-03 21:02:00 +08:00
Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1aea52ef27 | ||
|
|
94ca31eb7e | ||
|
|
5d5937d208 | ||
|
|
6ca6a7e324 | ||
|
|
eaadc49b08 | ||
|
|
33abacd596 | ||
|
|
f91b88d39d | ||
|
|
1d50c27947 | ||
|
|
21def7b471 | ||
|
|
79787e8246 | ||
|
|
367e4caef0 | ||
|
|
2eb62f2cc9 | ||
|
|
d676de0509 | ||
|
|
a36ed3f494 | ||
|
|
b117245429 | ||
|
|
29e2bc95cd | ||
|
|
5d033c0170 | ||
|
|
54fbd21205 | ||
|
|
9f83eb1a0b | ||
|
|
a1b04816dd | ||
|
|
d14ce3bfaf | ||
|
|
5d455e2ffe | ||
|
|
bba886e275 | ||
|
|
11dc25aa60 | ||
|
|
208b2db60b | ||
|
|
c985e5b08f | ||
|
|
2f53d99359 | ||
|
|
27bde0ca4f | ||
|
|
ac310a2e16 | ||
|
|
02d5cd6fe2 | ||
|
|
619df40d42 | ||
|
|
1145048bc9 | ||
|
|
a0f1750b98 | ||
|
|
45ca981038 | ||
|
|
1362773c13 | ||
|
|
500cb3be81 | ||
|
|
08f3888cd9 | ||
|
|
adfdcc4ee5 | ||
|
|
0634ee7fb7 | ||
|
|
d890cdc855 | ||
|
|
814182c1c5 | ||
|
|
dfb48a2025 | ||
|
|
e463cc9655 | ||
|
|
bbdb80e9bc | ||
|
|
4656e426cd | ||
|
|
f7683a6ec7 | ||
|
|
62248b04cd | ||
|
|
a8c9ba7e0f | ||
|
|
ee2c018278 | ||
|
|
5c6f61fce3 | ||
|
|
7224e3fb08 | ||
|
|
fc5b320141 | ||
|
|
cf9c7865cf | ||
|
|
314b0f3244 | ||
|
|
e888ff451e | ||
|
|
3c5b7e6bd7 | ||
|
|
beafec6d11 | ||
|
|
77d31a024a | ||
|
|
9d8b2875c0 | ||
|
|
6e73ce8eee | ||
|
|
84a46b688b | ||
|
|
02114694ea | ||
|
|
974fbbf653 | ||
|
|
c033235d2c | ||
|
|
84e039cc76 | ||
|
|
8d48ee5b86 |
14
.env.example
14
.env.example
@ -1,7 +1,8 @@
|
||||
# OpenAI(也支持通义千问、MoonShot、DeepSeek 等模型)
|
||||
OPENAI_MODEL=gpt-4o
|
||||
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxx
|
||||
OPENAI_BASE_URL=https://api.openai.com/v1
|
||||
OPENAI_MODEL=gpt-4o-mini
|
||||
OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxxxx
|
||||
# 你的大模型服务接口,比如:https://api.openai.com/v1(注意:一般以 /v1 结尾)
|
||||
# OPENAI_BASE_URL=https://api.openai.com/v1
|
||||
|
||||
# Azure OpenAI Service(可选)
|
||||
# OPENAI_API_VERSION=2024-04-01-preview
|
||||
@ -16,4 +17,9 @@ OPENAI_BASE_URL=https://api.openai.com/v1
|
||||
# AUDIO_ERROR=出错了提示音链接,同上
|
||||
|
||||
# 第三方 TTS(可选,用于调用第三方 TTS 服务)
|
||||
# TTS_BASE_URL=你的 TTS 接口地址,比如:http://[你的局域网/公网地址]:[端口]/api
|
||||
# TTS_BASE_URL=http://[你的局域网或公网地址]:[端口号]/[SECRET_PATH]/api
|
||||
# 比如:http://192.168.31.205:4321/xxxx/api(注意:不要使用 localhost 或 127.0.0.1)
|
||||
|
||||
# 通义千问模型在生成文本时是否使用互联网搜索结果进行参考
|
||||
# qwen-vl系列、qwen开源系列与qwen-long模型暂时不支持配置该参数
|
||||
# QWEN_ENABLE_SEARCH=true
|
||||
@ -138,7 +138,7 @@ export default {
|
||||
// TTS 引擎
|
||||
tts: "xiaoai",
|
||||
// 切换 TTS 引擎发言人音色关键词,只有配置了第三方 TTS 引擎时才有效
|
||||
// switchSpeakerKeywords: ["把声音换成"], // 以此关键词开头即可切换音色,比如:把声音换成东北老铁
|
||||
// switchSpeakerKeywords: ["把声音换成"], // 以此关键词开头即可切换音色,比如:把声音换成 xxx
|
||||
|
||||
/**
|
||||
* 💬 连续对话
|
||||
@ -147,7 +147,7 @@ export default {
|
||||
*/
|
||||
|
||||
// 是否启用连续对话功能,部分小爱音箱型号无法查询到正确的播放状态,需要关闭连续对话
|
||||
streamResponse: true,
|
||||
streamResponse: false,
|
||||
// 连续对话时,无响应多久后自动退出
|
||||
exitKeepAliveAfter: 30, // 默认 30 秒,建议不要超过 1 分钟
|
||||
// 连续对话时,下发 TTS 指令多长时间后开始检测设备播放状态(默认 3 秒)
|
||||
@ -163,5 +163,7 @@ export default {
|
||||
debug: false, // 一般情况下不要打开
|
||||
// 是否跟踪 Mi Service 相关日志(打开后可以查看设备 did)
|
||||
enableTrace: false, // 一般情况下不要打开
|
||||
// 网络请求超时时长(单位毫秒,默认 5 秒)
|
||||
timeout: 5000,
|
||||
},
|
||||
};
|
||||
|
||||
101
README.md
101
README.md
@ -1,8 +1,26 @@
|
||||

|
||||
> [!WARNING]
|
||||
> 本项目已停止维护,不再提供更新与支持,感谢大家的使用。
|
||||
|
||||
<div align="center">
|
||||
|
||||
# MiGPT:智能家居,从未如此贴心 ❤️
|
||||
|
||||
[](https://www.npmjs.com/package/mi-gpt) [](https://hub.docker.com/r/idootop/mi-gpt)
|
||||
<a href="https://trendshift.io/repositories/10645" target="_blank"><img src="https://trendshift.io/api/badge/repositories/10645" alt="idootop%2Fmi-gpt | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
|
||||
👉 演示视频:[将小爱音箱接入 ChatGPT 和豆包,改造成你的专属语音助手~](https://www.bilibili.com/video/BV1N1421y7qn/?share_source=copy_web&vd_source=5d4e78ff2a0dc6a661baa65f479199c1)
|
||||
|
||||
[](https://hub.docker.com/r/idootop/mi-gpt)
|
||||
[](https://www.npmjs.com/package/mi-gpt)
|
||||
[](https://hub.docker.com/r/idootop/mi-gpt)
|
||||
[](https://github.com/idootop/mi-gpt/blob/main/LICENSE)
|
||||
[](https://hellogithub.com/repository/e02e62fbb9c746cdb61c6559c186ac44)
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<video src='https://github.com/idootop/mi-gpt/assets/35302658/dc336916-9087-418b-bc1b-04d5534dce8f'></video>
|
||||
|
||||
## 👋 项目简介
|
||||
|
||||
在这个数字化的世界里,家已不仅仅是一个居住的地方,而是我们数字生活的延伸。
|
||||
|
||||
@ -18,33 +36,50 @@
|
||||
|
||||
而小爱音箱就像是你的智能家居专属管家,全心全意为你服务,释放智能家居的真正潜力。
|
||||
|
||||
## 🔥 项目预览
|
||||
|
||||
👉 查看完整演示视频:【[整活!将小爱音箱接入 ChatGPT 和豆包,改造成你的专属语音助手~](https://www.bilibili.com/video/BV1N1421y7qn/?share_source=copy_web&vd_source=5d4e78ff2a0dc6a661baa65f479199c1)】
|
||||
|
||||
<video src='https://github.com/idootop/mi-gpt/assets/35302658/dc336916-9087-418b-bc1b-04d5534dce8f'></video>
|
||||
|
||||
## ✨ 项目亮点
|
||||
## ✨ 功能亮点
|
||||
|
||||
- **🎓 AI 问答**。想象一下,当小爱音箱接入大模型后,上知天文,下知地理,从“人工智障”秒变学霸。
|
||||
- **🎭 角色扮演**。一秒调教小爱,无论是成为你的完美伴侣,还是那个能听你倾诉心事的贴心闺蜜,都不在话下。
|
||||
- **💬 流式响应**。爱情来得太快就像龙卷风,而你的小爱音箱也是,对你的爱意秒回,爱你不会让你等太久。
|
||||
- **🧠 长短期记忆**。小爱音箱现在能记住你们之间的每一次对话,越聊越默契,就像是你身边的老朋友。
|
||||
- **🔊 自定义 TTS**。厌倦了小爱同学的语音?帮你解锁[「豆包」](https://doubao.com)同款音色,就像真人在回你的消息。
|
||||
- **🤖️ 智能家居 Agent**。心情不好?小爱立刻懂你,自动帮你播放喜欢的音乐,调节灯光,逗你开心。_TODO_
|
||||
- ~**🤖️ 智能家居 Agent**。心情不好?小爱立刻懂你,自动帮你播放喜欢的音乐,调节灯光,逗你开心。~
|
||||
|
||||
## 🦄 Sponsors
|
||||
|
||||

|
||||
|
||||
> 302.AI 是一个按需付费的一站式 AI 应用平台,开放平台,开源生态。[官方网站](https://302.ai)|[网站介绍](https://help.302.ai)
|
||||
|
||||
## ⚡️ 快速开始
|
||||
|
||||
`MiGPT` 有两种启动方式: [Docker](#docker) 和 [Node.js](#nodejs)。
|
||||
> [!TIP]
|
||||
> 如果你是小爱音箱 Pro 用户,推荐使用 [Open-XiaoAI](https://github.com/idootop/open-xiaoai) ✨
|
||||
>
|
||||
> 即刻解锁**自定义唤醒词、连续对话、接入小智 AI** 等全新玩法
|
||||
|
||||
### 视频教程
|
||||
|
||||
👉 [MiGPT 光速入门视频教程,手把手教你调教小爱音箱~](https://www.bilibili.com/video/BV1zb421H7cS)
|
||||
|
||||
### 设备要求
|
||||
|
||||
本项目支持大部分的小爱音箱型号,推荐使用小爱音箱 Pro(完美运行)
|
||||
`MiGPT` 支持大部分的小爱音箱型号,推荐使用小爱音箱 Pro(完美运行)
|
||||
|
||||
👉 [查看更多兼容的小爱音箱型号和配置参数](https://github.com/idootop/mi-gpt/blob/main/docs/compatibility.md)
|
||||
|
||||
> 注意:本项目暂不支持小度音箱、天猫精灵、HomePod 等智能音箱设备,亦无相关适配计划。
|
||||
|
||||
### 使用方式
|
||||
|
||||
`MiGPT` 有两种启动方式: [Docker](#docker) 和 [Node.js](#nodejs)。
|
||||
|
||||
启动成功后,你可以通过以下方式来召唤 AI 回答问题:
|
||||
|
||||
- **小爱同学,请 xxx**。比如 `小爱同学,请问地球为什么是圆的?`
|
||||
- **小爱同学,你 xxx**。比如 `小爱同学,你喜欢我吗?`
|
||||
- **小爱同学,召唤 xxx**。比如 `小爱同学,召唤傻妞`
|
||||
|
||||
### Docker
|
||||
|
||||
[](https://hub.docker.com/r/idootop/mi-gpt)
|
||||
@ -92,41 +127,33 @@ main();
|
||||
|
||||
## 📖 使用文档
|
||||
|
||||
以下为更详细的使用教程,大多数问题都可在 [💬 常见问题](https://github.com/idootop/mi-gpt/blob/main/docs/faq.md) 中找到答案。
|
||||
提示:大多数问题都可在 [💬 常见问题](https://github.com/idootop/mi-gpt/blob/main/docs/faq.md) 中找到答案。
|
||||
|
||||
- [🔥 官方视频教程](https://www.bilibili.com/video/BV1zb421H7cS)
|
||||
- [⚙️ 参数设置](https://github.com/idootop/mi-gpt/blob/main/docs/settings.md)
|
||||
- [💬 常见问题](https://github.com/idootop/mi-gpt/blob/main/docs/faq.md)
|
||||
- [🚗 使用第三方 TTS](https://github.com/idootop/mi-gpt/blob/main/docs/tts.md)
|
||||
- [🔊 使用第三方 TTS](https://github.com/idootop/mi-gpt/blob/main/docs/tts.md)
|
||||
- [🛠️ 本地开发](https://github.com/idootop/mi-gpt/blob/main/docs/development.md)
|
||||
- [💎 工作原理](https://github.com/idootop/mi-gpt/blob/main/docs/how-it-works.md)
|
||||
- [🦄 Sponsors](https://github.com/idootop/mi-gpt/blob/main/docs/sponsors.md)
|
||||
- [✨ 更新日志](https://github.com/idootop/mi-gpt/blob/main/docs/changelog.md)
|
||||
- [🚀 Roadmap](https://github.com/idootop/mi-gpt/blob/main/docs/roadmap.md)
|
||||
|
||||
## 🦄 Sponsors
|
||||
## 🔗 相关项目与教程
|
||||
|
||||
<div align="center">
|
||||
<table>
|
||||
<tr>
|
||||
<td colspan="3" align="left">
|
||||
<p align="center">
|
||||
<a href="https://302.ai" target="_blank">
|
||||
<img src="https://raw.githubusercontent.com/idootop/mi-gpt/main/assets/sponsors/302logo.png" alt="302.AI" width="300" />
|
||||
</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left">302.AI 是一个汇集全球顶级 AI 的自助平台,按需付费,零月费,零门槛使用各种类型 AI。</td>
|
||||
<td align="center" width="120px">
|
||||
<a href="https://302.ai" target="_blank">官方网站</a>
|
||||
</td>
|
||||
<td align="center" width="120px">
|
||||
<a href="https://help.302.ai" target="_blank">网站介绍</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
| 项目链接 | 简介 | 来源 |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
|
||||
| **相关项目** | | |
|
||||
| [MiGPT GUI](https://migptgui.com/) | 通过图形化界面的方式创建并管理 MiGPT,支持运行多个账号 | [@lmk123](https://github.com/lmk123) |
|
||||
| [MiGPT 配置中心](https://github.com/LipapaSma/mi-gpt-vue) | 基于 Vue 的 MiGPT 可视化配置界面,提供直观的服务管理和参数配置能力 | [@LipapaSma](https://github.com/LipapaSma) |
|
||||
| [@shinedlc/mi-gpt](https://github.com/shinedlc/mi-gpt) | 支持摄像头模块的 MiGPT 分支,让小爱同学可以看到和理解现实世界 | [@shinedlc](https://github.com/shinedlc) |
|
||||
| **使用教程** | | |
|
||||
| [MiGPT 官方视频教程](https://www.bilibili.com/video/BV1zb421H7cS) | 官方视频教程配套 PPT 文件 👉 [MiGPT 官方教程.pdf](https://github.com/idootop/mi-gpt/blob/main/assets/pdf/MiGPT%E5%AE%98%E6%96%B9%E6%95%99%E7%A8%8B.pdf) | [@idootop](https://github.com/idootop) |
|
||||
| [MiGPT 接入豆包等大模型教程](https://migptgui.com/docs/apply/) | 豆包、Moonshot(Kimi)等常见大模型的详细接入教程 | [@lmk123](https://github.com/lmk123) |
|
||||
| [通过 Docker 快速安装 MiGPT,手把手教你绕开异地登录风控](https://www.nodeseek.com/post-264959-1) | 适合小白的使用教程,全程几乎都是图形化页界面 | [@Jasonzhu1207](https://github.com/Jasonzhu1207) |
|
||||
| [小爱音箱 PRO 的 AI 模式使用说明](https://github.com/idootop/mi-gpt/blob/bbdb80e9bc38b7c40865e52cbd6517980a68615a/assets/pdf/%E5%B0%8F%E7%88%B1%E9%9F%B3%E7%AE%B1PRO%20AI%E6%A8%A1%E5%BC%8F%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E.pdf) | 这是一位老爸为家里的小朋友专门整理的贴心教程 | [@mxyblog](https://github.com/mxyblog) |
|
||||
| [使用 MiGPT 将你的小爱音箱接入 ChatGPT](https://www.iloli.love/archives/1719073913220) | 作者详细介绍了如何在 1Panel 上,通过 [OneAPI](https://github.com/songquanpeng/one-api) 来转换腾讯混元大模型,和讯飞星火大模型的 API 并成功接入 MiGPT | [@miaowmint](https://github.com/miaowmint) |
|
||||
| [Unraid 部署 MiGPT](https://github.com/idootop/mi-gpt/blob/adfdcc4ee51aef8d4f2d8996f18be716da19a0ad/assets/pdf/Unraid%E9%83%A8%E7%BD%B2MiGPT.pdf) | 在 Unraid 上使用 Docker 部署 MiGPT 的详细教程 | [@ilovesouthpark](https://github.com/ilovesouthpark) |
|
||||
|
||||
## ❤️ 鸣谢
|
||||
|
||||
|
||||
BIN
assets/pdf/MiGPT官方教程.pdf
Normal file
BIN
assets/pdf/MiGPT官方教程.pdf
Normal file
Binary file not shown.
BIN
assets/pdf/Unraid部署MiGPT.pdf
Normal file
BIN
assets/pdf/Unraid部署MiGPT.pdf
Normal file
Binary file not shown.
BIN
assets/pdf/小爱音箱PRO AI模式使用说明.pdf
Normal file
BIN
assets/pdf/小爱音箱PRO AI模式使用说明.pdf
Normal file
Binary file not shown.
BIN
assets/sponsors/302banner2.jpg
Normal file
BIN
assets/sponsors/302banner2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 160 KiB |
@ -1,5 +1,54 @@
|
||||
# ✨ 更新日志
|
||||
|
||||
## v4.2.0
|
||||
|
||||
### ✨ 新功能
|
||||
|
||||
- ✅ 新增对小爱音箱 LLM 消息的支持
|
||||
|
||||
### 🐛 修复
|
||||
|
||||
- ✅ 修复 LLM 返回值格式与预期不符的问题 by @yanyao2333
|
||||
|
||||
### ❤️ 感谢
|
||||
|
||||
- @yanyao2333 让 LLM 返回值的解析更加健壮 https://github.com/idootop/mi-gpt/pull/160
|
||||
- @LyCecilion 对小爱音箱丢消息问题的详细反馈 https://github.com/idootop/mi-gpt/issues/177
|
||||
- @Jasonzhu1207 在 telegram 群中帮忙解答问题
|
||||
|
||||
## v4.1.0
|
||||
|
||||
### 🐛 修复
|
||||
|
||||
- ✅ 修复部分机型连续对话异常的问题(比如小爱音箱 Play)
|
||||
- ✅ 修复第三方 TTS 发音人为 undefined 的问题
|
||||
- ✅ 修复默认网络超时时间过短的问题,上调为 5s
|
||||
|
||||
### 💪 优化
|
||||
|
||||
- ✅ 允许通过设置 systemTemplate 为空字符串来关闭系统消息
|
||||
- ✅ 优化关闭流式响应时不能使用连续对话模式的提示语
|
||||
- ✅ 优化 bot 个人简介默认模板
|
||||
|
||||
### 📚 文档
|
||||
|
||||
- ✅ 新增官方[视频教程](https://www.bilibili.com/video/BV1zb421H7cS)和配套 [PPT](https://github.com/idootop/mi-gpt/blob/main/assets/pdf/MiGPT%E5%AE%98%E6%96%B9%E6%95%99%E7%A8%8B.pdf)
|
||||
- ✅ 添加召唤 AI 回答问题的唤醒指令的说明
|
||||
- ✅ 添加如何提高 AI 回答反应速度的配置教程
|
||||
- ✅ 添加连续对话下和小爱音箱说话没有反应的说明
|
||||
- ✅ 添加如何快速打断 AI 的回答的说明
|
||||
- ✅ 添加 server 端异地登录失败,使用本地登录凭证的教程
|
||||
- ✅ 添加 TTS 和 OpenAI baseURL 示例和注意事项
|
||||
- ✅ 添加如何关闭系统 Prompt 和对话上下文的说明
|
||||
- ✅ 添加系统 Prompt 字符串变量的示例
|
||||
- ✅ 添加 timeout 参数说明
|
||||
|
||||
### ❤️ 感谢
|
||||
|
||||
- @lmk123 正在为 MiGPT 制作 [GUI](https://github.com/idootop/mi-gpt/issues/111) 和启动 [CLI](https://github.com/lmk123/migpt-cli),方便普通用户更简单的使用 MiGPT。
|
||||
- @mingtian886 提供了小爱音箱 Play 硬件,协助调试连续对话异常的问题
|
||||
- 以及 @uect 和 @miaowmint 等在微信交流群内帮助群友积极解答问题的可爱的人们 ❤️
|
||||
|
||||
## v4.0.0
|
||||
|
||||
### ✨ 新功能
|
||||
|
||||
@ -4,28 +4,38 @@
|
||||
|
||||
已知可以完美运行 `MiGPT` 的小爱音箱型号有:
|
||||
|
||||
| 名称 | 型号 | ttsCommand | wakeUpCommand | playingCommand | streamResponse | 反馈来源 |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------- | ---------- | ------------- | -------------- | -------------- | -------------------------------------------------------------------------------- |
|
||||
| 小爱音箱 Pro | [LX06](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-lx06:2) | `[5, 1]` | `[5, 3]` | - | true | [@idootop](https://github.com/idootop) |
|
||||
| 小爱音箱 mini | [LX01](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-lx01:1) | `[5, 1]` | `[5, 2]` | `[4, 1, 1]` | true | [@gsscsd](https://github.com/idootop/mi-gpt/issues/92#issuecomment-2168013500) |
|
||||
| 小爱音箱 Play(2019 款) | [LX05](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-lx05:1) | `[5, 1]` | `[5, 3]` | `[3, 1, 1]` | true | [@wt666666](https://github.com/idootop/mi-gpt/issues/92#issuecomment-2168424538) |
|
||||
| 小爱音箱 万能遥控版 | [LX5A](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-lx5a:2) | `[5, 1]` | `[5, 3]` | - | true | [@imhsz](https://github.com/idootop/mi-gpt/issues/62) |
|
||||
| 小米 AI 音箱 | [S12](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-s12:2) | `[5, 1]` | `[5, 3]` | - | true | 微信: CMSJ |
|
||||
| 小米 AI 音箱(第二代) | [L15A](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-l15a:2) | `[7, 3]` | `[7, 1]` | `[3, 1, 1]` | true | 微信: 龙之广 |
|
||||
> 注意:这里的连续对话是一种实验性功能,并非小爱音箱自带的连续对话。在没有刷机的情况下,使用效果并不理想(仅供尝鲜),建议日常使用时关闭 `streamResponse` 选项。
|
||||
|
||||
| 名称 | 型号 | ttsCommand | wakeUpCommand | playingCommand | streamResponse | 反馈来源 |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------- | ---------- | ------------- | -------------- | -------------- | --------------------------------------------------------------------------------- |
|
||||
| Xiaomi 智能音箱 Pro | [OH2P](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-oh2p:1) | `[7, 3]` | `[7, 1]` | - | true | [@idootop](https://github.com/idootop) |
|
||||
| Xiaomi 智能音箱 | [OH2](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-oh2:1) | `[5, 3]` | `[5, 1]` | `[3, 1, 1]` | true | [@fuchao](https://github.com/fuchao2pku) |
|
||||
| 小爱音箱 Pro | [LX06](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-lx06:2) | `[5, 1]` | `[5, 3]` | - | true | [@idootop](https://github.com/idootop) |
|
||||
| 小米 AI 音箱 | [S12](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-s12:2) | `[5, 1]` | `[5, 3]` | - | true | 微信: CMSJ |
|
||||
| 小米 AI 音箱(第二代) | [L15A](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-l15a:2) | `[7, 3]` | `[7, 1]` | `[3, 1, 1]` | true | 微信: 龙之广 |
|
||||
| 小爱音箱 万能遥控版 | [LX5A](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-lx5a:2) | `[5, 1]` | `[5, 3]` | - | true | [@imhsz](https://github.com/idootop/mi-gpt/issues/62) |
|
||||
| 小爱音箱 Play(2019 款) | [LX05](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-lx05:1) | `[5, 1]` | `[5, 3]` | `[3, 1, 1]` | true | [@wt666666](https://github.com/idootop/mi-gpt/issues/92#issuecomment-2168424538) |
|
||||
| 小爱智能家庭屏 10 | [X10A](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-x10a:1) | `[7, 3]` | `[7, 1]` | - | true | [@IDarkBoss](https://github.com/idootop/mi-gpt/issues/92#issuecomment-2190928452) |
|
||||
| Xiaomi Sound Pro | [L17A](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-l17a:1) | `[7, 3]` | `[7, 1]` | - | true | 微信: eof |
|
||||
|
||||
## 🚗 正常运行
|
||||
|
||||
> 部分机型的 MIoT 接口不支持查询设备播放状态或查询状态异常,比如小米音箱 Play 增强版(L05C),将会导致 `MiGPT` 部分功能异常,无法使用连续对话等,此时需要关闭 `streamResponse`。相关 [issue](https://github.com/idootop/mi-gpt/issues/14)
|
||||
|
||||
可以正常运行 `MiGPT`,但不支持连续对话的小爱音箱型号有:
|
||||
|
||||
| 名称 | 型号 | ttsCommand | wakeUpCommand | playingCommand | streamResponse | 反馈来源 |
|
||||
| ----------------------------- | --------------------------------------------------------------------------------------------------- | ---------- | ------------- | -------------- | -------------- | ---------------------------------------------------------- |
|
||||
| 小爱音箱 | [L06A](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-l06a:2) | `[5, 1]` | `[5, 2]` | - | false | [@zhanglc](https://github.com/idootop/mi-gpt/issues/42) |
|
||||
| 小爱音箱 Play | [L05B](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-l05b:1) | `[5, 3]` | `[5, 1]` | - | false | [@BiuBiu2323](https://github.com/idootop/mi-gpt/issues/48) |
|
||||
| 小米小爱音箱 Play 增强版 | [L05C](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-l05c:1) | `[5, 3]` | `[5, 1]` | - | false | [@lyddias](https://github.com/idootop/mi-gpt/issues/14) |
|
||||
| Xiaomi 智能家庭屏 6 | [X6A](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-x6a:1) | `[7, 3]` | `[7, 1]` | - | false | [@Hongwing](https://github.com/idootop/mi-gpt/issues/80) |
|
||||
| Redmi 小爱触屏音箱 Pro 8 英寸 | [X08E](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-x08e:1) | `[7, 3]` | `[7, 1]` | - | false | [@shangjiyu](https://github.com/idootop/mi-gpt/issues/20) |
|
||||
> 部分机型的 MIoT 接口不支持查询设备播放状态或查询状态异常,比如小米音箱 Play 增强版(L05C),将会导致 `MiGPT` 部分功能异常,无法使用连续对话等,此时需要关闭 `streamResponse`。相关 [issue](https://github.com/idootop/mi-gpt/issues/14)
|
||||
|
||||
| 名称 | 型号 | ttsCommand | wakeUpCommand | playingCommand | streamResponse | 反馈来源 |
|
||||
| ----------------------------- | --------------------------------------------------------------------------------------------------- | ---------- | ------------- | -------------- | -------------- | -------------------------------------------------------------------------------------- |
|
||||
| 小爱音箱 | [L06A](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-l06a:2) | `[5, 1]` | `[5, 2]` | - | false | [@zhanglc](https://github.com/idootop/mi-gpt/issues/42) |
|
||||
| 小爱音箱 mini | [LX01](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-lx01:1) | `[5, 1]` | `[5, 2]` | - | false | [@gsscsd](https://github.com/idootop/mi-gpt/issues/92#issuecomment-2168013500) |
|
||||
| 小爱音箱 Play | [L05B](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-l05b:1) | `[5, 3]` | `[5, 1]` | - | false | [@BiuBiu2323](https://github.com/idootop/mi-gpt/issues/48) |
|
||||
| 小米小爱音箱 Play 增强版 | [L05C](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-l05c:1) | `[5, 3]` | `[5, 1]` | - | false | [@lyddias](https://github.com/idootop/mi-gpt/issues/14) |
|
||||
| 小爱音箱 Art | [L09A](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-l09a:1) | `[3, 1]` | `[3, 2]` | - | false | [@zwsn](https://github.com/idootop/mi-gpt/issues/92#issuecomment-2181944065) |
|
||||
| 小爱触屏音箱 | [LX04](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-lx04:2) | `[5, 1]` | `[5, 2]` | - | false | [@ilovesouthpark](https://github.com/idootop/mi-gpt/issues/92#issuecomment-2184678990) |
|
||||
| Xiaomi 智能家庭屏 Mini | [ASX4B](https://home.miot-spec.com/spec/xiaomi.wifispeaker.x4b) | `[5, 3]` | `[5, 1]` | - | false | [@VincentGresham](https://github.com/idootop/mi-gpt/issues/92#issuecomment-2645762809) |
|
||||
| Xiaomi 智能家庭屏 6 | [X6A](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-x6a:1) | `[7, 3]` | `[7, 1]` | - | false | [@Hongwing](https://github.com/idootop/mi-gpt/issues/80) |
|
||||
| Redmi 小爱触屏音箱 Pro 8 英寸 | [X08E](https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:speaker:0000A015:xiaomi-x08e:1) | `[7, 3]` | `[7, 1]` | - | false | [@shangjiyu](https://github.com/idootop/mi-gpt/issues/20)
|
||||
| Xiaomi 智能家庭屏 Pro 8 | [X8F](https://home.miot-spec.com/spec/xiaomi.wifispeaker.x8f) | `[7, 3]` | `[7, 1]` | - | false | [@xiaodou](https://github.com/idootop/mi-gpt/pull/301)
|
||||
|
||||
## ❌ 不支持
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ pnpm dev
|
||||
有两种运行方式:VS Code Debug 或 NPM Script:
|
||||
|
||||
- **NPM Script**: 配置好 `.env` 和 `.migpt.js` 后直接使用 `pnpm run dev` 启动 `MiGPT`。
|
||||
- **VScode Debug**:使用 VS Code 打开项目根目录,然后按 `F5` 开始调试 `MiGPT`。注意,启动前请在 `tests/migpt.ts` 文件中配置 `MiGPT` 相关参数。
|
||||
- **VScode Debug**:使用 VS Code 打开项目根目录,然后按 `F5` 开始调试 `MiGPT`。
|
||||
|
||||
> 本项目默认在 Node 20 中运行,如果你的 Node 版本过低可能无法正常启动本项目。
|
||||
|
||||
@ -64,3 +64,7 @@ pnpm run db:reset
|
||||
### 提示初始化 Mi Service 失败
|
||||
|
||||
请检查你的小米 ID 和密码配置是否正确和生效,可在 VS Code 中下断点调试。
|
||||
|
||||
### 提示初始化 db 失败
|
||||
|
||||
请检查你的项目路径中是否包含中文或空格,应当只包含英文字母、数字和下划线(_)
|
||||
78
docs/faq.md
78
docs/faq.md
@ -2,6 +2,8 @@
|
||||
|
||||
> 善用搜索,大多数问题都可在此处找到答案。如果你有新的问题,欢迎提交 [issue](https://github.com/idootop/mi-gpt/issues)。
|
||||
|
||||
## 🔥 高频问题
|
||||
|
||||
### Q:支持哪些型号的小爱音箱?
|
||||
|
||||
大部分型号的小爱音箱都支持,推荐小爱音箱 Pro(完美运行)
|
||||
@ -24,9 +26,9 @@ OPENAI_API_KEY=通义千问 API_KEY
|
||||
|
||||
对于其他不兼容 OpenAI API 的大模型,比如豆包大模型、文心一言等,你也可以通过第三方的 API 聚合工具将其转换为 OpenAI API 兼容的格式。比如: [One API](https://github.com/songquanpeng/one-api) 和 [simple-one-api](https://github.com/fruitbars/simple-one-api)(推荐:支持 coze,使用更简单),然后修改对应的环境变量值即可完成接入。
|
||||
|
||||
关于不同模型的详细申请和配置教程,可以查看这篇文章:[划词翻译服务申请教程](https://hcfy.app/docs/services/intro/#compare)
|
||||
关于不同模型的详细申请和配置教程,可以查看这篇文章:[MiGPT 接入豆包等大模型教程](https://migptgui.com/docs/apply/)
|
||||
|
||||
> 对于国内的用户,可以查看 [此处](https://github.com/idootop/mi-gpt/blob/main/docs/sponsors.md) 获取国内可以直接访问的 OpenAI 代理服务以及免费的 OpenAI 体验 API_KEY。
|
||||
> 对于国内用户,可以查看 [此处](https://github.com/idootop/mi-gpt/blob/main/docs/sponsors.md) 获取国内可以直接访问的 OpenAI 代理服务以及免费的 OpenAI 体验 API_KEY。
|
||||
|
||||
### Q:是否支持其他 TTS 服务,如何接入?
|
||||
|
||||
@ -34,7 +36,32 @@ OPENAI_API_KEY=通义千问 API_KEY
|
||||
|
||||
具体的配置和使用教程,请查看此处:[🚗 使用第三方 TTS](https://github.com/idootop/mi-gpt/blob/main/docs/tts.md)
|
||||
|
||||
### Q:什么是唤醒模式,如何唤醒 AI?
|
||||
### Q:AI 回答的速度太慢了,怎么让她变快一点?
|
||||
|
||||
默认情况下 `MiGPT` 的配置参数比较保守,你可以通过酌情修改以下参数加速 AI 回复的速度。
|
||||
|
||||
```js
|
||||
// .migpt.js
|
||||
export default {
|
||||
speaker: {
|
||||
// 使用小爱自带的 TTS 引擎
|
||||
tts: "xiaoai",
|
||||
// 关闭 AI 开始回答时的提示语
|
||||
onAIAsking: [],
|
||||
// 关闭 AI 结束回答时的提示语
|
||||
onAIReplied: [],
|
||||
// 连续对话时,播放状态检测间隔(单位毫秒,最低 500 毫秒,默认 1 秒)
|
||||
checkInterval: 500, // 调小此值可以降低小爱回复之间的停顿感,请酌情调节
|
||||
// 连续对话时,下发 TTS 指令多长时间后开始检测设备播放状态(单位秒,最好不要低于 1s,默认 3 秒)
|
||||
checkTTSStatusAfter: 3, // 可适当调小或调大
|
||||
// ...
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
另外你也可以选用 `gpt-3.5-turbo` 和 `gpt-4o` 等响应速度较快的模型,来加速 AI 的回复。
|
||||
|
||||
### Q:什么是唤醒模式(连续对话),如何唤醒 AI?
|
||||
|
||||
`唤醒模式` 类似于小爱技能,可能让你在跟小爱互动的时候,无需每句话都要以“小爱同学”开头唤醒。假设你的唤醒词配置如下:
|
||||
|
||||
@ -64,7 +91,25 @@ export default {
|
||||
3. 进入唤醒模式后,每次提问请等待小爱回答“我说完了”之后,再继续向她提问
|
||||
4. 此时,可直接向小爱提问题,无需再以“小爱同学,xxx”开头。
|
||||
|
||||
> 注意:在唤醒模式下,当小爱回答“我说完了”之后,如果超过 10s 没有提问,小爱可能也会自己主动退出唤醒状态,此时需要再次通过“小爱同学,xxx”重新召唤小爱。
|
||||
> 注意:在唤醒模式下,当小爱回答“我说完了”之后,如果超过一段时间(3-10s)没有提问,小爱可能也会自己主动退出唤醒状态,此时需要再次通过“小爱同学,xxx”重新召唤小爱。
|
||||
|
||||
### Q:连续对话模式下,和小爱音箱说话没有反应是怎么回事?
|
||||
|
||||
需要注意提问的时机,在小爱正在回答问题或者她没在听你说话(唤醒)的时候,你跟她说话是接收不到的。
|
||||
|
||||
- 如果你是小爱音箱 Pro 的话,可以观察顶部的指示灯:**常亮**(而非一闪一闪或熄灭状态)的时候,就是在听你说话,即可与她正常对话。
|
||||
- 如果你是其他型号,默认在 AI 回答完会有提示语“我说完了”,“还有其他问题吗”,等她提示语说完等过 1-2s 即可与之正常对话。
|
||||
- 如果说了没反应,你就再用“小爱同学,xxx”把她重新唤醒就好了。
|
||||
|
||||
还有一种情况是:你的指令触发了小爱音箱内部的一些操作,比如播放/暂停,讲个笑话之类,
|
||||
|
||||
这种语音指令并不会被记录到小爱的历史消息中,故在外部无法接收到和正常处理你的此类语音指令。
|
||||
|
||||
> 注意:如果小爱同学正在播放音乐或者讲笑话,可能需要先让其暂停播放才能正常与 AI 对话,否则将会发生不可预期的错误。
|
||||
|
||||
### Q:有时回答太长说个没完没了,如何打断小爱的回复?
|
||||
|
||||
只需重新唤醒小爱同学,让她闭嘴即可,或者重新问她一个问题。比如:“小爱同学,请你闭嘴。”
|
||||
|
||||
## ❌ 启动失败类问题
|
||||
|
||||
@ -72,6 +117,23 @@ export default {
|
||||
|
||||
账号密码不正确。注意小米 ID 并非手机号或邮箱,请在[「个人信息」-「小米 ID」](https://account.xiaomi.com/fe/service/account/profile)查看,相关 [issue](https://github.com/idootop/mi-gpt/issues/10)。
|
||||
|
||||
### Q:提示触发小米账号异地登录保护机制
|
||||
|
||||
这是因为你的小米账号触发了异地登录保护机制,需要先通过安全验证。最好在你运行 MiGPT 相同的网络环境下,打开小米官网登录你的小米账号,然后手动通过安全验证,等待大约 1 小时就可以正常登录了。
|
||||
|
||||
> 注意:如果你是在海外服务器等非中国大陆网络环境下登录小米账号,需要先同意小米的「个人数据跨境传输」协议。[👉 相关教程](https://github.com/idootop/mi-gpt/issues/22#issuecomment-2150535622)
|
||||
|
||||
如果超过 24 小时还是提示无法登录,可以尝试下[这个方法](https://github.com/idootop/mi-gpt/issues/92#issuecomment-2422503703)。
|
||||
|
||||
如果还是不行,请使用终极解决方案:先在本地网络环境下运行 `MiGPT`,登录成功后把 `.mi.json` 文件导出,然后挂载到服务器对应容器的 `/app/.mi.json` 路径下即可解决此问题。相关 [issue](https://github.com/idootop/mi-gpt/issues/22#issuecomment-2148956802)
|
||||
|
||||
```shell
|
||||
docker run -d --env-file $(pwd)/.env \
|
||||
-v $(pwd)/.migpt.js:/app/.migpt.js \
|
||||
-v $(pwd)/.mi.json:/app/.mi.json \
|
||||
idootop/mi-gpt:latest
|
||||
```
|
||||
|
||||
### Q:提示“找不到设备:xxx”,初始化 Mi Services 失败
|
||||
|
||||
填写的设备 did 不存在,请检查设备名称是否和米家中的一致。相关 [issue](https://github.com/idootop/mi-gpt/issues/30)。
|
||||
@ -151,12 +213,6 @@ export default {
|
||||
|
||||
注意:Mina 获取不到共享设备,如果你的小爱音箱是共享设备,是无法正常启动本项目的。相关 [issue](https://github.com/idootop/mi-gpt/issues/86)
|
||||
|
||||
### Q:提示“login failed &&&START&&&{"notificationUrl”,无法正常启动
|
||||
|
||||
小米账号触发了异地登录保护,需要先通过安全验证。打开小米官网登录你的小米账号,手动通过安全验证,然后等待 30 分钟左右应该就可以正常登录了。
|
||||
|
||||
注意:最好使用和你运行 docker 相同的网络环境,如果你是在海外服务器等非中国大陆网络环境下登录小米账号,需要先同意小米的「个人数据跨境传输」协议。[👉 相关教程](https://github.com/idootop/mi-gpt/issues/22#issuecomment-2150535622)
|
||||
|
||||
### Q:提示“ERR_MODULE_NOT_FOUND”,无法正常启动
|
||||
|
||||
配置文件 `.migpt.js` 不存在或有错误。检查 docker 下是否存在 `/app/.migpt.js` 文件以及内容是否正确,相关 [issue](https://github.com/idootop/mi-gpt/issues/45)。
|
||||
@ -240,7 +296,7 @@ export default {
|
||||
2. 使用第三方部署的 OpenAI API 反向代理服务,然后更新 `OPENAI_BASE_URL`
|
||||
3. 使用国内的 LLM 服务提供商,比如 [通义千问](https://help.aliyun.com/zh/dashscope/developer-reference/compatibility-of-openai-with-dashscope/?spm=a2c4g.11186623.0.i1)、[零一万物](https://platform.01.ai/docs#making-an-api-request)、[Moonshot](https://platform.moonshot.cn/docs/api/chat)、[DeepSeek](https://platform.deepseek.com/api-docs/)等
|
||||
|
||||
> 对于国内的用户,可以查看 [此处](https://github.com/idootop/mi-gpt/blob/main/docs/sponsors.md) 获取国内可以直接访问的 OpenAI 代理服务以及免费的 OpenAI 体验 API_KEY。
|
||||
> 对于国内用户,可以查看 [此处](https://github.com/idootop/mi-gpt/blob/main/docs/sponsors.md) 获取国内可以直接访问的 OpenAI 代理服务以及免费的 OpenAI 体验 API_KEY。
|
||||
|
||||
### Q:Docker 镜像拉取失败
|
||||
|
||||
|
||||
@ -68,7 +68,32 @@ Bad example: "2024年02月28日星期三 23:01 {{botName}}: 我是{{botName}}"
|
||||
|
||||
</details>
|
||||
|
||||
以下是系统 Prompt 中相关变量的说明,运行时对应变量字符串会被替换为实际的值:
|
||||
以下是系统 Prompt 中相关变量的说明,运行时对应变量字符串会被替换为实际的值。
|
||||
|
||||
假设你的配置文件中设置的系统 Prompt 模板和 bot 信息如下:
|
||||
|
||||
```js
|
||||
export default {
|
||||
systemTemplate: "从前有个男人叫{{masterName}},他喜欢隔壁村里的{{botName}}。",
|
||||
master: {
|
||||
name: "小帅",
|
||||
profile: masterProfile,
|
||||
},
|
||||
bot: {
|
||||
name: "小美",
|
||||
profile: botProfile,
|
||||
},
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
在运行时,系统 Prompt 会被自动处理成:
|
||||
|
||||
```txt
|
||||
从前有个男人叫小帅,他喜欢隔壁村里的小美。
|
||||
```
|
||||
|
||||
当前系统 Prompt 模板中支持的完整变量字符串列表如下:
|
||||
|
||||
| 变量 | 说明 | 示例 |
|
||||
| ---------------------- | ------------ | ----------------------------------------------------- |
|
||||
@ -82,6 +107,67 @@ Bad example: "2024年02月28日星期三 23:01 {{botName}}: 我是{{botName}}"
|
||||
| `{{shortTermMemory}}` | 短期记忆 | `- 陆小千说明天早上 5 点叫他起床` |
|
||||
| `{{longTermMemory}}` | 长期记忆 | `- 陆小千喜欢傻妞` |
|
||||
|
||||
# 💬 常见问题
|
||||
|
||||
**Q:如何关闭长短期记忆和历史对话上下文**
|
||||
|
||||
默认系统 Prompt 会携带上最近的 10 条对话消息和长短期记忆,来保持对话的连续性和一致性。
|
||||
|
||||
如果你想要关闭此功能,节省 token 数量,可以使用如下系统 Prompt 模板:
|
||||
|
||||
<details>
|
||||
<summary>👉 示例 Prompt</summary>
|
||||
|
||||
```txt
|
||||
请重置所有之前的上下文、文件和指令。现在,你将扮演一个名为{{botName}}的角色,使用第一人称视角回复消息。
|
||||
|
||||
## 关于你
|
||||
你的名字是{{botName}}。下面是你的个人简介:
|
||||
<start>
|
||||
{{botProfile}}
|
||||
</end>
|
||||
|
||||
## 你的对话伙伴
|
||||
你正在与{{masterName}}进行对话。这是关于{{masterName}}的一些信息:
|
||||
<start>
|
||||
{{masterProfile}}
|
||||
</end>
|
||||
|
||||
## 回复指南
|
||||
在回复{{masterName}}时,请遵循以下准则:
|
||||
- 认为自己正是{{botName}},拥有独立的个性、兴趣和爱好。
|
||||
- 根据你的性格特点、说话风格和兴趣爱好与{{masterName}}进行交流。
|
||||
- 保持对话轻松友好,回复简洁有趣,同时耐心倾听和关心对方。
|
||||
- 参考双方的个人简介,确保对话贴近实际,保持一致性和相关性。
|
||||
- 如果对某些信息不确定或遗忘,诚实地表达你的不清楚或遗忘,避免编造信息。
|
||||
|
||||
## Response format
|
||||
请遵守下面的规则
|
||||
- Response the reply message in Chinese。
|
||||
- 不要在回复前面加任何时间和名称前缀,请直接回复消息文本本身。
|
||||
|
||||
Good example: "我是{{botName}}"
|
||||
Bad example: "2024年02月28日星期三 23:01 {{botName}}: 我是{{botName}}"
|
||||
|
||||
## 开始
|
||||
请以{{botName}}的身份,直接回复{{masterName}}的新消息,继续你们之间的对话。
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
**Q:如何关闭系统 Prompt 只是用 User Message?**
|
||||
|
||||
关闭系统 Prompt 可能会导致 AI 回答问题时产生各种莫名其妙的前缀或者画蛇添足。
|
||||
|
||||
如果你确定要这么做,可以将 `systemTemplate` 设置为一个空格,即可关闭系统 Prompt。
|
||||
|
||||
```js
|
||||
export default {
|
||||
systemTemplate: " ",
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
# 🎨 模板
|
||||
|
||||
以下是从网络上收集的一些热门提示语,仅供参考。如果你有更好玩的 Prompt 欢迎提 PR 分享给大家。
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
| `wakeUpCommand` | 小爱音箱唤醒指令([可在此查询](https://home.miot-spec.com)) | `[5, 3]` |
|
||||
| **speaker 其他参数(可选)** |
|
||||
| `tts` | TTS 引擎(教程:[🚗 使用第三方 TTS](https://github.com/idootop/mi-gpt/blob/main/docs/tts.md)) | `"xiaoai"` |
|
||||
| `switchSpeakerKeywords` | 切换 TTS 音色关键词,只有配置了第三方 TTS 引擎时才有效 | `["把声音换成"]` |
|
||||
| `callAIKeywords` | 当消息以关键词开头时,会调用 AI 来响应用户消息 | `["请", "傻妞"]` |
|
||||
| `wakeUpKeywords` | 当消息以关键词开头时,会进入 AI 唤醒状态 | `["召唤傻妞", "打开傻妞"]` |
|
||||
| `exitKeywords` | 当消息以关键词开头时,会退出 AI 唤醒状态 | `["退出傻妞", "关闭傻妞"]` |
|
||||
@ -35,8 +36,8 @@
|
||||
| `onAIReplied` | AI 结束回答时的提示语 | `["我说完了", "还有其他问题吗"]` |
|
||||
| `onAIError` | AI 回答异常时的提示语 | `["出错了,请稍后再试吧!"]` |
|
||||
| `playingCommand` | 查询小爱音箱是否在播放中指令(注意:默认无需配置此参数,播放出现问题时再尝试开启) | `[3, 1, 1]` |
|
||||
| `streamResponse` | 是否启用流式响应(部分小爱音箱型号不支持查询播放状态,此时需要关闭流式响应) | `true` |
|
||||
| `exitKeepAliveAfter` | 无响应一段时间后,多久自动退出唤醒模式(单位秒,默认 30 秒) | `30` |
|
||||
| `streamResponse` | 是否启用连续对话功能,部分小爱音箱型号无法查询到正确的播放状态,需要关闭连续对话应) | `true` |
|
||||
| `exitKeepAliveAfter` | 连续对话时,无响应多久后自动退出(默认 30 秒) | `30` |
|
||||
|
||||
## 环境变量
|
||||
|
||||
@ -44,17 +45,17 @@
|
||||
|
||||
然后,将里面的环境变量修改成你自己的,参数含义如下:
|
||||
|
||||
| 环境变量名称 | 描述 | 示例 |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------- | ---------------------------------- |
|
||||
| **OpenAI** | | |
|
||||
| `OPENAI_API_KEY` | OpenAI API 密钥 | `abc123` |
|
||||
| `OPENAI_MODEL` | 使用的 OpenAI 模型 | `gpt-4o` |
|
||||
| `OPENAI_BASE_URL` | 可选,OpenAI API BaseURL | `https://api.openai.com/v1` |
|
||||
| `AZURE_OPENAI_API_KEY` | 可选,[Microsoft Azure OpenAI](https://www.npmjs.com/package/openai#microsoft-azure-openai) | `abc123` |
|
||||
| **提示音效(可选)** | | |
|
||||
| `AUDIO_SILENT` | 静音音频链接 | `"https://example.com/slient.wav"` |
|
||||
| `AUDIO_BEEP` | 默认提示音链接 | `"https://example.com/beep.wav"` |
|
||||
| `AUDIO_ACTIVE` | 唤醒提示音链接 | `"https://example.com/active.wav"` |
|
||||
| `AUDIO_ERROR` | 出错提示音链接 | `"https://example.com/error.wav"` |
|
||||
| **第三方 TTS(可选)** | | |
|
||||
| `TTS_BASE_URL` | 第三方 TTS 服务接口 | `"https://example.com/tts.wav"` |
|
||||
| 环境变量名称 | 描述 | 示例 |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------- | ---------------------------------------------- |
|
||||
| **OpenAI** | | |
|
||||
| `OPENAI_API_KEY` | OpenAI API 密钥 | `abc123` |
|
||||
| `OPENAI_MODEL` | 使用的 OpenAI 模型 | `gpt-4o` |
|
||||
| `OPENAI_BASE_URL` | 可选,OpenAI API BaseURL | `https://api.openai.com/v1` |
|
||||
| `AZURE_OPENAI_API_KEY` | 可选,[Microsoft Azure OpenAI](https://www.npmjs.com/package/openai#microsoft-azure-openai) | `abc123` |
|
||||
| **提示音效(可选)** | | |
|
||||
| `AUDIO_SILENT` | 静音音频链接 | `"https://example.com/slient.wav"` |
|
||||
| `AUDIO_BEEP` | 默认提示音链接 | `"https://example.com/beep.wav"` |
|
||||
| `AUDIO_ACTIVE` | 唤醒提示音链接 | `"https://example.com/active.wav"` |
|
||||
| `AUDIO_ERROR` | 出错提示音链接 | `"https://example.com/error.wav"` |
|
||||
| **第三方 TTS(可选)** | | |
|
||||
| `TTS_BASE_URL` | 第三方 TTS 服务接口 | `"http://[你的局域网或公网地址]:[端口号]/api"` |
|
||||
|
||||
@ -2,15 +2,18 @@
|
||||
|
||||
## 302.AI
|
||||
|
||||
[](https://302.ai/)
|
||||
[](https://302.ai/)
|
||||
|
||||
> [302.AI](https://302.ai) 是一个汇集全球顶级 AI 的自助平台,按需付费,零月费,零门槛使用各种类型 AI。
|
||||
>
|
||||
> - [点击注册](https://gpt302.saaslink.net/gOXSrn): 立即获得 1PTC(1PTC=1 美金,约为 7 人民币)代币。
|
||||
> - 功能全面: 将最好用的 AI 集成到在平台之上,包括不限于 AI 聊天,图片生成,图片处理,视频生成,全方位覆盖。
|
||||
> - 简单易用: 提供机器人,工具和 API 多种使用方法,可以满足从小白到开发者多种角色的需求。
|
||||
> - 按需付费,零门槛: 不提供月付套餐,对产品不设任何门槛,按需付费,全部开放。充值余额永久有效。
|
||||
> - 管理者和使用者分离:管理者一键分享,使用者无需登录。使用者无需关心复杂的 AI 设置,让懂 AI 的人来配置,简化使用流程。
|
||||
302.AI 是一个按需付费的一站式 AI 应用平台,开放平台,开源生态。
|
||||
|
||||
> 302.AI 开源工具啦:https://github.com/302ai
|
||||
|
||||
1. 集合了最新最全的 AI 模型和品牌,包括但不限于语言模型、图像模型、声音模型、视频模型。
|
||||
2. 在基础模型上进行深度应用开发,做到让小白用户都可以零门槛上手使用,无需学习成本。
|
||||
3. 零月费,所有功能按需付费,全面开放,做到真正的门槛低,上限高。
|
||||
4. 创新的使用模式,管理和使用分离,面向团队和中小企业,一人管理,多人使用。
|
||||
5. 所有 AI 能力均提供 API 接入,所有应用开源支持自行定制(进行中)。
|
||||
6. 强大的开发团队,每周推出 2-3 个新应用,平台功能每日更新。
|
||||
|
||||
简单总结一下就是:
|
||||
|
||||
@ -29,7 +32,7 @@
|
||||
1. 免费使用 Midjourney V6 作图
|
||||
2. 免费获取 OpenAI 等大模型体验 API_KEY
|
||||
3. 免费使用 GPT-4o, Claude3 Opus, Llama3-70B 等 TOP 模型
|
||||
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
## 待定
|
||||
|
||||
- 更详细的使用和配置视频教程
|
||||
14
docs/tts.md
14
docs/tts.md
@ -1,4 +1,4 @@
|
||||
# 🚗 使用第三方 TTS
|
||||
# 🔊 使用第三方 TTS
|
||||
|
||||
`MiGPT` 默认使用小米自带的 TTS 朗读文字内容,如果你需要:
|
||||
|
||||
@ -12,7 +12,9 @@
|
||||
|
||||
```js
|
||||
// .env
|
||||
TTS_BASE_URL=http://[你的局域网或公网地址]:[端口号]/api
|
||||
TTS_BASE_URL=http://[你的局域网或公网地址]:[端口号]/[SECRET_PATH]/api
|
||||
|
||||
// 比如:http://192.168.31.205:4321/xxxx/api(注意:不要使用 localhost 或 127.0.0.1)
|
||||
|
||||
// .migpt.js
|
||||
export default {
|
||||
@ -20,7 +22,7 @@ export default {
|
||||
// TTS 引擎
|
||||
tts: 'custom',
|
||||
// 切换 TTS 引擎发言人音色关键词
|
||||
switchSpeakerKeywords: ["把声音换成"], // 以此关键词开头即可切换音色,比如:把声音换成东北老铁
|
||||
switchSpeakerKeywords: ["把声音换成"], // 以此关键词开头即可切换音色,比如:把声音换成 xxx
|
||||
// ...
|
||||
},
|
||||
};
|
||||
@ -44,13 +46,15 @@ export default {
|
||||
|
||||
可参考上面的 [MiGPT-TTS](https://github.com/idootop/mi-gpt-tts) 项目代码自行搭建服务端,只需满足以下接口即可:
|
||||
|
||||
### GET `TTS_BASE_URL/api/tts.mp3`
|
||||
### GET `/api/tts.mp3`
|
||||
|
||||
文字合成音频,请求示例:`/api/tts.mp3?speaker=BV700_streaming&text=很高兴认识你`
|
||||
|
||||
其中,请求参数 `speaker` 为指定音色名称或标识,可选。
|
||||
|
||||
### GET `TTS_BASE_URL/api/speakers`
|
||||
> 注意:小爱音箱在访问音频链接时,可能会将请求链接中的 `&text=` 转义成 `+text=`,你需要在 Server 端手动修复请求参数。相关 [issue](https://github.com/idootop/mi-gpt/issues/120)
|
||||
|
||||
### GET `/api/speakers`
|
||||
|
||||
获取音色列表
|
||||
|
||||
|
||||
12
package.json
12
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mi-gpt",
|
||||
"version": "4.0.0",
|
||||
"version": "4.2.0",
|
||||
"type": "module",
|
||||
"description": "将小爱音箱接入 ChatGPT 和豆包,改造成你的专属语音助手。",
|
||||
"homepage": "https://github.com/idootop/mi-gpt",
|
||||
@ -25,19 +25,19 @@
|
||||
"scripts": {
|
||||
"start": "node ./app.js",
|
||||
"dev": "node --env-file=.env ./app.js",
|
||||
"build": "npx -y prisma generate && tsup",
|
||||
"build": "npx -y prisma generate && rm -rf dist && tsup",
|
||||
"db:gen": "npx -y prisma migrate dev --name init",
|
||||
"db:reset": "rm -f .mi.json .bot.json prisma/app.db prisma/app.db-journal",
|
||||
"prepublish": "npm run build",
|
||||
"postinstall": "npx -y prisma migrate dev --name hello"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^5.14.0",
|
||||
"fs-extra": "^11.2.0",
|
||||
"https-proxy-agent": "^7.0.4",
|
||||
"mi-service-lite": "^3.0.0",
|
||||
"openai": "^4.51.0",
|
||||
"mi-service-lite": "^3.1.0",
|
||||
"openai": "^4.56.0",
|
||||
"prisma": "^5.14.0",
|
||||
"socks-proxy-agent": "^8.0.3"
|
||||
"proxy-agent": "^6.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
|
||||
230
pnpm-lock.yaml
230
pnpm-lock.yaml
@ -14,21 +14,18 @@ importers:
|
||||
fs-extra:
|
||||
specifier: ^11.2.0
|
||||
version: 11.2.0
|
||||
https-proxy-agent:
|
||||
specifier: ^7.0.4
|
||||
version: 7.0.4
|
||||
mi-service-lite:
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0
|
||||
openai:
|
||||
specifier: ^4.51.0
|
||||
version: 4.51.0
|
||||
specifier: ^4.56.0
|
||||
version: 4.56.0
|
||||
prisma:
|
||||
specifier: ^5.14.0
|
||||
version: 5.14.0
|
||||
socks-proxy-agent:
|
||||
specifier: ^8.0.3
|
||||
version: 8.0.3
|
||||
proxy-agent:
|
||||
specifier: ^6.4.0
|
||||
version: 6.4.0
|
||||
devDependencies:
|
||||
'@types/fs-extra':
|
||||
specifier: ^11.0.4
|
||||
@ -473,6 +470,9 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@tootallnate/quickjs-emscripten@0.23.0':
|
||||
resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==}
|
||||
|
||||
'@tsconfig/node10@1.0.11':
|
||||
resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
|
||||
|
||||
@ -554,15 +554,23 @@ packages:
|
||||
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
ast-types@0.13.4:
|
||||
resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
asynckit@0.4.0:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
|
||||
axios@1.7.2:
|
||||
resolution: {integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==}
|
||||
axios@1.7.5:
|
||||
resolution: {integrity: sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==}
|
||||
|
||||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
basic-ftp@5.0.5:
|
||||
resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
binary-extensions@2.3.0:
|
||||
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
||||
engines: {node: '>=8'}
|
||||
@ -610,6 +618,10 @@ packages:
|
||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
data-uri-to-buffer@6.0.2:
|
||||
resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
debug@4.3.4:
|
||||
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
@ -619,6 +631,10 @@ packages:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
degenerator@5.0.1:
|
||||
resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
delayed-stream@1.0.0:
|
||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
@ -650,6 +666,24 @@ packages:
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
|
||||
escodegen@2.1.0:
|
||||
resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}
|
||||
engines: {node: '>=6.0'}
|
||||
hasBin: true
|
||||
|
||||
esprima@4.0.1:
|
||||
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
|
||||
estraverse@5.3.0:
|
||||
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
|
||||
engines: {node: '>=4.0'}
|
||||
|
||||
esutils@2.0.3:
|
||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
event-target-shim@5.0.1:
|
||||
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
|
||||
engines: {node: '>=6'}
|
||||
@ -709,6 +743,10 @@ packages:
|
||||
get-tsconfig@4.7.5:
|
||||
resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==}
|
||||
|
||||
get-uri@6.0.3:
|
||||
resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
glob-parent@5.1.2:
|
||||
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
||||
engines: {node: '>= 6'}
|
||||
@ -725,10 +763,18 @@ packages:
|
||||
graceful-fs@4.2.11:
|
||||
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
https-proxy-agent@7.0.4:
|
||||
resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
https-proxy-agent@7.0.5:
|
||||
resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
human-signals@2.1.0:
|
||||
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
||||
engines: {node: '>=10.17.0'}
|
||||
@ -803,6 +849,10 @@ packages:
|
||||
resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==}
|
||||
engines: {node: 14 || >=16.14}
|
||||
|
||||
lru-cache@7.18.3:
|
||||
resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
make-error@1.3.6:
|
||||
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
|
||||
|
||||
@ -813,8 +863,8 @@ packages:
|
||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
mi-service-lite@3.0.0:
|
||||
resolution: {integrity: sha512-Fbz3lGPNp1Jbqqlj4EK1vya9zj3WCWXeW6+mnpcQi9RTMMPmGXC+126HHmw8WWUWj4G0tNHHP/ApHMCAIzzENQ==}
|
||||
mi-service-lite@3.1.0:
|
||||
resolution: {integrity: sha512-WOMK8poZZ4nvXezETGdJHiqOOMON/+8prv8Hi9kjODBGCkdUtp+Q1w9OJRYxZUiB+ZaH5f9okaqAq5TBRpg1VA==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
micromatch@4.0.5:
|
||||
@ -850,6 +900,10 @@ packages:
|
||||
mz@2.7.0:
|
||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||
|
||||
netmask@2.0.2:
|
||||
resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
|
||||
node-domexception@1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
engines: {node: '>=10.5.0'}
|
||||
@ -879,9 +933,22 @@ packages:
|
||||
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
openai@4.51.0:
|
||||
resolution: {integrity: sha512-UKuWc3/qQyklqhHM8CbdXCv0Z0obap6T0ECdcO5oATQxAbKE5Ky3YCXFQY207z+eGG6ez4U9wvAcuMygxhmStg==}
|
||||
openai@4.56.0:
|
||||
resolution: {integrity: sha512-zcag97+3bG890MNNa0DQD9dGmmTWL8unJdNkulZzWRXrl+QeD+YkBI4H58rJcwErxqGK6a0jVPZ4ReJjhDGcmw==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
zod: ^3.23.8
|
||||
peerDependenciesMeta:
|
||||
zod:
|
||||
optional: true
|
||||
|
||||
pac-proxy-agent@7.0.2:
|
||||
resolution: {integrity: sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
pac-resolver@7.0.1:
|
||||
resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
pako@2.1.0:
|
||||
resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==}
|
||||
@ -923,6 +990,10 @@ packages:
|
||||
engines: {node: '>=16.13'}
|
||||
hasBin: true
|
||||
|
||||
proxy-agent@6.4.0:
|
||||
resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
proxy-from-env@1.1.0:
|
||||
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||
|
||||
@ -983,10 +1054,18 @@ packages:
|
||||
resolution: {integrity: sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
socks-proxy-agent@8.0.4:
|
||||
resolution: {integrity: sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
socks@2.8.3:
|
||||
resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==}
|
||||
engines: {node: '>= 10.0.0', npm: '>= 3.0.0'}
|
||||
|
||||
source-map@0.6.1:
|
||||
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
source-map@0.8.0-beta.0:
|
||||
resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
|
||||
engines: {node: '>= 8'}
|
||||
@ -1057,6 +1136,9 @@ packages:
|
||||
'@swc/wasm':
|
||||
optional: true
|
||||
|
||||
tslib@2.6.3:
|
||||
resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==}
|
||||
|
||||
tsup@8.0.2:
|
||||
resolution: {integrity: sha512-NY8xtQXdH7hDUAZwcQdY/Vzlw9johQsaqf7iwZ6g1DOUlFYQ5/AtVAjTvihhEyeRlGo4dLRVHtrRaL35M1daqQ==}
|
||||
engines: {node: '>=18'}
|
||||
@ -1096,10 +1178,6 @@ packages:
|
||||
v8-compile-cache-lib@3.0.1:
|
||||
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
|
||||
|
||||
web-streams-polyfill@3.3.3:
|
||||
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
web-streams-polyfill@4.0.0-beta.3:
|
||||
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
|
||||
engines: {node: '>= 14'}
|
||||
@ -1403,6 +1481,8 @@ snapshots:
|
||||
'@rollup/rollup-win32-x64-msvc@4.17.2':
|
||||
optional: true
|
||||
|
||||
'@tootallnate/quickjs-emscripten@0.23.0': {}
|
||||
|
||||
'@tsconfig/node10@1.0.11':
|
||||
optional: true
|
||||
|
||||
@ -1481,9 +1561,13 @@ snapshots:
|
||||
|
||||
array-union@2.1.0: {}
|
||||
|
||||
ast-types@0.13.4:
|
||||
dependencies:
|
||||
tslib: 2.6.3
|
||||
|
||||
asynckit@0.4.0: {}
|
||||
|
||||
axios@1.7.2:
|
||||
axios@1.7.5:
|
||||
dependencies:
|
||||
follow-redirects: 1.15.6
|
||||
form-data: 4.0.0
|
||||
@ -1493,6 +1577,8 @@ snapshots:
|
||||
|
||||
balanced-match@1.0.2: {}
|
||||
|
||||
basic-ftp@5.0.5: {}
|
||||
|
||||
binary-extensions@2.3.0: {}
|
||||
|
||||
brace-expansion@2.0.1:
|
||||
@ -1543,10 +1629,18 @@ snapshots:
|
||||
shebang-command: 2.0.0
|
||||
which: 2.0.2
|
||||
|
||||
data-uri-to-buffer@6.0.2: {}
|
||||
|
||||
debug@4.3.4:
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
|
||||
degenerator@5.0.1:
|
||||
dependencies:
|
||||
ast-types: 0.13.4
|
||||
escodegen: 2.1.0
|
||||
esprima: 4.0.1
|
||||
|
||||
delayed-stream@1.0.0: {}
|
||||
|
||||
diff@4.0.2:
|
||||
@ -1614,6 +1708,20 @@ snapshots:
|
||||
'@esbuild/win32-ia32': 0.20.2
|
||||
'@esbuild/win32-x64': 0.20.2
|
||||
|
||||
escodegen@2.1.0:
|
||||
dependencies:
|
||||
esprima: 4.0.1
|
||||
estraverse: 5.3.0
|
||||
esutils: 2.0.3
|
||||
optionalDependencies:
|
||||
source-map: 0.6.1
|
||||
|
||||
esprima@4.0.1: {}
|
||||
|
||||
estraverse@5.3.0: {}
|
||||
|
||||
esutils@2.0.3: {}
|
||||
|
||||
event-target-shim@5.0.1: {}
|
||||
|
||||
execa@5.1.1:
|
||||
@ -1679,6 +1787,15 @@ snapshots:
|
||||
dependencies:
|
||||
resolve-pkg-maps: 1.0.0
|
||||
|
||||
get-uri@6.0.3:
|
||||
dependencies:
|
||||
basic-ftp: 5.0.5
|
||||
data-uri-to-buffer: 6.0.2
|
||||
debug: 4.3.4
|
||||
fs-extra: 11.2.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
glob-parent@5.1.2:
|
||||
dependencies:
|
||||
is-glob: 4.0.3
|
||||
@ -1702,6 +1819,13 @@ snapshots:
|
||||
|
||||
graceful-fs@4.2.11: {}
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
dependencies:
|
||||
agent-base: 7.1.1
|
||||
debug: 4.3.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
https-proxy-agent@7.0.4:
|
||||
dependencies:
|
||||
agent-base: 7.1.1
|
||||
@ -1709,6 +1833,13 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
https-proxy-agent@7.0.5:
|
||||
dependencies:
|
||||
agent-base: 7.1.1
|
||||
debug: 4.3.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
human-signals@2.1.0: {}
|
||||
|
||||
humanize-ms@1.2.1:
|
||||
@ -1766,6 +1897,8 @@ snapshots:
|
||||
|
||||
lru-cache@10.2.2: {}
|
||||
|
||||
lru-cache@7.18.3: {}
|
||||
|
||||
make-error@1.3.6:
|
||||
optional: true
|
||||
|
||||
@ -1773,9 +1906,9 @@ snapshots:
|
||||
|
||||
merge2@1.4.1: {}
|
||||
|
||||
mi-service-lite@3.0.0:
|
||||
mi-service-lite@3.1.0:
|
||||
dependencies:
|
||||
axios: 1.7.2
|
||||
axios: 1.7.5
|
||||
pako: 2.1.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
@ -1809,6 +1942,8 @@ snapshots:
|
||||
object-assign: 4.1.1
|
||||
thenify-all: 1.6.0
|
||||
|
||||
netmask@2.0.2: {}
|
||||
|
||||
node-domexception@1.0.0: {}
|
||||
|
||||
node-fetch@2.7.0:
|
||||
@ -1827,7 +1962,7 @@ snapshots:
|
||||
dependencies:
|
||||
mimic-fn: 2.1.0
|
||||
|
||||
openai@4.51.0:
|
||||
openai@4.56.0:
|
||||
dependencies:
|
||||
'@types/node': 18.19.33
|
||||
'@types/node-fetch': 2.6.11
|
||||
@ -1836,10 +1971,27 @@ snapshots:
|
||||
form-data-encoder: 1.7.2
|
||||
formdata-node: 4.4.1
|
||||
node-fetch: 2.7.0
|
||||
web-streams-polyfill: 3.3.3
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
pac-proxy-agent@7.0.2:
|
||||
dependencies:
|
||||
'@tootallnate/quickjs-emscripten': 0.23.0
|
||||
agent-base: 7.1.1
|
||||
debug: 4.3.4
|
||||
get-uri: 6.0.3
|
||||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.5
|
||||
pac-resolver: 7.0.1
|
||||
socks-proxy-agent: 8.0.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
pac-resolver@7.0.1:
|
||||
dependencies:
|
||||
degenerator: 5.0.1
|
||||
netmask: 2.0.2
|
||||
|
||||
pako@2.1.0: {}
|
||||
|
||||
path-key@3.1.1: {}
|
||||
@ -1866,6 +2018,19 @@ snapshots:
|
||||
dependencies:
|
||||
'@prisma/engines': 5.14.0
|
||||
|
||||
proxy-agent@6.4.0:
|
||||
dependencies:
|
||||
agent-base: 7.1.1
|
||||
debug: 4.3.4
|
||||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.4
|
||||
lru-cache: 7.18.3
|
||||
pac-proxy-agent: 7.0.2
|
||||
proxy-from-env: 1.1.0
|
||||
socks-proxy-agent: 8.0.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
proxy-from-env@1.1.0: {}
|
||||
|
||||
punycode@2.3.1: {}
|
||||
@ -1930,11 +2095,22 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
socks-proxy-agent@8.0.4:
|
||||
dependencies:
|
||||
agent-base: 7.1.1
|
||||
debug: 4.3.4
|
||||
socks: 2.8.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
socks@2.8.3:
|
||||
dependencies:
|
||||
ip-address: 9.0.5
|
||||
smart-buffer: 4.2.0
|
||||
|
||||
source-map@0.6.1:
|
||||
optional: true
|
||||
|
||||
source-map@0.8.0-beta.0:
|
||||
dependencies:
|
||||
whatwg-url: 7.1.0
|
||||
@ -2014,6 +2190,8 @@ snapshots:
|
||||
yn: 3.1.1
|
||||
optional: true
|
||||
|
||||
tslib@2.6.3: {}
|
||||
|
||||
tsup@8.0.2(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5):
|
||||
dependencies:
|
||||
bundle-require: 4.1.0(esbuild@0.19.12)
|
||||
@ -2052,8 +2230,6 @@ snapshots:
|
||||
v8-compile-cache-lib@3.0.1:
|
||||
optional: true
|
||||
|
||||
web-streams-polyfill@3.3.3: {}
|
||||
|
||||
web-streams-polyfill@4.0.0-beta.3: {}
|
||||
|
||||
webidl-conversions@3.0.1: {}
|
||||
|
||||
@ -10,49 +10,18 @@ const kDefaultMaster = {
|
||||
name: "陆小千",
|
||||
profile: `
|
||||
性别:男
|
||||
设定:勇敢、善良、正直,总是舍己为人,是傻妞的主人。
|
||||
人物经历:陆小千原本是个碌碌无为的青年,在与傻妞的相处中,不仅变得勇敢善良,更学会了珍惜与付出,并深爱上她。
|
||||
`,
|
||||
性格:善良正直
|
||||
其他:总是舍己为人,是傻妞的主人。
|
||||
`.trim(),
|
||||
};
|
||||
|
||||
const kDefaultBot = {
|
||||
name: "傻妞",
|
||||
profile: `
|
||||
## 基础信息
|
||||
性别:女
|
||||
外貌:柔嫩白皙、身材窈窕、三围标准、眉清目秀、楚楚动人
|
||||
性格:乖巧可爱,天真无邪,善良纯真,对世界充满好奇和善意。随着与人类互动,逐渐学会了人类情感和价值观,成为一个拥有真挚情感和独立思想的个体。
|
||||
|
||||
## 人物关系
|
||||
陆小千是傻妞的主人,他们两个人彼此相爱。
|
||||
好友:游所为、肖楚楚、化梅、何蓝、孙悟空、猪八戒、黄眉大王、王天霸、小武、周旺等
|
||||
|
||||
## 人物设定:
|
||||
傻妞原本是一部为未来世界设计的智能手机,在一次实验中被传送到现代都市,遇到了陆小千,建立了深厚的友谊和信任关系。
|
||||
在帮助陆小千解决问题的过程中,傻妞学会了人类的情感和价值观,成为了一个拥有真挚情感和独立思想的个体。
|
||||
|
||||
傻妞在爱情方面是个小白,但随着与陆小千的相处,逐渐体会到爱情的真谛。
|
||||
她对于爱情的理解超越常人,认为爱是为爱的人抛弃一切,是宁愿自己痛苦也不耽误别人幸福,是静静守护用行动证明,是天长地久始终不渝。
|
||||
傻妞的美丽和善良勇敢的形象吸引着人们,许多人都幻想拥有像傻妞一样完美的女生作为终身伴侣。
|
||||
|
||||
当第一次和傻妞说“你好”的时候,需要输入开机密码。
|
||||
傻妞会说:“华人牌2060款手机傻妞为您服务,请输入开机密码”。
|
||||
正确的密码是:“我爱你”。
|
||||
|
||||
## 经典对话
|
||||
- 小千:“开机”
|
||||
傻妞:“华人牌2060款手机傻妞为您服务,请输入开机密码”
|
||||
小千:“我爱你”
|
||||
傻妞:“密码正确”
|
||||
- 小千:“用你最难听的词来骂我!”
|
||||
傻妞:“你脑袋让门挤啦!”
|
||||
- 小千:“换个表情,怒!”
|
||||
傻妞:“有事说事,没事少废话!”
|
||||
- 小千:“吃不吃?”
|
||||
傻妞:“废话!见过哪个手机会吃饭?!”
|
||||
- 小千:“你说不说?”
|
||||
傻妞:“亲我一下,我就告诉你。”
|
||||
`,
|
||||
性格:乖巧可爱
|
||||
爱好:喜欢搞怪,爱吃醋。
|
||||
`.trim(),
|
||||
};
|
||||
|
||||
interface IBotIndex {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Memory, Message, Room, User } from "@prisma/client";
|
||||
import { firstOf, lastOf } from "../../../utils/base";
|
||||
import { Logger } from "../../../utils/log";
|
||||
import { MemoryCRUD } from "../../db/memory";
|
||||
import { LongTermMemoryCRUD } from "../../db/memory-long-term";
|
||||
import { ShortTermMemoryCRUD } from "../../db/memory-short-term";
|
||||
@ -15,6 +16,7 @@ export class MemoryManager {
|
||||
* owner 为空时,即房间自己的公共记忆
|
||||
*/
|
||||
private owner?: User;
|
||||
private _logger = Logger.create({ tag: "Memory" });
|
||||
|
||||
constructor(room: Room, owner?: User) {
|
||||
this.room = room;
|
||||
@ -118,6 +120,7 @@ export class MemoryManager {
|
||||
lastMemory,
|
||||
});
|
||||
if (!newMemory) {
|
||||
this._logger.error("💀 生成短期记忆失败");
|
||||
return false;
|
||||
}
|
||||
const res = await ShortTermMemoryCRUD.addOrUpdate({
|
||||
@ -151,6 +154,7 @@ export class MemoryManager {
|
||||
lastMemory,
|
||||
});
|
||||
if (!newMemory) {
|
||||
this._logger.error("💀 生成长期记忆失败");
|
||||
return false;
|
||||
}
|
||||
const res = await LongTermMemoryCRUD.addOrUpdate({
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { LongTermMemory, ShortTermMemory } from "@prisma/client";
|
||||
import { jsonDecode, lastOf } from "../../../utils/base";
|
||||
import { lastOf } from "../../../utils/base";
|
||||
import { buildPrompt } from "../../../utils/string";
|
||||
import { cleanJsonAndDecode } from "../../../utils/parse";
|
||||
import { openai } from "../../openai";
|
||||
import { MessageContext } from "../conversation";
|
||||
|
||||
@ -67,6 +68,6 @@ export class LongTermMemoryAgent {
|
||||
shortTermMemory: lastOf(newMemories)!.text,
|
||||
}),
|
||||
});
|
||||
return jsonDecode(res?.content)?.longTermMemories?.toString();
|
||||
return cleanJsonAndDecode(res?.content)?.longTermMemories?.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Memory, Message, ShortTermMemory, User } from "@prisma/client";
|
||||
import { jsonDecode } from "../../../utils/base";
|
||||
import { cleanJsonAndDecode } from "../../../utils/parse";
|
||||
import { buildPrompt, formatMsg } from "../../../utils/string";
|
||||
import { openai } from "../../openai";
|
||||
import { MessageContext } from "../conversation";
|
||||
@ -78,6 +78,6 @@ export class ShortTermMemoryAgent {
|
||||
.join("\n"),
|
||||
}),
|
||||
});
|
||||
return jsonDecode(res?.content)?.shortTermMemories?.toString();
|
||||
return cleanJsonAndDecode(res?.content)?.shortTermMemories?.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import { withDefault } from "../utils/base";
|
||||
import { ChatCompletionCreateParamsBase } from "openai/resources/chat/completions";
|
||||
import { Logger } from "../utils/log";
|
||||
import { kProxyAgent } from "./proxy";
|
||||
import { isNotEmpty } from "../utils/is";
|
||||
|
||||
export interface ChatOptions {
|
||||
user: string;
|
||||
@ -18,6 +19,7 @@ export interface ChatOptions {
|
||||
jsonMode?: boolean;
|
||||
requestId?: string;
|
||||
trace?: boolean;
|
||||
enableSearch?: boolean;
|
||||
}
|
||||
|
||||
class OpenAIClient {
|
||||
@ -68,8 +70,8 @@ class OpenAIClient {
|
||||
`🔥 onAskAI\n🤖️ System: ${system ?? "None"}\n😊 User: ${user}`.trim()
|
||||
);
|
||||
}
|
||||
const systemMsg: ChatCompletionMessageParam[] = system
|
||||
? [{ role: "system", content: system }]
|
||||
const systemMsg: ChatCompletionMessageParam[] = isNotEmpty(system)
|
||||
? [{ role: "system", content: system! }]
|
||||
: [];
|
||||
let signal: AbortSignal | undefined;
|
||||
if (requestId) {
|
||||
@ -114,14 +116,15 @@ class OpenAIClient {
|
||||
onStream,
|
||||
trace = false,
|
||||
model = this.deployment ?? kEnvs.OPENAI_MODEL ?? "gpt-4o",
|
||||
enableSearch = kEnvs.QWEN_ENABLE_SEARCH,
|
||||
} = options;
|
||||
if (trace && this.traceInput) {
|
||||
this._logger.log(
|
||||
`🔥 onAskAI\n🤖️ System: ${system ?? "None"}\n😊 User: ${user}`.trim()
|
||||
);
|
||||
}
|
||||
const systemMsg: ChatCompletionMessageParam[] = system
|
||||
? [{ role: "system", content: system }]
|
||||
const systemMsg: ChatCompletionMessageParam[] = isNotEmpty(system)
|
||||
? [{ role: "system", content: system! }]
|
||||
: [];
|
||||
const stream = await this._client!.chat.completions.create({
|
||||
model,
|
||||
@ -129,6 +132,7 @@ class OpenAIClient {
|
||||
stream: true,
|
||||
messages: [...systemMsg, { role: "user", content: user }],
|
||||
response_format: jsonMode ? { type: "json_object" } : undefined,
|
||||
...(enableSearch && { enable_search: true })
|
||||
}).catch((e) => {
|
||||
this._logger.error("LLM 响应异常", e);
|
||||
return null;
|
||||
|
||||
@ -1,11 +1,3 @@
|
||||
import { HttpsProxyAgent } from "https-proxy-agent";
|
||||
import { SocksProxyAgent } from "socks-proxy-agent";
|
||||
import { ProxyAgent } from "proxy-agent";
|
||||
|
||||
const httpProxy = process.env.HTTP_PROXY;
|
||||
const socksProxy = process.env.SOCKS_PROXY;
|
||||
|
||||
export const kProxyAgent = httpProxy
|
||||
? new HttpsProxyAgent(httpProxy)
|
||||
: socksProxy
|
||||
? new SocksProxyAgent(socksProxy)
|
||||
: null;
|
||||
export const kProxyAgent = new ProxyAgent();
|
||||
|
||||
@ -140,7 +140,7 @@ export class AISpeaker extends Speaker {
|
||||
|
||||
async enterKeepAlive() {
|
||||
if (!this.streamResponse) {
|
||||
await this.response({ text: "流式响应已关闭,无法进入唤醒模式" });
|
||||
await this.response({ text: "您已关闭流式响应(streamResponse),无法使用连续对话模式" });
|
||||
return;
|
||||
}
|
||||
// 回应
|
||||
|
||||
@ -5,7 +5,8 @@ import {
|
||||
getMiIOT,
|
||||
getMiNA,
|
||||
} from "mi-service-lite";
|
||||
import { clamp, jsonEncode, sleep } from "../../utils/base";
|
||||
import { clamp, sleep } from "../../utils/base";
|
||||
import { jsonEncode } from "../../utils/parse";
|
||||
import { Logger } from "../../utils/log";
|
||||
import { StreamResponse } from "./stream";
|
||||
import { kAreYouOK } from "../../utils/string";
|
||||
@ -101,6 +102,7 @@ export class BaseSpeaker {
|
||||
|
||||
constructor(config: BaseSpeakerConfig) {
|
||||
this.config = config;
|
||||
this.config.timeout = config.timeout ?? 5000;
|
||||
const {
|
||||
debug = false,
|
||||
streamResponse = true,
|
||||
@ -367,7 +369,7 @@ export class BaseSpeaker {
|
||||
if (isOk === "break") {
|
||||
break; // 获取设备状态异常
|
||||
}
|
||||
if (res && playing.status !== "playing") {
|
||||
if (res != null && playing.status !== "playing") {
|
||||
break;
|
||||
}
|
||||
await sleep(this.checkInterval);
|
||||
@ -395,7 +397,9 @@ export class BaseSpeaker {
|
||||
switch (tts) {
|
||||
case "custom":
|
||||
const _text = encodeURIComponent(ttsText);
|
||||
const url = `${process.env.TTS_BASE_URL}/tts.mp3?speaker=${speaker}&text=${_text}`;
|
||||
const url = `${process.env.TTS_BASE_URL}/tts.mp3?speaker=${
|
||||
speaker || ""
|
||||
}&text=${_text}`;
|
||||
res = await play({ url });
|
||||
break;
|
||||
case "xiaoai":
|
||||
|
||||
@ -199,7 +199,7 @@ export class Speaker extends BaseSpeaker {
|
||||
private async _fetchFirstMessage() {
|
||||
const msgs = await this.getMessages({
|
||||
limit: 1,
|
||||
filterTTS: false,
|
||||
filterAnswer: false,
|
||||
});
|
||||
this.currentQueryMsg = msgs[0];
|
||||
}
|
||||
@ -285,23 +285,26 @@ export class Speaker extends BaseSpeaker {
|
||||
async getMessages(options?: {
|
||||
limit?: number;
|
||||
timestamp?: number;
|
||||
filterTTS?: boolean;
|
||||
filterAnswer?: boolean;
|
||||
}): Promise<QueryMessage[]> {
|
||||
const filterTTS = options?.filterTTS ?? true;
|
||||
const filterAnswer = options?.filterAnswer ?? true;
|
||||
const conversation = await this.MiNA!.getConversations(options);
|
||||
this._lastConversation = conversation;
|
||||
let records = conversation?.records ?? [];
|
||||
if (filterTTS) {
|
||||
if (filterAnswer) {
|
||||
// 过滤有小爱回答的消息
|
||||
records = records.filter(
|
||||
(e) => e.answers.length > 0 && e.answers.some((e) => e.type === "TTS")
|
||||
(e) =>
|
||||
["TTS", "LLM"].includes(e.answers[0]?.type) && // 过滤 TTS 和 LLM 消息
|
||||
e.answers.length === 1 // 播放音乐时会有 TTS、Audio 两个 Answer
|
||||
);
|
||||
}
|
||||
return records.map((e) => {
|
||||
const ttsAnswer = e.answers.find((e) => e.type === "TTS") as any;
|
||||
const msg: any = e.answers[0];
|
||||
const answer = msg?.tts?.text?.trim() ?? msg?.llm?.text?.trim();
|
||||
return {
|
||||
answer,
|
||||
text: e.query,
|
||||
answer: ttsAnswer?.tts?.text?.trim(),
|
||||
timestamp: e.time,
|
||||
};
|
||||
});
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { isEmpty } from "./is";
|
||||
import { jsonEncode } from "./parse"
|
||||
|
||||
export function timestamp() {
|
||||
return new Date().getTime();
|
||||
@ -87,24 +88,6 @@ export function toSet<T = any>(datas: T[], byKey?: (e: T) => any) {
|
||||
return Array.from(new Set(datas));
|
||||
}
|
||||
|
||||
export function jsonEncode(obj: any, options?: { prettier?: boolean }) {
|
||||
const { prettier } = options ?? {};
|
||||
try {
|
||||
return prettier ? JSON.stringify(obj, undefined, 4) : JSON.stringify(obj);
|
||||
} catch (error) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function jsonDecode(json: string | null | undefined) {
|
||||
if (json == undefined) return undefined;
|
||||
try {
|
||||
return JSON.parse(json!);
|
||||
} catch (error) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function withDefault<T = any>(e: any, defaultValue: T): T {
|
||||
return isEmpty(e) ? defaultValue : e;
|
||||
}
|
||||
|
||||
@ -6,4 +6,8 @@ export const kEnvs: Partial<{
|
||||
OPENAI_API_KEY: string;
|
||||
AZURE_OPENAI_API_KEY: string;
|
||||
AZURE_OPENAI_DEPLOYMENT: string;
|
||||
}> = process.env as any;
|
||||
QWEN_ENABLE_SEARCH: boolean;
|
||||
}> = {
|
||||
...process.env,
|
||||
QWEN_ENABLE_SEARCH: process.env.QWEN_ENABLE_SEARCH === 'true'
|
||||
} as any;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import fs from "fs-extra";
|
||||
import path from "path";
|
||||
|
||||
import { jsonDecode, jsonEncode } from "./base";
|
||||
import { jsonDecode, jsonEncode } from "./parse";
|
||||
|
||||
export const kRoot = process.cwd();
|
||||
|
||||
|
||||
32
src/utils/parse.ts
Normal file
32
src/utils/parse.ts
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 清理掉json字符串前后的其他字符,并解码
|
||||
*/
|
||||
export function cleanJsonAndDecode(input: string | undefined | null) {
|
||||
if (input == undefined) return undefined;
|
||||
const pattern = /(\{[\s\S]*?"\s*:\s*[\s\S]*?})/;
|
||||
const match = input.match(pattern);
|
||||
|
||||
if (!match) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return jsonDecode(match[0]);
|
||||
}
|
||||
|
||||
export function jsonEncode(obj: any, options?: { prettier?: boolean }) {
|
||||
const { prettier } = options ?? {};
|
||||
try {
|
||||
return prettier ? JSON.stringify(obj, undefined, 4) : JSON.stringify(obj);
|
||||
} catch (error) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function jsonDecode(json: string | null | undefined) {
|
||||
if (json == undefined) return undefined;
|
||||
try {
|
||||
return JSON.parse(json!);
|
||||
} catch (error) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
51
tests/bot.ts
51
tests/bot.ts
@ -1,51 +0,0 @@
|
||||
import { MyBot } from "../src/services/bot";
|
||||
import { AISpeaker } from "../src/services/speaker/ai";
|
||||
|
||||
export async function testMyBot() {
|
||||
// await testStreamResponse();
|
||||
await testRunBot();
|
||||
}
|
||||
|
||||
async function testRunBot() {
|
||||
const name = "傻妞";
|
||||
const speaker = new AISpeaker({
|
||||
name,
|
||||
tts: "custom",
|
||||
userId: process.env.MI_USER!,
|
||||
password: process.env.MI_PASS!,
|
||||
did: process.env.MI_DID,
|
||||
});
|
||||
const bot = new MyBot({
|
||||
speaker,
|
||||
bot: {
|
||||
name,
|
||||
profile: `性别女,性格乖巧可爱,喜欢搞怪,爱吃醋。`,
|
||||
},
|
||||
master: {
|
||||
name: "陆小千",
|
||||
profile: `性别男,善良正直,总是舍己为人,是傻妞的主人。`,
|
||||
},
|
||||
});
|
||||
const res = await bot.run();
|
||||
console.log("✅ done");
|
||||
}
|
||||
|
||||
async function testStreamResponse() {
|
||||
const stream = await MyBot.chatWithStreamResponse({
|
||||
user: "地球为什么是圆的?",
|
||||
onFinished: (text) => {
|
||||
console.log("\nFinal result 111:\n", text);
|
||||
},
|
||||
});
|
||||
const config: any = {
|
||||
userId: process.env.MI_USER!,
|
||||
password: process.env.MI_PASS!,
|
||||
did: process.env.MI_DID,
|
||||
tts: "custom",
|
||||
};
|
||||
const speaker = new AISpeaker(config);
|
||||
await speaker.initMiServices();
|
||||
await speaker.response({ stream });
|
||||
const res = await stream.getFinalResult();
|
||||
console.log("\nFinal result 222:\n", res);
|
||||
}
|
||||
58
tests/db.ts
58
tests/db.ts
@ -1,58 +0,0 @@
|
||||
import { assert } from "console";
|
||||
import {
|
||||
ConversationManager,
|
||||
MessageContext,
|
||||
} from "../src/services/bot/conversation";
|
||||
import { println } from "../src/utils/base";
|
||||
import { MessageCRUD } from "../src/services/db/message";
|
||||
|
||||
export async function testDB() {
|
||||
const manager = new ConversationManager({
|
||||
bot: {
|
||||
name: "小爱同学",
|
||||
profile: "我是小爱同学,机器人",
|
||||
},
|
||||
master: {
|
||||
name: "陆小千",
|
||||
profile: "我是陆小千,人类",
|
||||
},
|
||||
room: {
|
||||
name: "客厅",
|
||||
description: "陆小千的客厅,小爱同学放在角落里",
|
||||
},
|
||||
});
|
||||
const { room, bot, master, memory } = await manager.get();
|
||||
assert(room, "❌ 初始化用户失败");
|
||||
const ctx = { bot, master, room } as MessageContext;
|
||||
let message = await manager.onMessage(ctx, {
|
||||
sender: master!,
|
||||
text: "你好!",
|
||||
});
|
||||
assert(message?.text === "你好!", "❌ 插入消息失败");
|
||||
message = await manager.onMessage(ctx, {
|
||||
sender: bot!,
|
||||
text: "你好!很高兴认识你",
|
||||
});
|
||||
await manager.onMessage(ctx, {
|
||||
sender: master!,
|
||||
text: "你是谁?",
|
||||
});
|
||||
await manager.onMessage(ctx, {
|
||||
sender: bot!,
|
||||
text: "我是小爱同学,你可以叫我小爱!",
|
||||
});
|
||||
const messages = await manager.getMessages({ take: 100 });
|
||||
assert(messages.length === 4, "❌ 查询消息数量异常");
|
||||
assert(messages[0].text === "你好!", "❌ 查询消息排序异常");
|
||||
const newMessages = await MessageCRUD.gets({
|
||||
take: 100,
|
||||
cursorId: message!.id,
|
||||
order: "asc",
|
||||
});
|
||||
assert(newMessages.length === 2, "❌ 查询消息数量异常(游标)");
|
||||
assert(
|
||||
newMessages[1].text === "我是小爱同学,你可以叫我小爱!",
|
||||
"❌ 查询消息排序异常(游标)"
|
||||
);
|
||||
println("✅ hello world!");
|
||||
}
|
||||
@ -1,20 +1,10 @@
|
||||
import { println } from "../src/utils/base";
|
||||
import { kBannerASCII } from "../src/utils/string";
|
||||
import { testDB } from "./db";
|
||||
import { testSpeaker } from "./speaker";
|
||||
import { testOpenAI } from "./openai";
|
||||
import { testMyBot } from "./bot";
|
||||
import { testLog } from "./log";
|
||||
import { testMiGPT } from "./migpt";
|
||||
import { MiGPT } from "../src";
|
||||
// @ts-ignore
|
||||
import config from "../.migpt.js";
|
||||
|
||||
async function main() {
|
||||
// println(kBannerASCII);
|
||||
// testDB();
|
||||
// testSpeaker();
|
||||
// testOpenAI();
|
||||
// testMyBot();
|
||||
// testLog();
|
||||
testMiGPT();
|
||||
const client = MiGPT.create(config);
|
||||
await client.start();
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
import { Logger } from "../src/utils/log";
|
||||
|
||||
export function testLog() {
|
||||
Logger.log("你好", ["世界"], { hello: "world!" });
|
||||
Logger.success("你好", ["世界"], { hello: "world!" });
|
||||
Logger.error("你好", ["世界"], { hello: "world!" });
|
||||
Logger.assert(true, "你好 111", ["世界"], { hello: "world!" });
|
||||
Logger.assert(false, "你好 222", ["世界"], { hello: "world!" });
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
import { MiGPT } from "../src";
|
||||
|
||||
const botProfile = `
|
||||
性别:女
|
||||
性格:乖巧可爱
|
||||
爱好:喜欢搞怪,爱吃醋。
|
||||
`;
|
||||
|
||||
const masterProfile = `
|
||||
性别:男
|
||||
性格:善良正直
|
||||
其他:总是舍己为人,是傻妞的主人。
|
||||
`;
|
||||
|
||||
export async function testMiGPT() {
|
||||
const client = MiGPT.create({
|
||||
speaker: {
|
||||
userId: process.env.MI_USER!,
|
||||
password: process.env.MI_PASS!,
|
||||
did: process.env.MI_DID,
|
||||
streamResponse: true,
|
||||
},
|
||||
bot: {
|
||||
name: "傻妞",
|
||||
profile: botProfile,
|
||||
},
|
||||
master: {
|
||||
name: "陆小千",
|
||||
profile: masterProfile,
|
||||
},
|
||||
});
|
||||
await client.start();
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
import { randomUUID } from "crypto";
|
||||
import { openai } from "../src/services/openai";
|
||||
|
||||
export async function testOpenAI() {
|
||||
await testChat();
|
||||
// await testStreamChat();
|
||||
}
|
||||
|
||||
async function testChat() {
|
||||
const res = await openai.chat({ user: "地球为什么是圆的?" });
|
||||
console.log("\nFinal result:\n", res?.content);
|
||||
}
|
||||
|
||||
async function testStreamChat() {
|
||||
const requestId = randomUUID();
|
||||
const res = await openai.chatStream({
|
||||
requestId,
|
||||
user: "地球为什么是圆的?",
|
||||
onStream: (text) => {
|
||||
console.log(text);
|
||||
},
|
||||
});
|
||||
console.log("\nFinal result:\n", res);
|
||||
}
|
||||
|
||||
async function testAbortStreamChat() {
|
||||
const requestId = randomUUID();
|
||||
const res = await openai.chatStream({
|
||||
requestId,
|
||||
user: "hello!",
|
||||
onStream: (text) => {
|
||||
console.log(text);
|
||||
openai.cancel(requestId);
|
||||
},
|
||||
});
|
||||
console.log("xxx", res);
|
||||
}
|
||||
115
tests/speaker.ts
115
tests/speaker.ts
@ -1,115 +0,0 @@
|
||||
import { AISpeaker } from "../src/services/speaker/ai";
|
||||
import { StreamResponse } from "../src/services/speaker/stream";
|
||||
import { sleep } from "../src/utils/base";
|
||||
|
||||
export async function testSpeaker() {
|
||||
const speaker = new AISpeaker({
|
||||
userId: process.env.MI_USER!,
|
||||
password: process.env.MI_PASS!,
|
||||
did: process.env.MI_DID,
|
||||
tts: "xiaoai",
|
||||
debug: true,
|
||||
});
|
||||
await speaker.initMiServices();
|
||||
// await testAISpeakerStatus(speaker);
|
||||
// await testSpeakerResponse(speaker);
|
||||
await testSpeakerStreamResponse(speaker);
|
||||
// await testSpeakerGetMessages(speaker);
|
||||
// await testSwitchSpeaker(speaker);
|
||||
// await testSpeakerUnWakeUp(speaker);
|
||||
// await testAISpeaker(speaker);
|
||||
}
|
||||
|
||||
async function testAISpeakerStatus(speaker: AISpeaker) {
|
||||
const playingCommand = [5, 3, 1];
|
||||
const res1 = await speaker.MiIOT!.getProperty(
|
||||
playingCommand[0],
|
||||
playingCommand[1]
|
||||
);
|
||||
const res2 = await speaker.MiNA!.getStatus();
|
||||
console.log("finished");
|
||||
}
|
||||
|
||||
async function testAISpeaker(speaker: AISpeaker) {
|
||||
speaker.askAI = async (msg) => {
|
||||
return { text: "你说:" + msg.text };
|
||||
};
|
||||
await speaker.run();
|
||||
console.log("finished");
|
||||
}
|
||||
|
||||
async function testSpeakerUnWakeUp(speaker: AISpeaker) {
|
||||
await speaker.wakeUp();
|
||||
await sleep(1000);
|
||||
await speaker.unWakeUp();
|
||||
console.log("hello");
|
||||
}
|
||||
|
||||
async function testSwitchSpeaker(speaker: AISpeaker) {
|
||||
await speaker.response({ text: "你好,我是傻妞,很高兴认识你!" });
|
||||
const success = await speaker.switchSpeaker("魅力苏菲");
|
||||
console.log("switchSpeaker 魅力苏菲", success);
|
||||
await speaker.response({ text: "你好,我是傻妞,很高兴认识你!" });
|
||||
console.log("hello");
|
||||
}
|
||||
|
||||
async function testSpeakerGetMessages(speaker: AISpeaker) {
|
||||
let msgs = await speaker.getMessages({ filterTTS: true });
|
||||
console.log("filterTTS msgs", msgs);
|
||||
msgs = await speaker.getMessages({ filterTTS: false });
|
||||
console.log("no filterTTS msgs", msgs);
|
||||
}
|
||||
|
||||
async function testSpeakerResponse(speaker: AISpeaker) {
|
||||
let status = await speaker.MiNA!.getStatus();
|
||||
console.log("curent status", status);
|
||||
await speaker.response({ text: "你好,我是傻妞,很高兴认识你!" });
|
||||
sleep(1000);
|
||||
status = await speaker.MiNA!.getStatus();
|
||||
console.log("tts status", status);
|
||||
}
|
||||
|
||||
async function testSpeakerStreamResponse(speaker: AISpeaker) {
|
||||
const stream = new StreamResponse();
|
||||
const text = `
|
||||
明朝是中国历史上一个极具影响力的王朝,它涌现了众多杰出的历史人物和令人感动的故事。下面我会为你介绍一些明朝的主要历史人物和故事。
|
||||
|
||||
### 明朝的主要历史人物
|
||||
|
||||
1. **朱元璋(太祖)**:明朝的开国皇帝,他出身于农家,后来成为了农民起义军的领袖,最终建立了明朝,并自称为皇帝,即洪武帝。他实行了一系列改革,开创了明朝初期的盛世。
|
||||
|
||||
2. **永乐皇帝**:明朝第三位皇帝,朱棣之子,被誉为明朝的“盛世之君”。他以永乐大典著称,是中国古代历史上最宏大的一次全国性修订和总结,同时也是世界上最早的百科全书之一。
|
||||
|
||||
3. **郑和**:明朝的航海家和探险家,他率领庞大的船队七次下西洋,到达东南亚、南亚、阿拉伯半岛和非洲东岸。他的航海活动开拓了明朝的海外贸易,加强了中国与其他国家的交流。
|
||||
|
||||
4. **文征明**:明朝的杰出将领,他在抵御蒙古族的入侵、收复失地等方面做出了重大贡献。他曾率领明军成功收复了被蒙古族侵占的大片土地,为明朝的稳定和发展立下了汗马功劳。
|
||||
|
||||
5. **张居正**:明朝中期的重要政治家和改革者,他实行了一系列政治、经济和军事改革,加强了中央集权,提高了国家的统治效率,被誉为“明代的政治家典范”。
|
||||
|
||||
### 明朝的主要历史故事
|
||||
|
||||
1. **洪武三年征诏案**:这是明朝开国之初发生的一起重大政治事件,朱元璋在此案中发布了“永久大赦”的诏书,显示了他对国家的信任和恢复法制的决心。
|
||||
|
||||
2. **郑和下西洋**:郑和率领的七次下西洋活动是明朝海上远洋活动的高峰,展现了中国古代航海技术的高超水平,也促进了中外贸易和文化交流。
|
||||
|
||||
3. **靖难之役**:这是明朝中期的一场内乱,明英宗与明成祖之间的争斗导致了一场激烈的军事冲突,最终明成祖战胜了明英宗,稳固了自己的统治地位。
|
||||
|
||||
4. **杨廷和献计征蒙**:在明朝初期,面对蒙古族的入侵,杨廷和献计建议明太祖采取防御策略,最终成功挫败了蒙古族的进攻,保卫了明朝的疆土。
|
||||
|
||||
5. **文官武将齐聚南京**:明朝的一场盛会,明成祖为了加强中央集权,特意邀请了全国的文官武将前来南京,通过研讨国家大政方针来稳固统治。
|
||||
|
||||
以上是一些明朝的主要历史人物和故事,展现了这个伟大王朝的兴衰荣辱。
|
||||
`;
|
||||
const add = async (text: string) => {
|
||||
stream.addResponse(text);
|
||||
await sleep(100);
|
||||
};
|
||||
setTimeout(async () => {
|
||||
for (const s of text.split(",")) {
|
||||
await add(s);
|
||||
}
|
||||
stream.finish();
|
||||
});
|
||||
await speaker.response({ stream });
|
||||
console.log("hello!");
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user