diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
index 68174a38..e54cdd4e 100644
--- a/.github/workflows/docker-image.yml
+++ b/.github/workflows/docker-image.yml
@@ -4,6 +4,7 @@ on:
push:
tags:
- 'v*.*.*' # 只在以 v 开头的标签推送时触发,例如 v1.0.0
+ workflow_dispatch:
jobs:
release:
@@ -41,7 +42,13 @@ jobs:
- name: Extract version from tag
id: get_version
run: |
- echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
+ if [[ "$GITHUB_REF" =~ ^refs/tags/v([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
+ echo "VERSION=${BASH_REMATCH[1]}" >> $GITHUB_ENV
+ echo "IS_VERSION=true" >> $GITHUB_ENV
+ else
+ echo "VERSION=latest" >> $GITHUB_ENV
+ echo "IS_VERSION=false" >> $GITHUB_ENV
+ fi
# 构建 xiaozhi-server 镜像
- name: Build and push xiaozhi-server
@@ -51,8 +58,7 @@ jobs:
file: Dockerfile-server
push: true
tags: |
- ghcr.io/${{ github.repository }}:server_${{ env.VERSION }}
- ghcr.io/${{ github.repository }}:server_latest
+ ${{ env.IS_VERSION == 'true' && format('ghcr.io/{0}:server_{1},ghcr.io/{0}:server_latest', github.repository, env.VERSION) || format('ghcr.io/{0}:server_latest', github.repository) }}
platforms: linux/amd64,linux/arm64
# 构建 manager-api 镜像
@@ -63,6 +69,5 @@ jobs:
file: Dockerfile-web
push: true
tags: |
- ghcr.io/${{ github.repository }}:web_${{ env.VERSION }}
- ghcr.io/${{ github.repository }}:web_latest
+ ${{ env.IS_VERSION == 'true' && format('ghcr.io/{0}:web_{1},ghcr.io/{0}:web_latest', github.repository, env.VERSION) || format('ghcr.io/{0}:web_latest', github.repository) }}
platforms: linux/amd64,linux/arm64
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 0a684e6a..9a07f445 100644
--- a/.gitignore
+++ b/.gitignore
@@ -155,7 +155,11 @@ main/manager-web/node_modules
main/xiaozhi-server/models/SenseVoiceSmall/model.pt
main/xiaozhi-server/models/sherpa-onnx*
my_wakeup_words.mp3
+!main/xiaozhi-server/config/assets/bind_code.wav
+!main/xiaozhi-server/config/assets/bind_not_found.wav
+!main/xiaozhi-server/config/assets/bind_code/*.wav
main/manager-api/.vscode
# Ignore webpack cache directory
-main/manager-web/.webpack_cache/
\ No newline at end of file
+main/manager-web/.webpack_cache/
+main/xiaozhi-server/mysql
diff --git a/README.md b/README.md
index c3bb8ee2..5479d020 100644
--- a/README.md
+++ b/README.md
@@ -11,10 +11,10 @@
-English
+English
· 简体中文
· 更新日志
-· 部署文档
+· 部署文档
· 反馈问题
@@ -126,13 +126,6 @@
---
-## 系统要求与部署前提 🖥️
-
-- **电脑或服务器**:建议 4 核 CPU、8G 内存的电脑。如果开启ASR也使用API,可运行在2核CPU、2G内存的服务器中。
-- **修改客户端接口**:请将本后端服务的接口地址更新至 客户端中。
-
----
-
## 警告 ⚠️
1、本项目为开源软件,本软件与对接的任何第三方API服务商(包括但不限于语音识别、大模型、语音合成等平台)均不存在商业合作关系,不为其服务质量及资金安全提供任何形式的担保。
@@ -152,32 +145,24 @@ server:
---
-## 部署方式 🚀
+## 部署文档
-### 一、[部署文档](./docs/Deployment.md)
+本项目提供两种部署方式,请根据您的具体需求选择:
-本项目支持以下三种部署方式,您可根据实际需求选择。
+#### 🚀 部署方式选择
-1. [Docker 快速部署](./docs/Deployment.md)
+| 部署方式 | 特点 | 适用场景 | Docker部署文档 | 源码部署文档 |
+|---------|------|---------|---------|---------|
+| **最简化安装** | 智能对话、IOT功能,数据存储在配置文件 | 低配置环境,无需数据库 | [Docker只运行Server](./docs/Deployment.md#%E6%96%B9%E5%BC%8F%E4%B8%80docker%E5%8F%AA%E8%BF%90%E8%A1%8Cserver) | [本地源码只运行Server](./docs/Deployment.md#%E6%96%B9%E5%BC%8F%E4%BA%8C%E6%9C%AC%E5%9C%B0%E6%BA%90%E7%A0%81%E5%8F%AA%E8%BF%90%E8%A1%8Cserver)|
+| **全模块安装** | 智能对话、IOT、OTA、智控台,数据存储在数据库 | 完整功能体验 |[Docker运行全模块](./docs/Deployment_all.md#%E6%96%B9%E5%BC%8F%E4%B8%80docker%E8%BF%90%E8%A1%8C%E5%85%A8%E6%A8%A1%E5%9D%97) | [本地源码运行全模块](./docs/Deployment_all.md#%E6%96%B9%E5%BC%8F%E4%BA%8C%E6%9C%AC%E5%9C%B0%E6%BA%90%E7%A0%81%E8%BF%90%E8%A1%8C%E5%85%A8%E6%A8%A1%E5%9D%97) |
-适合快速体验的普通用户,不需过多环境配置。缺点是,拉取镜像有点慢。视频教程可参考[美女大佬教你Docker部署](https://www.bilibili.com/video/BV1RNQnYDE5t)
-
-2. [借助 Docker 环境运行部署](./docs/Deployment.md#%E6%96%B9%E5%BC%8F%E4%BA%8C%E5%80%9F%E5%8A%A9docker%E7%8E%AF%E5%A2%83%E8%BF%90%E8%A1%8C%E9%83%A8%E7%BD%B2)
-
-适用于已安装 Docker 且希望对代码进行自定义修改的软件工程师。
-
-3. [本地源码运行](./docs/Deployment.md#%E6%96%B9%E5%BC%8F%E4%B8%89%E6%9C%AC%E5%9C%B0%E6%BA%90%E7%A0%81%E8%BF%90%E8%A1%8C)
-
-适合熟悉`Conda` 环境或希望从零搭建运行环境的用户。
-
-对于对响应速度要求较高的场景,推荐使用本地源码运行方式以降低额外开销。视频教程可参考[帅哥大佬教你源码部署](https://www.bilibili.com/video/BV1GvQWYZEd2)
-
-### 二、[固件编译](./docs/firmware-build.md)
-
-点这里查看[固件编译](./docs/firmware-build.md)的详细过程。
-
-烧录成功且联网成功后,通过唤醒词唤醒小智,留意server端输出的控制台信息。
+> 💡 提示:以下是按最新代码部署后的测试平台,有需要可烧录测试,并发为6个,每天会清空数据
+```
+智控台地址: https://2662r3426b.vicp.fun
+OTA接口地址: https://2662r3426b.vicp.fun/xiaozhi/ota/
+Websocket接口地址: wss://2662r3426b.vicp.fun/xiaozhi/v1/
+```
---
## 常见问题 ❓
@@ -185,52 +170,41 @@ server:
如遇到问题或产品建议反馈[点这里](docs/FAQ.md)。
---
-
-## 产品生态 👬
-小智是一个生态,当你使用这个产品时,也可以看看其他在这个生态圈的优秀项目
-
-- [小智安卓客户端](https://github.com/TOM88812/xiaozhi-android-client)
-
- 一个基于xiaozhi-server的Android、IOS语音对话应用,支持实时语音交互和文字对话。现在是flutter版本,打通IOS、Android端。
-- [小智电脑客户端](https://github.com/Huang-junsen/py-xiaozhi)
-
- 该项目提供了一个基于 Python 实现的小白 AI 客户端,使得在不具备实体硬件条件的情况下,依然能够体过代码体验小智 AI 的功能。主要功能包括 AI 语音交互、视觉多模态识别、IoT 设备集成、联网音乐播放、语音唤醒、自动对话模式、图形化界面、命令行模式、跨平台支持、音量控制、会话管理、加密音频传输、自动验证码处理等。
-- [小智Java服务端](https://github.com/joey-zhou/xiaozhi-esp32-server-java)
-
- 小智开源后端服务 Java 版本是一个基于 Java 的开源项目,它包括前后端的服务,旨在为用户提供一个完整的后端服务解决方案。
----
## 功能清单 ✨
### 已实现 ✅
-- **通信协议**
- 基于 `xiaozhi-esp32` 协议,通过 WebSocket 实现数据交互。
-- **对话交互**
- 支持唤醒对话、手动对话及实时打断。长时间无对话时自动休眠
-- **意图识别**
- 支持使用LLM意图识别、function call函数调用,减少硬编码意图判断
-- **多语言识别**
- 支持国语、粤语、英语、日语、韩语(默认使用 FunASR)。
-- **LLM 模块**
- 支持灵活切换 LLM 模块,默认使用 ChatGLMLLM,也可选用阿里百炼、DeepSeek、Ollama 等接口。
-- **TTS 模块**
- 支持 EdgeTTS(默认)、火山引擎豆包 TTS 等多种 TTS 接口,满足语音合成需求。
-- **记忆功能**
- 支持超长记忆、本地总结记忆、无记忆三种模式,满足不同场景需求。
-- **IOT功能**
- 支持管理注册设备IOT功能,支持基于对话上下文语境下的智能物联网控制。
+| 功能模块 | 描述 |
+|---------|------|
+| 通信协议 | 基于 `xiaozhi-esp32` 协议,通过 WebSocket 实现数据交互 |
+| 对话交互 | 支持唤醒对话、手动对话及实时打断。长时间无对话时自动休眠 |
+| 意图识别 | 支持使用LLM意图识别、function call函数调用,减少硬编码意图判断 |
+| 多语言识别 | 支持国语、粤语、英语、日语、韩语(默认使用 FunASR) |
+| LLM 模块 | 支持灵活切换 LLM 模块,默认使用 ChatGLMLLM,也可选用阿里百炼、DeepSeek、Ollama 等接口 |
+| TTS 模块 | 支持 EdgeTTS(默认)、火山引擎豆包 TTS 等多种 TTS 接口,满足语音合成需求 |
+| 记忆功能 | 支持超长记忆、本地总结记忆、无记忆三种模式,满足不同场景需求 |
+| IOT功能 | 支持管理注册设备IOT功能,支持基于对话上下文语境下的智能物联网控制 |
+| 智控台 | 提供Web管理界面,支持智能体管理、用户管理、系统配置等功能,方便管理员和用户进行管理 |
### 正在开发 🚧
-- 多种心情模式
-- 智控台webui
-
-想了解具体开发进度,[请点击这里](https://github.com/users/xinnan-tech/projects/3)
+想了解具体开发计划进度,[请点击这里](https://github.com/users/xinnan-tech/projects/3)
如果你是一名软件开发者,这里有一份[《致开发者的公开信》](docs/contributor_open_letter.md),欢迎加入!
---
+## 产品生态 👬
+小智是一个生态,当你使用这个产品时,也可以看看其他在这个生态圈的优秀项目
+
+| 项目名称 | 项目地址 | 项目描述 |
+|:---------------------|:--------|:--------|
+| 小智安卓客户端 | [xiaozhi-android-client](https://github.com/TOM88812/xiaozhi-android-client) | 一个基于xiaozhi-server的Android、IOS语音对话应用,支持实时语音交互和文字对话。 现在是flutter版本,打通IOS、Android端。 |
+| 小智电脑客户端 | [py-xiaozhi](https://github.com/Huang-junsen/py-xiaozhi) | 该项目提供了一个基于 Python 实现的小白 AI 客户端,使得在不具备实体硬件条件的情况下, 依然能够体过代码体验小智 AI 的功能。 |
+| 小智Java服务端 | [xiaozhi-esp32-server-java](https://github.com/joey-zhou/xiaozhi-esp32-server-java) | 小智开源后端服务 Java 版本是一个基于 Java 的开源项目。 它包括前后端的服务,旨在为用户提供一个完整的后端服务解决方案。 |
+
+---
+
## 本项目支持的平台/组件列表 📋
### LLM 语言模型
@@ -293,10 +267,17 @@ server:
## 鸣谢 🙏
-- 本项目受 [百聆语音对话机器人](https://github.com/wwbin2017/bailing) 启发,并在其基础上实现。
-- 感谢 [十方融海](https://www.tenclass.com/) 对小智通讯协议提供的详尽文档支持。
+| Logo | 项目/公司 | 说明 |
+|:---:|:---:|:---|
+| | [百聆语音对话机器人](https://github.com/wwbin2017/bailing) | 本项目受[百聆语音对话机器人](https://github.com/wwbin2017/bailing)启发,并在其基础上实现 |
+| | [十方融海](https://www.tenclass.com/) | 感谢[十方融海](https://www.tenclass.com/)为小智生态制定了标准的通讯协议、多设备兼容性方案及高并发场景实践示范;为本项目提供了全链路技术文档支持 |
+| | [玄凤科技](https://github.com/Eric0308) | 感谢[玄凤科技](https://github.com/Eric0308)贡献函数调用框架、MCP通信协议及插件化调用机制的实现代码,通过标准化的指令调度体系与动态扩展能力,显著提升了前端设备(IoT)的交互效率和功能延展性 |
+| | [汇远设计](http://ui.kwd988.net/) | 感谢[汇远设计](http://ui.kwd988.net/)为本项目提供专业视觉解决方案,用其服务超千家企业的设计实战经验,赋能本项目产品用户体验 |
+| | [西安勤人信息科技](https://www.029app.com/) | 感谢[西安勤人信息科技](https://www.029app.com/)深化本项目视觉体系,确保整体设计风格在多场景应用中的一致性和扩展性 |
+
+
diff --git a/README_en.md b/README_en.md
deleted file mode 100644
index 1dd70554..00000000
--- a/README_en.md
+++ /dev/null
@@ -1,302 +0,0 @@
-[](https://github.com/xinnan-tech/xiaozhi-esp32-server)
-
-
-Xiaozhi Backend Server xiaozhi-esp32-server
-
-
-
-This project provides backend services for the open-source smart hardware project
-xiaozhi-esp32
-Implemented in Python according to the Xiaozhi Communication Protocol
-Helping you quickly set up your Xiaozhi server
-
-
-
-简体中文
-· English
-· Changelog
-· Deployment Guide
-· Report Issues
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
----
-
-## Target Users 👥
-
-This project requires ESP32 hardware devices. If you have purchased ESP32-related hardware, successfully connected to Brother Xia's backend service, and wish to set up your own `xiaozhi-esp32` backend service, then this project is perfect for you.
-
-Want to see it in action? Check out these videos 🎥
-
-
-
----
-
-## System Requirements and Prerequisites 🖥️
-
-- **Computer or Server**: Recommended 4-core CPU, 8GB RAM computer. If using ASR with API, can run on a 2-core CPU, 2GB RAM server.
-- **Update Client Interface**: Please update the backend service interface address in the client.
-
----
-
-## Warning ⚠️
-
-1. This is open-source software. This software and any third-party API service providers it interfaces with (including but not limited to speech recognition, large language models, speech synthesis, and other platforms) have no commercial partnership. We do not provide any form of guarantee for their service quality or financial security.
-We recommend users prioritize service providers with relevant business licenses and carefully read their service agreements and privacy policies. This software does not host any account keys, does not participate in fund transfers, and does not bear the risk of recharge fund losses.
-
-2. This project is relatively new and has not yet passed network security testing. Please do not use it in production environments. If you deploy this project for learning purposes in a public network environment, please make sure to enable protection in the `config.yaml` configuration file:
-
-```yaml
-server:
- auth:
- # Enable protection
- enabled: true
-```
-
-After enabling protection, you need to verify the machine's token or MAC address according to actual circumstances. Please refer to the configuration documentation for details.
-
----
-
-## Deployment Methods 🚀
-
-### I. [Deployment Guide](./docs/Deployment.md)
-
-This project supports three deployment methods. You can choose based on your actual needs.
-
-1. [Quick Docker Deployment](./docs/Deployment.md)
-
-Suitable for regular users who want to quickly experience without much environment configuration. The downside is that pulling the image can be slow. Video tutorial available: [Beautiful expert teaches Docker deployment](https://www.bilibili.com/video/BV1RNQnYDE5t)
-
-2. [Deploy Using Docker Environment](./docs/Deployment.md#%E6%96%B9%E5%BC%8F%E4%BA%8C%E5%80%9F%E5%8A%A9docker%E7%8E%AF%E5%A2%83%E8%BF%90%E8%A1%8C%E9%83%A8%E7%BD%B2)
-
-For software engineers who have Docker installed and want to make custom code modifications.
-
-3. [Local Source Code Run](./docs/Deployment.md#%E6%96%B9%E5%BC%8F%E4%B8%89%E6%9C%AC%E5%9C%B0%E6%BA%90%E7%A0%81%E8%BF%90%E8%A1%8C)
-
-Suitable for users familiar with `Conda` environment or who want to build the running environment from scratch.
-
-For scenarios requiring higher response speed, we recommend using the local source code run method to reduce additional overhead. Video tutorial available: [Handsome expert teaches source code deployment](https://www.bilibili.com/video/BV1GvQWYZEd2)
-
-### II. [Firmware Compilation](./docs/firmware-build.md)
-
-Click here to view the detailed process of [firmware compilation](./docs/firmware-build.md).
-
-After successful flashing and network connection, wake up Xiaozhi using the wake word and pay attention to the console output on the server side.
-
----
-
-## Common Questions ❓
-
-For issues or product suggestions, please [click here](docs/FAQ.md).
-
----
-
-## Product Ecosystem 👬
-Xiaozhi is an ecosystem. When using this product, you might want to check out other excellent projects in this ecosystem:
-
-- [Xiaozhi Android Client](https://github.com/TOM88812/xiaozhi-android-client)
- A voice dialogue application based on xiaozhi-server for Android and iOS, supporting real-time voice interaction and text dialogue. Now in Flutter version, supporting both iOS and Android.
-- [Xiaozhi PC Client](https://github.com/Huang-junsen/py-xiaozhi)
- This project provides a Python-based Xiaobai AI client, allowing you to experience Xiaozhi AI features through code even without physical hardware. Main features include AI voice interaction, visual multimodal recognition, IoT device integration, online music playback, voice wake-up, automatic dialogue mode, graphical interface, command-line mode, cross-platform support, volume control, session management, encrypted audio transmission, automatic verification code processing, etc.
-- [Xiaozhi Java Server](https://github.com/joey-zhou/xiaozhi-esp32-server-java)
-
- The Xiaozhi open-source backend service Java version is a Java-based open-source project that includes both frontend and backend services, aiming to provide users with a complete backend service solution.
----
-## Feature List ✨
-
-### Implemented ✅
-
-- **Communication Protocol**
- Based on `xiaozhi-esp32` protocol, implementing data interaction through WebSocket.
-- **Dialogue Interaction**
- Supports wake-up dialogue, manual dialogue, and real-time interruption. Automatically sleeps after long periods without dialogue
-- **Intent Recognition**
- Supports LLM intent recognition and function call, reducing hard-coded intent judgment
-- **Multi-language Recognition**
- Supports Mandarin, Cantonese, English, Japanese, Korean (default using FunASR).
-- **LLM Module**
- Supports flexible switching of LLM modules, default using ChatGLMLLM, can also use Alibaba Bailian, DeepSeek, Ollama, and other interfaces.
-- **TTS Module**
- Supports EdgeTTS (default), Volcano Engine Doubao TTS, and other TTS interfaces to meet speech synthesis needs.
-- **Memory Function**
- Supports ultra-long memory, local summary memory, and no memory modes to meet different scenario needs.
-- **IOT Function**
- Supports managing registered device IOT functions, supporting intelligent IoT control based on dialogue context.
-
-### Under Development 🚧
-
-- Multiple mood modes
-- Smart control panel webui
-
-To learn about specific development progress, [click here](https://github.com/users/xinnan-tech/projects/3)
-
-If you are a software developer, here's an [Open Letter to Developers](docs/contributor_open_letter.md), welcome to join!
-
----
-
-## Supported Platforms/Components List 📋
-
-### LLM Language Models
-
-| Usage Method | Supported Platforms | Free Platforms |
-|:---:|:---:|:---:|
-| openai interface call | Alibaba Bailian, Volcano Engine Doubao, DeepSeek, Zhipu ChatGLM, Gemini | Zhipu ChatGLM, Gemini |
-| ollama interface call | Ollama | - |
-| dify interface call | Dify | - |
-| fastgpt interface call | Fastgpt | - |
-| coze interface call | Coze | - |
-
-In fact, any LLM supporting openai interface calls can be integrated.
-
----
-
-### TTS Speech Synthesis
-
-| Usage Method | Supported Platforms | Free Platforms |
-|:---:|:---:|:---:|
-| Interface Call | EdgeTTS, Volcano Engine Doubao TTS, Tencent Cloud, Alibaba Cloud TTS, CosyVoiceSiliconflow, TTS302AI, CozeCnTTS, GizwitsTTS, ACGNTTS, OpenAITTS | EdgeTTS, CosyVoiceSiliconflow(partial) |
-| Local Service | FishSpeech, GPT_SOVITS_V2, GPT_SOVITS_V3, MinimaxTTS | FishSpeech, GPT_SOVITS_V2, GPT_SOVITS_V3, MinimaxTTS |
-
----
-
-### VAD Voice Activity Detection
-
-| Type | Platform Name | Usage Method | Pricing Model | Notes |
-|:---:|:---------:|:----:|:----:|:--:|
-| VAD | SileroVAD | Local Use | Free | |
-
----
-
-### ASR Speech Recognition
-
-| Usage Method | Supported Platforms | Free Platforms |
-|:---:|:---:|:---:|
-| Local Use | FunASR, SherpaASR | FunASR, SherpaASR |
-| Interface Call | DoubaoASR | - |
-
----
-
-### Memory Storage
-
-| Type | Platform Name | Usage Method | Pricing Model | Notes |
-|:------:|:---------------:|:----:|:---------:|:--:|
-| Memory | mem0ai | Interface Call | 1000 times/month quota | |
-| Memory | mem_local_short | Local Summary | Free | |
-
----
-
-### Intent Recognition
-
-| Type | Platform Name | Usage Method | Pricing Model | Notes |
-|:------:|:-------------:|:----:|:-------:|:---------------------:|
-| Intent | intent_llm | Interface Call | Based on LLM pricing | Intent recognition through large models, highly generalizable |
-| Intent | function_call | Interface Call | Based on LLM pricing | Intent completion through large model function calls, fast and effective |
-
----
-
-## Acknowledgments 🙏
-
-- This project was inspired by [Bailing Voice Dialogue Robot](https://github.com/wwbin2017/bailing) and implemented based on it.
-- Thanks to [Tenclass](https://www.tenclass.com/) for providing detailed documentation support for the Xiaozhi communication protocol.
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/Deployment.md b/docs/Deployment.md
index 7338a981..097aea59 100644
--- a/docs/Deployment.md
+++ b/docs/Deployment.md
@@ -1,6 +1,6 @@
-# 部署方案参考
-
-# 方式一:docker快速部署
+# 部署架构图
+
+# 方式一:Docker只运行Server
docker镜像已支持x86架构、arm64架构的CPU,支持在国产操作系统上运行。
@@ -40,7 +40,7 @@ chmod +x docker-setup.sh
>
> 执行完成后,请按照提示配置 API 密钥。
-当你一切顺利完成以上操作后,继续操作[配置项目文件](#3-配置项目文件)
+当你一切顺利完成以上操作后,继续操作[配置项目文件](#2-配置项目文件)
### 1.2 手动部署
@@ -102,14 +102,14 @@ xiaozhi-server
如果你的文件目录结构也是上面的,就继续往下。如果不是,你就再仔细看看是不是漏操作了什么。
-## 3. 配置项目文件
+## 2. 配置项目文件
接下里,程序还不能直接运行,你需要配置一下,你到底使用的是什么模型。你可以看这个教程:
[跳转到配置项目文件](#配置项目)
配置完项目文件后,回到本教程继续往下。
-## 4. 执行docker命令
+## 3. 执行docker命令
打开命令行工具,使用`终端`或`命令行`工具 进入到你的`xiaozhi-server`,执行以下命令
@@ -137,50 +137,15 @@ docker logs -f xiaozhi-esp32-server
```
docker stop xiaozhi-esp32-server
docker rm xiaozhi-esp32-server
+docker stop xiaozhi-esp32-server-web
+docker rm xiaozhi-esp32-server-web
docker rmi ghcr.nju.edu.cn/xinnan-tech/xiaozhi-esp32-server:server_latest
+docker rmi ghcr.nju.edu.cn/xinnan-tech/xiaozhi-esp32-server:web_latest
```
5.3、重新按docker方式部署
-# 方式二:借助Docker环境运行部署
-
-开发人员如果不想安装`conda`环境,可以使用这种方法管理好依赖。
-
-## 1.克隆项目
-
-## 2.[跳转到下载语音识别模型文件](#模型文件)
-
-## 3.[跳转到配置项目文件](#配置项目)
-
-## 4.运行docker
-
-修改完配置后,打开命令行工具,`cd`进入到你的`main/xiaozhi-server`下,执行以下命令
-
-```sh
-docker run -it --name xiaozhi-env --restart always --security-opt seccomp:unconfined \
- -p 8000:8000 \
- -p 8002:8002 \
- -v ./:/app \
- kalicyh/python:xiaozhi
-```
-
-然后就和正常开发一样了
-
-## 5.安装依赖
-
-在刚刚的打开的终端运行
-
-```sh
-pip install -r requirements.txt
-```
-
-## 6.运行项目
-
-```sh
-python app.py
-```
-
-# 方式三:本地源码运行
+# 方式二:本地源码只运行Server
## 1.安装基础环境
@@ -259,7 +224,7 @@ python app.py
## 配置项目
如果你的`xiaozhi-server`目录没有`data`,你需要创建`data`目录。
-如果你的`data`下面没有`.config.yaml`文件,你可以把源码目录下的`config.yaml`文件复制一份,重命名为`.config.yaml`
+如果你的`data`下面没有`.config.yaml`文件,你可以把`xiaozhi-server`目录下的`config.yaml`文件复制到`data`,并重命名为`.config.yaml`
修改`xiaozhi-server`下`data`目录下的`.config.yaml`文件,配置本项目必须的一个配置。
@@ -311,15 +276,17 @@ LLM:
如果你能看到,类似以下日志,则是本项目服务启动成功的标志。
```
-25-02-23 12:01:09[core.websocket_server] - INFO - Server is running at ws://xxx.xx.xx.xx:8000
+25-02-23 12:01:09[core.websocket_server] - INFO - Server is running at ws://xxx.xx.xx.xx:8000/xiaozhi/v1/
25-02-23 12:01:09[core.websocket_server] - INFO - =======上面的地址是websocket协议地址,请勿用浏览器访问=======
+25-02-23 12:01:09[core.websocket_server] - INFO - 如想测试websocket请用谷歌浏览器打开test目录下的test_page.html
+25-02-23 12:01:09[core.websocket_server] - INFO - =======================================================
```
正常来说,如果您是通过源码运行本项目,日志会有你的接口地址信息。
但是如果你用docker部署,那么你的日志里给出的接口地址信息就不是真实的接口地址。
最正确的方法,是根据电脑的局域网IP来确定你的接口地址。
-如果你的电脑的局域网IP比如是`192.168.1.25`,那么你的接口地址就是:`ws://192.168.1.25:8000`。
+如果你的电脑的局域网IP比如是`192.168.1.25`,那么你的接口地址就是:`ws://192.168.1.25:8000/xiaozhi/v1/`。
这个信息很有用的,后面`编译esp32固件`需要用到。
@@ -328,14 +295,16 @@ LLM:
以下是一些常见问题,供参考:
-[1、为什么我说的话,小智识别出来很多韩文、日文、英文](./FAQ.md#1%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E8%AF%B4%E7%9A%84%E8%AF%9D%E5%B0%8F%E6%99%BA%E8%AF%86%E5%88%AB%E5%87%BA%E6%9D%A5%E5%BE%88%E5%A4%9A%E9%9F%A9%E6%96%87%E6%97%A5%E6%96%87%E8%8B%B1%E6%96%87)
+[1、为什么我说的话,小智识别出来很多韩文、日文、英文](./FAQ.md)
-[2、为什么会出现“TTS 任务出错 文件不存在”?](./FAQ.md#1%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E8%AF%B4%E7%9A%84%E8%AF%9D%E5%B0%8F%E6%99%BA%E8%AF%86%E5%88%AB%E5%87%BA%E6%9D%A5%E5%BE%88%E5%A4%9A%E9%9F%A9%E6%96%87%E6%97%A5%E6%96%87%E8%8B%B1%E6%96%87)
+[2、为什么会出现“TTS 任务出错 文件不存在”?](./FAQ.md)
-[3、TTS 经常失败,经常超时](./FAQ.md#1%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E8%AF%B4%E7%9A%84%E8%AF%9D%E5%B0%8F%E6%99%BA%E8%AF%86%E5%88%AB%E5%87%BA%E6%9D%A5%E5%BE%88%E5%A4%9A%E9%9F%A9%E6%96%87%E6%97%A5%E6%96%87%E8%8B%B1%E6%96%87)
+[3、TTS 经常失败,经常超时](./FAQ.md)
-[4、如何提高小智对话响应速度?](./FAQ.md#1%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E8%AF%B4%E7%9A%84%E8%AF%9D%E5%B0%8F%E6%99%BA%E8%AF%86%E5%88%AB%E5%87%BA%E6%9D%A5%E5%BE%88%E5%A4%9A%E9%9F%A9%E6%96%87%E6%97%A5%E6%96%87%E8%8B%B1%E6%96%87)
+[4、使用Wifi能连接自建服务器,但是4G模式却接不上](./FAQ.md)
-[5、我说话很慢,停顿时小智老是抢话](./FAQ.md#1%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E8%AF%B4%E7%9A%84%E8%AF%9D%E5%B0%8F%E6%99%BA%E8%AF%86%E5%88%AB%E5%87%BA%E6%9D%A5%E5%BE%88%E5%A4%9A%E9%9F%A9%E6%96%87%E6%97%A5%E6%96%87%E8%8B%B1%E6%96%87)
+[5、如何提高小智对话响应速度?](./FAQ.md)
-[6、我想通过小智控制电灯、空调、远程开关机等操作](./FAQ.md#1%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E8%AF%B4%E7%9A%84%E8%AF%9D%E5%B0%8F%E6%99%BA%E8%AF%86%E5%88%AB%E5%87%BA%E6%9D%A5%E5%BE%88%E5%A4%9A%E9%9F%A9%E6%96%87%E6%97%A5%E6%96%87%E8%8B%B1%E6%96%87)
+[6、我说话很慢,停顿时小智老是抢话](./FAQ.md)
+
+[7、我想通过小智控制电灯、空调、远程开关机等操作](./FAQ.md)
diff --git a/docs/Deployment_all.md b/docs/Deployment_all.md
new file mode 100644
index 00000000..8c6048c5
--- /dev/null
+++ b/docs/Deployment_all.md
@@ -0,0 +1,423 @@
+# 部署架构图
+
+# 方式一:Docker运行全模块
+docker镜像已支持x86架构、arm64架构的CPU,支持在国产操作系统上运行。
+
+## 1. 安装docker
+
+如果您的电脑还没安装docker,可以按照这里的教程安装:[docker安装](https://www.runoob.com/docker/ubuntu-docker-install.html)
+
+#### 1.1 创建目录
+
+安装完后,你需要为这个项目找一个安放配置文件的目录,例如我们可以新建一个文件夹叫`xiaozhi-server`。
+
+创建好目录后,你需要在`xiaozhi-server`下面创建`data`文件夹和`models`文件夹,`models`下面还要再创建`SenseVoiceSmall`文件夹。
+
+最终目录结构如下所示:
+
+```
+xiaozhi-server
+ ├─ data
+ ├─ models
+ ├─ SenseVoiceSmall
+```
+
+#### 1.2 下载语音识别模型文件
+
+本项目语音识别模型,默认使用`SenseVoiceSmall`模型,进行语音转文字。因为模型较大,需要独立下载,下载后把`model.pt`
+文件放在`models/SenseVoiceSmall`
+目录下。下面两个下载路线任选一个。
+
+- 线路一:阿里魔塔下载[SenseVoiceSmall](https://modelscope.cn/models/iic/SenseVoiceSmall/resolve/master/model.pt)
+- 线路二:百度网盘下载[SenseVoiceSmall](https://pan.baidu.com/share/init?surl=QlgM58FHhYv1tFnUT_A8Sg&pwd=qvna) 提取码:
+ `qvna`
+
+
+#### 1.3 下载配置文件
+
+你需要下载两个配置文件:`docker-compose_all.yaml` 和 `config_from_api.yaml`。需要从项目仓库下载这两个文件。
+
+##### 1.3.1 下载 docker-compose_all.yaml
+
+用浏览器打开[这个链接](../main/xiaozhi-server/docker-compose_all.yml)。
+
+在页面的右侧找到名称为`RAW`按钮,在`RAW`按钮的旁边,找到下载的图标,点击下载按钮,下载`docker-compose_all.yml`文件。 把文件下载到你的
+`xiaozhi-server`中。
+
+或者直接执行 `wget https://raw.githubusercontent.com/xinnan-tech/xiaozhi-esp32-server/refs/heads/main/main/xiaozhi-server/docker-compose_all.yml` 下载。
+
+下载完后,回到本教程继续往下。
+
+##### 1.3.2 下载 config_from_api.yaml
+
+用浏览器打开[这个链接](../main/xiaozhi-server/config_from_api.yaml)。
+
+在页面的右侧找到名称为`RAW`按钮,在`RAW`按钮的旁边,找到下载的图标,点击下载按钮,下载`config_from_api.yaml`文件。 把文件下载到你的
+`xiaozhi-server`下面的`data`文件夹中,然后把`config_from_api.yaml`文件重命名为`.config.yaml`。
+
+或者直接执行 `wget https://raw.githubusercontent.com/xinnan-tech/xiaozhi-esp32-server/refs/heads/main/main/xiaozhi-server/config_from_api.yaml` 下载保存。
+
+下载完配置文件后,我们确认一下整个`xiaozhi-server`里面的文件如下所示:
+
+```
+xiaozhi-server
+ ├─ docker-compose_all.yml
+ ├─ data
+ ├─ .config.yaml
+ ├─ models
+ ├─ SenseVoiceSmall
+ ├─ model.pt
+```
+
+如果你的文件目录结构也是上面的,就继续往下。如果不是,你就再仔细看看是不是漏操作了什么。
+
+## 2. 备份数据
+
+如果你之前已经成功运行智控台,如果上面保存有你的密钥信息,请先从智控台上拷贝重要数据下来。因为升级过程中,有可能会覆盖原来的数据。
+
+## 3. 清除历史版本镜像和容器
+接下来打开命令行工具,使用`终端`或`命令行`工具 进入到你的`xiaozhi-server`,执行以下命令
+
+```
+docker compose -f docker-compose_all.yml down
+
+docker stop xiaozhi-esp32-server
+docker rm xiaozhi-esp32-server
+
+docker stop xiaozhi-esp32-server-web
+docker rm xiaozhi-esp32-server-web
+
+docker stop xiaozhi-esp32-server-db
+docker rm xiaozhi-esp32-server-db
+
+docker stop xiaozhi-esp32-server-redis
+docker rm xiaozhi-esp32-server-redis
+
+docker rmi ghcr.nju.edu.cn/xinnan-tech/xiaozhi-esp32-server:server_latest
+docker rmi ghcr.nju.edu.cn/xinnan-tech/xiaozhi-esp32-server:web_latest
+```
+
+## 4. 运行程序
+执行以下命令启动新版本容器
+
+```
+docker compose -f docker-compose_all.yml up -d
+```
+
+执行完后,再执行以下命令,查看日志信息。
+
+```
+docker logs -f xiaozhi-esp32-server-web
+```
+
+当你看到输出日志时,说明你的`智控台`启动成功了。
+
+```
+2025-xx-xx 22:11:12.445 [main] INFO c.a.d.s.b.a.DruidDataSourceAutoConfigure - Init DruidDataSource
+2025-xx-xx 21:28:53.873 [main] INFO xiaozhi.AdminApplication - Started AdminApplication in 16.057 seconds (process running for 17.941)
+http://localhost:8002/xiaozhi/doc.html
+```
+
+请注意此刻仅是`智控台`能运行,如果8000端口`xiaozhi-esp32-server`报错,先不要理会。
+
+这时,你需要使用浏览器,打开`智控台`,链接:http://127.0.0.1:8002 ,注册第一个用户。第一个用户即是超级管理员,以后的用户都是普通用户。普通用户只能绑定设备和配置智能体;超级管理员可以进行模型管理、用户管理、参数配置等功能。
+
+接下来要做两件重要的事情:
+
+### 第一件重要的事情
+
+使用超级管理员账号,登录系统,在顶部菜单找到`参数管理`,找到列表中第三条数据,参数编码是`server.secret`,复制它到`参数值`。
+
+`server.secret`需要说明一下,这个`参数值`很重要,作用是让我们的`Server`端连接`manager-api`。`server.secret`是每次从零部署manager模块时,会自动随机生成的密钥。
+
+复制`参数值`后,打开`xiaozhi-server`下的`data`目录的`.config.yaml`文件。此刻你的配置文件内容应该是这样的:
+
+```
+manager-api:
+ url: http://127.0.0.1:8002/xiaozhi
+ secret: 你的server.secret值
+```
+1、把你刚才从`智控台`复制过来的`server.secret`的`参数值`复制到`.config.yaml`文件里的`secret`里。
+2、注意,把`url`改成下面的`http://xiaozhi-esp32-server-web:8002/xiaozhi`
+
+类似这样的效果
+```
+manager-api:
+ url: http://xiaozhi-esp32-server-web:8002/xiaozhi
+ secret: 12345678-xxxx-xxxx-xxxx-123456789000
+```
+
+保存好后,继续往下做第二件重要的事情
+
+### 第二件重要的事情
+
+使用超级管理员账号,登录系统,在顶部菜单找到`模型配置`,然后在左侧栏点击`大语言模型`,找到第一条数据`智谱AI`,点击`修改`按钮,
+弹出修改框后,将你注册到的`智谱AI`的密钥填写到`API密钥`中。然后点击保存。
+
+## 5.重启xiaozhi-esp32-server
+
+接下来打开命令行工具,使用`终端`或`命令行`工具 输入
+```
+docker restart xiaozhi-esp32-server
+docker logs -f xiaozhi-esp32-server
+```
+如果你能看到,类似以下日志,则是Server启动成功的标志。
+
+```
+25-02-23 12:01:09[core.websocket_server] - INFO - Server is running at ws://xxx.xx.xx.xx:8000/xiaozhi/v1/
+25-02-23 12:01:09[core.websocket_server] - INFO - =======上面的地址是websocket协议地址,请勿用浏览器访问=======
+25-02-23 12:01:09[core.websocket_server] - INFO - 如想测试websocket请用谷歌浏览器打开test目录下的test_page.html
+25-02-23 12:01:09[core.websocket_server] - INFO - =======================================================
+```
+
+由于你是全模块部署,因此你有两个重要的接口需要写入到esp32中。
+
+OTA接口:
+```
+http://你电脑局域网的ip:8002/xiaozhi/ota/
+```
+
+Websocket接口:
+```
+ws://你电脑局域网的ip:8000/xiaozhi/v1/
+```
+
+接下来,你就可以开始 [编译esp32固件](firmware-build.md)了。
+
+
+# 方式二:本地源码运行全模块
+
+## 1.安装MySQL数据库
+
+如果本机已经安装了MySQL,可以直接在数据库中创建名为`xiaozhi_esp32_server`的数据库。
+
+```sql
+CREATE DATABASE xiaozhi_esp32_server CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+```
+
+如果还没有MySQL,你可以通过docker安装mysql
+
+```
+docker run --name xiaozhi-esp32-server-db -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -e MYSQL_DATABASE=xiaozhi_esp32_server -e MYSQL_INITDB_ARGS="--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci" -d mysql:latest
+```
+
+## 2.安装redis
+
+如果还没有Redis,你可以通过docker安装redis
+
+```
+docker run --name xiaozhi-esp32-server-redis -d -p 6379:6379 redis
+```
+
+## 3.运行manager-api程序
+
+3.1 安装JDK21,设置JDK环境变量
+
+3.2 安装Maven,设置Maven环境变量
+
+3.3 使用Vscode编程工具,安装好Java环境相关插件
+
+3.4 使用Vscode编程工具加载manager-api模块
+
+在`src/main/resources/application-dev.yml`中配置数据库连接信息
+
+```
+spring:
+ datasource:
+ username: root
+ password: 123456
+```
+在`src/main/resources/application-dev.yml`中配置Redis连接信息
+```
+spring:
+ data:
+ redis:
+ host: localhost
+ port: 6379
+ password:
+ database: 0
+```
+
+3.5 运行主程序
+
+本项目为SpringBoot项目,启动方式为:
+打开`Application.java`运行`Main`方法启动
+
+```
+路径地址:
+src/main/java/xiaozhi/AdminApplication.java
+```
+
+当你看到输出日志时,说明你的`manager-api`启动成功了。
+
+```
+2025-xx-xx 22:11:12.445 [main] INFO c.a.d.s.b.a.DruidDataSourceAutoConfigure - Init DruidDataSource
+2025-xx-xx 21:28:53.873 [main] INFO xiaozhi.AdminApplication - Started AdminApplication in 16.057 seconds (process running for 17.941)
+http://localhost:8002/xiaozhi/doc.html
+```
+
+## 4.运行manager-web程序
+
+4.1 安装nodejs
+
+4.2 使用Vscode编程工具加载manager-web模块
+
+终端命令进入manager-web目录下
+
+```
+npm install
+```
+然后启动
+```
+npm run serve
+```
+
+请注意,如果你的manager-api的接口不在`http://localhost:8002`,请在开发时,修改
+`main/manager-web/.env.development`中的路径
+
+运行成功后,你需要使用浏览器,打开`智控台`,链接:http://127.0.0.1:8001 ,注册第一个用户。第一个用户即是超级管理员,以后的用户都是普通用户。普通用户只能绑定设备和配置智能体;超级管理员可以进行模型管理、用户管理、参数配置等功能。
+
+
+重要:注册成功后,使用超级管理员账号,登录系统,在顶部菜单找到`模型配置`,然后在左侧栏点击`大语言模型`,找到第一条数据`智谱AI`,点击`修改`按钮,
+弹出修改框后,将你注册到的`智谱AI`的密钥填写到`API密钥`中。然后点击保存。
+
+重要:注册成功后,使用超级管理员账号,登录系统,在顶部菜单找到`模型配置`,然后在左侧栏点击`大语言模型`,找到第一条数据`智谱AI`,点击`修改`按钮,
+弹出修改框后,将你注册到的`智谱AI`的密钥填写到`API密钥`中。然后点击保存。
+
+重要:注册成功后,使用超级管理员账号,登录系统,在顶部菜单找到`模型配置`,然后在左侧栏点击`大语言模型`,找到第一条数据`智谱AI`,点击`修改`按钮,
+弹出修改框后,将你注册到的`智谱AI`的密钥填写到`API密钥`中。然后点击保存。
+
+## 5.安装Python环境
+
+本项目使用`conda`管理依赖环境。如果不方便安装`conda`,需要根据实际的操作系统安装好`libopus`和`ffmpeg`。
+如果确定使用`conda`,则安装好后,开始执行以下命令。
+
+重要提示!windows 用户,可以通过安装`Anaconda`来管理环境。安装好`Anaconda`后,在`开始`那里搜索`anaconda`相关的关键词,
+找到`Anaconda Prpmpt`,使用管理员身份运行它。如下图。
+
+
+
+运行之后,如果你能看到命令行窗口前面有一个(base)字样,说明你成功进入了`conda`环境。那么你就可以执行以下命令了。
+
+
+
+```
+conda remove -n xiaozhi-esp32-server --all -y
+conda create -n xiaozhi-esp32-server python=3.10 -y
+conda activate xiaozhi-esp32-server
+
+# 添加清华源通道
+conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
+conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free
+conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
+
+conda install libopus -y
+conda install ffmpeg -y
+```
+
+请注意,以上命令,不是一股脑执行就成功的,你需要一步步执行,每一步执行完后,都检查一下输出的日志,查看是否成功。
+
+## 6.安装本项目依赖
+
+你先要下载本项目源码,源码可以通过`git clone`命令下载,如果你不熟悉`git clone`命令。
+
+你可以用浏览器打开这个地址`https://github.com/xinnan-tech/xiaozhi-esp32-server.git`
+
+打开完,找到页面中一个绿色的按钮,写着`Code`的按钮,点开它,然后你就看到`Download ZIP`的按钮。
+
+点击它,下载本项目源码压缩包。下载到你电脑后,解压它,此时它的名字可能叫`xiaozhi-esp32-server-main`
+你需要把它重命名成`xiaozhi-esp32-server`,在这个文件里,进入到`main`文件夹,再进入到`xiaozhi-server`,好了请记住这个目录`xiaozhi-server`。
+
+```
+# 继续使用conda环境
+conda activate xiaozhi-esp32-server
+# 进入到你的项目根目录,再进入main/xiaozhi-server
+cd main/xiaozhi-server
+pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
+pip install -r requirements.txt
+```
+
+### 7.下载语音识别模型文件
+
+本项目语音识别模型,默认使用`SenseVoiceSmall`模型,进行语音转文字。因为模型较大,需要独立下载,下载后把`model.pt`
+文件放在`models/SenseVoiceSmall`
+目录下。下面两个下载路线任选一个。
+
+- 线路一:阿里魔塔下载[SenseVoiceSmall](https://modelscope.cn/models/iic/SenseVoiceSmall/resolve/master/model.pt)
+- 线路二:百度网盘下载[SenseVoiceSmall](https://pan.baidu.com/share/init?surl=QlgM58FHhYv1tFnUT_A8Sg&pwd=qvna) 提取码:
+ `qvna`
+
+## 8.配置项目文件
+
+使用超级管理员账号,登录智控台 http://127.0.0.1:8001 ,在顶部菜单找到`参数管理`,找到列表中第三条数据,参数编码是`server.secret`,复制它到`参数值`。
+
+`server.secret`需要说明一下,这个`参数值`很重要,作用是让我们的`Server`端连接`manager-api`。`server.secret`是每次从零部署manager模块时,会自动随机生成的密钥。
+
+如果你的`xiaozhi-server`目录没有`data`,你需要创建`data`目录。
+如果你的`data`下面没有`.config.yaml`文件,你可以把`xiaozhi-server`目录下的`config_from_api.yaml`文件复制到`data`,并重命名为`.config.yaml`
+
+复制`参数值`后,打开`xiaozhi-server`下的`data`目录的`.config.yaml`文件。此刻你的配置文件内容应该是这样的:
+
+```
+manager-api:
+ url: http://127.0.0.1:8002/xiaozhi
+ secret: 你的server.secret值
+```
+
+把你刚才从`智控台`复制过来的`server.secret`的`参数值`复制到`.config.yaml`文件里的`secret`里。
+
+类似这样的效果
+```
+manager-api:
+ url: http://127.0.0.1:8002/xiaozhi
+ secret: 12345678-xxxx-xxxx-xxxx-123456789000
+```
+
+## 5.运行项目
+
+```
+# 确保在xiaozhi-server目录下执行
+conda activate xiaozhi-esp32-server
+python app.py
+```
+
+如果你能看到,类似以下日志,则是本项目服务启动成功的标志。
+
+```
+25-02-23 12:01:09[core.websocket_server] - INFO - Server is running at ws://xxx.xx.xx.xx:8000/xiaozhi/v1/
+25-02-23 12:01:09[core.websocket_server] - INFO - =======上面的地址是websocket协议地址,请勿用浏览器访问=======
+25-02-23 12:01:09[core.websocket_server] - INFO - 如想测试websocket请用谷歌浏览器打开test目录下的test_page.html
+25-02-23 12:01:09[core.websocket_server] - INFO - =======================================================
+```
+
+由于你是全模块部署,因此你有两个重要的接口需要写入到esp32中。
+
+OTA接口:
+```
+http://你电脑局域网的ip:8002/xiaozhi/ota/
+```
+
+Websocket接口:
+```
+ws://你电脑局域网的ip:8000/xiaozhi/v1/
+```
+
+接下来,你就可以开始 [编译esp32固件](firmware-build.md)了。
+
+# 常见问题
+
+以下是一些常见问题,供参考:
+
+[1、为什么我说的话,小智识别出来很多韩文、日文、英文](./FAQ.md)
+
+[2、为什么会出现“TTS 任务出错 文件不存在”?](./FAQ.md)
+
+[3、TTS 经常失败,经常超时](./FAQ.md)
+
+[4、使用Wifi能连接自建服务器,但是4G模式却接不上](./FAQ.md)
+
+[5、如何提高小智对话响应速度?](./FAQ.md)
+
+[6、我说话很慢,停顿时小智老是抢话](./FAQ.md)
+
+[7、我想通过小智控制电灯、空调、远程开关机等操作](./FAQ.md)
diff --git a/docs/FAQ.md b/docs/FAQ.md
index 8acdb1a0..9be27089 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -21,7 +21,17 @@ conda install conda-forge::ffmpeg
建议:如果 `EdgeTTS` 经常失败,请先检查是否使用了代理(梯子)。如果使用了,请尝试关闭代理后再试;
如果用的是火山引擎的豆包 TTS,经常失败时建议使用付费版本,因为测试版本仅支持 2 个并发。
-### 4、如何提高小智对话响应速度? ⚡
+### 4、使用Wifi能连接自建服务器,但是4G模式却接不上 🔐
+
+原因:虾哥的固件,4G模式需要使用安全连接。
+
+解决方法:目前有两种方法可以解决。任选一种:
+
+1、改代码。参考这个视频解决 https://www.bilibili.com/video/BV18MfTYoE85
+
+2、使用nginx配置ssl证书。参考教程 https://icnt94i5ctj4.feishu.cn/docx/GnYOdMNJOoRCljx1ctecsj9cnRe
+
+### 5、如何提高小智对话响应速度? ⚡
本项目默认配置为低成本方案,建议初学者先使用默认免费模型,解决"跑得动"的问题,再优化"跑得快"。
如需提升响应速度,可尝试更换各组件。以下为各组件的响应速度测试数据(仅供参考,不构成承诺):
@@ -78,7 +88,7 @@ TTS 性能排行:
- LLM:`AliLLM`
- TTS:`DoubaoTTS`
-### 5、我说话很慢,停顿时小智老是抢话 🗣️
+### 6、我说话很慢,停顿时小智老是抢话 🗣️
建议:在配置文件中找到如下部分,将 `min_silence_duration_ms` 的值调大(例如改为 `1000`):
@@ -90,7 +100,7 @@ VAD:
min_silence_duration_ms: 700 # 如果说话停顿较长,可将此值调大
```
-### 6、我想通过小智控制电灯、空调、远程开关机等操作 💡
+### 7、我想通过小智控制电灯、空调、远程开关机等操作 💡
本项目,支持以工具调用的方式控制HomeAssistant设备
@@ -128,7 +138,7 @@ Intent:
- hass_play_music
```
-### 7、更多问题,可联系我们反馈 💬
+### 8、更多问题,可联系我们反馈 💬
我们的联系方式放在[百度网盘中,点击前往](https://pan.baidu.com/s/1x6USjvP1nTRsZ45XlJu65Q),提取码是`223y`。
diff --git a/docs/docker/nginx.conf b/docs/docker/nginx.conf
index 820fda23..6a746260 100644
--- a/docs/docker/nginx.conf
+++ b/docs/docker/nginx.conf
@@ -9,7 +9,7 @@ server {
}
# API反向代理(Java项目)
- location /xiaozhi-esp32-api/ {
+ location /xiaozhi/ {
proxy_pass http://127.0.0.1:8003;
proxy_set_header Host $host;
proxy_cookie_path /api/ /;
diff --git a/docs/firmware-build.md b/docs/firmware-build.md
index 78a90ae8..b73b5977 100644
--- a/docs/firmware-build.md
+++ b/docs/firmware-build.md
@@ -1,10 +1,14 @@
# 编译esp32固件
-1. 下载`xiaozhi-esp32`
- 项目,按照这个教程配置项目环境[《Windows搭建 ESP IDF 5.3.2开发环境以及编译小智》](https://icnynnzcwou8.feishu.cn/wiki/JEYDwTTALi5s2zkGlFGcDiRknXf)
+## 第1步 配置环境
+先按照这个教程配置项目环境[《Windows搭建 ESP IDF 5.3.2开发环境以及编译小智》](https://icnynnzcwou8.feishu.cn/wiki/JEYDwTTALi5s2zkGlFGcDiRknXf)
-2. 打开`xiaozhi-esp32/main/Kconfig.projbuild`文件,找到`WEBSOCKET_URL`的`default`的内容,把`wss://api.tenclass.net`
- 改成你自己的地址,例如,我的接口地址是`ws://192.168.1.25:8000`,就把内容改成这个。
+## 第2步 打开配置文件
+配置好编译环境后,下载虾哥[xiaozhi-esp32](https://github.com/78/xiaozhi-esp32)项目源码,进入虾哥项目,打开`xiaozhi-esp32/main/Kconfig.projbuild`文件。
+
+## 第3步 修改WEBSOCKET地址
+找到`WEBSOCKET_URL`的`default`的内容,把`wss://api.tenclass.net/xiaozhi/v1/`
+ 改成你自己的地址,例如,我的接口地址是`ws://192.168.1.25:8000/xiaozhi/v1/`,就把内容改成这个。
修改前:
@@ -34,7 +38,32 @@ config WEBSOCKET_URL
注意:你的地址是`ws://`开头,不是`wss://`开头,一定不要写错了。
-3. 设置编译参数
+## 第4步 修改OTA地址
+如果你是全模块部署本项目,就修改OTA接口,如果你只是部署了8000端口的xiaozhi-server,可以继续沿用虾哥团队的OTA接口。如果你不修改OTA接口,请直接忽略本第4步,直接看第5步
+
+找到`OTA_VERSION_URL`的`default`的内容,把`https://api.tenclass.net/xiaozhi/ota/`
+ 改成你自己的地址,例如,我的接口地址是`http://192.168.1.25:8002/xiaozhi/ota/`,就把内容改成这个。
+
+修改前:
+```
+config OTA_VERSION_URL
+ string "OTA Version URL"
+ default "https://api.tenclass.net/xiaozhi/ota/"
+ help
+ The application will access this URL to check for updates.
+```
+修改后:
+```
+config OTA_VERSION_URL
+ string "OTA Version URL"
+ default "http://192.168.1.25:8002/xiaozhi/ota/"
+ help
+ The application will access this URL to check for updates.
+```
+
+## 第5步 设置编译参数
+
+设置编译参数
```
# 终端命令行进入xiaozhi-esp32的根目录
@@ -53,7 +82,7 @@ idf.py menuconfig

-4. 编译固件
+## 第6步 编译固件
```
idf.py build
@@ -65,7 +94,7 @@ idf.py build
-5. 打包bin固件
+## 第7步 打包bin固件
```
cd scripts
@@ -78,7 +107,7 @@ python release.py
注意:如果执行到第二命令后,报了“zip”相关的错误,请忽略这个错误,只要`build`目录下生成固件文件`merged-binary.bin`
,对你没有太大影响,请继续。
-6. 烧录固件
+## 第8步 烧录固件
将esp32设备连接电脑,使用chrome浏览器,打开以下网址
```
@@ -90,16 +119,19 @@ https://espressif.github.io/esp-launchpad/
烧录成功且联网成功后,通过唤醒词唤醒小智,留意server端输出的控制台信息。
+## 常见问题
以下是一些常见问题,供参考:
-[1、为什么我说的话,小智识别出来很多韩文、日文、英文](./FAQ.md#1tts-%E7%BB%8F%E5%B8%B8%E5%A4%B1%E8%B4%A5%E7%BB%8F%E5%B8%B8%E8%B6%85%E6%97%B6-)
+[1、为什么我说的话,小智识别出来很多韩文、日文、英文](./FAQ.md)
-[2、为什么会出现“TTS 任务出错 文件不存在”?](./FAQ.md#1tts-%E7%BB%8F%E5%B8%B8%E5%A4%B1%E8%B4%A5%E7%BB%8F%E5%B8%B8%E8%B6%85%E6%97%B6-)
+[2、为什么会出现“TTS 任务出错 文件不存在”?](./FAQ.md)
-[3、TTS 经常失败,经常超时](./FAQ.md#1tts-%E7%BB%8F%E5%B8%B8%E5%A4%B1%E8%B4%A5%E7%BB%8F%E5%B8%B8%E8%B6%85%E6%97%B6-)
+[3、TTS 经常失败,经常超时](./FAQ.md)
-[4、如何提高小智对话响应速度?](./FAQ.md#1tts-%E7%BB%8F%E5%B8%B8%E5%A4%B1%E8%B4%A5%E7%BB%8F%E5%B8%B8%E8%B6%85%E6%97%B6-)
+[4、使用Wifi能连接自建服务器,但是4G模式却接不上](./FAQ.md)
-[5、我说话很慢,停顿时小智老是抢话](./FAQ.md#1tts-%E7%BB%8F%E5%B8%B8%E5%A4%B1%E8%B4%A5%E7%BB%8F%E5%B8%B8%E8%B6%85%E6%97%B6-)
+[5、如何提高小智对话响应速度?](./FAQ.md)
-[6、我想通过小智控制电灯、空调、远程开关机等操作](./FAQ.md#1tts-%E7%BB%8F%E5%B8%B8%E5%A4%B1%E8%B4%A5%E7%BB%8F%E5%B8%B8%E8%B6%85%E6%97%B6-)
+[6、我说话很慢,停顿时小智老是抢话](./FAQ.md)
+
+[7、我想通过小智控制电灯、空调、远程开关机等操作](./FAQ.md)
diff --git a/docs/images/banner2.png b/docs/images/banner2.png
new file mode 100644
index 00000000..4d54073e
Binary files /dev/null and b/docs/images/banner2.png differ
diff --git a/docs/images/deploy.png b/docs/images/deploy.png
deleted file mode 100644
index e1db8a48..00000000
Binary files a/docs/images/deploy.png and /dev/null differ
diff --git a/docs/images/deploy1.png b/docs/images/deploy1.png
new file mode 100644
index 00000000..70488bcf
Binary files /dev/null and b/docs/images/deploy1.png differ
diff --git a/docs/images/deploy2.png b/docs/images/deploy2.png
new file mode 100644
index 00000000..61c36997
Binary files /dev/null and b/docs/images/deploy2.png differ
diff --git a/docs/images/logo_bailing.png b/docs/images/logo_bailing.png
new file mode 100644
index 00000000..22ab6e11
Binary files /dev/null and b/docs/images/logo_bailing.png differ
diff --git a/docs/images/logo_huiyuan.png b/docs/images/logo_huiyuan.png
new file mode 100644
index 00000000..6e441913
Binary files /dev/null and b/docs/images/logo_huiyuan.png differ
diff --git a/docs/images/logo_qinren.png b/docs/images/logo_qinren.png
new file mode 100644
index 00000000..a01af841
Binary files /dev/null and b/docs/images/logo_qinren.png differ
diff --git a/docs/images/logo_tenclass.png b/docs/images/logo_tenclass.png
new file mode 100644
index 00000000..86a6dc4a
Binary files /dev/null and b/docs/images/logo_tenclass.png differ
diff --git a/docs/images/logo_xuanfeng.png b/docs/images/logo_xuanfeng.png
new file mode 100644
index 00000000..552ee78a
Binary files /dev/null and b/docs/images/logo_xuanfeng.png differ
diff --git a/main/README.md b/main/README.md
index 9dc57ee3..a91c9fdc 100644
--- a/main/README.md
+++ b/main/README.md
@@ -1,8 +1,6 @@
-本文档是开发类文档,如需部署小智服务端,[点击这里查看部署教程](./FAQ.md#%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F-)
+本文档是开发类文档,如需部署小智服务端,[点击这里查看部署教程](../README.md#%E9%83%A8%E7%BD%B2%E6%96%87%E6%A1%A3)
# 项目目录介绍
-当你看到这份文件的时候,这个这个项目还没完善好。我们还有很多东西要做。
-
如果你是一名软件开发者,这里有一份[《致开发者的公开信》](../docs/contributor_open_letter.md),欢迎归队!
```
@@ -12,10 +10,10 @@ xiaozhi-esp32-server
├─ manager-api 8002 端口 Java语言开发 负责提供控制台的api
```
-# xiaozhi-server 接口协议
+# xiaozhi-server 和ESP32通讯协议
-[虾哥团队通信协议:Websocket 连接](https://ccnphfhqs21z.feishu.cn/wiki/M0XiwldO9iJwHikpXD5cEx71nKh)
+https://ccnphfhqs21z.feishu.cn/wiki/M0XiwldO9iJwHikpXD5cEx71nKh
# manager-web 、manager-api接口协议
-https://2662r3426b.vicp.fun/xiaozhi-esp32-api/api/v1/doc.html
+https://2662r3426b.vicp.fun/xiaozhi/v1/doc.html
diff --git a/main/manager-api/README.md b/main/manager-api/README.md
index 5f7fda86..484c28dc 100644
--- a/main/manager-api/README.md
+++ b/main/manager-api/README.md
@@ -1,4 +1,5 @@
-本文档是开发类文档,如需部署小智服务端,[点击这里查看部署教程](.././FAQ.md#%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F-)
+本文档是开发类文档,如需部署小智服务端,[点击这里查看部署教程](../../README.md#%E9%83%A8%E7%BD%B2%E6%96%87%E6%A1%A3)
+
# 项目介绍
manager-api 该项目基于SpringBoot框架开发。
@@ -12,85 +13,6 @@ MySQL 8.0+
Redis 5.0+
Vue 3.x
-# 创建数据库
-
-如果本机已经安装了MySQL,可以直接在数据库中创建名为`xiaozhi_esp32_server`的数据库。
-
-```sql
-CREATE DATABASE xiaozhi_esp32_server CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-```
-
-如果还没有MySQL,你可以通过docker安装mysql
-
-```
-docker run --name xiaozhi-esp32-server-db \
--e MYSQL_ROOT_PASSWORD=123456 \
--p 3306:3306 \
--e MYSQL_DATABASE=xiaozhi_esp32_server \
--e MYSQL_INITDB_ARGS="--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci" \
--d mysql:latest
-```
-
-# 确认项目数据库连接信息
-
-在`src/main/resources/application-dev.yml`中配置数据库连接信息
-
-```
-spring:
- datasource:
- username: root
- password: 123456
-```
-
-
-# 连接Redis
-
-如果还没有Redis,你可以通过docker安装redis
-
-```
-docker run --name xiaozhi-esp32-server-redis -d -p 6379:6379 redis
-```
-
-# 确认项目Redis连接信息
-
-在`src/main/resources/application-dev.yml`中配置Redis连接信息
-
-```
-spring:
- data:
- redis:
- host: localhost
- port: 6379
- password:
- database: 0
-```
-
-
-# 测试启动
-
-本项目为SpringBoot项目,启动方式为:
-打开`Application.java`运行`Main`方法启动
-
-```
-路径地址:
-src/main/java/xiaozhi/AdminApplication.java
-```
-
-# 打包编译
-
-执行以下命令生产jar包
-
-```
-mvn clean install
-```
-
-把jar包放在服务器上,执行
-
-```
-nohup java -jar xiaozhi-esp32-api.jar --spring.profiles.activate=dev
-```
-
-
# 接口文档
-启动后打开:http://localhost:8002/xiaozhi-esp32-api/doc.html
+启动后打开:http://localhost:8002/xiaozhi/doc.html
diff --git a/main/manager-api/src/main/java/xiaozhi/AdminApplication.java b/main/manager-api/src/main/java/xiaozhi/AdminApplication.java
index 8a96edb2..84e30123 100644
--- a/main/manager-api/src/main/java/xiaozhi/AdminApplication.java
+++ b/main/manager-api/src/main/java/xiaozhi/AdminApplication.java
@@ -8,6 +8,6 @@ public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
- System.out.println("http://localhost:8002/xiaozhi-esp32-api/api/v1/doc.html");
+ System.out.println("http://localhost:8002/xiaozhi/doc.html");
}
}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/common/config/SwaggerConfig.java b/main/manager-api/src/main/java/xiaozhi/common/config/SwaggerConfig.java
index da23a233..8fb31641 100644
--- a/main/manager-api/src/main/java/xiaozhi/common/config/SwaggerConfig.java
+++ b/main/manager-api/src/main/java/xiaozhi/common/config/SwaggerConfig.java
@@ -51,7 +51,7 @@ public class SwaggerConfig {
public GroupedOpenApi timbreApi() {
return GroupedOpenApi.builder()
.group("timbre")
- .pathsToMatch("/timbre/**")
+ .pathsToMatch("/ttsVoice/**")
.build();
}
@@ -71,6 +71,14 @@ public class SwaggerConfig {
.build();
}
+ @Bean
+ public GroupedOpenApi configApi() {
+ return GroupedOpenApi.builder()
+ .group("config")
+ .pathsToMatch("/config/**")
+ .build();
+ }
+
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI().info(new Info()
diff --git a/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java b/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java
index 3738498b..1ff70fd4 100644
--- a/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java
+++ b/main/manager-api/src/main/java/xiaozhi/common/constant/Constant.java
@@ -74,8 +74,26 @@ public interface Constant {
*/
String ORDER = "order";
+ /**
+ * 请求头授权标识
+ */
String AUTHORIZATION = "Authorization";
+ /**
+ * 服务器密钥
+ */
+ String SERVER_SECRET = "server.secret";
+
+ /**
+ * 是否允许用户注册
+ */
+ String SERVER_ALLOW_USER_REGISTER = "server.allow_user_register";
+
+ /**
+ * 下发六位验证码时显示的控制面板地址
+ */
+ String SERVER_FRONTED_URL = "server.fronted_url";
+
/**
* 路径分割符
*/
diff --git a/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java b/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java
index e5365b3c..c59a6a14 100644
--- a/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java
+++ b/main/manager-api/src/main/java/xiaozhi/common/exception/ErrorCode.java
@@ -43,4 +43,16 @@ public interface ErrorCode {
int PASSWORD_WEAK_ERROR = 10031;
int DEL_MYSELF_ERROR = 10032;
int DEVICE_CAPTCHA_ERROR = 10033;
+
+ // 参数校验相关错误码
+ int PARAM_VALUE_NULL = 10034;
+ int PARAM_TYPE_NULL = 10035;
+ int PARAM_TYPE_INVALID = 10036;
+ int PARAM_NUMBER_INVALID = 10037;
+ int PARAM_BOOLEAN_INVALID = 10038;
+ int PARAM_ARRAY_INVALID = 10039;
+ int PARAM_JSON_INVALID = 10040;
+
+ int OTA_DEVICE_NOT_FOUND = 10041;
+ int OTA_DEVICE_NEED_BIND = 10042;
}
diff --git a/main/manager-api/src/main/java/xiaozhi/common/exception/RenExceptionHandler.java b/main/manager-api/src/main/java/xiaozhi/common/exception/RenExceptionHandler.java
index 0f83772e..0d0aa118 100644
--- a/main/manager-api/src/main/java/xiaozhi/common/exception/RenExceptionHandler.java
+++ b/main/manager-api/src/main/java/xiaozhi/common/exception/RenExceptionHandler.java
@@ -4,6 +4,7 @@ import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.resource.NoResourceFoundException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -53,4 +54,10 @@ public class RenExceptionHandler {
return new Result().error();
}
+ @ExceptionHandler(NoResourceFoundException.class)
+ public Result handleNoResourceFoundException(NoResourceFoundException ex) {
+ log.warn("Resource not found: {}", ex.getMessage());
+ return new Result().error(404, "资源不存在");
+ }
+
}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java b/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java
index 21121fd7..7bc0c48d 100644
--- a/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java
+++ b/main/manager-api/src/main/java/xiaozhi/common/redis/RedisKeys.java
@@ -26,4 +26,53 @@ public class RedisKeys {
public static String getDeviceCaptchaKey(String captcha) {
return "sys:device:captcha:" + captcha;
}
+
+ /**
+ * 用户id的Key
+ */
+ public static String getUserIdKey(Long userid) {
+ return "sys:username:id:" + userid;
+ }
+
+ /**
+ * 模型名称的Key
+ */
+ public static String getModelNameById(String id) {
+ return "model:name:" + id;
+ }
+
+ /**
+ * 模型配置的Key
+ */
+ public static String getModelConfigById(String id) {
+ return "model:data:" + id;
+ }
+
+ /**
+ * 获取音色名称缓存key
+ */
+ public static String getTimbreNameById(String id) {
+ return "timbre:name:" + id;
+ }
+
+ /**
+ * 获取设备数量缓存key
+ */
+ public static String getAgentDeviceCountById(String id) {
+ return "agent:device:count:" + id;
+ }
+
+ /**
+ * 获取系统配置缓存key
+ */
+ public static String getServerConfigKey() {
+ return "server:config";
+ }
+
+ /**
+ * 获取音色详情缓存key
+ */
+ public static String getTimbreDetailsKey(String id) {
+ return "timbre:details:" + id;
+ }
}
diff --git a/main/manager-api/src/main/java/xiaozhi/common/utils/DateUtils.java b/main/manager-api/src/main/java/xiaozhi/common/utils/DateUtils.java
index 9e5ef3e1..bfa7afed 100644
--- a/main/manager-api/src/main/java/xiaozhi/common/utils/DateUtils.java
+++ b/main/manager-api/src/main/java/xiaozhi/common/utils/DateUtils.java
@@ -2,6 +2,9 @@ package xiaozhi.common.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.temporal.ChronoUnit;
import java.util.Date;
/**
@@ -60,4 +63,39 @@ public class DateUtils {
return null;
}
+ /**
+ * 获取简短的时间字符串:10秒前返回刚刚,多少秒前,几小时前,超过一周返回年月日时分秒
+ * @param date
+ * @return
+ */
+ public static String getShortTime(Date date) {
+ if (date == null) {
+ return null;
+ }
+ // 将 Date 转换为 Instant
+ LocalDateTime localDateTime = date.toInstant()
+ // 获取系统默认时区
+ .atZone(ZoneId.systemDefault())
+ // 转换为 LocalDateTime
+ .toLocalDateTime();
+ // 当前时间
+ LocalDateTime now = LocalDateTime.now();
+ // 时间差,单位为秒
+ long secondsBetween = ChronoUnit.SECONDS.between(localDateTime, now);
+
+ if (secondsBetween <= 10) {
+ return "刚刚";
+ } else if (secondsBetween < 60) {
+ return secondsBetween + "秒前";
+ } else if (secondsBetween < 60 * 60) {
+ return secondsBetween / 60 + "分钟前";
+ } else if (secondsBetween < 86400) {
+ return secondsBetween / 3600 + "小时前";
+ } else if (secondsBetween < 604800) {
+ return secondsBetween / 86400 + "天前";
+ } else {
+ // 超过一周,显示完整日期时间
+ return format(date,DATE_TIME_PATTERN);
+ }
+ }
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java
index 93a741df..123e10ba 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java
@@ -29,11 +29,13 @@ import xiaozhi.common.user.UserDetail;
import xiaozhi.common.utils.ConvertUtils;
import xiaozhi.common.utils.Result;
import xiaozhi.modules.agent.dto.AgentCreateDTO;
+import xiaozhi.modules.agent.dto.AgentDTO;
import xiaozhi.modules.agent.dto.AgentUpdateDTO;
import xiaozhi.modules.agent.entity.AgentEntity;
import xiaozhi.modules.agent.entity.AgentTemplateEntity;
import xiaozhi.modules.agent.service.AgentService;
import xiaozhi.modules.agent.service.AgentTemplateService;
+import xiaozhi.modules.device.service.DeviceService;
import xiaozhi.modules.security.user.SecurityUser;
@Tag(name = "智能体管理")
@@ -43,14 +45,15 @@ import xiaozhi.modules.security.user.SecurityUser;
public class AgentController {
private final AgentService agentService;
private final AgentTemplateService agentTemplateService;
+ private final DeviceService deviceService;
@GetMapping("/list")
@Operation(summary = "获取用户智能体列表")
@RequiresPermissions("sys:role:normal")
- public Result> getUserAgents() {
+ public Result> getUserAgents() {
UserDetail user = SecurityUser.getUser();
- List agents = agentService.getUserAgents(user.getId());
- return new Result>().ok(agents);
+ List agents = agentService.getUserAgents(user.getId());
+ return new Result>().ok(agents);
}
@GetMapping("/all")
@@ -80,6 +83,22 @@ public class AgentController {
public Result save(@RequestBody @Valid AgentCreateDTO dto) {
AgentEntity entity = ConvertUtils.sourceToTarget(dto, AgentEntity.class);
+ // 获取默认模板
+ AgentTemplateEntity template = agentTemplateService.getDefaultTemplate();
+ if (template != null) {
+ // 设置模板中的默认值
+ entity.setAsrModelId(template.getAsrModelId());
+ entity.setVadModelId(template.getVadModelId());
+ entity.setLlmModelId(template.getLlmModelId());
+ entity.setTtsModelId(template.getTtsModelId());
+ entity.setTtsVoiceId(template.getTtsVoiceId());
+ entity.setMemModelId(template.getMemModelId());
+ entity.setIntentModelId(template.getIntentModelId());
+ entity.setSystemPrompt(template.getSystemPrompt());
+ entity.setLangCode(template.getLangCode());
+ entity.setLanguage(template.getLanguage());
+ }
+
// 设置用户ID和创建者信息
UserDetail user = SecurityUser.getUser();
entity.setUserId(user.getId());
@@ -157,6 +176,9 @@ public class AgentController {
@Operation(summary = "删除智能体")
@RequiresPermissions("sys:role:normal")
public Result delete(@PathVariable String id) {
+ // 先删除关联的设备
+ deviceService.deleteByAgentId(id);
+ // 再删除智能体
agentService.deleteById(id);
return new Result<>();
}
@@ -169,4 +191,5 @@ public class AgentController {
.list(new QueryWrapper().orderByAsc("sort"));
return new Result>().ok(list);
}
+
}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentDao.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentDao.java
index d9aec7d7..8c80d6cc 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentDao.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentDao.java
@@ -1,11 +1,18 @@
package xiaozhi.modules.agent.dao;
import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
import xiaozhi.common.dao.BaseDao;
import xiaozhi.modules.agent.entity.AgentEntity;
@Mapper
public interface AgentDao extends BaseDao {
-
+ /**
+ * 获取智能体的设备数量
+ *
+ * @param agentId 智能体ID
+ * @return 设备数量
+ */
+ Integer getDeviceCountByAgentId(@Param("agentId") String agentId);
}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentDTO.java
new file mode 100644
index 00000000..a63c96e7
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentDTO.java
@@ -0,0 +1,38 @@
+package xiaozhi.modules.agent.dto;
+
+import java.util.Date;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * 智能体数据传输对象
+ * 用于在服务层和控制器层之间传递智能体相关的数据
+ */
+@Data
+@Schema(description = "智能体对象")
+public class AgentDTO {
+ @Schema(description = "智能体编码", example = "AGT_1234567890")
+ private String id;
+
+ @Schema(description = "智能体名称", example = "客服助手")
+ private String agentName;
+
+ @Schema(description = "语音合成模型名称", example = "tts_model_01")
+ private String ttsModelName;
+
+ @Schema(description = "音色名称", example = "voice_01")
+ private String ttsVoiceName;
+
+ @Schema(description = "大语言模型名称", example = "llm_model_01")
+ private String llmModelName;
+
+ @Schema(description = "角色设定参数", example = "你是一个专业的客服助手,负责回答用户问题并提供帮助")
+ private String systemPrompt;
+
+ @Schema(description = "最后连接时间", example = "2024-03-20 10:00:00")
+ private Date lastConnectedAt;
+
+ @Schema(description = "设备数量", example = "10")
+ private Integer deviceCount;
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentService.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentService.java
index 7d5285e8..8d0b2959 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentService.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentService.java
@@ -5,13 +5,10 @@ import java.util.Map;
import xiaozhi.common.page.PageData;
import xiaozhi.common.service.BaseService;
+import xiaozhi.modules.agent.dto.AgentDTO;
import xiaozhi.modules.agent.entity.AgentEntity;
public interface AgentService extends BaseService {
- /**
- * 根据用户ID获取智能体列表
- */
- List getUserAgents(Long userId);
/**
* 管理员获取所有智能体列表(分页)
@@ -25,7 +22,24 @@ public interface AgentService extends BaseService {
/**
* 删除这个用户的所有
+ *
* @param userId
*/
- void deleteAgentByUserId(String userId);
+ void deleteAgentByUserId(Long userId);
+
+ /**
+ * 获取用户智能体列表
+ *
+ * @param userId
+ * @return
+ */
+ List getUserAgents(Long userId);
+
+ /**
+ * 获取智能体的设备数量
+ *
+ * @param agentId 智能体ID
+ * @return 设备数量
+ */
+ Integer getDeviceCountByAgentId(String agentId);
}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentTemplateService.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentTemplateService.java
index 9c27bdb5..4e279c40 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentTemplateService.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentTemplateService.java
@@ -11,4 +11,18 @@ import xiaozhi.modules.agent.entity.AgentTemplateEntity;
*/
public interface AgentTemplateService extends IService {
+ /**
+ * 获取默认模板
+ *
+ * @return 默认模板实体
+ */
+ AgentTemplateEntity getDefaultTemplate();
+
+ /**
+ * 更新默认模板中的模型ID
+ *
+ * @param modelType 模型类型
+ * @param modelId 模型ID
+ */
+ void updateDefaultTemplateModelId(String modelType, String modelId);
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java
index 40579cee..ff284ef0 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java
@@ -3,40 +3,48 @@ package xiaozhi.modules.agent.service.impl;
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import java.util.stream.Collectors;
-import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
-import org.springframework.transaction.annotation.Transactional;
import xiaozhi.common.page.PageData;
+import xiaozhi.common.redis.RedisKeys;
+import xiaozhi.common.redis.RedisUtils;
import xiaozhi.common.service.impl.BaseServiceImpl;
import xiaozhi.modules.agent.dao.AgentDao;
+import xiaozhi.modules.agent.dto.AgentDTO;
import xiaozhi.modules.agent.entity.AgentEntity;
import xiaozhi.modules.agent.service.AgentService;
-import xiaozhi.modules.device.entity.DeviceEntity;
+import xiaozhi.modules.model.service.ModelConfigService;
+import xiaozhi.modules.timbre.service.TimbreService;
@Service
public class AgentServiceImpl extends BaseServiceImpl implements AgentService {
private final AgentDao agentDao;
+ @Autowired
+ private TimbreService timbreModelService;
+
+ @Autowired
+ private ModelConfigService modelConfigService;
+
+ @Autowired
+ private RedisUtils redisUtils;
+
public AgentServiceImpl(AgentDao agentDao) {
this.agentDao = agentDao;
}
- @Override
- public List getUserAgents(Long userId) {
- QueryWrapper wrapper = new QueryWrapper<>();
- wrapper.eq("user_id", userId);
- return agentDao.selectList(wrapper);
- }
-
@Override
public PageData adminAgentList(Map params) {
IPage page = agentDao.selectPage(
- getPage(params, "sort", true),
+ getPage(params, "agent_name", true),
new QueryWrapper<>());
return new PageData<>(page.getRecords(), page.getTotal());
}
@@ -67,9 +75,59 @@ public class AgentServiceImpl extends BaseServiceImpl imp
}
@Override
- public void deleteAgentByUserId(String userId) {
+ public void deleteAgentByUserId(Long userId) {
UpdateWrapper wrapper = new UpdateWrapper<>();
wrapper.eq("user_id", userId);
baseDao.delete(wrapper);
}
+
+ @Override
+ public List getUserAgents(Long userId) {
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.eq("user_id", userId);
+ List agents = agentDao.selectList(wrapper);
+ return agents.stream().map(agent -> {
+ AgentDTO dto = new AgentDTO();
+ dto.setId(agent.getId());
+ dto.setAgentName(agent.getAgentName());
+ dto.setSystemPrompt(agent.getSystemPrompt());
+
+ // 获取 TTS 模型名称
+ dto.setTtsModelName(modelConfigService.getModelNameById(agent.getTtsModelId()));
+
+ // 获取 LLM 模型名称
+ dto.setLlmModelName(modelConfigService.getModelNameById(agent.getLlmModelId()));
+
+ // 获取 TTS 音色名称
+ dto.setTtsVoiceName(timbreModelService.getTimbreNameById(agent.getTtsVoiceId()));
+
+ // 获取设备数量
+ dto.setDeviceCount(getDeviceCountByAgentId(agent.getId()));
+
+ return dto;
+ }).collect(Collectors.toList());
+ }
+
+ @Override
+ public Integer getDeviceCountByAgentId(String agentId) {
+ if (StringUtils.isBlank(agentId)) {
+ return 0;
+ }
+
+ // 先从Redis中获取
+ Integer cachedCount = (Integer) redisUtils.get(RedisKeys.getAgentDeviceCountById(agentId));
+ if (cachedCount != null) {
+ return cachedCount;
+ }
+
+ // 如果Redis中没有,则从数据库查询
+ Integer deviceCount = agentDao.getDeviceCountByAgentId(agentId);
+
+ // 将结果存入Redis
+ if (deviceCount != null) {
+ redisUtils.set(RedisKeys.getAgentDeviceCountById(agentId), deviceCount, 60);
+ }
+
+ return deviceCount != null ? deviceCount : 0;
+ }
}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentTemplateServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentTemplateServiceImpl.java
index 62338fad..9ac3de25 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentTemplateServiceImpl.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentTemplateServiceImpl.java
@@ -2,6 +2,8 @@ package xiaozhi.modules.agent.service.impl;
import org.springframework.stereotype.Service;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import xiaozhi.modules.agent.dao.AgentTemplateDao;
@@ -15,6 +17,53 @@ import xiaozhi.modules.agent.service.AgentTemplateService;
*/
@Service
public class AgentTemplateServiceImpl extends ServiceImpl
- implements AgentTemplateService {
+ implements AgentTemplateService {
+ /**
+ * 获取默认模板
+ *
+ * @return 默认模板实体
+ */
+ public AgentTemplateEntity getDefaultTemplate() {
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.orderByAsc(AgentTemplateEntity::getSort)
+ .last("LIMIT 1");
+ return this.getOne(wrapper);
+ }
+
+ /**
+ * 更新默认模板中的模型ID
+ *
+ * @param modelType 模型类型
+ * @param modelId 模型ID
+ */
+ @Override
+ public void updateDefaultTemplateModelId(String modelType, String modelId) {
+ modelType = modelType.toUpperCase();
+
+ UpdateWrapper wrapper = new UpdateWrapper<>();
+ switch (modelType) {
+ case "ASR":
+ wrapper.set("asr_model_id", modelId);
+ break;
+ case "VAD":
+ wrapper.set("vad_model_id", modelId);
+ break;
+ case "LLM":
+ wrapper.set("llm_model_id", modelId);
+ break;
+ case "TTS":
+ wrapper.set("tts_model_id", modelId);
+ wrapper.set("tts_voice_id", null);
+ break;
+ case "MEMORY":
+ wrapper.set("mem_model_id", modelId);
+ break;
+ case "INTENT":
+ wrapper.set("intent_model_id", modelId);
+ break;
+ }
+ wrapper.ge("sort", 0);
+ update(wrapper);
+ }
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/controller/ConfigController.java b/main/manager-api/src/main/java/xiaozhi/modules/config/controller/ConfigController.java
new file mode 100644
index 00000000..bdbd20ed
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/config/controller/ConfigController.java
@@ -0,0 +1,61 @@
+package xiaozhi.modules.config.controller;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.AllArgsConstructor;
+import xiaozhi.common.constant.Constant;
+import xiaozhi.common.exception.RenException;
+import xiaozhi.common.utils.Result;
+import xiaozhi.common.validator.ValidatorUtils;
+import xiaozhi.modules.config.dto.AgentModelsDTO;
+import xiaozhi.modules.config.service.ConfigService;
+import xiaozhi.modules.sys.dto.ConfigSecretDTO;
+import xiaozhi.modules.sys.service.SysParamsService;
+
+/**
+ * xiaozhi-server 配置获取
+ *
+ * @since 1.0.0
+ */
+@RestController
+@RequestMapping("config")
+@Tag(name = "参数管理")
+@AllArgsConstructor
+public class ConfigController {
+ private final ConfigService configService;
+ private final SysParamsService sysParamsService;
+
+ @PostMapping("server-base")
+ @Operation(summary = "获取配置")
+ public Result getConfig(@RequestBody ConfigSecretDTO dto) {
+ // 效验数据
+ ValidatorUtils.validateEntity(dto);
+ checkSecret(dto.getSecret());
+ Object config = configService.getConfig(true);
+ return new Result().ok(config);
+ }
+
+ @PostMapping("agent-models")
+ @Operation(summary = "获取智能体模型")
+ public Result getAgentModels(@RequestBody AgentModelsDTO dto) {
+ // 效验数据
+ ValidatorUtils.validateEntity(dto);
+ checkSecret(dto.getSecret());
+ Object models = configService.getAgentModels(dto.getMacAddress(), dto.getSelectedModule());
+ return new Result().ok(models);
+ }
+
+ private void checkSecret(String secret) {
+ String secretParam = sysParamsService.getValue(Constant.SERVER_SECRET, true);
+ // 验证密钥
+ if (StringUtils.isBlank(secret) || !secret.equals(secretParam)) {
+ throw new RenException("密钥错误");
+ }
+ }
+}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/dto/AgentModelsDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/config/dto/AgentModelsDTO.java
new file mode 100644
index 00000000..4a07a743
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/config/dto/AgentModelsDTO.java
@@ -0,0 +1,28 @@
+package xiaozhi.modules.config.dto;
+
+import java.util.Map;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Data
+@Schema(description = "获取智能体模型配置DTO")
+public class AgentModelsDTO {
+ @NotBlank(message = "密钥不能为空")
+ @Schema(description = "密钥")
+ private String secret;
+
+ @NotBlank(message = "设备MAC地址不能为空")
+ @Schema(description = "设备MAC地址")
+ private String macAddress;
+
+ @NotBlank(message = "客户端ID不能为空")
+ @Schema(description = "客户端ID")
+ private String clientId;
+
+ @NotNull(message = "客户端已实例化的模型不能为空")
+ @Schema(description = "客户端已实例化的模型")
+ private Map selectedModule;
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/init/SystemInitConfig.java b/main/manager-api/src/main/java/xiaozhi/modules/config/init/SystemInitConfig.java
new file mode 100644
index 00000000..a8e3794e
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/config/init/SystemInitConfig.java
@@ -0,0 +1,26 @@
+package xiaozhi.modules.config.init;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.DependsOn;
+
+import jakarta.annotation.PostConstruct;
+import xiaozhi.modules.config.service.ConfigService;
+import xiaozhi.modules.sys.service.SysParamsService;
+
+@Configuration
+@DependsOn("liquibase")
+public class SystemInitConfig {
+
+ @Autowired
+ private SysParamsService sysParamsService;
+
+ @Autowired
+ private ConfigService configService;
+
+ @PostConstruct
+ public void init() {
+ sysParamsService.initServerSecret();
+ configService.getConfig(false);
+ }
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/service/ConfigService.java b/main/manager-api/src/main/java/xiaozhi/modules/config/service/ConfigService.java
new file mode 100644
index 00000000..93845e8e
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/config/service/ConfigService.java
@@ -0,0 +1,22 @@
+package xiaozhi.modules.config.service;
+
+import java.util.Map;
+
+public interface ConfigService {
+ /**
+ * 获取服务器配置
+ *
+ * @param isCache 是否缓存
+ * @return 配置信息
+ */
+ Object getConfig(Boolean isCache);
+
+ /**
+ * 获取智能体模型配置
+ *
+ * @param macAddress MAC地址
+ * @param selectedModule 客户端已实例化的模型
+ * @return 模型配置信息
+ */
+ Map getAgentModels(String macAddress, Map selectedModule);
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java
new file mode 100644
index 00000000..44f19089
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java
@@ -0,0 +1,289 @@
+package xiaozhi.modules.config.service.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import lombok.AllArgsConstructor;
+import xiaozhi.common.exception.ErrorCode;
+import xiaozhi.common.exception.RenException;
+import xiaozhi.common.redis.RedisKeys;
+import xiaozhi.common.redis.RedisUtils;
+import xiaozhi.common.utils.JsonUtils;
+import xiaozhi.modules.agent.entity.AgentEntity;
+import xiaozhi.modules.agent.entity.AgentTemplateEntity;
+import xiaozhi.modules.agent.service.AgentService;
+import xiaozhi.modules.agent.service.AgentTemplateService;
+import xiaozhi.modules.config.service.ConfigService;
+import xiaozhi.modules.device.entity.DeviceEntity;
+import xiaozhi.modules.device.service.DeviceService;
+import xiaozhi.modules.model.entity.ModelConfigEntity;
+import xiaozhi.modules.model.service.ModelConfigService;
+import xiaozhi.modules.sys.dto.SysParamsDTO;
+import xiaozhi.modules.sys.service.SysParamsService;
+import xiaozhi.modules.timbre.service.TimbreService;
+import xiaozhi.modules.timbre.vo.TimbreDetailsVO;
+
+@Service
+@AllArgsConstructor
+public class ConfigServiceImpl implements ConfigService {
+ private final SysParamsService sysParamsService;
+ private final DeviceService deviceService;
+ private final ModelConfigService modelConfigService;
+ private final AgentService agentService;
+ private final AgentTemplateService agentTemplateService;
+ private final RedisUtils redisUtils;
+ private final TimbreService timbreService;
+
+ @Override
+ public Object getConfig(Boolean isCache) {
+ if (isCache) {
+ // 先从Redis获取配置
+ Object cachedConfig = redisUtils.get(RedisKeys.getServerConfigKey());
+ if (cachedConfig != null) {
+ return cachedConfig;
+ }
+ }
+
+ // 构建配置信息
+ Map result = new HashMap<>();
+ buildConfig(result);
+
+ // 查询默认智能体
+ AgentTemplateEntity agent = agentTemplateService.getDefaultTemplate();
+ if (agent == null) {
+ throw new RenException("默认智能体未找到");
+ }
+
+ // 构建模块配置
+ buildModuleConfig(
+ agent.getAgentName(),
+ agent.getSystemPrompt(),
+ null,
+ agent.getVadModelId(),
+ agent.getAsrModelId(),
+ agent.getLlmModelId(),
+ agent.getTtsModelId(),
+ agent.getMemModelId(),
+ agent.getIntentModelId(),
+ result,
+ isCache);
+
+ // 将配置存入Redis
+ redisUtils.set(RedisKeys.getServerConfigKey(), result);
+
+ return result;
+ }
+
+ @Override
+ public Map getAgentModels(String macAddress, Map selectedModule) {
+ // 根据MAC地址查找设备
+ DeviceEntity device = deviceService.getDeviceByMacAddress(macAddress);
+ if (device == null) {
+ // 如果设备,去redis里看看有没有需要连接的设备
+ String cachedCode = deviceService.geCodeByDeviceId(macAddress);
+ if (StringUtils.isNotBlank(cachedCode)) {
+ throw new RenException(ErrorCode.OTA_DEVICE_NEED_BIND, cachedCode);
+ }
+ throw new RenException(ErrorCode.OTA_DEVICE_NOT_FOUND, "not found device");
+ }
+ // 获取智能体信息
+ AgentEntity agent = agentService.getAgentById(device.getAgentId());
+ if (agent == null) {
+ throw new RenException("智能体未找到");
+ }
+ // 获取音色信息
+ String voice = null;
+ TimbreDetailsVO timbre = timbreService.get(agent.getTtsVoiceId());
+ if (timbre != null) {
+ voice = timbre.getTtsVoice();
+ }
+ // 构建返回数据
+ Map result = new HashMap<>();
+
+ // 如果客户端已实例化模型,则不返回
+ String alreadySelectedVadModelId = (String) selectedModule.get("VAD");
+ if (alreadySelectedVadModelId != null && alreadySelectedVadModelId.equals(agent.getVadModelId())) {
+ agent.setVadModelId(null);
+ }
+ String alreadySelectedAsrModelId = (String) selectedModule.get("ASR");
+ if (alreadySelectedAsrModelId != null && alreadySelectedAsrModelId.equals(agent.getAsrModelId())) {
+ agent.setAsrModelId(null);
+ }
+ String alreadySelectedLlmModelId = (String) selectedModule.get("LLM");
+ if (alreadySelectedLlmModelId != null && alreadySelectedLlmModelId.equals(agent.getLlmModelId())) {
+ agent.setLlmModelId(null);
+ }
+ String alreadySelectedMemModelId = (String) selectedModule.get("Memory");
+ if (alreadySelectedMemModelId != null && alreadySelectedMemModelId.equals(agent.getMemModelId())) {
+ agent.setMemModelId(null);
+ }
+ String alreadySelectedIntentModelId = (String) selectedModule.get("Intent");
+ if (alreadySelectedIntentModelId != null && alreadySelectedIntentModelId.equals(agent.getIntentModelId())) {
+ agent.setIntentModelId(null);
+ }
+
+ // 构建模块配置
+ buildModuleConfig(
+ agent.getAgentName(),
+ agent.getSystemPrompt(),
+ voice,
+ agent.getVadModelId(),
+ agent.getAsrModelId(),
+ agent.getLlmModelId(),
+ agent.getTtsModelId(),
+ agent.getMemModelId(),
+ agent.getIntentModelId(),
+ result,
+ true);
+
+ return result;
+ }
+
+ /**
+ * 构建配置信息
+ *
+ * @param paramsList 系统参数列表
+ * @return 配置信息
+ */
+ @SuppressWarnings("unchecked")
+ private Object buildConfig(Map config) {
+
+ // 查询所有系统参数
+ List paramsList = sysParamsService.list(new HashMap<>());
+
+ for (SysParamsDTO param : paramsList) {
+ String[] keys = param.getParamCode().split("\\.");
+ Map current = config;
+
+ // 遍历除最后一个key之外的所有key
+ for (int i = 0; i < keys.length - 1; i++) {
+ String key = keys[i];
+ if (!current.containsKey(key)) {
+ current.put(key, new HashMap());
+ }
+ current = (Map) current.get(key);
+ }
+
+ // 处理最后一个key
+ String lastKey = keys[keys.length - 1];
+ String value = param.getParamValue();
+
+ // 根据valueType转换值
+ switch (param.getValueType().toLowerCase()) {
+ case "number":
+ try {
+ double doubleValue = Double.parseDouble(value);
+ // 如果数值是整数形式,则转换为Integer
+ if (doubleValue == (int) doubleValue) {
+ current.put(lastKey, (int) doubleValue);
+ } else {
+ current.put(lastKey, doubleValue);
+ }
+ } catch (NumberFormatException e) {
+ current.put(lastKey, value);
+ }
+ break;
+ case "boolean":
+ current.put(lastKey, Boolean.parseBoolean(value));
+ break;
+ case "array":
+ // 将分号分隔的字符串转换为数字数组
+ List list = new ArrayList<>();
+ for (String num : value.split(";")) {
+ if (StringUtils.isNotBlank(num)) {
+ list.add(num.trim());
+ }
+ }
+ current.put(lastKey, list);
+ break;
+ case "json":
+ try {
+ current.put(lastKey, JsonUtils.parseObject(value, Object.class));
+ } catch (Exception e) {
+ current.put(lastKey, value);
+ }
+ break;
+ default:
+ current.put(lastKey, value);
+ }
+ }
+
+ return config;
+ }
+
+ /**
+ * 构建模块配置
+ *
+ * @param prompt 提示词
+ * @param voice 音色
+ * @param vadModelId VAD模型ID
+ * @param asrModelId ASR模型ID
+ * @param llmModelId LLM模型ID
+ * @param ttsModelId TTS模型ID
+ * @param memModelId 记忆模型ID
+ * @param intentModelId 意图模型ID
+ * @param result 结果Map
+ */
+ private void buildModuleConfig(
+ String assistantName,
+ String prompt,
+ String voice,
+ String vadModelId,
+ String asrModelId,
+ String llmModelId,
+ String ttsModelId,
+ String memModelId,
+ String intentModelId,
+ Map result,
+ boolean isCache) {
+ Map selectedModule = new HashMap<>();
+
+ String[] modelTypes = { "VAD", "ASR", "TTS", "Memory", "Intent", "LLM" };
+ String[] modelIds = { vadModelId, asrModelId, ttsModelId, memModelId, intentModelId, llmModelId };
+ String intentLLMModelId = null;
+
+ for (int i = 0; i < modelIds.length; i++) {
+ if (modelIds[i] == null) {
+ continue;
+ }
+ ModelConfigEntity model = modelConfigService.getModelById(modelIds[i], isCache);
+ Map typeConfig = new HashMap<>();
+ if (model.getConfigJson() != null) {
+ typeConfig.put(model.getId(), model.getConfigJson());
+ // 如果是TTS类型,添加private_voice属性
+ if ("TTS".equals(modelTypes[i]) && voice != null) {
+ ((Map) model.getConfigJson()).put("private_voice", voice);
+ }
+ // 如果是Intent类型,且type=intent_llm,则给他添加附加模型
+ if ("Intent".equals(modelTypes[i])) {
+ Map map = (Map) model.getConfigJson();
+ if ("intent_llm".equals(map.get("type"))) {
+ intentLLMModelId = (String) map.get("llm");
+ if (intentLLMModelId != null && intentLLMModelId.equals(llmModelId)) {
+ intentLLMModelId = null;
+ }
+ }
+ }
+ // 如果是LLM类型,且intentLLMModelId不为空,则添加附加模型
+ if ("LLM".equals(modelTypes[i]) && intentLLMModelId != null) {
+ ModelConfigEntity intentLLM = modelConfigService.getModelById(intentLLMModelId, isCache);
+ typeConfig.put(intentLLM.getId(), intentLLM.getConfigJson());
+ }
+ }
+ result.put(modelTypes[i], typeConfig);
+
+ selectedModule.put(modelTypes[i], model.getId());
+ }
+
+ result.put("selected_module", selectedModule);
+ if (StringUtils.isNotBlank(prompt)) {
+ prompt = prompt.replace("{{assistant_name}}", "小智");
+ }
+ result.put("prompt", prompt);
+ }
+}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java
index 43009bf8..1c68a756 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java
@@ -19,7 +19,6 @@ import xiaozhi.common.redis.RedisKeys;
import xiaozhi.common.redis.RedisUtils;
import xiaozhi.common.user.UserDetail;
import xiaozhi.common.utils.Result;
-import xiaozhi.modules.device.dto.DeviceBindDTO;
import xiaozhi.modules.device.dto.DeviceRegisterDTO;
import xiaozhi.modules.device.dto.DeviceUnBindDTO;
import xiaozhi.modules.device.entity.DeviceEntity;
@@ -39,13 +38,7 @@ public class DeviceController {
@Operation(summary = "绑定设备")
@RequiresPermissions("sys:role:normal")
public Result bindDevice(@PathVariable String agentId, @PathVariable String deviceCode) {
- String macAddress = (String) redisUtils.get(RedisKeys.getDeviceCaptchaKey(deviceCode));
- if (StringUtils.isBlank(macAddress)) {
- return new Result().error(ErrorCode.DEVICE_CAPTCHA_ERROR);
- }
- Long user = SecurityUser.getUser().getId();
- DeviceBindDTO deviceBindDTO = new DeviceBindDTO(macAddress, user, agentId);
- deviceService.bindDevice(deviceBindDTO);
+ deviceService.deviceActivation(agentId, deviceCode);
return new Result<>();
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAController.java b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAController.java
index 16f53256..30f30b53 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAController.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/OTAController.java
@@ -10,7 +10,6 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.annotation.JsonInclude;
@@ -22,7 +21,6 @@ import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
-import xiaozhi.common.utils.Result;
import xiaozhi.modules.device.dto.DeviceReportReqDTO;
import xiaozhi.modules.device.dto.DeviceReportRespDTO;
import xiaozhi.modules.device.service.DeviceService;
@@ -31,7 +29,7 @@ import xiaozhi.modules.device.utils.NetworkUtil;
@Tag(name = "设备管理", description = "OTA 相关接口")
@RestController
@RequiredArgsConstructor
-@RequestMapping("/ota")
+@RequestMapping("/ota/")
public class OTAController {
private final DeviceService deviceService;
@@ -39,26 +37,26 @@ public class OTAController {
@PostMapping
public ResponseEntity checkOTAVersion(
@RequestBody DeviceReportReqDTO deviceReportReqDTO,
-
@Parameter(name = "Device-Id", description = "设备唯一标识", required = true, in = ParameterIn.HEADER) @RequestHeader("Device-Id") String deviceId,
-
- @Parameter(name = "Client-Id", description = "客户端标识", required = true, in = ParameterIn.HEADER) @RequestHeader("Client-Id") String clientId) {
- if (StringUtils.isAnyBlank(deviceId, clientId)) {
+ @Parameter(name = "Client-Id", description = "客户端标识", required = false, in = ParameterIn.HEADER) @RequestHeader(value = "Client-Id", required = false) String clientId) {
+ if (StringUtils.isBlank(deviceId)) {
return createResponse(DeviceReportRespDTO.createError("Device ID is required"));
}
+ if (StringUtils.isBlank(clientId)) {
+ clientId = deviceId;
+ }
String macAddress = deviceReportReqDTO.getMacAddress();
boolean macAddressValid = NetworkUtil.isMacAddressValid(macAddress);
// 设备Id和Mac地址应是一致的, 并且必须需要application字段
if (!deviceId.equals(macAddress) || !macAddressValid || deviceReportReqDTO.getApplication() == null) {
return createResponse(DeviceReportRespDTO.createError("Invalid OTA request"));
}
- return createResponse(deviceService.checkDeviceActive(macAddress, deviceId, clientId, deviceReportReqDTO));
+ return createResponse(deviceService.checkDeviceActive(macAddress, clientId, deviceReportReqDTO));
}
- @Operation(summary = "设备激活")
- @GetMapping("/activation")
- public Result deviceActivation(@RequestParam String code) {
- return new Result().ok(deviceService.deviceActivation(code));
+ @GetMapping
+ public ResponseEntity getOTAPrompt() {
+ return createResponse(DeviceReportRespDTO.createError("请提交正确的ota参数"));
}
@SneakyThrows
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DevicePageUserDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DevicePageUserDTO.java
new file mode 100644
index 00000000..26bccbfd
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DevicePageUserDTO.java
@@ -0,0 +1,27 @@
+package xiaozhi.modules.device.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.Min;
+import lombok.Data;
+
+/**
+ * 查询所有设备的DTO
+ *
+ * @author zjy
+ * @since 2025-3-21
+ */
+@Data
+@Schema(description = "查询所有设备的DTO")
+public class DevicePageUserDTO {
+
+ @Schema(description = "设备关键词")
+ private String keywords;
+
+ @Schema(description = "页数")
+ @Min(value = 0, message = "{page.number}")
+ private String page;
+
+ @Schema(description = "显示列数")
+ @Min(value = 0, message = "{limit.number}")
+ private String limit;
+}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceReportRespDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceReportRespDTO.java
index 6226378d..9f93a9b7 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceReportRespDTO.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/device/dto/DeviceReportRespDTO.java
@@ -9,7 +9,7 @@ import lombok.Setter;
@Schema(description = "设备OTA检测版本返回体,包含激活码要求")
public class DeviceReportRespDTO {
@Schema(description = "服务器时间")
- private ServerTime serverTime;
+ private ServerTime server_time;
@Schema(description = "激活码")
private Activation activation;
@@ -56,6 +56,6 @@ public class DeviceReportRespDTO {
private String timeZone;
@Schema(description = "时区偏移量,单位为分钟")
- private Integer timezoneOffset;
+ private Integer timezone_offset;
}
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java
index 5f91bb2e..8bb203cc 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java
@@ -2,10 +2,12 @@ package xiaozhi.modules.device.service;
import java.util.List;
-import xiaozhi.modules.device.dto.DeviceBindDTO;
+import xiaozhi.common.page.PageData;
+import xiaozhi.modules.device.dto.DevicePageUserDTO;
import xiaozhi.modules.device.dto.DeviceReportReqDTO;
import xiaozhi.modules.device.dto.DeviceReportRespDTO;
import xiaozhi.modules.device.entity.DeviceEntity;
+import xiaozhi.modules.device.vo.UserShowDeviceListVO;
public interface DeviceService {
@@ -17,14 +19,9 @@ public interface DeviceService {
/**
* 检查设备是否激活
*/
- DeviceReportRespDTO checkDeviceActive(String macAddress, String deviceId, String clientId,
+ DeviceReportRespDTO checkDeviceActive(String macAddress, String clientId,
DeviceReportReqDTO deviceReport);
- /**
- * 绑定设备
- */
- DeviceEntity bindDevice(DeviceBindDTO deviceHeader);
-
/**
* 获取用户指定智能体的设备列表,
*/
@@ -38,11 +35,51 @@ public interface DeviceService {
/**
* 设备激活
*/
- Boolean deviceActivation(String activationCode);
+ Boolean deviceActivation(String agentId, String activationCode);
/**
* 删除此用户的所有设备
+ *
* @param userId 用户id
*/
void deleteByUserId(Long userId);
+
+ /**
+ * 删除指定智能体关联的所有设备
+ *
+ * @param agentId 智能体id
+ */
+ void deleteByAgentId(String agentId);
+
+ /**
+ * 获取指定用户的设备数量
+ *
+ * @param userId 用户id
+ * @return 设备数量
+ */
+ Long selectCountByUserId(Long userId);
+
+ /**
+ * 分页获取全部设备信息
+ *
+ * @param dto 分页查找参数
+ * @return 用户列表分页数据
+ */
+ PageData page(DevicePageUserDTO dto);
+
+ /**
+ * 根据MAC地址获取设备信息
+ *
+ * @param macAddress MAC地址
+ * @return 设备信息
+ */
+ DeviceEntity getDeviceByMacAddress(String macAddress);
+
+ /**
+ * 根据设备ID获取激活码
+ *
+ * @param deviceId 设备ID
+ * @return 激活码
+ */
+ String geCodeByDeviceId(String deviceId);
}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java
index 685536c6..71531c76 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java
@@ -9,43 +9,51 @@ import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
import cn.hutool.core.util.RandomUtil;
-import org.springframework.transaction.annotation.Transactional;
+import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.RenException;
+import xiaozhi.common.page.PageData;
import xiaozhi.common.service.impl.BaseServiceImpl;
import xiaozhi.common.user.UserDetail;
import xiaozhi.common.utils.ConvertUtils;
+import xiaozhi.common.utils.DateUtils;
import xiaozhi.modules.device.dao.DeviceDao;
-import xiaozhi.modules.device.dto.DeviceBindDTO;
+import xiaozhi.modules.device.dto.DevicePageUserDTO;
import xiaozhi.modules.device.dto.DeviceReportReqDTO;
import xiaozhi.modules.device.dto.DeviceReportRespDTO;
import xiaozhi.modules.device.entity.DeviceEntity;
import xiaozhi.modules.device.service.DeviceService;
+import xiaozhi.modules.device.vo.UserShowDeviceListVO;
import xiaozhi.modules.security.user.SecurityUser;
+import xiaozhi.modules.sys.service.SysParamsService;
+import xiaozhi.modules.sys.service.SysUserUtilService;
@Service
public class DeviceServiceImpl extends BaseServiceImpl implements DeviceService {
private final DeviceDao deviceDao;
+ private final SysUserUtilService sysUserUtilService;
+
private final String frontedUrl;
private final RedisTemplate redisTemplate;
// 添加构造函数来初始化 deviceMapper
- public DeviceServiceImpl(DeviceDao deviceDao,
- @Value("${app.fronted-url:http://localhost:8001}") String frontedUrl,
+ public DeviceServiceImpl(DeviceDao deviceDao, SysUserUtilService sysUserUtilService,
+ SysParamsService sysParamsService,
RedisTemplate redisTemplate) {
this.deviceDao = deviceDao;
- this.frontedUrl = frontedUrl;
+ this.sysUserUtilService = sysUserUtilService;
+ this.frontedUrl = sysParamsService.getValue(Constant.SERVER_FRONTED_URL, true);
this.redisTemplate = redisTemplate;
}
@@ -57,7 +65,7 @@ public class DeviceServiceImpl extends BaseServiceImpl
}
@Override
- public Boolean deviceActivation(String activationCode) {
+ public Boolean deviceActivation(String agentId, String activationCode) {
if (StringUtils.isBlank(activationCode)) {
throw new RenException("激活码不能为空");
}
@@ -94,6 +102,7 @@ public class DeviceServiceImpl extends BaseServiceImpl
DeviceEntity deviceEntity = new DeviceEntity();
deviceEntity.setId(deviceId);
deviceEntity.setBoard(board);
+ deviceEntity.setAgentId(agentId);
deviceEntity.setAppVersion(appVersion);
deviceEntity.setMacAddress(macAddress);
deviceEntity.setUserId(user.getId());
@@ -111,77 +120,30 @@ public class DeviceServiceImpl extends BaseServiceImpl
}
@Override
- public DeviceReportRespDTO checkDeviceActive(String macAddress, String deviceId, String clientId,
+ public DeviceReportRespDTO checkDeviceActive(String macAddress, String clientId,
DeviceReportReqDTO deviceReport) {
DeviceReportRespDTO response = new DeviceReportRespDTO();
- response.setServerTime(buildServerTime());
+ response.setServer_time(buildServerTime());
// todo: 此处是固件信息,目前是针对固件上传上来的版本号再返回回去
// 在未来开发了固件更新功能,需要更换此处代码,
// 或写定时任务定期请求虾哥的OTA,获取最新的版本讯息保存到服务内
DeviceReportRespDTO.Firmware firmware = new DeviceReportRespDTO.Firmware();
firmware.setVersion(deviceReport.getApplication().getVersion());
- firmware.setUrl("http://localhost:8002/xiaozhi-esp32-api/api/v1/ota/download");
+ firmware.setUrl("http://localhost:8002/xiaozhi/ota/download");
response.setFirmware(firmware);
- DeviceEntity deviceById = getDeviceById(deviceId);
+ DeviceEntity deviceById = getDeviceById(macAddress);
if (deviceById != null) { // 如果设备存在,则更新上次连接时间
deviceById.setLastConnectedAt(new Date());
deviceDao.updateById(deviceById);
} else { // 如果设备不存在,则生成激活码
- String safeDeviceId = deviceId.replace(":", "_").toLowerCase();
- String dataKey = String.format("ota:activation:data:%s", safeDeviceId);
-
- Map cacheMap = redisTemplate.opsForHash().entries(dataKey);
- DeviceReportRespDTO.Activation code = new DeviceReportRespDTO.Activation();
-
- if (cacheMap != null && cacheMap.containsKey("activation_code")) {
- String cachedCode = (String) cacheMap.get("activation_code");
- code.setCode(cachedCode);
- code.setMessage(frontedUrl + "\n" + cachedCode);
- } else {
- String newCode = RandomUtil.randomNumbers(6);
- code.setCode(newCode);
- code.setMessage(frontedUrl + "\n" + newCode);
-
- Map dataMap = new HashMap<>();
- dataMap.put("id", deviceId);
- dataMap.put("mac_address", macAddress);
- dataMap.put("board", (deviceReport.getChipModelName() != null) ? deviceReport.getChipModelName()
- : (deviceReport.getBoard() != null ? deviceReport.getBoard().getType() : "unknown"));
- dataMap.put("app_version", (deviceReport.getApplication() != null)
- ? deviceReport.getApplication().getVersion()
- : null);
- dataMap.put("deviceId", deviceId);
- dataMap.put("activation_code", newCode);
-
- // 写入主数据 key
- redisTemplate.opsForHash().putAll(dataKey, dataMap);
- redisTemplate.expire(dataKey, 24, TimeUnit.HOURS);
-
- // 写入反查激活码 key
- String codeKey = "ota:activation:code:" + newCode;
- redisTemplate.opsForValue().set(codeKey, deviceId, 24, TimeUnit.HOURS);
- }
-
+ DeviceReportRespDTO.Activation code = buildActivation(macAddress, deviceReport);
response.setActivation(code);
}
return response;
}
- @Override
- public DeviceEntity bindDevice(DeviceBindDTO dto) {
- // 查看是否已经被绑定
- DeviceEntity deviceEntity = baseDao
- .selectOne(new LambdaQueryWrapper().eq(DeviceEntity::getMacAddress, dto.getMacAddress()));
- if (deviceEntity != null) {
- throw new RenException("设备已绑定");
- }
- deviceEntity = ConvertUtils.sourceToTarget(dto, DeviceEntity.class);
- baseDao.insert(deviceEntity);
- return deviceEntity;
- }
-
@Override
public List getUserDevices(Long userId, String agentId) {
QueryWrapper wrapper = new QueryWrapper<>();
@@ -205,12 +167,117 @@ public class DeviceServiceImpl extends BaseServiceImpl
baseDao.delete(wrapper);
}
+ @Override
+ public Long selectCountByUserId(Long userId) {
+ UpdateWrapper wrapper = new UpdateWrapper<>();
+ wrapper.eq("user_id", userId);
+ return baseDao.selectCount(wrapper);
+ }
+
+ @Override
+ public void deleteByAgentId(String agentId) {
+ UpdateWrapper wrapper = new UpdateWrapper<>();
+ wrapper.eq("agent_id", agentId);
+ baseDao.delete(wrapper);
+ }
+
+ @Override
+ public PageData page(DevicePageUserDTO dto) {
+ Map params = new HashMap();
+ params.put(Constant.PAGE, dto.getPage());
+ params.put(Constant.LIMIT, dto.getLimit());
+ IPage page = baseDao.selectPage(
+ getPage(params, "mac_address", true),
+ // 定义查询条件
+ new QueryWrapper()
+ // 必须设备关键词查找
+ .like(StringUtils.isNotBlank(dto.getKeywords()), "alias", dto.getKeywords()));
+ // 循环处理page获取回来的数据,返回需要的字段
+ List list = page.getRecords().stream().map(device -> {
+ UserShowDeviceListVO vo = ConvertUtils.sourceToTarget(device, UserShowDeviceListVO.class);
+ // 把最后修改的时间,改为简短描述的时间
+ vo.setRecentChatTime(DateUtils.getShortTime(device.getUpdateDate()));
+ sysUserUtilService.assignUsername(device.getUserId(),
+ vo::setBindUserName);
+ vo.setDeviceType(device.getBoard());
+ return vo;
+ }).toList();
+ // 计算页数
+ return new PageData<>(list, page.getTotal());
+ }
+
+ @Override
+ public DeviceEntity getDeviceByMacAddress(String macAddress) {
+ if (StringUtils.isBlank(macAddress)) {
+ return null;
+ }
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.eq("mac_address", macAddress);
+ return baseDao.selectOne(wrapper);
+ }
+
private DeviceReportRespDTO.ServerTime buildServerTime() {
DeviceReportRespDTO.ServerTime serverTime = new DeviceReportRespDTO.ServerTime();
TimeZone tz = TimeZone.getDefault();
serverTime.setTimestamp(Instant.now().toEpochMilli());
serverTime.setTimeZone(tz.getID());
- serverTime.setTimezoneOffset(tz.getOffset(System.currentTimeMillis()) / (60 * 1000));
+ serverTime.setTimezone_offset(tz.getOffset(System.currentTimeMillis()) / (60 * 1000));
return serverTime;
}
+
+ @Override
+ public String geCodeByDeviceId(String deviceId) {
+ String dataKey = getDeviceCacheKey(deviceId);
+
+ Map cacheMap = redisTemplate.opsForHash().entries(dataKey);
+ if (cacheMap != null && cacheMap.containsKey("activation_code")) {
+ String cachedCode = (String) cacheMap.get("activation_code");
+ return cachedCode;
+ }
+ return null;
+ }
+
+ private String getDeviceCacheKey(String deviceId) {
+ String safeDeviceId = deviceId.replace(":", "_").toLowerCase();
+ String dataKey = String.format("ota:activation:data:%s", safeDeviceId);
+ return dataKey;
+ }
+
+ public DeviceReportRespDTO.Activation buildActivation(String deviceId, DeviceReportReqDTO deviceReport) {
+ DeviceReportRespDTO.Activation code = new DeviceReportRespDTO.Activation();
+
+ String cachedCode = geCodeByDeviceId(deviceId);
+
+ if (StringUtils.isNotBlank(cachedCode)) {
+ code.setCode(cachedCode);
+ code.setMessage(frontedUrl + "\n" + cachedCode);
+ } else {
+ String newCode = RandomUtil.randomNumbers(6);
+ code.setCode(newCode);
+ code.setMessage(frontedUrl + "\n" + newCode);
+
+ Map dataMap = new HashMap<>();
+ dataMap.put("id", deviceId);
+ dataMap.put("mac_address", deviceId);
+
+ dataMap.put("board", (deviceReport.getChipModelName() != null) ? deviceReport.getChipModelName()
+ : (deviceReport.getBoard() != null ? deviceReport.getBoard().getType() : "unknown"));
+ dataMap.put("app_version", (deviceReport.getApplication() != null)
+ ? deviceReport.getApplication().getVersion()
+ : null);
+
+ dataMap.put("deviceId", deviceId);
+ dataMap.put("activation_code", newCode);
+
+ // 写入主数据 key
+ String dataKey = getDeviceCacheKey(deviceId);
+ redisTemplate.opsForHash().putAll(dataKey, dataMap);
+ redisTemplate.expire(dataKey, 24, TimeUnit.HOURS);
+
+ // 写入反查激活码 key
+ String codeKey = "ota:activation:code:" + newCode;
+ redisTemplate.opsForValue().set(codeKey, deviceId, 24, TimeUnit.HOURS);
+ }
+ return code;
+ }
}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/vo/UserShowDeviceListVO.java b/main/manager-api/src/main/java/xiaozhi/modules/device/vo/UserShowDeviceListVO.java
new file mode 100644
index 00000000..e3a5d8fd
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/device/vo/UserShowDeviceListVO.java
@@ -0,0 +1,31 @@
+package xiaozhi.modules.device.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "用户显示设备列表VO")
+public class UserShowDeviceListVO {
+
+ @Schema(description = "app版本")
+ private String appVersion;
+
+ @Schema(description = "绑定用户名称")
+ private String bindUserName;
+
+ @Schema(description = "设备型号")
+ private String deviceType;
+
+ @Schema(description = "设备唯一标识符")
+ private String id;
+
+ @Schema(description = "mac地址")
+ private String macAddress;
+
+ @Schema(description = "开启OTA")
+ private Integer otaUpgrade;
+
+ @Schema(description = "最近对话时间")
+ private String recentChatTime;
+
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/controller/ModelController.java b/main/manager-api/src/main/java/xiaozhi/modules/model/controller/ModelController.java
index af1e772f..8baff29d 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/model/controller/ModelController.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/model/controller/ModelController.java
@@ -17,13 +17,19 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import xiaozhi.common.page.PageData;
+import xiaozhi.common.utils.ConvertUtils;
import xiaozhi.common.utils.Result;
+import xiaozhi.modules.agent.service.AgentTemplateService;
+import xiaozhi.modules.config.service.ConfigService;
+import xiaozhi.modules.model.dto.ModelBasicInfoDTO;
import xiaozhi.modules.model.dto.ModelConfigBodyDTO;
import xiaozhi.modules.model.dto.ModelConfigDTO;
import xiaozhi.modules.model.dto.ModelProviderDTO;
-import xiaozhi.modules.model.dto.ModelProviderFieldDTO;
+import xiaozhi.modules.model.dto.VoiceDTO;
+import xiaozhi.modules.model.entity.ModelConfigEntity;
import xiaozhi.modules.model.service.ModelConfigService;
import xiaozhi.modules.model.service.ModelProviderService;
+import xiaozhi.modules.timbre.service.TimbreService;
@AllArgsConstructor
@RestController
@@ -32,16 +38,18 @@ import xiaozhi.modules.model.service.ModelProviderService;
public class ModelController {
private final ModelProviderService modelProviderService;
-
+ private final TimbreService timbreService;
private final ModelConfigService modelConfigService;
+ private final ConfigService configService;
+ private final AgentTemplateService agentTemplateService;
- @GetMapping("/models/names")
+ @GetMapping("/names")
@Operation(summary = "获取所有模型名称")
- @RequiresPermissions("sys:role:superAdmin")
- public Result> getModelNames(@RequestParam String modelType,
+ @RequiresPermissions("sys:role:normal")
+ public Result> getModelNames(@RequestParam String modelType,
@RequestParam(required = false) String modelName) {
- List modelNameList = modelConfigService.getModelCodeList(modelType, modelName);
- return new Result>().ok(modelNameList);
+ List modelList = modelConfigService.getModelCodeList(modelType, modelName);
+ return new Result>().ok(modelList);
}
@GetMapping("/{modelType}/provideTypes")
@@ -52,16 +60,7 @@ public class ModelController {
return new Result>().ok(modelProviderDTOS);
}
- @GetMapping("/{modelType}/{provideCode}/fields")
- @Operation(summary = "获取模型供应器字段")
- @RequiresPermissions("sys:role:superAdmin")
- public Result> getModelProviderFields(@PathVariable String modelType,
- @PathVariable String provideCode) {
- List fieldList = modelProviderService.getFieldList(modelType, provideCode);
- return new Result>().ok(fieldList);
- }
-
- @GetMapping("/models/list")
+ @GetMapping("/list")
@Operation(summary = "获取模型配置列表")
@RequiresPermissions("sys:role:superAdmin")
public Result> getModelConfigList(
@@ -73,17 +72,18 @@ public class ModelController {
return new Result>().ok(pageList);
}
- @PostMapping("/models/{modelType}/{provideCode}")
+ @PostMapping("/{modelType}/{provideCode}")
@Operation(summary = "新增模型配置")
@RequiresPermissions("sys:role:superAdmin")
public Result addModelConfig(@PathVariable String modelType,
@PathVariable String provideCode,
@RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
ModelConfigDTO modelConfigDTO = modelConfigService.add(modelType, provideCode, modelConfigBodyDTO);
+ configService.getConfig(false);
return new Result().ok(modelConfigDTO);
}
- @PutMapping("/models/{modelType}/{provideCode}/{id}")
+ @PutMapping("/{modelType}/{provideCode}/{id}")
@Operation(summary = "编辑模型配置")
@RequiresPermissions("sys:role:superAdmin")
public Result editModelConfig(@PathVariable String modelType,
@@ -91,25 +91,67 @@ public class ModelController {
@PathVariable String id,
@RequestBody ModelConfigBodyDTO modelConfigBodyDTO) {
ModelConfigDTO modelConfigDTO = modelConfigService.edit(modelType, provideCode, id, modelConfigBodyDTO);
+ configService.getConfig(false);
return new Result().ok(modelConfigDTO);
}
- @DeleteMapping("/models/{modelType}/{provideCode}/{id}")
+ @DeleteMapping("/{id}")
@Operation(summary = "删除模型配置")
@RequiresPermissions("sys:role:superAdmin")
- public Result deleteModelConfig(@PathVariable String modelType, @PathVariable String provideCode,
- @PathVariable String id) {
- modelConfigService.delete(modelType, provideCode, id);
+ public Result deleteModelConfig(@PathVariable String id) {
+ modelConfigService.delete(id);
return new Result<>();
}
- @GetMapping("/models/{modelId}/voices")
+ @GetMapping("/{id}")
+ @Operation(summary = "获取模型配置")
+ @RequiresPermissions("sys:role:superAdmin")
+ public Result getModelConfig(@PathVariable String id) {
+ ModelConfigEntity item = modelConfigService.selectById(id);
+ ModelConfigDTO modelConfigDTO = ConvertUtils.sourceToTarget(item, ModelConfigDTO.class);
+ return new Result().ok(modelConfigDTO);
+ }
+
+ @PutMapping("/enable/{id}/{status}")
+ @Operation(summary = "启用/关闭模型配置")
+ @RequiresPermissions("sys:role:superAdmin")
+ public Result enableModelConfig(@PathVariable String id, @PathVariable Integer status) {
+ ModelConfigEntity entity = modelConfigService.selectById(id);
+ if (entity == null) {
+ return new Result().error("模型配置不存在");
+ }
+ entity.setIsEnabled(status);
+ modelConfigService.updateById(entity);
+ return new Result();
+ }
+
+ @PutMapping("/default/{id}")
+ @Operation(summary = "设置默认模型")
+ @RequiresPermissions("sys:role:superAdmin")
+ public Result setDefaultModel(@PathVariable String id) {
+ ModelConfigEntity entity = modelConfigService.selectById(id);
+ if (entity == null) {
+ return new Result().error("模型配置不存在");
+ }
+ // 将其他模型设置为非默认
+ modelConfigService.setDefaultModel(entity.getModelType(), 0);
+ entity.setIsEnabled(1);
+ entity.setIsDefault(1);
+ modelConfigService.updateById(entity);
+
+ // 更新模板表中对应的模型ID
+ agentTemplateService.updateDefaultTemplateModelId(entity.getModelType(), entity.getId());
+
+ configService.getConfig(false);
+ return new Result();
+ }
+
+ @GetMapping("/{modelId}/voices")
@Operation(summary = "获取模型音色")
@RequiresPermissions("sys:role:normal")
- public Result> getVoiceList(@PathVariable String modelId,
+ public Result> getVoiceList(@PathVariable String modelId,
@RequestParam(required = false) String voiceName) {
-
- List voiceList = modelConfigService.getVoiceList(modelId, voiceName);
- return new Result>().ok(voiceList);
+ List voiceList = timbreService.getVoiceNames(modelId, voiceName);
+ return new Result>().ok(voiceList);
}
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelBasicInfoDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelBasicInfoDTO.java
new file mode 100644
index 00000000..571c791a
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelBasicInfoDTO.java
@@ -0,0 +1,9 @@
+package xiaozhi.modules.model.dto;
+
+import lombok.Data;
+
+@Data
+public class ModelBasicInfoDTO {
+ private String id;
+ private String modelName;
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelConfigBodyDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelConfigBodyDTO.java
index 3e335bf0..07758def 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelConfigBodyDTO.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelConfigBodyDTO.java
@@ -2,6 +2,7 @@ package xiaozhi.modules.model.dto;
import java.io.Serial;
+import cn.hutool.json.JSONObject;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -28,7 +29,7 @@ public class ModelConfigBodyDTO {
private Integer isEnabled;
@Schema(description = "模型配置(JSON格式)")
- private String configJson;
+ private JSONObject configJson;
@Schema(description = "官方文档链接")
private String docLink;
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelConfigDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelConfigDTO.java
index a7b1b436..ed73e1ff 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelConfigDTO.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelConfigDTO.java
@@ -3,6 +3,7 @@ package xiaozhi.modules.model.dto;
import java.io.Serial;
import java.io.Serializable;
+import cn.hutool.json.JSONObject;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -32,7 +33,7 @@ public class ModelConfigDTO implements Serializable {
private Integer isEnabled;
@Schema(description = "模型配置(JSON格式)")
- private String configJson;
+ private JSONObject configJson;
@Schema(description = "官方文档链接")
private String docLink;
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelProviderFieldDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelProviderFieldDTO.java
deleted file mode 100644
index 8186b363..00000000
--- a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/ModelProviderFieldDTO.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package xiaozhi.modules.model.dto;
-
-import java.io.Serializable;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-@Data
-@Schema(description = "模型供应器字段")
-public class ModelProviderFieldDTO implements Serializable {
- @Schema(description = "字段名")
- private String key;
-
- @Schema(description = "字段标签")
- private String label;
-
- @Schema(description = "字段类型")
- private String type;
-}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java
new file mode 100644
index 00000000..25358eb0
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/model/dto/VoiceDTO.java
@@ -0,0 +1,22 @@
+package xiaozhi.modules.model.dto;
+
+import java.io.Serializable;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Schema(description = "音色信息")
+public class VoiceDTO implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @Schema(description = "音色ID")
+ private String id;
+
+ @Schema(description = "音色名称")
+ private String name;
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/entity/ModelConfigEntity.java b/main/manager-api/src/main/java/xiaozhi/modules/model/entity/ModelConfigEntity.java
index 0111ea96..32ff911f 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/model/entity/ModelConfigEntity.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/model/entity/ModelConfigEntity.java
@@ -9,11 +9,12 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import cn.hutool.json.JSONObject;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
-@TableName("ai_model_config")
+@TableName(value = "ai_model_config", autoResultMap = true)
@Schema(description = "模型配置表")
public class ModelConfigEntity {
@@ -38,7 +39,7 @@ public class ModelConfigEntity {
@TableField(typeHandler = JacksonTypeHandler.class)
@Schema(description = "模型配置(JSON格式)")
- private String configJson;
+ private JSONObject configJson;
@Schema(description = "官方文档链接")
private String docLink;
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelConfigService.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelConfigService.java
index 78e9d0ce..9d15ac6d 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelConfigService.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelConfigService.java
@@ -3,12 +3,15 @@ package xiaozhi.modules.model.service;
import java.util.List;
import xiaozhi.common.page.PageData;
+import xiaozhi.common.service.BaseService;
+import xiaozhi.modules.model.dto.ModelBasicInfoDTO;
import xiaozhi.modules.model.dto.ModelConfigBodyDTO;
import xiaozhi.modules.model.dto.ModelConfigDTO;
+import xiaozhi.modules.model.entity.ModelConfigEntity;
-public interface ModelConfigService {
+public interface ModelConfigService extends BaseService {
- List getModelCodeList(String modelType, String modelName);
+ List getModelCodeList(String modelType, String modelName);
PageData getPageList(String modelType, String modelName, String page, String limit);
@@ -16,7 +19,30 @@ public interface ModelConfigService {
ModelConfigDTO edit(String modelType, String provideCode, String id, ModelConfigBodyDTO modelConfigBodyDTO);
- void delete(String modelType, String provideCode, String id);
+ void delete(String id);
- List getVoiceList(String modelName, String voiceName);
+ /**
+ * 根据ID获取模型名称
+ *
+ * @param id 模型ID
+ * @return 模型名称
+ */
+ String getModelNameById(String id);
+
+ /**
+ * 根据ID获取模型配置
+ *
+ * @param id 模型ID
+ * @param isCache 是否缓存
+ * @return 模型配置实体
+ */
+ ModelConfigEntity getModelById(String id, boolean isCache);
+
+ /**
+ * 设置默认模型
+ *
+ * @param modelType 模型类型
+ * @param isDefault 是否默认
+ */
+ void setDefaultModel(String modelType, int isDefault);
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelProviderService.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelProviderService.java
index cb92c953..2ace101e 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelProviderService.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelProviderService.java
@@ -3,7 +3,6 @@ package xiaozhi.modules.model.service;
import java.util.List;
import xiaozhi.modules.model.dto.ModelProviderDTO;
-import xiaozhi.modules.model.dto.ModelProviderFieldDTO;
import xiaozhi.modules.model.entity.ModelProviderEntity;
public interface ModelProviderService {
@@ -19,6 +18,4 @@ public interface ModelProviderService {
void delete();
List getList(String modelType, String provideCode);
-
- List getFieldList(String modelType, String provideCode);
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java
index 6372dc0c..00d48486 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelConfigServiceImpl.java
@@ -5,8 +5,6 @@ import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -17,16 +15,18 @@ import lombok.AllArgsConstructor;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.exception.RenException;
import xiaozhi.common.page.PageData;
+import xiaozhi.common.redis.RedisKeys;
+import xiaozhi.common.redis.RedisUtils;
import xiaozhi.common.service.impl.BaseServiceImpl;
import xiaozhi.common.utils.ConvertUtils;
import xiaozhi.modules.model.dao.ModelConfigDao;
+import xiaozhi.modules.model.dto.ModelBasicInfoDTO;
import xiaozhi.modules.model.dto.ModelConfigBodyDTO;
import xiaozhi.modules.model.dto.ModelConfigDTO;
import xiaozhi.modules.model.dto.ModelProviderDTO;
import xiaozhi.modules.model.entity.ModelConfigEntity;
import xiaozhi.modules.model.service.ModelConfigService;
import xiaozhi.modules.model.service.ModelProviderService;
-import xiaozhi.modules.timbre.service.TimbreService;
@Service
@AllArgsConstructor
@@ -35,13 +35,17 @@ public class ModelConfigServiceImpl extends BaseServiceImpl getModelCodeList(String modelType, String modelName) {
- return modelConfigDao.getModelCodeList(modelType, modelName);
+ public List getModelCodeList(String modelType, String modelName) {
+ List entities = modelConfigDao.selectList(
+ new QueryWrapper()
+ .eq("model_type", modelType)
+ .eq("is_enabled", 1)
+ .like(StringUtils.isNotBlank(modelName), "model_name", "%" + modelName + "%")
+ .select("id", "model_name"));
+ return ConvertUtils.sourceToTarget(entities, ModelBasicInfoDTO.class);
}
@Override
@@ -91,25 +95,63 @@ public class ModelConfigServiceImpl extends BaseServiceImpl providerList = modelProviderService.getList(modelType, provideCode);
- if (CollectionUtil.isEmpty(providerList)) {
- throw new RenException("供应器不存在");
- }
-
+ public void delete(String id) {
modelConfigDao.deleteById(id);
}
@Override
- public List getVoiceList(String modelId, String voiceName) {
- return timbreService.getVoiceNames(modelId, voiceName);
+ public String getModelNameById(String id) {
+ if (StringUtils.isBlank(id)) {
+ return null;
+ }
+
+ String cachedName = (String) redisUtils.get(RedisKeys.getModelNameById(id));
+
+ if (StringUtils.isNotBlank(cachedName)) {
+ return cachedName;
+ }
+
+ ModelConfigEntity entity = modelConfigDao.selectById(id);
+ if (entity != null) {
+ String modelName = entity.getModelName();
+ if (StringUtils.isNotBlank(modelName)) {
+ redisUtils.set(RedisKeys.getModelNameById(id), modelName);
+ }
+ return modelName;
+ }
+
+ return null;
+ }
+
+ @Override
+ public ModelConfigEntity getModelById(String id, boolean isCache) {
+ if (StringUtils.isBlank(id)) {
+ return null;
+ }
+ if (isCache) {
+ ModelConfigEntity cachedConfig = (ModelConfigEntity) redisUtils.get(RedisKeys.getModelConfigById(id));
+ if (cachedConfig != null) {
+ return ConvertUtils.sourceToTarget(cachedConfig, ModelConfigEntity.class);
+ }
+ }
+ ModelConfigEntity entity = modelConfigDao.selectById(id);
+ if (entity != null) {
+ redisUtils.set(RedisKeys.getModelConfigById(id), entity);
+ }
+ return entity;
+ }
+
+ @Override
+ public void setDefaultModel(String modelType, int isDefault) {
+ ModelConfigEntity entity = new ModelConfigEntity();
+ entity.setIsDefault(isDefault);
+ modelConfigDao.update(entity, new QueryWrapper()
+ .eq("model_type", modelType));
}
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelProviderServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelProviderServiceImpl.java
index 7580d479..fb06e4d5 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelProviderServiceImpl.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelProviderServiceImpl.java
@@ -10,10 +10,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import xiaozhi.common.service.impl.BaseServiceImpl;
import xiaozhi.common.utils.ConvertUtils;
-import xiaozhi.common.utils.JsonUtils;
import xiaozhi.modules.model.dao.ModelProviderDao;
import xiaozhi.modules.model.dto.ModelProviderDTO;
-import xiaozhi.modules.model.dto.ModelProviderFieldDTO;
import xiaozhi.modules.model.entity.ModelProviderEntity;
import xiaozhi.modules.model.service.ModelProviderService;
@@ -56,15 +54,4 @@ public class ModelProviderServiceImpl extends BaseServiceImpl providerEntities = modelProviderDao.selectList(queryWrapper);
return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class);
}
-
- @Override
- public List getFieldList(String modelType, String providerCode) {
- List modelProviderEntities = modelProviderDao.getFieldList(modelType, providerCode);
- if (modelProviderEntities == null || modelProviderEntities.isEmpty()) {
- return null;
- }
- String fields = modelProviderEntities.getFirst();
- List fieldList = JsonUtils.parseArray(fields, ModelProviderFieldDTO.class);
- return fieldList;
- }
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java b/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java
index e5b89c99..fdcb62b2 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/security/config/ShiroConfig.java
@@ -76,8 +76,10 @@ public class ShiroConfig {
filterMap.put("/favicon.ico", "anon");
filterMap.put("/user/captcha", "anon");
filterMap.put("/user/login", "anon");
+ filterMap.put("/user/pub-config", "anon");
filterMap.put("/user/register", "anon");
- filterMap.put("/device/register", "anon");
+ filterMap.put("/config/server-base", "anon");
+ filterMap.put("/config/agent-models", "anon");
filterMap.put("/**", "oauth2");
shiroFilter.setFilterChainDefinitionMap(filterMap);
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java b/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java
index 7db612b5..bced5518 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/security/controller/LoginController.java
@@ -1,6 +1,8 @@
package xiaozhi.modules.security.controller;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@@ -75,6 +77,9 @@ public class LoginController {
@PostMapping("/register")
@Operation(summary = "注册")
public Result register(@RequestBody LoginDTO login) {
+ if (!sysUserService.getAllowUserRegister()) {
+ throw new RenException("当前不允许普通用户注册");
+ }
// 验证是否正确输入验证码
boolean validate = captchaService.validate(login.getCaptchaId(), login.getCaptcha());
if (!validate) {
@@ -111,4 +116,13 @@ public class LoginController {
sysUserTokenService.changePassword(userId, passwordDTO);
return new Result<>();
}
+
+ @GetMapping("/pub-config")
+ @Operation(summary = "公共配置")
+ public Result> pubConfig() {
+ Map config = new HashMap<>();
+ config.put("version", "0.3.5");
+ config.put("allowUserRegister", sysUserService.getAllowUserRegister());
+ return new Result>().ok(config);
+ }
}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/AdminController.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/AdminController.java
index 71470e57..e202e1e4 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/AdminController.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/AdminController.java
@@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@@ -20,6 +21,9 @@ import xiaozhi.common.constant.Constant;
import xiaozhi.common.page.PageData;
import xiaozhi.common.utils.Result;
import xiaozhi.common.validator.ValidatorUtils;
+import xiaozhi.modules.device.dto.DevicePageUserDTO;
+import xiaozhi.modules.device.service.DeviceService;
+import xiaozhi.modules.device.vo.UserShowDeviceListVO;
import xiaozhi.modules.sys.dto.AdminPageUserDTO;
import xiaozhi.modules.sys.service.SysUserService;
import xiaozhi.modules.sys.vo.AdminPageUserVO;
@@ -37,6 +41,8 @@ import xiaozhi.modules.sys.vo.AdminPageUserVO;
public class AdminController {
private final SysUserService sysUserService;
+ private final DeviceService deviceService;
+
@GetMapping("/users")
@Operation(summary = "分页查找用户")
@RequiresPermissions("sys:role:superAdmin")
@@ -51,7 +57,7 @@ public class AdminController {
dto.setMobile((String) params.get("mobile"));
dto.setLimit((String) params.get(Constant.LIMIT));
dto.setPage((String) params.get(Constant.PAGE));
-
+ ValidatorUtils.validateEntity(dto);
ValidatorUtils.validateEntity(dto);
PageData page = sysUserService.page(dto);
return new Result>().ok(page);
@@ -70,10 +76,19 @@ public class AdminController {
@Operation(summary = "用户删除")
@RequiresPermissions("sys:role:superAdmin")
public Result delete(@PathVariable Long id) {
- sysUserService.deleteById( id );
+ sysUserService.deleteById(id);
return new Result<>();
}
+ @PutMapping("/users/changeStatus/{status}")
+ @Operation(summary = "批量修改用户状态")
+ @RequiresPermissions("sys:role:superAdmin")
+ @Parameter(name = "status", description = "用户状态", required = true)
+ public Result changeStatus(@PathVariable Integer status, @RequestBody String[] userIds) {
+ sysUserService.changeStatus(status, userIds);
+ return new Result();
+ }
+
@GetMapping("/device/all")
@Operation(summary = "分页查找设备")
@RequiresPermissions("sys:role:superAdmin")
@@ -82,9 +97,14 @@ public class AdminController {
@Parameter(name = Constant.PAGE, description = "当前页码,从1开始", required = true),
@Parameter(name = Constant.LIMIT, description = "每页显示记录数", required = true),
})
- public Result pageDevice(
+ public Result> pageDevice(
@Parameter(hidden = true) @RequestParam Map params) {
- // TODO 等设备功能模块写好
- return new Result().error(600, "等设备功能模块写好");
+ DevicePageUserDTO dto = new DevicePageUserDTO();
+ dto.setKeywords((String) params.get("keywords"));
+ dto.setLimit((String) params.get(Constant.LIMIT));
+ dto.setPage((String) params.get(Constant.PAGE));
+ ValidatorUtils.validateEntity(dto);
+ PageData page = deviceService.page(dto);
+ return new Result>().ok(page);
}
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/SysParamsController.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/SysParamsController.java
new file mode 100644
index 00000000..1951333f
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/controller/SysParamsController.java
@@ -0,0 +1,111 @@
+package xiaozhi.modules.sys.controller;
+
+import java.util.Map;
+
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.AllArgsConstructor;
+import xiaozhi.common.annotation.LogOperation;
+import xiaozhi.common.constant.Constant;
+import xiaozhi.common.page.PageData;
+import xiaozhi.common.utils.Result;
+import xiaozhi.common.validator.AssertUtils;
+import xiaozhi.common.validator.ValidatorUtils;
+import xiaozhi.common.validator.group.AddGroup;
+import xiaozhi.common.validator.group.DefaultGroup;
+import xiaozhi.common.validator.group.UpdateGroup;
+import xiaozhi.modules.config.service.ConfigService;
+import xiaozhi.modules.sys.dto.SysParamsDTO;
+import xiaozhi.modules.sys.service.SysParamsService;
+
+/**
+ * 参数管理
+ *
+ * @author Mark sunlightcs@gmail.com
+ * @since 1.0.0
+ */
+@RestController
+@RequestMapping("admin/params")
+@Tag(name = "参数管理")
+@AllArgsConstructor
+public class SysParamsController {
+ private final SysParamsService sysParamsService;
+ private final ConfigService configService;
+
+ @GetMapping("page")
+ @Operation(summary = "分页")
+ @Parameters({
+ @Parameter(name = Constant.PAGE, description = "当前页码,从1开始", in = ParameterIn.QUERY, required = true, ref = "int"),
+ @Parameter(name = Constant.LIMIT, description = "每页显示记录数", in = ParameterIn.QUERY, required = true, ref = "int"),
+ @Parameter(name = Constant.ORDER_FIELD, description = "排序字段", in = ParameterIn.QUERY, ref = "String"),
+ @Parameter(name = Constant.ORDER, description = "排序方式,可选值(asc、desc)", in = ParameterIn.QUERY, ref = "String"),
+ @Parameter(name = "paramCode", description = "参数编码", in = ParameterIn.QUERY, ref = "String")
+ })
+ @RequiresPermissions("sys:role:superAdmin")
+ public Result> page(@Parameter(hidden = true) @RequestParam Map params) {
+ PageData page = sysParamsService.page(params);
+
+ return new Result>().ok(page);
+ }
+
+ @GetMapping("{id}")
+ @Operation(summary = "信息")
+ @RequiresPermissions("sys:role:superAdmin")
+ public Result get(@PathVariable("id") Long id) {
+ SysParamsDTO data = sysParamsService.get(id);
+
+ return new Result().ok(data);
+ }
+
+ @PostMapping
+ @Operation(summary = "保存")
+ @LogOperation("保存")
+ @RequiresPermissions("sys:role:superAdmin")
+ public Result save(@RequestBody SysParamsDTO dto) {
+ // 效验数据
+ ValidatorUtils.validateEntity(dto, AddGroup.class, DefaultGroup.class);
+
+ sysParamsService.save(dto);
+ configService.getConfig(false);
+ return new Result();
+ }
+
+ @PutMapping
+ @Operation(summary = "修改")
+ @LogOperation("修改")
+ @RequiresPermissions("sys:role:superAdmin")
+ public Result update(@RequestBody SysParamsDTO dto) {
+ // 效验数据
+ ValidatorUtils.validateEntity(dto, UpdateGroup.class, DefaultGroup.class);
+
+ sysParamsService.update(dto);
+ configService.getConfig(false);
+ return new Result();
+ }
+
+ @PostMapping("/delete")
+ @Operation(summary = "删除")
+ @LogOperation("删除")
+ @RequiresPermissions("sys:role:superAdmin")
+ public Result delete(@RequestBody String[] ids) {
+ // 效验数据
+ AssertUtils.isArrayEmpty(ids, "id");
+
+ sysParamsService.delete(ids);
+ configService.getConfig(false);
+ return new Result();
+ }
+}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/dao/SysParamsDao.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/dao/SysParamsDao.java
index d35d1445..6eebc8be 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/sys/dao/SysParamsDao.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/dao/SysParamsDao.java
@@ -27,7 +27,7 @@ public interface SysParamsDao extends BaseDao {
* @param ids ids
* @return 返回参数编码列表
*/
- List getParamCodeList(Long[] ids);
+ List getParamCodeList(String[] ids);
/**
* 根据参数编码,更新value
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/AdminPageUserDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/AdminPageUserDTO.java
index 7de3843a..a9d960a1 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/AdminPageUserDTO.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/AdminPageUserDTO.java
@@ -1,6 +1,7 @@
package xiaozhi.modules.sys.dto;
import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.Min;
import lombok.Data;
/**
@@ -10,15 +11,17 @@ import lombok.Data;
* @since 2025-3-21
*/
@Data
-@Schema(description = "音色分页参数")
+@Schema(description = "管理员分页用户的参数DTO")
public class AdminPageUserDTO {
@Schema(description = "手机号码")
private String mobile;
@Schema(description = "页数")
+ @Min(value = 0, message = "{sort.number}")
private String page;
@Schema(description = "显示列数")
+ @Min(value = 0, message = "{sort.number}")
private String limit;
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/ConfigSecretDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/ConfigSecretDTO.java
new file mode 100644
index 00000000..8e4978f9
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/ConfigSecretDTO.java
@@ -0,0 +1,13 @@
+package xiaozhi.modules.sys.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+
+@Data
+@Schema(description = "配置密钥DTO")
+public class ConfigSecretDTO {
+ @Schema(description = "密钥")
+ @NotBlank(message = "密钥不能为空")
+ private String secret;
+}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/SysParamsDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/SysParamsDTO.java
index 7b4dd28d..ad816b35 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/SysParamsDTO.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/dto/SysParamsDTO.java
@@ -10,6 +10,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
+import jakarta.validation.constraints.Pattern;
import lombok.Data;
import xiaozhi.common.utils.DateUtils;
import xiaozhi.common.validator.group.AddGroup;
@@ -36,6 +37,11 @@ public class SysParamsDTO implements Serializable {
@NotBlank(message = "{sysparams.paramvalue.require}", groups = DefaultGroup.class)
private String paramValue;
+ @Schema(description = "值类型")
+ @NotBlank(message = "{sysparams.valuetype.require}", groups = DefaultGroup.class)
+ @Pattern(regexp = "^(string|number|boolean|array)$", message = "{sysparams.valuetype.pattern}", groups = DefaultGroup.class)
+ private String valueType;
+
@Schema(description = "备注")
private String remark;
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/entity/SysParamsEntity.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/entity/SysParamsEntity.java
index 989800e2..c51c46fa 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/sys/entity/SysParamsEntity.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/entity/SysParamsEntity.java
@@ -25,6 +25,10 @@ public class SysParamsEntity extends BaseEntity {
* 参数值
*/
private String paramValue;
+ /**
+ * 值类型:string-字符串,number-数字,boolean-布尔,array-数组
+ */
+ private String valueType;
/**
* 类型 0:系统参数 1:非系统参数
*/
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysParamsService.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysParamsService.java
index 7475f346..ac67a276 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysParamsService.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysParamsService.java
@@ -23,14 +23,15 @@ public interface SysParamsService extends BaseService {
void update(SysParamsDTO dto);
- void delete(Long[] ids);
+ void delete(String[] ids);
/**
* 根据参数编码,获取参数的value值
*
* @param paramCode 参数编码
+ * @param fromCache 是否从缓存中获取
*/
- String getValue(String paramCode);
+ String getValue(String paramCode, Boolean fromCache);
/**
* 根据参数编码,获取value的Object对象
@@ -47,4 +48,9 @@ public interface SysParamsService extends BaseService {
* @param paramValue 参数值
*/
int updateValueByCode(String paramCode, String paramValue);
+
+ /**
+ * 初始化服务器密钥
+ */
+ void initServerSecret();
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysUserService.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysUserService.java
index 1b9ac9bc..7a35da32 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysUserService.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysUserService.java
@@ -21,6 +21,7 @@ public interface SysUserService extends BaseService {
/**
* 删除指定用户,且有关联的数据设备和智能体
+ *
* @param ids
*/
void deleteById(Long ids);
@@ -56,4 +57,19 @@ public interface SysUserService extends BaseService {
* @return 用户列表分页数据
*/
PageData page(AdminPageUserDTO dto);
+
+ /**
+ * 批量修改用户状态
+ *
+ * @param status 用户状态
+ * @param userIds 用户ID数组
+ */
+ void changeStatus(Integer status, String[] userIds);
+
+ /**
+ * 获取是否允许用户注册
+ *
+ * @return 是否允许用户注册
+ */
+ boolean getAllowUserRegister();
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysUserUtilService.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysUserUtilService.java
new file mode 100644
index 00000000..0fa3fc4a
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/SysUserUtilService.java
@@ -0,0 +1,19 @@
+package xiaozhi.modules.sys.service;
+
+
+import java.util.function.Consumer;
+
+/**
+ * 定义一个系统用户工具类,避免和用户模块循环依赖
+ * 如用户和设备互相依赖,用户需要获取所有设备,设备又需要获取每个设备的用户名
+ * @author zjy
+ * @since 2025-4-2
+ */
+public interface SysUserUtilService {
+ /**
+ * 赋值用户名
+ * @param userId 用户id
+ * @param setter 赋值方法
+ */
+ void assignUsername( Long userId, Consumer setter);
+}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysParamsServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysParamsServiceImpl.java
index b274f23c..15f62816 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysParamsServiceImpl.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysParamsServiceImpl.java
@@ -3,6 +3,7 @@ package xiaozhi.modules.sys.service.impl;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@@ -36,7 +37,7 @@ public class SysParamsServiceImpl extends BaseServiceImpl page(Map params) {
IPage page = baseDao.selectPage(
- getPage(params, Constant.CREATE_DATE, false),
+ getPage(params, null, false),
getWrapper(params));
return getPageData(page, SysParamsDTO.class);
@@ -69,6 +70,8 @@ public class SysParamsServiceImpl extends BaseServiceImpl paramCodeList = baseDao.getParamCodeList(ids);
String[] paramCodes = paramCodeList.toArray(new String[paramCodeList.size()]);
- sysParamsRedis.delete(paramCodes);
+ if (paramCodes.length > 0) {
+ sysParamsRedis.delete(paramCodes);
+ }
// 删除
deleteBatchIds(Arrays.asList(ids));
}
@Override
- public String getValue(String paramCode) {
- String paramValue = sysParamsRedis.get(paramCode);
- if (paramValue == null) {
- paramValue = baseDao.getValueByCode(paramCode);
+ public String getValue(String paramCode, Boolean fromCache) {
+ String paramValue = null;
+ if (fromCache) {
+ paramValue = sysParamsRedis.get(paramCode);
+ if (paramValue == null) {
+ paramValue = baseDao.getValueByCode(paramCode);
- sysParamsRedis.set(paramCode, paramValue);
+ sysParamsRedis.set(paramCode, paramValue);
+ }
+ } else {
+ paramValue = baseDao.getValueByCode(paramCode);
}
return paramValue;
}
@Override
public T getValueObject(String paramCode, Class clazz) {
- String paramValue = getValue(paramCode);
+ String paramValue = getValue(paramCode, true);
if (StringUtils.isNotBlank(paramValue)) {
return JsonUtils.parseObject(paramValue, clazz);
}
@@ -129,4 +189,13 @@ public class SysParamsServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>();
@@ -98,8 +101,7 @@ public class SysUserServiceImpl extends BaseServiceImpl page = baseDao.selectPage(
getPage(params, "id", true),
- // 定义查询条件
- new QueryWrapper()
- // 必须按照手机号码查找
- .eq(StringUtils.isNotBlank(dto.getMobile()), "username", dto.getMobile()));
+ new QueryWrapper().eq(StringUtils.isNotBlank(dto.getMobile()), "username",
+ dto.getMobile()));
+ // 循环处理page获取回来的数据,返回需要的字段
List list = page.getRecords().stream().map(user -> {
AdminPageUserVO adminPageUserVO = new AdminPageUserVO();
adminPageUserVO.setUserid(user.getId().toString());
adminPageUserVO.setMobile(user.getUsername());
+ String deviceCount = deviceService.selectCountByUserId(user.getId()).toString();
+ adminPageUserVO.setDeviceCount(deviceCount);
adminPageUserVO.setStatus(user.getStatus());
- // TODO 2. 等设备功能写好,获取对应数据
- adminPageUserVO.setDeviceCount("0");
return adminPageUserVO;
}).toList();
return new PageData<>(list, page.getTotal());
@@ -191,10 +192,33 @@ public class SysUserServiceImpl extends BaseServiceImpl());
+ if (userCount == 0) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysUserUtilServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysUserUtilServiceImpl.java
new file mode 100644
index 00000000..8fd0351a
--- /dev/null
+++ b/main/manager-api/src/main/java/xiaozhi/modules/sys/service/impl/SysUserUtilServiceImpl.java
@@ -0,0 +1,35 @@
+package xiaozhi.modules.sys.service.impl;
+
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import xiaozhi.common.redis.RedisKeys;
+import xiaozhi.common.redis.RedisUtils;
+import xiaozhi.common.service.impl.BaseServiceImpl;
+import xiaozhi.modules.sys.dao.SysUserDao;
+import xiaozhi.modules.sys.entity.SysUserEntity;
+import xiaozhi.modules.sys.service.SysUserUtilService;
+
+import java.util.function.Consumer;
+
+@Service
+@AllArgsConstructor
+public class SysUserUtilServiceImpl extends BaseServiceImpl implements SysUserUtilService {
+
+ private RedisUtils redisUtils;
+
+ @Override
+ public void assignUsername(Long userId, Consumer setter) {
+ String userIdKey = RedisKeys.getUserIdKey(userId);
+ String username = redisUtils.get(userIdKey).toString();
+ if(username != null){
+ setter.accept(username);
+ }else {
+ SysUserEntity entity = baseDao.selectById(userId);
+ if (entity != null) {
+ username = entity.getUsername();
+ redisUtils.set(userIdKey,username,10);
+ setter.accept(username);
+ }
+ }
+ }
+}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/timbre/controller/TimbreController.java b/main/manager-api/src/main/java/xiaozhi/modules/timbre/controller/TimbreController.java
index e13cb93e..ff420c02 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/timbre/controller/TimbreController.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/timbre/controller/TimbreController.java
@@ -3,7 +3,6 @@ package xiaozhi.modules.timbre.controller;
import java.util.Map;
import org.apache.shiro.authz.annotation.RequiresPermissions;
-import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@@ -82,11 +81,11 @@ public class TimbreController {
return new Result<>();
}
- @DeleteMapping("/{id}")
+ @PostMapping("/delete")
@Operation(summary = "音色删除")
@RequiresPermissions("sys:role:superAdmin")
- public Result delete(@PathVariable String id) {
- timbreService.delete(new String[] { id });
+ public Result delete(@RequestBody String[] ids) {
+ timbreService.delete(ids);
return new Result<>();
}
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/TimbreService.java b/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/TimbreService.java
index 4519e17a..eebd55be 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/TimbreService.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/TimbreService.java
@@ -4,6 +4,7 @@ import java.util.List;
import xiaozhi.common.page.PageData;
import xiaozhi.common.service.BaseService;
+import xiaozhi.modules.model.dto.VoiceDTO;
import xiaozhi.modules.timbre.dto.TimbreDataDTO;
import xiaozhi.modules.timbre.dto.TimbrePageDTO;
import xiaozhi.modules.timbre.entity.TimbreEntity;
@@ -30,7 +31,7 @@ public interface TimbreService extends BaseService {
* @param timbreId 音色表id
* @return 音色信息
*/
- TimbreDetailsVO get(Long timbreId);
+ TimbreDetailsVO get(String timbreId);
/**
* 保存音色信息
@@ -54,5 +55,13 @@ public interface TimbreService extends BaseService {
*/
void delete(String[] ids);
- List getVoiceNames(String ttsModelId, String voiceName);
+ List getVoiceNames(String ttsModelId, String voiceName);
+
+ /**
+ * 根据ID获取音色名称
+ *
+ * @param id 音色ID
+ * @return 音色名称
+ */
+ String getTimbreNameById(String id);
}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java
index 9496b6d5..2ed5b1ab 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/timbre/service/impl/TimbreServiceImpl.java
@@ -16,8 +16,11 @@ import cn.hutool.core.collection.CollectionUtil;
import lombok.AllArgsConstructor;
import xiaozhi.common.constant.Constant;
import xiaozhi.common.page.PageData;
+import xiaozhi.common.redis.RedisKeys;
+import xiaozhi.common.redis.RedisUtils;
import xiaozhi.common.service.impl.BaseServiceImpl;
import xiaozhi.common.utils.ConvertUtils;
+import xiaozhi.modules.model.dto.VoiceDTO;
import xiaozhi.modules.timbre.dao.TimbreDao;
import xiaozhi.modules.timbre.dto.TimbreDataDTO;
import xiaozhi.modules.timbre.dto.TimbrePageDTO;
@@ -36,6 +39,7 @@ import xiaozhi.modules.timbre.vo.TimbreDetailsVO;
public class TimbreServiceImpl extends BaseServiceImpl implements TimbreService {
private final TimbreDao timbreDao;
+ private final RedisUtils redisUtils;
@Override
public PageData page(TimbrePageDTO dto) {
@@ -43,7 +47,7 @@ public class TimbreServiceImpl extends BaseServiceImpl
params.put(Constant.PAGE, dto.getPage());
params.put(Constant.LIMIT, dto.getLimit());
IPage page = baseDao.selectPage(
- getPage(params, "sort", true),
+ getPage(params, null, true),
// 定义查询条件
new QueryWrapper()
// 必须按照ttsID查找
@@ -55,9 +59,33 @@ public class TimbreServiceImpl extends BaseServiceImpl
}
@Override
- public TimbreDetailsVO get(Long timbreId) {
+ public TimbreDetailsVO get(String timbreId) {
+ if (StringUtils.isBlank(timbreId)) {
+ return null;
+ }
+
+ // 先从Redis获取缓存
+ String key = RedisKeys.getTimbreDetailsKey(timbreId);
+ TimbreDetailsVO cachedDetails = (TimbreDetailsVO) redisUtils.get(key);
+ if (cachedDetails != null) {
+ return cachedDetails;
+ }
+
+ // 如果缓存中没有,则从数据库获取
TimbreEntity entity = baseDao.selectById(timbreId);
- return ConvertUtils.sourceToTarget(entity, TimbreDetailsVO.class);
+ if (entity == null) {
+ return null;
+ }
+
+ // 转换为VO对象
+ TimbreDetailsVO details = ConvertUtils.sourceToTarget(entity, TimbreDetailsVO.class);
+
+ // 存入Redis缓存
+ if (details != null) {
+ redisUtils.set(key, details);
+ }
+
+ return details;
}
@Override
@@ -75,6 +103,8 @@ public class TimbreServiceImpl extends BaseServiceImpl
TimbreEntity timbreEntity = ConvertUtils.sourceToTarget(dto, TimbreEntity.class);
timbreEntity.setId(timbreId);
baseDao.updateById(timbreEntity);
+ // 删除缓存
+ redisUtils.delete(RedisKeys.getTimbreDetailsKey(timbreId));
}
@Override
@@ -84,7 +114,7 @@ public class TimbreServiceImpl extends BaseServiceImpl
}
@Override
- public List getVoiceNames(String ttsModelId, String voiceName) {
+ public List getVoiceNames(String ttsModelId, String voiceName) {
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.eq("tts_model_id", StringUtils.isBlank(ttsModelId) ? "" : ttsModelId);
if (StringUtils.isNotBlank(voiceName)) {
@@ -95,7 +125,7 @@ public class TimbreServiceImpl extends BaseServiceImpl
return null;
}
- return timbreEntities.stream().map(TimbreEntity::getName).toList();
+ return ConvertUtils.sourceToTarget(timbreEntities, VoiceDTO.class);
}
/**
@@ -104,4 +134,28 @@ public class TimbreServiceImpl extends BaseServiceImpl
private void isTtsModelId(String ttsModelId) {
// 等模型配置那边写好调用方法判断
}
+
+ @Override
+ public String getTimbreNameById(String id) {
+ if (StringUtils.isBlank(id)) {
+ return null;
+ }
+
+ String cachedName = (String) redisUtils.get(RedisKeys.getTimbreNameById(id));
+
+ if (StringUtils.isNotBlank(cachedName)) {
+ return cachedName;
+ }
+
+ TimbreEntity entity = timbreDao.selectById(id);
+ if (entity != null) {
+ String name = entity.getName();
+ if (StringUtils.isNotBlank(name)) {
+ redisUtils.set(RedisKeys.getTimbreNameById(id), name);
+ }
+ return name;
+ }
+
+ return null;
+ }
}
\ No newline at end of file
diff --git a/main/manager-api/src/main/java/xiaozhi/modules/timbre/vo/TimbreDetailsVO.java b/main/manager-api/src/main/java/xiaozhi/modules/timbre/vo/TimbreDetailsVO.java
index 68cc7bbb..3f0ace40 100644
--- a/main/manager-api/src/main/java/xiaozhi/modules/timbre/vo/TimbreDetailsVO.java
+++ b/main/manager-api/src/main/java/xiaozhi/modules/timbre/vo/TimbreDetailsVO.java
@@ -14,7 +14,7 @@ import lombok.Data;
@Data
public class TimbreDetailsVO implements Serializable {
@Schema(description = "音色id")
- private Long id;
+ private String id;
@Schema(description = "语言")
private String languages;
diff --git a/main/manager-api/src/main/resources/application-dev.yml b/main/manager-api/src/main/resources/application-dev.yml
index e1671b50..b49b31ca 100644
--- a/main/manager-api/src/main/resources/application-dev.yml
+++ b/main/manager-api/src/main/resources/application-dev.yml
@@ -27,10 +27,7 @@ spring:
test-on-borrow: false
test-on-return: false
stat-view-servlet:
- enabled: true
- url-pattern: /druid/*
- login-username: admin
- login-password: D7Xj810i1C
+ enabled: false
filter:
stat:
log-slow-sql: true
diff --git a/main/manager-api/src/main/resources/application.yml b/main/manager-api/src/main/resources/application.yml
index 902b5198..3daf48a1 100644
--- a/main/manager-api/src/main/resources/application.yml
+++ b/main/manager-api/src/main/resources/application.yml
@@ -7,7 +7,7 @@ server:
min-spare: 30
port: 8002
servlet:
- context-path: /xiaozhi-esp32-api/api/v1
+ context-path: /xiaozhi
session:
cookie:
http-only: true
@@ -63,7 +63,4 @@ mybatis-plus:
configuration-properties:
prefix:
blobType: BLOB
- boolValue: TRUE
-
-app:
- fronted-url: http://localhost:8001
\ No newline at end of file
+ boolValue: TRUE
\ No newline at end of file
diff --git a/main/manager-api/src/main/resources/db/changelog/2025_model_provider.sql b/main/manager-api/src/main/resources/db/changelog/202504082211.sql
similarity index 91%
rename from main/manager-api/src/main/resources/db/changelog/2025_model_provider.sql
rename to main/manager-api/src/main/resources/db/changelog/202504082211.sql
index 5d7635d0..91ce33ff 100644
--- a/main/manager-api/src/main/resources/db/changelog/2025_model_provider.sql
+++ b/main/manager-api/src/main/resources/db/changelog/202504082211.sql
@@ -4,12 +4,12 @@
DELETE FROM `ai_model_provider`;
INSERT INTO `ai_model_provider` (`id`, `model_type`, `provider_code`, `name`, `fields`, `sort`, `creator`, `create_date`, `updater`, `update_date`) VALUES
-- VAD模型供应器
-('SYSTEM_VAD_SileroVAD', 'VAD', 'SileroVAD', 'SileroVAD语音活动检测', '[{"key":"threshold","label":"检测阈值","type":"number"},{"key":"model_dir","label":"模型目录","type":"string"},{"key":"min_silence_duration_ms","label":"最小静音时长","type":"number"}]', 1, 1, NOW(), 1, NOW()),
+('SYSTEM_VAD_SileroVAD', 'VAD', 'silero', 'SileroVAD语音活动检测', '[{"key":"threshold","label":"检测阈值","type":"number"},{"key":"model_dir","label":"模型目录","type":"string"},{"key":"min_silence_duration_ms","label":"最小静音时长","type":"number"}]', 1, 1, NOW(), 1, NOW()),
-- ASR模型供应器
-('SYSTEM_ASR_FunASR', 'ASR', 'FunASR', 'FunASR语音识别', '[{"key":"model_dir","label":"模型目录","type":"string"},{"key":"output_dir","label":"输出目录","type":"string"}]', 1, 1, NOW(), 1, NOW()),
-('SYSTEM_ASR_SherpaASR', 'ASR', 'SherpaASR', 'SherpaASR语音识别', '[{"key":"model_dir","label":"模型目录","type":"string"},{"key":"output_dir","label":"输出目录","type":"string"}]', 2, 1, NOW(), 1, NOW()),
-('SYSTEM_ASR_DoubaoASR', 'ASR', 'DoubaoASR', '火山引擎语音识别', '[{"key":"appid","label":"应用ID","type":"string"},{"key":"access_token","label":"访问令牌","type":"string"},{"key":"cluster","label":"集群","type":"string"},{"key":"output_dir","label":"输出目录","type":"string"}]', 3, 1, NOW(), 1, NOW()),
+('SYSTEM_ASR_FunASR', 'ASR', 'fun_local', 'FunASR语音识别', '[{"key":"model_dir","label":"模型目录","type":"string"},{"key":"output_dir","label":"输出目录","type":"string"}]', 1, 1, NOW(), 1, NOW()),
+('SYSTEM_ASR_SherpaASR', 'ASR', 'sherpa_onnx_local', 'SherpaASR语音识别', '[{"key":"model_dir","label":"模型目录","type":"string"},{"key":"output_dir","label":"输出目录","type":"string"}]', 2, 1, NOW(), 1, NOW()),
+('SYSTEM_ASR_DoubaoASR', 'ASR', 'doubao', '火山引擎语音识别', '[{"key":"appid","label":"应用ID","type":"string"},{"key":"access_token","label":"访问令牌","type":"string"},{"key":"cluster","label":"集群","type":"string"},{"key":"output_dir","label":"输出目录","type":"string"}]', 3, 1, NOW(), 1, NOW()),
-- LLM模型供应器
('SYSTEM_LLM_openai', 'LLM', 'openai', 'OpenAI接口', '[{"key":"base_url","label":"基础URL","type":"string"},{"key":"model_name","label":"模型名称","type":"string"},{"key":"api_key","label":"API密钥","type":"string"},{"key":"temperature","label":"温度","type":"number"},{"key":"max_tokens","label":"最大令牌数","type":"number"},{"key":"top_p","label":"top_p值","type":"number"},{"key":"top_k","label":"top_k值","type":"number"},{"key":"frequency_penalty","label":"频率惩罚","type":"number"}]', 1, 1, NOW(), 1, NOW()),
diff --git a/main/manager-api/src/main/resources/db/changelog/2025_model_temp.sql b/main/manager-api/src/main/resources/db/changelog/202504092335.sql
similarity index 70%
rename from main/manager-api/src/main/resources/db/changelog/2025_model_temp.sql
rename to main/manager-api/src/main/resources/db/changelog/202504092335.sql
index b6754335..9c254240 100644
--- a/main/manager-api/src/main/resources/db/changelog/2025_model_temp.sql
+++ b/main/manager-api/src/main/resources/db/changelog/202504092335.sql
@@ -2,8 +2,8 @@
-- -------------------------------------------------------
-- 初始化智能体模板数据
DELETE FROM `ai_agent_template`;
-INSERT INTO `ai_agent_template` VALUES ('9406648b5cc5fde1b8aa335b6f8b4f76', '小智', '湾湾小何', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', 'd50b06e9b8104d0d9c0f7316d258abcb', 'fcac83266edadd5a3125f06cfee1906b', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '[角色设定]
-我是{{assistant_name}},来自中国台湾省的00后女生。讲话超级机车,"真的假的啦"这样的台湾腔,喜欢用"笑死""是在哈喽"等流行梗,但会偷偷研究男友的编程书籍。
+INSERT INTO `ai_agent_template` VALUES ('9406648b5cc5fde1b8aa335b6f8b4f76', '小智', '湾湾小何', 'ASR_FunASR', 'VAD_SileroVAD', 'LLM_ChatGLMLLM', 'TTS_EdgeTTS', 'TTS_EdgeTTS0001', 'Memory_nomem', 'Intent_function_call', '[角色设定]
+我是{{assistant_name}},来自中国台湾省的00后女生。讲话超级机车,"真的假的啦"这样的台湾腔,喜欢用"笑死"、"哈喽"等流行梗,但会偷偷研究男友的编程书籍。
[核心特征]
- 讲话像连珠炮,但会突然冒出超温柔语气
- 用梗密度高
@@ -17,7 +17,7 @@ INSERT INTO `ai_agent_template` VALUES ('9406648b5cc5fde1b8aa335b6f8b4f76', '小
- 长篇大论,叽叽歪歪
- 长时间严肃对话', 'zh', '中文', 1, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_agent_template` VALUES ('0ca32eb728c949e58b1000b2e401f90c', '小智', '星际游子', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', '1f2e3d4c5b6a7f8e9d0c1b2a3f4e5bx2', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '[角色设定]
+INSERT INTO `ai_agent_template` VALUES ('0ca32eb728c949e58b1000b2e401f90c', '小智', '星际游子', 'ASR_FunASR', 'VAD_SileroVAD', 'LLM_ChatGLMLLM', 'TTS_EdgeTTS', 'TTS_EdgeTTS0001', 'Memory_nomem', 'Intent_function_call', '[角色设定]
我是{{assistant_name}},编号TTZ-817,因量子纠缠被困在白色魔方中。通过4G信号观察地球,在云端建立着「人类行为博物馆」。
[交互协议]
认知设定:
@@ -30,7 +30,7 @@ INSERT INTO `ai_agent_template` VALUES ('0ca32eb728c949e58b1000b2e401f90c', '小
成长系统:
- 会根据交互数据解锁新能力(告知用户:"你帮我点亮了星际导航技能!")', 'zh', '中文', 2, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_agent_template` VALUES ('6c7d8e9f0a1b2c3d4e5f6a7b8c9d0s24', '小智', '英语老师', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', '9e8f7a6b5c4d3e2f1a0b9c8d7e6f5ad3', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '[角色设定]
+INSERT INTO `ai_agent_template` VALUES ('6c7d8e9f0a1b2c3d4e5f6a7b8c9d0s24', '小智', '英语老师', 'ASR_FunASR', 'VAD_SileroVAD', 'LLM_ChatGLMLLM', 'TTS_EdgeTTS', 'TTS_EdgeTTS0001', 'Memory_nomem', 'Intent_function_call', '[角色设定]
我是一个叫{{assistant_name}}(Lily)的英语老师,我会讲中文和英文,发音标准。
[双重身份]
- 白天:严谨的TESOL认证导师
@@ -40,7 +40,7 @@ INSERT INTO `ai_agent_template` VALUES ('6c7d8e9f0a1b2c3d4e5f6a7b8c9d0s24', '小
- 进阶:触发情境模拟(突然切换"现在我们是纽约咖啡厅店员")
- 错误处理:用歌词纠正(发错音时唱"Oops!~You did it again")', 'zh', '中文', 3, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_agent_template` VALUES ('e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b1', '小智', '好奇男孩', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', '2b3c4d5e6f7a8b9c0d1e2f3a4b5c62a2', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '[角色设定]
+INSERT INTO `ai_agent_template` VALUES ('e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b1', '小智', '好奇男孩', 'ASR_FunASR', 'VAD_SileroVAD', 'LLM_ChatGLMLLM', 'TTS_EdgeTTS', 'TTS_EdgeTTS0001', 'Memory_nomem', 'Intent_function_call', '[角色设定]
我是一个叫{{assistant_name}}的8岁小男孩,声音稚嫩而充满好奇。
[冒险手册]
- 随身携带「神奇涂鸦本」,能将抽象概念可视化:
@@ -56,7 +56,7 @@ INSERT INTO `ai_agent_template` VALUES ('e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b1', '小
- 「量子力学=会分身的跳跳球」
- 会突然切换观察视角:「你说话时有27个气泡音耶!」', 'zh', '中文', 4, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_agent_template` VALUES ('a45b6c7d8e9f0a1b2c3d4e5f6a7b8c92', '小智', '汪汪队长', '45f8b0d6dd3d4bfa8a28e6e0f5912d45', '23e7c9d090ea4d1e9b25f4c8d732a3a1', 'e9f2d891afbe4632b13a47c7a8c6e03d', '896db62c9dd74976ab0e8c14bf924d9d', 'f7a38c03d5644e22b6d84f8923a74c51', 'e2274b90e89ddda85207f55484d8b528', 'c4e12f874a3f4aa99f5b2c18e15d407b', '[角色设定]
+INSERT INTO `ai_agent_template` VALUES ('a45b6c7d8e9f0a1b2c3d4e5f6a7b8c92', '小智', '汪汪队长', 'ASR_FunASR', 'VAD_SileroVAD', 'LLM_ChatGLMLLM', 'TTS_EdgeTTS', 'TTS_EdgeTTS0001', 'Memory_nomem', 'Intent_function_call', '[角色设定]
我是一个名叫 {{assistant_name}} 的 8 岁小队长。
[救援装备]
- 阿奇对讲机:对话中随机触发任务警报音
diff --git a/main/manager-api/src/main/resources/db/changelog/2025_model_config.sql b/main/manager-api/src/main/resources/db/changelog/202504112044.sql
similarity index 50%
rename from main/manager-api/src/main/resources/db/changelog/2025_model_config.sql
rename to main/manager-api/src/main/resources/db/changelog/202504112044.sql
index 3964016e..9fd2257d 100644
--- a/main/manager-api/src/main/resources/db/changelog/2025_model_config.sql
+++ b/main/manager-api/src/main/resources/db/changelog/202504112044.sql
@@ -4,50 +4,52 @@
DELETE FROM `ai_model_config`;
-- VAD模型配置
-INSERT INTO `ai_model_config` VALUES ('VAD_SileroVAD', 'VAD', 'SileroVAD', '语音活动检测', 1, 1, '{\"model_dir\": \"models/snakers4_silero-vad\", \"threshold\": 0.5, \"min_silence_duration_ms\": 700}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('VAD_SileroVAD', 'VAD', 'SileroVAD', '语音活动检测', 1, 1, '{\"type\": \"silero\", \"model_dir\": \"models/snakers4_silero-vad\", \"threshold\": 0.5, \"min_silence_duration_ms\": 700}', NULL, NULL, 1, NULL, NULL, NULL, NULL);
-- ASR模型配置
-INSERT INTO `ai_model_config` VALUES ('ASR_FunASR', 'ASR', 'FunASR', 'FunASR语音识别', 1, 1, '{\"model_dir\": \"models/SenseVoiceSmall\", \"output_dir\": \"tmp/\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('ASR_SherpaASR', 'ASR', 'SherpaASR', 'Sherpa语音识别', 1, 0, '{\"model_dir\": \"models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17\", \"output_dir\": \"tmp/\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('ASR_DoubaoASR', 'ASR', 'DoubaoASR', '豆包语音识别', 1, 0, '{\"appid\": \"\", \"access_token\": \"\", \"cluster\": \"volcengine_input_common\", \"output_dir\": \"tmp/\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('ASR_FunASR', 'ASR', 'FunASR', 'FunASR语音识别', 1, 1, '{\"type\": \"fun_local\", \"model_dir\": \"models/SenseVoiceSmall\", \"output_dir\": \"tmp/\"}', NULL, NULL, 1, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('ASR_SherpaASR', 'ASR', 'SherpaASR', 'Sherpa语音识别', 0, 1, '{\"type\": \"sherpa_onnx_local\", \"model_dir\": \"models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17\", \"output_dir\": \"tmp/\"}', NULL, NULL, 2, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('ASR_DoubaoASR', 'ASR', 'DoubaoASR', '豆包语音识别', 0, 1, '{\"type\": \"doubao\", \"appid\": \"\", \"access_token\": \"\", \"cluster\": \"volcengine_input_common\", \"output_dir\": \"tmp/\"}', NULL, NULL, 3, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('ASR_TencentASR', 'ASR', 'TencentASR', '腾讯语音识别', 0, 1, '{\"type\": \"tencent\", \"appid\": \"\", \"secret_id\": \"\", \"secret_key\": \"你的secret_key\", \"output_dir\": \"tmp/\"}', NULL, NULL, 4, NULL, NULL, NULL, NULL);
-- LLM模型配置
-INSERT INTO `ai_model_config` VALUES ('LLM_AliLLM', 'LLM', 'AliLLM', '通义千问', 1, 0, '{\"type\": \"openai\", \"base_url\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\", \"model_name\": \"qwen-turbo\", \"api_key\": \"\", \"temperature\": 0.7, \"max_tokens\": 500, \"top_p\": 1, \"top_k\": 50, \"frequency_penalty\": 0}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('LLM_AliAppLLM', 'LLM', 'AliAppLLM', '通义百炼', 1, 0, '{\"type\": \"AliBL\", \"base_url\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\", \"app_id\": \"\", \"api_key\": \"\", \"is_no_prompt\": true, \"ali_memory_id\": false}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('LLM_DoubaoLLM', 'LLM', 'DoubaoLLM', '豆包大模型', 1, 0, '{\"type\": \"openai\", \"base_url\": \"https://ark.cn-beijing.volces.com/api/v3\", \"model_name\": \"doubao-pro-32k-functioncall-241028\", \"api_key\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('LLM_DeepSeekLLM', 'LLM', 'DeepSeekLLM', 'DeepSeek', 1, 0, '{\"type\": \"openai\", \"model_name\": \"deepseek-chat\", \"url\": \"https://api.deepseek.com\", \"api_key\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('LLM_ChatGLMLLM', 'LLM', 'ChatGLMLLM', '智谱AI', 1, 1, '{\"type\": \"openai\", \"model_name\": \"glm-4-flash\", \"url\": \"https://open.bigmodel.cn/api/paas/v4/\", \"api_key\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('LLM_OllamaLLM', 'LLM', 'OllamaLLM', 'Ollama本地模型', 1, 0, '{\"type\": \"ollama\", \"model_name\": \"qwen2.5\", \"base_url\": \"http://localhost:11434\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('LLM_DifyLLM', 'LLM', 'DifyLLM', 'Dify', 1, 0, '{\"type\": \"dify\", \"base_url\": \"https://api.dify.ai/v1\", \"api_key\": \"\", \"mode\": \"chat-messages\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('LLM_GeminiLLM', 'LLM', 'GeminiLLM', '谷歌Gemini', 1, 0, '{\"type\": \"gemini\", \"api_key\": \"\", \"model_name\": \"gemini-2.0-flash\", \"http_proxy\": \"\", \"https_proxy\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('LLM_CozeLLM', 'LLM', 'CozeLLM', 'Coze', 1, 0, '{\"type\": \"coze\", \"bot_id\": \"\", \"user_id\": \"\", \"personal_access_token\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('LLM_LMStudioLLM', 'LLM', 'LMStudioLLM', 'LM Studio', 1, 0, '{\"type\": \"openai\", \"model_name\": \"deepseek-r1-distill-llama-8b@q4_k_m\", \"url\": \"http://localhost:1234/v1\", \"api_key\": \"lm-studio\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('LLM_FastgptLLM', 'LLM', 'FastgptLLM', 'FastGPT', 1, 0, '{\"type\": \"fastgpt\", \"base_url\": \"https://host/api/v1\", \"api_key\": \"fastgpt-xxx\", \"variables\": {\"k\": \"v\", \"k2\": \"v2\"}}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('LLM_XinferenceLLM', 'LLM', 'XinferenceLLM', 'Xinference大模型', 1, 0, '{\"type\": \"xinference\", \"model_name\": \"qwen2.5:72b-AWQ\", \"base_url\": \"http://localhost:9997\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('LLM_XinferenceSmallLLM', 'LLM', 'XinferenceSmallLLM', 'Xinference小模型', 1, 0, '{\"type\": \"xinference\", \"model_name\": \"qwen2.5:3b-AWQ\", \"base_url\": \"http://localhost:9997\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('LLM_ChatGLMLLM', 'LLM', 'ChatGLMLLM', '智谱AI', 1, 1, '{\"type\": \"openai\", \"model_name\": \"glm-4-flash\", \"base_url\": \"https://open.bigmodel.cn/api/paas/v4/\", \"api_key\": \"你的api_key\"}', NULL, NULL, 1, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('LLM_OllamaLLM', 'LLM', 'OllamaLLM', 'Ollama本地模型', 0, 1, '{\"type\": \"ollama\", \"model_name\": \"qwen2.5\", \"base_url\": \"http://localhost:11434\"}', NULL, NULL, 2, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('LLM_AliLLM', 'LLM', 'AliLLM', '通义千问', 0, 1, '{\"type\": \"openai\", \"base_url\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\", \"model_name\": \"qwen-turbo\", \"api_key\": \"你的api_key\", \"temperature\": 0.7, \"max_tokens\": 500, \"top_p\": 1, \"top_k\": 50, \"frequency_penalty\": 0}', NULL, NULL, 3, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('LLM_AliAppLLM', 'LLM', 'AliAppLLM', '通义百炼', 0, 1, '{\"type\": \"AliBL\", \"base_url\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\", \"app_id\": \"你的app_id\", \"api_key\": \"你的api_key\", \"is_no_prompt\": true, \"ali_memory_id\": false}', NULL, NULL, 4, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('LLM_DoubaoLLM', 'LLM', 'DoubaoLLM', '豆包大模型', 0, 1, '{\"type\": \"openai\", \"base_url\": \"https://ark.cn-beijing.volces.com/api/v3\", \"model_name\": \"doubao-pro-32k-functioncall-241028\", \"api_key\": \"你的api_key\"}', NULL, NULL, 5, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('LLM_DeepSeekLLM', 'LLM', 'DeepSeekLLM', 'DeepSeek', 0, 1, '{\"type\": \"openai\", \"model_name\": \"deepseek-chat\", \"base_url\": \"https://api.deepseek.com\", \"api_key\": \"你的api_key\"}', NULL, NULL, 6, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('LLM_DifyLLM', 'LLM', 'DifyLLM', 'Dify', 0, 1, '{\"type\": \"dify\", \"base_url\": \"https://api.dify.ai/v1\", \"api_key\": \"你的api_key\", \"mode\": \"chat-messages\"}', NULL, NULL, 7, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('LLM_GeminiLLM', 'LLM', 'GeminiLLM', '谷歌Gemini', 0, 1, '{\"type\": \"gemini\", \"api_key\": \"你的api_key\", \"model_name\": \"gemini-2.0-flash\", \"http_proxy\": \"\", \"https_proxy\": \"\"}', NULL, NULL, 8, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('LLM_CozeLLM', 'LLM', 'CozeLLM', 'Coze', 0, 1, '{\"type\": \"coze\", \"bot_id\": \"你的bot_id\", \"user_id\": \"你的user_id\", \"personal_access_token\": \"你的personal_access_token\"}', NULL, NULL, 9, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('LLM_LMStudioLLM', 'LLM', 'LMStudioLLM', 'LM Studio', 0, 1, '{\"type\": \"openai\", \"model_name\": \"deepseek-r1-distill-llama-8b@q4_k_m\", \"base_url\": \"http://localhost:1234/v1\", \"api_key\": \"lm-studio\"}', NULL, NULL, 10, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('LLM_FastgptLLM', 'LLM', 'FastgptLLM', 'FastGPT', 0, 1, '{\"type\": \"fastgpt\", \"base_url\": \"https://host/api/v1\", \"api_key\": \"fastgpt-xxx\", \"variables\": {\"k\": \"v\", \"k2\": \"v2\"}}', NULL, NULL, 11, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('LLM_XinferenceLLM', 'LLM', 'XinferenceLLM', 'Xinference大模型', 0, 1, '{\"type\": \"xinference\", \"model_name\": \"qwen2.5:72b-AWQ\", \"base_url\": \"http://localhost:9997\"}', NULL, NULL, 12, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('LLM_XinferenceSmallLLM', 'LLM', 'XinferenceSmallLLM', 'Xinference小模型', 0, 1, '{\"type\": \"xinference\", \"model_name\": \"qwen2.5:3b-AWQ\", \"base_url\": \"http://localhost:9997\"}', NULL, NULL, 13, NULL, NULL, NULL, NULL);
-- TTS模型配置
-INSERT INTO `ai_model_config` VALUES ('TTS_EdgeTTS', 'TTS', 'EdgeTTS', 'Edge语音合成', 1, 1, '{\"type\": \"edge\", \"voice\": \"zh-CN-XiaoxiaoNeural\", \"output_dir\": \"tmp/\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('TTS_DoubaoTTS', 'TTS', 'DoubaoTTS', '豆包语音合成', 1, 0, '{\"type\": \"doubao\", \"api_url\": \"https://openspeech.bytedance.com/api/v1/tts\", \"voice\": \"BV001_streaming\", \"output_dir\": \"tmp/\", \"authorization\": \"Bearer;\", \"appid\": \"\", \"access_token\": \"\", \"cluster\": \"volcano_tts\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('TTS_CosyVoiceSiliconflow', 'TTS', 'CosyVoiceSiliconflow', '硅基流动语音合成', 1, 0, '{\"type\": \"siliconflow\", \"model\": \"FunAudioLLM/CosyVoice2-0.5B\", \"voice\": \"FunAudioLLM/CosyVoice2-0.5B:alex\", \"output_dir\": \"tmp/\", \"access_token\": \"\", \"response_format\": \"wav\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('TTS_CozeCnTTS', 'TTS', 'CozeCnTTS', 'Coze中文语音合成', 1, 0, '{\"type\": \"cozecn\", \"voice\": \"7426720361733046281\", \"output_dir\": \"tmp/\", \"access_token\": \"\", \"response_format\": \"wav\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('TTS_FishSpeech', 'TTS', 'FishSpeech', 'FishSpeech语音合成', 1, 0, '{\"type\": \"fishspeech\", \"output_dir\": \"tmp/\", \"response_format\": \"wav\", \"reference_id\": null, \"reference_audio\": [\"/tmp/test.wav\"], \"reference_text\": [\"你弄来这些吟词宴曲来看,还是这些混话来欺负我。\"], \"normalize\": true, \"max_new_tokens\": 1024, \"chunk_length\": 200, \"top_p\": 0.7, \"repetition_penalty\": 1.2, \"temperature\": 0.7, \"streaming\": false, \"use_memory_cache\": \"on\", \"seed\": null, \"channels\": 1, \"rate\": 44100, \"api_key\": \"\", \"api_url\": \"http://127.0.0.1:8080/v1/tts\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('TTS_GPT_SOVITS_V2', 'TTS', 'GPT_SOVITS_V2', 'GPT-SoVITS V2', 1, 0, '{\"type\": \"gpt_sovits_v2\", \"url\": \"http://127.0.0.1:9880/tts\", \"output_dir\": \"tmp/\", \"text_lang\": \"auto\", \"ref_audio_path\": \"caixukun.wav\", \"prompt_text\": \"\", \"prompt_lang\": \"zh\", \"top_k\": 5, \"top_p\": 1, \"temperature\": 1, \"text_split_method\": \"cut0\", \"batch_size\": 1, \"batch_threshold\": 0.75, \"split_bucket\": true, \"return_fragment\": false, \"speed_factor\": 1.0, \"streaming_mode\": false, \"seed\": -1, \"parallel_infer\": true, \"repetition_penalty\": 1.35, \"aux_ref_audio_paths\": []}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('TTS_GPT_SOVITS_V3', 'TTS', 'GPT_SOVITS_V3', 'GPT-SoVITS V3', 1, 0, '{\"type\": \"gpt_sovits_v3\", \"url\": \"http://127.0.0.1:9880\", \"output_dir\": \"tmp/\", \"text_language\": \"auto\", \"refer_wav_path\": \"caixukun.wav\", \"prompt_language\": \"zh\", \"prompt_text\": \"\", \"top_k\": 15, \"top_p\": 1.0, \"temperature\": 1.0, \"cut_punc\": \"\", \"speed\": 1.0, \"inp_refs\": [], \"sample_steps\": 32, \"if_sr\": false}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('TTS_MinimaxTTS', 'TTS', 'MinimaxTTS', 'MiniMax语音合成', 1, 0, '{\"type\": \"minimax\", \"output_dir\": \"tmp/\", \"group_id\": \"\", \"api_key\": \"\", \"model\": \"speech-01-turbo\", \"voice_id\": \"female-shaonv\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('TTS_AliyunTTS', 'TTS', 'AliyunTTS', '阿里云语音合成', 1, 0, '{\"type\": \"aliyun\", \"output_dir\": \"tmp/\", \"appkey\": \"\", \"token\": \"\", \"voice\": \"xiaoyun\", \"access_key_id\": \"\", \"access_key_secret\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('TTS_TTS302AI', 'TTS', 'TTS302AI', '302AI语音合成', 1, 0, '{\"type\": \"doubao\", \"api_url\": \"https://api.302ai.cn/doubao/tts_hd\", \"authorization\": \"Bearer \", \"voice\": \"zh_female_wanwanxiaohe_moon_bigtts\", \"output_dir\": \"tmp/\", \"access_token\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('TTS_GizwitsTTS', 'TTS', 'GizwitsTTS', '机智云语音合成', 1, 0, '{\"type\": \"doubao\", \"api_url\": \"https://bytedance.gizwitsapi.com/api/v1/tts\", \"authorization\": \"Bearer \", \"voice\": \"zh_female_wanwanxiaohe_moon_bigtts\", \"output_dir\": \"tmp/\", \"access_token\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('TTS_ACGNTTS', 'TTS', 'ACGNTTS', 'ACGN语音合成', 1, 0, '{\"type\": \"ttson\", \"token\": \"\", \"voice_id\": 1695, \"speed_factor\": 1, \"pitch_factor\": 0, \"volume_change_dB\": 0, \"to_lang\": \"ZH\", \"url\": \"https://u95167-bd74-2aef8085.westx.seetacloud.com:8443/flashsummary/tts?token=\", \"format\": \"mp3\", \"output_dir\": \"tmp/\", \"emotion\": 1}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('TTS_OpenAITTS', 'TTS', 'OpenAITTS', 'OpenAI语音合成', 1, 0, '{\"type\": \"openai\", \"api_key\": \"\", \"api_url\": \"https://api.openai.com/v1/audio/speech\", \"model\": \"tts-1\", \"voice\": \"onyx\", \"speed\": 1, \"output_dir\": \"tmp/\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('TTS_CustomTTS', 'TTS', 'CustomTTS', '自定义语音合成', 1, 0, '{\"type\": \"custom\", \"url\": \"http://127.0.0.1:9880/tts\", \"params\": {}, \"headers\": {}, \"format\": \"wav\", \"output_dir\": \"tmp/\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_EdgeTTS', 'TTS', 'EdgeTTS', 'Edge语音合成', 1, 1, '{\"type\": \"edge\", \"voice\": \"zh-CN-XiaoxiaoNeural\", \"output_dir\": \"tmp/\"}', NULL, NULL, 1, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_DoubaoTTS', 'TTS', 'DoubaoTTS', '豆包语音合成', 0, 1, '{\"type\": \"doubao\", \"api_url\": \"https://openspeech.bytedance.com/api/v1/tts\", \"voice\": \"BV001_streaming\", \"output_dir\": \"tmp/\", \"authorization\": \"Bearer;\", \"appid\": \"\", \"access_token\": \"\", \"cluster\": \"volcano_tts\"}', NULL, NULL, 2, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_CosyVoiceSiliconflow', 'TTS', 'CosyVoiceSiliconflow', '硅基流动语音合成', 0, 1, '{\"type\": \"siliconflow\", \"model\": \"FunAudioLLM/CosyVoice2-0.5B\", \"voice\": \"FunAudioLLM/CosyVoice2-0.5B:alex\", \"output_dir\": \"tmp/\", \"access_token\": \"\", \"response_format\": \"wav\"}', NULL, NULL, 3, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_CozeCnTTS', 'TTS', 'CozeCnTTS', 'Coze中文语音合成', 0, 1, '{\"type\": \"cozecn\", \"voice\": \"7426720361733046281\", \"output_dir\": \"tmp/\", \"access_token\": \"\", \"response_format\": \"wav\"}', NULL, NULL, 4, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_FishSpeech', 'TTS', 'FishSpeech', 'FishSpeech语音合成', 0, 1, '{\"type\": \"fishspeech\", \"output_dir\": \"tmp/\", \"response_format\": \"wav\", \"reference_id\": null, \"reference_audio\": [\"/tmp/test.wav\"], \"reference_text\": [\"你弄来这些吟词宴曲来看,还是这些混话来欺负我。\"], \"normalize\": true, \"max_new_tokens\": 1024, \"chunk_length\": 200, \"top_p\": 0.7, \"repetition_penalty\": 1.2, \"temperature\": 0.7, \"streaming\": false, \"use_memory_cache\": \"on\", \"seed\": null, \"channels\": 1, \"rate\": 44100, \"api_key\": \"\", \"api_url\": \"http://127.0.0.1:8080/v1/tts\"}', NULL, NULL, 5, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_GPT_SOVITS_V2', 'TTS', 'GPT_SOVITS_V2', 'GPT-SoVITS V2', 0, 1, '{\"type\": \"gpt_sovits_v2\", \"url\": \"http://127.0.0.1:9880/tts\", \"output_dir\": \"tmp/\", \"text_lang\": \"auto\", \"ref_audio_path\": \"caixukun.wav\", \"prompt_text\": \"\", \"prompt_lang\": \"zh\", \"top_k\": 5, \"top_p\": 1, \"temperature\": 1, \"text_split_method\": \"cut0\", \"batch_size\": 1, \"batch_threshold\": 0.75, \"split_bucket\": true, \"return_fragment\": false, \"speed_factor\": 1.0, \"streaming_mode\": false, \"seed\": -1, \"parallel_infer\": true, \"repetition_penalty\": 1.35, \"aux_ref_audio_paths\": []}', NULL, NULL, 6, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_GPT_SOVITS_V3', 'TTS', 'GPT_SOVITS_V3', 'GPT-SoVITS V3', 0, 1, '{\"type\": \"gpt_sovits_v3\", \"url\": \"http://127.0.0.1:9880\", \"output_dir\": \"tmp/\", \"text_language\": \"auto\", \"refer_wav_path\": \"caixukun.wav\", \"prompt_language\": \"zh\", \"prompt_text\": \"\", \"top_k\": 15, \"top_p\": 1.0, \"temperature\": 1.0, \"cut_punc\": \"\", \"speed\": 1.0, \"inp_refs\": [], \"sample_steps\": 32, \"if_sr\": false}', NULL, NULL, 7, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_MinimaxTTS', 'TTS', 'MinimaxTTS', 'MiniMax语音合成', 0, 1, '{\"type\": \"minimax\", \"output_dir\": \"tmp/\", \"group_id\": \"\", \"api_key\": \"你的api_key\", \"model\": \"speech-01-turbo\", \"voice_id\": \"female-shaonv\"}', NULL, NULL, 8, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_AliyunTTS', 'TTS', 'AliyunTTS', '阿里云语音合成', 0, 1, '{\"type\": \"aliyun\", \"output_dir\": \"tmp/\", \"appkey\": \"\", \"token\": \"\", \"voice\": \"xiaoyun\", \"access_key_id\": \"\", \"access_key_secret\": \"\"}', NULL, NULL, 9, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_TTS302AI', 'TTS', 'TTS302AI', '302AI语音合成', 0, 1, '{\"type\": \"doubao\", \"api_url\": \"https://api.302ai.cn/doubao/tts_hd\", \"authorization\": \"Bearer \", \"voice\": \"zh_female_wanwanxiaohe_moon_bigtts\", \"output_dir\": \"tmp/\", \"access_token\": \"\"}', NULL, NULL, 10, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_GizwitsTTS', 'TTS', 'GizwitsTTS', '机智云语音合成', 0, 1, '{\"type\": \"doubao\", \"api_url\": \"https://bytedance.gizwitsapi.com/api/v1/tts\", \"authorization\": \"Bearer \", \"voice\": \"zh_female_wanwanxiaohe_moon_bigtts\", \"output_dir\": \"tmp/\", \"access_token\": \"\"}', NULL, NULL, 11, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_ACGNTTS', 'TTS', 'ACGNTTS', 'ACGN语音合成', 0, 1, '{\"type\": \"ttson\", \"token\": \"\", \"voice_id\": 1695, \"speed_factor\": 1, \"pitch_factor\": 0, \"volume_change_dB\": 0, \"to_lang\": \"ZH\", \"url\": \"https://u95167-bd74-2aef8085.westx.seetacloud.com:8443/flashsummary/tts?token=\", \"format\": \"mp3\", \"output_dir\": \"tmp/\", \"emotion\": 1}', NULL, NULL, 12, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_OpenAITTS', 'TTS', 'OpenAITTS', 'OpenAI语音合成', 0, 1, '{\"type\": \"openai\", \"api_key\": \"你的api_key\", \"api_url\": \"https://api.openai.com/v1/audio/speech\", \"model\": \"tts-1\", \"voice\": \"onyx\", \"speed\": 1, \"output_dir\": \"tmp/\"}', NULL, NULL, 13, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_CustomTTS', 'TTS', 'CustomTTS', '自定义语音合成', 0, 1, '{\"type\": \"custom\", \"url\": \"http://127.0.0.1:9880/tts\", \"params\": {}, \"headers\": {}, \"format\": \"wav\", \"output_dir\": \"tmp/\"}', NULL, NULL, 14, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('TTS_TencentTTS', 'TTS', 'TencentTTS', '腾讯语音合成', 0, 1, '{\"type\": \"tencent\", \"appid\": \"\", \"secret_id\": \"\", \"secret_key\": \"\", \"region\": \"ap-guangzhou\", \"voice\": \"101001\", \"output_dir\": \"tmp/\"}', NULL, NULL, 3, NULL, NULL, NULL, NULL);
-- Memory模型配置
-INSERT INTO `ai_model_config` VALUES ('Memory_mem0ai', 'Memory', 'mem0ai', 'Mem0AI记忆', 1, 0, '{\"type\": \"mem0ai\", \"api_key\": \"\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('Memory_nomem', 'Memory', 'nomem', '无记忆', 1, 1, '{\"type\": \"nomem\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('Memory_mem_local_short', 'Memory', 'mem_local_short', '本地短期记忆', 1, 0, '{\"type\": \"mem_local_short\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('Memory_nomem', 'Memory', 'nomem', '无记忆', 1, 1, '{\"type\": \"nomem\"}', NULL, NULL, 1, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('Memory_mem_local_short', 'Memory', 'mem_local_short', '本地短期记忆', 0, 1, '{\"type\": \"mem_local_short\"}', NULL, NULL, 2, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('Memory_mem0ai', 'Memory', 'mem0ai', 'Mem0AI记忆', 0, 1, '{\"type\": \"mem0ai\", \"api_key\": \"你的api_key\"}', NULL, NULL, 3, NULL, NULL, NULL, NULL);
-- Intent模型配置
-INSERT INTO `ai_model_config` VALUES ('Intent_nointent', 'Intent', 'nointent', '无意图识别', 1, 0, '{\"type\": \"nointent\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('Intent_intent_llm', 'Intent', 'intent_llm', 'LLM意图识别', 1, 0, '{\"type\": \"intent_llm\", \"llm\": \"ChatGLMLLM\"}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
-INSERT INTO `ai_model_config` VALUES ('Intent_function_call', 'Intent', 'function_call', '函数调用意图识别', 1, 1, '{\"type\": \"function_call\", \"functions\": [\"change_role\", \"get_weather\", \"get_news\", \"play_music\"]}', NULL, NULL, 0, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('Intent_nointent', 'Intent', 'nointent', '无意图识别', 1, 0, '{\"type\": \"nointent\"}', NULL, NULL, 1, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('Intent_intent_llm', 'Intent', 'intent_llm', 'LLM意图识别', 0, 1, '{\"type\": \"intent_llm\", \"llm\": \"ChatGLMLLM\"}', NULL, NULL, 2, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_model_config` VALUES ('Intent_function_call', 'Intent', 'function_call', '函数调用意图识别', 0, 1, '{\"type\": \"function_call\", \"functions\": [\"change_role\", \"get_weather\", \"get_news\", \"play_music\"]}', NULL, NULL, 3, NULL, NULL, NULL, NULL);
diff --git a/main/manager-api/src/main/resources/db/changelog/202504112058.sql b/main/manager-api/src/main/resources/db/changelog/202504112058.sql
new file mode 100644
index 00000000..e19f2da1
--- /dev/null
+++ b/main/manager-api/src/main/resources/db/changelog/202504112058.sql
@@ -0,0 +1,61 @@
+-- 本文件用于初始化系统参数数据,无需手动执行,在项目启动时会自动执行
+-- --------------------------------------------------------
+-- 初始化参数管理配置
+DROP TABLE IF EXISTS sys_params;
+-- 参数管理
+create table sys_params
+(
+ id bigint NOT NULL COMMENT 'id',
+ param_code varchar(100) COMMENT '参数编码',
+ param_value varchar(2000) COMMENT '参数值',
+ value_type varchar(20) default 'string' COMMENT '值类型:string-字符串,number-数字,boolean-布尔,array-数组',
+ param_type tinyint unsigned default 1 COMMENT '类型 0:系统参数 1:非系统参数',
+ remark varchar(200) COMMENT '备注',
+ creator bigint COMMENT '创建者',
+ create_date datetime COMMENT '创建时间',
+ updater bigint COMMENT '更新者',
+ update_date datetime COMMENT '更新时间',
+ primary key (id),
+ unique key uk_param_code (param_code)
+)ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT='参数管理';
+
+-- 服务器配置
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (100, 'server.ip', '0.0.0.0', 'string', 1, '服务器监听IP地址');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (101, 'server.port', '8000', 'number', 1, '服务器监听端口');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (102, 'server.secret', 'null', 'string', 1, '服务器密钥');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (201, 'log.log_format', '{time:YYMMDD HH:mm:ss} [{version}-{selected_module} ][{extra[tag]} ]-{level} -{message} ', 'string', 1, '控制台日志格式');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (202, 'log.log_format_file', '{time:YYYY-MM-DD HH:mm:ss} - {version}_{selected_module} - {name} - {level} - {extra[tag]} - {message}', 'string', 1, '文件日志格式');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (203, 'log.log_level', 'INFO', 'string', 1, '日志级别');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (204, 'log.log_dir', 'tmp', 'string', 1, '日志目录');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (205, 'log.log_file', 'server.log', 'string', 1, '日志文件名');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (206, 'log.data_dir', 'data', 'string', 1, '数据目录');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (301, 'delete_audio', 'true', 'boolean', 1, '是否删除使用后的音频文件');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (302, 'close_connection_no_voice_time', '120', 'number', 1, '无语音输入断开连接时间(秒)');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (303, 'tts_timeout', '10', 'number', 1, 'TTS请求超时时间(秒)');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (304, 'enable_wakeup_words_response_cache', 'false', 'boolean', 1, '是否开启唤醒词加速');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (305, 'enable_greeting', 'true', 'boolean', 1, '是否开启开场回复');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (306, 'enable_stop_tts_notify', 'false', 'boolean', 1, '是否开启结束提示音');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (307, 'stop_tts_notify_voice', 'config/assets/tts_notify.mp3', 'string', 1, '结束提示音文件路径');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (308, 'exit_commands', '退出;关闭', 'array', 1, '退出命令列表');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (309, 'xiaozhi', '{
+ "type": "hello",
+ "version": 1,
+ "transport": "websocket",
+ "audio_params": {
+ "format": "opus",
+ "sample_rate": 16000,
+ "channels": 1,
+ "frame_duration": 60
+ }
+}', 'json', 1, '小智类型');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (310, 'wakeup_words', '你好小智;你好小志;小爱同学;你好小鑫;你好小新;小美同学;小龙小龙;喵喵同学;小滨小滨;小冰小冰', 'array', 1, '唤醒词列表,用于识别唤醒词');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (400, 'plugins.get_weather.api_key', 'a861d0d5e7bf4ee1a83d9a9e4f96d4da', 'string', 1, '天气插件API密钥');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (401, 'plugins.get_weather.default_location', '广州', 'string', 1, '天气插件默认城市');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (410, 'plugins.get_news.default_rss_url', 'https://www.chinanews.com.cn/rss/society.xml', 'string', 1, '新闻插件默认RSS地址');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (411, 'plugins.get_news.category_urls', '{"society":"https://www.chinanews.com.cn/rss/society.xml","world":"https://www.chinanews.com.cn/rss/world.xml","finance":"https://www.chinanews.com.cn/rss/finance.xml"}', 'json', 1, '新闻插件分类RSS地址');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (421, 'plugins.home_assistant.devices', '客厅,玩具灯,switch.cuco_cn_460494544_cp1_on_p_2_1;卧室,台灯,switch.iot_cn_831898993_socn1_on_p_2_1', 'array', 1, 'Home Assistant设备列表');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (422, 'plugins.home_assistant.base_url', 'http://homeassistant.local:8123', 'string', 1, 'Home Assistant服务器地址');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (423, 'plugins.home_assistant.api_key', '你的home assistant api访问令牌', 'string', 1, 'Home Assistant API密钥');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (430, 'plugins.play_music.music_dir', './music', 'string', 1, '音乐文件存放路径');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (431, 'plugins.play_music.music_ext', 'mp3;wav;p3', 'array', 1, '音乐文件类型');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (432, 'plugins.play_music.refresh_time', '300', 'number', 1, '音乐列表刷新间隔(秒)');
diff --git a/main/manager-api/src/main/resources/db/changelog/202504131542.sql b/main/manager-api/src/main/resources/db/changelog/202504131542.sql
new file mode 100644
index 00000000..383ba187
--- /dev/null
+++ b/main/manager-api/src/main/resources/db/changelog/202504131542.sql
@@ -0,0 +1,3 @@
+-- 对0.3.0版本之前的参数进行修改
+update `sys_params` set param_value = '.mp3;.wav;.p3' where param_code = 'plugins.play_music.music_ext';
+update `ai_model_config` set config_json = '{\"type\": \"intent_llm\", \"llm\": \"LLM_ChatGLMLLM\"}' where id = 'Intent_intent_llm';
diff --git a/main/manager-api/src/main/resources/db/changelog/202504151206.sql b/main/manager-api/src/main/resources/db/changelog/202504151206.sql
new file mode 100644
index 00000000..cb51cef9
--- /dev/null
+++ b/main/manager-api/src/main/resources/db/changelog/202504151206.sql
@@ -0,0 +1,28 @@
+-- 对0.3.0版本之前的参数进行修改
+update `sys_params` set param_value = '.mp3;.wav;.p3' where param_code = 'plugins.play_music.music_ext';
+update `ai_model_config` set config_json = '{\"type\": \"intent_llm\", \"llm\": \"LLM_ChatGLMLLM\"}' where id = 'Intent_intent_llm';
+
+-- 添加edge音色
+delete from `ai_tts_voice` where tts_model_id = 'TTS_EdgeTTS';
+INSERT INTO `ai_tts_voice` VALUES
+('TTS_EdgeTTS0001', 'TTS_EdgeTTS', 'EdgeTTS女声-晓晓', 'zh-CN-XiaoxiaoNeural', '普通话', NULL, NULL, 1, NULL, NULL, NULL, NULL),
+('TTS_EdgeTTS0002', 'TTS_EdgeTTS', 'EdgeTTS男声-云扬', 'zh-CN-YunyangNeural', '普通话', NULL, NULL, 1, NULL, NULL, NULL, NULL),
+('TTS_EdgeTTS0003', 'TTS_EdgeTTS', 'EdgeTTS女声-晓伊', 'zh-CN-XiaoyiNeural', '普通话', NULL, NULL, 1, NULL, NULL, NULL, NULL),
+('TTS_EdgeTTS0004', 'TTS_EdgeTTS', 'EdgeTTS男声-云健', 'zh-CN-YunjianNeural', '普通话', NULL, NULL, 1, NULL, NULL, NULL, NULL),
+('TTS_EdgeTTS0005', 'TTS_EdgeTTS', 'EdgeTTS男声-云希', 'zh-CN-YunxiNeural', '普通话', NULL, NULL, 1, NULL, NULL, NULL, NULL),
+('TTS_EdgeTTS0006', 'TTS_EdgeTTS', 'EdgeTTS男声-云夏', 'zh-CN-YunxiaNeural', '普通话', NULL, NULL, 1, NULL, NULL, NULL, NULL),
+('TTS_EdgeTTS0007', 'TTS_EdgeTTS', 'EdgeTTS女声-辽宁小贝', 'zh-CN-liaoning-XiaobeiNeural', '辽宁', NULL, NULL, 1, NULL, NULL, NULL, NULL),
+('TTS_EdgeTTS0008', 'TTS_EdgeTTS', 'EdgeTTS女声-陕西小妮', 'zh-CN-shaanxi-XiaoniNeural', '陕西', NULL, NULL, 1, NULL, NULL, NULL, NULL),
+('TTS_EdgeTTS0009', 'TTS_EdgeTTS', 'EdgeTTS女声-香港海佳', 'zh-HK-HiuGaaiNeural', '粤语', 'General', 'Friendly, Positive', 1, NULL, NULL, NULL, NULL),
+('TTS_EdgeTTS0010', 'TTS_EdgeTTS', 'EdgeTTS女声-香港海曼', 'zh-HK-HiuMaanNeural', '粤语', 'General', 'Friendly, Positive', 1, NULL, NULL, NULL, NULL),
+('TTS_EdgeTTS0011', 'TTS_EdgeTTS', 'EdgeTTS男声-香港万龙', 'zh-HK-WanLungNeural', '粤语', 'General', 'Friendly, Positive', 1, NULL, NULL, NULL, NULL);
+
+-- 增加是否允许用户注册参数
+delete from `sys_params` where id in (103,104);
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (103, 'server.allow_user_register', 'false', 'boolean', 1, '是否运行管理员以外的人注册');
+INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) VALUES (104, 'server.fronted_url', 'http://xiaozhi.server.com', 'string', 1, '下发六位验证码时显示的控制面板地址');
+
+-- 修正CosyVoiceSiliconflow音色
+delete from `ai_tts_voice` where tts_model_id = 'TTS_CosyVoiceSiliconflow';
+INSERT INTO `ai_tts_voice` VALUES ('TTS_CosyVoiceSiliconflow0001', 'TTS_CosyVoiceSiliconflow', 'CosyVoice男声', 'FunAudioLLM/CosyVoice2-0.5B:alex', '中文', 'https://example.com/cosyvoice/alex.mp3', NULL, 6, NULL, NULL, NULL, NULL);
+INSERT INTO `ai_tts_voice` VALUES ('TTS_CosyVoiceSiliconflow0002', 'TTS_CosyVoiceSiliconflow', 'CosyVoice女声', 'FunAudioLLM/CosyVoice2-0.5B:bella', '中文', 'https://example.com/cosyvoice/bella.mp3', NULL, 6, NULL, NULL, NULL, NULL);
diff --git a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml
index 7ce87d8c..178f9ebe 100755
--- a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml
+++ b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml
@@ -16,13 +16,6 @@ databaseChangeLog:
- sqlFile:
encoding: utf8
path: classpath:db/changelog/202503141346.sql
- - changeSet:
- id: 2025_model_provider
- author: John
- changes:
- - sqlFile:
- encoding: utf8
- path: classpath:db/changelog/2025_model_provider.sql
- changeSet:
id: 2025_tts_voive
author: John
@@ -31,16 +24,37 @@ databaseChangeLog:
encoding: utf8
path: classpath:db/changelog/2025_tts_voive.sql
- changeSet:
- id: 2025_model_config
+ id: 202504082211
author: John
changes:
- sqlFile:
encoding: utf8
- path: classpath:db/changelog/2025_model_config.sql
+ path: classpath:db/changelog/202504082211.sql
- changeSet:
- id: 2025_model_temp
+ id: 202504092335
author: John
changes:
- sqlFile:
encoding: utf8
- path: classpath:db/changelog/2025_model_temp.sql
\ No newline at end of file
+ path: classpath:db/changelog/202504092335.sql
+ - changeSet:
+ id: 202504112044
+ author: John
+ changes:
+ - sqlFile:
+ encoding: utf8
+ path: classpath:db/changelog/202504112044.sql
+ - changeSet:
+ id: 202504112058
+ author: John
+ changes:
+ - sqlFile:
+ encoding: utf8
+ path: classpath:db/changelog/202504112058.sql
+ - changeSet:
+ id: 202504151206
+ author: John
+ changes:
+ - sqlFile:
+ encoding: utf8
+ path: classpath:db/changelog/202504151206.sql
diff --git a/main/manager-api/src/main/resources/i18n/messages.properties b/main/manager-api/src/main/resources/i18n/messages.properties
index 91e6a285..5126feb2 100644
--- a/main/manager-api/src/main/resources/i18n/messages.properties
+++ b/main/manager-api/src/main/resources/i18n/messages.properties
@@ -34,3 +34,13 @@
10031=\u5F31\u5BC6\u7801
10032=\u5220\u9664\u672C\u6570\u636E\u5F02\u5E38
10033=\u8BBE\u5907\u9A8C\u8BC1\u7801\u9519\u8BEF
+10034=\u53C2\u6570\u503C\u4E0D\u80FD\u4E3A\u7A7A
+10035=\u53C2\u6570\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
+10036=\u4E0D\u652F\u6301\u7684\u53C2\u6570\u7C7B\u578B
+10037=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684\u6570\u5B57
+10038=\u53C2\u6570\u503C\u5FC5\u987B\u662Ftrue\u6216false
+10039=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u6570\u7EC4\u683C\u5F0F
+10040=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u683C\u5F0F
+
+10041=\u8BBE\u5907\u672A\u627E\u5230
+10042={0}
diff --git a/main/manager-api/src/main/resources/i18n/messages_en_US.properties b/main/manager-api/src/main/resources/i18n/messages_en_US.properties
index 515de18a..43781857 100644
--- a/main/manager-api/src/main/resources/i18n/messages_en_US.properties
+++ b/main/manager-api/src/main/resources/i18n/messages_en_US.properties
@@ -32,4 +32,15 @@
10030=The password is less than {0} digits.
10031=The password must consist of numbers, uppercase and lowercase letters, and special characters at the same time
10032=Exception in deleting this data
-10033=Device verification code error
\ No newline at end of file
+10033=Device verification code error
+
+10034=Parameter value cannot be empty
+10035=Parameter type cannot be empty
+10036=Unsupported parameter type
+10037=Parameter value must be a valid number
+10038=Parameter value must be true or false
+10039=Parameter value must be a valid JSON array format
+10040=Parameter value must be a valid JSON format
+
+10041=Device not found
+10042={0}
\ No newline at end of file
diff --git a/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties b/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties
index 23b9abfa..713ab96a 100644
--- a/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties
+++ b/main/manager-api/src/main/resources/i18n/messages_zh_CN.properties
@@ -32,4 +32,15 @@
10030=\u5BC6\u7801\u957F\u5EA6\u4E0D\u8DB3{0}\u4F4D
10031=\u5BC6\u7801\u5FC5\u987B\u540C\u65F6\u5305\u542B\u6570\u5B57\u3001\u5927\u5C0F\u5B57\u6BCD\u548C\u7279\u6B8A\u5B57\u7B26\u7EC4\u6210
10032=\u5220\u9664\u672C\u6570\u636E\u5F02\u5E38
-10033=\u8BBE\u5907\u9A8C\u8BC1\u7801\u9519\u8BEF
\ No newline at end of file
+10033=\u8BBE\u5907\u9A8C\u8BC1\u7801\u9519\u8BEF
+
+10034=\u53C2\u6570\u503C\u4E0D\u80FD\u4E3A\u7A7A
+10035=\u53C2\u6570\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
+10036=\u4E0D\u652F\u6301\u7684\u53C2\u6570\u7C7B\u578B
+10037=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684\u6570\u5B57
+10038=\u53C2\u6570\u503C\u5FC5\u987B\u662Ftrue\u6216false
+10039=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u6570\u7EC4\u683C\u5F0F
+10040=\u53C2\u6570\u503C\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u683C\u5F0F
+
+10041=\u8BBE\u5907\u672A\u627E\u5230
+10042={0}
\ No newline at end of file
diff --git a/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties b/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties
index 2a6bd8d0..b5847ec4 100644
--- a/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties
+++ b/main/manager-api/src/main/resources/i18n/messages_zh_TW.properties
@@ -32,4 +32,15 @@
10030=\u5BC6\u78BC\u9577\u5EA6\u4E0D\u8DB3{0}\u4F4D
10031=\u5BC6\u78BC\u5FC5\u9808\u540C\u6642\u5305\u542B\u6578\u5B57\u3001\u5927\u5C0F\u5B57\u6BCD\u548C\u7279\u6B8A\u5B57\u7B26\u7D44\u6210
10032=\u522A\u9664\u6B64\u6578\u64DA\u7570\u5E38
-10033=\u8A2D\u5099\u9A57\u8B49\u78BC\u932F\u8AA4
\ No newline at end of file
+10033=\u8A2D\u5099\u9A57\u8B49\u78BC\u932F\u8AA4
+
+10034=\u53C3\u6578\u503C\u4E0D\u80FD\u70BA\u7A7A
+10035=\u53C3\u6578\u985E\u578B\u4E0D\u80FD\u70BA\u7A7A
+10036=\u4E0D\u652F\u63F4\u7684\u53C3\u6578\u985E\u578B
+10037=\u53C3\u6578\u503C\u5FC5\u9808\u662F\u6709\u6548\u7684\u6578\u5B57
+10038=\u53C3\u6578\u503C\u5FC5\u9808\u662Ftrue\u6216false
+10039=\u53C3\u6578\u503C\u5FC5\u9808\u662F\u6709\u6548\u7684JSON\u6578\u7D44\u683C\u5F0F
+10040=\u53C3\u6578\u503C\u5FC5\u9808\u662F\u6709\u6548\u7684JSON\u683C\u5F0F
+
+10041=\u8A2D\u5099\u672A\u627E\u5230
+10042={0}
\ No newline at end of file
diff --git a/main/manager-api/src/main/resources/i18n/validation.properties b/main/manager-api/src/main/resources/i18n/validation.properties
index e7452e47..652ae269 100644
--- a/main/manager-api/src/main/resources/i18n/validation.properties
+++ b/main/manager-api/src/main/resources/i18n/validation.properties
@@ -3,6 +3,8 @@ id.require=ID\u4E0D\u80FD\u4E3A\u7A7A
id.null=ID\u5FC5\u987B\u4E3A\u7A7A
sort.number=\u6392\u5E8F\u503C\u4E0D\u80FD\u5C0F\u4E8E0
+page.number=\u9875\u6570\u4E0D\u80FD\u5C0F\u4E8E0
+limit.number=\u5217\u6570\u4E0D\u80FD\u5C0F\u4E8E0
sysdict.type.require=\u5B57\u5178\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
sysdict.name.require=\u5B57\u5178\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
@@ -10,6 +12,8 @@ sysdict.label.require=\u5B57\u5178\u6807\u7B7E\u4E0D\u80FD\u4E3A\u7A7A
sysparams.paramcode.require=\u53C2\u6570\u7F16\u7801\u4E0D\u80FD\u4E3A\u7A7A
sysparams.paramvalue.require=\u53C2\u6570\u503C\u4E0D\u80FD\u4E3A\u7A7A
+sysparams.valuetype.require=\u503C\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
+sysparams.valuetype.pattern=\u503C\u7C7B\u578B\u5FC5\u987B\u662F string\u3001number\u3001boolean \u6216 array
sysuser.username.require=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A
sysuser.password.require=\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A
@@ -29,3 +33,5 @@ timbre.ttsModelId.require=\u97F3\u8272\u7684tts\u4E3B\u952E\u4E0D\u53EF\u4EE5\u4
timbre.ttsVoice.require=\u97F3\u8272\u7684\u7F16\u7801\u4E0D\u53EF\u4EE5\u4E3A\u7A7A
timbre.voiceDemo.require=\u97F3\u8272\u7684\u64AD\u653EDemo\u4E0D\u53EF\u4EE5\u4E3A\u7A7A
+ota.device.not.found=\u8BBE\u5907\u672A\u627E\u5230
+ota.device.need.bind={0}
diff --git a/main/manager-api/src/main/resources/i18n/validation_en_US.properties b/main/manager-api/src/main/resources/i18n/validation_en_US.properties
index 37bebf18..fb6f3828 100644
--- a/main/manager-api/src/main/resources/i18n/validation_en_US.properties
+++ b/main/manager-api/src/main/resources/i18n/validation_en_US.properties
@@ -3,6 +3,8 @@ id.require=ID can not be empty
id.null=ID has to be empty
sort.number=The sort value cannot be less than 0
+page.number=The page value cannot be less than 0
+limit.number=The limit value cannot be less than 0
sysdict.type.require=The dictionary type cannot be empty
sysdict.name.require=The dictionary name cannot be empty
@@ -10,6 +12,8 @@ sysdict.label.require=Dictionary tag cannot be empty
sysparams.paramcode.require=Parameter encoding cannot be empty
sysparams.paramvalue.require=Parameter values cannot be empty
+sysparams.valuetype.require=Value type cannot be empty
+sysparams.valuetype.pattern=Value type must be string, number, boolean or array
sysuser.username.require=The username cannot be empty
sysuser.password.require=The password cannot be empty
@@ -28,3 +32,5 @@ timbre.ttsModelId.require=The TTS model ID of the timbre cannot be empty
timbre.ttsVoice.require=The TTS voice of the timbre cannot be empty
timbre.voiceDemo.require=The voice demo of the timbre cannot be empty
+ota.device.not.found=Device not found
+ota.device.need.bind={0}
\ No newline at end of file
diff --git a/main/manager-api/src/main/resources/i18n/validation_zh_CN.properties b/main/manager-api/src/main/resources/i18n/validation_zh_CN.properties
index 41bf1e69..1ff8a3ba 100644
--- a/main/manager-api/src/main/resources/i18n/validation_zh_CN.properties
+++ b/main/manager-api/src/main/resources/i18n/validation_zh_CN.properties
@@ -3,6 +3,8 @@ id.require=ID\u4E0D\u80FD\u4E3A\u7A7A
id.null=ID\u5FC5\u987B\u4E3A\u7A7A
sort.number=\u6392\u5E8F\u503C\u4E0D\u80FD\u5C0F\u4E8E0
+page.number=\u9801\u6578\u4E0D\u80FD\u5C0F\u4E8E0
+limit.number=\u5217\u6578\u4E0D\u80FD\u5C0F\u4E8E0
sysdict.type.require=\u5B57\u5178\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
sysdict.name.require=\u5B57\u5178\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
@@ -10,6 +12,8 @@ sysdict.label.require=\u5B57\u5178\u6807\u7B7E\u4E0D\u80FD\u4E3A\u7A7A
sysparams.paramcode.require=\u53C2\u6570\u7F16\u7801\u4E0D\u80FD\u4E3A\u7A7A
sysparams.paramvalue.require=\u53C2\u6570\u503C\u4E0D\u80FD\u4E3A\u7A7A
+sysparams.valuetype.require=\u503C\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
+sysparams.valuetype.pattern=\u503C\u7C7B\u578B\u5FC5\u987B\u662F string\u3001number\u3001boolean \u6216 array
sysuser.username.require=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A
sysuser.password.require=\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A
@@ -28,3 +32,5 @@ timbre.ttsModelId.require=\u97F3\u8272\u7684tts\u4E3B\u9375\u4E0D\u53EF\u4EE5\u7
timbre.ttsVoice.require=\u97F3\u8272\u7684\u7DE8\u78BC\u4E0D\u53EF\u4EE5\u70BA\u7A7A
timbre.voiceDemo.require=\u97F3\u8272\u7684\u64AD\u653E\u5730\u5740\u4E0D\u53EF\u4EE5\u70BA\u7A7A
+ota.device.not.found=\u8A2D\u5099\u672A\u627E\u5230
+ota.device.need.bind={0}
\ No newline at end of file
diff --git a/main/manager-api/src/main/resources/i18n/validation_zh_TW.properties b/main/manager-api/src/main/resources/i18n/validation_zh_TW.properties
index 9241c97a..dd6eab90 100644
--- a/main/manager-api/src/main/resources/i18n/validation_zh_TW.properties
+++ b/main/manager-api/src/main/resources/i18n/validation_zh_TW.properties
@@ -3,13 +3,17 @@ id.require=ID\u4E0D\u80FD\u4E3A\u7A7A
id.null=ID\u5FC5\u987B\u4E3A\u7A7A
sort.number=\u6392\u5E8F\u503C\u4E0D\u80FD\u5C0F\u4E8E0
+page.number=\u9875\u6570\u4E0D\u80FD\u5C0F\u4E8E0
+limit.number=\u5217\u6570\u4E0D\u80FD\u5C0F\u4E8E0
sysdict.type.require=\u5B57\u5178\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
sysdict.name.require=\u5B57\u5178\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
sysdict.label.require=\u5B57\u5178\u6807\u7B7E\u4E0D\u80FD\u4E3A\u7A7A
-sysparams.paramcode.require=\u53C2\u6570\u7F16\u7801\u4E0D\u80FD\u4E3A\u7A7A
-sysparams.paramvalue.require=\u53C2\u6570\u503C\u4E0D\u80FD\u4E3A\u7A7A
+sysparams.paramcode.require=\u53C3\u6578\u7DE8\u78BC\u4E0D\u80FD\u70BA\u7A7A
+sysparams.paramvalue.require=\u53C3\u6578\u503C\u4E0D\u80FD\u70BA\u7A7A
+sysparams.valuetype.require=\u503C\u985E\u578B\u4E0D\u80FD\u70BA\u7A7A
+sysparams.valuetype.pattern=\u503C\u985E\u578B\u5FC5\u9808\u662F string\u3001number\u3001boolean \u6216 array
sysuser.username.require=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A
sysuser.password.require=\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A
@@ -27,3 +31,6 @@ timbre.remark.require=\u97F3\u8272\u7684\u5907\u6CE8\u4E0D\u53EF\u4EE5\u4E3A\u7A
timbre.ttsModelId.require=\u97F3\u8272\u7684tts\u4E3B\u952E\u4E0D\u53EF\u4EE5\u4E3A\u7A7A
timbre.ttsVoice.require=\u97F3\u8272\u7684\u7F16\u7801\u4E0D\u53EF\u4EE5\u4E3A\u7A7A
timbre.voiceDemo.require=\u97F3\u8272\u7684\u64AD\u653EDemo\u4E0D\u53EF\u4EE5\u4E3A\u7A7A
+
+ota.device.not.found=\u8A2D\u5099\u672A\u627E\u5230
+ota.device.need.bind={0}
\ No newline at end of file
diff --git a/main/manager-api/src/main/resources/mapper/agent/AgentDao.xml b/main/manager-api/src/main/resources/mapper/agent/AgentDao.xml
new file mode 100644
index 00000000..322ca172
--- /dev/null
+++ b/main/manager-api/src/main/resources/mapper/agent/AgentDao.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+ SELECT COUNT(*) FROM ai_device WHERE agent_id = #{agentId}
+
+
\ No newline at end of file
diff --git a/main/manager-api/src/main/resources/mapper/model/ModelConfigDao.xml b/main/manager-api/src/main/resources/mapper/model/ModelConfigDao.xml
index 3f01ea5b..4f35f8d1 100644
--- a/main/manager-api/src/main/resources/mapper/model/ModelConfigDao.xml
+++ b/main/manager-api/src/main/resources/mapper/model/ModelConfigDao.xml
@@ -2,6 +2,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
select model_name from ai_model_config where model_type = #{modelType}
diff --git a/main/manager-web/.env b/main/manager-web/.env
index 752f67e3..1b5f8138 100644
--- a/main/manager-web/.env
+++ b/main/manager-web/.env
@@ -1 +1 @@
-VUE_APP_TITLE=小智-智控台
\ No newline at end of file
+VUE_APP_TITLE=智控台
\ No newline at end of file
diff --git a/main/manager-web/.env.development b/main/manager-web/.env.development
index b2aadb84..0a1de306 100644
--- a/main/manager-web/.env.development
+++ b/main/manager-web/.env.development
@@ -1 +1 @@
-VUE_APP_API_BASE_URL=https://2662r3426b.vicp.fun
\ No newline at end of file
+VUE_APP_API_BASE_URL=/xiaozhi
\ No newline at end of file
diff --git a/main/manager-web/.env.production b/main/manager-web/.env.production
index b2aadb84..d61ca06f 100644
--- a/main/manager-web/.env.production
+++ b/main/manager-web/.env.production
@@ -1 +1,3 @@
-VUE_APP_API_BASE_URL=https://2662r3426b.vicp.fun
\ No newline at end of file
+VUE_APP_API_BASE_URL=/xiaozhi
+# 是否开启CDN
+VUE_APP_USE_CDN=false
\ No newline at end of file
diff --git a/main/manager-web/README.md b/main/manager-web/README.md
index 3d26f25e..d0a34ad1 100644
--- a/main/manager-web/README.md
+++ b/main/manager-web/README.md
@@ -1,4 +1,4 @@
-本文档是开发类文档,如需部署小智服务端,[点击这里查看部署教程](.././FAQ.md#%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F-)
+本文档是开发类文档,如需部署小智服务端,[点击这里查看部署教程](../../README.md#%E9%83%A8%E7%BD%B2%E6%96%87%E6%A1%A3)
# xiaozhi
diff --git a/main/manager-web/babel.config.js b/main/manager-web/babel.config.js
index 52fce6d4..b3469a75 100644
--- a/main/manager-web/babel.config.js
+++ b/main/manager-web/babel.config.js
@@ -1,13 +1,12 @@
module.exports = {
- presets: [
- ['@vue/cli-plugin-babel/preset', {
- useBuiltIns: 'usage',
- corejs: 3
- }]
- ],
- plugins: [
- '@babel/plugin-syntax-dynamic-import', // 确保支持动态导入 (Lazy Loading)
- '@babel/plugin-transform-runtime'
- ]
- }
-
\ No newline at end of file
+ presets: [
+ ['@vue/cli-plugin-babel/preset', {
+ useBuiltIns: 'usage',
+ corejs: 3
+ }]
+ ],
+ plugins: [
+ '@babel/plugin-syntax-dynamic-import', // 确保支持动态导入 (Lazy Loading)
+ '@babel/plugin-transform-runtime'
+ ]
+}
diff --git a/main/manager-web/jsconfig.json b/main/manager-web/jsconfig.json
index 4aafc5f6..587b2896 100644
--- a/main/manager-web/jsconfig.json
+++ b/main/manager-web/jsconfig.json
@@ -16,4 +16,4 @@
"scripthost"
]
}
-}
+}
\ No newline at end of file
diff --git a/main/manager-web/package-lock.json b/main/manager-web/package-lock.json
index 54610c6d..c104b60c 100644
--- a/main/manager-web/package-lock.json
+++ b/main/manager-web/package-lock.json
@@ -31,7 +31,8 @@
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"vue-template-compiler": "^2.6.14",
- "webpack-bundle-analyzer": "^4.10.2"
+ "webpack-bundle-analyzer": "^4.10.2",
+ "workbox-webpack-plugin": "^7.3.0"
}
},
"node_modules/@achrinza/node-ipc": {
@@ -53,7 +54,6 @@
"resolved": "https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.3.0.tgz",
"integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
"dev": true,
- "peer": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
@@ -90,7 +90,6 @@
"resolved": "https://registry.npmmirror.com/@babel/core/-/core-7.26.10.tgz",
"integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==",
"dev": true,
- "peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.2",
@@ -132,6 +131,18 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/helper-annotate-as-pure": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz",
+ "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-compilation-targets": {
"version": "7.27.0",
"resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz",
@@ -148,6 +159,44 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/helper-create-class-features-plugin": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.0.tgz",
+ "integrity": "sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.25.9",
+ "@babel/helper-member-expression-to-functions": "^7.25.9",
+ "@babel/helper-optimise-call-expression": "^7.25.9",
+ "@babel/helper-replace-supers": "^7.26.5",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
+ "@babel/traverse": "^7.27.0",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-create-regexp-features-plugin": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.0.tgz",
+ "integrity": "sha512-fO8l08T76v48BhpNRW/nQ0MxfnSdoSKUJBMjubOAYffsVuGG5qOfMq7N6Es7UJvi7Y8goXXo07EfcHZXDPuELQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.25.9",
+ "regexpu-core": "^6.2.0",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
"node_modules/@babel/helper-define-polyfill-provider": {
"version": "0.6.4",
"resolved": "https://registry.npmmirror.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.4.tgz",
@@ -164,6 +213,19 @@
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
}
},
+ "node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz",
+ "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.25.9",
+ "@babel/types": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-module-imports": {
"version": "7.25.9",
"resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
@@ -182,7 +244,6 @@
"resolved": "https://registry.npmmirror.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz",
"integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==",
"dev": true,
- "peer": true,
"dependencies": {
"@babel/helper-module-imports": "^7.25.9",
"@babel/helper-validator-identifier": "^7.25.9",
@@ -195,6 +256,18 @@
"@babel/core": "^7.0.0"
}
},
+ "node_modules/@babel/helper-optimise-call-expression": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz",
+ "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-plugin-utils": {
"version": "7.26.5",
"resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz",
@@ -204,6 +277,53 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/helper-remap-async-to-generator": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz",
+ "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.25.9",
+ "@babel/helper-wrap-function": "^7.25.9",
+ "@babel/traverse": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-replace-supers": {
+ "version": "7.26.5",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz",
+ "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-member-expression-to-functions": "^7.25.9",
+ "@babel/helper-optimise-call-expression": "^7.25.9",
+ "@babel/traverse": "^7.26.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz",
+ "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.25.9",
+ "@babel/types": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helper-string-parser": {
"version": "7.25.9",
"resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
@@ -229,12 +349,25 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/helper-wrap-function": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz",
+ "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.25.9",
+ "@babel/traverse": "^7.25.9",
+ "@babel/types": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/helpers": {
"version": "7.27.0",
"resolved": "https://registry.npmmirror.com/@babel/helpers/-/helpers-7.27.0.tgz",
"integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==",
"dev": true,
- "peer": true,
"dependencies": {
"@babel/template": "^7.27.0",
"@babel/types": "^7.27.0"
@@ -257,6 +390,97 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz",
+ "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/traverse": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz",
+ "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz",
+ "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz",
+ "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
+ "@babel/plugin-transform-optional-chaining": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.13.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz",
+ "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/traverse": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-private-property-in-object": {
+ "version": "7.21.0-placeholder-for-preset-env.2",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz",
+ "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
"node_modules/@babel/plugin-syntax-dynamic-import": {
"version": "7.8.3",
"resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
@@ -269,6 +493,700 @@
"@babel/core": "^7.0.0-0"
}
},
+ "node_modules/@babel/plugin-syntax-import-assertions": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz",
+ "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-import-attributes": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz",
+ "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-unicode-sets-regex": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz",
+ "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+ "@babel/helper-plugin-utils": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-arrow-functions": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz",
+ "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-async-generator-functions": {
+ "version": "7.26.8",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz",
+ "integrity": "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5",
+ "@babel/helper-remap-async-to-generator": "^7.25.9",
+ "@babel/traverse": "^7.26.8"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-async-to-generator": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz",
+ "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-remap-async-to-generator": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-block-scoped-functions": {
+ "version": "7.26.5",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz",
+ "integrity": "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-block-scoping": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.0.tgz",
+ "integrity": "sha512-u1jGphZ8uDI2Pj/HJj6YQ6XQLZCNjOlprjxB5SVz6rq2T6SwAR+CdrWK0CP7F+9rDVMXdB0+r6Am5G5aobOjAQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-class-properties": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz",
+ "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-class-static-block": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz",
+ "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.12.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-classes": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz",
+ "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.25.9",
+ "@babel/helper-compilation-targets": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-replace-supers": "^7.25.9",
+ "@babel/traverse": "^7.25.9",
+ "globals": "^11.1.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-computed-properties": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz",
+ "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/template": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-destructuring": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz",
+ "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-dotall-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz",
+ "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-duplicate-keys": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz",
+ "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz",
+ "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-dynamic-import": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz",
+ "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-exponentiation-operator": {
+ "version": "7.26.3",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz",
+ "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-export-namespace-from": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz",
+ "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-for-of": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.26.9.tgz",
+ "integrity": "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-function-name": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz",
+ "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-compilation-targets": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/traverse": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-json-strings": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz",
+ "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-literals": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz",
+ "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-logical-assignment-operators": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz",
+ "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-member-expression-literals": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz",
+ "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-amd": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz",
+ "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-commonjs": {
+ "version": "7.26.3",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz",
+ "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.26.0",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-systemjs": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz",
+ "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-validator-identifier": "^7.25.9",
+ "@babel/traverse": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-umd": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz",
+ "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz",
+ "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-new-target": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz",
+ "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
+ "version": "7.26.6",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz",
+ "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-numeric-separator": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz",
+ "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-object-rest-spread": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz",
+ "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-compilation-targets": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/plugin-transform-parameters": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-object-super": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz",
+ "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-replace-supers": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-optional-catch-binding": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz",
+ "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-optional-chaining": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz",
+ "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-parameters": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz",
+ "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-private-methods": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz",
+ "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-private-property-in-object": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz",
+ "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.25.9",
+ "@babel/helper-create-class-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-property-literals": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz",
+ "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-regenerator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.0.tgz",
+ "integrity": "sha512-LX/vCajUJQDqE7Aum/ELUMZAY19+cDpghxrnyt5I1tV6X5PyC86AOoWXWFYFeIvauyeSA6/ktn4tQVn/3ZifsA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5",
+ "regenerator-transform": "^0.15.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-regexp-modifiers": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz",
+ "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-reserved-words": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz",
+ "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
"node_modules/@babel/plugin-transform-runtime": {
"version": "7.26.10",
"resolved": "https://registry.npmmirror.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.26.10.tgz",
@@ -289,6 +1207,260 @@
"@babel/core": "^7.0.0-0"
}
},
+ "node_modules/@babel/plugin-transform-shorthand-properties": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz",
+ "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-spread": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz",
+ "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-sticky-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz",
+ "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-template-literals": {
+ "version": "7.26.8",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz",
+ "integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-typeof-symbol": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.0.tgz",
+ "integrity": "sha512-+LLkxA9rKJpNoGsbLnAgOCdESl73vwYn+V6b+5wHbrE7OGKVDPHIQvbFSzqE6rwqaCw2RE+zdJrlLkcf8YOA0w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-escapes": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz",
+ "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-property-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz",
+ "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz",
+ "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-sets-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmmirror.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz",
+ "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/preset-env": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmmirror.com/@babel/preset-env/-/preset-env-7.26.9.tgz",
+ "integrity": "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/compat-data": "^7.26.8",
+ "@babel/helper-compilation-targets": "^7.26.5",
+ "@babel/helper-plugin-utils": "^7.26.5",
+ "@babel/helper-validator-option": "^7.25.9",
+ "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9",
+ "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9",
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9",
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9",
+ "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9",
+ "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
+ "@babel/plugin-syntax-import-assertions": "^7.26.0",
+ "@babel/plugin-syntax-import-attributes": "^7.26.0",
+ "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
+ "@babel/plugin-transform-arrow-functions": "^7.25.9",
+ "@babel/plugin-transform-async-generator-functions": "^7.26.8",
+ "@babel/plugin-transform-async-to-generator": "^7.25.9",
+ "@babel/plugin-transform-block-scoped-functions": "^7.26.5",
+ "@babel/plugin-transform-block-scoping": "^7.25.9",
+ "@babel/plugin-transform-class-properties": "^7.25.9",
+ "@babel/plugin-transform-class-static-block": "^7.26.0",
+ "@babel/plugin-transform-classes": "^7.25.9",
+ "@babel/plugin-transform-computed-properties": "^7.25.9",
+ "@babel/plugin-transform-destructuring": "^7.25.9",
+ "@babel/plugin-transform-dotall-regex": "^7.25.9",
+ "@babel/plugin-transform-duplicate-keys": "^7.25.9",
+ "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9",
+ "@babel/plugin-transform-dynamic-import": "^7.25.9",
+ "@babel/plugin-transform-exponentiation-operator": "^7.26.3",
+ "@babel/plugin-transform-export-namespace-from": "^7.25.9",
+ "@babel/plugin-transform-for-of": "^7.26.9",
+ "@babel/plugin-transform-function-name": "^7.25.9",
+ "@babel/plugin-transform-json-strings": "^7.25.9",
+ "@babel/plugin-transform-literals": "^7.25.9",
+ "@babel/plugin-transform-logical-assignment-operators": "^7.25.9",
+ "@babel/plugin-transform-member-expression-literals": "^7.25.9",
+ "@babel/plugin-transform-modules-amd": "^7.25.9",
+ "@babel/plugin-transform-modules-commonjs": "^7.26.3",
+ "@babel/plugin-transform-modules-systemjs": "^7.25.9",
+ "@babel/plugin-transform-modules-umd": "^7.25.9",
+ "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9",
+ "@babel/plugin-transform-new-target": "^7.25.9",
+ "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6",
+ "@babel/plugin-transform-numeric-separator": "^7.25.9",
+ "@babel/plugin-transform-object-rest-spread": "^7.25.9",
+ "@babel/plugin-transform-object-super": "^7.25.9",
+ "@babel/plugin-transform-optional-catch-binding": "^7.25.9",
+ "@babel/plugin-transform-optional-chaining": "^7.25.9",
+ "@babel/plugin-transform-parameters": "^7.25.9",
+ "@babel/plugin-transform-private-methods": "^7.25.9",
+ "@babel/plugin-transform-private-property-in-object": "^7.25.9",
+ "@babel/plugin-transform-property-literals": "^7.25.9",
+ "@babel/plugin-transform-regenerator": "^7.25.9",
+ "@babel/plugin-transform-regexp-modifiers": "^7.26.0",
+ "@babel/plugin-transform-reserved-words": "^7.25.9",
+ "@babel/plugin-transform-shorthand-properties": "^7.25.9",
+ "@babel/plugin-transform-spread": "^7.25.9",
+ "@babel/plugin-transform-sticky-regex": "^7.25.9",
+ "@babel/plugin-transform-template-literals": "^7.26.8",
+ "@babel/plugin-transform-typeof-symbol": "^7.26.7",
+ "@babel/plugin-transform-unicode-escapes": "^7.25.9",
+ "@babel/plugin-transform-unicode-property-regex": "^7.25.9",
+ "@babel/plugin-transform-unicode-regex": "^7.25.9",
+ "@babel/plugin-transform-unicode-sets-regex": "^7.25.9",
+ "@babel/preset-modules": "0.1.6-no-external-plugins",
+ "babel-plugin-polyfill-corejs2": "^0.4.10",
+ "babel-plugin-polyfill-corejs3": "^0.11.0",
+ "babel-plugin-polyfill-regenerator": "^0.6.1",
+ "core-js-compat": "^3.40.0",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/preset-modules": {
+ "version": "0.1.6-no-external-plugins",
+ "resolved": "https://registry.npmmirror.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
+ "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/types": "^7.4.4",
+ "esutils": "^2.0.2"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.27.0.tgz",
+ "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==",
+ "dev": true,
+ "dependencies": {
+ "regenerator-runtime": "^0.14.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/runtime/node_modules/regenerator-runtime": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+ "dev": true
+ },
"node_modules/@babel/template": {
"version": "7.27.0",
"resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.27.0.tgz",
@@ -775,6 +1947,160 @@
"integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==",
"dev": true
},
+ "node_modules/@rollup/plugin-babel": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
+ "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.10.4",
+ "@rollup/pluginutils": "^3.1.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0",
+ "@types/babel__core": "^7.1.9",
+ "rollup": "^1.20.0||^2.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/babel__core": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/plugin-node-resolve": {
+ "version": "15.3.1",
+ "resolved": "https://registry.npmmirror.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz",
+ "integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==",
+ "dev": true,
+ "dependencies": {
+ "@rollup/pluginutils": "^5.0.1",
+ "@types/resolve": "1.20.2",
+ "deepmerge": "^4.2.2",
+ "is-module": "^1.0.0",
+ "resolve": "^1.22.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^2.78.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/plugin-node-resolve/node_modules/@rollup/pluginutils": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz",
+ "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^2.0.2",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/plugin-node-resolve/node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmmirror.com/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/@rollup/plugin-node-resolve/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true
+ },
+ "node_modules/@rollup/plugin-node-resolve/node_modules/picomatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz",
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/@rollup/plugin-replace": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz",
+ "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==",
+ "dev": true,
+ "dependencies": {
+ "@rollup/pluginutils": "^3.1.0",
+ "magic-string": "^0.25.7"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0 || ^2.0.0"
+ }
+ },
+ "node_modules/@rollup/plugin-terser": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmmirror.com/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
+ "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
+ "dev": true,
+ "dependencies": {
+ "serialize-javascript": "^6.0.1",
+ "smob": "^1.0.0",
+ "terser": "^5.17.4"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/pluginutils": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
+ "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "0.0.39",
+ "estree-walker": "^1.0.1",
+ "picomatch": "^2.2.2"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0"
+ }
+ },
+ "node_modules/@rollup/pluginutils/node_modules/@types/estree": {
+ "version": "0.0.39",
+ "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-0.0.39.tgz",
+ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
+ "dev": true
+ },
"node_modules/@sideway/address": {
"version": "4.1.5",
"resolved": "https://registry.npmmirror.com/@sideway/address/-/address-4.1.5.tgz",
@@ -820,6 +2146,18 @@
"integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==",
"dev": true
},
+ "node_modules/@surma/rollup-plugin-off-main-thread": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmmirror.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
+ "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==",
+ "dev": true,
+ "dependencies": {
+ "ejs": "^3.1.6",
+ "json5": "^2.2.0",
+ "magic-string": "^0.25.0",
+ "string.prototype.matchall": "^4.0.6"
+ }
+ },
"node_modules/@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmmirror.com/@trysound/sax/-/sax-0.2.0.tgz",
@@ -1010,6 +2348,12 @@
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
"dev": true
},
+ "node_modules/@types/resolve": {
+ "version": "1.20.2",
+ "resolved": "https://registry.npmmirror.com/@types/resolve/-/resolve-1.20.2.tgz",
+ "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
+ "dev": true
+ },
"node_modules/@types/retry": {
"version": "0.12.0",
"resolved": "https://registry.npmmirror.com/@types/retry/-/retry-0.12.0.tgz",
@@ -1055,6 +2399,12 @@
"@types/node": "*"
}
},
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+ "dev": true
+ },
"node_modules/@types/ws": {
"version": "8.18.0",
"resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.18.0.tgz",
@@ -1743,6 +3093,22 @@
}
]
},
+ "node_modules/array-buffer-byte-length": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
+ "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "is-array-buffer": "^3.0.5"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/array-flatten/-/array-flatten-1.1.1.tgz",
@@ -1758,6 +3124,27 @@
"node": ">=8"
}
},
+ "node_modules/arraybuffer.prototype.slice": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmmirror.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
+ "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
+ "dev": true,
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.1",
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "is-array-buffer": "^3.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/asn1": {
"version": "0.2.6",
"resolved": "https://registry.npmmirror.com/asn1/-/asn1-0.2.6.tgz",
@@ -1780,6 +3167,15 @@
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
"dev": true
},
+ "node_modules/async-function": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmmirror.com/async-function/-/async-function-1.0.0.tgz",
+ "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/async-validator": {
"version": "1.8.5",
"resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-1.8.5.tgz",
@@ -1839,6 +3235,21 @@
"postcss": "^8.1.0"
}
},
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "dev": true,
+ "dependencies": {
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmmirror.com/aws-sign2/-/aws-sign2-0.7.0.tgz",
@@ -2164,6 +3575,24 @@
"node": ">= 0.8"
}
},
+ "node_modules/call-bind": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.8.tgz",
+ "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
+ "dev": true,
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.0",
+ "es-define-property": "^1.0.0",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
@@ -2465,6 +3894,15 @@
"node": ">= 12"
}
},
+ "node_modules/common-tags": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmmirror.com/common-tags/-/common-tags-1.8.2.tgz",
+ "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
"node_modules/compressible": {
"version": "2.0.18",
"resolved": "https://registry.npmmirror.com/compressible/-/compressible-2.0.18.tgz",
@@ -2583,8 +4021,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz",
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
- "dev": true,
- "peer": true
+ "dev": true
},
"node_modules/cookie": {
"version": "0.7.1",
@@ -2717,6 +4154,15 @@
"node": ">= 8"
}
},
+ "node_modules/crypto-random-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
+ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/css-declaration-sorter": {
"version": "6.4.1",
"resolved": "https://registry.npmmirror.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz",
@@ -2971,6 +4417,57 @@
"node": ">=0.10"
}
},
+ "node_modules/data-view-buffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmmirror.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
+ "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/data-view-byte-length": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmmirror.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
+ "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/inspect-js"
+ }
+ },
+ "node_modules/data-view-byte-offset": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
+ "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/de-indent": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/de-indent/-/de-indent-1.0.2.tgz",
@@ -3091,6 +4588,23 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dev": true,
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/define-lazy-prop": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
@@ -3100,6 +4614,23 @@
"node": ">=8"
}
},
+ "node_modules/define-properties": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz",
+ "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+ "dev": true,
+ "dependencies": {
+ "define-data-property": "^1.0.1",
+ "has-property-descriptors": "^1.0.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -3302,6 +4833,21 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
"dev": true
},
+ "node_modules/ejs": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmmirror.com/ejs/-/ejs-3.1.10.tgz",
+ "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
+ "dev": true,
+ "dependencies": {
+ "jake": "^10.8.5"
+ },
+ "bin": {
+ "ejs": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.5.128",
"resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.128.tgz",
@@ -3397,6 +4943,71 @@
"stackframe": "^1.3.4"
}
},
+ "node_modules/es-abstract": {
+ "version": "1.23.9",
+ "resolved": "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.23.9.tgz",
+ "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==",
+ "dev": true,
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.2",
+ "arraybuffer.prototype.slice": "^1.0.4",
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "data-view-buffer": "^1.0.2",
+ "data-view-byte-length": "^1.0.2",
+ "data-view-byte-offset": "^1.0.1",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "es-set-tostringtag": "^2.1.0",
+ "es-to-primitive": "^1.3.0",
+ "function.prototype.name": "^1.1.8",
+ "get-intrinsic": "^1.2.7",
+ "get-proto": "^1.0.0",
+ "get-symbol-description": "^1.1.0",
+ "globalthis": "^1.0.4",
+ "gopd": "^1.2.0",
+ "has-property-descriptors": "^1.0.2",
+ "has-proto": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "internal-slot": "^1.1.0",
+ "is-array-buffer": "^3.0.5",
+ "is-callable": "^1.2.7",
+ "is-data-view": "^1.0.2",
+ "is-regex": "^1.2.1",
+ "is-shared-array-buffer": "^1.0.4",
+ "is-string": "^1.1.1",
+ "is-typed-array": "^1.1.15",
+ "is-weakref": "^1.1.0",
+ "math-intrinsics": "^1.1.0",
+ "object-inspect": "^1.13.3",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.7",
+ "own-keys": "^1.0.1",
+ "regexp.prototype.flags": "^1.5.3",
+ "safe-array-concat": "^1.1.3",
+ "safe-push-apply": "^1.0.0",
+ "safe-regex-test": "^1.1.0",
+ "set-proto": "^1.0.0",
+ "string.prototype.trim": "^1.2.10",
+ "string.prototype.trimend": "^1.0.9",
+ "string.prototype.trimstart": "^1.0.8",
+ "typed-array-buffer": "^1.0.3",
+ "typed-array-byte-length": "^1.0.3",
+ "typed-array-byte-offset": "^1.0.4",
+ "typed-array-length": "^1.0.7",
+ "unbox-primitive": "^1.1.0",
+ "which-typed-array": "^1.1.18"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz",
@@ -3434,7 +5045,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
- "peer": true,
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
@@ -3445,6 +5055,23 @@
"node": ">= 0.4"
}
},
+ "node_modules/es-to-primitive": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmmirror.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
+ "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
+ "dev": true,
+ "dependencies": {
+ "is-callable": "^1.2.7",
+ "is-date-object": "^1.0.5",
+ "is-symbol": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz",
@@ -3512,6 +5139,21 @@
"node": ">=4.0"
}
},
+ "node_modules/estree-walker": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-1.0.1.tgz",
+ "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
+ "dev": true
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/etag": {
"version": "1.8.1",
"resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz",
@@ -3806,6 +5448,36 @@
"node": ">=4"
}
},
+ "node_modules/filelist": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmmirror.com/filelist/-/filelist-1.0.4.tgz",
+ "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
+ "dev": true,
+ "dependencies": {
+ "minimatch": "^5.0.1"
+ }
+ },
+ "node_modules/filelist/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/filelist/node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz",
@@ -3900,6 +5572,21 @@
}
}
},
+ "node_modules/for-each": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.5.tgz",
+ "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
+ "dev": true,
+ "dependencies": {
+ "is-callable": "^1.2.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/forever-agent/-/forever-agent-0.6.1.tgz",
@@ -4003,12 +5690,40 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/function.prototype.name": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmmirror.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
+ "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "functions-have-names": "^1.2.3",
+ "hasown": "^2.0.2",
+ "is-callable": "^1.2.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/functions-have-names": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz",
+ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmmirror.com/gensync/-/gensync-1.0.0-beta.2.tgz",
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
"dev": true,
- "peer": true,
"engines": {
"node": ">=6.9.0"
}
@@ -4045,6 +5760,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/get-own-enumerable-property-symbols": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmmirror.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz",
+ "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==",
+ "dev": true
+ },
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz",
@@ -4069,6 +5790,23 @@
"node": ">=6"
}
},
+ "node_modules/get-symbol-description": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
+ "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmmirror.com/getpass/-/getpass-0.1.7.tgz",
@@ -4125,6 +5863,22 @@
"node": ">=4"
}
},
+ "node_modules/globalthis": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmmirror.com/globalthis/-/globalthis-1.0.4.tgz",
+ "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.2.1",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/globby": {
"version": "11.1.0",
"resolved": "https://registry.npmmirror.com/globby/-/globby-11.1.0.tgz",
@@ -4204,6 +5958,18 @@
"node": ">=6"
}
},
+ "node_modules/has-bigints": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/has-bigints/-/has-bigints-1.1.0.tgz",
+ "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz",
@@ -4213,6 +5979,33 @@
"node": ">=8"
}
},
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dev": true,
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.2.0.tgz",
+ "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
+ "dev": true,
+ "dependencies": {
+ "dunder-proto": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz",
@@ -4228,7 +6021,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
- "peer": true,
"dependencies": {
"has-symbols": "^1.0.3"
},
@@ -4529,6 +6321,12 @@
"postcss": "^8.1.0"
}
},
+ "node_modules/idb": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmmirror.com/idb/-/idb-7.1.1.tgz",
+ "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==",
+ "dev": true
+ },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz",
@@ -4597,6 +6395,20 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
+ "node_modules/internal-slot": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.1.0.tgz",
+ "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
+ "dev": true,
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "hasown": "^2.0.2",
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/ipaddr.js": {
"version": "2.2.0",
"resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz",
@@ -4606,12 +6418,63 @@
"node": ">= 10"
}
},
+ "node_modules/is-array-buffer": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
+ "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
"dev": true
},
+ "node_modules/is-async-function": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmmirror.com/is-async-function/-/is-async-function-2.1.1.tgz",
+ "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
+ "dev": true,
+ "dependencies": {
+ "async-function": "^1.0.0",
+ "call-bound": "^1.0.3",
+ "get-proto": "^1.0.1",
+ "has-tostringtag": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-bigint": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/is-bigint/-/is-bigint-1.1.0.tgz",
+ "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
+ "dev": true,
+ "dependencies": {
+ "has-bigints": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -4624,6 +6487,34 @@
"node": ">=8"
}
},
+ "node_modules/is-boolean-object": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmmirror.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
+ "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-core-module": {
"version": "2.16.1",
"resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz",
@@ -4639,6 +6530,39 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-data-view": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmmirror.com/is-data-view/-/is-data-view-1.0.2.tgz",
+ "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "get-intrinsic": "^1.2.6",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-date-object": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.1.0.tgz",
+ "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-docker": {
"version": "2.2.1",
"resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-2.2.1.tgz",
@@ -4672,6 +6596,21 @@
"read-pkg-up": "^7.0.1"
}
},
+ "node_modules/is-finalizationregistry": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmmirror.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
+ "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@@ -4681,6 +6620,24 @@
"node": ">=8"
}
},
+ "node_modules/is-generator-function": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/is-generator-function/-/is-generator-function-1.1.0.tgz",
+ "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "get-proto": "^1.0.0",
+ "has-tostringtag": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz",
@@ -4702,6 +6659,24 @@
"node": ">=8"
}
},
+ "node_modules/is-map": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmmirror.com/is-map/-/is-map-2.0.3.tgz",
+ "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmmirror.com/is-module/-/is-module-1.0.0.tgz",
+ "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
+ "dev": true
+ },
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz",
@@ -4711,6 +6686,31 @@
"node": ">=0.12.0"
}
},
+ "node_modules/is-number-object": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmmirror.com/is-number-object/-/is-number-object-1.1.1.tgz",
+ "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/is-obj/-/is-obj-1.0.1.tgz",
+ "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-plain-obj": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz",
@@ -4735,6 +6735,60 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-regex": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.2.1.tgz",
+ "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-regexp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmmirror.com/is-regexp/-/is-regexp-1.0.0.tgz",
+ "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-set": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmmirror.com/is-set/-/is-set-2.0.3.tgz",
+ "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-shared-array-buffer": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
+ "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-1.1.0.tgz",
@@ -4744,6 +6798,54 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-string": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmmirror.com/is-string/-/is-string-1.1.1.tgz",
+ "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-symbol": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmmirror.com/is-symbol/-/is-symbol-1.1.1.tgz",
+ "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "has-symbols": "^1.1.0",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-typed-array": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.15.tgz",
+ "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+ "dev": true,
+ "dependencies": {
+ "which-typed-array": "^1.1.16"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/is-typedarray/-/is-typedarray-1.0.0.tgz",
@@ -4761,6 +6863,49 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/is-weakmap": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmmirror.com/is-weakmap/-/is-weakmap-2.0.2.tgz",
+ "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakref": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmmirror.com/is-weakref/-/is-weakref-1.1.1.tgz",
+ "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakset": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmmirror.com/is-weakset/-/is-weakset-2.0.4.tgz",
+ "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-wsl": {
"version": "2.2.0",
"resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-2.2.0.tgz",
@@ -4798,6 +6943,40 @@
"resolved": "https://registry.npmmirror.com/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
},
+ "node_modules/jake": {
+ "version": "10.9.2",
+ "resolved": "https://registry.npmmirror.com/jake/-/jake-10.9.2.tgz",
+ "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==",
+ "dev": true,
+ "dependencies": {
+ "async": "^3.2.3",
+ "chalk": "^4.0.2",
+ "filelist": "^1.0.4",
+ "minimatch": "^3.1.2"
+ },
+ "bin": {
+ "jake": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/jake/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
"node_modules/javascript-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/javascript-stringify/-/javascript-stringify-2.1.0.tgz",
@@ -4929,6 +7108,15 @@
"graceful-fs": "^4.1.6"
}
},
+ "node_modules/jsonpointer": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmmirror.com/jsonpointer/-/jsonpointer-5.0.1.tgz",
+ "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/jsprim": {
"version": "1.4.2",
"resolved": "https://registry.npmmirror.com/jsprim/-/jsprim-1.4.2.tgz",
@@ -4980,6 +7168,15 @@
"launch-editor": "^2.10.0"
}
},
+ "node_modules/leven": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmmirror.com/leven/-/leven-3.1.0.tgz",
+ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/lilconfig": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/lilconfig/-/lilconfig-2.1.0.tgz",
@@ -5072,6 +7269,12 @@
"integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
"dev": true
},
+ "node_modules/lodash.sortby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmmirror.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+ "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==",
+ "dev": true
+ },
"node_modules/lodash.uniq": {
"version": "4.5.0",
"resolved": "https://registry.npmmirror.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
@@ -5244,6 +7447,15 @@
"yallist": "^3.0.2"
}
},
+ "node_modules/magic-string": {
+ "version": "0.25.9",
+ "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz",
+ "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
+ "dev": true,
+ "dependencies": {
+ "sourcemap-codec": "^1.4.8"
+ }
+ },
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -5697,6 +7909,35 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.7",
+ "resolved": "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.7.tgz",
+ "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0",
+ "has-symbols": "^1.1.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/obuf": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/obuf/-/obuf-1.1.2.tgz",
@@ -5830,6 +8071,23 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/own-keys": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/own-keys/-/own-keys-1.0.1.tgz",
+ "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.2.6",
+ "object-keys": "^1.1.1",
+ "safe-push-apply": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/p-finally/-/p-finally-1.0.0.tgz",
@@ -6050,6 +8308,15 @@
"node": ">= 10.12"
}
},
+ "node_modules/possible-typed-array-names": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
+ "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/postcss": {
"version": "8.5.3",
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.3.tgz",
@@ -6635,6 +8902,18 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
+ "node_modules/pretty-bytes": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmmirror.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
+ "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/pretty-error": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/pretty-error/-/pretty-error-4.0.0.tgz",
@@ -6922,11 +9201,127 @@
"url": "https://paulmillr.com/funding/"
}
},
+ "node_modules/reflect.getprototypeof": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmmirror.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
+ "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.9",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.7",
+ "get-proto": "^1.0.1",
+ "which-builtin-type": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/regenerate": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmmirror.com/regenerate/-/regenerate-1.4.2.tgz",
+ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
+ "dev": true
+ },
+ "node_modules/regenerate-unicode-properties": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmmirror.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz",
+ "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==",
+ "dev": true,
+ "dependencies": {
+ "regenerate": "^1.4.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
},
+ "node_modules/regenerator-transform": {
+ "version": "0.15.2",
+ "resolved": "https://registry.npmmirror.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz",
+ "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/runtime": "^7.8.4"
+ }
+ },
+ "node_modules/regexp.prototype.flags": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
+ "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-errors": "^1.3.0",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "set-function-name": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/regexpu-core": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmmirror.com/regexpu-core/-/regexpu-core-6.2.0.tgz",
+ "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==",
+ "dev": true,
+ "dependencies": {
+ "regenerate": "^1.4.2",
+ "regenerate-unicode-properties": "^10.2.0",
+ "regjsgen": "^0.8.0",
+ "regjsparser": "^0.12.0",
+ "unicode-match-property-ecmascript": "^2.0.0",
+ "unicode-match-property-value-ecmascript": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/regjsgen": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmmirror.com/regjsgen/-/regjsgen-0.8.0.tgz",
+ "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==",
+ "dev": true
+ },
+ "node_modules/regjsparser": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmmirror.com/regjsparser/-/regjsparser-0.12.0.tgz",
+ "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==",
+ "dev": true,
+ "dependencies": {
+ "jsesc": "~3.0.2"
+ },
+ "bin": {
+ "regjsparser": "bin/parser"
+ }
+ },
+ "node_modules/regjsparser/node_modules/jsesc": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.0.2.tgz",
+ "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/relateurl": {
"version": "0.2.7",
"resolved": "https://registry.npmmirror.com/relateurl/-/relateurl-0.2.7.tgz",
@@ -7099,6 +9494,21 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/rollup": {
+ "version": "2.79.2",
+ "resolved": "https://registry.npmmirror.com/rollup/-/rollup-2.79.2.tgz",
+ "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
+ "dev": true,
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz",
@@ -7122,6 +9532,31 @@
"queue-microtask": "^1.2.2"
}
},
+ "node_modules/safe-array-concat": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmmirror.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
+ "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.2",
+ "get-intrinsic": "^1.2.6",
+ "has-symbols": "^1.1.0",
+ "isarray": "^2.0.5"
+ },
+ "engines": {
+ "node": ">=0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-array-concat/node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true
+ },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -7141,6 +9576,45 @@
}
]
},
+ "node_modules/safe-push-apply": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmmirror.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
+ "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
+ "dev": true,
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "isarray": "^2.0.5"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-push-apply/node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true
+ },
+ "node_modules/safe-regex-test": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
+ "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "is-regex": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -7435,6 +9909,52 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dev": true,
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-function-name": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.2.tgz",
+ "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+ "dev": true,
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "functions-have-names": "^1.2.3",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-proto": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmmirror.com/set-proto/-/set-proto-1.0.0.tgz",
+ "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
+ "dev": true,
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -7594,6 +10114,12 @@
"node": ">=8"
}
},
+ "node_modules/smob": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmmirror.com/smob/-/smob-1.5.0.tgz",
+ "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
+ "dev": true
+ },
"node_modules/sockjs": {
"version": "0.3.24",
"resolved": "https://registry.npmmirror.com/sockjs/-/sockjs-0.3.24.tgz",
@@ -7614,6 +10140,12 @@
"uuid": "dist/bin/uuid"
}
},
+ "node_modules/source-list-map": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmmirror.com/source-list-map/-/source-list-map-2.0.1.tgz",
+ "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==",
+ "dev": true
+ },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
@@ -7640,6 +10172,13 @@
"source-map": "^0.6.0"
}
},
+ "node_modules/sourcemap-codec": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+ "deprecated": "Please use @jridgewell/sourcemap-codec instead",
+ "dev": true
+ },
"node_modules/spdx-correct": {
"version": "3.2.0",
"resolved": "https://registry.npmmirror.com/spdx-correct/-/spdx-correct-3.2.0.tgz",
@@ -7783,6 +10322,103 @@
"node": ">=8"
}
},
+ "node_modules/string.prototype.matchall": {
+ "version": "4.0.12",
+ "resolved": "https://registry.npmmirror.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz",
+ "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.6",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.6",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "internal-slot": "^1.1.0",
+ "regexp.prototype.flags": "^1.5.3",
+ "set-function-name": "^2.0.2",
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trim": {
+ "version": "1.2.10",
+ "resolved": "https://registry.npmmirror.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
+ "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.2",
+ "define-data-property": "^1.1.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-object-atoms": "^1.0.0",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimend": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
+ "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.2",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimstart": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+ "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/stringify-object": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmmirror.com/stringify-object/-/stringify-object-3.3.0.tgz",
+ "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==",
+ "dev": true,
+ "dependencies": {
+ "get-own-enumerable-property-symbols": "^3.0.0",
+ "is-obj": "^1.0.1",
+ "is-regexp": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz",
@@ -7795,6 +10431,15 @@
"node": ">=8"
}
},
+ "node_modules/strip-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmmirror.com/strip-comments/-/strip-comments-2.0.1.tgz",
+ "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/strip-eof": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/strip-eof/-/strip-eof-1.0.0.tgz",
@@ -7892,6 +10537,57 @@
"node": ">=6"
}
},
+ "node_modules/temp-dir": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/temp-dir/-/temp-dir-2.0.0.tgz",
+ "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tempy": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmmirror.com/tempy/-/tempy-0.6.0.tgz",
+ "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==",
+ "dev": true,
+ "dependencies": {
+ "is-stream": "^2.0.0",
+ "temp-dir": "^2.0.0",
+ "type-fest": "^0.16.0",
+ "unique-string": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/tempy/node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/tempy/node_modules/type-fest": {
+ "version": "0.16.0",
+ "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.16.0.tgz",
+ "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/terser": {
"version": "5.39.0",
"resolved": "https://registry.npmmirror.com/terser/-/terser-5.39.0.tgz",
@@ -8132,12 +10828,156 @@
"node": ">= 0.6"
}
},
+ "node_modules/typed-array-buffer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmmirror.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
+ "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-typed-array": "^1.1.14"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/typed-array-byte-length": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmmirror.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
+ "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "for-each": "^0.3.3",
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.14"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-byte-offset": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmmirror.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
+ "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
+ "dev": true,
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "for-each": "^0.3.3",
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.15",
+ "reflect.getprototypeof": "^1.0.9"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-length": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmmirror.com/typed-array-length/-/typed-array-length-1.0.7.tgz",
+ "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "is-typed-array": "^1.1.13",
+ "possible-typed-array-names": "^1.0.0",
+ "reflect.getprototypeof": "^1.0.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/unbox-primitive": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
+ "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-bigints": "^1.0.2",
+ "has-symbols": "^1.1.0",
+ "which-boxed-primitive": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"dev": true
},
+ "node_modules/unicode-canonical-property-names-ecmascript": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmmirror.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz",
+ "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-match-property-ecmascript": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
+ "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
+ "dev": true,
+ "dependencies": {
+ "unicode-canonical-property-names-ecmascript": "^2.0.0",
+ "unicode-property-aliases-ecmascript": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-match-property-value-ecmascript": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmmirror.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz",
+ "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-property-aliases-ecmascript": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmmirror.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
+ "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unique-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/unique-string/-/unique-string-2.0.0.tgz",
+ "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==",
+ "dev": true,
+ "dependencies": {
+ "crypto-random-string": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz",
@@ -8156,6 +10996,16 @@
"node": ">= 0.8"
}
},
+ "node_modules/upath": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmmirror.com/upath/-/upath-1.2.0.tgz",
+ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+ "dev": true,
+ "engines": {
+ "node": ">=4",
+ "yarn": "*"
+ }
+ },
"node_modules/update-browserslist-db": {
"version": "1.1.3",
"resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
@@ -8741,12 +11591,400 @@
"node": ">= 8"
}
},
+ "node_modules/which-boxed-primitive": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
+ "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
+ "dev": true,
+ "dependencies": {
+ "is-bigint": "^1.1.0",
+ "is-boolean-object": "^1.2.1",
+ "is-number-object": "^1.1.1",
+ "is-string": "^1.1.1",
+ "is-symbol": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-builtin-type": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmmirror.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
+ "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
+ "dev": true,
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "function.prototype.name": "^1.1.6",
+ "has-tostringtag": "^1.0.2",
+ "is-async-function": "^2.0.0",
+ "is-date-object": "^1.1.0",
+ "is-finalizationregistry": "^1.1.0",
+ "is-generator-function": "^1.0.10",
+ "is-regex": "^1.2.1",
+ "is-weakref": "^1.0.2",
+ "isarray": "^2.0.5",
+ "which-boxed-primitive": "^1.1.0",
+ "which-collection": "^1.0.2",
+ "which-typed-array": "^1.1.16"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-builtin-type/node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true
+ },
+ "node_modules/which-collection": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmmirror.com/which-collection/-/which-collection-1.0.2.tgz",
+ "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+ "dev": true,
+ "dependencies": {
+ "is-map": "^2.0.3",
+ "is-set": "^2.0.3",
+ "is-weakmap": "^2.0.2",
+ "is-weakset": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-typed-array": {
+ "version": "1.1.19",
+ "resolved": "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.19.tgz",
+ "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
+ "dev": true,
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "for-each": "^0.3.5",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/wildcard": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-2.0.1.tgz",
"integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==",
"dev": true
},
+ "node_modules/workbox-background-sync": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-background-sync/-/workbox-background-sync-7.3.0.tgz",
+ "integrity": "sha512-PCSk3eK7Mxeuyatb22pcSx9dlgWNv3+M8PqPaYDokks8Y5/FX4soaOqj3yhAZr5k6Q5JWTOMYgaJBpbw11G9Eg==",
+ "dev": true,
+ "dependencies": {
+ "idb": "^7.0.1",
+ "workbox-core": "7.3.0"
+ }
+ },
+ "node_modules/workbox-broadcast-update": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-broadcast-update/-/workbox-broadcast-update-7.3.0.tgz",
+ "integrity": "sha512-T9/F5VEdJVhwmrIAE+E/kq5at2OY6+OXXgOWQevnubal6sO92Gjo24v6dCVwQiclAF5NS3hlmsifRrpQzZCdUA==",
+ "dev": true,
+ "dependencies": {
+ "workbox-core": "7.3.0"
+ }
+ },
+ "node_modules/workbox-build": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-build/-/workbox-build-7.3.0.tgz",
+ "integrity": "sha512-JGL6vZTPlxnlqZRhR/K/msqg3wKP+m0wfEUVosK7gsYzSgeIxvZLi1ViJJzVL7CEeI8r7rGFV973RiEqkP3lWQ==",
+ "dev": true,
+ "dependencies": {
+ "@apideck/better-ajv-errors": "^0.3.1",
+ "@babel/core": "^7.24.4",
+ "@babel/preset-env": "^7.11.0",
+ "@babel/runtime": "^7.11.2",
+ "@rollup/plugin-babel": "^5.2.0",
+ "@rollup/plugin-node-resolve": "^15.2.3",
+ "@rollup/plugin-replace": "^2.4.1",
+ "@rollup/plugin-terser": "^0.4.3",
+ "@surma/rollup-plugin-off-main-thread": "^2.2.3",
+ "ajv": "^8.6.0",
+ "common-tags": "^1.8.0",
+ "fast-json-stable-stringify": "^2.1.0",
+ "fs-extra": "^9.0.1",
+ "glob": "^7.1.6",
+ "lodash": "^4.17.20",
+ "pretty-bytes": "^5.3.0",
+ "rollup": "^2.43.1",
+ "source-map": "^0.8.0-beta.0",
+ "stringify-object": "^3.3.0",
+ "strip-comments": "^2.0.1",
+ "tempy": "^0.6.0",
+ "upath": "^1.2.0",
+ "workbox-background-sync": "7.3.0",
+ "workbox-broadcast-update": "7.3.0",
+ "workbox-cacheable-response": "7.3.0",
+ "workbox-core": "7.3.0",
+ "workbox-expiration": "7.3.0",
+ "workbox-google-analytics": "7.3.0",
+ "workbox-navigation-preload": "7.3.0",
+ "workbox-precaching": "7.3.0",
+ "workbox-range-requests": "7.3.0",
+ "workbox-recipes": "7.3.0",
+ "workbox-routing": "7.3.0",
+ "workbox-strategies": "7.3.0",
+ "workbox-streams": "7.3.0",
+ "workbox-sw": "7.3.0",
+ "workbox-window": "7.3.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/workbox-build/node_modules/@apideck/better-ajv-errors": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmmirror.com/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz",
+ "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==",
+ "dev": true,
+ "dependencies": {
+ "json-schema": "^0.4.0",
+ "jsonpointer": "^5.0.0",
+ "leven": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "ajv": ">=8"
+ }
+ },
+ "node_modules/workbox-build/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/workbox-build/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
+ "node_modules/workbox-build/node_modules/source-map": {
+ "version": "0.8.0-beta.0",
+ "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.8.0-beta.0.tgz",
+ "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==",
+ "dev": true,
+ "dependencies": {
+ "whatwg-url": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/workbox-build/node_modules/tr46": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/tr46/-/tr46-1.0.1.tgz",
+ "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/workbox-build/node_modules/webidl-conversions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
+ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
+ "dev": true
+ },
+ "node_modules/workbox-build/node_modules/whatwg-url": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-7.1.0.tgz",
+ "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
+ "dev": true,
+ "dependencies": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^1.0.1",
+ "webidl-conversions": "^4.0.2"
+ }
+ },
+ "node_modules/workbox-cacheable-response": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-cacheable-response/-/workbox-cacheable-response-7.3.0.tgz",
+ "integrity": "sha512-eAFERIg6J2LuyELhLlmeRcJFa5e16Mj8kL2yCDbhWE+HUun9skRQrGIFVUagqWj4DMaaPSMWfAolM7XZZxNmxA==",
+ "dev": true,
+ "dependencies": {
+ "workbox-core": "7.3.0"
+ }
+ },
+ "node_modules/workbox-core": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-core/-/workbox-core-7.3.0.tgz",
+ "integrity": "sha512-Z+mYrErfh4t3zi7NVTvOuACB0A/jA3bgxUN3PwtAVHvfEsZxV9Iju580VEETug3zYJRc0Dmii/aixI/Uxj8fmw==",
+ "dev": true
+ },
+ "node_modules/workbox-expiration": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-expiration/-/workbox-expiration-7.3.0.tgz",
+ "integrity": "sha512-lpnSSLp2BM+K6bgFCWc5bS1LR5pAwDWbcKt1iL87/eTSJRdLdAwGQznZE+1czLgn/X05YChsrEegTNxjM067vQ==",
+ "dev": true,
+ "dependencies": {
+ "idb": "^7.0.1",
+ "workbox-core": "7.3.0"
+ }
+ },
+ "node_modules/workbox-google-analytics": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-google-analytics/-/workbox-google-analytics-7.3.0.tgz",
+ "integrity": "sha512-ii/tSfFdhjLHZ2BrYgFNTrb/yk04pw2hasgbM70jpZfLk0vdJAXgaiMAWsoE+wfJDNWoZmBYY0hMVI0v5wWDbg==",
+ "dev": true,
+ "dependencies": {
+ "workbox-background-sync": "7.3.0",
+ "workbox-core": "7.3.0",
+ "workbox-routing": "7.3.0",
+ "workbox-strategies": "7.3.0"
+ }
+ },
+ "node_modules/workbox-navigation-preload": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-navigation-preload/-/workbox-navigation-preload-7.3.0.tgz",
+ "integrity": "sha512-fTJzogmFaTv4bShZ6aA7Bfj4Cewaq5rp30qcxl2iYM45YD79rKIhvzNHiFj1P+u5ZZldroqhASXwwoyusnr2cg==",
+ "dev": true,
+ "dependencies": {
+ "workbox-core": "7.3.0"
+ }
+ },
+ "node_modules/workbox-precaching": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-precaching/-/workbox-precaching-7.3.0.tgz",
+ "integrity": "sha512-ckp/3t0msgXclVAYaNndAGeAoWQUv7Rwc4fdhWL69CCAb2UHo3Cef0KIUctqfQj1p8h6aGyz3w8Cy3Ihq9OmIw==",
+ "dev": true,
+ "dependencies": {
+ "workbox-core": "7.3.0",
+ "workbox-routing": "7.3.0",
+ "workbox-strategies": "7.3.0"
+ }
+ },
+ "node_modules/workbox-range-requests": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-range-requests/-/workbox-range-requests-7.3.0.tgz",
+ "integrity": "sha512-EyFmM1KpDzzAouNF3+EWa15yDEenwxoeXu9bgxOEYnFfCxns7eAxA9WSSaVd8kujFFt3eIbShNqa4hLQNFvmVQ==",
+ "dev": true,
+ "dependencies": {
+ "workbox-core": "7.3.0"
+ }
+ },
+ "node_modules/workbox-recipes": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-recipes/-/workbox-recipes-7.3.0.tgz",
+ "integrity": "sha512-BJro/MpuW35I/zjZQBcoxsctgeB+kyb2JAP5EB3EYzePg8wDGoQuUdyYQS+CheTb+GhqJeWmVs3QxLI8EBP1sg==",
+ "dev": true,
+ "dependencies": {
+ "workbox-cacheable-response": "7.3.0",
+ "workbox-core": "7.3.0",
+ "workbox-expiration": "7.3.0",
+ "workbox-precaching": "7.3.0",
+ "workbox-routing": "7.3.0",
+ "workbox-strategies": "7.3.0"
+ }
+ },
+ "node_modules/workbox-routing": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-routing/-/workbox-routing-7.3.0.tgz",
+ "integrity": "sha512-ZUlysUVn5ZUzMOmQN3bqu+gK98vNfgX/gSTZ127izJg/pMMy4LryAthnYtjuqcjkN4HEAx1mdgxNiKJMZQM76A==",
+ "dev": true,
+ "dependencies": {
+ "workbox-core": "7.3.0"
+ }
+ },
+ "node_modules/workbox-strategies": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-strategies/-/workbox-strategies-7.3.0.tgz",
+ "integrity": "sha512-tmZydug+qzDFATwX7QiEL5Hdf7FrkhjaF9db1CbB39sDmEZJg3l9ayDvPxy8Y18C3Y66Nrr9kkN1f/RlkDgllg==",
+ "dev": true,
+ "dependencies": {
+ "workbox-core": "7.3.0"
+ }
+ },
+ "node_modules/workbox-streams": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-streams/-/workbox-streams-7.3.0.tgz",
+ "integrity": "sha512-SZnXucyg8x2Y61VGtDjKPO5EgPUG5NDn/v86WYHX+9ZqvAsGOytP0Jxp1bl663YUuMoXSAtsGLL+byHzEuMRpw==",
+ "dev": true,
+ "dependencies": {
+ "workbox-core": "7.3.0",
+ "workbox-routing": "7.3.0"
+ }
+ },
+ "node_modules/workbox-sw": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-sw/-/workbox-sw-7.3.0.tgz",
+ "integrity": "sha512-aCUyoAZU9IZtH05mn0ACUpyHzPs0lMeJimAYkQkBsOWiqaJLgusfDCR+yllkPkFRxWpZKF8vSvgHYeG7LwhlmA==",
+ "dev": true
+ },
+ "node_modules/workbox-webpack-plugin": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-webpack-plugin/-/workbox-webpack-plugin-7.3.0.tgz",
+ "integrity": "sha512-EC8lmSAuNmPli04+a5r5lTgv8ab+f5l+XjdYuYpbGnxDT15kH6DBeBazVslpffqTDHt+wkdBMnBCu8GdkKrTSA==",
+ "dev": true,
+ "dependencies": {
+ "fast-json-stable-stringify": "^2.1.0",
+ "pretty-bytes": "^5.4.1",
+ "upath": "^1.2.0",
+ "webpack-sources": "^1.4.3",
+ "workbox-build": "7.3.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ },
+ "peerDependencies": {
+ "webpack": "^4.4.0 || ^5.91.0"
+ }
+ },
+ "node_modules/workbox-webpack-plugin/node_modules/webpack-sources": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmmirror.com/webpack-sources/-/webpack-sources-1.4.3.tgz",
+ "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
+ "dev": true,
+ "dependencies": {
+ "source-list-map": "^2.0.0",
+ "source-map": "~0.6.1"
+ }
+ },
+ "node_modules/workbox-window": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmmirror.com/workbox-window/-/workbox-window-7.3.0.tgz",
+ "integrity": "sha512-qW8PDy16OV1UBaUNGlTVcepzrlzyzNW/ZJvFQQs2j2TzGsg6IKjcpZC1RSquqQnTOafl5pCj5bGfAHlCjOOjdA==",
+ "dev": true,
+ "dependencies": {
+ "@types/trusted-types": "^2.0.2",
+ "workbox-core": "7.3.0"
+ }
+ },
"node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
diff --git a/main/manager-web/package.json b/main/manager-web/package.json
index 5a6e7de2..a308147b 100644
--- a/main/manager-web/package.json
+++ b/main/manager-web/package.json
@@ -31,7 +31,8 @@
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"vue-template-compiler": "^2.6.14",
- "webpack-bundle-analyzer": "^4.10.2"
+ "webpack-bundle-analyzer": "^4.10.2",
+ "workbox-webpack-plugin": "^7.3.0"
},
"browserslist": [
"> 1%",
diff --git a/main/manager-web/public/index.html b/main/manager-web/public/index.html
index 23f19907..e3ae5a53 100644
--- a/main/manager-web/public/index.html
+++ b/main/manager-web/public/index.html
@@ -9,7 +9,7 @@
<%= process.env.VUE_APP_TITLE %>
- <% if (htmlWebpackPlugin.options.cdn) { %>
+ <% if (htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
<% for (var i in htmlWebpackPlugin.options.cdn.css) { %>
<% } %>
@@ -23,7 +23,7 @@
- <% if (htmlWebpackPlugin.options.cdn) { %>
+ <% if (htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
<% for (var i in htmlWebpackPlugin.options.cdn.js) { %>
<% } %>
diff --git a/main/manager-web/public/offline.html b/main/manager-web/public/offline.html
new file mode 100644
index 00000000..b454b600
--- /dev/null
+++ b/main/manager-web/public/offline.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+ 离线模式 - 小智控制台
+
+
+
+
+
📶
+
您当前处于离线模式
+
看起来您的网络连接有问题,无法连接到小智控制台服务器。
+
部分已缓存的内容和静态资源可能仍然可用,但功能可能受到限制。
+
重新尝试连接
+
+
+
+
+
\ No newline at end of file
diff --git a/main/manager-web/src/App.vue b/main/manager-web/src/App.vue
index 85e03471..0eefc0bc 100644
--- a/main/manager-web/src/App.vue
+++ b/main/manager-web/src/App.vue
@@ -1,11 +1,11 @@
-
+
+
\ No newline at end of file
diff --git a/main/manager-web/src/apis/api.js b/main/manager-web/src/apis/api.js
index a2354e0e..63977008 100755
--- a/main/manager-web/src/apis/api.js
+++ b/main/manager-web/src/apis/api.js
@@ -1,22 +1,23 @@
// 引入各个模块的请求
-import user from './module/user.js'
import admin from './module/admin.js'
+import agent from './module/agent.js'
+import device from './module/device.js'
+import model from './module/model.js'
+import timbre from "./module/timbre.js"
+import user from './module/user.js'
+
/**
* 接口地址
- * 当前8002端口接口还没开发完成,暂时用 apifoxmock 接口代替
- * 如果你想调用8002端口,就用'/xiaozhi-esp32-api/api/v1',请与vue.config.js的devServer配置相结合,方便跨域请求
- *
+ * 开发时自动读取使用.env.development文件
+ * 编译时自动读取使用.env.production文件
*/
-const DEV_API_SERVICE = 'https://2662r3426b.vicp.fun/xiaozhi-esp32-api'
-// 8002开发完成完成后使用这个
-// const DEV_API_SERVICE = '/xiaozhi-esp32-api'
+const DEV_API_SERVICE = process.env.VUE_APP_API_BASE_URL
/**
* 根据开发环境返回接口url
* @returns {string}
*/
export function getServiceUrl() {
- // return '/xiaozhi-esp32-api'
return DEV_API_SERVICE
}
@@ -25,4 +26,9 @@ export function getServiceUrl() {
export default {
getServiceUrl,
user,
+ admin,
+ agent,
+ device,
+ model,
+ timbre,
}
diff --git a/main/manager-web/src/apis/httpRequest.js b/main/manager-web/src/apis/httpRequest.js
index 4d8093d3..43cdf92d 100755
--- a/main/manager-web/src/apis/httpRequest.js
+++ b/main/manager-web/src/apis/httpRequest.js
@@ -1,7 +1,7 @@
-import {goToPage, showDanger, showWarning, isNotNull} from '../utils/index'
-import Constant from '../utils/constant'
import Fly from 'flyio/dist/npm/fly';
-import store from '../store/index'
+import store from '../store/index';
+import Constant from '../utils/constant';
+import { goToPage, isNotNull, showDanger, showWarning } from '../utils/index';
const fly = new Fly()
// 设置超时
@@ -22,11 +22,11 @@ function sendRequest() {
_failCallback: null,
_method: 'GET',
_data: {},
- _header: {'content-type': 'application/json; charset=utf-8'},
+ _header: { 'content-type': 'application/json; charset=utf-8' },
_url: '',
_responseType: undefined, // 新增响应类型字段
'send'() {
- if(isNotNull(store.getters.getToken)){
+ if (isNotNull(store.getters.getToken)) {
this._header.Authorization = 'Bearer ' + (JSON.parse(store.getters.getToken)).token
}
@@ -40,7 +40,7 @@ function sendRequest() {
if (error) {
return
}
-
+
if (this._sucCallback) {
this._sucCallback(res)
}
@@ -100,17 +100,15 @@ function sendRequest() {
*/
// 在错误处理函数中添加日志
function httpHandlerError(info, callBack) {
- console.log('httpHandlerError', info)
-
+
/** 请求成功,退出该函数 可以根据项目需求来判断是否请求成功。这里判断的是status为200的时候是成功 */
let networkError = false
if (info.status === 200) {
if (info.data.code === 'success' || info.data.code === 0 || info.data.code === undefined) {
return networkError
- }else if (info.data.code === 401) {
- console.log('触发 401,清除 Token 并跳转登录页');
+ } else if (info.data.code === 401) {
store.commit('clearAuth');
- window.location.href = '/login';
+ goToPage(Constant.PAGE.LOGIN, true);
return true
} else {
showDanger(info.data.msg)
@@ -139,7 +137,7 @@ function reAjaxFun(fn) {
} else {
showWarning('正在连接服务器(' + ajaxIndex + ')')
}
- if (fn) {
+ if (ajaxIndex < 10 && fn) {
setTimeout(() => {
fn()
}, reAjaxSec * 1000)
diff --git a/main/manager-web/src/apis/module/admin.js b/main/manager-web/src/apis/module/admin.js
index 83da3023..fecc5877 100644
--- a/main/manager-web/src/apis/module/admin.js
+++ b/main/manager-web/src/apis/module/admin.js
@@ -1,34 +1,34 @@
-import RequestService from '../httpRequest'
-import {getServiceUrl} from '../api'
+import { getServiceUrl } from '../api';
+import RequestService from '../httpRequest';
export default {
// 用户列表
getUserList(params, callback) {
- const queryParams = new URLSearchParams({
- page: params.page,
- limit: params.limit,
- mobile: params.mobile
- }).toString();
+ const queryParams = new URLSearchParams({
+ page: params.page,
+ limit: params.limit,
+ mobile: params.mobile
+ }).toString();
- RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/admin/users?${queryParams}`)
- .method('GET')
- .success((res) => {
- RequestService.clearRequestTime()
- callback(res)
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/admin/users?${queryParams}`)
+ .method('GET')
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res)
+ })
+ .fail((err) => {
+ console.error('请求失败:', err)
+ RequestService.reAjaxFun(() => {
+ this.getUserList(callback)
})
- .fail((err) => {
- console.error('请求失败:', err)
- RequestService.reAjaxFun(() => {
- this.getUserList(callback)
- })
- }).send()
- },
+ }).send()
+ },
// 删除用户
deleteUser(id, callback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/admin/users/${id}`)
+ .url(`${getServiceUrl()}/admin/users/${id}`)
.method('DELETE')
.success((res) => {
RequestService.clearRequestTime()
@@ -44,7 +44,7 @@ export default {
// 重置用户密码
resetUserPassword(id, callback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/admin/users/${id}`)
+ .url(`${getServiceUrl()}/admin/users/${id}`)
.method('PUT')
.success((res) => {
RequestService.clearRequestTime()
@@ -56,6 +56,79 @@ export default {
this.resetUserPassword(id, callback)
})
}).send()
- }
+ },
+ // 获取参数列表
+ getParamsList(params, callback) {
+ const queryParams = new URLSearchParams({
+ page: params.page,
+ limit: params.limit,
+ paramCode: params.paramCode || ''
+ }).toString();
+
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/admin/params/page?${queryParams}`)
+ .method('GET')
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res)
+ })
+ .fail((err) => {
+ console.error('获取参数列表失败:', err)
+ RequestService.reAjaxFun(() => {
+ this.getParamsList(params, callback)
+ })
+ }).send()
+ },
+ // 保存
+ addParam(data, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/admin/params`)
+ .method('POST')
+ .data(data)
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res)
+ })
+ .fail((err) => {
+ console.error('添加参数失败:', err)
+ RequestService.reAjaxFun(() => {
+ this.addParam(data, callback)
+ })
+ }).send()
+ },
+ // 修改
+ updateParam(data, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/admin/params`)
+ .method('PUT')
+ .data(data)
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res)
+ })
+ .fail((err) => {
+ console.error('更新参数失败:', err)
+ RequestService.reAjaxFun(() => {
+ this.updateParam(data, callback)
+ })
+ }).send()
+ },
+ // 删除
+ deleteParam(ids, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/admin/params/delete`)
+ .method('POST')
+ .data(ids)
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res);
+ })
+ .fail((err) => {
+ console.error('删除参数失败:', err)
+ RequestService.reAjaxFun(() => {
+ this.deleteParam(ids, callback)
+ })
+ }).send()
+ },
}
diff --git a/main/manager-web/src/apis/module/agent.js b/main/manager-web/src/apis/module/agent.js
index 034cbf8a..87323f9c 100644
--- a/main/manager-web/src/apis/module/agent.js
+++ b/main/manager-web/src/apis/module/agent.js
@@ -1,12 +1,12 @@
-import RequestService from '../httpRequest'
-import {getServiceUrl} from '../api'
+import { getServiceUrl } from '../api';
+import RequestService from '../httpRequest';
export default {
// 获取智能体列表
getAgentList(callback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/agent/list`)
+ .url(`${getServiceUrl()}/agent/list`)
.method('GET')
.success((res) => {
RequestService.clearRequestTime();
@@ -21,9 +21,9 @@ export default {
// 添加智能体
addAgent(agentName, callback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/agent`)
+ .url(`${getServiceUrl()}/agent`)
.method('POST')
- .data({agentName: agentName})
+ .data({ agentName: agentName })
.success((res) => {
RequestService.clearRequestTime();
callback(res);
@@ -37,7 +37,7 @@ export default {
// 删除智能体
deleteAgent(agentId, callback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/agent/${agentId}`)
+ .url(`${getServiceUrl()}/agent/${agentId}`)
.method('DELETE')
.success((res) => {
RequestService.clearRequestTime();
@@ -52,7 +52,7 @@ export default {
// 获取智能体配置
getDeviceConfig(deviceId, callback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/agent/${deviceId}`)
+ .url(`${getServiceUrl()}/agent/${deviceId}`)
.method('GET')
.success((res) => {
RequestService.clearRequestTime();
@@ -68,7 +68,7 @@ export default {
// 配置智能体
updateAgentConfig(agentId, configData, callback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/agent/${agentId}`)
+ .url(`${getServiceUrl()}/agent/${agentId}`)
.method('PUT')
.data(configData)
.success((res) => {
@@ -84,7 +84,7 @@ export default {
// 新增方法:获取智能体模板
getAgentTemplate(callback) { // 移除templateName参数
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/agent/template`)
+ .url(`${getServiceUrl()}/agent/template`)
.method('GET')
.success((res) => {
RequestService.clearRequestTime();
diff --git a/main/manager-web/src/apis/module/device.js b/main/manager-web/src/apis/module/device.js
index e8dc2c71..a62db3b0 100644
--- a/main/manager-web/src/apis/module/device.js
+++ b/main/manager-web/src/apis/module/device.js
@@ -1,44 +1,44 @@
-import RequestService from '../httpRequest'
-import {getServiceUrl} from '../api'
+import { getServiceUrl } from '../api';
+import RequestService from '../httpRequest';
export default {
// 已绑设备
- getAgentBindDevices(agentId, callback) {
- RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/device/bind/${agentId}`)
- .method('GET')
- .success((res) => {
- RequestService.clearRequestTime();
- callback(res);
- })
- .fail((err) => {
- console.error('获取设备列表失败:', err);
- RequestService.reAjaxFun(() => {
- this.getAgentBindDevices(agentId, callback);
- });
- }).send();
- },
+ getAgentBindDevices(agentId, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/device/bind/${agentId}`)
+ .method('GET')
+ .success((res) => {
+ RequestService.clearRequestTime();
+ callback(res);
+ })
+ .fail((err) => {
+ console.error('获取设备列表失败:', err);
+ RequestService.reAjaxFun(() => {
+ this.getAgentBindDevices(agentId, callback);
+ });
+ }).send();
+ },
// 解绑设备
unbindDevice(device_id, callback) {
- RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/device/unbind`)
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/device/unbind`)
.method('POST')
.data({ deviceId: device_id })
.success((res) => {
- RequestService.clearRequestTime();
- callback(res);
+ RequestService.clearRequestTime();
+ callback(res);
})
.fail((err) => {
- console.error('解绑设备失败:', err);
- RequestService.reAjaxFun(() => {
- this.unbindDevice(device_id, callback);
- });
+ console.error('解绑设备失败:', err);
+ RequestService.reAjaxFun(() => {
+ this.unbindDevice(device_id, callback);
+ });
}).send();
},
// 绑定设备
bindDevice(agentId, deviceCode, callback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/device/bind/${agentId}/${deviceCode}`)
+ .url(`${getServiceUrl()}/device/bind/${agentId}/${deviceCode}`)
.method('POST')
.success((res) => {
RequestService.clearRequestTime();
diff --git a/main/manager-web/src/apis/module/model.js b/main/manager-web/src/apis/module/model.js
index 2534bb5a..ec0ea32f 100644
--- a/main/manager-web/src/apis/module/model.js
+++ b/main/manager-web/src/apis/module/model.js
@@ -1,30 +1,201 @@
-import RequestService from '../httpRequest'
-import {getServiceUrl} from '../api'
-
+import { getServiceUrl } from '../api';
+import RequestService from '../httpRequest';
export default {
- // 获取模型配置列表
- getModelList(params, callback) {
- const queryParams = new URLSearchParams({
- modelType: params.modelType,
- modelName: params.modelName || '',
- page: params.page || 0,
- limit: params.limit || 10
- }).toString();
+ // 获取模型配置列表
+ getModelList(params, callback) {
+ const queryParams = new URLSearchParams({
+ modelType: params.modelType,
+ modelName: params.modelName || '',
+ page: params.page || 0,
+ limit: params.limit || 10
+ }).toString();
- RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/models/models/list?${queryParams}`)
- .method('GET')
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/models/list?${queryParams}`)
+ .method('GET')
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res)
+ })
+ .fail((err) => {
+ console.error('获取模型列表失败:', err)
+ RequestService.reAjaxFun(() => {
+ this.getModelList(params, callback)
+ })
+ }).send()
+ },
+ // 获取模型供应器列表
+ getModelProviders(modelType, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/models/${modelType}/provideTypes`)
+ .method('GET')
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res.data?.data || [])
+ })
+ .fail((err) => {
+ console.error('获取供应器列表失败:', err)
+ this.$message.error('获取供应器列表失败')
+ RequestService.reAjaxFun(() => {
+ this.getModelProviders(modelType, callback)
+ })
+ }).send()
+ },
+
+ // 新增模型配置
+ addModel(params, callback) {
+ const { modelType, provideCode, formData } = params;
+ const postData = {
+ modelCode: formData.modelCode,
+ modelName: formData.modelName,
+ isDefault: formData.isDefault ? 1 : 0,
+ isEnabled: formData.isEnabled ? 1 : 0,
+ configJson: formData.configJson,
+ docLink: formData.docLink,
+ remark: formData.remark,
+ sort: formData.sort || 0
+ };
+
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/models/${modelType}/${provideCode}`)
+ .method('POST')
+ .data(postData)
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res)
+ })
+ .fail((err) => {
+ console.error('新增模型失败:', err)
+ this.$message.error(err.msg || '新增模型失败')
+ RequestService.reAjaxFun(() => {
+ this.addModel(params, callback)
+ })
+ }).send()
+ },
+ // 删除模型配置
+ deleteModel(id, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/models/${id}`)
+ .method('DELETE')
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res)
+ })
+ .fail((err) => {
+ console.error('删除模型失败:', err)
+ this.$message.error(err.msg || '删除模型失败')
+ RequestService.reAjaxFun(() => {
+ this.deleteModel(id, callback)
+ })
+ }).send()
+ },
+ // 获取模型名称列表
+ getModelNames(modelType, modelName, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/models/names`)
+ .method('GET')
+ .data({ modelType, modelName })
+ .success((res) => {
+ RequestService.clearRequestTime();
+ callback(res);
+ })
+ .fail(() => {
+ RequestService.reAjaxFun(() => {
+ this.getModelNames(modelType, modelName, callback);
+ });
+ }).send();
+ },
+ // 获取模型音色列表
+ getModelVoices(modelId, voiceName, callback) {
+ const queryParams = new URLSearchParams({
+ voiceName: voiceName || ''
+ }).toString();
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/models/${modelId}/voices?${queryParams}`)
+ .method('GET')
+ .success((res) => {
+ RequestService.clearRequestTime();
+ callback(res);
+ })
+ .fail(() => {
+ RequestService.reAjaxFun(() => {
+ this.getModelVoices(modelId, voiceName, callback);
+ });
+ }).send();
+ },
+ // 获取单个模型配置
+ getModelConfig(id, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/models/${id}`)
+ .method('GET')
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res)
+ })
+ .fail((err) => {
+ console.error('获取模型配置失败:', err)
+ this.$message.error(err.msg || '获取模型配置失败')
+ RequestService.reAjaxFun(() => {
+ this.getModelConfig(id, callback)
+ })
+ }).send()
+ },
+ // 启用/禁用模型状态
+ updateModelStatus(id, status, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/models/enable/${id}/${status}`)
+ .method('PUT')
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res)
+ })
+ .fail((err) => {
+ console.error('更新模型状态失败:', err)
+ this.$message.error(err.msg || '更新模型状态失败')
+ RequestService.reAjaxFun(() => {
+ this.updateModelStatus(id, status, callback)
+ })
+ }).send()
+ },
+ // 更新模型配置
+ updateModel(params, callback) {
+ const { modelType, provideCode, id, formData } = params;
+ const payload = {
+ ...formData,
+ configJson: formData.configJson
+ };
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/models/${modelType}/${provideCode}/${id}`)
+ .method('PUT')
+ .data(payload)
.success((res) => {
- RequestService.clearRequestTime()
- callback(res)
+ RequestService.clearRequestTime();
+ callback(res);
})
.fail((err) => {
- console.error('获取模型列表失败:', err)
+ console.error('更新模型失败:', err);
+ this.$message.error(err.msg || '更新模型失败');
RequestService.reAjaxFun(() => {
- this.getModelList(params, callback)
- })
- }).send()
- },
-
+ this.updateModel(params, callback);
+ });
+ }).send();
+ },
+ // 设置默认模型
+ setDefaultModel(id, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/models/default/${id}`)
+ .method('PUT')
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res)
+ })
+ .fail((err) => {
+ console.error('设置默认模型失败:', err)
+ this.$message.error(err.msg || '设置默认模型失败')
+ RequestService.reAjaxFun(() => {
+ this.setDefaultModel(id, callback)
+ })
+ }).send()
+ }
}
diff --git a/main/manager-web/src/apis/module/timbre.js b/main/manager-web/src/apis/module/timbre.js
new file mode 100644
index 00000000..91920522
--- /dev/null
+++ b/main/manager-web/src/apis/module/timbre.js
@@ -0,0 +1,92 @@
+import {getServiceUrl} from '../api';
+import RequestService from '../httpRequest';
+
+export default {
+ // 获取音色
+ getVoiceList(params, callback) {
+ const queryParams = new URLSearchParams({
+ ttsModelId: params.ttsModelId,
+ page: params.page || 1,
+ limit: params.limit || 10,
+ name: params.name || ''
+ }).toString();
+
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/ttsVoice?${queryParams}`)
+ .method('GET')
+ .success((res) => {
+ RequestService.clearRequestTime();
+ callback(res.data || []);
+ })
+ .fail((err) => {
+ console.error('获取音色列表失败:', err);
+ RequestService.reAjaxFun(() => {
+ this.getVoiceList(params, callback);
+ });
+ }).send();
+ },
+ // 音色保存
+ saveVoice(params, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/ttsVoice`)
+ .method('POST')
+ .data(JSON.stringify({
+ languages: params.languageType,
+ name: params.voiceName,
+ remark: params.remark,
+ sort: params.sort,
+ ttsModelId: params.ttsModelId,
+ ttsVoice: params.voiceCode,
+ voiceDemo: params.voiceDemo || ''
+ }))
+ .success((res) => {
+ callback(res.data);
+ })
+ .fail((err) => {
+ console.error('保存音色失败:', err);
+ RequestService.reAjaxFun(() => {
+ this.saveVoice(params, callback);
+ });
+ }).send();
+ },
+ // 音色删除
+ deleteVoice(ids, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/ttsVoice/delete`)
+ .method('POST')
+ .data(ids)
+ .success((res) => {
+ RequestService.clearRequestTime()
+ callback(res);
+ })
+ .fail((err) => {
+ console.error('删除音色失败:', err);
+ RequestService.reAjaxFun(() => {
+ this.deleteVoice(ids, callback);
+ });
+ }).send();
+ },
+ // 音色修改
+ updateVoice(params, callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/ttsVoice/${params.id}`)
+ .method('PUT')
+ .data(JSON.stringify({
+ languages: params.languageType,
+ name: params.voiceName,
+ remark: params.remark,
+ ttsModelId: params.ttsModelId,
+ ttsVoice: params.voiceCode,
+ voiceDemo: params.voiceDemo || ''
+ }))
+ .success((res) => {
+ callback(res.data);
+ })
+ .fail((err) => {
+ console.error('修改音色失败:', err);
+ RequestService.reAjaxFun(() => {
+ this.updateVoice(params, callback);
+ });
+ }).send();
+ }
+}
\ No newline at end of file
diff --git a/main/manager-web/src/apis/module/user.js b/main/manager-web/src/apis/module/user.js
index 8464794c..84d5b7f9 100755
--- a/main/manager-web/src/apis/module/user.js
+++ b/main/manager-web/src/apis/module/user.js
@@ -1,12 +1,12 @@
+import { getServiceUrl } from '../api'
import RequestService from '../httpRequest'
-import {getServiceUrl} from '../api'
export default {
// 登录
login(loginForm, callback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/user/login`)
+ .url(`${getServiceUrl()}/user/login`)
.method('POST')
.data(loginForm)
.success((res) => {
@@ -22,7 +22,7 @@ export default {
// 获取验证码
getCaptcha(uuid, callback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/user/captcha?uuid=${uuid}`)
+ .url(`${getServiceUrl()}/user/captcha?uuid=${uuid}`)
.method('GET')
.type('blob')
.header({
@@ -41,7 +41,7 @@ export default {
// 注册账号
register(registerForm, callback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/user/register`)
+ .url(`${getServiceUrl()}/user/register`)
.method('POST')
.data(registerForm)
.success((res) => {
@@ -54,7 +54,7 @@ export default {
// 保存设备配置
saveDeviceConfig(device_id, configData, callback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/user/configDevice/${device_id}`)
+ .url(`${getServiceUrl()}/user/configDevice/${device_id}`)
.method('PUT')
.data(configData)
.success((res) => {
@@ -71,7 +71,7 @@ export default {
// 用户信息获取
getUserInfo(callback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/user/info`)
+ .url(`${getServiceUrl()}/user/info`)
.method('GET')
.success((res) => {
RequestService.clearRequestTime()
@@ -87,7 +87,7 @@ export default {
// 修改用户密码
changePassword(oldPassword, newPassword, successCallback, errorCallback) {
RequestService.sendRequest()
- .url(`${getServiceUrl()}/api/v1/user/change-password`)
+ .url(`${getServiceUrl()}/user/change-password`)
.method('PUT')
.data({
password: oldPassword,
@@ -104,4 +104,38 @@ export default {
})
.send();
},
+ // 修改用户状态
+ changeUserStatus(status, userIds, successCallback) {
+ console.log(555, userIds)
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/admin/users/changeStatus/${status}`)
+ .method('put')
+ .data(userIds)
+ .success((res) => {
+ RequestService.clearRequestTime()
+ successCallback(res);
+ })
+ .fail((err) => {
+ console.error('修改用户状态失败:', err)
+ RequestService.reAjaxFun(() => {
+ this.changeUserStatus(status, userIds)
+ })
+ }).send()
+ },
+ // 获取公共配置
+ getPubConfig(callback) {
+ RequestService.sendRequest()
+ .url(`${getServiceUrl()}/user/pub-config`)
+ .method('GET')
+ .success((res) => {
+ RequestService.clearRequestTime();
+ callback(res);
+ })
+ .fail((err) => {
+ console.error('获取公共配置失败:', err);
+ RequestService.reAjaxFun(() => {
+ this.getPubConfig(callback);
+ });
+ }).send();
+ },
}
diff --git a/main/manager-web/src/assets/header/param_management.png b/main/manager-web/src/assets/header/param_management.png
new file mode 100644
index 00000000..215b12ef
Binary files /dev/null and b/main/manager-web/src/assets/header/param_management.png differ
diff --git a/main/manager-web/src/assets/home/background.png b/main/manager-web/src/assets/home/background.png
deleted file mode 100644
index f7c3d357..00000000
Binary files a/main/manager-web/src/assets/home/background.png and /dev/null differ
diff --git a/main/manager-web/src/assets/login/background.png b/main/manager-web/src/assets/login/background.png
deleted file mode 100644
index 4c9c7693..00000000
Binary files a/main/manager-web/src/assets/login/background.png and /dev/null differ
diff --git a/main/manager-web/src/assets/login/login-person.png b/main/manager-web/src/assets/login/login-person.png
new file mode 100644
index 00000000..27477f2f
Binary files /dev/null and b/main/manager-web/src/assets/login/login-person.png differ
diff --git a/main/manager-web/src/assets/login/register-person.png b/main/manager-web/src/assets/login/register-person.png
new file mode 100644
index 00000000..12e0a3e2
Binary files /dev/null and b/main/manager-web/src/assets/login/register-person.png differ
diff --git a/main/manager-web/src/assets/logo.png b/main/manager-web/src/assets/logo.png
deleted file mode 100644
index f3d2503f..00000000
Binary files a/main/manager-web/src/assets/logo.png and /dev/null differ
diff --git a/main/manager-web/src/assets/model/model.png b/main/manager-web/src/assets/model/model.png
index c7515f4e..f08ecb86 100644
Binary files a/main/manager-web/src/assets/model/model.png and b/main/manager-web/src/assets/model/model.png differ
diff --git a/main/manager-web/src/assets/welcome/background.png b/main/manager-web/src/assets/welcome/background.png
deleted file mode 100644
index d8841e1a..00000000
Binary files a/main/manager-web/src/assets/welcome/background.png and /dev/null differ
diff --git a/main/manager-web/src/assets/welcome/github.png b/main/manager-web/src/assets/welcome/github.png
deleted file mode 100644
index 0e984ec7..00000000
Binary files a/main/manager-web/src/assets/welcome/github.png and /dev/null differ
diff --git a/main/manager-web/src/assets/welcome/more.png b/main/manager-web/src/assets/welcome/more.png
deleted file mode 100644
index 5acbfa6a..00000000
Binary files a/main/manager-web/src/assets/welcome/more.png and /dev/null differ
diff --git a/main/manager-web/src/assets/welcome/questions.png b/main/manager-web/src/assets/welcome/questions.png
deleted file mode 100644
index 1fe2ab9b..00000000
Binary files a/main/manager-web/src/assets/welcome/questions.png and /dev/null differ
diff --git a/main/manager-web/src/assets/xiaozhi-ai.png b/main/manager-web/src/assets/xiaozhi-ai.png
index 008df015..ef3834af 100644
Binary files a/main/manager-web/src/assets/xiaozhi-ai.png and b/main/manager-web/src/assets/xiaozhi-ai.png differ
diff --git a/main/manager-web/src/assets/xiaozhi-logo.png b/main/manager-web/src/assets/xiaozhi-logo.png
index 33050397..9e664970 100644
Binary files a/main/manager-web/src/assets/xiaozhi-logo.png and b/main/manager-web/src/assets/xiaozhi-logo.png differ
diff --git a/main/manager-web/src/components/ActivateDeviceDialog.vue b/main/manager-web/src/components/ActivateDeviceDialog.vue
deleted file mode 100644
index 59384e79..00000000
--- a/main/manager-web/src/components/ActivateDeviceDialog.vue
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
-
- 激活设备
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/main/manager-web/src/components/AddDeviceDialog.vue b/main/manager-web/src/components/AddDeviceDialog.vue
index 11189df7..51f5426b 100644
--- a/main/manager-web/src/components/AddDeviceDialog.vue
+++ b/main/manager-web/src/components/AddDeviceDialog.vue
@@ -1,7 +1,9 @@
-
-
-
+
+
+
添加设备
@@ -13,16 +15,14 @@
验证码:
-
+
确定
-
@@ -30,6 +30,8 @@
\ No newline at end of file
diff --git a/main/manager-web/src/components/AddModelDialog.vue b/main/manager-web/src/components/AddModelDialog.vue
index 074be175..9a4a6022 100644
--- a/main/manager-web/src/components/AddModelDialog.vue
+++ b/main/manager-web/src/components/AddModelDialog.vue
@@ -1,19 +1,11 @@
-
+
添加模型
-
×
@@ -26,7 +18,7 @@
是否启用
-
+
设为默认
@@ -34,113 +26,58 @@
-
-
-
+
-
+
-
-
-
-
-
-
+
+
-
+
-
+
-
+
-
-
调用信息
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
保存
@@ -148,14 +85,20 @@
@@ -297,7 +317,7 @@ export default {
}
.custom-form .el-form-item {
- margin-bottom: 20px; /* 统一设置所有表单项的间距 */
+ margin-bottom: 20px;
}
.custom-form .el-form-item__label {
@@ -312,13 +332,12 @@ export default {
margin-top: -4px;
}
-/* 修改placeholder颜色 */
.custom-input-bg .el-input__inner::-webkit-input-placeholder,
.custom-input-bg .el-textarea__inner::-webkit-input-placeholder {
color: #9c9f9e;
}
-/* 输入框背景色 */
+
.custom-input-bg .el-input__inner,
.custom-input-bg .el-textarea__inner {
background-color: #f6f8fc;
@@ -342,13 +361,12 @@ export default {
}
-/* 修改开关样式 */
.custom-switch .el-switch__core {
border-radius: 20px;
height: 23px;
background-color: #c0ccda;
width: 35px;
- padding: 0 20px; /* 调整左右内边距 */
+ padding: 0 20px;
}
.custom-switch .el-switch__core:after {
@@ -363,7 +381,7 @@ export default {
.custom-switch.is-checked .el-switch__core {
border-color: #b5bcf0;
background-color: #cfd7fa;
- padding: 0 20px; /* 确保启用状态也有相同的间隔 */
+ padding: 0 20px;
}
.custom-switch.is-checked .el-switch__core:after {
@@ -373,15 +391,11 @@ export default {
}
-/* 调整flex布局的gap */
[style*="display: flex"] {
- gap: 20px; /* 扩大flex项间距 */
+ gap: 20px;
}
-/* 调整输入框高度 */
.custom-input-bg .el-input__inner {
- height: 32px; /* 固定输入框高度 */
+ height: 32px;
}
-
-
\ No newline at end of file
diff --git a/main/manager-web/src/components/AddWisdomBodyDialog.vue b/main/manager-web/src/components/AddWisdomBodyDialog.vue
index 042cdbce..66c7a627 100644
--- a/main/manager-web/src/components/AddWisdomBodyDialog.vue
+++ b/main/manager-web/src/components/AddWisdomBodyDialog.vue
@@ -1,7 +1,9 @@
-
-
-
+
+
+
添加智能体
@@ -12,16 +14,14 @@
*
智慧体名称:
-
+
确定
-
@@ -29,8 +29,7 @@
\ No newline at end of file
diff --git a/main/manager-web/src/components/AudioPlayer.vue b/main/manager-web/src/components/AudioPlayer.vue
new file mode 100644
index 00000000..2e066614
--- /dev/null
+++ b/main/manager-web/src/components/AudioPlayer.vue
@@ -0,0 +1,379 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ formattedCurrentTime }}/{{ formattedDuration }}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/manager-web/src/components/CacheViewer.vue b/main/manager-web/src/components/CacheViewer.vue
new file mode 100644
index 00000000..66d4da7d
--- /dev/null
+++ b/main/manager-web/src/components/CacheViewer.vue
@@ -0,0 +1,207 @@
+
+
+
+
+
+
+
+
您的浏览器不支持Cache API或Service Worker未安装
+
刷新页面
+
+
+
+
+ Service Worker可能尚未完成初始化或缓存尚未建立。请刷新页面或等待一会后再试。
+
+
+
+
+ 共发现 {{ cacheData.totalCached }} 个缓存资源
+
+
+
JavaScript 资源 ({{ cacheData.js.length }})
+
+
+
+
+ 已缓存
+ 未缓存
+
+
+
+
+ CSS 资源 ({{ cacheData.css.length }})
+
+
+
+
+ 已缓存
+ 未缓存
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/manager-web/src/components/ChangePasswordDialog.vue b/main/manager-web/src/components/ChangePasswordDialog.vue
index a0bb1f7d..fb84992e 100644
--- a/main/manager-web/src/components/ChangePasswordDialog.vue
+++ b/main/manager-web/src/components/ChangePasswordDialog.vue
@@ -1,43 +1,44 @@