diff --git a/helm-chart/.gitignore b/helm-chart/.gitignore new file mode 100644 index 00000000..b5ec6e00 --- /dev/null +++ b/helm-chart/.gitignore @@ -0,0 +1 @@ +!napcat diff --git a/helm-chart/.gitlab-ci.yml b/helm-chart/.gitlab-ci.yml new file mode 100644 index 00000000..ad7af61d --- /dev/null +++ b/helm-chart/.gitlab-ci.yml @@ -0,0 +1,77 @@ +stages: + - initialize-maibot-git-repo + - build + - package + +# 仅在helm-chart分支运行 +workflow: + rules: + - if: '$CI_COMMIT_BRANCH == "helm-chart"' + - when: never + +# 查询并将麦麦仓库的工作区置为最后一个tag的版本 +initialize-maibot-git-repo: + stage: initialize-maibot-git-repo + image: reg.mikumikumi.xyz/base/git:latest + cache: + key: git-repo + policy: push + paths: + - target-repo/ + script: + - git clone https://github.com/Mai-with-u/MaiBot.git target-repo/ + - cd target-repo/ + - export MAIBOT_VERSION=$(git describe --tags --abbrev=0) + - echo "Current version is ${MAIBOT_VERSION}" + - git reset --hard ${MAIBOT_VERSION} + - echo ${MAIBOT_VERSION} > MAIBOT_VERSION + - git clone https://github.com/MaiM-with-u/maim_message maim_message + - git clone https://github.com/MaiM-with-u/MaiMBot-LPMM.git MaiMBot-LPMM + - ls -al + +# 构建最后一个tag的麦麦本体的镜像 +build-core: + stage: build + image: reg.mikumikumi.xyz/base/kaniko-builder:latest + cache: + key: git-repo + policy: pull + paths: + - target-repo/ + script: + - cd target-repo/ + - export BUILD_CONTEXT=$(pwd) + - ls -al + - export BUILD_DESTINATION="reg.mikumikumi.xyz/maibot/maibot:tag-$(cat MAIBOT_VERSION)" + - build + +# 将Helm Chart版本作为tag,构建并推送镜像 +build-adapter-cm-generator: + stage: build + image: reg.mikumikumi.xyz/base/kaniko-builder:latest +# rules: +# - changes: +# - helm-chart/adapter-cm-generator/** + script: + - export BUILD_CONTEXT=helm-chart/adapter-cm-generator + - export TMP_DST=reg.mikumikumi.xyz/maibot/adapter-cm-generator + - export CHART_VERSION=$(cat helm-chart/Chart.yaml | grep '^version:' | cut -d' ' -f2) + - export BUILD_DESTINATION="${TMP_DST}:${CHART_VERSION}" + - export BUILD_ARGS="--destination ${TMP_DST}:latest" + - build + +# 打包并推送helm chart +package-helm-chart: + stage: package + image: reg.mikumikumi.xyz/mirror/helm:latest +# rules: +# - changes: +# - helm-chart/files/** +# - helm-chart/templates/** +# - helm-chart/Chart.yaml +# - helm-chart/values.yaml + script: + - export CHART_VERSION=$(cat helm-chart/Chart.yaml | grep '^version:' | cut -d' ' -f2) + - helm registry login reg.mikumikumi.xyz --username ${CI_REGISTRY_USER} --password ${CI_REGISTRY_PASSWORD} + - helm package helm-chart + - helm push maibot-${CHART_VERSION}.tgz oci://reg.mikumikumi.xyz/maibot diff --git a/helm-chart/.helmignore b/helm-chart/.helmignore new file mode 100644 index 00000000..8cb2bba7 --- /dev/null +++ b/helm-chart/.helmignore @@ -0,0 +1,2 @@ +adapter-cm-generator +.gitlab-ci.yml \ No newline at end of file diff --git a/helm-chart/Chart.yaml b/helm-chart/Chart.yaml new file mode 100644 index 00000000..f218a58b --- /dev/null +++ b/helm-chart/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: maibot +description: "Maimai Bot, a cyber friend dedicated to group chats" +type: application +version: 0.11.0-beta +appVersion: 0.11.0-beta diff --git a/helm-chart/README.md b/helm-chart/README.md new file mode 100644 index 00000000..d07aacf1 --- /dev/null +++ b/helm-chart/README.md @@ -0,0 +1,127 @@ +# MaiBot Helm Chart + +这是麦麦的Helm Chart,可以方便地将麦麦部署在Kubernetes集群中。 + +当前Helm Chart对应的麦麦版本可以在`Chart.yaml`中查看`appVersion`项。 + +详细部署文档:[Kubernetes 部署](https://docs.mai-mai.org/manual/deployment/mmc_deploy_kubernetes.html) + +## 可用的Helm Chart版本列表 + +| Helm Chart版本 | 对应的MaiBot版本 | +|----------------|--------------| +| 0.11.0-beta | 0.11.0-beta | +| 0.10.3-beta | 0.10.3-beta | +| 0.10.0-alpha.0 | 0.10.0-alpha | + +## TL; DR + +```shell +helm install maimai \ + oci://reg.mikumikumi.xyz/maibot/maibot \ + --namespace bot \ + --version \ + --values maibot.yaml +``` + +## Values项说明 + +`values.yaml`分为几个大部分。 + +1. `EULA` & `PRIVACY`: 用户必须同意这里的协议才能成功部署麦麦。 + +2. `adapter`: 麦麦的Adapter的部署配置。 + +3. `core`: 麦麦本体的部署配置。 + +4. `statistics_dashboard`: 麦麦的运行统计看板部署配置。 + + 麦麦每隔一段时间会自动输出html格式的运行统计报告,此统计报告可以部署为看板。 + + 出于隐私考虑,默认禁用。 + +5. `napcat`: Napcat的部署配置。 + + 考虑到复用外部Napcat实例的情况,Napcat部署已被解耦。用户可选是否要部署Napcat。 + + 默认会捆绑部署Napcat。 + +6. `sqlite_web`: sqlite-web的部署配置。 + + 通过sqlite-web可以在网页上操作麦麦的数据库,方便调试。不部署对麦麦的运行无影响。 + + 此服务如果暴露在公网会十分危险,默认不会部署。 + +7. `config`: 这里填写麦麦各部分组件的运行配置文件。 + + 这里填写的配置文件需要严格遵守yaml文件的缩进格式。 + + - `adapter_config`: 对应adapter的`config.toml`。 + + 此配置文件中对于`host`和`port`的配置会被上面`adapter.service`中的配置覆盖,因此不需要改动。 + + - `core_model_config`: 对应core的`model_config.toml`。 + + - `core_bot_config`: 对应core的`bot_config.toml`。 + +## 部署说明 + +使用此Helm Chart的一些注意事项。 + +### 修改麦麦配置 + +麦麦的配置文件会通过ConfigMap资源注入各个组件内。 + +对于通过Helm Chart部署的麦麦,如果需要修改配置,不应该直接修改这些ConfigMap,否则下次Helm更新可能会覆盖掉所有配置。 + +最佳实践是重新配置Helm Chart的values,然后通过`helm upgrade`更新实例。 + +### 动态生成的ConfigMap + +adapter的ConfigMap是每次部署/更新Helm安装实例时动态生成的。 + +动态生成的原因: + +- core服务的DNS名称是动态的,无法在adapter服务的配置文件中提前确定。 +- 一些与k8s现有资源冲突的配置需要被重置。 + +因此,首次部署时,ConfigMap的生成会需要一些时间,部分Pod会无法启动,等待几分钟即可。 + +### 运行统计看板与core的挂载冲突 + +如果启用了运行统计看板,那么statistics_dashboard会与core共同挂载statistics_dashboard存储卷,用于同步html文件。 + +如果k8s集群有多个节点,且statistics_dashboard与core未调度到同一节点,那么就需要statistics_dashboard的PVC访问模式具备`ReadWriteMany`访问模式。 + +不是所有存储卷的底层存储都支持`ReadWriteMany`访问模式。 + +如果你的存储底层无法支持`ReadWriteMany`访问模式,你可以通过`nodeSelector`配置将statistics_dashboard与core调度到同一节点来避免问题。 + +*如果启用了`sqlite-web`,那么上述问题也同样适用于`sqlite-web`与`core`,需要注意。* + +### 麦麦的默认插件 + +麦麦的`core`容器提供了一些默认插件,以提升使用体验。但是插件目录存储在存储卷中,容器启动时挂载的存储卷会完全覆盖掉容器的默认插件目录,导致默认插件无法加载,也难以被用户感知。 + +为了解决这一问题,此Helm Chart中为`core`容器引入了初始化容器。此初始化容器用于为用户自动安装默认插件到存储卷中。可以选择启用(默认启用)。 + +*初始化容器使用与`core`主容器相同的镜像,且用后即销毁,因此不会消耗额外的带宽和存储成本。* + +#### 触发插件安装的条件 + +- 首次部署时(此时没有任何插件处于安装状态) +- 默认插件更新(即默认插件内容发生变化) + +#### 安装状态识别能力 + +初始化容器会记录安装过的默认插件,不会重复安装。为了实现这一点,初始化容器会将安装状态写入`/MaiMBot/data/plugins/.installed-setup-plugins`文件中。 + +基于上述状态识别能力,如果用户不需要某个插件,可以将其删除。由于此插件已自动安装过(记录在状态文件中),即使插件本体不存在也不会再次安装(除非插件更新)。 + +#### 插件更新 + +一旦在镜像中检测到新版本插件(即插件内容不同),初始化容器即会用新插件覆盖旧插件。 + +考虑到旧插件中可能存在用户自定义配置,因此旧插件在被覆盖前会备份到`/MaiMBot/data/plugins-backup`目录中,并以时间归档。 + +因此在升级麦麦后,请注意观察初始容器的日志并重新配置插件。 diff --git a/helm-chart/adapter-cm-generator/Dockerfile b/helm-chart/adapter-cm-generator/Dockerfile new file mode 100644 index 00000000..cd1f7747 --- /dev/null +++ b/helm-chart/adapter-cm-generator/Dockerfile @@ -0,0 +1,10 @@ +# 此镜像用于在部署helm chart时动态生成adapter的配置文件 +FROM python:3.11-slim + +WORKDIR /app + +COPY . /app + +RUN pip3 install --no-cache-dir -i https://mirrors.ustc.edu.cn/pypi/simple -r requirements.txt + +ENTRYPOINT ["python3", "adapter-cm-generator.py"] diff --git a/helm-chart/adapter-cm-generator/adapter-cm-generator.py b/helm-chart/adapter-cm-generator/adapter-cm-generator.py new file mode 100644 index 00000000..2f3e06b0 --- /dev/null +++ b/helm-chart/adapter-cm-generator/adapter-cm-generator.py @@ -0,0 +1,72 @@ +#!/bin/python3 +# 这个脚本的作用是在部署helm chart时动态生成adapter的配置文件,保存在configmap中 +# 需要动态生成的原因是core服务的DNS名称是动态的,无法在adapter服务的配置文件中提前确定 +# 一些与k8s现有资源冲突的配置也会在这里重置 + +import os +import toml +import base64 +from kubernetes import client, config +from datetime import datetime, timezone + +config.load_incluster_config() +core_api = client.CoreV1Api() +apps_api = client.AppsV1Api() + +# 读取部署的关键信息 +namespace = os.getenv("NAMESPACE") +release_name = os.getenv("RELEASE_NAME") +data_b64 = os.getenv("DATA_B64") + +# 解析并覆盖关键配置 +# 这里被覆盖的配置应当在helm chart中针对对应的k8s资源来灵活修改 +data = toml.loads(base64.b64decode(data_b64).decode("utf-8")) +data.setdefault('napcat_server', {}) +data['napcat_server']['host'] = '0.0.0.0' +data['napcat_server']['port'] = 8095 +data.setdefault('maibot_server', {}) +data['maibot_server']['host'] = f'{release_name}-maibot-core' # 根据release名称动态拼接core服务的DNS名称 +data['maibot_server']['port'] = 8000 + +# 创建/修改configmap +cm_name = f'{release_name}-maibot-adapter' +cm = client.V1ConfigMap( + metadata=client.V1ObjectMeta(name=cm_name), + data={'config.toml': toml.dumps(data)} +) +try: + core_api.create_namespaced_config_map(namespace, cm) + print(f"ConfigMap `{cm_name}` created successfully") +except client.exceptions.ApiException as e: + if e.status == 409: # 已存在,更新 + core_api.replace_namespaced_config_map(cm_name, namespace, cm) + print(f"ConfigMap `{cm_name}` replaced successfully") + else: + raise + +# 重启adapter和core的statefulset +now = datetime.now(timezone.utc).isoformat() +body = { + "spec": { + "template": { + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": now + } + } + } + } +} +apps_api.patch_namespaced_stateful_set( + name=f'{release_name}-maibot-adapter', + namespace=namespace, + body=body, +) +apps_api.patch_namespaced_stateful_set( + name=f'{release_name}-maibot-core', + namespace=namespace, + body=body, +) +print(f"StatefulSet `{release_name}-maibot-adapter` restarted successfully") + +print('Job succeed.') diff --git a/helm-chart/adapter-cm-generator/requirements.txt b/helm-chart/adapter-cm-generator/requirements.txt new file mode 100644 index 00000000..83e030ca --- /dev/null +++ b/helm-chart/adapter-cm-generator/requirements.txt @@ -0,0 +1,2 @@ +toml~=0.10.2 +kubernetes~=34.1.0 \ No newline at end of file diff --git a/helm-chart/files/setup-plugins.py b/helm-chart/files/setup-plugins.py new file mode 100644 index 00000000..9fde6804 --- /dev/null +++ b/helm-chart/files/setup-plugins.py @@ -0,0 +1,95 @@ +#!/usr/local/bin/python3 +# 用户插件目录存储在存储卷中,会在启动时覆盖掉容器的默认插件目录。此脚本用于默认插件更新后或麦麦首次启动时为用户自动安装默认插件到存储卷中 +# 如果用户主动删除插件且插件无更新,则不会再次安装。插件状态保存在/MaiMBot/data/plugins/.installed-setup-plugins文件中 +# 此脚本应当挂载进初始化容器中,从/MaiMBot工作路径开始运行。初始化容器的镜像同core容器,初始化容器中应挂载core存储卷的数据到/MaiMBot/data +import os +import shutil +import hashlib +from datetime import datetime + +SRC_DIR = '/MaiMBot/plugins' +DST_DIR = '/MaiMBot/data/plugins' +STATUS_FILE = f'{DST_DIR}/.installed-setup-plugins' +BAK_DIR = '/MaiMBot/data/plugins-backup' +CURRENT_TIME = datetime.now().strftime('%Y%m%d%H%M%S') + +def hash_dir_file(path: str): + """计算目录/文件的SHA256,用于判断是否发生变化""" + def hash_file(_file_path: str): + _h = hashlib.sha256() + with open(_file_path, 'rb') as _f: + for _chunk in iter(lambda: _f.read(8192), b''): + _h.update(_chunk) + return _h.hexdigest() + + if os.path.isfile(path): + return hash_file(path) + + h = hashlib.sha256() + for root, dirs, files in os.walk(path): + for filename in sorted(files): + filepath = os.path.join(root, filename) + relpath = os.path.relpath(filepath, path) + file_hash = hash_file(filepath) + h.update(relpath.encode('utf-8')) + h.update(file_hash.encode('utf-8')) + return h.hexdigest() + +def copy_plugin(plugin: str): + """复制插件,如果插件已存在则备份旧的插件然后用新的插件覆盖""" + src = os.path.join(SRC_DIR, plugin) + if not os.path.exists(src): + raise FileNotFoundError(f"File not found: {src}") + + dst = os.path.join(DST_DIR, plugin) + if os.path.exists(dst): + print(f"\t\tWarning: Old version of plugin '{plugin}' already exists. " + f"Old plugin will be moved to '{BAK_DIR}/{CURRENT_TIME}/{plugin}'. " + f"Remember to re-edit config of this plugin.") + if not os.path.exists(os.path.join(BAK_DIR, CURRENT_TIME)): + os.makedirs(os.path.join(BAK_DIR, CURRENT_TIME)) + if os.path.isdir(dst): + shutil.copytree(dst, os.path.join(BAK_DIR, CURRENT_TIME, plugin)) + shutil.rmtree(dst) + else: + shutil.copy2(dst, os.path.join(BAK_DIR, CURRENT_TIME)) + os.remove(dst) + + if os.path.isdir(src): + shutil.copytree(src, dst) + else: + shutil.copy2(src, DST_DIR) + +setup_plugins = {plugin: hash_dir_file(plugin) for plugin in os.listdir(SRC_DIR)} +installed_plugins = {} +to_install_plugins = {} + +print(f"[SetupPlugins] Default plugin, which has been updated or never been installed, " + f"will be installed in this init container.") +if os.path.exists(STATUS_FILE) and os.path.isfile(STATUS_FILE): + print(f"[SetupPlugins] Reading status file: '{STATUS_FILE}'...") + with open(STATUS_FILE, 'r', encoding='utf-8') as f: + lines = f.readlines() + for line in lines: + if line == '': + continue + plugin = line.strip().split(':') + installed_plugins[plugin[0]] = plugin[1] + print(f"[SetupPlugins] Found {len(installed_plugins)} default plugins which used to be installed:") + for plugin in installed_plugins.keys(): + print(f'\t{plugin}') +else: + print(f"[SetupPlugins] No status file found. Status file '{STATUS_FILE}' will be created. " + f"All default plugins will be installed now.") + +print(f"[SetupPlugins] Checking plugins...") +for plugin, sha256 in setup_plugins.items(): + if (plugin not in installed_plugins) or (sha256 != installed_plugins[plugin]): + print(f"\tFound default plugin to install: '{plugin}'. Installing...") + copy_plugin(plugin) + installed_plugins[plugin] = sha256 + +with open(STATUS_FILE, 'w', encoding='utf-8') as f: + f.write('\n'.join(sorted([f'{plugin}:{sha256}' for plugin, sha256 in installed_plugins.items()]))) + +print(f"[SetupPlugins] Default plugin checking done. Status saved to '{STATUS_FILE}'.") diff --git a/helm-chart/files/volume-linker.sh b/helm-chart/files/volume-linker.sh new file mode 100644 index 00000000..4a371e3c --- /dev/null +++ b/helm-chart/files/volume-linker.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# 此脚本用于覆盖core容器的默认启动命令 +# 由于k8s与docker-compose的卷挂载方式有所不同,需要利用此脚本为一些文件和目录提前创建好软链接 +# /MaiMBot/data是麦麦数据的实际挂载路径 +# /MaiMBot/statistics是统计数据的实际挂载路径 + +set -e +echo "[VolumeLinker] Preparing volume..." + +# 初次启动,在存储卷中检查并创建关键文件和目录 +mkdir -p /MaiMBot/data/plugins +mkdir -p /MaiMBot/data/logs +if [ ! -d "/MaiMBot/statistics" ] +then + echo "[VolumeLinker] Statistics volume disabled." +else + touch /MaiMBot/statistics/index.html +fi + +# 删除空的插件目录,准备创建软链接 +rm -rf /MaiMBot/plugins + +# 创建软链接,从存储卷链接到实际位置 +ln -s /MaiMBot/data/plugins /MaiMBot/plugins +ln -s /MaiMBot/data/logs /MaiMBot/logs +if [ -f "/MaiMBot/statistics/index.html" ] +then + ln -s /MaiMBot/statistics/index.html /MaiMBot/maibot_statistics.html +fi + +# 启动麦麦 +echo "[VolumeLinker] Starting MaiBot..." +exec python bot.py diff --git a/helm-chart/templates/NOTES.txt b/helm-chart/templates/NOTES.txt new file mode 100644 index 00000000..d898adf3 --- /dev/null +++ b/helm-chart/templates/NOTES.txt @@ -0,0 +1,3 @@ +MaiBot has been successfully deployed. + +MaiBot on GitHub: https://github.com/MaiM-with-u/MaiBot diff --git a/helm-chart/templates/adapter/pvc.yaml b/helm-chart/templates/adapter/pvc.yaml new file mode 100644 index 00000000..61778630 --- /dev/null +++ b/helm-chart/templates/adapter/pvc.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-maibot-adapter + namespace: {{ .Release.Namespace }} +spec: + {{- if .Values.adapter.persistence.accessModes }} + accessModes: + {{ toYaml .Values.adapter.persistence.accessModes | nindent 4 }} + {{- end }} + resources: + requests: + storage: {{ .Values.adapter.persistence.size }} + {{- if .Values.adapter.persistence.storageClass }} + storageClassName: {{ .Values.adapter.persistence.storageClass | default nil }} + {{- end }} diff --git a/helm-chart/templates/adapter/service.yaml b/helm-chart/templates/adapter/service.yaml new file mode 100644 index 00000000..86c39246 --- /dev/null +++ b/helm-chart/templates/adapter/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-maibot-adapter + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Release.Name }}-maibot-adapter +spec: + ports: + - name: napcat-ws + port: {{ .Values.adapter.service.port }} + protocol: TCP + targetPort: 8095 + {{- if eq .Values.adapter.service.type "NodePort" }} + nodePort: {{ .Values.adapter.service.nodePort | default nil }} + {{- end }} + selector: + app: {{ .Release.Name }}-maibot-adapter + type: {{ .Values.adapter.service.type }} diff --git a/helm-chart/templates/adapter/statefulset.yaml b/helm-chart/templates/adapter/statefulset.yaml new file mode 100644 index 00000000..262891b4 --- /dev/null +++ b/helm-chart/templates/adapter/statefulset.yaml @@ -0,0 +1,62 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ .Release.Name }}-maibot-adapter + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Release.Name }}-maibot-adapter +spec: + serviceName: {{ .Release.Name }}-maibot-adapter + replicas: 1 + selector: + matchLabels: + app: {{ .Release.Name }}-maibot-adapter + template: + metadata: + labels: + app: {{ .Release.Name }}-maibot-adapter + spec: + containers: + - name: adapter + env: + - name: TZ + value: Asia/Shanghai + image: {{ .Values.adapter.image.repository | default "unclas/maimbot-adapter" }}:{{ .Values.adapter.image.tag | default "main-20250924053857" }} + imagePullPolicy: {{ .Values.adapter.image.pullPolicy }} + ports: + - containerPort: 8095 + name: napcat-ws + protocol: TCP + {{- if .Values.adapter.resources }} + resources: + {{ toYaml .Values.adapter.resources | nindent 12 }} + {{- end }} + volumeMounts: + - mountPath: /adapters/data + name: data + - mountPath: /adapters/config.toml + name: config + readOnly: true + subPath: config.toml + {{- if .Values.adapter.image.pullSecrets }} + imagePullSecrets: + {{ toYaml .Values.adapter.image.pullSecrets | nindent 8 }} + {{- end }} + {{- if .Values.adapter.nodeSelector }} + nodeSelector: + {{ toYaml .Values.adapter.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.adapter.tolerations }} + tolerations: + {{ toYaml .Values.adapter.tolerations | nindent 8 }} + {{- end }} + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ .Release.Name }}-maibot-adapter + - configMap: + items: + - key: config.toml + path: config.toml + name: {{ .Release.Name }}-maibot-adapter + name: config diff --git a/helm-chart/templates/core/configmap.yaml b/helm-chart/templates/core/configmap.yaml new file mode 100644 index 00000000..25f0ef2d --- /dev/null +++ b/helm-chart/templates/core/configmap.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-maibot-core + namespace: {{ .Release.Namespace }} +data: + .env: | + HOST=0.0.0.0 + PORT=8000 + model_config.toml: | + {{ .Values.config.core_model_config | nindent 4 }} + bot_config.toml: | + {{ .Values.config.core_bot_config | nindent 4 }} diff --git a/helm-chart/templates/core/pvc.yaml b/helm-chart/templates/core/pvc.yaml new file mode 100644 index 00000000..e7fe15c7 --- /dev/null +++ b/helm-chart/templates/core/pvc.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-maibot-core + namespace: {{ .Release.Namespace }} +spec: + {{- if .Values.core.persistence.accessModes }} + accessModes: + {{ toYaml .Values.core.persistence.accessModes | nindent 4 }} + {{- end }} + resources: + requests: + storage: {{ .Values.core.persistence.size }} + {{- if .Values.core.persistence.storageClass }} + storageClassName: {{ .Values.core.persistence.storageClass | default nil }} + {{- end }} diff --git a/helm-chart/templates/core/service.yaml b/helm-chart/templates/core/service.yaml new file mode 100644 index 00000000..c236e746 --- /dev/null +++ b/helm-chart/templates/core/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-maibot-core + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Release.Name }}-maibot-core +spec: + ports: + - name: adapter-ws + port: 8000 + protocol: TCP + targetPort: 8000 + selector: + app: {{ .Release.Name }}-maibot-core + type: ClusterIP diff --git a/helm-chart/templates/core/statefulset.yaml b/helm-chart/templates/core/statefulset.yaml new file mode 100644 index 00000000..8bdc2077 --- /dev/null +++ b/helm-chart/templates/core/statefulset.yaml @@ -0,0 +1,124 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ .Release.Name }}-maibot-core + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Release.Name }}-maibot-core +spec: + serviceName: {{ .Release.Name }}-maibot-core + replicas: 1 + selector: + matchLabels: + app: {{ .Release.Name }}-maibot-core + template: + metadata: + labels: + app: {{ .Release.Name }}-maibot-core + spec: + containers: + - name: core + command: # 为了在k8s中初始化存储卷,这里替换启动命令为指定脚本 + - sh + args: + - /MaiMBot/volume-linker.sh + env: + - name: TZ + value: Asia/Shanghai + - name: EULA_AGREE + value: 99f08e0cab0190de853cb6af7d64d4de + - name: PRIVACY_AGREE + value: 9943b855e72199d0f5016ea39052f1b6 + image: {{ .Values.core.image.repository | default "reg.mikumikumi.xyz/maibot/maibot" }}:{{ .Values.core.image.tag | default "tag-0.11.0-beta" }} + imagePullPolicy: {{ .Values.core.image.pullPolicy }} + ports: + - containerPort: 8000 + name: adapter-ws + protocol: TCP + {{- if .Values.core.resources }} + resources: + {{ toYaml .Values.core.resources | nindent 12 }} + {{- end }} + volumeMounts: + - mountPath: /MaiMBot/data + name: data + - mountPath: /MaiMBot/volume-linker.sh + name: scripts + readOnly: true + subPath: volume-linker.sh + - mountPath: /MaiMBot/.env + name: config + readOnly: true + subPath: .env + - mountPath: /MaiMBot/config/model_config.toml + name: config + readOnly: true + subPath: model_config.toml + - mountPath: /MaiMBot/config/bot_config.toml + name: config + readOnly: true + subPath: bot_config.toml + {{- if .Values.statistics_dashboard.enabled }} + - mountPath: /MaiMBot/statistics + name: statistics + {{- end }} + {{- if .Values.core.setup_default_plugins }} + initContainers: # 用户插件目录存储在存储卷中,会在启动时覆盖掉容器的默认插件目录。此初始化容器用于默认插件更新后或麦麦首次启动时为用户自动安装默认插件到存储卷中 + - args: + - setup-plugins.py + command: + - python3 + workingDir: /MaiMBot + image: {{ .Values.core.image.repository | default "reg.mikumikumi.xyz/maibot/maibot" }}:{{ .Values.core.image.tag | default "tag-0.11.0-beta" }} + imagePullPolicy: {{ .Values.core.image.pullPolicy }} + name: setup-plugins + resources: { } + volumeMounts: + - mountPath: /MaiMBot/data + name: data + - mountPath: /MaiMBot/setup-plugins.py + name: scripts + readOnly: true + subPath: setup-plugins.py + {{- end }} + {{- if .Values.core.image.pullSecrets }} + imagePullSecrets: + {{ toYaml .Values.core.image.pullSecrets | nindent 8 }} + {{- end }} + {{- if .Values.core.nodeSelector }} + nodeSelector: + {{ toYaml .Values.core.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.core.tolerations }} + tolerations: + {{ toYaml .Values.core.tolerations | nindent 8 }} + {{- end }} + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ .Release.Name }}-maibot-core + - configMap: + items: + - key: volume-linker.sh + path: volume-linker.sh + {{- if .Values.core.setup_default_plugins }} + - key: setup-plugins.py + path: setup-plugins.py + {{- end }} + name: {{ .Release.Name }}-maibot-scripts + name: scripts + - configMap: + items: + - key: .env + path: .env + - key: model_config.toml + path: model_config.toml + - key: bot_config.toml + path: bot_config.toml + name: {{ .Release.Name }}-maibot-core + name: config + {{- if .Values.statistics_dashboard.enabled }} + - name: statistics + persistentVolumeClaim: + claimName: {{ .Release.Name }}-maibot-statistics-dashboard + {{- end }} diff --git a/helm-chart/templates/job-post-install/job-gen-adapter-cm.yaml b/helm-chart/templates/job-post-install/job-gen-adapter-cm.yaml new file mode 100644 index 00000000..5678fd63 --- /dev/null +++ b/helm-chart/templates/job-post-install/job-gen-adapter-cm.yaml @@ -0,0 +1,30 @@ +# 动态生成adapter配置文件的configmap的job,仅会在部署时运行一次 +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Release.Name }}-maibot-adapter-cm-generator + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +spec: + backoffLimit: 2 + template: + spec: + serviceAccountName: {{ .Release.Name }}-maibot-adapter-cm-generator + restartPolicy: Never + containers: + - name: adapter-cm-generator + image: {{ .Values.adapter.cm_generator.image.repository | default "reg.mikumikumi.xyz/maibot/adapter-cm-generator" }}:{{ .Values.adapter.cm_generator.image.tag | default "0.11.0-beta" }} + workingDir: /app + env: + - name: PYTHONUNBUFFERED + value: "1" + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: RELEASE_NAME + value: {{ .Release.Name }} + - name: DATA_B64 + value: {{ .Values.config.adapter_config | b64enc }} # 将配置文件编码为base64,从环境变量注入 diff --git a/helm-chart/templates/job-post-install/rbac-gen-adapter-cm.yaml b/helm-chart/templates/job-post-install/rbac-gen-adapter-cm.yaml new file mode 100644 index 00000000..1df08343 --- /dev/null +++ b/helm-chart/templates/job-post-install/rbac-gen-adapter-cm.yaml @@ -0,0 +1,33 @@ +# 动态生成adapter配置文件的configmap所需要的rbac授权 +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Release.Name }}-maibot-adapter-cm-generator + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ .Release.Name }}-maibot-adapter-cm-gen-role + namespace: {{ .Release.Namespace }} +rules: + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "create", "update", "patch"] + - apiGroups: ["apps"] + resources: ["statefulsets"] + verbs: ["get", "list", "create", "update", "patch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ .Release.Name }}-maibot-adapter-cm-gen-role-binding + namespace: {{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: {{ .Release.Name }}-maibot-adapter-cm-generator + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role + name: {{ .Release.Name }}-maibot-adapter-cm-gen-role + apiGroup: rbac.authorization.k8s.io diff --git a/helm-chart/templates/napcat/ingress.yaml b/helm-chart/templates/napcat/ingress.yaml new file mode 100644 index 00000000..e46243a2 --- /dev/null +++ b/helm-chart/templates/napcat/ingress.yaml @@ -0,0 +1,26 @@ +{{- if and .Values.napcat.enabled .Values.napcat.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }}-maibot-napcat + namespace: {{ .Release.Namespace }} + {{- if .Values.napcat.ingress.annotations }} + annotations: + {{ toYaml .Values.napcat.ingress.annotations | nindent 4 }} + {{- end }} + labels: + app: {{ .Release.Name }}-maibot-napcat +spec: + ingressClassName: {{ .Values.napcat.ingress.className }} + rules: + - host: {{ .Values.napcat.ingress.host }} + http: + paths: + - backend: + service: + name: {{ .Release.Name }}-maibot-napcat + port: + number: {{ .Values.napcat.service.port }} + path: {{ .Values.napcat.ingress.path }} + pathType: {{ .Values.napcat.ingress.pathType }} +{{- end }} diff --git a/helm-chart/templates/napcat/pvc.yaml b/helm-chart/templates/napcat/pvc.yaml new file mode 100644 index 00000000..530eca72 --- /dev/null +++ b/helm-chart/templates/napcat/pvc.yaml @@ -0,0 +1,18 @@ +{{- if .Values.napcat.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-maibot-napcat + namespace: {{ .Release.Namespace }} +spec: + {{- if .Values.napcat.persistence.accessModes }} + accessModes: + {{ toYaml .Values.napcat.persistence.accessModes | nindent 4 }} + {{- end }} + resources: + requests: + storage: {{ .Values.napcat.persistence.size }} + {{- if .Values.napcat.persistence.storageClass }} + storageClassName: {{ .Values.napcat.persistence.storageClass | default nil }} + {{- end }} +{{- end }} diff --git a/helm-chart/templates/napcat/service.yaml b/helm-chart/templates/napcat/service.yaml new file mode 100644 index 00000000..ec06b231 --- /dev/null +++ b/helm-chart/templates/napcat/service.yaml @@ -0,0 +1,21 @@ +{{- if .Values.napcat.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-maibot-napcat + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Release.Name }}-maibot-napcat +spec: + ports: + - name: webui + port: {{ .Values.napcat.service.port }} + protocol: TCP + targetPort: 6099 + {{- if eq .Values.napcat.service.type "NodePort" }} + nodePort: {{ .Values.napcat.service.nodePort | default nil }} + {{- end }} + selector: + app: {{ .Release.Name }}-maibot-napcat + type: {{ .Values.napcat.service.type }} +{{- end }} diff --git a/helm-chart/templates/napcat/statefulset.yaml b/helm-chart/templates/napcat/statefulset.yaml new file mode 100644 index 00000000..fe1efe3c --- /dev/null +++ b/helm-chart/templates/napcat/statefulset.yaml @@ -0,0 +1,72 @@ +{{- if .Values.napcat.enabled }} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ .Release.Name }}-maibot-napcat + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Release.Name }}-maibot-napcat +spec: + serviceName: {{ .Release.Name }}-maibot-napcat + replicas: 1 + selector: + matchLabels: + app: {{ .Release.Name }}-maibot-napcat + template: + metadata: + labels: + app: {{ .Release.Name }}-maibot-napcat + spec: + containers: + - name: napcat + env: + - name: NAPCAT_GID + value: "{{ .Values.napcat.permission.gid }}" + - name: NAPCAT_UID + value: "{{ .Values.napcat.permission.uid }}" + - name: TZ + value: Asia/Shanghai + image: {{ .Values.napcat.image.repository | default "mlikiowa/napcat-docker" }}:{{ .Values.napcat.image.tag | default "v4.9.8" }} + imagePullPolicy: {{ .Values.napcat.image.pullPolicy }} + livenessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 6099 + scheme: HTTP + initialDelaySeconds: 60 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 10 + ports: + - containerPort: 6099 + name: webui + protocol: TCP + {{- if .Values.napcat.resources }} + resources: + {{ toYaml .Values.napcat.resources | nindent 12 }} + {{- end }} + volumeMounts: + - mountPath: /app/napcat/config + name: napcat + subPath: config + - mountPath: /app/.config/QQ + name: napcat + subPath: data + {{- if .Values.napcat.image.pullSecrets }} + imagePullSecrets: + {{ toYaml .Values.napcat.image.pullSecrets | nindent 8 }} + {{- end }} + {{- if .Values.napcat.nodeSelector }} + nodeSelector: + {{ toYaml .Values.napcat.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.napcat.tolerations }} + tolerations: + {{ toYaml .Values.napcat.tolerations | nindent 8 }} + {{- end }} + volumes: + - name: napcat + persistentVolumeClaim: + claimName: {{ .Release.Name }}-maibot-napcat +{{- end }} diff --git a/helm-chart/templates/other/check-eula-privacy.yaml b/helm-chart/templates/other/check-eula-privacy.yaml new file mode 100644 index 00000000..18b0cca2 --- /dev/null +++ b/helm-chart/templates/other/check-eula-privacy.yaml @@ -0,0 +1,8 @@ +# 检查EULA和PRIVACY +{{- if not .Values.EULA_AGREE }} +{{- fail "You must accept the EULA by setting 'EULA_AGREE: true'. EULA: https://github.com/MaiM-with-u/MaiBot/blob/main/EULA.md" }} +{{- end }} + +{{- if not .Values.PRIVACY_AGREE }} +{{- fail "You must accept the Privacy Policy by setting 'PRIVACY_AGREE: true'. Privacy Policy: https://github.com/MaiM-with-u/MaiBot/blob/main/PRIVACY.md" }} +{{- end }} diff --git a/helm-chart/templates/other/configmap-scripts.yaml b/helm-chart/templates/other/configmap-scripts.yaml new file mode 100644 index 00000000..4d1e546f --- /dev/null +++ b/helm-chart/templates/other/configmap-scripts.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-maibot-scripts + namespace: {{ .Release.Namespace }} +data: + # core + volume-linker.sh: | + {{ .Files.Get "files/volume-linker.sh" | nindent 4 }} + # core的初始化容器 + {{- if .Values.core.setup_default_plugins }} + setup-plugins.py: | + {{ .Files.Get "files/setup-plugins.py" | nindent 4 }} + {{- end }} diff --git a/helm-chart/templates/sqlite-web/ingress.yaml b/helm-chart/templates/sqlite-web/ingress.yaml new file mode 100644 index 00000000..fe14e744 --- /dev/null +++ b/helm-chart/templates/sqlite-web/ingress.yaml @@ -0,0 +1,26 @@ +{{- if and .Values.sqlite_web.enabled .Values.sqlite_web.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }}-maibot-sqlite-web + namespace: {{ .Release.Namespace }} + {{- if .Values.sqlite_web.ingress.annotations }} + annotations: + {{ toYaml .Values.sqlite_web.ingress.annotations | nindent 4 }} + {{- end }} + labels: + app: {{ .Release.Name }}-maibot-sqlite-web +spec: + ingressClassName: {{ .Values.sqlite_web.ingress.className }} + rules: + - host: {{ .Values.sqlite_web.ingress.host }} + http: + paths: + - backend: + service: + name: {{ .Release.Name }}-maibot-sqlite-web + port: + number: {{ .Values.sqlite_web.service.port }} + path: {{ .Values.sqlite_web.ingress.path }} + pathType: {{ .Values.sqlite_web.ingress.pathType }} +{{- end }} diff --git a/helm-chart/templates/sqlite-web/service.yaml b/helm-chart/templates/sqlite-web/service.yaml new file mode 100644 index 00000000..9c9559a9 --- /dev/null +++ b/helm-chart/templates/sqlite-web/service.yaml @@ -0,0 +1,21 @@ +{{- if .Values.sqlite_web.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-maibot-sqlite-web + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Release.Name }}-maibot-sqlite-web +spec: + ports: + - name: webui + port: {{ .Values.sqlite_web.service.port }} + protocol: TCP + targetPort: 8080 + {{- if eq .Values.sqlite_web.service.type "NodePort" }} + nodePort: {{ .Values.sqlite_web.service.nodePort | default nil }} + {{- end }} + selector: + app: {{ .Release.Name }}-maibot-sqlite-web + type: {{ .Values.sqlite_web.service.type }} +{{- end }} diff --git a/helm-chart/templates/sqlite-web/statefulset.yaml b/helm-chart/templates/sqlite-web/statefulset.yaml new file mode 100644 index 00000000..9fb0010b --- /dev/null +++ b/helm-chart/templates/sqlite-web/statefulset.yaml @@ -0,0 +1,64 @@ +{{- if .Values.sqlite_web.enabled }} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ .Release.Name }}-maibot-sqlite-web + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Release.Name }}-maibot-sqlite-web +spec: + serviceName: {{ .Release.Name }}-maibot-sqlite-web + replicas: 1 + selector: + matchLabels: + app: {{ .Release.Name }}-maibot-sqlite-web + template: + metadata: + labels: + app: {{ .Release.Name }}-maibot-sqlite-web + spec: + containers: + - name: sqlite-web + env: + - name: SQLITE_DATABASE + value: /data/MaiMBot/MaiBot.db + image: {{ .Values.sqlite_web.image.repository | default "coleifer/sqlite-web" }}:{{ .Values.sqlite_web.image.tag | default "latest" }} + imagePullPolicy: {{ .Values.sqlite_web.image.pullPolicy }} + livenessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + periodSeconds: 60 + successThreshold: 1 + timeoutSeconds: 10 + ports: + - containerPort: 8080 + name: webui + protocol: TCP + {{- if .Values.sqlite_web.resources }} + resources: + {{ toYaml .Values.sqlite_web.resources | nindent 12 }} + {{- end }} + volumeMounts: + - mountPath: /data/MaiMBot + name: data + {{- if .Values.sqlite_web.image.pullSecrets }} + imagePullSecrets: + {{ toYaml .Values.sqlite_web.image.pullSecrets | nindent 8 }} + {{- end }} + {{- if .Values.sqlite_web.nodeSelector }} + nodeSelector: + {{ toYaml .Values.sqlite_web.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.sqlite_web.tolerations }} + tolerations: + {{ toYaml .Values.sqlite_web.tolerations | nindent 8 }} + {{- end }} + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ .Release.Name }}-maibot-core +{{- end }} diff --git a/helm-chart/templates/statistics/deployment.yaml b/helm-chart/templates/statistics/deployment.yaml new file mode 100644 index 00000000..c5e951e1 --- /dev/null +++ b/helm-chart/templates/statistics/deployment.yaml @@ -0,0 +1,61 @@ +{{- if .Values.statistics_dashboard.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-maibot-statistics-dashboard + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Release.Name }}-maibot-statistics-dashboard +spec: + replicas: {{ .Values.statistics_dashboard.replicaCount }} + selector: + matchLabels: + app: {{ .Release.Name }}-maibot-statistics-dashboard + template: + metadata: + labels: + app: {{ .Release.Name }}-maibot-statistics-dashboard + spec: + containers: + - name: nginx + image: {{ .Values.statistics_dashboard.image.repository | default "nginx" }}:{{ .Values.statistics_dashboard.image.tag | default "latest" }} + imagePullPolicy: {{ .Values.statistics_dashboard.image.pullPolicy }} + livenessProbe: + failureThreshold: 3 + httpGet: + path: / + port: 80 + scheme: HTTP + initialDelaySeconds: 60 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + ports: + - containerPort: 80 + name: dashboard + protocol: TCP + {{- if .Values.statistics_dashboard.resources }} + resources: + {{ toYaml .Values.statistics_dashboard.resources | nindent 12 }} + {{- end }} + volumeMounts: + - mountPath: /usr/share/nginx/html + name: statistics + readOnly: true + {{- if .Values.statistics_dashboard.image.pullSecrets }} + imagePullSecrets: + {{ toYaml .Values.statistics_dashboard.image.pullSecrets | nindent 8 }} + {{- end }} + {{- if .Values.statistics_dashboard.nodeSelector }} + nodeSelector: + {{ toYaml .Values.statistics_dashboard.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.statistics_dashboard.tolerations }} + tolerations: + {{ toYaml .Values.statistics_dashboard.tolerations | nindent 8 }} + {{- end }} + volumes: + - name: statistics + persistentVolumeClaim: + claimName: {{ .Release.Name }}-maibot-statistics-dashboard +{{- end }} diff --git a/helm-chart/templates/statistics/ingress.yaml b/helm-chart/templates/statistics/ingress.yaml new file mode 100644 index 00000000..70c18353 --- /dev/null +++ b/helm-chart/templates/statistics/ingress.yaml @@ -0,0 +1,26 @@ +{{- if and .Values.statistics_dashboard.enabled .Values.statistics_dashboard.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }}-maibot-statistics-dashboard + namespace: {{ .Release.Namespace }} + {{- if .Values.statistics_dashboard.ingress.annotations }} + annotations: + {{ toYaml .Values.statistics_dashboard.ingress.annotations | nindent 4 }} + {{- end }} + labels: + app: {{ .Release.Name }}-maibot-statistics-dashboard +spec: + ingressClassName: {{ .Values.statistics_dashboard.ingress.className }} + rules: + - host: {{ .Values.statistics_dashboard.ingress.host }} + http: + paths: + - backend: + service: + name: {{ .Release.Name }}-maibot-statistics-dashboard + port: + number: {{ .Values.statistics_dashboard.service.port }} + path: {{ .Values.statistics_dashboard.ingress.path }} + pathType: {{ .Values.statistics_dashboard.ingress.pathType }} +{{- end }} diff --git a/helm-chart/templates/statistics/pvc.yaml b/helm-chart/templates/statistics/pvc.yaml new file mode 100644 index 00000000..74b698ce --- /dev/null +++ b/helm-chart/templates/statistics/pvc.yaml @@ -0,0 +1,18 @@ +{{- if .Values.statistics_dashboard.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-maibot-statistics-dashboard + namespace: {{ .Release.Namespace }} +spec: + {{- if .Values.statistics_dashboard.persistence.accessModes }} + accessModes: + {{ toYaml .Values.statistics_dashboard.persistence.accessModes | nindent 4 }} + {{- end }} + resources: + requests: + storage: {{ .Values.statistics_dashboard.persistence.size }} + {{- if .Values.statistics_dashboard.persistence.storageClass }} + storageClassName: {{ .Values.statistics_dashboard.persistence.storageClass | default nil }} + {{- end }} +{{- end }} diff --git a/helm-chart/templates/statistics/service.yaml b/helm-chart/templates/statistics/service.yaml new file mode 100644 index 00000000..c1750894 --- /dev/null +++ b/helm-chart/templates/statistics/service.yaml @@ -0,0 +1,21 @@ +{{- if .Values.statistics_dashboard.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-maibot-statistics-dashboard + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Release.Name }}-maibot-statistics-dashboard +spec: + ports: + - name: dashboard + port: {{ .Values.statistics_dashboard.service.port }} + protocol: TCP + targetPort: 80 + {{- if eq .Values.statistics_dashboard.service.type "NodePort" }} + nodePort: {{ .Values.statistics_dashboard.service.nodePort | default nil }} + {{- end }} + selector: + app: {{ .Release.Name }}-maibot-statistics-dashboard + type: {{ .Values.statistics_dashboard.service.type }} +{{- end }} diff --git a/helm-chart/values.yaml b/helm-chart/values.yaml new file mode 100644 index 00000000..d409231a --- /dev/null +++ b/helm-chart/values.yaml @@ -0,0 +1,633 @@ +# 只有同意了EULA和PRIVACY协议才可以部署麦麦 +# 配置以下的选项为true表示你同意了EULA和PRIVACY条款 +# https://github.com/MaiM-with-u/MaiBot/blob/main/EULA.md +# https://github.com/MaiM-with-u/MaiBot/blob/main/PRIVACY.md +EULA_AGREE: false +PRIVACY_AGREE: false + +# 麦麦Adapter的部署配置 +adapter: + + image: + repository: # 默认 unclas/maimbot-adapter + tag: # 默认 main-20250924053857 + pullPolicy: IfNotPresent + pullSecrets: [ ] + + resources: { } + + nodeSelector: { } + tolerations: [ ] + + # 配置adapter的napcat websocket service + # adapter会启动一个websocket服务端,用于与napcat通信 + # 这里的选项可以帮助你自定义服务端口 + # !!!默认不使用NodePort。如果通过NodePort将服务端口映射到公网可能会被恶意客户端连接,请自行使用中间件鉴权!!! + service: + type: ClusterIP # ClusterIP / NodePort 指定NodePort可以将内网的websocket端口映射到物理节点的端口 + port: 8095 # websocket监听端口ClusterIP的端口 + nodePort: # 仅在设置NodePort类型时有效,不指定则会随机分配端口 + + persistence: + storageClass: + accessModes: + - ReadWriteOnce + size: 1Gi + + # adapter的动态生成configmap的Job的配置 + cm_generator: + image: + repository: # 默认 reg.mikumikumi.xyz/maibot/adapter-cm-generator + tag: # 默认 0.11.0-beta + pullPolicy: IfNotPresent + pullSecrets: [ ] + + +# 麦麦本体的部署配置 +core: + + image: + repository: # 默认 reg.mikumikumi.xyz/maibot/maibot + tag: # 默认 tag-0.11.0-beta + pullPolicy: IfNotPresent + pullSecrets: [ ] + + resources: { } + + nodeSelector: { } + tolerations: [ ] + + persistence: + storageClass: + accessModes: + - ReadWriteOnce + size: 10Gi + + setup_default_plugins: true # 启用一个初始化容器,用于为用户自动安装默认插件到存储卷中 + +# 麦麦的运行统计看板配置 +# 麦麦每隔一段时间会自动输出html格式的运行统计报告,此统计报告可以作为静态网页访问 +# 此功能默认禁用。如果你认为报告可以被公开访问(报告包含联系人/群组名称、模型token花费信息等),则可以启用此功能 +# 如果启用此功能,你也可以考虑使用中间件进行鉴权,保护隐私信息 +statistics_dashboard: + + enabled: false # 是否启用运行统计看板 + + replicaCount: 1 + + image: + repository: # 默认 nginx + tag: # 默认 latest + pullPolicy: IfNotPresent + pullSecrets: [ ] + + resources: { } + + nodeSelector: { } + tolerations: [ ] + + service: + type: ClusterIP # ClusterIP / NodePort 指定NodePort可以将内网的服务端口映射到物理节点的端口 + port: 80 # 服务端口 + nodePort: # 仅在设置NodePort类型时有效,不指定则会随机分配端口 + ingress: + enabled: false + className: nginx + annotations: { } + host: maim-statistics.example.com # 访问运行统计看板的域名 + path: / + pathType: Prefix + + persistence: + storageClass: + # 如果你希望运行统计看板服务与麦麦本体运行在不同的节点(多活部署),那么需要ReadWriteMany访问模式 + # 注意:ReadWriteMany特性需要存储类底层支持 + accessModes: + - ReadWriteOnce + size: 100Mi + +# napcat的部署配置 +# !!!napcat部署完毕后,务必修改默认密码!!! +napcat: + + # 考虑到复用外部napcat实例的情况,napcat部署已被解耦 + # 如果你有外部部署的napcat,则可以修改下面的enabled为false,本次不会重复部署napcat + # 如果没有外部部署的napcat,默认会捆绑部署napcat,不需要修改此项 + enabled: true + + image: + repository: # 默认 mlikiowa/napcat-docker + tag: # 默认 v4.9.8 + pullPolicy: IfNotPresent + pullSecrets: [ ] + + resources: { } + + nodeSelector: { } + tolerations: [ ] + + # napcat进程的权限,默认不是特权用户 + permission: + uid: 1000 + gid: 1000 + + # 配置napcat web面板的service + service: + type: ClusterIP # ClusterIP / NodePort 指定NodePort可以将内网的服务端口映射到物理节点的端口 + port: 6099 # 服务端口 + nodePort: # 仅在设置NodePort类型时有效,不指定则会随机分配端口 + + # 配置napcat web面板的ingress + ingress: + enabled: false # 是否启用 + className: nginx + annotations: { } + host: napcat.example.com # 暴露napcat web面板使用的域名 + path: / + pathType: Prefix + + persistence: + storageClass: + accessModes: + - ReadWriteOnce + size: 5Gi + +# sqlite-web的部署配置 +sqlite_web: + + # 通过sqlite-web可以在网页上操作麦麦的数据库,方便调试。不部署对麦麦的运行无影响 + # 默认不会捆绑部署sqlite-web,如果你需要部署,请修改下面的enabled为true + # !!!sqlite-web服务无鉴权,暴露在公网上十分危险,推荐使用集群ClusterIP内网访问!!! + # !!!如果一定要暴露在公网,请自行使用中间件鉴权!!! + enabled: false + + image: + repository: # 默认 coleifer/sqlite-web + tag: # 默认 latest + pullPolicy: IfNotPresent + pullSecrets: [ ] + + resources: { } + + nodeSelector: { } + tolerations: [ ] + + # 配置sqlite-web面板的service + # !!!默认不使用NodePort。如果使用NodePort暴露到公网,请自行使用中间件鉴权!!! + service: + type: ClusterIP # ClusterIP / NodePort 指定NodePort可以将内网的服务端口映射到物理节点的端口 + port: 8080 # 服务端口 + nodePort: # 仅在设置NodePort类型时有效,不指定则会随机分配端口 + + # 配置sqlite-web面板的ingress + # !!!默认不使用ingress。如果使用ingress暴露到公网,请自行使用中间件鉴权!!! + ingress: + enabled: false # 是否启用 + className: nginx + annotations: { } + host: maim-sqlite.example.com # 暴露websocket使用的域名 + path: / + pathType: Prefix + +# 麦麦各部分组件的运行配置文件 +config: + + # adapter的config.toml + adapter_config: | + [inner] + version = "0.1.2" # 版本号 + # 请勿修改版本号,除非你知道自己在做什么 + + [nickname] # 现在没用 + nickname = "" + + [napcat_server] # Napcat连接的ws服务设置 + token = "" # Napcat设定的访问令牌,若无则留空 + heartbeat_interval = 30 # 与Napcat设置的心跳相同(按秒计) + + [chat] # 黑白名单功能 + group_list_type = "whitelist" # 群组名单类型,可选为:whitelist, blacklist + group_list = [] # 群组名单 + # 当group_list_type为whitelist时,只有群组名单中的群组可以聊天 + # 当group_list_type为blacklist时,群组名单中的任何群组无法聊天 + private_list_type = "whitelist" # 私聊名单类型,可选为:whitelist, blacklist + private_list = [] # 私聊名单 + # 当private_list_type为whitelist时,只有私聊名单中的用户可以聊天 + # 当private_list_type为blacklist时,私聊名单中的任何用户无法聊天 + ban_user_id = [] # 全局禁止名单(全局禁止名单中的用户无法进行任何聊天) + ban_qq_bot = false # 是否屏蔽QQ官方机器人 + enable_poke = true # 是否启用戳一戳功能 + + [voice] # 发送语音设置 + use_tts = false # 是否使用tts语音(请确保你配置了tts并有对应的adapter) + + [debug] + level = "INFO" # 日志等级(DEBUG, INFO, WARNING, ERROR, CRITICAL) + + # core的model_config.toml + core_model_config: | + [inner] + version = "1.7.7" + + # 配置文件版本号迭代规则同bot_config.toml + + [[api_providers]] # API服务提供商(可以配置多个) + name = "DeepSeek" # API服务商名称(可随意命名,在models的api-provider中需使用这个命名) + base_url = "https://api.deepseek.com/v1" # API服务商的BaseURL + api_key = "your-api-key-here" # API密钥(请替换为实际的API密钥) + client_type = "openai" # 请求客户端(可选,默认值为"openai",使用gimini等Google系模型时请配置为"gemini") + max_retry = 2 # 最大重试次数(单个模型API调用失败,最多重试的次数) + timeout = 120 # API请求超时时间(单位:秒) + retry_interval = 10 # 重试间隔时间(单位:秒) + + [[api_providers]] # 阿里 百炼 API服务商配置 + name = "BaiLian" + base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1" + api_key = "your-bailian-key" + client_type = "openai" + max_retry = 2 + timeout = 120 + retry_interval = 5 + + [[api_providers]] # 特殊:Google的Gimini使用特殊API,与OpenAI格式不兼容,需要配置client为"gemini" + name = "Google" + base_url = "https://generativelanguage.googleapis.com/v1beta" + api_key = "your-google-api-key-1" + client_type = "gemini" + max_retry = 2 + timeout = 120 + retry_interval = 10 + + [[api_providers]] # SiliconFlow的API服务商配置 + name = "SiliconFlow" + base_url = "https://api.siliconflow.cn/v1" + api_key = "your-siliconflow-api-key" + client_type = "openai" + max_retry = 3 + timeout = 120 + retry_interval = 5 + + + [[models]] # 模型(可以配置多个) + model_identifier = "deepseek-chat" # 模型标识符(API服务商提供的模型标识符) + name = "deepseek-v3" # 模型名称(可随意命名,在后面中需使用这个命名) + api_provider = "DeepSeek" # API服务商名称(对应在api_providers中配置的服务商名称) + price_in = 2.0 # 输入价格(用于API调用统计,单位:元/ M token)(可选,若无该字段,默认值为0) + price_out = 8.0 # 输出价格(用于API调用统计,单位:元/ M token)(可选,若无该字段,默认值为0) + #force_stream_mode = true # 强制流式输出模式(若模型不支持非流式输出,请取消该注释,启用强制流式输出,若无该字段,默认值为false) + + [[models]] + model_identifier = "deepseek-ai/DeepSeek-V3.2-Exp" + name = "siliconflow-deepseek-v3.2" + api_provider = "SiliconFlow" + price_in = 2.0 + price_out = 3.0 + [models.extra_params] # 可选的额外参数配置 + enable_thinking = false # 不启用思考 + + [[models]] + model_identifier = "deepseek-ai/DeepSeek-V3.2-Exp" + name = "siliconflow-deepseek-v3.2-think" + api_provider = "SiliconFlow" + price_in = 2.0 + price_out = 3.0 + [models.extra_params] # 可选的额外参数配置 + enable_thinking = true # 不启用思考 + + [[models]] + model_identifier = "deepseek-ai/DeepSeek-R1" + name = "siliconflow-deepseek-r1" + api_provider = "SiliconFlow" + price_in = 4.0 + price_out = 16.0 + + + [[models]] + model_identifier = "Qwen/Qwen3-30B-A3B-Instruct-2507" + name = "qwen3-30b" + api_provider = "SiliconFlow" + price_in = 0.7 + price_out = 2.8 + + [[models]] + model_identifier = "Qwen/Qwen3-VL-30B-A3B-Instruct" + name = "qwen3-vl-30" + api_provider = "SiliconFlow" + price_in = 4.13 + price_out = 4.13 + + [[models]] + model_identifier = "FunAudioLLM/SenseVoiceSmall" + name = "sensevoice-small" + api_provider = "SiliconFlow" + price_in = 0 + price_out = 0 + + [[models]] + model_identifier = "BAAI/bge-m3" + name = "bge-m3" + api_provider = "SiliconFlow" + price_in = 0 + price_out = 0 + + + [model_task_config.utils] # 在麦麦的一些组件中使用的模型,例如表情包模块,取名模块,关系模块,麦麦的情绪变化等,是麦麦必须的模型 + model_list = ["siliconflow-deepseek-v3.2"] # 使用的模型列表,每个子项对应上面的模型名称(name) + temperature = 0.2 # 模型温度,新V3建议0.1-0.3 + max_tokens = 2048 # 最大输出token数 + + [model_task_config.utils_small] # 在麦麦的一些组件中使用的小模型,消耗量较大,建议使用速度较快的小模型 + model_list = ["qwen3-30b"] + temperature = 0.7 + max_tokens = 2048 + + [model_task_config.tool_use] #工具调用模型,需要使用支持工具调用的模型 + model_list = ["qwen3-30b"] + temperature = 0.7 + max_tokens = 800 + + [model_task_config.replyer] # 首要回复模型,还用于表达器和表达方式学习 + model_list = ["siliconflow-deepseek-v3.2-think","siliconflow-deepseek-r1","siliconflow-deepseek-v3.2"] + temperature = 0.3 # 模型温度,新V3建议0.1-0.3 + max_tokens = 2048 + + [model_task_config.planner] #决策:负责决定麦麦该什么时候回复的模型 + model_list = ["siliconflow-deepseek-v3.2"] + temperature = 0.3 + max_tokens = 800 + + [model_task_config.vlm] # 图像识别模型 + model_list = ["qwen3-vl-30"] + max_tokens = 256 + + [model_task_config.voice] # 语音识别模型 + model_list = ["sensevoice-small"] + + #嵌入模型 + [model_task_config.embedding] + model_list = ["bge-m3"] + + #------------LPMM知识库模型------------ + + [model_task_config.lpmm_entity_extract] # 实体提取模型 + model_list = ["siliconflow-deepseek-v3.2"] + temperature = 0.2 + max_tokens = 800 + + [model_task_config.lpmm_rdf_build] # RDF构建模型 + model_list = ["siliconflow-deepseek-v3.2"] + temperature = 0.2 + max_tokens = 800 + + [model_task_config.lpmm_qa] # 问答模型 + model_list = ["siliconflow-deepseek-v3.2"] + temperature = 0.7 + max_tokens = 800 + + # core的bot_config.toml + core_bot_config: | + [inner] + version = "6.19.1" + + #----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读---- + #如果你想要修改配置文件,请递增version的值 + #如果新增项目,请阅读src/config/official_configs.py中的说明 + # + # 版本格式:主版本号.次版本号.修订号,版本号递增规则如下: + # 主版本号:MMC版本更新 + # 次版本号:配置文件内容大更新 + # 修订号:配置文件内容小更新 + #----以上是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读---- + + [bot] + platform = "qq" + qq_account = "1145141919810" # 麦麦的QQ账号 + + platforms = ["wx:114514","xx:1919810"] # 麦麦的其他平台账号 + + nickname = "麦麦" # 麦麦的昵称 + alias_names = ["麦叠", "牢麦"] # 麦麦的别名 + + [personality] + # 建议120字以内,描述人格特质 和 身份特征 + personality = "是一个女大学生,现在在读大二,会刷贴吧。" + #アイデンティティがない 生まれないらららら + # 描述麦麦说话的表达风格,表达习惯,如要修改,可以酌情新增内容 + reply_style = "请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景。可以参考贴吧,知乎和微博的回复风格。" + + # 麦麦的兴趣,会影响麦麦对什么话题进行回复 + interest = "对技术相关话题,游戏和动漫相关话题感兴趣,也对日常话题感兴趣,不喜欢太过沉重严肃的话题" + + # 麦麦的说话规则,行为风格: + plan_style = """ + 1.思考**所有**的可用的action中的**每个动作**是否符合当下条件,如果动作使用条件符合聊天内容就使用 + 2.如果相同的内容已经被执行,请不要重复执行 + 3.请控制你的发言频率,不要太过频繁的发言 + 4.如果有人对你感到厌烦,请减少回复 + 5.如果有人对你进行攻击,或者情绪激动,请你以合适的方法应对""" + + # 麦麦识图规则,不建议修改 + visual_style = "请用中文描述这张图片的内容。如果有文字,请把文字描述概括出来,请留意其主题,直观感受,输出为一段平文本,最多30字,请注意不要分点,就输出一段文本" + + # 麦麦私聊的说话规则,行为风格: + private_plan_style = """ + 1.思考**所有**的可用的action中的**每个动作**是否符合当下条件,如果动作使用条件符合聊天内容就使用 + 2.如果相同的内容已经被执行,请不要重复执行 + 3.某句话如果已经被回复过,不要重复回复""" + + # 状态,可以理解为人格多样性,会随机替换人格 + states = [ + "是一个女大学生,喜欢上网聊天,会刷小红书。" , + "是一个大二心理学生,会刷贴吧和中国知网。" , + "是一个赛博网友,最近很想吐槽人。" + ] + + # 替换概率,每次构建人格时替换personality的概率(0.0-1.0) + state_probability = 0.3 + + [expression] + # 表达方式模式 + mode = "classic" + # 可选:classic经典模式,exp_model 表达模型模式,这个模式需要一定时间学习才会有比较好的效果 + + # 表达学习配置 + learning_list = [ # 表达学习配置列表,支持按聊天流配置 + ["", "enable", "enable", "1.0"], # 全局配置:使用表达,启用学习,学习强度1.0 + ["qq:1919810:group", "enable", "enable", "1.5"], # 特定群聊配置:使用表达,启用学习,学习强度1.5 + ["qq:114514:private", "enable", "disable", "0.5"], # 特定私聊配置:使用表达,禁用学习,学习强度0.5 + # 格式说明: + # 第一位: chat_stream_id,空字符串表示全局配置 + # 第二位: 是否使用学到的表达 ("enable"/"disable") + # 第三位: 是否学习表达 ("enable"/"disable") + # 第四位: 学习强度(浮点数),影响学习频率,最短学习时间间隔 = 300/学习强度(秒) + # 学习强度越高,学习越频繁;学习强度越低,学习越少 + ] + + expression_groups = [ + # ["*"], # 全局共享组:所有chat_id共享学习到的表达方式(取消注释以启用全局共享) + ["qq:1919810:private","qq:114514:private","qq:1111111:group"], # 特定互通组,相同组的chat_id会共享学习到的表达方式 + # 格式说明: + # ["*"] - 启用全局共享,所有聊天流共享表达方式 + # ["qq:123456:private","qq:654321:group"] - 特定互通组,组内chat_id共享表达方式 + # 注意:如果为群聊,则需要设置为group,如果设置为私聊,则需要设置为private + ] + + + [chat] #麦麦的聊天设置 + talk_value = 1 #聊天频率,越小越沉默,范围0-1 + mentioned_bot_reply = true # 是否启用提及必回复 + max_context_size = 30 # 上下文长度 + auto_chat_value = 1 # 自动聊天,越小,麦麦主动聊天的概率越低 + planner_smooth = 5 #规划器平滑,增大数值会减小planner负荷,略微降低反应速度,推荐2-8,0为关闭,必须大于等于0 + + enable_talk_value_rules = true # 是否启用动态发言频率规则 + enable_auto_chat_value_rules = false # 是否启用动态自动聊天频率规则 + + # 动态发言频率规则:按时段/按chat_id调整 talk_value(优先匹配具体chat,再匹配全局) + # 推荐格式(对象数组):{ target="platform:id:type" 或 "", time="HH:MM-HH:MM", value=0.5 } + # 说明: + # - target 为空字符串表示全局;type 为 group/private,例如:"qq:1919810:group" 或 "qq:114514:private"; + # - 支持跨夜区间,例如 "23:00-02:00";数值范围建议 0-1。 + talk_value_rules = [ + { target = "", time = "00:00-08:59", value = 0.8 }, + { target = "", time = "09:00-22:59", value = 1.0 }, + { target = "qq:1919810:group", time = "20:00-23:59", value = 0.6 }, + { target = "qq:114514:private", time = "00:00-23:59", value = 0.3 }, + ] + + # 动态自动聊天频率规则:按时段/按chat_id调整 auto_chat_value(优先匹配具体chat,再匹配全局) + # 推荐格式(对象数组):{ target="platform:id:type" 或 "", time="HH:MM-HH:MM", value=0.5 } + # 说明: + # - target 为空字符串表示全局;type 为 group/private,例如:"qq:1919810:group" 或 "qq:114514:private"; + # - 支持跨夜区间,例如 "23:00-02:00";数值范围建议 0-1。 + auto_chat_value_rules = [ + { target = "", time = "00:00-08:59", value = 0.3 }, + { target = "", time = "09:00-22:59", value = 1.0 }, + { target = "qq:1919810:group", time = "20:00-23:59", value = 0.8 }, + { target = "qq:114514:private", time = "00:00-23:59", value = 0.5 }, + ] + + [memory] + max_memory_number = 100 # 记忆最大数量 + max_memory_size = 2048 # 记忆最大大小 + memory_build_frequency = 1 # 记忆构建频率 + + + [tool] + enable_tool = true # 是否启用工具 + + [mood] + enable_mood = false # 是否启用情绪系统 + mood_update_threshold = 1 # 情绪更新阈值,越高,更新越慢 + # 情感特征,影响情绪的变化情况 + emotion_style = "情绪较为稳定,但遭遇特定事件的时候起伏较大" + + [emoji] + emoji_chance = 0.4 # 麦麦激活表情包动作的概率 + max_reg_num = 100 # 表情包最大注册数量 + do_replace = true # 开启则在达到最大数量时删除(替换)表情包,关闭则达到最大数量时不会继续收集表情包 + check_interval = 10 # 检查表情包(注册,破损,删除)的时间间隔(分钟) + steal_emoji = true # 是否偷取表情包,让麦麦可以将一些表情包据为己有 + content_filtration = false # 是否启用表情包过滤,只有符合该要求的表情包才会被保存 + filtration_prompt = "符合公序良俗" # 表情包过滤要求,只有符合该要求的表情包才会被保存 + + [voice] + enable_asr = false # 是否启用语音识别,启用后麦麦可以识别语音消息,启用该功能需要配置语音识别模型[model_task_config.voice] + + [message_receive] + # 以下是消息过滤,可以根据规则过滤特定消息,将不会读取这些消息 + ban_words = [ + # "403","张三" + ] + + ban_msgs_regex = [ + # 需要过滤的消息(原始消息)匹配的正则表达式,匹配到的消息将被过滤,若不了解正则表达式请勿修改 + #"https?://[^\\s]+", # 匹配https链接 + #"\\d{4}-\\d{2}-\\d{2}", # 匹配日期 + ] + + + [lpmm_knowledge] # lpmm知识库配置 + enable = false # 是否启用lpmm知识库 + rag_synonym_search_top_k = 10 # 同义词搜索TopK + rag_synonym_threshold = 0.8 # 同义词阈值(相似度高于此阈值的词语会被认为是同义词) + info_extraction_workers = 3 # 实体提取同时执行线程数,非Pro模型不要设置超过5 + qa_relation_search_top_k = 10 # 关系搜索TopK + qa_relation_threshold = 0.5 # 关系阈值(相似度高于此阈值的关系会被认为是相关的关系) + qa_paragraph_search_top_k = 1000 # 段落搜索TopK(不能过小,可能影响搜索结果) + qa_paragraph_node_weight = 0.05 # 段落节点权重(在图搜索&PPR计算中的权重,当搜索仅使用DPR时,此参数不起作用) + qa_ent_filter_top_k = 10 # 实体过滤TopK + qa_ppr_damping = 0.8 # PPR阻尼系数 + qa_res_top_k = 3 # 最终提供的文段TopK + embedding_dimension = 1024 # 嵌入向量维度,应该与模型的输出维度一致 + + # keyword_rules 用于设置关键词触发的额外回复知识 + # 添加新规则方法:在 keyword_rules 数组中增加一项,格式如下: + # { keywords = ["关键词1", "关键词2"], reaction = "触发这些关键词时的回复内容" } + # 例如,添加一个新规则:当检测到“你好”或“hello”时回复“你好,有什么可以帮你?” + # { keywords = ["你好", "hello"], reaction = "你好,有什么可以帮你?" } + [keyword_reaction] + keyword_rules = [ + { keywords = ["人机", "bot", "机器", "入机", "robot", "机器人", "ai", "AI"], reaction = "有人说你是人机或者机器人,否定这一事实,攻击或反问他。注意,只有认为你是机器人才回复,否则不要否认" }, + { keywords = ["测试关键词回复", "test"], reaction = "回答测试成功" }, + #{ keywords = ["你好", "hello"], reaction = "你好,有什么可以帮你?" } + # 在此处添加更多规则,格式同上 + ] + + regex_rules = [ + { regex = ["^(?P\\S{1,20})是这样的$"], reaction = "请按照以下模板造句:[n]是这样的,xx只要xx就可以,可是[n]要考虑的事情就很多了,比如什么时候xx,什么时候xx,什么时候xx。(请自由发挥替换xx部分,只需保持句式结构,同时表达一种将[n]过度重视的反讽意味)" }, + { regex = ["(?:[^,。.\\s]+,\\s*)?我(?:也)?[没沒]要求你\\s*(?P.+?)[.。,,]?$"],reaction = "进行一次“八岐大蛇定型文”补完。暂时忽略回复风格,进入“粉絲吐槽”模式。请严格按照以下“填空模板”,围绕“[action]”进行创作,使其充满滑稽的夸张感和天马行空的联想:我没要求你[action],我不是(与action关联的、宽容的角色)。可是,(与action相关的具体负面行为)是什么意思?你的(与action相关的某种观念)怎么了?你才(与action相关的某个状态或时间点)吧?再这样下去,你(一个中期的、等比级数式的滑稽推演),(一个后期的、等比级数式的滑稽推演),最后就变成(一个与主题相关的、夸张的最终形态)了。作为(与最终形态相关的、克星或权威身份),我可能得(对你执行一个天罚般的行动)。真的。"} + ] + + [response_post_process] + enable_response_post_process = true # 是否启用回复后处理,包括错别字生成器,回复分割器 + + [chinese_typo] + enable = true # 是否启用中文错别字生成器 + error_rate=0.01 # 单字替换概率 + min_freq=9 # 最小字频阈值 + tone_error_rate=0.1 # 声调错误概率 + word_replace_rate=0.006 # 整词替换概率 + + [response_splitter] + enable = true # 是否启用回复分割器 + max_length = 512 # 回复允许的最大长度 + max_sentence_num = 8 # 回复允许的最大句子数 + enable_kaomoji_protection = false # 是否启用颜文字保护 + + [log] + date_style = "m-d H:i:s" # 日期格式 + log_level_style = "lite" # 日志级别样式,可选FULL,compact,lite + color_text = "full" # 日志文本颜色,可选none,title,full + log_level = "INFO" # 全局日志级别(向下兼容,优先级低于下面的分别设置) + console_log_level = "INFO" # 控制台日志级别,可选: DEBUG, INFO, WARNING, ERROR, CRITICAL + file_log_level = "DEBUG" # 文件日志级别,可选: DEBUG, INFO, WARNING, ERROR, CRITICAL + + # 第三方库日志控制 + suppress_libraries = ["faiss","httpx", "urllib3", "asyncio", "websockets", "httpcore", "requests", "peewee", "openai","uvicorn","jieba"] # 完全屏蔽的库 + library_log_levels = { aiohttp = "WARNING"} # 设置特定库的日志级别 + + [debug] + show_prompt = false # 是否显示prompt + + [maim_message] + auth_token = [] # 认证令牌,用于API验证,为空则不启用验证 + # 以下项目若要使用需要打开use_custom,并单独配置maim_message的服务器 + use_custom = false # 是否启用自定义的maim_message服务器,注意这需要设置新的端口,不能与.env重复 + host="127.0.0.1" + port=8090 + mode="ws" # 支持ws和tcp两种模式 + use_wss = false # 是否使用WSS安全连接,只支持ws模式 + cert_file = "" # SSL证书文件路径,仅在use_wss=true时有效 + key_file = "" # SSL密钥文件路径,仅在use_wss=true时有效 + + [telemetry] #发送统计信息,主要是看全球有多少只麦麦 + enable = true + + [experimental] #实验性功能 + none = false # 暂无 + + + #此系统暂时移除,无效配置 + [relationship] + enable_relationship = true # 是否启用关系系统