mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-20 19:36:08 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6bb73297e0 |
@@ -1,5 +1,5 @@
|
|||||||
name: 漏洞反馈
|
name: 漏洞反馈
|
||||||
description: 【供中文用户】报错或漏洞请使用这个模板创建,不使用此模板创建的异常、漏洞相关issue将被直接关闭。由于自己操作不当/不甚了解所用技术栈引起的网络连接问题恕无法解决,请勿提 issue。容器间网络连接问题,参考文档 https://link.langbot.app/zh/docs/network
|
description: 【供中文用户】报错或漏洞请使用这个模板创建,不使用此模板创建的异常、漏洞相关issue将被直接关闭。由于自己操作不当/不甚了解所用技术栈引起的网络连接问题恕无法解决,请勿提 issue。容器间网络连接问题,参考文档 https://docs.langbot.app/zh/workshop/network-details.html
|
||||||
title: "[Bug]: "
|
title: "[Bug]: "
|
||||||
labels: ["bug?"]
|
labels: ["bug?"]
|
||||||
body:
|
body:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: Bug report
|
name: Bug report
|
||||||
description: Report bugs or vulnerabilities using this template. For container network connection issues, refer to the documentation https://link.langbot.app/en/docs/network
|
description: Report bugs or vulnerabilities using this template. For container network connection issues, refer to the documentation https://docs.langbot.app/en/workshop/network-details.html
|
||||||
title: "[Bug]: "
|
title: "[Bug]: "
|
||||||
labels: ["bug?"]
|
labels: ["bug?"]
|
||||||
body:
|
body:
|
||||||
|
|||||||
@@ -52,3 +52,11 @@ src/langbot/web/
|
|||||||
/dist
|
/dist
|
||||||
/build
|
/build
|
||||||
*.egg-info
|
*.egg-info
|
||||||
|
|
||||||
|
# Docker 部署产生的本地文件
|
||||||
|
docker/data/
|
||||||
|
docker/docker-compose.override.yaml
|
||||||
|
|
||||||
|
# 备份目录
|
||||||
|
LangBot_backup_*/
|
||||||
|
*.bak
|
||||||
|
|||||||
+6
-2
@@ -10,14 +10,18 @@ FROM python:3.12.7-slim
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Use Chinese mirror for faster and more reliable package downloads
|
||||||
|
RUN sed -i 's|deb.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources 2>/dev/null || \
|
||||||
|
sed -i 's|deb.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list 2>/dev/null || true
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
COPY --from=node /app/web/out ./web/out
|
COPY --from=node /app/web/out ./web/out
|
||||||
|
|
||||||
RUN apt update \
|
RUN apt update \
|
||||||
&& apt install gcc -y \
|
&& apt install gcc -y \
|
||||||
&& python -m pip install --no-cache-dir uv \
|
&& python -m pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple uv \
|
||||||
&& uv sync \
|
&& uv sync --index-url https://pypi.tuna.tsinghua.edu.cn/simple \
|
||||||
&& touch /.dockerenv
|
&& touch /.dockerenv
|
||||||
|
|
||||||
CMD [ "uv", "run", "--no-sync", "main.py" ]
|
CMD [ "uv", "run", "--no-sync", "main.py" ]
|
||||||
@@ -19,9 +19,9 @@ English / [简体中文](README_CN.md) / [繁體中文](README_TW.md) / [日本
|
|||||||
[](https://github.com/langbot-app/LangBot/stargazers)
|
[](https://github.com/langbot-app/LangBot/stargazers)
|
||||||
|
|
||||||
<a href="https://langbot.app">Website</a> |
|
<a href="https://langbot.app">Website</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/features">Features</a> |
|
<a href="https://docs.langbot.app/en/insight/features">Features</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/guide">Docs</a> |
|
<a href="https://docs.langbot.app/en/insight/guide">Docs</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/api">API</a> |
|
<a href="https://docs.langbot.app/en/tags/readme">API</a> |
|
||||||
<a href="https://space.langbot.app/cloud">Cloud</a> |
|
<a href="https://space.langbot.app/cloud">Cloud</a> |
|
||||||
<a href="https://space.langbot.app">Plugin Market</a> |
|
<a href="https://space.langbot.app">Plugin Market</a> |
|
||||||
<a href="https://langbot.featurebase.app/roadmap">Roadmap</a>
|
<a href="https://langbot.featurebase.app/roadmap">Roadmap</a>
|
||||||
@@ -45,7 +45,7 @@ LangBot is an **open-source, production-grade platform** for building AI-powered
|
|||||||
- **Web Management Panel** — Configure, manage, and monitor your bots through an intuitive browser interface. No YAML editing required.
|
- **Web Management Panel** — Configure, manage, and monitor your bots through an intuitive browser interface. No YAML editing required.
|
||||||
- **Multi-Pipeline Architecture** — Different bots for different scenarios, with comprehensive monitoring and exception handling.
|
- **Multi-Pipeline Architecture** — Different bots for different scenarios, with comprehensive monitoring and exception handling.
|
||||||
|
|
||||||
[→ Learn more about all features](https://link.langbot.app/en/docs/features)
|
[→ Learn more about all features](https://docs.langbot.app/en/insight/features)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ docker compose up -d
|
|||||||
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
||||||
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
||||||
|
|
||||||
**More options:** [Docker](https://link.langbot.app/en/docs/docker) · [Manual](https://link.langbot.app/en/docs/manual-deploy) · [BTPanel](https://link.langbot.app/en/docs/bt-panel) · [Kubernetes](./docker/README_K8S.md)
|
**More options:** [Docker](https://docs.langbot.app/en/deploy/langbot/docker) · [Manual](https://docs.langbot.app/en/deploy/langbot/manual) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt) · [Kubernetes](./docker/README_K8S.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ docker compose up -d
|
|||||||
| [接口 AI](https://jiekou.ai/) | Gateway | ✅ |
|
| [接口 AI](https://jiekou.ai/) | Gateway | ✅ |
|
||||||
| [302.AI](https://share.302.ai/SuTG99) | Gateway | ✅ |
|
| [302.AI](https://share.302.ai/SuTG99) | Gateway | ✅ |
|
||||||
|
|
||||||
[→ View all integrations](https://link.langbot.app/en/docs/features)
|
[→ View all integrations](https://docs.langbot.app/en/insight/features)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -21,9 +21,9 @@
|
|||||||
[](https://gitcode.com/RockChinQ/LangBot)
|
[](https://gitcode.com/RockChinQ/LangBot)
|
||||||
|
|
||||||
<a href="https://langbot.app">官网</a> |
|
<a href="https://langbot.app">官网</a> |
|
||||||
<a href="https://link.langbot.app/zh/docs/features">特性</a> |
|
<a href="https://docs.langbot.app/zh/insight/features.html">特性</a> |
|
||||||
<a href="https://link.langbot.app/zh/docs/guide">文档</a> |
|
<a href="https://docs.langbot.app/zh/insight/guide.html">文档</a> |
|
||||||
<a href="https://link.langbot.app/zh/docs/api">API</a> |
|
<a href="https://docs.langbot.app/zh/tags/readme.html">API</a> |
|
||||||
<a href="https://space.langbot.app/cloud">Cloud</a> |
|
<a href="https://space.langbot.app/cloud">Cloud</a> |
|
||||||
<a href="https://space.langbot.app">插件市场</a> |
|
<a href="https://space.langbot.app">插件市场</a> |
|
||||||
<a href="https://langbot.featurebase.app/roadmap">路线图</a>
|
<a href="https://langbot.featurebase.app/roadmap">路线图</a>
|
||||||
@@ -45,7 +45,7 @@ LangBot 是一个**开源的生产级平台**,用于构建 AI 驱动的即时
|
|||||||
- **Web 管理面板** — 通过浏览器直观地配置、管理和监控机器人,无需手动编辑配置文件。
|
- **Web 管理面板** — 通过浏览器直观地配置、管理和监控机器人,无需手动编辑配置文件。
|
||||||
- **多流水线架构** — 不同机器人用于不同场景,具备全面的监控和异常处理能力。
|
- **多流水线架构** — 不同机器人用于不同场景,具备全面的监控和异常处理能力。
|
||||||
|
|
||||||
[→ 了解更多功能特性](https://link.langbot.app/zh/docs/features)
|
[→ 了解更多功能特性](https://docs.langbot.app/zh/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ docker compose up -d
|
|||||||
[](https://zeabur.com/zh-CN/templates/ZKTBDH)
|
[](https://zeabur.com/zh-CN/templates/ZKTBDH)
|
||||||
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
||||||
|
|
||||||
**更多方式:** [Docker](https://link.langbot.app/zh/docs/docker) · [手动部署](https://link.langbot.app/zh/docs/manual-deploy) · [宝塔面板](https://link.langbot.app/zh/docs/bt-panel) · [Kubernetes](./docker/README_K8S.md)
|
**更多方式:** [Docker](https://docs.langbot.app/zh/deploy/langbot/docker.html) · [手动部署](https://docs.langbot.app/zh/deploy/langbot/manual.html) · [宝塔面板](https://docs.langbot.app/zh/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ docker compose up -d
|
|||||||
| [小马算力](https://www.tokenpony.cn/453z1) | 聚合平台 | ✅ |
|
| [小马算力](https://www.tokenpony.cn/453z1) | 聚合平台 | ✅ |
|
||||||
| [百宝箱Tbox](https://www.tbox.cn/open) | 智能体平台 | ✅ |
|
| [百宝箱Tbox](https://www.tbox.cn/open) | 智能体平台 | ✅ |
|
||||||
|
|
||||||
[→ 查看完整集成列表](https://link.langbot.app/zh/docs/features)
|
[→ 查看完整集成列表](https://docs.langbot.app/zh/insight/features.html)
|
||||||
|
|
||||||
### TTS(语音合成)
|
### TTS(语音合成)
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -19,9 +19,9 @@
|
|||||||
[](https://github.com/langbot-app/LangBot/stargazers)
|
[](https://github.com/langbot-app/LangBot/stargazers)
|
||||||
|
|
||||||
<a href="https://langbot.app">Inicio</a> |
|
<a href="https://langbot.app">Inicio</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/features">Características</a> |
|
<a href="https://docs.langbot.app/en/insight/features.html">Características</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/guide">Documentación</a> |
|
<a href="https://docs.langbot.app/en/insight/guide.html">Documentación</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/api">API</a> |
|
<a href="https://docs.langbot.app/en/tags/readme.html">API</a> |
|
||||||
<a href="https://space.langbot.app">Mercado de Plugins</a> |
|
<a href="https://space.langbot.app">Mercado de Plugins</a> |
|
||||||
<a href="https://langbot.featurebase.app/roadmap">Hoja de Ruta</a>
|
<a href="https://langbot.featurebase.app/roadmap">Hoja de Ruta</a>
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ LangBot es una **plataforma de código abierto y grado de producción** para con
|
|||||||
- **Panel de Gestión Web** — Configure, gestione y monitoree sus bots a través de una interfaz de navegador intuitiva. Sin necesidad de editar YAML.
|
- **Panel de Gestión Web** — Configure, gestione y monitoree sus bots a través de una interfaz de navegador intuitiva. Sin necesidad de editar YAML.
|
||||||
- **Arquitectura Multi-Pipeline** — Diferentes bots para diferentes escenarios, con monitoreo completo y manejo de excepciones.
|
- **Arquitectura Multi-Pipeline** — Diferentes bots para diferentes escenarios, con monitoreo completo y manejo de excepciones.
|
||||||
|
|
||||||
[→ Conocer más sobre todas las funcionalidades](https://link.langbot.app/en/docs/features)
|
[→ Conocer más sobre todas las funcionalidades](https://docs.langbot.app/en/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ docker compose up -d
|
|||||||
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
||||||
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
||||||
|
|
||||||
**Más opciones:** [Docker](https://link.langbot.app/en/docs/docker) · [Manual](https://link.langbot.app/en/docs/manual-deploy) · [BTPanel](https://link.langbot.app/en/docs/bt-panel) · [Kubernetes](./docker/README_K8S.md)
|
**Más opciones:** [Docker](https://docs.langbot.app/en/deploy/langbot/docker.html) · [Manual](https://docs.langbot.app/en/deploy/langbot/manual.html) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ docker compose up -d
|
|||||||
| [接口 AI](https://jiekou.ai/) | Pasarela | ✅ |
|
| [接口 AI](https://jiekou.ai/) | Pasarela | ✅ |
|
||||||
| [302.AI](https://share.302.ai/SuTG99) | Pasarela | ✅ |
|
| [302.AI](https://share.302.ai/SuTG99) | Pasarela | ✅ |
|
||||||
|
|
||||||
[→ Ver todas las integraciones](https://link.langbot.app/en/docs/features)
|
[→ Ver todas las integraciones](https://docs.langbot.app/en/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -19,9 +19,9 @@
|
|||||||
[](https://github.com/langbot-app/LangBot/stargazers)
|
[](https://github.com/langbot-app/LangBot/stargazers)
|
||||||
|
|
||||||
<a href="https://langbot.app">Accueil</a> |
|
<a href="https://langbot.app">Accueil</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/features">Fonctionnalités</a> |
|
<a href="https://docs.langbot.app/en/insight/features.html">Fonctionnalités</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/guide">Documentation</a> |
|
<a href="https://docs.langbot.app/en/insight/guide.html">Documentation</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/api">API</a> |
|
<a href="https://docs.langbot.app/en/tags/readme.html">API</a> |
|
||||||
<a href="https://space.langbot.app">Marché des Plugins</a> |
|
<a href="https://space.langbot.app">Marché des Plugins</a> |
|
||||||
<a href="https://langbot.featurebase.app/roadmap">Feuille de Route</a>
|
<a href="https://langbot.featurebase.app/roadmap">Feuille de Route</a>
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ LangBot est une **plateforme open-source de niveau production** pour créer des
|
|||||||
- **Panneau de Gestion Web** — Configurez, gérez et surveillez vos bots via une interface navigateur intuitive. Aucune édition de YAML requise.
|
- **Panneau de Gestion Web** — Configurez, gérez et surveillez vos bots via une interface navigateur intuitive. Aucune édition de YAML requise.
|
||||||
- **Architecture Multi-Pipeline** — Différents bots pour différents scénarios, avec surveillance complète et gestion des exceptions.
|
- **Architecture Multi-Pipeline** — Différents bots pour différents scénarios, avec surveillance complète et gestion des exceptions.
|
||||||
|
|
||||||
[→ En savoir plus sur toutes les fonctionnalités](https://link.langbot.app/en/docs/features)
|
[→ En savoir plus sur toutes les fonctionnalités](https://docs.langbot.app/en/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ docker compose up -d
|
|||||||
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
||||||
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
||||||
|
|
||||||
**Plus d'options :** [Docker](https://link.langbot.app/en/docs/docker) · [Manuel](https://link.langbot.app/en/docs/manual-deploy) · [BTPanel](https://link.langbot.app/en/docs/bt-panel) · [Kubernetes](./docker/README_K8S.md)
|
**Plus d'options :** [Docker](https://docs.langbot.app/en/deploy/langbot/docker.html) · [Manuel](https://docs.langbot.app/en/deploy/langbot/manual.html) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ docker compose up -d
|
|||||||
| [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | Plateforme GPU | ✅ |
|
| [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | Plateforme GPU | ✅ |
|
||||||
| [ShengSuanYun](https://www.shengsuanyun.com/?from=CH_KYIPP758) | Plateforme GPU | ✅ |
|
| [ShengSuanYun](https://www.shengsuanyun.com/?from=CH_KYIPP758) | Plateforme GPU | ✅ |
|
||||||
|
|
||||||
[→ Voir toutes les intégrations](https://link.langbot.app/en/docs/features)
|
[→ Voir toutes les intégrations](https://docs.langbot.app/en/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -19,9 +19,9 @@
|
|||||||
[](https://github.com/langbot-app/LangBot/stargazers)
|
[](https://github.com/langbot-app/LangBot/stargazers)
|
||||||
|
|
||||||
<a href="https://langbot.app">ホーム</a> |
|
<a href="https://langbot.app">ホーム</a> |
|
||||||
<a href="https://link.langbot.app/ja/docs/features">機能</a> |
|
<a href="https://docs.langbot.app/ja/insight/features.html">機能</a> |
|
||||||
<a href="https://link.langbot.app/ja/docs/guide">ドキュメント</a> |
|
<a href="https://docs.langbot.app/ja/insight/guide.html">ドキュメント</a> |
|
||||||
<a href="https://link.langbot.app/ja/docs/api">API</a> |
|
<a href="https://docs.langbot.app/ja/tags/readme.html">API</a> |
|
||||||
<a href="https://space.langbot.app">プラグインマーケット</a> |
|
<a href="https://space.langbot.app">プラグインマーケット</a> |
|
||||||
<a href="https://langbot.featurebase.app/roadmap">ロードマップ</a>
|
<a href="https://langbot.featurebase.app/roadmap">ロードマップ</a>
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ LangBot は、AI搭載のインスタントメッセージングボットを構
|
|||||||
- **Web管理パネル** — 直感的なブラウザインターフェースからボットの設定、管理、監視が可能。YAML編集は不要。
|
- **Web管理パネル** — 直感的なブラウザインターフェースからボットの設定、管理、監視が可能。YAML編集は不要。
|
||||||
- **マルチパイプラインアーキテクチャ** — 異なるシナリオに異なるボットを配置し、包括的な監視と例外処理を実現。
|
- **マルチパイプラインアーキテクチャ** — 異なるシナリオに異なるボットを配置し、包括的な監視と例外処理を実現。
|
||||||
|
|
||||||
[→ すべての機能について詳しく見る](https://link.langbot.app/ja/docs/features)
|
[→ すべての機能について詳しく見る](https://docs.langbot.app/ja/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ docker compose up -d
|
|||||||
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
||||||
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
||||||
|
|
||||||
**その他:** [Docker](https://link.langbot.app/en/docs/docker) · [手動デプロイ](https://link.langbot.app/en/docs/manual-deploy) · [BTPanel](https://link.langbot.app/en/docs/bt-panel) · [Kubernetes](./docker/README_K8S.md)
|
**その他:** [Docker](https://docs.langbot.app/en/deploy/langbot/docker.html) · [手動デプロイ](https://docs.langbot.app/en/deploy/langbot/manual.html) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ docker compose up -d
|
|||||||
| [接口 AI](https://jiekou.ai/) | ゲートウェイ | ✅ |
|
| [接口 AI](https://jiekou.ai/) | ゲートウェイ | ✅ |
|
||||||
| [302.AI](https://share.302.ai/SuTG99) | ゲートウェイ | ✅ |
|
| [302.AI](https://share.302.ai/SuTG99) | ゲートウェイ | ✅ |
|
||||||
|
|
||||||
[→ すべての統合を表示](https://link.langbot.app/en/docs/features)
|
[→ すべての統合を表示](https://docs.langbot.app/en/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -19,9 +19,9 @@
|
|||||||
[](https://github.com/langbot-app/LangBot/stargazers)
|
[](https://github.com/langbot-app/LangBot/stargazers)
|
||||||
|
|
||||||
<a href="https://langbot.app">홈</a> |
|
<a href="https://langbot.app">홈</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/features">기능</a> |
|
<a href="https://docs.langbot.app/en/insight/features.html">기능</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/guide">문서</a> |
|
<a href="https://docs.langbot.app/en/insight/guide.html">문서</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/api">API</a> |
|
<a href="https://docs.langbot.app/en/tags/readme.html">API</a> |
|
||||||
<a href="https://space.langbot.app">플러그인 마켓</a> |
|
<a href="https://space.langbot.app">플러그인 마켓</a> |
|
||||||
<a href="https://langbot.featurebase.app/roadmap">로드맵</a>
|
<a href="https://langbot.featurebase.app/roadmap">로드맵</a>
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ LangBot은 AI 기반 인스턴트 메시징 봇을 구축하기 위한 **오픈
|
|||||||
- **웹 관리 패널** — 직관적인 브라우저 인터페이스로 봇을 구성, 관리 및 모니터링. YAML 편집 불필요.
|
- **웹 관리 패널** — 직관적인 브라우저 인터페이스로 봇을 구성, 관리 및 모니터링. YAML 편집 불필요.
|
||||||
- **멀티 파이프라인 아키텍처** — 다양한 시나리오에 맞는 다양한 봇 구성, 종합 모니터링 및 예외 처리.
|
- **멀티 파이프라인 아키텍처** — 다양한 시나리오에 맞는 다양한 봇 구성, 종합 모니터링 및 예외 처리.
|
||||||
|
|
||||||
[→ 모든 기능 자세히 보기](https://link.langbot.app/en/docs/features)
|
[→ 모든 기능 자세히 보기](https://docs.langbot.app/en/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ docker compose up -d
|
|||||||
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
||||||
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
||||||
|
|
||||||
**더 많은 옵션:** [Docker](https://link.langbot.app/en/docs/docker) · [수동 배포](https://link.langbot.app/en/docs/manual-deploy) · [BTPanel](https://link.langbot.app/en/docs/bt-panel) · [Kubernetes](./docker/README_K8S.md)
|
**더 많은 옵션:** [Docker](https://docs.langbot.app/en/deploy/langbot/docker.html) · [수동 배포](https://docs.langbot.app/en/deploy/langbot/manual.html) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ docker compose up -d
|
|||||||
| [接口 AI](https://jiekou.ai/) | 게이트웨이 | ✅ |
|
| [接口 AI](https://jiekou.ai/) | 게이트웨이 | ✅ |
|
||||||
| [302.AI](https://share.302.ai/SuTG99) | 게이트웨이 | ✅ |
|
| [302.AI](https://share.302.ai/SuTG99) | 게이트웨이 | ✅ |
|
||||||
|
|
||||||
[→ 모든 통합 보기](https://link.langbot.app/en/docs/features)
|
[→ 모든 통합 보기](https://docs.langbot.app/en/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -19,9 +19,9 @@
|
|||||||
[](https://github.com/langbot-app/LangBot/stargazers)
|
[](https://github.com/langbot-app/LangBot/stargazers)
|
||||||
|
|
||||||
<a href="https://langbot.app">Главная</a> |
|
<a href="https://langbot.app">Главная</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/features">Возможности</a> |
|
<a href="https://docs.langbot.app/en/insight/features.html">Возможности</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/guide">Документация</a> |
|
<a href="https://docs.langbot.app/en/insight/guide.html">Документация</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/api">API</a> |
|
<a href="https://docs.langbot.app/en/tags/readme.html">API</a> |
|
||||||
<a href="https://space.langbot.app">Магазин плагинов</a> |
|
<a href="https://space.langbot.app">Магазин плагинов</a> |
|
||||||
<a href="https://langbot.featurebase.app/roadmap">Дорожная карта</a>
|
<a href="https://langbot.featurebase.app/roadmap">Дорожная карта</a>
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ LangBot — это **платформа с открытым исходным к
|
|||||||
- **Веб-панель управления** — Настраивайте, управляйте и мониторьте ваших ботов через интуитивный браузерный интерфейс. Ручное редактирование YAML не требуется.
|
- **Веб-панель управления** — Настраивайте, управляйте и мониторьте ваших ботов через интуитивный браузерный интерфейс. Ручное редактирование YAML не требуется.
|
||||||
- **Мультиконвейерная архитектура** — Разные боты для разных сценариев с комплексным мониторингом и обработкой исключений.
|
- **Мультиконвейерная архитектура** — Разные боты для разных сценариев с комплексным мониторингом и обработкой исключений.
|
||||||
|
|
||||||
[→ Подробнее обо всех возможностях](https://link.langbot.app/en/docs/features)
|
[→ Подробнее обо всех возможностях](https://docs.langbot.app/en/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ docker compose up -d
|
|||||||
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
||||||
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
||||||
|
|
||||||
**Другие варианты:** [Docker](https://link.langbot.app/en/docs/docker) · [Ручная установка](https://link.langbot.app/en/docs/manual-deploy) · [BTPanel](https://link.langbot.app/en/docs/bt-panel) · [Kubernetes](./docker/README_K8S.md)
|
**Другие варианты:** [Docker](https://docs.langbot.app/en/deploy/langbot/docker.html) · [Ручная установка](https://docs.langbot.app/en/deploy/langbot/manual.html) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ docker compose up -d
|
|||||||
| [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | Платформа GPU | ✅ |
|
| [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | Платформа GPU | ✅ |
|
||||||
| [ShengSuanYun](https://www.shengsuanyun.com/?from=CH_KYIPP758) | Платформа GPU | ✅ |
|
| [ShengSuanYun](https://www.shengsuanyun.com/?from=CH_KYIPP758) | Платформа GPU | ✅ |
|
||||||
|
|
||||||
[→ Смотреть все интеграции](https://link.langbot.app/en/docs/features)
|
[→ Смотреть все интеграции](https://docs.langbot.app/en/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -21,9 +21,9 @@
|
|||||||
[](https://gitcode.com/RockChinQ/LangBot)
|
[](https://gitcode.com/RockChinQ/LangBot)
|
||||||
|
|
||||||
<a href="https://langbot.app">官網</a> |
|
<a href="https://langbot.app">官網</a> |
|
||||||
<a href="https://link.langbot.app/zh/docs/features">特性</a> |
|
<a href="https://docs.langbot.app/zh/insight/features.html">特性</a> |
|
||||||
<a href="https://link.langbot.app/zh/docs/guide">文件</a> |
|
<a href="https://docs.langbot.app/zh/insight/guide.html">文件</a> |
|
||||||
<a href="https://link.langbot.app/zh/docs/api">API</a> |
|
<a href="https://docs.langbot.app/zh/tags/readme.html">API</a> |
|
||||||
<a href="https://space.langbot.app">外掛市場</a> |
|
<a href="https://space.langbot.app">外掛市場</a> |
|
||||||
<a href="https://langbot.featurebase.app/roadmap">路線圖</a>
|
<a href="https://langbot.featurebase.app/roadmap">路線圖</a>
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ LangBot 是一個**開源的生產級平台**,用於建構 AI 驅動的即時
|
|||||||
- **Web 管理面板** — 透過瀏覽器直觀地配置、管理和監控機器人,無需手動編輯設定檔。
|
- **Web 管理面板** — 透過瀏覽器直觀地配置、管理和監控機器人,無需手動編輯設定檔。
|
||||||
- **多流水線架構** — 不同機器人用於不同場景,具備全面的監控和異常處理能力。
|
- **多流水線架構** — 不同機器人用於不同場景,具備全面的監控和異常處理能力。
|
||||||
|
|
||||||
[→ 了解更多功能特性](https://link.langbot.app/zh/docs/features)
|
[→ 了解更多功能特性](https://docs.langbot.app/zh/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ docker compose up -d
|
|||||||
[](https://zeabur.com/zh-CN/templates/ZKTBDH)
|
[](https://zeabur.com/zh-CN/templates/ZKTBDH)
|
||||||
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
||||||
|
|
||||||
**更多方式:** [Docker](https://link.langbot.app/zh/docs/docker) · [手動部署](https://link.langbot.app/zh/docs/manual-deploy) · [寶塔面板](https://link.langbot.app/zh/docs/bt-panel) · [Kubernetes](./docker/README_K8S.md)
|
**更多方式:** [Docker](https://docs.langbot.app/zh/deploy/langbot/docker.html) · [手動部署](https://docs.langbot.app/zh/deploy/langbot/manual.html) · [寶塔面板](https://docs.langbot.app/zh/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ docker compose up -d
|
|||||||
|-----------|------|
|
|-----------|------|
|
||||||
| 阿里雲百煉 | [外掛](https://github.com/Thetail001/LangBot_BailianTextToImagePlugin) |
|
| 阿里雲百煉 | [外掛](https://github.com/Thetail001/LangBot_BailianTextToImagePlugin) |
|
||||||
|
|
||||||
[→ 查看完整整合列表](https://link.langbot.app/zh/docs/features)
|
[→ 查看完整整合列表](https://docs.langbot.app/zh/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -19,9 +19,9 @@
|
|||||||
[](https://github.com/langbot-app/LangBot/stargazers)
|
[](https://github.com/langbot-app/LangBot/stargazers)
|
||||||
|
|
||||||
<a href="https://langbot.app">Trang chủ</a> |
|
<a href="https://langbot.app">Trang chủ</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/features">Tính năng</a> |
|
<a href="https://docs.langbot.app/en/insight/features.html">Tính năng</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/guide">Tài liệu</a> |
|
<a href="https://docs.langbot.app/en/insight/guide.html">Tài liệu</a> |
|
||||||
<a href="https://link.langbot.app/en/docs/api">API</a> |
|
<a href="https://docs.langbot.app/en/tags/readme.html">API</a> |
|
||||||
<a href="https://space.langbot.app">Chợ Plugin</a> |
|
<a href="https://space.langbot.app">Chợ Plugin</a> |
|
||||||
<a href="https://langbot.featurebase.app/roadmap">Lộ trình</a>
|
<a href="https://langbot.featurebase.app/roadmap">Lộ trình</a>
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ LangBot là một **nền tảng mã nguồn mở, cấp sản xuất** để x
|
|||||||
- **Bảng quản lý Web** — Cấu hình, quản lý và giám sát bot thông qua giao diện trình duyệt trực quan. Không cần chỉnh sửa YAML.
|
- **Bảng quản lý Web** — Cấu hình, quản lý và giám sát bot thông qua giao diện trình duyệt trực quan. Không cần chỉnh sửa YAML.
|
||||||
- **Kiến trúc đa Pipeline** — Các bot khác nhau cho các kịch bản khác nhau, với giám sát toàn diện và xử lý ngoại lệ.
|
- **Kiến trúc đa Pipeline** — Các bot khác nhau cho các kịch bản khác nhau, với giám sát toàn diện và xử lý ngoại lệ.
|
||||||
|
|
||||||
[→ Tìm hiểu thêm về tất cả tính năng](https://link.langbot.app/en/docs/features)
|
[→ Tìm hiểu thêm về tất cả tính năng](https://docs.langbot.app/en/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ docker compose up -d
|
|||||||
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
[](https://zeabur.com/en-US/templates/ZKTBDH)
|
||||||
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
[](https://railway.app/template/yRrAyL?referralCode=vogKPF)
|
||||||
|
|
||||||
**Thêm tùy chọn:** [Docker](https://link.langbot.app/en/docs/docker) · [Thủ công](https://link.langbot.app/en/docs/manual-deploy) · [BTPanel](https://link.langbot.app/en/docs/bt-panel) · [Kubernetes](./docker/README_K8S.md)
|
**Thêm tùy chọn:** [Docker](https://docs.langbot.app/en/deploy/langbot/docker.html) · [Thủ công](https://docs.langbot.app/en/deploy/langbot/manual.html) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ docker compose up -d
|
|||||||
| [接口 AI](https://jiekou.ai/) | Cổng | ✅ |
|
| [接口 AI](https://jiekou.ai/) | Cổng | ✅ |
|
||||||
| [302.AI](https://share.302.ai/SuTG99) | Cổng | ✅ |
|
| [302.AI](https://share.302.ai/SuTG99) | Cổng | ✅ |
|
||||||
|
|
||||||
[→ Xem tất cả tích hợp](https://link.langbot.app/en/docs/features)
|
[→ Xem tất cả tích hợp](https://docs.langbot.app/en/insight/features.html)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ spec:
|
|||||||
### 参考资源
|
### 参考资源
|
||||||
|
|
||||||
- [LangBot 官方文档](https://docs.langbot.app)
|
- [LangBot 官方文档](https://docs.langbot.app)
|
||||||
- [Docker 部署文档](https://link.langbot.app/zh/docs/docker)
|
- [Docker 部署文档](https://docs.langbot.app/zh/deploy/langbot/docker.html)
|
||||||
- [Kubernetes 官方文档](https://kubernetes.io/docs/)
|
- [Kubernetes 官方文档](https://kubernetes.io/docs/)
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -625,5 +625,5 @@ spec:
|
|||||||
### References
|
### References
|
||||||
|
|
||||||
- [LangBot Official Documentation](https://docs.langbot.app)
|
- [LangBot Official Documentation](https://docs.langbot.app)
|
||||||
- [Docker Deployment Guide](https://link.langbot.app/zh/docs/docker)
|
- [Docker Deployment Guide](https://docs.langbot.app/zh/deploy/langbot/docker.html)
|
||||||
- [Kubernetes Official Documentation](https://kubernetes.io/docs/)
|
- [Kubernetes Official Documentation](https://kubernetes.io/docs/)
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "langbot"
|
name = "langbot"
|
||||||
version = "4.9.5"
|
version = "4.9.4"
|
||||||
description = "Production-grade platform for building agentic IM bots"
|
description = "Production-grade platform for building agentic IM bots"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
@@ -64,7 +64,7 @@ dependencies = [
|
|||||||
"chromadb>=1.0.0,<2.0.0",
|
"chromadb>=1.0.0,<2.0.0",
|
||||||
"qdrant-client (>=1.15.1,<2.0.0)",
|
"qdrant-client (>=1.15.1,<2.0.0)",
|
||||||
"pyseekdb==1.1.0.post3",
|
"pyseekdb==1.1.0.post3",
|
||||||
"langbot-plugin==0.3.6",
|
"langbot-plugin==0.3.5",
|
||||||
"asyncpg>=0.30.0",
|
"asyncpg>=0.30.0",
|
||||||
"line-bot-sdk>=3.19.0",
|
"line-bot-sdk>=3.19.0",
|
||||||
"tboxsdk>=0.0.10",
|
"tboxsdk>=0.0.10",
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
"""LangBot - Production-grade platform for building agentic IM bots"""
|
"""LangBot - Production-grade platform for building agentic IM bots"""
|
||||||
|
|
||||||
__version__ = '4.9.5'
|
__version__ = '4.9.4'
|
||||||
|
|||||||
@@ -900,7 +900,8 @@ class WecomBotClient:
|
|||||||
session = self.stream_sessions.get_session_by_feedback_id(feedback_id)
|
session = self.stream_sessions.get_session_by_feedback_id(feedback_id)
|
||||||
if session:
|
if session:
|
||||||
await self.logger.info(
|
await self.logger.info(
|
||||||
f'反馈关联到会话: stream_id={session.stream_id}, msg_id={session.msg_id}, user_id={session.user_id}'
|
f'反馈关联到会话: stream_id={session.stream_id}, msg_id={session.msg_id}, '
|
||||||
|
f'user_id={session.user_id}'
|
||||||
)
|
)
|
||||||
for handler in self._message_handlers.get('feedback', []):
|
for handler in self._message_handlers.get('feedback', []):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1301,19 +1301,28 @@ class MonitoringService:
|
|||||||
satisfaction_rate = (total_likes / total_feedback * 100) if total_feedback > 0 else 0
|
satisfaction_rate = (total_likes / total_feedback * 100) if total_feedback > 0 else 0
|
||||||
|
|
||||||
# Get feedback by bot
|
# Get feedback by bot
|
||||||
bot_stats_query = sqlalchemy.select(
|
bot_stats_query = (
|
||||||
persistence_monitoring.MonitoringFeedback.bot_id,
|
sqlalchemy.select(
|
||||||
persistence_monitoring.MonitoringFeedback.bot_name,
|
persistence_monitoring.MonitoringFeedback.bot_id,
|
||||||
sqlalchemy.func.count(persistence_monitoring.MonitoringFeedback.id).label('total'),
|
persistence_monitoring.MonitoringFeedback.bot_name,
|
||||||
sqlalchemy.func.sum(
|
sqlalchemy.func.count(persistence_monitoring.MonitoringFeedback.id).label('total'),
|
||||||
sqlalchemy.case((persistence_monitoring.MonitoringFeedback.feedback_type == 1, 1), else_=0)
|
sqlalchemy.func.sum(
|
||||||
).label('likes'),
|
sqlalchemy.case(
|
||||||
sqlalchemy.func.sum(
|
(persistence_monitoring.MonitoringFeedback.feedback_type == 1, 1),
|
||||||
sqlalchemy.case((persistence_monitoring.MonitoringFeedback.feedback_type == 2, 1), else_=0)
|
else_=0
|
||||||
).label('dislikes'),
|
)
|
||||||
).group_by(
|
).label('likes'),
|
||||||
persistence_monitoring.MonitoringFeedback.bot_id,
|
sqlalchemy.func.sum(
|
||||||
persistence_monitoring.MonitoringFeedback.bot_name,
|
sqlalchemy.case(
|
||||||
|
(persistence_monitoring.MonitoringFeedback.feedback_type == 2, 1),
|
||||||
|
else_=0
|
||||||
|
)
|
||||||
|
).label('dislikes'),
|
||||||
|
)
|
||||||
|
.group_by(
|
||||||
|
persistence_monitoring.MonitoringFeedback.bot_id,
|
||||||
|
persistence_monitoring.MonitoringFeedback.bot_name,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
if conditions:
|
if conditions:
|
||||||
bot_stats_query = bot_stats_query.where(sqlalchemy.and_(*conditions))
|
bot_stats_query = bot_stats_query.where(sqlalchemy.and_(*conditions))
|
||||||
@@ -1424,9 +1433,7 @@ class MonitoringService:
|
|||||||
'id': row[0].id if isinstance(row, tuple) else row.id,
|
'id': row[0].id if isinstance(row, tuple) else row.id,
|
||||||
'timestamp': self._format_timestamp(row[0].timestamp if isinstance(row, tuple) else row.timestamp),
|
'timestamp': self._format_timestamp(row[0].timestamp if isinstance(row, tuple) else row.timestamp),
|
||||||
'feedback_id': row[0].feedback_id if isinstance(row, tuple) else row.feedback_id,
|
'feedback_id': row[0].feedback_id if isinstance(row, tuple) else row.feedback_id,
|
||||||
'feedback_type': 'like'
|
'feedback_type': 'like' if (row[0].feedback_type if isinstance(row, tuple) else row.feedback_type) == 1 else 'dislike',
|
||||||
if (row[0].feedback_type if isinstance(row, tuple) else row.feedback_type) == 1
|
|
||||||
else 'dislike',
|
|
||||||
'feedback_content': row[0].feedback_content if isinstance(row, tuple) else row.feedback_content,
|
'feedback_content': row[0].feedback_content if isinstance(row, tuple) else row.feedback_content,
|
||||||
'inaccurate_reasons': row[0].inaccurate_reasons if isinstance(row, tuple) else row.inaccurate_reasons,
|
'inaccurate_reasons': row[0].inaccurate_reasons if isinstance(row, tuple) else row.inaccurate_reasons,
|
||||||
'bot_id': row[0].bot_id if isinstance(row, tuple) else row.bot_id,
|
'bot_id': row[0].bot_id if isinstance(row, tuple) else row.bot_id,
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import sqlalchemy
|
||||||
|
from .. import migration
|
||||||
|
|
||||||
|
|
||||||
|
@migration.migration_class(25)
|
||||||
|
class DBMigrateFeedbackStats(migration.DBMigration):
|
||||||
|
"""Add monitoring_feedback table for storing user feedback from AI Bot conversations"""
|
||||||
|
|
||||||
|
async def _table_exists(self, table_name: str) -> bool:
|
||||||
|
"""Check if a table exists (works for both SQLite and PostgreSQL)."""
|
||||||
|
if self.ap.persistence_mgr.db.name == 'postgresql':
|
||||||
|
result = await self.ap.persistence_mgr.execute_async(
|
||||||
|
sqlalchemy.text(
|
||||||
|
'SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = :table_name);'
|
||||||
|
).bindparams(table_name=table_name)
|
||||||
|
)
|
||||||
|
return bool(result.scalar())
|
||||||
|
else:
|
||||||
|
result = await self.ap.persistence_mgr.execute_async(
|
||||||
|
sqlalchemy.text("SELECT name FROM sqlite_master WHERE type='table' AND name=:table_name;").bindparams(
|
||||||
|
table_name=table_name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return result.first() is not None
|
||||||
|
|
||||||
|
async def upgrade(self):
|
||||||
|
"""Create monitoring_feedback table."""
|
||||||
|
if await self._table_exists('monitoring_feedback'):
|
||||||
|
self.ap.logger.debug('monitoring_feedback table already exists, skipping migration.')
|
||||||
|
return
|
||||||
|
|
||||||
|
# Create monitoring_feedback table with all columns
|
||||||
|
create_table_sql = '''
|
||||||
|
CREATE TABLE monitoring_feedback (
|
||||||
|
id VARCHAR(255) PRIMARY KEY,
|
||||||
|
timestamp DATETIME NOT NULL,
|
||||||
|
feedback_id VARCHAR(255) NOT NULL UNIQUE,
|
||||||
|
feedback_type INTEGER NOT NULL,
|
||||||
|
feedback_content TEXT,
|
||||||
|
inaccurate_reasons TEXT,
|
||||||
|
bot_id VARCHAR(255),
|
||||||
|
bot_name VARCHAR(255),
|
||||||
|
pipeline_id VARCHAR(255),
|
||||||
|
pipeline_name VARCHAR(255),
|
||||||
|
session_id VARCHAR(255),
|
||||||
|
message_id VARCHAR(255),
|
||||||
|
stream_id VARCHAR(255),
|
||||||
|
user_id VARCHAR(255),
|
||||||
|
platform VARCHAR(255)
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
await self.ap.persistence_mgr.execute_async(sqlalchemy.text(create_table_sql))
|
||||||
|
|
||||||
|
# Create indexes
|
||||||
|
indexes = [
|
||||||
|
'CREATE INDEX ix_monitoring_feedback_timestamp ON monitoring_feedback (timestamp)',
|
||||||
|
'CREATE UNIQUE INDEX ix_monitoring_feedback_feedback_id ON monitoring_feedback (feedback_id)',
|
||||||
|
'CREATE INDEX ix_monitoring_feedback_bot_id ON monitoring_feedback (bot_id)',
|
||||||
|
'CREATE INDEX ix_monitoring_feedback_pipeline_id ON monitoring_feedback (pipeline_id)',
|
||||||
|
'CREATE INDEX ix_monitoring_feedback_session_id ON monitoring_feedback (session_id)',
|
||||||
|
'CREATE INDEX ix_monitoring_feedback_message_id ON monitoring_feedback (message_id)',
|
||||||
|
'CREATE INDEX ix_monitoring_feedback_stream_id ON monitoring_feedback (stream_id)',
|
||||||
|
]
|
||||||
|
for index_sql in indexes:
|
||||||
|
await self.ap.persistence_mgr.execute_async(sqlalchemy.text(index_sql))
|
||||||
|
|
||||||
|
self.ap.logger.info('Created monitoring_feedback table with indexes.')
|
||||||
|
|
||||||
|
async def downgrade(self):
|
||||||
|
"""Drop monitoring_feedback table."""
|
||||||
|
if await self._table_exists('monitoring_feedback'):
|
||||||
|
await self.ap.persistence_mgr.execute_async(
|
||||||
|
sqlalchemy.text('DROP TABLE monitoring_feedback')
|
||||||
|
)
|
||||||
|
self.ap.logger.info('Dropped monitoring_feedback table.')
|
||||||
@@ -353,3 +353,62 @@ class LLMCallMonitor:
|
|||||||
)
|
)
|
||||||
|
|
||||||
return False # Don't suppress exceptions
|
return False # Don't suppress exceptions
|
||||||
|
|
||||||
|
|
||||||
|
class FeedbackMonitor:
|
||||||
|
"""Helper for recording user feedback from AI Bot conversations"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def record_feedback(
|
||||||
|
ap: app.Application,
|
||||||
|
feedback_id: str,
|
||||||
|
feedback_type: int,
|
||||||
|
feedback_content: str | None = None,
|
||||||
|
inaccurate_reasons: list[str] | None = None,
|
||||||
|
bot_id: str | None = None,
|
||||||
|
bot_name: str | None = None,
|
||||||
|
pipeline_id: str | None = None,
|
||||||
|
pipeline_name: str | None = None,
|
||||||
|
session_id: str | None = None,
|
||||||
|
message_id: str | None = None,
|
||||||
|
stream_id: str | None = None,
|
||||||
|
user_id: str | None = None,
|
||||||
|
platform: str = 'wecom',
|
||||||
|
):
|
||||||
|
"""Record user feedback (like/dislike) from AI Bot conversation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ap: Application instance
|
||||||
|
feedback_id: Unique feedback identifier from platform
|
||||||
|
feedback_type: 1 = like, 2 = dislike
|
||||||
|
feedback_content: Optional user feedback text
|
||||||
|
inaccurate_reasons: List of reasons for inaccurate response
|
||||||
|
bot_id: Bot UUID
|
||||||
|
bot_name: Bot name
|
||||||
|
pipeline_id: Pipeline UUID
|
||||||
|
pipeline_name: Pipeline name
|
||||||
|
session_id: Session ID
|
||||||
|
message_id: Message ID
|
||||||
|
stream_id: Stream ID
|
||||||
|
user_id: User ID
|
||||||
|
platform: Platform name (default: wecom)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
await ap.monitoring_service.record_feedback(
|
||||||
|
feedback_id=feedback_id,
|
||||||
|
feedback_type=feedback_type,
|
||||||
|
feedback_content=feedback_content,
|
||||||
|
inaccurate_reasons=inaccurate_reasons,
|
||||||
|
bot_id=bot_id,
|
||||||
|
bot_name=bot_name,
|
||||||
|
pipeline_id=pipeline_id,
|
||||||
|
pipeline_name=pipeline_name,
|
||||||
|
session_id=session_id,
|
||||||
|
message_id=message_id,
|
||||||
|
stream_id=stream_id,
|
||||||
|
user_id=user_id,
|
||||||
|
platform=platform,
|
||||||
|
)
|
||||||
|
ap.logger.info(f'Recorded feedback: feedback_id={feedback_id}, type={feedback_type}')
|
||||||
|
except Exception as e:
|
||||||
|
ap.logger.error(f'Failed to record feedback: {e}')
|
||||||
|
|||||||
@@ -142,50 +142,6 @@ class RuntimeBot:
|
|||||||
self.adapter.register_listener(platform_events.FriendMessage, on_friend_message)
|
self.adapter.register_listener(platform_events.FriendMessage, on_friend_message)
|
||||||
self.adapter.register_listener(platform_events.GroupMessage, on_group_message)
|
self.adapter.register_listener(platform_events.GroupMessage, on_group_message)
|
||||||
|
|
||||||
# Register feedback listener (only effective on adapters that support it)
|
|
||||||
async def on_feedback(
|
|
||||||
event: platform_events.FeedbackEvent,
|
|
||||||
adapter: abstract_platform_adapter.AbstractMessagePlatformAdapter,
|
|
||||||
):
|
|
||||||
try:
|
|
||||||
# Resolve pipeline name
|
|
||||||
pipeline_name = ''
|
|
||||||
if self.bot_entity.use_pipeline_uuid:
|
|
||||||
try:
|
|
||||||
pipeline_result = await self.ap.persistence_mgr.execute_async(
|
|
||||||
sqlalchemy.select(persistence_pipeline.LegacyPipeline.name).where(
|
|
||||||
persistence_pipeline.LegacyPipeline.uuid == self.bot_entity.use_pipeline_uuid
|
|
||||||
)
|
|
||||||
)
|
|
||||||
pipeline_row = pipeline_result.first()
|
|
||||||
if pipeline_row:
|
|
||||||
pipeline_name = pipeline_row[0]
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
await self.ap.monitoring_service.record_feedback(
|
|
||||||
feedback_id=event.feedback_id,
|
|
||||||
feedback_type=event.feedback_type,
|
|
||||||
feedback_content=event.feedback_content,
|
|
||||||
inaccurate_reasons=event.inaccurate_reasons,
|
|
||||||
bot_id=self.bot_entity.uuid,
|
|
||||||
bot_name=self.bot_entity.name,
|
|
||||||
pipeline_id=self.bot_entity.use_pipeline_uuid or '',
|
|
||||||
pipeline_name=pipeline_name,
|
|
||||||
session_id=event.session_id,
|
|
||||||
message_id=event.message_id,
|
|
||||||
stream_id=event.stream_id,
|
|
||||||
user_id=event.user_id,
|
|
||||||
platform=adapter.__class__.__name__,
|
|
||||||
)
|
|
||||||
await self.logger.info(
|
|
||||||
f'Recorded feedback: feedback_id={event.feedback_id}, type={event.feedback_type}'
|
|
||||||
)
|
|
||||||
except Exception:
|
|
||||||
await self.logger.error(f'Failed to record feedback: {traceback.format_exc()}')
|
|
||||||
|
|
||||||
self.adapter.register_listener(platform_events.FeedbackEvent, on_feedback)
|
|
||||||
|
|
||||||
async def run(self):
|
async def run(self):
|
||||||
async def exception_wrapper():
|
async def exception_wrapper():
|
||||||
try:
|
try:
|
||||||
@@ -312,12 +268,35 @@ class PlatformManager:
|
|||||||
adapter_inst = self.adapter_dict[bot_entity.adapter](
|
adapter_inst = self.adapter_dict[bot_entity.adapter](
|
||||||
bot_entity.adapter_config,
|
bot_entity.adapter_config,
|
||||||
logger,
|
logger,
|
||||||
|
ap=self.ap,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 如果 adapter 支持 set_bot_uuid 方法,设置 bot_uuid(用于统一 webhook)
|
# 如果 adapter 支持 set_bot_uuid 方法,设置 bot_uuid(用于统一 webhook)
|
||||||
if hasattr(adapter_inst, 'set_bot_uuid'):
|
if hasattr(adapter_inst, 'set_bot_uuid'):
|
||||||
adapter_inst.set_bot_uuid(bot_entity.uuid)
|
adapter_inst.set_bot_uuid(bot_entity.uuid)
|
||||||
|
|
||||||
|
# 如果 adapter 支持 set_bot_info 方法,设置 bot 信息(用于监控记录)
|
||||||
|
if hasattr(adapter_inst, 'set_bot_info'):
|
||||||
|
pipeline_name = ''
|
||||||
|
if bot_entity.use_pipeline_uuid:
|
||||||
|
try:
|
||||||
|
pipeline_result = await self.ap.persistence_mgr.execute_async(
|
||||||
|
sqlalchemy.select(persistence_pipeline.LegacyPipeline.name).where(
|
||||||
|
persistence_pipeline.LegacyPipeline.uuid == bot_entity.use_pipeline_uuid
|
||||||
|
)
|
||||||
|
)
|
||||||
|
pipeline_row = pipeline_result.first()
|
||||||
|
if pipeline_row:
|
||||||
|
pipeline_name = pipeline_row[0]
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
adapter_inst.set_bot_info(
|
||||||
|
bot_id=bot_entity.uuid,
|
||||||
|
bot_name=bot_entity.name,
|
||||||
|
pipeline_id=bot_entity.use_pipeline_uuid or '',
|
||||||
|
pipeline_name=pipeline_name,
|
||||||
|
)
|
||||||
|
|
||||||
runtime_bot = RuntimeBot(ap=self.ap, bot_entity=bot_entity, adapter=adapter_inst, logger=logger)
|
runtime_bot = RuntimeBot(ap=self.ap, bot_entity=bot_entity, adapter=adapter_inst, logger=logger)
|
||||||
|
|
||||||
await runtime_bot.initialize()
|
await runtime_bot.initialize()
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
categories:
|
categories:
|
||||||
- protocol
|
- protocol
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/aiocqhttp
|
|
||||||
en: https://link.langbot.app/en/platforms/aiocqhttp
|
|
||||||
ja: https://link.langbot.app/ja/platforms/aiocqhttp
|
|
||||||
config:
|
config:
|
||||||
- name: host
|
- name: host
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ class DingTalkAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
|
|||||||
dict # 回复卡片消息字典,key为消息id,value为回复卡片实例id,用于在流式消息时判断是否发送到指定卡片
|
dict # 回复卡片消息字典,key为消息id,value为回复卡片实例id,用于在流式消息时判断是否发送到指定卡片
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, config: dict, logger: EventLogger):
|
def __init__(self, config: dict, logger: EventLogger, ap=None, **kwargs):
|
||||||
required_keys = [
|
required_keys = [
|
||||||
'client_id',
|
'client_id',
|
||||||
'client_secret',
|
'client_secret',
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
categories:
|
categories:
|
||||||
- china
|
- china
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/dingtalk
|
|
||||||
en: https://link.langbot.app/en/platforms/dingtalk
|
|
||||||
ja: https://link.langbot.app/ja/platforms/dingtalk
|
|
||||||
config:
|
config:
|
||||||
- name: client_id
|
- name: client_id
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -23,10 +23,6 @@ spec:
|
|||||||
categories:
|
categories:
|
||||||
- popular
|
- popular
|
||||||
- global
|
- global
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/discord
|
|
||||||
en: https://link.langbot.app/en/platforms/discord
|
|
||||||
ja: https://link.langbot.app/ja/platforms/discord
|
|
||||||
config:
|
config:
|
||||||
- name: client_id
|
- name: client_id
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
categories:
|
categories:
|
||||||
- china
|
- china
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/kook
|
|
||||||
en: https://link.langbot.app/en/platforms/kook
|
|
||||||
ja: https://link.langbot.app/ja/platforms/kook
|
|
||||||
config:
|
config:
|
||||||
- name: token
|
- name: token
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -18,10 +18,6 @@ spec:
|
|||||||
- popular
|
- popular
|
||||||
- china
|
- china
|
||||||
- global
|
- global
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/lark
|
|
||||||
en: https://link.langbot.app/en/platforms/lark
|
|
||||||
ja: https://link.langbot.app/ja/platforms/lark
|
|
||||||
config:
|
config:
|
||||||
- name: app_id
|
- name: app_id
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ class LINEAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
|
|||||||
|
|
||||||
seq: int # 用于在发送卡片消息中识别消息顺序,直接以seq作为标识
|
seq: int # 用于在发送卡片消息中识别消息顺序,直接以seq作为标识
|
||||||
|
|
||||||
def __init__(self, config: dict, logger: EventLogger):
|
def __init__(self, config: dict, logger: EventLogger, ap=None, **kwargs):
|
||||||
configuration = Configuration(access_token=config['channel_access_token'])
|
configuration = Configuration(access_token=config['channel_access_token'])
|
||||||
line_webhook = WebhookHandler(config['channel_secret'])
|
line_webhook = WebhookHandler(config['channel_secret'])
|
||||||
parser = WebhookParser(config['channel_secret'])
|
parser = WebhookParser(config['channel_secret'])
|
||||||
|
|||||||
@@ -21,10 +21,6 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
categories:
|
categories:
|
||||||
- global
|
- global
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/line
|
|
||||||
en: https://link.langbot.app/en/platforms/line
|
|
||||||
ja: https://link.langbot.app/ja/platforms/line
|
|
||||||
config:
|
config:
|
||||||
- name: webhook_url
|
- name: webhook_url
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class OfficialAccountAdapter(abstract_platform_adapter.AbstractMessagePlatformAd
|
|||||||
bot: typing.Union[OAClient, OAClientForLongerResponse] = pydantic.Field(exclude=True)
|
bot: typing.Union[OAClient, OAClientForLongerResponse] = pydantic.Field(exclude=True)
|
||||||
bot_uuid: str = None
|
bot_uuid: str = None
|
||||||
|
|
||||||
def __init__(self, config: dict, logger: EventLogger):
|
def __init__(self, config: dict, logger: EventLogger, ap=None, **kwargs):
|
||||||
# 校验必填项
|
# 校验必填项
|
||||||
required_keys = ['token', 'EncodingAESKey', 'AppSecret', 'AppID', 'Mode']
|
required_keys = ['token', 'EncodingAESKey', 'AppSecret', 'AppID', 'Mode']
|
||||||
missing_keys = [k for k in required_keys if k not in config]
|
missing_keys = [k for k in required_keys if k not in config]
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
categories:
|
categories:
|
||||||
- china
|
- china
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/officialaccount
|
|
||||||
en: https://link.langbot.app/en/platforms/officialaccount
|
|
||||||
ja: https://link.langbot.app/ja/platforms/officialaccount
|
|
||||||
config:
|
config:
|
||||||
- name: webhook_url
|
- name: webhook_url
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ spec:
|
|||||||
categories:
|
categories:
|
||||||
- popular
|
- popular
|
||||||
- china
|
- china
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/openclaw_weixin
|
|
||||||
en: https://link.langbot.app/en/platforms/openclaw_weixin
|
|
||||||
ja: https://link.langbot.app/ja/platforms/openclaw_weixin
|
|
||||||
config:
|
config:
|
||||||
- name: base_url
|
- name: base_url
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ class QQOfficialAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter
|
|||||||
message_converter: QQOfficialMessageConverter = QQOfficialMessageConverter()
|
message_converter: QQOfficialMessageConverter = QQOfficialMessageConverter()
|
||||||
event_converter: QQOfficialEventConverter = QQOfficialEventConverter()
|
event_converter: QQOfficialEventConverter = QQOfficialEventConverter()
|
||||||
|
|
||||||
def __init__(self, config: dict, logger: EventLogger):
|
def __init__(self, config: dict, logger: EventLogger, ap=None, **kwargs):
|
||||||
bot = QQOfficialClient(
|
bot = QQOfficialClient(
|
||||||
app_id=config['appid'], secret=config['secret'], token=config['token'], logger=logger, unified_mode=True
|
app_id=config['appid'], secret=config['secret'], token=config['token'], logger=logger, unified_mode=True
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
categories:
|
categories:
|
||||||
- china
|
- china
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/qqofficial
|
|
||||||
en: https://link.langbot.app/en/platforms/qqofficial
|
|
||||||
ja: https://link.langbot.app/ja/platforms/qqofficial
|
|
||||||
config:
|
config:
|
||||||
- name: webhook_url
|
- name: webhook_url
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -20,10 +20,6 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
categories:
|
categories:
|
||||||
- protocol
|
- protocol
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/satori
|
|
||||||
en: https://link.langbot.app/en/platforms/satori
|
|
||||||
ja: https://link.langbot.app/ja/platforms/satori
|
|
||||||
config:
|
config:
|
||||||
- name: platform
|
- name: platform
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ class SlackAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
|
|||||||
event_converter: SlackEventConverter = SlackEventConverter()
|
event_converter: SlackEventConverter = SlackEventConverter()
|
||||||
config: dict
|
config: dict
|
||||||
|
|
||||||
def __init__(self, config: dict, logger: EventLogger):
|
def __init__(self, config: dict, logger: EventLogger, ap=None, **kwargs):
|
||||||
required_keys = [
|
required_keys = [
|
||||||
'bot_token',
|
'bot_token',
|
||||||
'signing_secret',
|
'signing_secret',
|
||||||
|
|||||||
@@ -23,10 +23,6 @@ spec:
|
|||||||
categories:
|
categories:
|
||||||
- popular
|
- popular
|
||||||
- global
|
- global
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/slack
|
|
||||||
en: https://link.langbot.app/en/platforms/slack
|
|
||||||
ja: https://link.langbot.app/ja/platforms/slack
|
|
||||||
config:
|
config:
|
||||||
- name: webhook_url
|
- name: webhook_url
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -23,10 +23,6 @@ spec:
|
|||||||
categories:
|
categories:
|
||||||
- popular
|
- popular
|
||||||
- global
|
- global
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/telegram
|
|
||||||
en: https://link.langbot.app/en/platforms/telegram
|
|
||||||
ja: https://link.langbot.app/ja/platforms/telegram
|
|
||||||
config:
|
config:
|
||||||
- name: token
|
- name: token
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -539,7 +539,7 @@ class WeChatPadAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter)
|
|||||||
typing.Callable[[platform_events.Event, abstract_platform_adapter.AbstractMessagePlatformAdapter], None],
|
typing.Callable[[platform_events.Event, abstract_platform_adapter.AbstractMessagePlatformAdapter], None],
|
||||||
] = {}
|
] = {}
|
||||||
|
|
||||||
def __init__(self, config: dict, logger: EventLogger):
|
def __init__(self, config: dict, logger: EventLogger, ap=None, **kwargs):
|
||||||
quart_app = quart.Quart(__name__)
|
quart_app = quart.Quart(__name__)
|
||||||
|
|
||||||
message_converter = WeChatPadMessageConverter(config, logger)
|
message_converter = WeChatPadMessageConverter(config, logger)
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
categories:
|
categories:
|
||||||
- china
|
- china
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/wechatpad
|
|
||||||
en: https://link.langbot.app/en/platforms/wechatpad
|
|
||||||
ja: https://link.langbot.app/ja/platforms/wechatpad
|
|
||||||
config:
|
config:
|
||||||
- name: wechatpad_url
|
- name: wechatpad_url
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ class WecomAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
|
|||||||
config: dict
|
config: dict
|
||||||
bot_uuid: str = None
|
bot_uuid: str = None
|
||||||
|
|
||||||
def __init__(self, config: dict, logger: EventLogger):
|
def __init__(self, config: dict, logger: EventLogger, ap=None, **kwargs):
|
||||||
# 校验必填项
|
# 校验必填项
|
||||||
required_keys = [
|
required_keys = [
|
||||||
'corpid',
|
'corpid',
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ spec:
|
|||||||
categories:
|
categories:
|
||||||
- popular
|
- popular
|
||||||
- china
|
- china
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/wecom
|
|
||||||
en: https://link.langbot.app/en/platforms/wecom
|
|
||||||
ja: https://link.langbot.app/ja/platforms/wecom
|
|
||||||
config:
|
config:
|
||||||
- name: webhook_url
|
- name: webhook_url
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ import langbot_plugin.api.entities.builtin.platform.events as platform_events
|
|||||||
import langbot_plugin.api.entities.builtin.platform.entities as platform_entities
|
import langbot_plugin.api.entities.builtin.platform.entities as platform_entities
|
||||||
from ..logger import EventLogger
|
from ..logger import EventLogger
|
||||||
from langbot.libs.wecom_ai_bot_api.wecombotevent import WecomBotEvent
|
from langbot.libs.wecom_ai_bot_api.wecombotevent import WecomBotEvent
|
||||||
from langbot.libs.wecom_ai_bot_api.api import WecomBotClient
|
from langbot.libs.wecom_ai_bot_api.api import WecomBotClient, StreamSession
|
||||||
from langbot.libs.wecom_ai_bot_api.ws_client import WecomBotWsClient
|
from langbot.libs.wecom_ai_bot_api.ws_client import WecomBotWsClient
|
||||||
|
from ...core import app as langbot_app
|
||||||
|
from ...pipeline.monitoring_helper import FeedbackMonitor
|
||||||
|
|
||||||
|
|
||||||
class WecomBotMessageConverter(abstract_platform_adapter.AbstractMessageConverter):
|
class WecomBotMessageConverter(abstract_platform_adapter.AbstractMessageConverter):
|
||||||
@@ -192,8 +194,10 @@ class WecomBotAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
|
|||||||
_ws_mode: bool = False
|
_ws_mode: bool = False
|
||||||
bot_name: str = ''
|
bot_name: str = ''
|
||||||
listeners: dict = {}
|
listeners: dict = {}
|
||||||
|
ap: langbot_app.Application = None # Application reference for monitoring
|
||||||
|
_bot_info: dict = None # Bot info for monitoring (bot_id, bot_name, pipeline_id, pipeline_name)
|
||||||
|
|
||||||
def __init__(self, config: dict, logger: EventLogger):
|
def __init__(self, config: dict, logger: EventLogger, ap: langbot_app.Application = None, **kwargs):
|
||||||
enable_webhook = config.get('enable-webhook', False)
|
enable_webhook = config.get('enable-webhook', False)
|
||||||
bot_name = config.get('robot_name', '')
|
bot_name = config.get('robot_name', '')
|
||||||
|
|
||||||
@@ -228,8 +232,14 @@ class WecomBotAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
|
|||||||
bot_account_id=bot_account_id,
|
bot_account_id=bot_account_id,
|
||||||
bot_name=bot_name,
|
bot_name=bot_name,
|
||||||
event_converter=event_converter,
|
event_converter=event_converter,
|
||||||
|
**kwargs,
|
||||||
)
|
)
|
||||||
self.listeners = {}
|
self.listeners = {}
|
||||||
|
object.__setattr__(self, '_ws_mode', ws_mode)
|
||||||
|
object.__setattr__(self, 'ap', ap)
|
||||||
|
|
||||||
|
# Register feedback handler for monitoring
|
||||||
|
self._register_feedback_handler()
|
||||||
|
|
||||||
async def reply_message(
|
async def reply_message(
|
||||||
self,
|
self,
|
||||||
@@ -311,9 +321,6 @@ class WecomBotAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
|
|||||||
self.bot.on_message('single')(self.on_message)
|
self.bot.on_message('single')(self.on_message)
|
||||||
elif event_type == platform_events.GroupMessage:
|
elif event_type == platform_events.GroupMessage:
|
||||||
self.bot.on_message('group')(self.on_message)
|
self.bot.on_message('group')(self.on_message)
|
||||||
elif event_type == platform_events.FeedbackEvent:
|
|
||||||
if hasattr(self.bot, 'on_feedback'):
|
|
||||||
self.bot.on_feedback()(self._on_feedback)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
print(traceback.format_exc())
|
print(traceback.format_exc())
|
||||||
|
|
||||||
@@ -321,44 +328,65 @@ class WecomBotAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
|
|||||||
"""设置 bot UUID(用于生成 webhook URL)"""
|
"""设置 bot UUID(用于生成 webhook URL)"""
|
||||||
self.bot_uuid = bot_uuid
|
self.bot_uuid = bot_uuid
|
||||||
|
|
||||||
async def _on_feedback(self, **kwargs):
|
def set_bot_info(
|
||||||
"""Handle feedback event from WeChat Work AI Bot SDK and dispatch as FeedbackEvent."""
|
self,
|
||||||
try:
|
bot_id: str,
|
||||||
feedback_id = kwargs.get('feedback_id', '')
|
bot_name: str,
|
||||||
feedback_type = kwargs.get('feedback_type', 0)
|
pipeline_id: str,
|
||||||
feedback_content = kwargs.get('feedback_content', '') or None
|
pipeline_name: str,
|
||||||
inaccurate_reasons = kwargs.get('inaccurate_reasons', []) or None
|
):
|
||||||
session = kwargs.get('session')
|
"""设置 bot 信息(用于监控记录)"""
|
||||||
|
self._bot_info = {
|
||||||
|
'bot_id': bot_id,
|
||||||
|
'bot_name': bot_name,
|
||||||
|
'pipeline_id': pipeline_id,
|
||||||
|
'pipeline_name': pipeline_name,
|
||||||
|
}
|
||||||
|
|
||||||
session_id = None
|
def _register_feedback_handler(self):
|
||||||
user_id = None
|
"""注册用户反馈处理器,用于持久化反馈数据到监控服务"""
|
||||||
message_id = None
|
|
||||||
stream_id = None
|
async def handle_feedback(
|
||||||
if session:
|
feedback_id: str,
|
||||||
|
feedback_type: int,
|
||||||
|
feedback_content: str,
|
||||||
|
inaccurate_reasons: list[str],
|
||||||
|
session: StreamSession,
|
||||||
|
):
|
||||||
|
"""处理用户反馈事件,持久化到监控服务"""
|
||||||
|
if not self.ap or not self._bot_info:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Build session_id from session info
|
||||||
|
session_id = None
|
||||||
if session.chat_id:
|
if session.chat_id:
|
||||||
session_id = f'group_{session.chat_id}'
|
session_id = f'group_{session.chat_id}'
|
||||||
elif session.user_id:
|
elif session.user_id:
|
||||||
session_id = f'person_{session.user_id}'
|
session_id = f'person_{session.user_id}'
|
||||||
user_id = session.user_id
|
|
||||||
message_id = session.msg_id
|
|
||||||
stream_id = session.stream_id
|
|
||||||
|
|
||||||
event = platform_events.FeedbackEvent(
|
await FeedbackMonitor.record_feedback(
|
||||||
feedback_id=feedback_id,
|
ap=self.ap,
|
||||||
feedback_type=feedback_type,
|
feedback_id=feedback_id,
|
||||||
feedback_content=feedback_content,
|
feedback_type=feedback_type,
|
||||||
inaccurate_reasons=inaccurate_reasons,
|
feedback_content=feedback_content if feedback_content else None,
|
||||||
user_id=user_id,
|
inaccurate_reasons=inaccurate_reasons if inaccurate_reasons else None,
|
||||||
session_id=session_id,
|
bot_id=self._bot_info['bot_id'],
|
||||||
message_id=message_id,
|
bot_name=self._bot_info['bot_name'],
|
||||||
stream_id=stream_id,
|
pipeline_id=self._bot_info['pipeline_id'],
|
||||||
source_platform_object=session,
|
pipeline_name=self._bot_info['pipeline_name'],
|
||||||
)
|
session_id=session_id,
|
||||||
|
message_id=session.msg_id if session else None,
|
||||||
|
stream_id=session.stream_id if session else None,
|
||||||
|
user_id=session.user_id if session else None,
|
||||||
|
platform='wecom',
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
await self.logger.error(f'Failed to record feedback: {traceback.format_exc()}')
|
||||||
|
|
||||||
if platform_events.FeedbackEvent in self.listeners:
|
# Register the feedback handler with the bot client
|
||||||
await self.listeners[platform_events.FeedbackEvent](event, self)
|
if hasattr(self.bot, 'on_feedback'):
|
||||||
except Exception:
|
self.bot.on_feedback()(handle_feedback)
|
||||||
await self.logger.error(f'Error in wecombot feedback callback: {traceback.format_exc()}')
|
|
||||||
|
|
||||||
async def handle_unified_webhook(self, bot_uuid: str, path: str, request):
|
async def handle_unified_webhook(self, bot_uuid: str, path: str, request):
|
||||||
_ws_mode = not self.config.get('enable-webhook', False)
|
_ws_mode = not self.config.get('enable-webhook', False)
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
categories:
|
categories:
|
||||||
- china
|
- china
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/wecombot
|
|
||||||
en: https://link.langbot.app/en/platforms/wecombot
|
|
||||||
ja: https://link.langbot.app/ja/platforms/wecombot
|
|
||||||
config:
|
config:
|
||||||
- name: BotId
|
- name: BotId
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
categories:
|
categories:
|
||||||
- china
|
- china
|
||||||
help_links:
|
|
||||||
zh: https://link.langbot.app/zh/platforms/wecomcs
|
|
||||||
en: https://link.langbot.app/en/platforms/wecomcs
|
|
||||||
ja: https://link.langbot.app/ja/platforms/wecomcs
|
|
||||||
config:
|
config:
|
||||||
- name: webhook_url
|
- name: webhook_url
|
||||||
label:
|
label:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import langbot
|
|||||||
|
|
||||||
semantic_version = f'v{langbot.__version__}'
|
semantic_version = f'v{langbot.__version__}'
|
||||||
|
|
||||||
required_database_version = 24
|
required_database_version = 25
|
||||||
"""Tag the version of the database schema, used to check if the database needs to be migrated"""
|
"""Tag the version of the database schema, used to check if the database needs to be migrated"""
|
||||||
|
|
||||||
debug_mode = False
|
debug_mode = False
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ class VersionManager:
|
|||||||
try:
|
try:
|
||||||
if await self.ap.ver_mgr.is_new_version_available():
|
if await self.ap.ver_mgr.is_new_version_available():
|
||||||
return (
|
return (
|
||||||
'New version available:\n有新版本可用,根据文档更新: \nhttps://link.langbot.app/zh/docs/update',
|
'New version available:\n有新版本可用,根据文档更新: \nhttps://docs.langbot.app/zh/deploy/update.html',
|
||||||
logging.INFO,
|
logging.INFO,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1832,7 +1832,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langbot"
|
name = "langbot"
|
||||||
version = "4.9.5"
|
version = "4.9.4"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "aiocqhttp" },
|
{ name = "aiocqhttp" },
|
||||||
@@ -1937,7 +1937,7 @@ requires-dist = [
|
|||||||
{ name = "ebooklib", specifier = ">=0.18" },
|
{ name = "ebooklib", specifier = ">=0.18" },
|
||||||
{ name = "gewechat-client", specifier = ">=0.1.5" },
|
{ name = "gewechat-client", specifier = ">=0.1.5" },
|
||||||
{ name = "html2text", specifier = ">=2024.2.26" },
|
{ name = "html2text", specifier = ">=2024.2.26" },
|
||||||
{ name = "langbot-plugin", specifier = "==0.3.6" },
|
{ name = "langbot-plugin", specifier = "==0.3.5" },
|
||||||
{ name = "langchain", specifier = ">=0.2.0" },
|
{ name = "langchain", specifier = ">=0.2.0" },
|
||||||
{ name = "langchain-text-splitters", specifier = ">=0.0.1" },
|
{ name = "langchain-text-splitters", specifier = ">=0.0.1" },
|
||||||
{ name = "lark-oapi", specifier = ">=1.4.15" },
|
{ name = "lark-oapi", specifier = ">=1.4.15" },
|
||||||
@@ -1993,7 +1993,7 @@ dev = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langbot-plugin"
|
name = "langbot-plugin"
|
||||||
version = "0.3.6"
|
version = "0.3.5"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "aiofiles" },
|
{ name = "aiofiles" },
|
||||||
@@ -2011,9 +2011,9 @@ dependencies = [
|
|||||||
{ name = "watchdog" },
|
{ name = "watchdog" },
|
||||||
{ name = "websockets" },
|
{ name = "websockets" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/ff/f0/e5561bd1ebda0b9345ad6b98718b5f002bb3ca79b5ec294dc77cc10957b9/langbot_plugin-0.3.6.tar.gz", hash = "sha256:20db981e416a640f22246e54517abc2a095d8ccf5e69e06c2674fb8a443f5dbe", size = 179266, upload-time = "2026-03-30T15:58:58.523Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/1c/8f/0a22e4461b0893ac2afb1b6aaebafe04c921df6dbbf4b8bd6c83cf6a97b2/langbot_plugin-0.3.5.tar.gz", hash = "sha256:79c7feb08f788f480435de8cdefc3cfed4de2dfb03978a460251b8c9d1c271d3", size = 171927, upload-time = "2026-03-25T13:53:18.334Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/a3/f5/ac424c2620e1be98a54a0b8ec0ed256a9c06cea7cd32a30732a1aea5fdc5/langbot_plugin-0.3.6-py3-none-any.whl", hash = "sha256:3238448436c41d50a0a0cf37438d845f0a1371159d440af3411a984e3d4e9eb7", size = 156752, upload-time = "2026-03-30T15:59:00.229Z" },
|
{ url = "https://files.pythonhosted.org/packages/cd/93/fdd4eb54434a358a3917aec74190e2e1b64351a5bb955677f634d29fc4fd/langbot_plugin-0.3.5-py3-none-any.whl", hash = "sha256:4d31f92338e1e2dc343ae00982e4facbe7abae84f4d1c4e1375cdcac9d7155d7", size = 146575, upload-time = "2026-03-25T13:53:16.987Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
NEXT_PUBLIC_API_BASE_URL=http://localhost:5300
|
NEXT_PUBLIC_API_BASE_URL=http://192.168.1.97:5300
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
# Debug LangBot Frontend
|
# Debug LangBot Frontend
|
||||||
|
|
||||||
Please refer to the [Development Guide](https://link.langbot.app/en/docs/dev-config) for more information.
|
Please refer to the [Development Guide](https://docs.langbot.app/en/develop/dev-config.html) for more information.
|
||||||
|
|||||||
Generated
+1099
-3276
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,4 @@
|
|||||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import i18n from 'i18next';
|
|
||||||
import {
|
import {
|
||||||
IChooseAdapterEntity,
|
IChooseAdapterEntity,
|
||||||
IPipelineEntity,
|
IPipelineEntity,
|
||||||
@@ -14,8 +13,6 @@ import { UUID } from 'uuidjs';
|
|||||||
import DynamicFormComponent from '@/app/home/components/dynamic-form/DynamicFormComponent';
|
import DynamicFormComponent from '@/app/home/components/dynamic-form/DynamicFormComponent';
|
||||||
import { httpClient } from '@/app/infra/http/HttpClient';
|
import { httpClient } from '@/app/infra/http/HttpClient';
|
||||||
import { Bot } from '@/app/infra/entities/api';
|
import { Bot } from '@/app/infra/entities/api';
|
||||||
import { getAdapterDocUrl } from '@/app/infra/entities/adapter-docs';
|
|
||||||
import { ExternalLink } from 'lucide-react';
|
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
@@ -105,9 +102,6 @@ export default function BotForm({
|
|||||||
const [adapterDescriptionList, setAdapterDescriptionList] = useState<
|
const [adapterDescriptionList, setAdapterDescriptionList] = useState<
|
||||||
Record<string, string>
|
Record<string, string>
|
||||||
>({});
|
>({});
|
||||||
const [adapterHelpLinks, setAdapterHelpLinks] = useState<
|
|
||||||
Record<string, Record<string, string>>
|
|
||||||
>({});
|
|
||||||
|
|
||||||
const [pipelineNameList, setPipelineNameList] = useState<IPipelineEntity[]>(
|
const [pipelineNameList, setPipelineNameList] = useState<IPipelineEntity[]>(
|
||||||
[],
|
[],
|
||||||
@@ -215,18 +209,6 @@ export default function BotForm({
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
setAdapterHelpLinks(
|
|
||||||
adaptersRes.adapters.reduce(
|
|
||||||
(acc, item) => {
|
|
||||||
if (item.spec.help_links) {
|
|
||||||
acc[item.name] = item.spec.help_links;
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{} as Record<string, Record<string, string>>,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
adaptersRes.adapters.forEach((rawAdapter) => {
|
adaptersRes.adapters.forEach((rawAdapter) => {
|
||||||
adapterNameToDynamicConfigMap.set(
|
adapterNameToDynamicConfigMap.set(
|
||||||
rawAdapter.name,
|
rawAdapter.name,
|
||||||
@@ -487,81 +469,59 @@ export default function BotForm({
|
|||||||
<span className="text-destructive">*</span>
|
<span className="text-destructive">*</span>
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div className="flex items-center gap-2">
|
<Select
|
||||||
<Select
|
onValueChange={(value) => {
|
||||||
onValueChange={(value) => {
|
field.onChange(value);
|
||||||
field.onChange(value);
|
handleAdapterSelect(value);
|
||||||
handleAdapterSelect(value);
|
}}
|
||||||
}}
|
value={field.value}
|
||||||
value={field.value}
|
>
|
||||||
>
|
<SelectTrigger className="w-[240px]">
|
||||||
<SelectTrigger className="w-[240px]">
|
{field.value ? (
|
||||||
{field.value ? (
|
<div className="flex items-center gap-2">
|
||||||
<div className="flex items-center gap-2">
|
<img
|
||||||
<img
|
src={httpClient.getAdapterIconURL(field.value)}
|
||||||
src={httpClient.getAdapterIconURL(field.value)}
|
alt=""
|
||||||
alt=""
|
className="h-5 w-5 rounded"
|
||||||
className="h-5 w-5 rounded"
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
{adapterNameList.find(
|
|
||||||
(a) => a.value === field.value,
|
|
||||||
)?.label ?? field.value}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<SelectValue
|
|
||||||
placeholder={t('bots.selectAdapter')}
|
|
||||||
/>
|
/>
|
||||||
)}
|
<span>
|
||||||
</SelectTrigger>
|
{adapterNameList.find(
|
||||||
<SelectContent>
|
(a) => a.value === field.value,
|
||||||
{groupedAdapters.map((group) => (
|
)?.label ?? field.value}
|
||||||
<SelectGroup
|
</span>
|
||||||
key={group.categoryId ?? 'uncategorized'}
|
</div>
|
||||||
>
|
) : (
|
||||||
{group.categoryId && (
|
<SelectValue placeholder={t('bots.selectAdapter')} />
|
||||||
<SelectLabel>
|
)}
|
||||||
{getCategoryLabel(t, group.categoryId)}
|
</SelectTrigger>
|
||||||
</SelectLabel>
|
<SelectContent>
|
||||||
)}
|
{groupedAdapters.map((group) => (
|
||||||
{group.items.map((item) => (
|
<SelectGroup
|
||||||
<SelectItem key={item.value} value={item.value}>
|
key={group.categoryId ?? 'uncategorized'}
|
||||||
<div className="flex items-center gap-2">
|
>
|
||||||
<img
|
{group.categoryId && (
|
||||||
src={httpClient.getAdapterIconURL(
|
<SelectLabel>
|
||||||
item.value,
|
{getCategoryLabel(t, group.categoryId)}
|
||||||
)}
|
</SelectLabel>
|
||||||
alt=""
|
)}
|
||||||
className="h-5 w-5 rounded"
|
{group.items.map((item) => (
|
||||||
/>
|
<SelectItem key={item.value} value={item.value}>
|
||||||
<span>{item.label}</span>
|
<div className="flex items-center gap-2">
|
||||||
</div>
|
<img
|
||||||
</SelectItem>
|
src={httpClient.getAdapterIconURL(
|
||||||
))}
|
item.value,
|
||||||
</SelectGroup>
|
)}
|
||||||
))}
|
alt=""
|
||||||
</SelectContent>
|
className="h-5 w-5 rounded"
|
||||||
</Select>
|
/>
|
||||||
{currentAdapter &&
|
<span>{item.label}</span>
|
||||||
(() => {
|
</div>
|
||||||
const docUrl = getAdapterDocUrl(
|
</SelectItem>
|
||||||
adapterHelpLinks[currentAdapter],
|
))}
|
||||||
i18n.language,
|
</SelectGroup>
|
||||||
);
|
))}
|
||||||
return docUrl ? (
|
</SelectContent>
|
||||||
<a
|
</Select>
|
||||||
href={docUrl}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="inline-flex shrink-0 items-center gap-1 text-xs text-primary hover:underline"
|
|
||||||
>
|
|
||||||
{t('bots.viewAdapterDocs')}
|
|
||||||
<ExternalLink className="h-3 w-3" />
|
|
||||||
</a>
|
|
||||||
) : null;
|
|
||||||
})()}
|
|
||||||
</div>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
{currentAdapter && adapterDescriptionList[currentAdapter] && (
|
{currentAdapter && adapterDescriptionList[currentAdapter] && (
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
|
|||||||
@@ -1423,12 +1423,12 @@ export default function HomeSidebar({
|
|||||||
localStorage.getItem('langbot_language');
|
localStorage.getItem('langbot_language');
|
||||||
if (language === 'zh-Hans' || language === 'zh-Hant') {
|
if (language === 'zh-Hans' || language === 'zh-Hant') {
|
||||||
window.open(
|
window.open(
|
||||||
'https://link.langbot.app/zh/docs/guide',
|
'https://docs.langbot.app/zh/insight/guide',
|
||||||
'_blank',
|
'_blank',
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
window.open(
|
window.open(
|
||||||
'https://link.langbot.app/en/docs/guide',
|
'https://docs.langbot.app/en/insight/guide',
|
||||||
'_blank',
|
'_blank',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,9 +67,9 @@ export const sidebarConfigList = [
|
|||||||
route: '/home/bots',
|
route: '/home/bots',
|
||||||
description: t('bots.description'),
|
description: t('bots.description'),
|
||||||
helpLink: {
|
helpLink: {
|
||||||
en_US: 'https://link.langbot.app/en/docs/platforms',
|
en_US: 'https://docs.langbot.app/en/usage/platforms/readme',
|
||||||
zh_Hans: 'https://link.langbot.app/zh/docs/platforms',
|
zh_Hans: 'https://docs.langbot.app/zh/usage/platforms/readme',
|
||||||
ja_JP: 'https://link.langbot.app/ja/docs/platforms',
|
ja_JP: 'https://docs.langbot.app/ja/usage/platforms/readme',
|
||||||
},
|
},
|
||||||
section: 'home',
|
section: 'home',
|
||||||
}),
|
}),
|
||||||
@@ -89,9 +89,9 @@ export const sidebarConfigList = [
|
|||||||
route: '/home/pipelines',
|
route: '/home/pipelines',
|
||||||
description: t('pipelines.description'),
|
description: t('pipelines.description'),
|
||||||
helpLink: {
|
helpLink: {
|
||||||
en_US: 'https://link.langbot.app/en/docs/pipelines',
|
en_US: 'https://docs.langbot.app/en/usage/pipelines/readme',
|
||||||
zh_Hans: 'https://link.langbot.app/zh/docs/pipelines',
|
zh_Hans: 'https://docs.langbot.app/zh/usage/pipelines/readme',
|
||||||
ja_JP: 'https://link.langbot.app/ja/docs/pipelines',
|
ja_JP: 'https://docs.langbot.app/ja/usage/pipelines/readme',
|
||||||
},
|
},
|
||||||
section: 'home',
|
section: 'home',
|
||||||
}),
|
}),
|
||||||
@@ -111,9 +111,9 @@ export const sidebarConfigList = [
|
|||||||
route: '/home/knowledge',
|
route: '/home/knowledge',
|
||||||
description: t('knowledge.description'),
|
description: t('knowledge.description'),
|
||||||
helpLink: {
|
helpLink: {
|
||||||
en_US: 'https://link.langbot.app/en/docs/knowledge',
|
en_US: 'https://docs.langbot.app/en/usage/knowledge/readme',
|
||||||
zh_Hans: 'https://link.langbot.app/zh/docs/knowledge',
|
zh_Hans: 'https://docs.langbot.app/zh/usage/knowledge/readme',
|
||||||
ja_JP: 'https://link.langbot.app/ja/docs/knowledge',
|
ja_JP: 'https://docs.langbot.app/ja/usage/knowledge/readme',
|
||||||
},
|
},
|
||||||
section: 'home',
|
section: 'home',
|
||||||
}),
|
}),
|
||||||
@@ -135,9 +135,9 @@ export const sidebarConfigList = [
|
|||||||
route: '/home/plugins',
|
route: '/home/plugins',
|
||||||
description: t('plugins.description'),
|
description: t('plugins.description'),
|
||||||
helpLink: {
|
helpLink: {
|
||||||
en_US: 'https://link.langbot.app/en/docs/plugins',
|
en_US: 'https://docs.langbot.app/en/usage/plugin/plugin-intro',
|
||||||
zh_Hans: 'https://link.langbot.app/zh/docs/plugins',
|
zh_Hans: 'https://docs.langbot.app/zh/usage/plugin/plugin-intro',
|
||||||
ja_JP: 'https://link.langbot.app/ja/docs/plugins',
|
ja_JP: 'https://docs.langbot.app/ja/usage/plugin/plugin-intro',
|
||||||
},
|
},
|
||||||
section: 'extensions',
|
section: 'extensions',
|
||||||
}),
|
}),
|
||||||
@@ -157,9 +157,9 @@ export const sidebarConfigList = [
|
|||||||
route: '/home/market',
|
route: '/home/market',
|
||||||
description: t('plugins.description'),
|
description: t('plugins.description'),
|
||||||
helpLink: {
|
helpLink: {
|
||||||
en_US: 'https://link.langbot.app/en/docs/plugins',
|
en_US: 'https://docs.langbot.app/en/usage/plugin/plugin-intro',
|
||||||
zh_Hans: 'https://link.langbot.app/zh/docs/plugins',
|
zh_Hans: 'https://docs.langbot.app/zh/usage/plugin/plugin-intro',
|
||||||
ja_JP: 'https://link.langbot.app/ja/docs/plugins',
|
ja_JP: 'https://docs.langbot.app/ja/usage/plugin/plugin-intro',
|
||||||
},
|
},
|
||||||
section: 'extensions',
|
section: 'extensions',
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ export default function NewVersionDialog({
|
|||||||
const getUpdateDocsUrl = () => {
|
const getUpdateDocsUrl = () => {
|
||||||
const language = i18n.language;
|
const language = i18n.language;
|
||||||
if (language === 'zh-Hans' || language === 'zh-Hant') {
|
if (language === 'zh-Hans' || language === 'zh-Hant') {
|
||||||
return 'https://link.langbot.app/zh/docs/update';
|
return 'https://docs.langbot.app/zh/deploy/update';
|
||||||
} else if (language === 'ja-JP') {
|
} else if (language === 'ja-JP') {
|
||||||
return 'https://link.langbot.app/ja/docs/update';
|
return 'https://docs.langbot.app/ja/deploy/update';
|
||||||
} else {
|
} else {
|
||||||
return 'https://link.langbot.app/en/docs/update';
|
return 'https://docs.langbot.app/en/deploy/update';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import { ThumbsUp, ThumbsDown, TrendingUp, TrendingDown, Minus } from 'lucide-react';
|
||||||
ThumbsUp,
|
|
||||||
ThumbsDown,
|
|
||||||
TrendingUp,
|
|
||||||
TrendingDown,
|
|
||||||
Minus,
|
|
||||||
} from 'lucide-react';
|
|
||||||
|
|
||||||
interface FeedbackCardProps {
|
interface FeedbackCardProps {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -34,10 +28,8 @@ export function FeedbackCard({
|
|||||||
}: FeedbackCardProps) {
|
}: FeedbackCardProps) {
|
||||||
const variantStyles = {
|
const variantStyles = {
|
||||||
default: 'bg-white dark:bg-[#2a2a2e] border-gray-200 dark:border-gray-700',
|
default: 'bg-white dark:bg-[#2a2a2e] border-gray-200 dark:border-gray-700',
|
||||||
success:
|
success: 'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800',
|
||||||
'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800',
|
warning: 'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-800',
|
||||||
warning:
|
|
||||||
'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-800',
|
|
||||||
danger: 'bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800',
|
danger: 'bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,9 +64,7 @@ export function FeedbackCard({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={`p-6 rounded-xl border shadow-sm ${variantStyles[variant]}`}>
|
||||||
className={`p-6 rounded-xl border shadow-sm ${variantStyles[variant]}`}
|
|
||||||
>
|
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-start justify-between">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<p className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">
|
<p className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-1">
|
||||||
@@ -89,28 +79,15 @@ export function FeedbackCard({
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{trend && (
|
{trend && (
|
||||||
<div
|
<div className={`flex items-center mt-2 text-sm ${trendStyles[trend.direction]}`}>
|
||||||
className={`flex items-center mt-2 text-sm ${trendStyles[trend.direction]}`}
|
{trend.direction === 'up' && <TrendingUp className="w-4 h-4 mr-1" />}
|
||||||
>
|
{trend.direction === 'down' && <TrendingDown className="w-4 h-4 mr-1" />}
|
||||||
{trend.direction === 'up' && (
|
{trend.direction === 'neutral' && <Minus className="w-4 h-4 mr-1" />}
|
||||||
<TrendingUp className="w-4 h-4 mr-1" />
|
<span>{trend.value > 0 ? '+' : ''}{trend.value}%</span>
|
||||||
)}
|
|
||||||
{trend.direction === 'down' && (
|
|
||||||
<TrendingDown className="w-4 h-4 mr-1" />
|
|
||||||
)}
|
|
||||||
{trend.direction === 'neutral' && (
|
|
||||||
<Minus className="w-4 h-4 mr-1" />
|
|
||||||
)}
|
|
||||||
<span>
|
|
||||||
{trend.value > 0 ? '+' : ''}
|
|
||||||
{trend.value}%
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className={`p-3 rounded-lg bg-gray-100 dark:bg-gray-800 ${iconStyles[variant]}`}>
|
||||||
className={`p-3 rounded-lg bg-gray-100 dark:bg-gray-800 ${iconStyles[variant]}`}
|
|
||||||
>
|
|
||||||
{icon}
|
{icon}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -162,11 +139,7 @@ export function FeedbackStatsCards({ stats, loading }: FeedbackStatsProps) {
|
|||||||
<path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5 7.67 11 8.5 11zm3.5 6.5c2.33 0 4.31-1.46 5.11-3.5H6.89c.8 2.04 2.78 3.5 5.11 3.5z" />
|
<path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5 7.67 11 8.5 11zm3.5 6.5c2.33 0 4.31-1.46 5.11-3.5H6.89c.8 2.04 2.78 3.5 5.11 3.5z" />
|
||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
variant: (stats && stats.satisfactionRate >= 80
|
variant: (stats && stats.satisfactionRate >= 80 ? 'success' : stats && stats.satisfactionRate >= 50 ? 'warning' : 'danger') as 'default' | 'success' | 'warning' | 'danger',
|
||||||
? 'success'
|
|
||||||
: stats && stats.satisfactionRate >= 50
|
|
||||||
? 'warning'
|
|
||||||
: 'danger') as 'default' | 'success' | 'warning' | 'danger',
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import { ThumbsUp, ThumbsDown, ChevronRight, ChevronDown, ExternalLink } from 'lucide-react';
|
||||||
ThumbsUp,
|
|
||||||
ThumbsDown,
|
|
||||||
ChevronRight,
|
|
||||||
ChevronDown,
|
|
||||||
ExternalLink,
|
|
||||||
} from 'lucide-react';
|
|
||||||
import { FeedbackRecord } from '../types/monitoring';
|
import { FeedbackRecord } from '../types/monitoring';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { LoadingSpinner } from '@/components/ui/loading-spinner';
|
import { LoadingSpinner } from '@/components/ui/loading-spinner';
|
||||||
@@ -19,11 +13,7 @@ interface FeedbackListProps {
|
|||||||
onViewMessage?: (messageId: string) => void;
|
onViewMessage?: (messageId: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FeedbackList({
|
export function FeedbackList({ feedback, loading, onViewMessage }: FeedbackListProps) {
|
||||||
feedback,
|
|
||||||
loading,
|
|
||||||
onViewMessage,
|
|
||||||
}: FeedbackListProps) {
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [expandedId, setExpandedId] = React.useState<string | null>(null);
|
const [expandedId, setExpandedId] = React.useState<string | null>(null);
|
||||||
|
|
||||||
@@ -90,13 +80,9 @@ export function FeedbackList({
|
|||||||
{/* Expand Icon */}
|
{/* Expand Icon */}
|
||||||
<div className="mr-3 mt-0.5">
|
<div className="mr-3 mt-0.5">
|
||||||
{expandedId === item.id ? (
|
{expandedId === item.id ? (
|
||||||
<ChevronDown
|
<ChevronDown className={`w-5 h-5 ${item.feedbackType === 'like' ? 'text-green-500' : 'text-red-500'}`} />
|
||||||
className={`w-5 h-5 ${item.feedbackType === 'like' ? 'text-green-500' : 'text-red-500'}`}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<ChevronRight
|
<ChevronRight className={`w-5 h-5 ${item.feedbackType === 'like' ? 'text-green-500' : 'text-red-500'}`} />
|
||||||
className={`w-5 h-5 ${item.feedbackType === 'like' ? 'text-green-500' : 'text-red-500'}`}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -109,12 +95,8 @@ export function FeedbackList({
|
|||||||
) : (
|
) : (
|
||||||
<ThumbsDown className="w-5 h-5 text-red-500" />
|
<ThumbsDown className="w-5 h-5 text-red-500" />
|
||||||
)}
|
)}
|
||||||
<span
|
<span className={`text-sm font-medium ${item.feedbackType === 'like' ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'}`}>
|
||||||
className={`text-sm font-medium ${item.feedbackType === 'like' ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'}`}
|
{item.feedbackType === 'like' ? t('monitoring.feedback.like') : t('monitoring.feedback.dislike')}
|
||||||
>
|
|
||||||
{item.feedbackType === 'like'
|
|
||||||
? t('monitoring.feedback.like')
|
|
||||||
: t('monitoring.feedback.dislike')}
|
|
||||||
</span>
|
</span>
|
||||||
{item.botName && (
|
{item.botName && (
|
||||||
<>
|
<>
|
||||||
@@ -137,19 +119,18 @@ export function FeedbackList({
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{item.inaccurateReasons &&
|
{item.inaccurateReasons && item.inaccurateReasons.length > 0 && (
|
||||||
item.inaccurateReasons.length > 0 && (
|
<div className="flex flex-wrap gap-1 mt-2">
|
||||||
<div className="flex flex-wrap gap-1 mt-2">
|
{item.inaccurateReasons.map((reason, idx) => (
|
||||||
{item.inaccurateReasons.map((reason, idx) => (
|
<span
|
||||||
<span
|
key={idx}
|
||||||
key={idx}
|
className="text-xs px-2 py-0.5 rounded bg-red-100 dark:bg-red-900/30 text-red-600 dark:text-red-400"
|
||||||
className="text-xs px-2 py-0.5 rounded bg-red-100 dark:bg-red-900/30 text-red-600 dark:text-red-400"
|
>
|
||||||
>
|
{reason}
|
||||||
{reason}
|
</span>
|
||||||
</span>
|
))}
|
||||||
))}
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -164,13 +145,9 @@ export function FeedbackList({
|
|||||||
|
|
||||||
{/* Expanded Details */}
|
{/* Expanded Details */}
|
||||||
{expandedId === item.id && (
|
{expandedId === item.id && (
|
||||||
<div
|
<div className={`border-t p-5 bg-white dark:bg-gray-900 ${
|
||||||
className={`border-t p-5 bg-white dark:bg-gray-900 ${
|
item.feedbackType === 'like' ? 'border-green-200 dark:border-green-900' : 'border-red-200 dark:border-red-900'
|
||||||
item.feedbackType === 'like'
|
}`}>
|
||||||
? 'border-green-200 dark:border-green-900'
|
|
||||||
: 'border-red-200 dark:border-red-900'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div className="space-y-4 pl-8 border-l-2 border-gray-200 dark:border-gray-700 ml-4">
|
<div className="space-y-4 pl-8 border-l-2 border-gray-200 dark:border-gray-700 ml-4">
|
||||||
{/* Context Info */}
|
{/* Context Info */}
|
||||||
<div className="bg-gray-50 dark:bg-gray-800 rounded-lg p-3">
|
<div className="bg-gray-50 dark:bg-gray-800 rounded-lg p-3">
|
||||||
|
|||||||
@@ -54,7 +54,10 @@ export function useFeedbackData(params: UseFeedbackDataParams = {}) {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState<Error | null>(null);
|
const [error, setError] = useState<Error | null>(null);
|
||||||
|
|
||||||
const paramsStr = useMemo(() => JSON.stringify(params), [params]);
|
const paramsStr = useMemo(
|
||||||
|
() => JSON.stringify(params),
|
||||||
|
[params],
|
||||||
|
);
|
||||||
|
|
||||||
const fetchStats = useCallback(async () => {
|
const fetchStats = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -63,9 +66,7 @@ export function useFeedbackData(params: UseFeedbackDataParams = {}) {
|
|||||||
params.botIds.forEach((id) => queryParams.append('botId', id));
|
params.botIds.forEach((id) => queryParams.append('botId', id));
|
||||||
}
|
}
|
||||||
if (params.pipelineIds) {
|
if (params.pipelineIds) {
|
||||||
params.pipelineIds.forEach((id) =>
|
params.pipelineIds.forEach((id) => queryParams.append('pipelineId', id));
|
||||||
queryParams.append('pipelineId', id),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (params.startTime) {
|
if (params.startTime) {
|
||||||
queryParams.append('startTime', params.startTime);
|
queryParams.append('startTime', params.startTime);
|
||||||
@@ -90,8 +91,7 @@ export function useFeedbackData(params: UseFeedbackDataParams = {}) {
|
|||||||
totalFeedback: bot.total,
|
totalFeedback: bot.total,
|
||||||
totalLikes: bot.likes,
|
totalLikes: bot.likes,
|
||||||
totalDislikes: bot.dislikes,
|
totalDislikes: bot.dislikes,
|
||||||
satisfactionRate:
|
satisfactionRate: bot.total > 0 ? Math.round((bot.likes / bot.total) * 100) : 0,
|
||||||
bot.total > 0 ? Math.round((bot.likes / bot.total) * 100) : 0,
|
|
||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -110,9 +110,7 @@ export function useFeedbackData(params: UseFeedbackDataParams = {}) {
|
|||||||
params.botIds.forEach((id) => queryParams.append('botId', id));
|
params.botIds.forEach((id) => queryParams.append('botId', id));
|
||||||
}
|
}
|
||||||
if (params.pipelineIds) {
|
if (params.pipelineIds) {
|
||||||
params.pipelineIds.forEach((id) =>
|
params.pipelineIds.forEach((id) => queryParams.append('pipelineId', id));
|
||||||
queryParams.append('pipelineId', id),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (params.startTime) {
|
if (params.startTime) {
|
||||||
queryParams.append('startTime', params.startTime);
|
queryParams.append('startTime', params.startTime);
|
||||||
@@ -121,10 +119,7 @@ export function useFeedbackData(params: UseFeedbackDataParams = {}) {
|
|||||||
queryParams.append('endTime', params.endTime);
|
queryParams.append('endTime', params.endTime);
|
||||||
}
|
}
|
||||||
if (params.feedbackType) {
|
if (params.feedbackType) {
|
||||||
queryParams.append(
|
queryParams.append('feedbackType', params.feedbackType === 'like' ? '1' : '2');
|
||||||
'feedbackType',
|
|
||||||
params.feedbackType === 'like' ? '1' : '2',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (params.limit) {
|
if (params.limit) {
|
||||||
queryParams.append('limit', params.limit.toString());
|
queryParams.append('limit', params.limit.toString());
|
||||||
@@ -139,27 +134,25 @@ export function useFeedbackData(params: UseFeedbackDataParams = {}) {
|
|||||||
}>(`/api/v1/monitoring/feedback?${queryParams.toString()}`);
|
}>(`/api/v1/monitoring/feedback?${queryParams.toString()}`);
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
const transformedFeedback: FeedbackRecord[] = result.feedback.map(
|
const transformedFeedback: FeedbackRecord[] = result.feedback.map((item) => ({
|
||||||
(item) => ({
|
id: item.id,
|
||||||
id: item.id,
|
timestamp: new Date(item.timestamp),
|
||||||
timestamp: new Date(item.timestamp),
|
feedbackId: item.feedback_id,
|
||||||
feedbackId: item.feedback_id,
|
feedbackType: item.feedback_type === 1 ? 'like' : 'dislike',
|
||||||
feedbackType: item.feedback_type === 1 ? 'like' : 'dislike',
|
feedbackContent: item.feedback_content,
|
||||||
feedbackContent: item.feedback_content,
|
inaccurateReasons: item.inaccurate_reasons
|
||||||
inaccurateReasons: item.inaccurate_reasons
|
? JSON.parse(item.inaccurate_reasons)
|
||||||
? JSON.parse(item.inaccurate_reasons)
|
: undefined,
|
||||||
: undefined,
|
botId: item.bot_id,
|
||||||
botId: item.bot_id,
|
botName: item.bot_name,
|
||||||
botName: item.bot_name,
|
pipelineId: item.pipeline_id,
|
||||||
pipelineId: item.pipeline_id,
|
pipelineName: item.pipeline_name,
|
||||||
pipelineName: item.pipeline_name,
|
sessionId: item.session_id,
|
||||||
sessionId: item.session_id,
|
messageId: item.message_id,
|
||||||
messageId: item.message_id,
|
streamId: item.stream_id,
|
||||||
streamId: item.stream_id,
|
userId: item.user_id,
|
||||||
userId: item.user_id,
|
platform: item.platform,
|
||||||
platform: item.platform,
|
}));
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
setFeedback(transformedFeedback);
|
setFeedback(transformedFeedback);
|
||||||
setTotal(result.total);
|
setTotal(result.total);
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import {
|
|||||||
ModelCall,
|
ModelCall,
|
||||||
LLMCall,
|
LLMCall,
|
||||||
EmbeddingCall,
|
EmbeddingCall,
|
||||||
|
FeedbackRecord,
|
||||||
|
FeedbackStats,
|
||||||
} from '../types/monitoring';
|
} from '../types/monitoring';
|
||||||
import { backendClient } from '@/app/infra/http';
|
import { backendClient } from '@/app/infra/http';
|
||||||
import { parseUTCTimestamp } from '../utils/dateUtils';
|
import { parseUTCTimestamp } from '../utils/dateUtils';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React, { Suspense, useState, useMemo } from 'react';
|
import React, { Suspense, useState, useMemo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
@@ -114,16 +114,12 @@ function MonitoringPageContent() {
|
|||||||
const {
|
const {
|
||||||
feedback: feedbackList,
|
feedback: feedbackList,
|
||||||
stats: feedbackStats,
|
stats: feedbackStats,
|
||||||
|
total: feedbackTotal,
|
||||||
loading: feedbackLoading,
|
loading: feedbackLoading,
|
||||||
|
refetch: refetchFeedback,
|
||||||
} = useFeedbackData({
|
} = useFeedbackData({
|
||||||
botIds:
|
botIds: filterState.selectedBots.length > 0 ? filterState.selectedBots : undefined,
|
||||||
filterState.selectedBots.length > 0
|
pipelineIds: filterState.selectedPipelines.length > 0 ? filterState.selectedPipelines : undefined,
|
||||||
? filterState.selectedBots
|
|
||||||
: undefined,
|
|
||||||
pipelineIds:
|
|
||||||
filterState.selectedPipelines.length > 0
|
|
||||||
? filterState.selectedPipelines
|
|
||||||
: undefined,
|
|
||||||
startTime: feedbackTimeRange.startTime,
|
startTime: feedbackTimeRange.startTime,
|
||||||
endTime: feedbackTimeRange.endTime,
|
endTime: feedbackTimeRange.endTime,
|
||||||
limit: 50,
|
limit: 50,
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
/**
|
|
||||||
* Resolves the documentation URL for a given adapter from its
|
|
||||||
* spec.help_links map, selecting the best match for the current locale
|
|
||||||
* with a fallback to English.
|
|
||||||
*/
|
|
||||||
export function getAdapterDocUrl(
|
|
||||||
helpLinks: Record<string, string> | undefined,
|
|
||||||
locale: string,
|
|
||||||
): string | null {
|
|
||||||
if (!helpLinks) return null;
|
|
||||||
|
|
||||||
// Map locale to simplified language key
|
|
||||||
let lang: string;
|
|
||||||
if (locale.startsWith('zh')) {
|
|
||||||
lang = 'zh';
|
|
||||||
} else if (locale.startsWith('ja')) {
|
|
||||||
lang = 'ja';
|
|
||||||
} else {
|
|
||||||
lang = 'en';
|
|
||||||
}
|
|
||||||
|
|
||||||
return helpLinks[lang] ?? helpLinks['en'] ?? null;
|
|
||||||
}
|
|
||||||
@@ -118,7 +118,6 @@ export interface Adapter {
|
|||||||
icon?: string;
|
icon?: string;
|
||||||
spec: {
|
spec: {
|
||||||
categories?: string[];
|
categories?: string[];
|
||||||
help_links?: Record<string, string>;
|
|
||||||
config: IDynamicFormItemSchema[];
|
config: IDynamicFormItemSchema[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
PartyPopper,
|
PartyPopper,
|
||||||
Loader2,
|
Loader2,
|
||||||
X,
|
X,
|
||||||
ExternalLink,
|
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
|
||||||
import { httpClient } from '@/app/infra/http/HttpClient';
|
import { httpClient } from '@/app/infra/http/HttpClient';
|
||||||
@@ -46,8 +45,6 @@ import {
|
|||||||
groupByCategory,
|
groupByCategory,
|
||||||
getCategoryLabel,
|
getCategoryLabel,
|
||||||
} from '@/app/infra/entities/adapter-categories';
|
} from '@/app/infra/entities/adapter-categories';
|
||||||
import { getAdapterDocUrl } from '@/app/infra/entities/adapter-docs';
|
|
||||||
import i18n from 'i18next';
|
|
||||||
|
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
@@ -801,24 +798,6 @@ function StepPlatform({
|
|||||||
<p className="text-sm text-muted-foreground line-clamp-2">
|
<p className="text-sm text-muted-foreground line-clamp-2">
|
||||||
{extractI18nObject(adapter.description)}
|
{extractI18nObject(adapter.description)}
|
||||||
</p>
|
</p>
|
||||||
{(() => {
|
|
||||||
const docUrl = getAdapterDocUrl(
|
|
||||||
adapter.spec.help_links,
|
|
||||||
i18n.language,
|
|
||||||
);
|
|
||||||
return docUrl ? (
|
|
||||||
<a
|
|
||||||
href={docUrl}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="mt-2 inline-flex items-center text-xs text-primary hover:underline"
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
>
|
|
||||||
<ExternalLink className="mr-1 h-3 w-3" />
|
|
||||||
{t('bots.viewAdapterDocs')}
|
|
||||||
</a>
|
|
||||||
) : null;
|
|
||||||
})()}
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
@@ -888,34 +867,11 @@ function StepBotConfig({
|
|||||||
{adapterConfigItems.length > 0 && (
|
{adapterConfigItems.length > 0 && (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2">
|
<CardHeader className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2">
|
||||||
<div className="flex items-center gap-2">
|
<CardTitle className="text-base">
|
||||||
<CardTitle className="text-base">
|
{t('wizard.config.platformConfig', {
|
||||||
{t('wizard.config.platformConfig', {
|
platform: adapterLabel,
|
||||||
platform: adapterLabel,
|
})}
|
||||||
})}
|
</CardTitle>
|
||||||
</CardTitle>
|
|
||||||
{selectedAdapterName &&
|
|
||||||
(() => {
|
|
||||||
const selectedAdapter = adapters.find(
|
|
||||||
(a) => a.name === selectedAdapterName,
|
|
||||||
);
|
|
||||||
const docUrl = getAdapterDocUrl(
|
|
||||||
selectedAdapter?.spec.help_links,
|
|
||||||
i18n.language,
|
|
||||||
);
|
|
||||||
return docUrl ? (
|
|
||||||
<a
|
|
||||||
href={docUrl}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="inline-flex items-center text-xs text-primary hover:underline"
|
|
||||||
>
|
|
||||||
<ExternalLink className="mr-1 h-3 w-3" />
|
|
||||||
{t('bots.viewAdapterDocs')}
|
|
||||||
</a>
|
|
||||||
) : null;
|
|
||||||
})()}
|
|
||||||
</div>
|
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={onSaveBot}
|
onClick={onSaveBot}
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ const enUS = {
|
|||||||
privacyPolicy: 'Privacy Policy',
|
privacyPolicy: 'Privacy Policy',
|
||||||
and: 'and',
|
and: 'and',
|
||||||
dataCollectionPolicy: 'Data Collection Policy',
|
dataCollectionPolicy: 'Data Collection Policy',
|
||||||
dataCollectionPolicyUrl: 'https://link.langbot.app/en/docs/data-policy',
|
dataCollectionPolicyUrl:
|
||||||
|
'https://docs.langbot.app/en/insight/data-collection-policy',
|
||||||
loading: 'Loading...',
|
loading: 'Loading...',
|
||||||
fieldRequired: 'This field is required',
|
fieldRequired: 'This field is required',
|
||||||
or: 'or',
|
or: 'or',
|
||||||
@@ -288,7 +289,6 @@ const enUS = {
|
|||||||
platformAdapter: 'Platform/Adapter Selection',
|
platformAdapter: 'Platform/Adapter Selection',
|
||||||
selectAdapter: 'Select Adapter',
|
selectAdapter: 'Select Adapter',
|
||||||
adapterConfig: 'Adapter Configuration',
|
adapterConfig: 'Adapter Configuration',
|
||||||
viewAdapterDocs: 'View Docs',
|
|
||||||
bindPipeline: 'Bind Pipeline',
|
bindPipeline: 'Bind Pipeline',
|
||||||
selectPipeline: 'Select Pipeline',
|
selectPipeline: 'Select Pipeline',
|
||||||
selectBot: 'Select Bot',
|
selectBot: 'Select Bot',
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ const esES = {
|
|||||||
privacyPolicy: 'Política de privacidad',
|
privacyPolicy: 'Política de privacidad',
|
||||||
and: 'y',
|
and: 'y',
|
||||||
dataCollectionPolicy: 'Política de recopilación de datos',
|
dataCollectionPolicy: 'Política de recopilación de datos',
|
||||||
dataCollectionPolicyUrl: 'https://link.langbot.app/en/docs/data-policy',
|
dataCollectionPolicyUrl:
|
||||||
|
'https://docs.langbot.app/en/insight/data-collection-policy',
|
||||||
loading: 'Cargando...',
|
loading: 'Cargando...',
|
||||||
fieldRequired: 'Este campo es obligatorio',
|
fieldRequired: 'Este campo es obligatorio',
|
||||||
or: 'o',
|
or: 'o',
|
||||||
@@ -297,7 +298,6 @@ const esES = {
|
|||||||
platformAdapter: 'Selección de plataforma/adaptador',
|
platformAdapter: 'Selección de plataforma/adaptador',
|
||||||
selectAdapter: 'Seleccionar adaptador',
|
selectAdapter: 'Seleccionar adaptador',
|
||||||
adapterConfig: 'Configuración del adaptador',
|
adapterConfig: 'Configuración del adaptador',
|
||||||
viewAdapterDocs: 'Ver documentación',
|
|
||||||
bindPipeline: 'Vincular Pipeline',
|
bindPipeline: 'Vincular Pipeline',
|
||||||
selectPipeline: 'Seleccionar Pipeline',
|
selectPipeline: 'Seleccionar Pipeline',
|
||||||
selectBot: 'Seleccionar Bot',
|
selectBot: 'Seleccionar Bot',
|
||||||
@@ -1062,7 +1062,6 @@ const esES = {
|
|||||||
embeddingCalls: 'Llamadas Embedding',
|
embeddingCalls: 'Llamadas Embedding',
|
||||||
modelCalls: 'Llamadas a modelos',
|
modelCalls: 'Llamadas a modelos',
|
||||||
sessions: 'Análisis de sesiones',
|
sessions: 'Análisis de sesiones',
|
||||||
feedback: 'Comentarios de usuarios',
|
|
||||||
errors: 'Registros de errores',
|
errors: 'Registros de errores',
|
||||||
},
|
},
|
||||||
messageList: {
|
messageList: {
|
||||||
@@ -1142,26 +1141,6 @@ const esES = {
|
|||||||
noErrors: 'No se encontraron errores',
|
noErrors: 'No se encontraron errores',
|
||||||
stackTrace: 'Traza de pila',
|
stackTrace: 'Traza de pila',
|
||||||
},
|
},
|
||||||
feedback: {
|
|
||||||
title: 'Comentarios de usuarios',
|
|
||||||
totalFeedback: 'Total de comentarios',
|
|
||||||
totalLikes: 'Me gusta',
|
|
||||||
totalDislikes: 'No me gusta',
|
|
||||||
satisfactionRate: 'Tasa de satisfacción',
|
|
||||||
like: 'Me gusta',
|
|
||||||
dislike: 'No me gusta',
|
|
||||||
noFeedback: 'Aún no hay comentarios',
|
|
||||||
noFeedbackDescription: 'Los comentarios de los usuarios aparecerán aquí',
|
|
||||||
feedbackList: 'Lista de comentarios',
|
|
||||||
feedbackContent: 'Contenido del comentario',
|
|
||||||
contextInfo: 'Información de contexto',
|
|
||||||
userId: 'ID de usuario',
|
|
||||||
messageId: 'ID de mensaje',
|
|
||||||
streamId: 'ID de flujo',
|
|
||||||
inaccurateReasons: 'Razones de inexactitud',
|
|
||||||
platform: 'Plataforma',
|
|
||||||
exportFeedback: 'Exportar comentarios',
|
|
||||||
},
|
|
||||||
queries: {
|
queries: {
|
||||||
title: 'Consultas',
|
title: 'Consultas',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -66,7 +66,8 @@
|
|||||||
privacyPolicy: 'プライバシーポリシー',
|
privacyPolicy: 'プライバシーポリシー',
|
||||||
and: 'および',
|
and: 'および',
|
||||||
dataCollectionPolicy: 'データ収集ポリシー',
|
dataCollectionPolicy: 'データ収集ポリシー',
|
||||||
dataCollectionPolicyUrl: 'https://link.langbot.app/ja/docs/data-policy',
|
dataCollectionPolicyUrl:
|
||||||
|
'https://docs.langbot.app/ja/insight/data-collection-policy',
|
||||||
loading: '読み込み中...',
|
loading: '読み込み中...',
|
||||||
fieldRequired: 'この項目は必須です',
|
fieldRequired: 'この項目は必須です',
|
||||||
or: 'または',
|
or: 'または',
|
||||||
@@ -293,7 +294,6 @@
|
|||||||
platformAdapter: 'プラットフォーム/アダプター選択',
|
platformAdapter: 'プラットフォーム/アダプター選択',
|
||||||
selectAdapter: 'アダプターを選択',
|
selectAdapter: 'アダプターを選択',
|
||||||
adapterConfig: 'アダプター設定',
|
adapterConfig: 'アダプター設定',
|
||||||
viewAdapterDocs: 'ドキュメントを見る',
|
|
||||||
bindPipeline: 'パイプラインを紐付け',
|
bindPipeline: 'パイプラインを紐付け',
|
||||||
selectPipeline: 'パイプラインを選択',
|
selectPipeline: 'パイプラインを選択',
|
||||||
selectBot: 'ボットを選択してください',
|
selectBot: 'ボットを選択してください',
|
||||||
@@ -1024,7 +1024,6 @@
|
|||||||
embeddingCalls: 'Embedding呼び出し',
|
embeddingCalls: 'Embedding呼び出し',
|
||||||
modelCalls: 'モデル呼び出し',
|
modelCalls: 'モデル呼び出し',
|
||||||
sessions: 'セッション分析',
|
sessions: 'セッション分析',
|
||||||
feedback: 'ユーザーフィードバック',
|
|
||||||
errors: 'エラーログ',
|
errors: 'エラーログ',
|
||||||
},
|
},
|
||||||
messageList: {
|
messageList: {
|
||||||
@@ -1094,26 +1093,6 @@
|
|||||||
stackTrace: 'スタックトレース',
|
stackTrace: 'スタックトレース',
|
||||||
title: 'エラー',
|
title: 'エラー',
|
||||||
},
|
},
|
||||||
feedback: {
|
|
||||||
title: 'ユーザーフィードバック',
|
|
||||||
totalFeedback: 'フィードバック合計',
|
|
||||||
totalLikes: 'いいね数',
|
|
||||||
totalDislikes: 'よくないね数',
|
|
||||||
satisfactionRate: '満足度',
|
|
||||||
like: 'いいね',
|
|
||||||
dislike: 'よくないね',
|
|
||||||
noFeedback: 'フィードバックはまだありません',
|
|
||||||
noFeedbackDescription: 'ユーザーフィードバックがここに表示されます',
|
|
||||||
feedbackList: 'フィードバック一覧',
|
|
||||||
feedbackContent: 'フィードバック内容',
|
|
||||||
contextInfo: 'コンテキスト情報',
|
|
||||||
userId: 'ユーザーID',
|
|
||||||
messageId: 'メッセージID',
|
|
||||||
streamId: 'ストリームID',
|
|
||||||
inaccurateReasons: '不正確な理由',
|
|
||||||
platform: 'プラットフォーム',
|
|
||||||
exportFeedback: 'フィードバックをエクスポート',
|
|
||||||
},
|
|
||||||
messageDetails: {
|
messageDetails: {
|
||||||
noData: 'このクエリにはLLM呼び出しやエラーがありません',
|
noData: 'このクエリにはLLM呼び出しやエラーがありません',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ const thTH = {
|
|||||||
privacyPolicy: 'นโยบายความเป็นส่วนตัว',
|
privacyPolicy: 'นโยบายความเป็นส่วนตัว',
|
||||||
and: 'และ',
|
and: 'และ',
|
||||||
dataCollectionPolicy: 'นโยบายการเก็บรวบรวมข้อมูล',
|
dataCollectionPolicy: 'นโยบายการเก็บรวบรวมข้อมูล',
|
||||||
dataCollectionPolicyUrl: 'https://link.langbot.app/en/docs/data-policy',
|
dataCollectionPolicyUrl:
|
||||||
|
'https://docs.langbot.app/en/insight/data-collection-policy',
|
||||||
loading: 'กำลังโหลด...',
|
loading: 'กำลังโหลด...',
|
||||||
fieldRequired: 'ช่องนี้จำเป็นต้องกรอก',
|
fieldRequired: 'ช่องนี้จำเป็นต้องกรอก',
|
||||||
or: 'หรือ',
|
or: 'หรือ',
|
||||||
@@ -283,7 +284,6 @@ const thTH = {
|
|||||||
platformAdapter: 'การเลือกแพลตฟอร์ม/อะแดปเตอร์',
|
platformAdapter: 'การเลือกแพลตฟอร์ม/อะแดปเตอร์',
|
||||||
selectAdapter: 'เลือกอะแดปเตอร์',
|
selectAdapter: 'เลือกอะแดปเตอร์',
|
||||||
adapterConfig: 'การกำหนดค่าอะแดปเตอร์',
|
adapterConfig: 'การกำหนดค่าอะแดปเตอร์',
|
||||||
viewAdapterDocs: 'ดูเอกสาร',
|
|
||||||
bindPipeline: 'ผูก Pipeline',
|
bindPipeline: 'ผูก Pipeline',
|
||||||
selectPipeline: 'เลือก Pipeline',
|
selectPipeline: 'เลือก Pipeline',
|
||||||
selectBot: 'เลือก Bot',
|
selectBot: 'เลือก Bot',
|
||||||
@@ -1011,7 +1011,6 @@ const thTH = {
|
|||||||
embeddingCalls: 'การเรียก Embedding',
|
embeddingCalls: 'การเรียก Embedding',
|
||||||
modelCalls: 'การเรียกโมเดล',
|
modelCalls: 'การเรียกโมเดล',
|
||||||
sessions: 'การวิเคราะห์เซสชัน',
|
sessions: 'การวิเคราะห์เซสชัน',
|
||||||
feedback: 'ความคิดเห็นผู้ใช้',
|
|
||||||
errors: 'บันทึกข้อผิดพลาด',
|
errors: 'บันทึกข้อผิดพลาด',
|
||||||
},
|
},
|
||||||
messageList: {
|
messageList: {
|
||||||
@@ -1090,26 +1089,6 @@ const thTH = {
|
|||||||
noErrors: 'ไม่พบข้อผิดพลาด',
|
noErrors: 'ไม่พบข้อผิดพลาด',
|
||||||
stackTrace: 'Stack Trace',
|
stackTrace: 'Stack Trace',
|
||||||
},
|
},
|
||||||
feedback: {
|
|
||||||
title: 'ความคิดเห็นผู้ใช้',
|
|
||||||
totalFeedback: 'ความคิดเห็นทั้งหมด',
|
|
||||||
totalLikes: 'ถูกใจ',
|
|
||||||
totalDislikes: 'ไม่ถูกใจ',
|
|
||||||
satisfactionRate: 'อัตราความพึงพอใจ',
|
|
||||||
like: 'ถูกใจ',
|
|
||||||
dislike: 'ไม่ถูกใจ',
|
|
||||||
noFeedback: 'ยังไม่มีความคิดเห็น',
|
|
||||||
noFeedbackDescription: 'ความคิดเห็นของผู้ใช้จะแสดงที่นี่',
|
|
||||||
feedbackList: 'รายการความคิดเห็น',
|
|
||||||
feedbackContent: 'เนื้อหาความคิดเห็น',
|
|
||||||
contextInfo: 'ข้อมูลบริบท',
|
|
||||||
userId: 'ID ผู้ใช้',
|
|
||||||
messageId: 'ID ข้อความ',
|
|
||||||
streamId: 'ID สตรีม',
|
|
||||||
inaccurateReasons: 'เหตุผลที่ไม่ถูกต้อง',
|
|
||||||
platform: 'แพลตฟอร์ม',
|
|
||||||
exportFeedback: 'ส่งออกความคิดเห็น',
|
|
||||||
},
|
|
||||||
queries: {
|
queries: {
|
||||||
title: 'คำค้นหา',
|
title: 'คำค้นหา',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ const viVN = {
|
|||||||
privacyPolicy: 'Chính sách bảo mật',
|
privacyPolicy: 'Chính sách bảo mật',
|
||||||
and: 'và',
|
and: 'và',
|
||||||
dataCollectionPolicy: 'Chính sách thu thập dữ liệu',
|
dataCollectionPolicy: 'Chính sách thu thập dữ liệu',
|
||||||
dataCollectionPolicyUrl: 'https://link.langbot.app/en/docs/data-policy',
|
dataCollectionPolicyUrl:
|
||||||
|
'https://docs.langbot.app/en/insight/data-collection-policy',
|
||||||
loading: 'Đang tải...',
|
loading: 'Đang tải...',
|
||||||
fieldRequired: 'Trường này là bắt buộc',
|
fieldRequired: 'Trường này là bắt buộc',
|
||||||
or: 'hoặc',
|
or: 'hoặc',
|
||||||
@@ -292,7 +293,6 @@ const viVN = {
|
|||||||
platformAdapter: 'Nền tảng/Lựa chọn Adapter',
|
platformAdapter: 'Nền tảng/Lựa chọn Adapter',
|
||||||
selectAdapter: 'Chọn Adapter',
|
selectAdapter: 'Chọn Adapter',
|
||||||
adapterConfig: 'Cấu hình Adapter',
|
adapterConfig: 'Cấu hình Adapter',
|
||||||
viewAdapterDocs: 'Xem tài liệu',
|
|
||||||
bindPipeline: 'Liên kết Pipeline',
|
bindPipeline: 'Liên kết Pipeline',
|
||||||
selectPipeline: 'Chọn Pipeline',
|
selectPipeline: 'Chọn Pipeline',
|
||||||
selectBot: 'Chọn Bot',
|
selectBot: 'Chọn Bot',
|
||||||
@@ -1032,7 +1032,6 @@ const viVN = {
|
|||||||
embeddingCalls: 'Cuộc gọi Embedding',
|
embeddingCalls: 'Cuộc gọi Embedding',
|
||||||
modelCalls: 'Cuộc gọi mô hình',
|
modelCalls: 'Cuộc gọi mô hình',
|
||||||
sessions: 'Phân tích phiên',
|
sessions: 'Phân tích phiên',
|
||||||
feedback: 'Phản hồi người dùng',
|
|
||||||
errors: 'Nhật ký lỗi',
|
errors: 'Nhật ký lỗi',
|
||||||
},
|
},
|
||||||
messageList: {
|
messageList: {
|
||||||
@@ -1111,26 +1110,6 @@ const viVN = {
|
|||||||
noErrors: 'Không tìm thấy lỗi',
|
noErrors: 'Không tìm thấy lỗi',
|
||||||
stackTrace: 'Stack Trace',
|
stackTrace: 'Stack Trace',
|
||||||
},
|
},
|
||||||
feedback: {
|
|
||||||
title: 'Phản hồi người dùng',
|
|
||||||
totalFeedback: 'Tổng phản hồi',
|
|
||||||
totalLikes: 'Lượt thích',
|
|
||||||
totalDislikes: 'Lượt không thích',
|
|
||||||
satisfactionRate: 'Tỷ lệ hài lòng',
|
|
||||||
like: 'Thích',
|
|
||||||
dislike: 'Không thích',
|
|
||||||
noFeedback: 'Chưa có phản hồi',
|
|
||||||
noFeedbackDescription: 'Phản hồi của người dùng sẽ hiển thị tại đây',
|
|
||||||
feedbackList: 'Danh sách phản hồi',
|
|
||||||
feedbackContent: 'Nội dung phản hồi',
|
|
||||||
contextInfo: 'Thông tin ngữ cảnh',
|
|
||||||
userId: 'ID người dùng',
|
|
||||||
messageId: 'ID tin nhắn',
|
|
||||||
streamId: 'ID luồng',
|
|
||||||
inaccurateReasons: 'Lý do không chính xác',
|
|
||||||
platform: 'Nền tảng',
|
|
||||||
exportFeedback: 'Xuất phản hồi',
|
|
||||||
},
|
|
||||||
queries: {
|
queries: {
|
||||||
title: 'Truy vấn',
|
title: 'Truy vấn',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -64,7 +64,8 @@ const zhHans = {
|
|||||||
privacyPolicy: '隐私政策',
|
privacyPolicy: '隐私政策',
|
||||||
and: '和',
|
and: '和',
|
||||||
dataCollectionPolicy: '数据收集政策',
|
dataCollectionPolicy: '数据收集政策',
|
||||||
dataCollectionPolicyUrl: 'https://link.langbot.app/zh/docs/data-policy',
|
dataCollectionPolicyUrl:
|
||||||
|
'https://docs.langbot.app/zh/insight/data-collection-policy',
|
||||||
loading: '加载中...',
|
loading: '加载中...',
|
||||||
fieldRequired: '此字段为必填项',
|
fieldRequired: '此字段为必填项',
|
||||||
or: '或',
|
or: '或',
|
||||||
@@ -276,7 +277,6 @@ const zhHans = {
|
|||||||
platformAdapter: '平台/适配器选择',
|
platformAdapter: '平台/适配器选择',
|
||||||
selectAdapter: '选择适配器',
|
selectAdapter: '选择适配器',
|
||||||
adapterConfig: '适配器配置',
|
adapterConfig: '适配器配置',
|
||||||
viewAdapterDocs: '查看文档',
|
|
||||||
bindPipeline: '绑定流水线',
|
bindPipeline: '绑定流水线',
|
||||||
selectPipeline: '选择流水线',
|
selectPipeline: '选择流水线',
|
||||||
selectBot: '请选择机器人',
|
selectBot: '请选择机器人',
|
||||||
|
|||||||
@@ -64,7 +64,8 @@ const zhHant = {
|
|||||||
privacyPolicy: '隱私政策',
|
privacyPolicy: '隱私政策',
|
||||||
and: '和',
|
and: '和',
|
||||||
dataCollectionPolicy: '數據收集政策',
|
dataCollectionPolicy: '數據收集政策',
|
||||||
dataCollectionPolicyUrl: 'https://link.langbot.app/zh/docs/data-policy',
|
dataCollectionPolicyUrl:
|
||||||
|
'https://docs.langbot.app/zh/insight/data-collection-policy',
|
||||||
loading: '載入中...',
|
loading: '載入中...',
|
||||||
fieldRequired: '此欄位為必填',
|
fieldRequired: '此欄位為必填',
|
||||||
or: '或',
|
or: '或',
|
||||||
@@ -275,7 +276,6 @@ const zhHant = {
|
|||||||
platformAdapter: '平台/適配器選擇',
|
platformAdapter: '平台/適配器選擇',
|
||||||
selectAdapter: '選擇適配器',
|
selectAdapter: '選擇適配器',
|
||||||
adapterConfig: '適配器設定',
|
adapterConfig: '適配器設定',
|
||||||
viewAdapterDocs: '查看文檔',
|
|
||||||
bindPipeline: '綁定流程線',
|
bindPipeline: '綁定流程線',
|
||||||
selectPipeline: '選擇流程線',
|
selectPipeline: '選擇流程線',
|
||||||
selectBot: '請選擇機器人',
|
selectBot: '請選擇機器人',
|
||||||
@@ -963,7 +963,6 @@ const zhHant = {
|
|||||||
embeddingCalls: 'Embedding調用',
|
embeddingCalls: 'Embedding調用',
|
||||||
modelCalls: '模型調用',
|
modelCalls: '模型調用',
|
||||||
sessions: '會話分析',
|
sessions: '會話分析',
|
||||||
feedback: '使用者反饋',
|
|
||||||
errors: '錯誤日誌',
|
errors: '錯誤日誌',
|
||||||
},
|
},
|
||||||
messageList: {
|
messageList: {
|
||||||
@@ -1033,26 +1032,6 @@ const zhHant = {
|
|||||||
stackTrace: '堆疊追蹤',
|
stackTrace: '堆疊追蹤',
|
||||||
title: '錯誤',
|
title: '錯誤',
|
||||||
},
|
},
|
||||||
feedback: {
|
|
||||||
title: '使用者反饋',
|
|
||||||
totalFeedback: '總反饋數',
|
|
||||||
totalLikes: '按讚數',
|
|
||||||
totalDislikes: '按倒讚數',
|
|
||||||
satisfactionRate: '滿意度',
|
|
||||||
like: '按讚',
|
|
||||||
dislike: '按倒讚',
|
|
||||||
noFeedback: '暫無反饋',
|
|
||||||
noFeedbackDescription: '使用者反饋將在此顯示',
|
|
||||||
feedbackList: '反饋列表',
|
|
||||||
feedbackContent: '反饋內容',
|
|
||||||
contextInfo: '上下文資訊',
|
|
||||||
userId: '使用者ID',
|
|
||||||
messageId: '訊息ID',
|
|
||||||
streamId: '串流ID',
|
|
||||||
inaccurateReasons: '不準確原因',
|
|
||||||
platform: '平台',
|
|
||||||
exportFeedback: '匯出反饋',
|
|
||||||
},
|
|
||||||
messageDetails: {
|
messageDetails: {
|
||||||
noData: '此查詢沒有LLM調用或錯誤記錄',
|
noData: '此查詢沒有LLM調用或錯誤記錄',
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user