neuro-simulator 0.6.1__py3-none-any.whl → 0.6.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. README.md +40 -45
  2. neuro_simulator/client/assets/index-rmyQl8Tr.css +1 -0
  3. neuro_simulator/client/index.html +10 -10
  4. neuro_simulator/core/application.py +19 -11
  5. neuro_simulator/dashboard/assets/{AgentView-DBq2msN_.js → AgentView-DGut3feB.js} +2 -2
  6. neuro_simulator/dashboard/assets/{ChatBotView-BqQsuJUv.js → ChatBotView-bvwHe8hJ.js} +2 -2
  7. neuro_simulator/dashboard/assets/{ConfigView-CPYMgl_d.js → ConfigView-DLy2_6Tx.js} +2 -2
  8. neuro_simulator/dashboard/assets/{ContextTab-BSROkcd2.js → ContextTab-Cv2a7xRF.js} +1 -1
  9. neuro_simulator/dashboard/assets/{ControlView-BvflkxO-.js → ControlView-BVJk6r1d.js} +1 -1
  10. neuro_simulator/dashboard/assets/{FieldRenderer-DyPAEyOT.js → FieldRenderer-xMOXYQeU.js} +1 -1
  11. neuro_simulator/dashboard/assets/{LogsTab-C-SZhHdN.js → LogsTab-C7r21Vcz.js} +1 -1
  12. neuro_simulator/dashboard/assets/{LogsView-82wOs2Pp.js → LogsView-DF62M8uv.js} +1 -1
  13. neuro_simulator/dashboard/assets/{MemoryTab-p3Q-Wa4e.js → MemoryTab-BMDqRcHX.js} +1 -1
  14. neuro_simulator/dashboard/assets/{ToolsTab-BxbFZhXs.js → ToolsTab-Ds4M2VeQ.js} +1 -1
  15. neuro_simulator/dashboard/assets/{index-CcYt9OR6.css → index-D2ait7Ff.css} +2 -2
  16. neuro_simulator/dashboard/assets/{index-Ba5ZG3QB.js → index-Sav9Djr5.js} +3 -3
  17. neuro_simulator/dashboard/index.html +3 -3
  18. {neuro_simulator-0.6.1.dist-info → neuro_simulator-0.6.2.dist-info}/METADATA +37 -39
  19. {neuro_simulator-0.6.1.dist-info → neuro_simulator-0.6.2.dist-info}/RECORD +23 -23
  20. neuro_simulator/client/assets/index-C_kzLmQy.css +0 -1
  21. /neuro_simulator/client/assets/{index-DRLWJPZv.js → index-BHgW05Wx.js} +0 -0
  22. {neuro_simulator-0.6.1.dist-info → neuro_simulator-0.6.2.dist-info}/WHEEL +0 -0
  23. {neuro_simulator-0.6.1.dist-info → neuro_simulator-0.6.2.dist-info}/entry_points.txt +0 -0
  24. {neuro_simulator-0.6.1.dist-info → neuro_simulator-0.6.2.dist-info}/licenses/LICENSE +0 -0
README.md CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  *本临时README由AI自动生成*
4
4
 
5
- 这是 Neuro Simulator 的服务端,负责处理直播逻辑、AI 交互、TTS 合成等核心功能
5
+ 这是 Neuro Simulator 的服务端,负责处理直播逻辑、AI 交互、TTS 合成等核心功能。
6
6
 
7
7
  ## 功能特性
8
8
 
9
- - **动态观众**:调用无状态LLM,动态生成观众聊天内容,支持 Gemini 和 OpenAI API
9
+ - **动态观众**:调用LLM,基于直播内容动态生成 Chat
10
10
  - **配置管理**:支持通过 API 动态修改和热重载配置
11
11
  - **外部控制**:完全使用外部API端点操控服务端运行
12
12
 
@@ -15,7 +15,7 @@
15
15
  ``` main
16
16
  neuro_simulator/
17
17
  ├── __init__.py
18
- ├── cli.py # 命令行启动脚本
18
+ ├── cli.py
19
19
  ├── agent/
20
20
  │ ├── __init__.py
21
21
  │ ├── core.py
@@ -49,7 +49,6 @@ neuro_simulator/
49
49
  │ ├── audience.py
50
50
  │ ├── audio.py
51
51
  │ ├── builtin.py
52
- │ ├── letta.py
53
52
  │ └── stream.py
54
53
  └── utils/
55
54
  ├── __init__.py
@@ -61,11 +60,10 @@ neuro_simulator/
61
60
  ```
62
61
 
63
62
  ``` workin'dir
64
- working_dir_example/ # 工作目录结构,请将这个目录重命名和复制到你想要的位置(推荐放到~/.config/neuro-simulator)
63
+ working_dir_example/ # 工作目录结构,供你参考
65
64
  ├── assets/ # 媒体文件夹,如缺失会使用自带资源覆盖
66
65
  │ └── neuro_start.mp4 # 用来计算Start Soon长度,仅读取时长,请和客户端的视频保持一致
67
- ├── config.yaml # 由用户手工创建的配置文件
68
- ├── config.yaml.example # 自动生成的配置文件模板,必须手动重命名和填写
66
+ ├── config.yaml # 系统配置文件,由服务端自动管理,无需手动填写
69
67
  └── agents/ # Agent相关文件夹
70
68
  ├── memories/ # Agent记忆文件夹
71
69
  │ ├── core_memory.json
@@ -85,34 +83,35 @@ working_dir_example/ # 工作目录结构,请将这个目录重命名和
85
83
 
86
84
  ## 安装与配置
87
85
 
88
- 1. 复制一份 `../docs/working_dir_example` 到你想要的位置,作为配置文件目录.
89
- - 程序会在未指定 `--dir` 的情况下自动生成一个工作目录,路径为 `~/.config/neuro-simulator/`
90
- 2. 然后进入配置文件目录,复制 `config.yaml.example` 到 `config.yaml`
91
- 3. 编辑 `config.yaml` 文件,填入必要的 API 密钥和配置项:
92
- - 如果使用 Letta Agent,需要配置 Letta Token 和 Agent ID
93
- - Gemini/OpenAI API Key(用于观众聊天生成和 Agent)
94
- - Azure TTS Key 和 Region
86
+ 1. 自己找一个最好是空的文件夹作为工作目录。
87
+ - 程序会在未指定 `--dir, -D` 的情况下自动生成一个工作目录,路径为 `~/.config/neuro-simulator/`。
88
+ 2. 启动程序,按照外面那个 README 中的方式完成配置。
95
89
 
96
- 可以自行替换 `$dir/assets/neuro_start.mp4` 为其它视频文件,但记得手动替换 client 中的同名文件
90
+ 3. 可以自行替换 `$dir/assets/neuro_start.mp4` 为其它视频文件,但记得手动替换 client 中的同名文件。
97
91
 
98
92
  ### Agent配置
99
93
 
100
- 服务端支持两种Agent类型:
101
- 1. **Letta Agent**:需要配置 Letta Cloud 或自托管的 Letta Server
102
- 2. **内建 Agent**:使用服务端自带的 Agent,支持 Gemini 和OpenAI API
94
+ 服务端支持两种 Agent 类型:
95
+ ~~1. **Letta Agent**:需要配置 Letta Cloud 或自托管的 Letta Server~~ 暂时下线,后会有期。
96
+ 2. **内建 Agent**:使用服务端自带的 Agent,支持 Gemini 和OpenAI API
103
97
 
104
- `config.yaml` 中通过 `agent_type` 字段选择使用的 Agent 类型:
105
- - `agent_type: "letta"`:使用 Letta Agent
106
- - `agent_type: "builtin"`:使用内建 Agent
107
-
108
- 当使用内建Agent时,还需要配置:
109
- - `agent.agent_provider`:选择"gemini"或"openai"
110
- - `agent.agent_model`:指定具体的模型名称
98
+ 不管用的是什么 Agent,在管理面板中配置和分配好服务商相关就行了。
111
99
 
112
100
  ### 直接安装方式(无需二次开发)
113
101
 
114
102
  若无需二次开发,可以直接使用 pip 安装:
115
103
  ```bash
104
+ # 直接使用 pip 安装为全局软件:
105
+ pip install neuro-simulator
106
+ ```
107
+
108
+ ```bash
109
+ # 系统 Python 环境不宜变动时,建议使用 pipx 安装为全局软件
110
+ pipx install neuro-simulator
111
+ ```
112
+
113
+ ```bash
114
+ # 使用 venv 方式安装:
116
115
  python3 -m venv venv
117
116
  # Windows
118
117
  venv/Scripts/pip install neuro-simulator
@@ -132,6 +131,7 @@ venv/Scripts/pip install -e .
132
131
  # macOS/Linux
133
132
  venv/bin/pip install -e .
134
133
  ```
134
+ 安装时会自动构建 Dashboard 和 Client,请确保系统安装了 Node.js。
135
135
 
136
136
  ### 运行服务
137
137
 
@@ -142,43 +142,34 @@ neuro
142
142
  # 指定工作目录
143
143
  neuro -D /path/to/your/config
144
144
 
145
- # 指定主机和端口
145
+ # 指定监听地址和端口
146
146
  neuro -H 0.0.0.0 -P 8080
147
147
 
148
148
  # 组合使用
149
149
  neuro -D /path/to/your/config -H 0.0.0.0 -P 8080
150
150
  ```
151
151
 
152
- 服务默认运行在 `http://127.0.0.1:8000`
152
+ 手动指定的监听地址和端口会覆盖配置文件中的设置。
153
153
 
154
- ## API 接口
154
+ 如果没有指定,服务默认遵循配置文件中的设置,运行在 `http://127.0.0.1:8000`。
155
155
 
156
- 服务端的主要管理和控制功能已统一迁移至 WebSocket 接口 `/ws/admin`。原有的 HTTP API 仅保留 `/api/system/health` 用于建立 WS 连接前的健康检查
156
+ ## API 接口
157
157
 
158
- - `/ws/admin`: 用于控制面板的管理接口,提供直播控制、配置管理、日志监控、Agent交互等所有功能,详细规范请参阅 `WEBSOCKET_API.md`
159
- - `/ws/stream`: 客户端使用的直播接口
160
- - `/api/system/health`: 健康检查接口
161
- - `/docs`: 自动生成的API文档 (Swagger UI)
158
+ - `/ws/admin`: 用于控制面板的管理接口,提供直播控制、配置管理、日志监控、Agent交互等所有功能,详细规范请参阅 `WEBSOCKET_API.md`。
159
+ - `/ws/stream`: 客户端使用的直播接口。
160
+ - `/api/system/health`: 健康检查接口。
162
161
 
163
162
  ## 配置说明
164
163
 
165
- 配置文件 `config.yaml` 包含以下主要配置项:
166
-
167
- - `api_keys` - 各种服务的 API 密钥
168
- - `stream_metadata` - 直播元数据(标题、分类、标签等)
169
- - `neuro_behavior` - Neuro 行为设置
170
- - `audience_simulation` - 观众模拟设置
171
- - `tts` - TTS 语音合成设置
172
- - `performance` - 性能相关设置
173
- - `server` - 服务器设置(主机、端口、CORS 等)
164
+ 配置文件 `config.yaml` 现在一般无需手动编辑,所有配置项在管理面板中均可进行可视化配置。
174
165
 
175
166
  有关配置文件的完整示例,请参阅项目根目录下的 `docs/working_dir_example/` 文件夹
176
167
 
177
168
  ## 安全说明
178
169
 
179
- 1. 通过 `panel_password` 配置项可以设置控制面板访问密码
180
- 2. 敏感配置项(如 API 密钥)不会通过 API 接口暴露
181
- 3. 支持 CORS,仅允许预配置的来源访问
170
+ 服务端具有 CORS 配置,仅允许预配置的来源访问。如果莫名其妙地连不上服务端(尤其是在外网环境中),可以检查和更改此项设置。
171
+
172
+ **公网部署请务必更改管理密钥**,建议更改端口为非常规端口以避免爆破。咱这个程序只是能用就行的水平,永远不要相信它的安保性能。
182
173
 
183
174
  ## 故障排除
184
175
 
@@ -186,3 +177,7 @@ neuro -D /path/to/your/config -H 0.0.0.0 -P 8080
186
177
  - 检查网络连接是否正常
187
178
  - 查看日志文件获取错误信息
188
179
  - 确保端口未被其他程序占用
180
+
181
+ > 都是些 AI 生成的垃圾话,看看就好
182
+
183
+ *作为看这篇💩文档的奖励,如果你需要使用外部面板而不是服务器自托管面板,可以直接使用我部署的 https://dashboard.neuro.jiahui.cafe 连接到你的服务端,但是不保证始终能用,而且请配置好 CORS*
@@ -0,0 +1 @@
1
+ :root{--twitch-purple: #9147FF;--twitch-dark-bg: #F2F2F2;--twitch-chat-bg: #FFFFFF;--twitch-text-color: #18181B;--twitch-secondary-text-color: #6A6A6D;--twitch-border-color: #D3D3D3;--twitch-hover-bg: #EFEFF1;--twitch-button-bg: #EFEFF1;--twitch-button-text-color: #0E0E10;--twitch-button-hover-bg: #DFDFE1;--twitch-primary-button-bg: var(--twitch-purple);--twitch-primary-button-text-color: #FFFFFF;--twitch-primary-button-hover-bg: #772CE8;--twitch-tag-bg: #EFEFF1;--twitch-tag-text-color: #6A6A6D;--twitch-live-red: #EB0400;--twitch-viewer-red: #971311;--sidebar-width: 340px;--header-height: 50px;--neuro-shadow-color: #32003C;--neuro-avatar-display-width-percent: 50%;--fast-transition: background-color .2s, color .2s;--twitch-dark-button-bg: #333333;--twitch-dark-button-hover-bg: #444444;--twitch-dark-button-text-color: #FFFFFF;--sc-pink-bg-color: #f68795;--sc-purple-bg-color: #b97ad5}@font-face{font-family:First Coffee;src:url(/fonts/first-coffee.woff2) format("woff2");font-weight:400;font-style:normal}@font-face{font-family:Comic Sans MS;src:url(/fonts/comic.woff2) format("woff2");font-weight:400;font-style:normal}@font-face{font-family:Noto Sans SC;src:url(/fonts/noto-sans-sc.woff2) format("woff2");font-weight:400;font-style:normal}@font-face{font-family:Causten;src:url(/fonts/causten.woff2) format("woff2");font-weight:400;font-style:normal}html,body{height:100%;margin:0;padding:0;overflow:hidden}body{font-family:Inter,Arial,sans-serif;display:flex;flex-direction:column;background-color:var(--twitch-dark-bg);color:var(--twitch-text-color)}.twitch-button{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:0 10px;border-radius:100px;font-size:.9em;font-weight:600;cursor:pointer;border:none;transition:var(--fast-transition);outline:none;background-color:var(--twitch-button-bg);color:var(--twitch-button-text-color);height:32px;box-sizing:border-box;line-height:1}.twitch-button svg{width:1.2em;height:1.2em;fill:currentColor;vertical-align:middle}.twitch-button span{padding-top:2px}.twitch-button:hover:not(:disabled){background-color:var(--twitch-button-hover-bg)}.twitch-button.subscribe-button{background-color:var(--twitch-primary-button-bg);color:var(--twitch-primary-button-text-color)}.twitch-button.subscribe-button:hover:not(:disabled){background-color:var(--twitch-primary-button-hover-bg)}.twitch-button.icon-button{width:32px;padding:0;border-radius:50%}.nav-icon-button{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:0;border-radius:50%;font-size:.9em;font-weight:600;cursor:pointer;border:none;transition:var(--fast-transition);outline:none;background-color:transparent;color:var(--twitch-button-text-color);width:32px;height:32px;box-sizing:border-box;line-height:1}.nav-icon-button:hover:not(:disabled){background-color:var(--twitch-button-hover-bg);border-radius:50%}.nav-icon-button svg{width:20px;height:20px;fill:currentColor;vertical-align:middle}.search-button{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:0;font-size:.9em;font-weight:600;cursor:pointer;border:none;transition:var(--fast-transition);outline:none;background-color:transparent;color:var(--twitch-button-text-color);width:32px;height:32px;box-sizing:border-box;line-height:1}.search-button:hover:not(:disabled){background-color:var(--twitch-button-hover-bg)}.search-button svg{width:20px;height:20px;fill:currentColor;vertical-align:middle}.chat-toolbar-button{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:0;border-radius:50%;font-size:.9em;font-weight:600;cursor:pointer;border:none;transition:var(--fast-transition);outline:none;background-color:transparent;color:var(--twitch-button-text-color);width:32px;height:32px;box-sizing:border-box;line-height:1}.chat-toolbar-button:hover:not(:disabled){background-color:var(--twitch-button-hover-bg);border-radius:50%}.chat-toolbar-button svg{width:20px;height:20px;fill:currentColor;vertical-align:middle}.chat-toolbar-button img{width:20px;height:20px;object-fit:contain}.video-overlay-chat-button{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:0;border-radius:50%;font-size:.9em;font-weight:600;cursor:pointer;border:none;transition:var(--fast-transition);outline:none;background-color:#0009;color:#fff;width:32px;height:32px;box-sizing:border-box;line-height:1}.video-overlay-chat-button:hover:not(:disabled){background-color:#000c;border-radius:50%}.video-overlay-chat-button svg{width:20px;height:20px;fill:#fff;vertical-align:middle}.mute-button{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:0;border-radius:50%;font-size:.9em;font-weight:600;cursor:pointer;border:none;transition:var(--fast-transition);outline:none;background-color:#0009;color:#fff;width:32px;height:32px;box-sizing:border-box;line-height:1}.mute-button:hover:not(:disabled){background-color:#000c;border-radius:50%}.mute-button svg{width:20px;height:20px;fill:#fff;vertical-align:middle}.twitch-button.dark{background-color:var(--twitch-dark-button-bg);color:var(--twitch-dark-button-text-color)}.twitch-button.dark:hover:not(:disabled){background-color:var(--twitch-dark-button-hover-bg)}.twitch-button.dark svg,.twitch-button.dark img{fill:var(--twitch-dark-button-text-color)}.twitch-button img{width:20px;height:20px;object-fit:contain;vertical-align:middle}.chat-toolbar-text-button{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:0 10px;border-radius:100px;font-size:.9em;font-weight:600;cursor:pointer;border:none;transition:var(--fast-transition);outline:none;background-color:transparent;color:var(--twitch-button-text-color);height:32px;box-sizing:border-box;line-height:1}.chat-toolbar-text-button:hover:not(:disabled){background-color:var(--twitch-button-hover-bg)}.chat-toolbar-text-button svg,.chat-toolbar-text-button img{width:1.2em;height:1.2em;fill:currentColor;vertical-align:middle;object-fit:contain}.chat-toolbar-text-button .points-value{padding-top:2px}.chat-toolbar-text-button .channel-points-icon{width:1.2em;height:1.2em;object-fit:contain}#twitch-header{height:var(--header-height);background-color:var(--twitch-chat-bg);display:flex;justify-content:space-between;align-items:center;padding:0 1rem;border-bottom:1px solid var(--twitch-border-color);flex-shrink:0;z-index:100;color:var(--twitch-text-color);gap:1rem}.top-nav-left,.top-nav-right{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.top-nav-center{flex-grow:1;flex-shrink:1;display:flex;justify-content:center;min-width:150px}.twitch-logo-link{display:flex;align-items:center;text-decoration:none;margin-left:.5rem}.twitch-logo-container{margin:0;transform:scaleY(-1);transition:transform .3s ease-out}.twitch-logo-container:hover{transform:scaleY(1)}.twitch-logo-svg .logo-body{fill:var(--twitch-purple)}.twitch-logo-svg .logo-face{fill:var(--twitch-chat-bg)}.twitch-logo-svg .logo-eye-path{fill:var(--twitch-purple)}.nav-links-main{display:flex;gap:1.5rem;margin-left:1.5rem}.nav-link{display:flex;align-items:center;gap:.5rem;text-decoration:none;color:var(--twitch-text-color);font-weight:500;font-size:1.1rem;padding:.25rem .5rem;border-radius:4px;transition:var(--fast-transition)}.nav-link:hover{color:var(--twitch-purple)}.nav-link p{margin:0}.search-container{display:flex;align-items:center;width:100%;max-width:400px;border:1px solid var(--twitch-border-color);border-radius:8px;overflow:hidden;background-color:var(--twitch-button-bg)}.search-input{flex:1 1 0;min-width:50px;padding:.5rem .75rem;border:none;background-color:transparent;color:var(--twitch-text-color);font-size:.95rem;outline:none}.search-input::placeholder{color:var(--twitch-secondary-text-color)}.search-button{flex-shrink:0;display:flex;align-items:center;justify-content:center;padding:0 .5rem}.search-button svg{fill:var(--twitch-text-color)}.top-nav-right{gap:.75rem}.nav-user-avatar-button{background:none;border:none;cursor:pointer;padding:0;border-radius:50%;width:32px;height:32px;overflow:hidden;flex-shrink:0}.user-avatar-wrapper{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.user-avatar-img{width:100%;height:100%;object-fit:cover;border-radius:50%}#main-content-wrapper{flex-grow:1;display:flex;overflow:hidden;position:relative}#stream-and-info-container{flex-grow:1;flex-shrink:1;display:flex;flex-direction:column;overflow-y:auto;min-height:0;scrollbar-width:none}#stream-and-info-container::-webkit-scrollbar{display:none}#stream-display-viewport{flex-grow:1;background-color:#000;display:flex;justify-content:center;align-items:center;overflow:hidden;min-height:0;position:relative}#mute-button{position:absolute;bottom:1rem;left:1rem;z-index:60}#stream-display-area{position:relative;background-color:#000;overflow:hidden;flex-shrink:0;visibility:hidden;opacity:0;transition:opacity .3s ease-in-out;container-type:size;container-name:streamArea}#background-display,#startup-video-overlay{position:absolute;top:0;left:0;width:100%;height:100%}#background-display{z-index:0;pointer-events:none;background:url(/background.webp) center/cover no-repeat}#neuro-static-avatar-container{position:absolute;left:70%;transform:translate(-50%);width:var(--neuro-avatar-display-width-percent);height:auto;overflow:visible;pointer-events:none;z-index:15;visibility:hidden;transition:transform .5s ease-in-out}#neuro-static-avatar-container img{width:100%;height:auto;display:block}.spin-animation{animation:spin-counter-clockwise .75s linear}@keyframes spin-counter-clockwise{0%{transform:translate(-50%) rotate(0)}to{transform:translate(-50%) rotate(-360deg)}}#neuro-static-avatar-container.zoom-in{transform:translate(-50%) scale(1.15)}#neuro-caption{position:absolute;bottom:5%;left:50%;transform:translate(-50%);width:90%;padding:10px 20px;border-radius:10px;text-align:center;font-weight:400;opacity:1;pointer-events:none;z-index:20;color:#fff;transition:none;text-shadow:0 0 4px var(--neuro-shadow-color),0 0 4px var(--neuro-shadow-color),0 0 4px var(--neuro-shadow-color);font-family:First Coffee,Noto Sans SC;font-size:3cqi}#neuro-caption:not(.show){opacity:0}#startup-video-overlay{background-color:#000;z-index:10;display:flex;justify-content:center;align-items:center;opacity:1;transition:none}#startup-video-overlay.hidden{opacity:0;pointer-events:none;visibility:hidden}#startup-video{width:100%;height:100%;object-fit:contain}#show-chat-button{position:absolute;top:1rem;right:1rem;z-index:60;background-color:#0009;border:none;border-radius:50%;padding:0;cursor:pointer;display:flex;align-items:center;justify-content:center;color:#fff;transition:background-color .2s,opacity .3s ease-in-out,visibility .3s ease-in-out;opacity:0;visibility:hidden;pointer-events:none;width:32px;height:32px;box-sizing:border-box}#show-chat-button:hover{background-color:#000c}#show-chat-button svg{width:20px;height:20px;fill:currentColor}body.chat-collapsed #show-chat-button{opacity:1;visibility:visible;pointer-events:auto}#twitch-chat-overlay{position:absolute;top:0;left:0;width:25%;height:50%;background-color:transparent;color:#fff;padding:10px;overflow-y:auto;z-index:5;font-size:1.5cqi;scrollbar-width:none;font-family:Comic Sans MS,Noto Sans SC;pointer-events:none;-webkit-user-select:none;user-select:none;scroll-behavior:auto}#twitch-chat-overlay::-webkit-scrollbar{display:none}#twitch-chat-overlay *{pointer-events:none;-webkit-user-select:none;user-select:none}#twitch-chat-overlay .chat-line__message{padding:2px 0;margin:0;text-shadow:-1px -1px 0 #00000080,1px -1px 0 #00000080,-1px 1px 0 #00000080,1px 1px 0 #00000080,2px 2px 0 rgba(0,0,0,.5);font-size:1.5cqi}#twitch-chat-overlay .chat-line__username{font-weight:700;margin-right:.25rem;font-size:1.5cqi}#twitch-chat-overlay .text-fragment{font-weight:700;color:#fff;font-size:1.5cqi}#twitch-chat-overlay .chat-author__display-name{font-size:1.5cqi}#twitch-chat-overlay .chat-line__message-container>span:not(.chat-line__username){font-weight:700;color:#fff;text-shadow:-1px -1px 0 #00000080,1px -1px 0 #00000080,-1px 1px 0 #00000080,1px 1px 0 #00000080,2px 2px 0 rgba(0,0,0,.5);font-size:1.5cqi}#stream-display-viewport *:not(.mute-button):not(#show-chat-button){pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}#stream-info{padding:10px 20px;background-color:var(--twitch-chat-bg);border-bottom:1px solid var(--twitch-border-color)}.stream-info-layout{display:flex;gap:16px;align-items:center}.stream-info-left-column{flex-shrink:0}.streamer-avatar-link{display:block;position:relative}.streamer-avatar-wrapper{position:relative}#streamer-avatar{width:64px;height:64px;border-radius:50%;border:2px solid transparent;transition:border-color .2s}.streamer-avatar-link:hover #streamer-avatar{border-color:var(--twitch-purple)}.live-indicator-wrapper{position:absolute;bottom:-2px;left:50%;transform:translate(-50%);z-index:2}.live-indicator-rect{background-color:var(--twitch-live-red);color:#fff;font-size:.7em;font-weight:600;padding:2px 6px;border-radius:4px;white-space:nowrap;border:2px solid var(--twitch-chat-bg);text-transform:uppercase}.stream-info-right-column{display:flex;flex-direction:column;flex-grow:1;gap:4px;min-width:0}.stream-info-main-row{display:flex;justify-content:space-between;align-items:center}.streamer-info-and-name{display:flex;align-items:center;gap:6px;min-width:0}#streamer-nickname{margin:0;font-size:1.2em;color:var(--twitch-text-color);font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.verified-badge svg{width:16px;height:16px;fill:var(--twitch-purple)}.main-action-buttons{display:flex;gap:6px;align-items:center;flex-shrink:0}#stream-info .twitch-button{display:inline-flex;align-items:center;justify-content:center;height:30px;padding:6px 10px;box-sizing:border-box}#stream-info .twitch-button.follow-button,#stream-info .twitch-button.icon-button{width:30px;padding:0}#stream-info .twitch-button:not(.follow-button):not(.icon-button){padding-top:0;padding-bottom:1px}#stream-info .twitch-button svg{width:18px;height:18px}.stream-info-details-row{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}.stream-details-left{display:flex;flex-direction:column;gap:6px;min-width:0}#stream-title-full{margin:0;font-size:.9em;font-weight:600;color:var(--twitch-text-color);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.stream-category-and-tags{display:flex;align-items:center;gap:6px;min-width:0}.stream-category{font-size:.9em;color:var(--twitch-purple);text-decoration:none;font-weight:500;transition:color .2s;flex-shrink:0}.stream-category:hover{text-decoration:underline}.stream-tags{display:flex;gap:6px;align-items:center;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.stream-tags::-webkit-scrollbar{display:none}.stream-tag{display:inline-flex;align-items:center;padding:3px 8px;border-radius:100px;background-color:var(--twitch-tag-bg);color:var(--twitch-tag-text-color);font-size:.75em;font-weight:600;text-decoration:none;transition:background-color .2s;height:20px;box-sizing:border-box;flex-shrink:0}.stream-tag:hover{background-color:var(--twitch-button-hover-bg)}.stream-details-right{display:flex;align-items:center;gap:12px;flex-shrink:0}.stream-stats-section{display:flex;gap:0px;align-items:center;font-size:.9em;color:var(--twitch-secondary-text-color);justify-content:flex-end}.viewer-count,.stream-duration{display:flex;align-items:center;gap:4px}.viewer-count{color:var(--twitch-viewer-red)}.viewer-count svg{width:18px;height:18px;fill:currentColor}.viewer-count strong{font-weight:600}.stream-duration .duration-text{font-weight:500;color:var(--twitch-text-color);min-width:4.5em;text-align:right}.stream-secondary-actions{display:flex;gap:6px}.stream-secondary-actions .twitch-button{background-color:transparent}.stream-secondary-actions .twitch-button:hover:not(:disabled){background-color:var(--twitch-button-hover-bg)}#chat-sidebar{width:var(--sidebar-width);min-width:var(--sidebar-width);background-color:var(--twitch-chat-bg);flex-shrink:0;display:flex;flex-direction:column;border-left:1px solid var(--twitch-border-color);z-index:50;height:100%;transition:width .3s ease-in-out,min-width .3s ease-in-out}#chat-sidebar.collapsed{width:0;min-width:0;overflow:hidden;visibility:hidden;pointer-events:none}.chat-sidebar-header{height:3.5rem;display:flex;justify-content:space-between;align-items:center;padding:0 1rem;border-bottom:1px solid var(--twitch-border-color);flex-shrink:0;position:relative}.chat-header-left,.chat-header-right{display:flex;align-items:center;gap:.5rem;z-index:1}.chat-sidebar-header .chat-title{position:absolute;left:50%;transform:translate(-50%);margin:0;font-size:1rem;font-weight:600;color:var(--twitch-text-color)}.chat-toggle-button{display:flex;align-items:center;justify-content:center;background:none;border:none;border-radius:50%;padding:0;cursor:pointer;color:var(--twitch-text-color);transition:background-color .2s;width:32px;height:32px;box-sizing:border-box}.chat-toggle-button:hover{background-color:var(--twitch-hover-bg)}.chat-toggle-button svg{width:20px;height:20px;fill:currentColor}#chat-sidebar.collapsed .chat-toggle-button{transform:rotate(180deg)}.messages-display{flex-grow:1;overflow-y:auto;padding:.5rem 1rem;min-height:0;scrollbar-width:thin;scrollbar-color:#B0B0B0 var(--twitch-hover-bg)}.messages-display::-webkit-scrollbar{width:8px}.messages-display::-webkit-scrollbar-track{background:var(--twitch-hover-bg);border-radius:4px}.messages-display::-webkit-scrollbar-thumb{background:#b0b0b0;border-radius:4px}.messages-display::-webkit-scrollbar-thumb:hover{background:#888}.chat-line__message{display:flex;align-items:flex-start;padding:.3rem 0;line-height:1.5;word-wrap:break-word;color:var(--twitch-text-color);border-radius:4px}.chat-line__message:hover{background-color:#ffffff0d}.chat-line__message-container{display:inline}.chat-line__username{font-weight:700;display:inline-block;margin-right:.1rem;cursor:pointer}.chat-author__display-name{font-size:.9rem}.text-fragment{font-size:.9rem;color:var(--twitch-text-color)}.chat-line__message.user-sent-message{background-color:#9147ff1a;border-left:3px solid var(--twitch-purple);padding-left:.75rem}.chat-line__message.system-message{color:var(--twitch-secondary-text-color);font-style:italic;font-size:.85rem;justify-content:center}.chat-line__message.system-message .chat-line__username,.chat-line__message.system-message .text-fragment{font-size:inherit;color:inherit;font-weight:400}.chat-input-area{padding:.75rem 1rem;border-top:1px solid var(--twitch-border-color);flex-shrink:0}.chat-input-and-buttons{display:flex;flex-direction:column;gap:.5rem}.chat-input-textarea-container{display:flex;align-items:center;border:1px solid var(--twitch-border-color);border-radius:4px;background-color:var(--twitch-button-bg);padding:0 .5rem;transition:var(--fast-transition)}.chat-input-textarea-container:focus-within{border-color:var(--twitch-purple);box-shadow:0 0 0 2px #9147ff33}.chat-input-prefix-icons,.chat-input-suffix-icons{display:flex;align-items:center}.chat-input-wrapper{flex-grow:1}.chat-input-element{width:100%;height:2.25rem;padding:0 .5rem;border:none;background-color:transparent;color:var(--twitch-text-color);font-size:.95rem;outline:none}.chat-input-element::placeholder{color:var(--twitch-secondary-text-color)}.chat-input-buttons-container{display:flex;justify-content:space-between;align-items:center}.chat-buttons-left,.chat-buttons-right{display:flex;align-items:center;gap:.5rem}.chat-points-display{display:flex;align-items:center;gap:.25rem;font-size:.85rem;color:var(--twitch-secondary-text-color)}.chat-points-display svg,.chat-points-display .channel-points-icon{width:18px;height:18px;fill:currentColor;object-fit:contain}.chat-points-display .points-value{color:var(--twitch-text-color);font-weight:600}#send-button:disabled{background-color:#b0b0b0;cursor:not-allowed}.chat-toolbar-text-button.selected{background-color:var(--twitch-purple-light);border:1px solid var(--twitch-purple);box-shadow:0 0 5px var(--twitch-purple-light)}#highlight-message-overlay{position:absolute;left:41%;transform:translate(-50%) translateY(-200%);width:24vw;height:auto;z-index:100;transition:transform 1s}#highlight-message-overlay.is-visible{transform:translate(-50%) translateY(0);transition-timing-function:cubic-bezier(.25,1,.5,1)}.sc-background-image{width:100%;height:auto;display:block;border-radius:20px}.sc-content{position:absolute;top:0;left:0;width:100%;height:100%;z-index:2;color:#fff;font-family:Causten}.sc-user{position:absolute;top:20%;left:40%;transform:translate(-50%);font-size:2cqi;text-align:left}.sc-message{position:absolute;top:60%;left:50%;transform:translate(-50%,-50%);width:90%;font-size:2cqi;text-align:center;overflow-wrap:break-word}.settings-modal-container{position:fixed;top:0;left:0;width:100%;height:100%;z-index:1000;display:flex;justify-content:center;align-items:center}.settings-modal-container.hidden{display:none}.modal-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#0009}.modal-content{position:relative;background-color:var(--twitch-chat-bg);color:var(--twitch-text-color);border-radius:8px;width:90%;max-width:450px;box-shadow:0 4px 20px #0003;display:flex;flex-direction:column}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:1rem 1.5rem;border-bottom:1px solid var(--twitch-border-color)}.modal-header h2{margin:0;font-size:1.25rem}.modal-body{padding:1.5rem;display:flex;flex-direction:column;gap:1.5rem}.setting-item{display:flex;flex-direction:column;gap:.5rem}.setting-item label{font-weight:600;font-size:.9rem}.modal-input{padding:.75rem;border:1px solid var(--twitch-border-color);border-radius:4px;background-color:var(--twitch-button-bg);color:var(--twitch-text-color);font-size:1rem}.modal-input:focus{outline:none;border-color:var(--twitch-purple);box-shadow:0 0 0 2px #9147ff33}.avatar-setting .avatar-preview-container{display:flex;align-items:center;gap:1rem}.avatar-preview{width:60px;height:60px;border-radius:50%;object-fit:cover;border:2px solid var(--twitch-border-color)}.avatar-upload-input{display:none}.modal-footer{padding:1rem 1.5rem;border-top:1px solid var(--twitch-border-color);display:flex;justify-content:flex-end}.setting-description{font-size:.8rem;color:var(--twitch-secondary-text-color);margin:4px 0 0}.turbo-button-icon{display:none}.turbo-button-full{display:inline-flex}@media (max-width: 992px){.turbo-button-full{display:none}.turbo-button-icon{display:inline-flex}}@media (max-width: 767px){body,#main-content-wrapper{flex-direction:column}#stream-and-info-container{width:100%}#chat-sidebar{width:100%;height:40vh;min-height:200px;min-width:unset;border-left:none;border-top:1px solid var(--twitch-border-color)}#chat-sidebar.collapsed{height:0;min-height:0;overflow:hidden;visibility:hidden;pointer-events:none}.nav-links-main,button[aria-label=Prime],button[aria-label=打开通知],button[aria-label=悄悄话],button[aria-label=购买呼币],button[aria-label=免费体验无广告观赏],button#show-chat-button,button[aria-label=通知],button.twitch-button[aria-label=购买呼币],button.twitch-button[aria-label=赠送一次订阅],.stream-details-right,.chat-sidebar-header{display:none!important}*{scrollbar-width:none!important}*::-webkit-scrollbar{display:none!important}*::-webkit-scrollbar-thumb{display:none!important}*::-webkit-scrollbar-track{display:none!important}#streamer-avatar{width:50px;height:50px}}.tooltip{position:absolute;background:#18181b;color:#fff;padding:6px 10px;font-size:12px;border-radius:4px;pointer-events:none;opacity:0;transition:opacity .2s ease;white-space:nowrap;z-index:1000;transform-origin:center bottom;-webkit-user-select:none;user-select:none}.tooltip.show{opacity:1}.tooltip:after{content:"";position:absolute;left:50%;transform:translate(-50%);border-width:6px;border-style:solid;top:100%;border-color:#18181b transparent transparent transparent;transition:border-color .2s ease,top .2s ease}.tooltip.tooltip-arrow-up:after{top:-12px;border-color:transparent transparent #18181b transparent}.hidden{display:none!important}#offline-content-container{display:flex;flex-direction:row;align-items:center;justify-content:center;flex-wrap:wrap;width:100%;min-height:500px;flex-grow:1;background-image:url(/banner.jpeg);background-size:cover;background-position:center;background-repeat:no-repeat;padding:2rem;gap:2rem;box-sizing:border-box}.offline-info-card{display:flex;flex-direction:column;align-items:flex-start;background-color:#fff;padding:1.5rem;border-radius:0;color:#0e0e10;box-shadow:0 4px 10px #0000001a;box-sizing:border-box;flex:0 1 270px}.offline-status-section{display:flex;flex-direction:column;justify-content:center;align-items:flex-start;flex-grow:1;gap:.75rem}.offline-status-badge{background-color:#000;color:#fff;font-size:.9em;font-weight:600;padding:2px 6px;border-radius:4px;white-space:nowrap;text-transform:uppercase}.offline-status-title{font-size:1.6rem;font-weight:600;margin:0}.offline-notification-section{width:100%;margin-left:-10px}.offline-notification-button{background-color:transparent;color:var(--twitch-primary-button-hover-bg);justify-content:flex-start}.offline-notification-button:hover{background-color:var(--twitch-button-hover-bg);color:var(--twitch-button-text-color)}.offline-notification-button svg{fill:currentColor}.offline-video-player{aspect-ratio:16 / 9;flex:0 1 576px;min-width:300px;max-width:576px}@font-face{font-family:Inter;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/inter-cyrillic-ext-400-normal-Dc4VJyIJ.woff2) format("woff2"),url(/assets/inter-cyrillic-ext-400-normal-BE2fNs0E.woff) format("woff");unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/inter-cyrillic-400-normal-BLGc9T1a.woff2) format("woff2"),url(/assets/inter-cyrillic-400-normal-alAqRL36.woff) format("woff");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/inter-greek-ext-400-normal-Bput3-QP.woff2) format("woff2"),url(/assets/inter-greek-ext-400-normal-XIH6-K3k.woff) format("woff");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/inter-greek-400-normal-DxZsaF_h.woff2) format("woff2"),url(/assets/inter-greek-400-normal-C3I71FoW.woff) format("woff");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/inter-vietnamese-400-normal-DMkecbls.woff2) format("woff2"),url(/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff) format("woff");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/inter-latin-ext-400-normal-C1nco2VV.woff2) format("woff2"),url(/assets/inter-latin-ext-400-normal-77YHD8bZ.woff) format("woff");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter;font-style:normal;font-display:swap;font-weight:400;src:url(/assets/inter-latin-400-normal-C38fXH4l.woff2) format("woff2"),url(/assets/inter-latin-400-normal-CyCys3Eg.woff) format("woff");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@@ -2,11 +2,11 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
- <link rel="icon" type="image/x-icon" href="./favicon.ico" />
5
+ <link rel="icon" type="image/x-icon" href="/favicon.ico" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>𝐯𝐞𝐝𝐚𝐥𝟗𝟖𝟕 - 𝐓𝐰𝐢𝐭𝐜𝐡</title>
8
- <script type="module" crossorigin src="./assets/index-DRLWJPZv.js"></script>
9
- <link rel="stylesheet" crossorigin href="./assets/index-C_kzLmQy.css">
8
+ <script type="module" crossorigin src="/assets/index-BHgW05Wx.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-rmyQl8Tr.css">
10
10
  </head>
11
11
  <body>
12
12
  <header id="twitch-header">
@@ -69,7 +69,7 @@
69
69
 
70
70
  <button class="nav-user-avatar-button" aria-expanded="false" aria-label="用户菜单">
71
71
  <div class="user-avatar-wrapper">
72
- <img class="user-avatar-img" alt="用户头像" src="./user_avatar.jpg" style="object-fit: cover;">
72
+ <img class="user-avatar-img" alt="用户头像" src="/user_avatar.jpg" style="object-fit: cover;">
73
73
  </div>
74
74
  </button>
75
75
  </div>
@@ -81,11 +81,11 @@
81
81
  <div id="stream-display-area">
82
82
  <div id="background-display" data-darkreader-ignore></div>
83
83
  <div id="neuro-static-avatar-container">
84
- <img id="neuro-static-avatar" src="./neurosama.png" alt="Neuro-Sama Static Avatar" />
84
+ <img id="neuro-static-avatar" src="/neurosama.png" alt="Neuro-Sama Static Avatar" />
85
85
  </div>
86
86
  <div id="neuro-caption"></div>
87
87
  <div id="startup-video-overlay">
88
- <video id="startup-video" src="./neuro_start.mp4" playsinline muted preload="auto"></video>
88
+ <video id="startup-video" src="/neuro_start.mp4" playsinline muted preload="auto"></video>
89
89
  </div>
90
90
  <!-- Twitch 风格聊天覆盖层 -->
91
91
  <div id="twitch-chat-overlay" class="messages-display">
@@ -124,7 +124,7 @@
124
124
  <div class="stream-info-left-column">
125
125
  <a href="https://twitch.tv/vedal987" class="streamer-avatar-link">
126
126
  <div class="streamer-avatar-wrapper">
127
- <img id="streamer-avatar" src="./avatar.webp" alt="Streamer Avatar" />
127
+ <img id="streamer-avatar" src="/avatar.webp" alt="Streamer Avatar" />
128
128
  <div class="live-indicator-wrapper">
129
129
  <div class="live-indicator-rect">
130
130
  <span class="live-text" id="live-indicator-text">LIVE</span>
@@ -226,7 +226,7 @@
226
226
  <div class="chat-input-textarea-container">
227
227
  <div class="chat-input-prefix-icons">
228
228
  <button class="chat-toolbar-button" aria-label="聊天室身份">
229
- <img alt="订阅者徽章" class="chat-badge-icon" src="./sub_badge.svg">
229
+ <img alt="订阅者徽章" class="chat-badge-icon" src="/sub_badge.svg">
230
230
  </button>
231
231
  </div>
232
232
  <div class="chat-input-wrapper">
@@ -248,7 +248,7 @@
248
248
  <span class="points-value">0</span>
249
249
  </button>
250
250
  <button id="sc-points-button" class="chat-toolbar-text-button" aria-label="频道点数">
251
- <img class="channel-points-icon" src="./channel_points.png" alt="频道点数">
251
+ <img class="channel-points-icon" src="/channel_points.png" alt="频道点数">
252
252
  <span class="points-value">0</span>
253
253
  </button>
254
254
  </div>
@@ -282,7 +282,7 @@
282
282
  <div class="setting-item avatar-setting">
283
283
  <label>头像</label>
284
284
  <div class="avatar-preview-container">
285
- <img id="avatar-setting-preview" src="./user_avatar.jpg" alt="Avatar Preview" class="avatar-preview">
285
+ <img id="avatar-setting-preview" src="/user_avatar.jpg" alt="Avatar Preview" class="avatar-preview">
286
286
  <input type="file" id="avatar-setting-upload" accept="image/*" class="avatar-upload-input">
287
287
  <button id="avatar-upload-button" class="twitch-button">上传图片</button>
288
288
  </div>
@@ -68,6 +68,14 @@ app.add_middleware(
68
68
 
69
69
  app.include_router(system_router)
70
70
 
71
+
72
+ # --- Redirect for trailing slash on dashboard ---
73
+ from fastapi.responses import RedirectResponse
74
+ @app.get("/dashboard", include_in_schema=False)
75
+ async def redirect_dashboard_to_trailing_slash():
76
+ return RedirectResponse(url="/dashboard/")
77
+
78
+
71
79
  # --- Background Task Definitions ---
72
80
 
73
81
  chatbot: ChatbotAgent = None
@@ -258,8 +266,16 @@ async def startup_event():
258
266
  else:
259
267
  frontend_dir = None
260
268
 
269
+ # --- Mount Dashboard Frontend ---
270
+ # Mount the dashboard frontend at /dashboard path (more specific) - MOUNT THIS FIRST
271
+ if frontend_dir:
272
+ app.mount("/dashboard", SPAStaticFiles(directory=frontend_dir, html=True), name="dashboard")
273
+ logger.info("Dashboard frontend mounted at /dashboard")
274
+ else:
275
+ logger.error("Frontend directory not found in either production or development locations.")
276
+
261
277
  # --- Mount Client Frontend ---
262
- # Mount the client frontend at /client path (more specific) - MOUNT THIS FIRST
278
+ # Mount the client frontend at / path (more general) - MOUNT THIS AFTER
263
279
  try:
264
280
  # Production/Standard install: find client frontend in the package
265
281
  client_frontend_dir_traversable = files('neuro_simulator').joinpath('client')
@@ -277,19 +293,11 @@ async def startup_event():
277
293
  client_frontend_dir = None
278
294
 
279
295
  if client_frontend_dir:
280
- app.mount("/client", SPAStaticFiles(directory=client_frontend_dir, html=True), name="client")
281
- logger.info("Client frontend mounted at /client")
296
+ app.mount("/", SPAStaticFiles(directory=client_frontend_dir, html=True), name="client")
297
+ logger.info("Client frontend mounted at /")
282
298
  else:
283
299
  logger.error("Client frontend directory not found in either production or development locations.")
284
300
 
285
- # --- Mount Dashboard Frontend ---
286
- # Mount the dashboard frontend at / path (more general) - MOUNT THIS AFTER
287
- if frontend_dir:
288
- app.mount("/", SPAStaticFiles(directory=frontend_dir, html=True), name="dashboard")
289
- logger.info("Dashboard frontend mounted at /")
290
- else:
291
- logger.error("Frontend directory not found in either production or development locations.")
292
-
293
301
  # 1. Configure logging first
294
302
  configure_server_logging()
295
303
 
@@ -1,2 +1,2 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ContextTab-BSROkcd2.js","assets/index-Ba5ZG3QB.js","assets/index-CcYt9OR6.css","assets/ContextTab-DyPsixHQ.css","assets/MemoryTab-p3Q-Wa4e.js","assets/MemoryTab-DPthi6jg.css","assets/ToolsTab-BxbFZhXs.js","assets/LogsTab-C-SZhHdN.js","assets/LogsTab-wg3i3S6b.css"])))=>i.map(i=>d[i]);
2
- import{d as C,j as k,k as I,l as L,n as c,z as P,e as t,g as v,w as o,b as n,f as a,h as d,q as r,s as u,o as f,_ as D}from"./index-Ba5ZG3QB.js";const N={class:"agent-view-wrapper"},O={key:0,class:"overlay"},R={class:"overlay-content"},B=C({__name:"AgentView",setup(z){const g=r(()=>u(()=>import("./ContextTab-BSROkcd2.js"),__vite__mapDeps([0,1,2,3]))),b=r(()=>u(()=>import("./MemoryTab-p3Q-Wa4e.js"),__vite__mapDeps([4,1,2,5]))),V=r(()=>u(()=>import("./ToolsTab-BxbFZhXs.js"),__vite__mapDeps([6,1,2]))),w=r(()=>u(()=>import("./LogsTab-C-SZhHdN.js"),__vite__mapDeps([7,1,2,8]))),m=k(),s=I("context"),p=L(()=>m.config?.agent_type&&m.config.agent_type!=="builtin");return(S,e)=>{const x=n("v-icon"),l=n("v-tab"),y=n("v-tabs"),_=n("v-window-item"),E=n("v-window"),T=n("v-card-text"),A=n("v-card");return f(),c("div",N,[p.value?(f(),c("div",O,[v("div",R,[t(x,{size:"x-large",class:"mb-4"},{default:o(()=>[...e[2]||(e[2]=[a("mdi-link-variant",-1)])]),_:1}),e[3]||(e[3]=v("h2",{class:"text-h5"},"当前正在调用外部 Agent",-1)),e[4]||(e[4]=v("p",{class:"text-body-1"},"请前往相应平台进行控制",-1))])])):P("",!0),t(A,{disabled:p.value},{default:o(()=>[t(y,{modelValue:s.value,"onUpdate:modelValue":e[0]||(e[0]=i=>s.value=i),"bg-color":"primary",grow:""},{default:o(()=>[t(l,{value:"context"},{default:o(()=>[...e[5]||(e[5]=[a("对话",-1)])]),_:1}),t(l,{value:"memory"},{default:o(()=>[...e[6]||(e[6]=[a("记忆",-1)])]),_:1}),t(l,{value:"tools"},{default:o(()=>[...e[7]||(e[7]=[a("工具",-1)])]),_:1}),t(l,{value:"logs"},{default:o(()=>[...e[8]||(e[8]=[a("日志",-1)])]),_:1})]),_:1},8,["modelValue"]),t(T,null,{default:o(()=>[t(E,{modelValue:s.value,"onUpdate:modelValue":e[1]||(e[1]=i=>s.value=i)},{default:o(()=>[t(_,{value:"context"},{default:o(()=>[t(d(g))]),_:1}),t(_,{value:"memory"},{default:o(()=>[t(d(b))]),_:1}),t(_,{value:"tools"},{default:o(()=>[t(d(V))]),_:1}),t(_,{value:"logs"},{default:o(()=>[t(d(w))]),_:1})]),_:1},8,["modelValue"])]),_:1})]),_:1},8,["disabled"])])}}}),j=D(B,[["__scopeId","data-v-871d2dc1"]]);export{j as default};
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ContextTab-Cv2a7xRF.js","assets/index-Sav9Djr5.js","assets/index-D2ait7Ff.css","assets/ContextTab-DyPsixHQ.css","assets/MemoryTab-BMDqRcHX.js","assets/MemoryTab-DPthi6jg.css","assets/ToolsTab-Ds4M2VeQ.js","assets/LogsTab-C7r21Vcz.js","assets/LogsTab-wg3i3S6b.css"])))=>i.map(i=>d[i]);
2
+ import{d as C,j as k,k as I,l as L,n as c,z as P,e as t,g as v,w as o,b as n,f as a,h as d,q as r,s as u,o as f,_ as D}from"./index-Sav9Djr5.js";const N={class:"agent-view-wrapper"},O={key:0,class:"overlay"},R={class:"overlay-content"},B=C({__name:"AgentView",setup(z){const g=r(()=>u(()=>import("./ContextTab-Cv2a7xRF.js"),__vite__mapDeps([0,1,2,3]))),b=r(()=>u(()=>import("./MemoryTab-BMDqRcHX.js"),__vite__mapDeps([4,1,2,5]))),V=r(()=>u(()=>import("./ToolsTab-Ds4M2VeQ.js"),__vite__mapDeps([6,1,2]))),w=r(()=>u(()=>import("./LogsTab-C7r21Vcz.js"),__vite__mapDeps([7,1,2,8]))),m=k(),s=I("context"),p=L(()=>m.config?.agent_type&&m.config.agent_type!=="builtin");return(S,e)=>{const x=n("v-icon"),l=n("v-tab"),y=n("v-tabs"),_=n("v-window-item"),E=n("v-window"),T=n("v-card-text"),A=n("v-card");return f(),c("div",N,[p.value?(f(),c("div",O,[v("div",R,[t(x,{size:"x-large",class:"mb-4"},{default:o(()=>[...e[2]||(e[2]=[a("mdi-link-variant",-1)])]),_:1}),e[3]||(e[3]=v("h2",{class:"text-h5"},"当前正在调用外部 Agent",-1)),e[4]||(e[4]=v("p",{class:"text-body-1"},"请前往相应平台进行控制",-1))])])):P("",!0),t(A,{disabled:p.value},{default:o(()=>[t(y,{modelValue:s.value,"onUpdate:modelValue":e[0]||(e[0]=i=>s.value=i),"bg-color":"primary",grow:""},{default:o(()=>[t(l,{value:"context"},{default:o(()=>[...e[5]||(e[5]=[a("对话",-1)])]),_:1}),t(l,{value:"memory"},{default:o(()=>[...e[6]||(e[6]=[a("记忆",-1)])]),_:1}),t(l,{value:"tools"},{default:o(()=>[...e[7]||(e[7]=[a("工具",-1)])]),_:1}),t(l,{value:"logs"},{default:o(()=>[...e[8]||(e[8]=[a("日志",-1)])]),_:1})]),_:1},8,["modelValue"]),t(T,null,{default:o(()=>[t(E,{modelValue:s.value,"onUpdate:modelValue":e[1]||(e[1]=i=>s.value=i)},{default:o(()=>[t(_,{value:"context"},{default:o(()=>[t(d(g))]),_:1}),t(_,{value:"memory"},{default:o(()=>[t(d(b))]),_:1}),t(_,{value:"tools"},{default:o(()=>[t(d(V))]),_:1}),t(_,{value:"logs"},{default:o(()=>[t(d(w))]),_:1})]),_:1},8,["modelValue"])]),_:1})]),_:1},8,["disabled"])])}}}),j=D(B,[["__scopeId","data-v-871d2dc1"]]);export{j as default};
@@ -1,2 +1,2 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ContextTab-BSROkcd2.js","assets/index-Ba5ZG3QB.js","assets/index-CcYt9OR6.css","assets/ContextTab-DyPsixHQ.css","assets/MemoryTab-p3Q-Wa4e.js","assets/MemoryTab-DPthi6jg.css","assets/ToolsTab-BxbFZhXs.js","assets/LogsTab-C-SZhHdN.js","assets/LogsTab-wg3i3S6b.css"])))=>i.map(i=>d[i]);
2
- import{d as E,k as y,n as C,g as d,e as o,w as e,b as a,f as n,h as u,q as r,s as v,o as g,_ as A}from"./index-Ba5ZG3QB.js";const I={class:"chatbot-view-wrapper"},P={class:"overlay"},B={class:"overlay-content"},L=E({__name:"ChatBotView",setup(D){const i=r(()=>v(()=>import("./ContextTab-BSROkcd2.js"),__vite__mapDeps([0,1,2,3]))),p=r(()=>v(()=>import("./MemoryTab-p3Q-Wa4e.js"),__vite__mapDeps([4,1,2,5]))),f=r(()=>v(()=>import("./ToolsTab-BxbFZhXs.js"),__vite__mapDeps([6,1,2]))),c=r(()=>v(()=>import("./LogsTab-C-SZhHdN.js"),__vite__mapDeps([7,1,2,8]))),s=y("context");return(O,t)=>{const b=a("v-icon"),l=a("v-tab"),w=a("v-tabs"),_=a("v-window-item"),V=a("v-window"),x=a("v-card-text"),T=a("v-card");return g(),C("div",I,[d("div",P,[d("div",B,[o(b,{size:"x-large",class:"mb-4"},{default:e(()=>[...t[2]||(t[2]=[n("mdi-dev-to",-1)])]),_:1}),t[3]||(t[3]=d("h2",{class:"text-h5"},"Chatbot 控制开发中",-1)),t[4]||(t[4]=d("p",{class:"text-body-1"},"后端 API 尚未实现",-1))])]),o(T,null,{default:e(()=>[o(w,{modelValue:s.value,"onUpdate:modelValue":t[0]||(t[0]=m=>s.value=m),"bg-color":"primary",grow:""},{default:e(()=>[o(l,{value:"context"},{default:e(()=>[...t[5]||(t[5]=[n("对话",-1)])]),_:1}),o(l,{value:"memory"},{default:e(()=>[...t[6]||(t[6]=[n("记忆",-1)])]),_:1}),o(l,{value:"tools"},{default:e(()=>[...t[7]||(t[7]=[n("工具",-1)])]),_:1}),o(l,{value:"logs"},{default:e(()=>[...t[8]||(t[8]=[n("日志",-1)])]),_:1})]),_:1},8,["modelValue"]),o(x,null,{default:e(()=>[o(V,{modelValue:s.value,"onUpdate:modelValue":t[1]||(t[1]=m=>s.value=m)},{default:e(()=>[o(_,{value:"context"},{default:e(()=>[o(u(i))]),_:1}),o(_,{value:"memory"},{default:e(()=>[o(u(p))]),_:1}),o(_,{value:"tools"},{default:e(()=>[o(u(f))]),_:1}),o(_,{value:"logs"},{default:e(()=>[o(u(c))]),_:1})]),_:1},8,["modelValue"])]),_:1})]),_:1})])}}}),k=A(L,[["__scopeId","data-v-ed63d404"]]);export{k as default};
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ContextTab-Cv2a7xRF.js","assets/index-Sav9Djr5.js","assets/index-D2ait7Ff.css","assets/ContextTab-DyPsixHQ.css","assets/MemoryTab-BMDqRcHX.js","assets/MemoryTab-DPthi6jg.css","assets/ToolsTab-Ds4M2VeQ.js","assets/LogsTab-C7r21Vcz.js","assets/LogsTab-wg3i3S6b.css"])))=>i.map(i=>d[i]);
2
+ import{d as E,k as y,n as C,g as d,e as o,w as e,b as a,f as n,h as u,q as r,s as v,o as g,_ as A}from"./index-Sav9Djr5.js";const I={class:"chatbot-view-wrapper"},P={class:"overlay"},B={class:"overlay-content"},L=E({__name:"ChatBotView",setup(D){const i=r(()=>v(()=>import("./ContextTab-Cv2a7xRF.js"),__vite__mapDeps([0,1,2,3]))),p=r(()=>v(()=>import("./MemoryTab-BMDqRcHX.js"),__vite__mapDeps([4,1,2,5]))),f=r(()=>v(()=>import("./ToolsTab-Ds4M2VeQ.js"),__vite__mapDeps([6,1,2]))),c=r(()=>v(()=>import("./LogsTab-C7r21Vcz.js"),__vite__mapDeps([7,1,2,8]))),s=y("context");return(O,t)=>{const b=a("v-icon"),l=a("v-tab"),w=a("v-tabs"),_=a("v-window-item"),V=a("v-window"),x=a("v-card-text"),T=a("v-card");return g(),C("div",I,[d("div",P,[d("div",B,[o(b,{size:"x-large",class:"mb-4"},{default:e(()=>[...t[2]||(t[2]=[n("mdi-dev-to",-1)])]),_:1}),t[3]||(t[3]=d("h2",{class:"text-h5"},"Chatbot 控制开发中",-1)),t[4]||(t[4]=d("p",{class:"text-body-1"},"后端 API 尚未实现",-1))])]),o(T,null,{default:e(()=>[o(w,{modelValue:s.value,"onUpdate:modelValue":t[0]||(t[0]=m=>s.value=m),"bg-color":"primary",grow:""},{default:e(()=>[o(l,{value:"context"},{default:e(()=>[...t[5]||(t[5]=[n("对话",-1)])]),_:1}),o(l,{value:"memory"},{default:e(()=>[...t[6]||(t[6]=[n("记忆",-1)])]),_:1}),o(l,{value:"tools"},{default:e(()=>[...t[7]||(t[7]=[n("工具",-1)])]),_:1}),o(l,{value:"logs"},{default:e(()=>[...t[8]||(t[8]=[n("日志",-1)])]),_:1})]),_:1},8,["modelValue"]),o(x,null,{default:e(()=>[o(V,{modelValue:s.value,"onUpdate:modelValue":t[1]||(t[1]=m=>s.value=m)},{default:e(()=>[o(_,{value:"context"},{default:e(()=>[o(u(i))]),_:1}),o(_,{value:"memory"},{default:e(()=>[o(u(p))]),_:1}),o(_,{value:"tools"},{default:e(()=>[o(u(f))]),_:1}),o(_,{value:"logs"},{default:e(()=>[o(u(c))]),_:1})]),_:1},8,["modelValue"])]),_:1})]),_:1})])}}}),k=A(L,[["__scopeId","data-v-ed63d404"]]);export{k as default};
@@ -1,2 +1,2 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/FieldRenderer-DyPAEyOT.js","assets/index-Ba5ZG3QB.js","assets/index-CcYt9OR6.css"])))=>i.map(i=>d[i]);
2
- import{d as U,i as E,j as G,a as $,k as b,l as D,m as I,n as l,e as u,g as O,b as r,t as h,h as p,w as d,F as V,p as x,f as B,o as n,c as j,q as M,s as P}from"./index-Ba5ZG3QB.js";const R={key:0,class:"text-center pa-10"},T={class:"mt-4"},q={key:1},W={class:"text-h4 mb-6"},J=U({__name:"ConfigView",setup(z){const{t:_}=E(),F=M(()=>P(()=>import("./FieldRenderer-DyPAEyOT.js"),__vite__mapDeps([0,1,2]))),f=G(),S=$(),k=b(!0),m=b(null),C=b(!1),A=D(()=>{const s=f.schema;if(!s||!s.properties)return[];const c=["llm_providers","tts_providers","neuro","chatbot","stream","server"],v=Object.keys(s.properties);return v.sort((t,o)=>{const i=c.indexOf(t),a=c.indexOf(o);return i!==-1&&a!==-1?i-a:i!==-1?-1:a!==-1?1:t.localeCompare(o)}),v.map(t=>{const o=s.properties[t];if(o.$ref){const i=o.$ref.split("/").pop()||"",a=s.$defs?.[i]||{},y=a.properties||{};return{key:t,title:o.title||a.title||t.charAt(0).toUpperCase()+t.slice(1),isGroup:!0,properties:Object.keys(y).map(g=>({key:g,schema:y[g]}))}}return{key:t,title:o.title||t.charAt(0).toUpperCase()+t.slice(1),isGroup:!1,properties:[{key:t,schema:o}]}})});async function L(){if(S.isConnected){C.value=!0;try{await S.sendAdminWsMessage("update_configs",f.config),console.log("Config saved successfully!")}catch(s){console.error("Failed to save config:",s)}finally{C.value=!1}}}return I(async()=>{k.value=!0;try{await f.fetchSchema(),await f.fetchConfig()}finally{k.value=!1}}),(s,c)=>{const v=r("v-progress-circular"),t=r("v-tab"),o=r("v-tabs"),i=r("v-btn"),a=r("v-card-actions"),y=r("v-card"),g=r("v-window-item"),N=r("v-window");return n(),l("div",null,[k.value?(n(),l("div",R,[u(v,{indeterminate:"",color:"primary"}),O("p",T,h(p(_)("Loading configuration...")),1)])):(n(),l("div",q,[u(o,{modelValue:m.value,"onUpdate:modelValue":c[0]||(c[0]=e=>m.value=e),"bg-color":"primary",class:"mb-4 config-tabs",grow:""},{default:d(()=>[(n(!0),l(V,null,x(A.value,e=>(n(),j(t,{key:e.key,value:e.key},{default:d(()=>[B(h(p(_)(e.title)),1)]),_:2},1032,["value"]))),128))]),_:1},8,["modelValue"]),u(a,{class:"justify-end pa-4"},{default:d(()=>[u(i,{onClick:L,color:"primary",variant:"flat",loading:C.value},{default:d(()=>[B(h(p(_)("Save Configuration")),1)]),_:1},8,["loading"])]),_:1}),u(N,{modelValue:m.value,"onUpdate:modelValue":c[1]||(c[1]=e=>m.value=e),eager:""},{default:d(()=>[(n(!0),l(V,null,x(A.value,e=>(n(),j(g,{key:e.key,value:e.key},{default:d(()=>[u(y,{flat:"",class:"pa-4"},{default:d(()=>[O("h1",W,h(p(_)(e.title)),1),(n(!0),l(V,null,x(e.properties,w=>(n(),l("div",{key:w.key},[u(p(F),{"group-key":e.isGroup?e.key:null,"prop-key":w.key,"prop-schema":w.schema},null,8,["group-key","prop-key","prop-schema"])]))),128))]),_:2},1024)]),_:2},1032,["value"]))),128))]),_:1},8,["modelValue"])]))])}}});export{J as default};
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/FieldRenderer-xMOXYQeU.js","assets/index-Sav9Djr5.js","assets/index-D2ait7Ff.css"])))=>i.map(i=>d[i]);
2
+ import{d as U,i as E,j as G,a as $,k as b,l as D,m as I,n as l,e as u,g as O,b as r,t as h,h as p,w as d,F as V,p as x,f as B,o as n,c as j,q as M,s as P}from"./index-Sav9Djr5.js";const R={key:0,class:"text-center pa-10"},T={class:"mt-4"},q={key:1},W={class:"text-h4 mb-6"},J=U({__name:"ConfigView",setup(z){const{t:_}=E(),F=M(()=>P(()=>import("./FieldRenderer-xMOXYQeU.js"),__vite__mapDeps([0,1,2]))),f=G(),S=$(),k=b(!0),m=b(null),C=b(!1),A=D(()=>{const s=f.schema;if(!s||!s.properties)return[];const c=["llm_providers","tts_providers","neuro","chatbot","stream","server"],v=Object.keys(s.properties);return v.sort((t,o)=>{const i=c.indexOf(t),a=c.indexOf(o);return i!==-1&&a!==-1?i-a:i!==-1?-1:a!==-1?1:t.localeCompare(o)}),v.map(t=>{const o=s.properties[t];if(o.$ref){const i=o.$ref.split("/").pop()||"",a=s.$defs?.[i]||{},y=a.properties||{};return{key:t,title:o.title||a.title||t.charAt(0).toUpperCase()+t.slice(1),isGroup:!0,properties:Object.keys(y).map(g=>({key:g,schema:y[g]}))}}return{key:t,title:o.title||t.charAt(0).toUpperCase()+t.slice(1),isGroup:!1,properties:[{key:t,schema:o}]}})});async function L(){if(S.isConnected){C.value=!0;try{await S.sendAdminWsMessage("update_configs",f.config),console.log("Config saved successfully!")}catch(s){console.error("Failed to save config:",s)}finally{C.value=!1}}}return I(async()=>{k.value=!0;try{await f.fetchSchema(),await f.fetchConfig()}finally{k.value=!1}}),(s,c)=>{const v=r("v-progress-circular"),t=r("v-tab"),o=r("v-tabs"),i=r("v-btn"),a=r("v-card-actions"),y=r("v-card"),g=r("v-window-item"),N=r("v-window");return n(),l("div",null,[k.value?(n(),l("div",R,[u(v,{indeterminate:"",color:"primary"}),O("p",T,h(p(_)("Loading configuration...")),1)])):(n(),l("div",q,[u(o,{modelValue:m.value,"onUpdate:modelValue":c[0]||(c[0]=e=>m.value=e),"bg-color":"primary",class:"mb-4 config-tabs",grow:""},{default:d(()=>[(n(!0),l(V,null,x(A.value,e=>(n(),j(t,{key:e.key,value:e.key},{default:d(()=>[B(h(p(_)(e.title)),1)]),_:2},1032,["value"]))),128))]),_:1},8,["modelValue"]),u(a,{class:"justify-end pa-4"},{default:d(()=>[u(i,{onClick:L,color:"primary",variant:"flat",loading:C.value},{default:d(()=>[B(h(p(_)("Save Configuration")),1)]),_:1},8,["loading"])]),_:1}),u(N,{modelValue:m.value,"onUpdate:modelValue":c[1]||(c[1]=e=>m.value=e),eager:""},{default:d(()=>[(n(!0),l(V,null,x(A.value,e=>(n(),j(g,{key:e.key,value:e.key},{default:d(()=>[u(y,{flat:"",class:"pa-4"},{default:d(()=>[O("h1",W,h(p(_)(e.title)),1),(n(!0),l(V,null,x(e.properties,w=>(n(),l("div",{key:w.key},[u(p(F),{"group-key":e.isGroup?e.key:null,"prop-key":w.key,"prop-schema":w.schema},null,8,["group-key","prop-key","prop-schema"])]))),128))]),_:2},1024)]),_:2},1032,["value"]))),128))]),_:1},8,["modelValue"])]))])}}});export{J as default};
@@ -1 +1 @@
1
- import{d as m,k as g,A as x,a as v,x as f,b as C,n as o,o as s,g as r,e as h,t as l,h as p,F as y,p as b,f as w,_ as k}from"./index-Ba5ZG3QB.js";const V={class:"d-flex align-center mb-4"},S={key:0,class:"context-prompt-view"},A={key:1,class:"context-conversation-view"},M=m({__name:"ContextTab",setup(B){const t=g(!1),n=x(),c=v();async function i(){if(c.isConnected)if(t.value)try{const e=await c.sendAdminWsMessage("get_last_prompt");n.agentContext=e.prompt}catch(e){console.error("获取最新Prompt失败:",e),n.agentContext=`获取提示词失败: ${e}`}else try{const e=await c.sendAdminWsMessage("get_agent_context");n.agentContext=e}catch(e){console.error("获取上下文失败:",e)}}return f(t,i),i(),(e,d)=>{const u=C("v-switch");return s(),o("div",null,[r("div",V,[h(u,{modelValue:t.value,"onUpdate:modelValue":d[0]||(d[0]=a=>t.value=a),label:"上下文模式",color:"primary","hide-details":""},null,8,["modelValue"])]),t.value?(s(),o("div",S,[r("pre",null,l(p(n).agentContext),1)])):(s(),o("div",A,[(s(!0),o(y,null,b(p(n).agentContext,(a,_)=>(s(),o("div",{key:_,class:"message-item"},[r("p",null,[r("strong",null,l(a.role)+":",1),w(" "+l(a.content),1)])]))),128))]))])}}}),T=k(M,[["__scopeId","data-v-dd6969bb"]]);export{T as default};
1
+ import{d as m,k as g,A as x,a as v,x as f,b as C,n as o,o as s,g as r,e as h,t as l,h as p,F as y,p as b,f as w,_ as k}from"./index-Sav9Djr5.js";const V={class:"d-flex align-center mb-4"},S={key:0,class:"context-prompt-view"},A={key:1,class:"context-conversation-view"},M=m({__name:"ContextTab",setup(B){const t=g(!1),n=x(),c=v();async function i(){if(c.isConnected)if(t.value)try{const e=await c.sendAdminWsMessage("get_last_prompt");n.agentContext=e.prompt}catch(e){console.error("获取最新Prompt失败:",e),n.agentContext=`获取提示词失败: ${e}`}else try{const e=await c.sendAdminWsMessage("get_agent_context");n.agentContext=e}catch(e){console.error("获取上下文失败:",e)}}return f(t,i),i(),(e,d)=>{const u=C("v-switch");return s(),o("div",null,[r("div",V,[h(u,{modelValue:t.value,"onUpdate:modelValue":d[0]||(d[0]=a=>t.value=a),label:"上下文模式",color:"primary","hide-details":""},null,8,["modelValue"])]),t.value?(s(),o("div",S,[r("pre",null,l(p(n).agentContext),1)])):(s(),o("div",A,[(s(!0),o(y,null,b(p(n).agentContext,(a,_)=>(s(),o("div",{key:_,class:"message-item"},[r("p",null,[r("strong",null,l(a.role)+":",1),w(" "+l(a.content),1)])]))),128))]))])}}}),T=k(M,[["__scopeId","data-v-dd6969bb"]]);export{T as default};
@@ -1 +1 @@
1
- import{d as C,u as S,a as w,r as x,c as k,w as o,b as r,e as a,f as n,g as i,h as _,t as V,o as b,_ as A}from"./index-Ba5ZG3QB.js";const B={class:"stream-status"},M={class:"control-buttons"},N=C({__name:"ControlView",setup(W){const d=S(),l=w(),e=x({start:!1,stop:!1,restart:!1});async function u(){e.start=!0;try{await l.sendAdminWsMessage("start_stream")}catch(s){console.error(s)}finally{e.start=!1}}async function f(){e.stop=!0;try{await l.sendAdminWsMessage("stop_stream")}catch(s){console.error(s)}finally{e.stop=!1}}async function p(){e.restart=!0;try{await l.sendAdminWsMessage("restart_stream")}catch(s){console.error(s)}finally{e.restart=!1}}return(s,t)=>{const m=r("v-card-title"),g=r("v-chip"),c=r("v-btn"),v=r("v-card-text"),y=r("v-card");return b(),k(y,null,{default:o(()=>[a(m,null,{default:o(()=>[...t[0]||(t[0]=[n("直播控制",-1)])]),_:1}),a(v,null,{default:o(()=>[i("div",B,[i("p",null,[t[1]||(t[1]=n("当前状态: ",-1)),a(g,{color:_(d).isRunning?"green":"red",dark:""},{default:o(()=>[n(V(_(d).isRunning?"运行中":"已停止"),1)]),_:1},8,["color"])])]),i("div",M,[a(c,{color:"primary",onClick:u,loading:e.start},{default:o(()=>[...t[2]||(t[2]=[n("开始直播",-1)])]),_:1},8,["loading"]),a(c,{color:"error",onClick:f,loading:e.stop},{default:o(()=>[...t[3]||(t[3]=[n("停止直播",-1)])]),_:1},8,["loading"]),a(c,{color:"warning",onClick:p,loading:e.restart},{default:o(()=>[...t[4]||(t[4]=[n("重启直播",-1)])]),_:1},8,["loading"])])]),_:1})]),_:1})}}}),D=A(N,[["__scopeId","data-v-607a7661"]]);export{D as default};
1
+ import{d as C,u as S,a as w,r as x,c as k,w as o,b as r,e as a,f as n,g as i,h as _,t as V,o as b,_ as A}from"./index-Sav9Djr5.js";const B={class:"stream-status"},M={class:"control-buttons"},N=C({__name:"ControlView",setup(W){const d=S(),l=w(),e=x({start:!1,stop:!1,restart:!1});async function u(){e.start=!0;try{await l.sendAdminWsMessage("start_stream")}catch(s){console.error(s)}finally{e.start=!1}}async function f(){e.stop=!0;try{await l.sendAdminWsMessage("stop_stream")}catch(s){console.error(s)}finally{e.stop=!1}}async function p(){e.restart=!0;try{await l.sendAdminWsMessage("restart_stream")}catch(s){console.error(s)}finally{e.restart=!1}}return(s,t)=>{const m=r("v-card-title"),g=r("v-chip"),c=r("v-btn"),v=r("v-card-text"),y=r("v-card");return b(),k(y,null,{default:o(()=>[a(m,null,{default:o(()=>[...t[0]||(t[0]=[n("直播控制",-1)])]),_:1}),a(v,null,{default:o(()=>[i("div",B,[i("p",null,[t[1]||(t[1]=n("当前状态: ",-1)),a(g,{color:_(d).isRunning?"green":"red",dark:""},{default:o(()=>[n(V(_(d).isRunning?"运行中":"已停止"),1)]),_:1},8,["color"])])]),i("div",M,[a(c,{color:"primary",onClick:u,loading:e.start},{default:o(()=>[...t[2]||(t[2]=[n("开始直播",-1)])]),_:1},8,["loading"]),a(c,{color:"error",onClick:f,loading:e.stop},{default:o(()=>[...t[3]||(t[3]=[n("停止直播",-1)])]),_:1},8,["loading"]),a(c,{color:"warning",onClick:p,loading:e.restart},{default:o(()=>[...t[4]||(t[4]=[n("重启直播",-1)])]),_:1},8,["loading"])])]),_:1})]),_:1})}}}),D=A(N,[["__scopeId","data-v-607a7661"]]);export{D as default};
@@ -1 +1 @@
1
- import{d as ee,i as te,j as le,l as U,k as C,r as ne,b as p,n as b,o as d,c as m,z as S,h as r,e as s,F as T,p as J,w as v,g as P,t as f,f as N,q as oe,s as ae}from"./index-Ba5ZG3QB.js";let O;const ie=new Uint8Array(16);function re(){if(!O&&(O=typeof crypto<"u"&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!O))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return O(ie)}const u=[];for(let e=0;e<256;++e)u.push((e+256).toString(16).slice(1));function de(e,t=0){return u[e[t+0]]+u[e[t+1]]+u[e[t+2]]+u[e[t+3]]+"-"+u[e[t+4]]+u[e[t+5]]+"-"+u[e[t+6]]+u[e[t+7]]+"-"+u[e[t+8]]+u[e[t+9]]+"-"+u[e[t+10]]+u[e[t+11]]+u[e[t+12]]+u[e[t+13]]+u[e[t+14]]+u[e[t+15]]}const ue=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),B={randomUUID:ue};function pe(e,t,j){if(B.randomUUID&&!e)return B.randomUUID();e=e||{};const l=e.random||(e.rng||re)();return l[6]=l[6]&15|64,l[8]=l[8]&63|128,de(l)}const se={class:"mb-6"},ce={key:8},me={key:0,class:"text-body-2"},ve={key:1,class:"text-body-2"},ye=ee({__name:"FieldRenderer",props:{groupKey:{},propKey:{},propSchema:{},isInDialog:{type:Boolean},dialogData:{}},setup(e){const{t}=te(),j=oe(()=>ae(()=>Promise.resolve().then(()=>fe),void 0)),l=e,y=le();function h(i){return l.propSchema.type===i?!0:Array.isArray(l.propSchema.anyOf)?l.propSchema.anyOf.some(o=>o.type===i):!1}const $=U(()=>!h("array")||!l.propSchema.items?!1:l.propSchema.items.type==="object"||!!l.propSchema.items.$ref),V=U(()=>{if(!$.value)return{};const i=l.propSchema.items;if(i.$ref){const o=i.$ref.split("/").pop();return y.schema.$defs?.[o]||{}}return i}),w=U(()=>l.propKey.endsWith("_provider_id")),F=U(()=>l.propKey==="llm_provider_id"?y.config.llm_providers||[]:l.propKey==="tts_provider_id"?y.config.tts_providers||[]:[]),a=U({get(){return l.isInDialog?l.dialogData?.[l.propKey]:l.groupKey?y.config[l.groupKey]?.[l.propKey]:y.config[l.propKey]},set(i){if(l.isInDialog){l.dialogData&&(l.dialogData[l.propKey]=i);return}l.groupKey?(y.config[l.groupKey]||(y.config[l.groupKey]={}),y.config[l.groupKey][l.propKey]=i):y.config[l.propKey]=i}}),k=C(!1),I=C(!1),c=ne({}),_=C(-1);function z(){I.value=!1,Object.keys(c).forEach(K=>delete c[K]);const i=V.value.properties||{};for(const K in i)c[K]=i[K].default??null;const o=c.provider_type||V.value.properties?.provider_type?.enum?.[0]||"unknown",g=l.propKey==="llm_providers"?"llm":"tts";c.provider_id=`${g}-${o}-${pe()}`,k.value=!0}function M(i,o){I.value=!0,_.value=o,Object.keys(c).forEach(g=>delete c[g]),Object.assign(c,JSON.parse(JSON.stringify(i))),k.value=!0}function L(){const i=a.value||[];I.value?i[_.value]=JSON.parse(JSON.stringify(c)):i.push(JSON.parse(JSON.stringify(c))),a.value=i,k.value=!1}function q(i){const o=a.value||[];o.splice(i,1),a.value=o}return(i,o)=>{const g=p("v-text-field"),K=p("v-textarea"),H=p("v-switch"),A=p("v-select"),x=p("v-btn"),W=p("v-card-title"),E=p("v-card-text"),R=p("v-card"),G=p("v-spacer"),Q=p("v-card-actions"),X=p("v-dialog"),Y=p("v-combobox");return d(),b("div",se,[e.propKey==="provider_id"?(d(),m(g,{key:0,modelValue:a.value,"onUpdate:modelValue":o[0]||(o[0]=n=>a.value=n),label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",variant:"outlined",density:"compact",disabled:""},null,8,["modelValue","label","hint"])):h("integer")||h("number")?(d(),m(g,{key:1,modelValue:a.value,"onUpdate:modelValue":o[1]||(o[1]=n=>a.value=n),modelModifiers:{number:!0},label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,type:"number","persistent-hint":"",variant:"outlined",density:"compact"},null,8,["modelValue","label","hint"])):h("string")&&e.propSchema.format==="password"?(d(),m(g,{key:2,modelValue:a.value,"onUpdate:modelValue":o[2]||(o[2]=n=>a.value=n),label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,type:"password","persistent-hint":"",variant:"outlined",density:"compact"},null,8,["modelValue","label","hint"])):h("string")&&e.propSchema.format==="text-area"?(d(),m(K,{key:3,modelValue:a.value,"onUpdate:modelValue":o[3]||(o[3]=n=>a.value=n),label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",variant:"outlined"},null,8,["modelValue","label","hint"])):h("string")&&!e.propSchema.enum&&!w.value?(d(),m(g,{key:4,modelValue:a.value,"onUpdate:modelValue":o[4]||(o[4]=n=>a.value=n),label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",variant:"outlined",density:"compact"},null,8,["modelValue","label","hint"])):S("",!0),h("boolean")?(d(),m(H,{key:5,modelValue:a.value,"onUpdate:modelValue":o[5]||(o[5]=n=>a.value=n),label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",color:"primary",inset:""},null,8,["modelValue","label","hint"])):S("",!0),e.propSchema.enum?(d(),m(A,{key:6,modelValue:a.value,"onUpdate:modelValue":o[6]||(o[6]=n=>a.value=n),items:e.propSchema.enum,label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",variant:"outlined",density:"compact"},null,8,["modelValue","items","label","hint"])):S("",!0),w.value?(d(),m(A,{key:7,modelValue:a.value,"onUpdate:modelValue":o[7]||(o[7]=n=>a.value=n),items:F.value,"item-title":"display_name","item-value":"provider_id",label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",variant:"outlined",density:"compact",clearable:""},null,8,["modelValue","items","label","hint"])):$.value?(d(),b("div",ce,[(d(!0),b(T,null,J(a.value,(n,D)=>(d(),m(R,{key:n.provider_id||D,class:"mb-4",variant:"outlined"},{default:v(()=>[s(W,{class:"d-flex justify-space-between align-center text-body-1"},{default:v(()=>[P("span",null,f(n.display_name||r(t)("Item")+" "+(D+1)),1),P("div",null,[s(x,{icon:"mdi-pencil",size:"small",variant:"text",onClick:Z=>M(n,D)},null,8,["onClick"]),s(x,{icon:"mdi-delete",size:"small",variant:"text",onClick:Z=>q(D)},null,8,["onClick"])])]),_:2},1024),n.provider_type||n.model_name?(d(),m(E,{key:0},{default:v(()=>[n.provider_type?(d(),b("p",me,f(r(t)("Provider Type"))+": "+f(n.provider_type),1)):S("",!0),n.model_name?(d(),b("p",ve,f(r(t)("Model Name"))+": "+f(n.model_name),1)):S("",!0)]),_:2},1024)):S("",!0)]),_:2},1024))),128)),s(x,{color:"primary",onClick:z,block:""},{default:v(()=>[N(f(r(t)("Add"))+" "+f(r(t)(V.value.title||"Item")),1)]),_:1}),s(X,{modelValue:k.value,"onUpdate:modelValue":o[9]||(o[9]=n=>k.value=n),"max-width":"800px",persistent:""},{default:v(()=>[s(R,{title:r(t)(I.value?"Edit":"Add")+" "+r(t)(V.value.title||"Item")},{default:v(()=>[s(E,null,{default:v(()=>[(d(!0),b(T,null,J(Object.keys(V.value.properties||{}),n=>(d(),b("div",{key:n},[s(r(j),{"group-key":null,"prop-key":n,"prop-schema":V.value.properties[n],"is-in-dialog":!0,"dialog-data":c},null,8,["prop-key","prop-schema","dialog-data"])]))),128))]),_:1}),s(Q,null,{default:v(()=>[s(G),s(x,{text:"",onClick:o[8]||(o[8]=n=>k.value=!1)},{default:v(()=>[N(f(r(t)("Cancel")),1)]),_:1}),s(x,{color:"primary",onClick:L},{default:v(()=>[N(f(r(t)("Save")),1)]),_:1})]),_:1})]),_:1},8,["title"])]),_:1},8,["modelValue"])])):h("array")?(d(),m(Y,{key:9,modelValue:a.value,"onUpdate:modelValue":o[10]||(o[10]=n=>a.value=n),label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",chips:"",multiple:"","closable-chips":"",variant:"outlined",density:"compact"},null,8,["modelValue","label","hint"])):S("",!0)])}}}),fe=Object.freeze(Object.defineProperty({__proto__:null,default:ye},Symbol.toStringTag,{value:"Module"}));export{ye as default};
1
+ import{d as ee,i as te,j as le,l as U,k as C,r as ne,b as p,n as b,o as d,c as m,z as S,h as r,e as s,F as T,p as J,w as v,g as P,t as f,f as N,q as oe,s as ae}from"./index-Sav9Djr5.js";let O;const ie=new Uint8Array(16);function re(){if(!O&&(O=typeof crypto<"u"&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!O))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return O(ie)}const u=[];for(let e=0;e<256;++e)u.push((e+256).toString(16).slice(1));function de(e,t=0){return u[e[t+0]]+u[e[t+1]]+u[e[t+2]]+u[e[t+3]]+"-"+u[e[t+4]]+u[e[t+5]]+"-"+u[e[t+6]]+u[e[t+7]]+"-"+u[e[t+8]]+u[e[t+9]]+"-"+u[e[t+10]]+u[e[t+11]]+u[e[t+12]]+u[e[t+13]]+u[e[t+14]]+u[e[t+15]]}const ue=typeof crypto<"u"&&crypto.randomUUID&&crypto.randomUUID.bind(crypto),B={randomUUID:ue};function pe(e,t,j){if(B.randomUUID&&!e)return B.randomUUID();e=e||{};const l=e.random||(e.rng||re)();return l[6]=l[6]&15|64,l[8]=l[8]&63|128,de(l)}const se={class:"mb-6"},ce={key:8},me={key:0,class:"text-body-2"},ve={key:1,class:"text-body-2"},ye=ee({__name:"FieldRenderer",props:{groupKey:{},propKey:{},propSchema:{},isInDialog:{type:Boolean},dialogData:{}},setup(e){const{t}=te(),j=oe(()=>ae(()=>Promise.resolve().then(()=>fe),void 0)),l=e,y=le();function h(i){return l.propSchema.type===i?!0:Array.isArray(l.propSchema.anyOf)?l.propSchema.anyOf.some(o=>o.type===i):!1}const $=U(()=>!h("array")||!l.propSchema.items?!1:l.propSchema.items.type==="object"||!!l.propSchema.items.$ref),V=U(()=>{if(!$.value)return{};const i=l.propSchema.items;if(i.$ref){const o=i.$ref.split("/").pop();return y.schema.$defs?.[o]||{}}return i}),w=U(()=>l.propKey.endsWith("_provider_id")),F=U(()=>l.propKey==="llm_provider_id"?y.config.llm_providers||[]:l.propKey==="tts_provider_id"?y.config.tts_providers||[]:[]),a=U({get(){return l.isInDialog?l.dialogData?.[l.propKey]:l.groupKey?y.config[l.groupKey]?.[l.propKey]:y.config[l.propKey]},set(i){if(l.isInDialog){l.dialogData&&(l.dialogData[l.propKey]=i);return}l.groupKey?(y.config[l.groupKey]||(y.config[l.groupKey]={}),y.config[l.groupKey][l.propKey]=i):y.config[l.propKey]=i}}),k=C(!1),I=C(!1),c=ne({}),_=C(-1);function z(){I.value=!1,Object.keys(c).forEach(K=>delete c[K]);const i=V.value.properties||{};for(const K in i)c[K]=i[K].default??null;const o=c.provider_type||V.value.properties?.provider_type?.enum?.[0]||"unknown",g=l.propKey==="llm_providers"?"llm":"tts";c.provider_id=`${g}-${o}-${pe()}`,k.value=!0}function M(i,o){I.value=!0,_.value=o,Object.keys(c).forEach(g=>delete c[g]),Object.assign(c,JSON.parse(JSON.stringify(i))),k.value=!0}function L(){const i=a.value||[];I.value?i[_.value]=JSON.parse(JSON.stringify(c)):i.push(JSON.parse(JSON.stringify(c))),a.value=i,k.value=!1}function q(i){const o=a.value||[];o.splice(i,1),a.value=o}return(i,o)=>{const g=p("v-text-field"),K=p("v-textarea"),H=p("v-switch"),A=p("v-select"),x=p("v-btn"),W=p("v-card-title"),E=p("v-card-text"),R=p("v-card"),G=p("v-spacer"),Q=p("v-card-actions"),X=p("v-dialog"),Y=p("v-combobox");return d(),b("div",se,[e.propKey==="provider_id"?(d(),m(g,{key:0,modelValue:a.value,"onUpdate:modelValue":o[0]||(o[0]=n=>a.value=n),label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",variant:"outlined",density:"compact",disabled:""},null,8,["modelValue","label","hint"])):h("integer")||h("number")?(d(),m(g,{key:1,modelValue:a.value,"onUpdate:modelValue":o[1]||(o[1]=n=>a.value=n),modelModifiers:{number:!0},label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,type:"number","persistent-hint":"",variant:"outlined",density:"compact"},null,8,["modelValue","label","hint"])):h("string")&&e.propSchema.format==="password"?(d(),m(g,{key:2,modelValue:a.value,"onUpdate:modelValue":o[2]||(o[2]=n=>a.value=n),label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,type:"password","persistent-hint":"",variant:"outlined",density:"compact"},null,8,["modelValue","label","hint"])):h("string")&&e.propSchema.format==="text-area"?(d(),m(K,{key:3,modelValue:a.value,"onUpdate:modelValue":o[3]||(o[3]=n=>a.value=n),label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",variant:"outlined"},null,8,["modelValue","label","hint"])):h("string")&&!e.propSchema.enum&&!w.value?(d(),m(g,{key:4,modelValue:a.value,"onUpdate:modelValue":o[4]||(o[4]=n=>a.value=n),label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",variant:"outlined",density:"compact"},null,8,["modelValue","label","hint"])):S("",!0),h("boolean")?(d(),m(H,{key:5,modelValue:a.value,"onUpdate:modelValue":o[5]||(o[5]=n=>a.value=n),label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",color:"primary",inset:""},null,8,["modelValue","label","hint"])):S("",!0),e.propSchema.enum?(d(),m(A,{key:6,modelValue:a.value,"onUpdate:modelValue":o[6]||(o[6]=n=>a.value=n),items:e.propSchema.enum,label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",variant:"outlined",density:"compact"},null,8,["modelValue","items","label","hint"])):S("",!0),w.value?(d(),m(A,{key:7,modelValue:a.value,"onUpdate:modelValue":o[7]||(o[7]=n=>a.value=n),items:F.value,"item-title":"display_name","item-value":"provider_id",label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",variant:"outlined",density:"compact",clearable:""},null,8,["modelValue","items","label","hint"])):$.value?(d(),b("div",ce,[(d(!0),b(T,null,J(a.value,(n,D)=>(d(),m(R,{key:n.provider_id||D,class:"mb-4",variant:"outlined"},{default:v(()=>[s(W,{class:"d-flex justify-space-between align-center text-body-1"},{default:v(()=>[P("span",null,f(n.display_name||r(t)("Item")+" "+(D+1)),1),P("div",null,[s(x,{icon:"mdi-pencil",size:"small",variant:"text",onClick:Z=>M(n,D)},null,8,["onClick"]),s(x,{icon:"mdi-delete",size:"small",variant:"text",onClick:Z=>q(D)},null,8,["onClick"])])]),_:2},1024),n.provider_type||n.model_name?(d(),m(E,{key:0},{default:v(()=>[n.provider_type?(d(),b("p",me,f(r(t)("Provider Type"))+": "+f(n.provider_type),1)):S("",!0),n.model_name?(d(),b("p",ve,f(r(t)("Model Name"))+": "+f(n.model_name),1)):S("",!0)]),_:2},1024)):S("",!0)]),_:2},1024))),128)),s(x,{color:"primary",onClick:z,block:""},{default:v(()=>[N(f(r(t)("Add"))+" "+f(r(t)(V.value.title||"Item")),1)]),_:1}),s(X,{modelValue:k.value,"onUpdate:modelValue":o[9]||(o[9]=n=>k.value=n),"max-width":"800px",persistent:""},{default:v(()=>[s(R,{title:r(t)(I.value?"Edit":"Add")+" "+r(t)(V.value.title||"Item")},{default:v(()=>[s(E,null,{default:v(()=>[(d(!0),b(T,null,J(Object.keys(V.value.properties||{}),n=>(d(),b("div",{key:n},[s(r(j),{"group-key":null,"prop-key":n,"prop-schema":V.value.properties[n],"is-in-dialog":!0,"dialog-data":c},null,8,["prop-key","prop-schema","dialog-data"])]))),128))]),_:1}),s(Q,null,{default:v(()=>[s(G),s(x,{text:"",onClick:o[8]||(o[8]=n=>k.value=!1)},{default:v(()=>[N(f(r(t)("Cancel")),1)]),_:1}),s(x,{color:"primary",onClick:L},{default:v(()=>[N(f(r(t)("Save")),1)]),_:1})]),_:1})]),_:1},8,["title"])]),_:1},8,["modelValue"])])):h("array")?(d(),m(Y,{key:9,modelValue:a.value,"onUpdate:modelValue":o[10]||(o[10]=n=>a.value=n),label:r(t)(e.propSchema.title||e.propKey),hint:e.propSchema.description,"persistent-hint":"",chips:"",multiple:"","closable-chips":"",variant:"outlined",density:"compact"},null,8,["modelValue","label","hint"])):S("",!0)])}}}),fe=Object.freeze(Object.defineProperty({__proto__:null,default:ye},Symbol.toStringTag,{value:"Module"}));export{ye as default};
@@ -1 +1 @@
1
- import{d as r,v as l,k as c,x as g,n as s,o as t,F as u,p as i,t as p,h as _,y as f,_ as d}from"./index-Ba5ZG3QB.js";const m=r({__name:"LogsTab",setup(v){const a=l(),e=c(null);return g(()=>a.agentLogs.length,async()=>{await f(),e.value&&(e.value.scrollTop=e.value.scrollHeight)},{deep:!0}),(k,y)=>(t(),s("div",{ref_key:"logsContainer",ref:e,class:"logs-output"},[(t(!0),s(u,null,i(_(a).agentLogs,(o,n)=>(t(),s("div",{key:`agent-${n}`,class:"log-entry"},p(o),1))),128))],512))}}),h=d(m,[["__scopeId","data-v-20098789"]]);export{h as default};
1
+ import{d as r,v as l,k as c,x as g,n as s,o as t,F as u,p as i,t as p,h as _,y as f,_ as d}from"./index-Sav9Djr5.js";const m=r({__name:"LogsTab",setup(v){const a=l(),e=c(null);return g(()=>a.agentLogs.length,async()=>{await f(),e.value&&(e.value.scrollTop=e.value.scrollHeight)},{deep:!0}),(k,y)=>(t(),s("div",{ref_key:"logsContainer",ref:e,class:"logs-output"},[(t(!0),s(u,null,i(_(a).agentLogs,(o,n)=>(t(),s("div",{key:`agent-${n}`,class:"log-entry"},p(o),1))),128))],512))}}),h=d(m,[["__scopeId","data-v-20098789"]]);export{h as default};
@@ -1 +1 @@
1
- import{d as p,v,k as f,x as g,c as m,w as t,b as s,e as n,f as x,g as k,n as l,p as w,h as y,F as L,o as a,t as C,y as V,_ as h}from"./index-Ba5ZG3QB.js";const B=p({__name:"LogsView",setup(S){const o=v(),e=f(null);return g(()=>o.serverLogs.length,async()=>{await V(),e.value&&(e.value.scrollTop=e.value.scrollHeight)},{deep:!0}),(N,r)=>{const c=s("v-card-title"),_=s("v-card-text"),d=s("v-card");return a(),m(d,null,{default:t(()=>[n(c,null,{default:t(()=>[...r[0]||(r[0]=[x("Server 日志",-1)])]),_:1}),n(_,null,{default:t(()=>[k("div",{ref_key:"logsContainer",ref:e,class:"logs-output"},[(a(!0),l(L,null,w(y(o).serverLogs,(u,i)=>(a(),l("div",{key:`server-${i}`,class:"log-entry"},C(u),1))),128))],512)]),_:1})]),_:1})}}}),F=h(B,[["__scopeId","data-v-f9df559f"]]);export{F as default};
1
+ import{d as p,v,k as f,x as g,c as m,w as t,b as s,e as n,f as x,g as k,n as l,p as w,h as y,F as L,o as a,t as C,y as V,_ as h}from"./index-Sav9Djr5.js";const B=p({__name:"LogsView",setup(S){const o=v(),e=f(null);return g(()=>o.serverLogs.length,async()=>{await V(),e.value&&(e.value.scrollTop=e.value.scrollHeight)},{deep:!0}),(N,r)=>{const c=s("v-card-title"),_=s("v-card-text"),d=s("v-card");return a(),m(d,null,{default:t(()=>[n(c,null,{default:t(()=>[...r[0]||(r[0]=[x("Server 日志",-1)])]),_:1}),n(_,null,{default:t(()=>[k("div",{ref_key:"logsContainer",ref:e,class:"logs-output"},[(a(!0),l(L,null,w(y(o).serverLogs,(u,i)=>(a(),l("div",{key:`server-${i}`,class:"log-entry"},C(u),1))),128))],512)]),_:1})]),_:1})}}}),F=h(B,[["__scopeId","data-v-f9df559f"]]);export{F as default};
@@ -1,4 +1,4 @@
1
- import{d as le,A as ne,a as oe,B as re,k as x,m as ae,b as i,n as f,o as s,e as t,w as l,g as v,c as V,f as d,h as k,F as U,p as F,t as C,_ as ie}from"./index-Ba5ZG3QB.js";const se={class:"d-flex mb-4"},de={key:1},ue={class:"d-flex mb-4"},me={key:1},ce={class:"d-flex mb-4"},fe={key:0},ve={key:1},pe={class:"text-h5"},_e={class:"text-h5"},ye=le({__name:"MemoryTab",setup(xe){const p=ne(),a=oe();re();const M=x(!1),y=x({role:"user",content:""}),g=x(!1),m=x({}),b=x(!1),c=x({});function O(n=null){n?m.value={...n,contentStr:n.content.join(`
1
+ import{d as le,A as ne,a as oe,B as re,k as x,m as ae,b as i,n as f,o as s,e as t,w as l,g as v,c as V,f as d,h as k,F as U,p as F,t as C,_ as ie}from"./index-Sav9Djr5.js";const se={class:"d-flex mb-4"},de={key:1},ue={class:"d-flex mb-4"},me={key:1},ce={class:"d-flex mb-4"},fe={key:0},ve={key:1},pe={class:"text-h5"},_e={class:"text-h5"},ye=le({__name:"MemoryTab",setup(xe){const p=ne(),a=oe();re();const M=x(!1),y=x({role:"user",content:""}),g=x(!1),m=x({}),b=x(!1),c=x({});function O(n=null){n?m.value={...n,contentStr:n.content.join(`
2
2
  `)}:m.value={title:"",description:"",contentStr:""},g.value=!0}async function G(){if(!a.isConnected)return;const n=m.value,e={title:n.title,description:n.description,content:n.contentStr.split(`
3
3
  `).filter(r=>r.trim()!=="")};try{n.id?await a.sendAdminWsMessage("update_core_memory_block",{block_id:n.id,...e}):await a.sendAdminWsMessage("create_core_memory_block",e),g.value=!1}catch(r){console.error("Failed to save core memory block:",r)}}function z(n=null,e=null){if(n!==null){let r=e;Array.isArray(e)?r=e.join(`
4
4
  `):typeof e=="object"&&(r=JSON.stringify(e,null,2)),c.value={key:n,valueStr:r,isEditing:!0}}else c.value={key:"",valueStr:"",isEditing:!1};b.value=!0}async function H(){if(!a.isConnected||!c.value.key.trim())return;const{key:n,valueStr:e}=c.value;let r=e;try{const u=e.trim();u.startsWith("{")&&u.endsWith("}")||u.startsWith("[")&&u.endsWith("]")?r=JSON.parse(u):u.includes(`
@@ -1 +1 @@
1
- import{d as F,C as D,a as R,k as W,x as E,m as G,b as s,c as b,o as u,w as e,e as t,g as n,f as d,n as m,F as A,p as k,h,t as f}from"./index-Ba5ZG3QB.js";const J={class:"d-flex mb-4"},O={class:"text-center"},I={class:"text-center"},j=F({__name:"ToolsTab",setup(L){const c=D(),r=R(),i=W({neuro_agent:[],memory_agent:[]});E(()=>c.allocations,l=>{i.value=JSON.parse(JSON.stringify(l||{neuro_agent:[],memory_agent:[]}))},{deep:!0,immediate:!0});async function S(){if(r.isConnected)try{await r.sendAdminWsMessage("set_agent_tool_allocations",{allocations:i.value}),console.log("Tool allocations saved successfully!")}catch(l){console.error("Failed to save allocations:",l)}}async function T(){if(r.isConnected)try{await r.sendAdminWsMessage("reload_tools")}catch(l){console.error("Failed to reload tools:",l)}}async function B(){if(r.isConnected)try{const[l,o]=await Promise.all([r.sendAdminWsMessage("get_all_tools"),r.sendAdminWsMessage("get_agent_tool_allocations")]);console.log("DEBUG: toolsResponse:",l),console.log("DEBUG: allocationsResponse:",o),c.handleAvailableToolsUpdate(l.tools),c.handleAllocationsUpdate(o.allocations)}catch(l){console.error("Failed to fetch tools initial data:",l)}}return G(()=>{B()}),(l,o)=>{const C=s("v-btn"),_=s("v-col"),p=s("v-row"),v=s("v-card-title"),V=s("v-checkbox-btn"),N=s("v-table"),g=s("v-card-text"),y=s("v-card"),w=s("v-chip"),M=s("v-chip-group"),U=s("v-container");return u(),b(U,{fluid:""},{default:e(()=>[t(p,null,{default:e(()=>[t(_,{cols:"12"},{default:e(()=>[n("div",J,[t(C,{onClick:T,class:"mr-2"},{default:e(()=>[...o[2]||(o[2]=[d("重载工具",-1)])]),_:1}),t(C,{onClick:S,color:"primary"},{default:e(()=>[...o[3]||(o[3]=[d("保存分配",-1)])]),_:1})]),o[4]||(o[4]=n("p",{class:"text-caption"},"在这里为 Agent 分配可用的工具标签。Neuro Agent 负责与观众互动,Memory Agent 负责在后台整理记忆。",-1))]),_:1})]),_:1}),t(p,null,{default:e(()=>[t(_,{cols:"12"},{default:e(()=>[t(y,{variant:"outlined"},{default:e(()=>[t(v,null,{default:e(()=>[...o[5]||(o[5]=[d("所有可用工具",-1)])]),_:1}),t(g,null,{default:e(()=>[t(N,{density:"compact"},{default:e(()=>[o[6]||(o[6]=n("thead",null,[n("tr",null,[n("th",{class:"text-left"},"工具名称"),n("th",{class:"text-left"},"描述"),n("th",{class:"text-center"},"Neuro Agent"),n("th",{class:"text-center"},"Memory Agent")])],-1)),n("tbody",null,[(u(!0),m(A,null,k(h(c).availableTools,a=>(u(),m("tr",{key:a.name},[n("td",null,f(a.name),1),n("td",null,f(a.description),1),n("td",O,[t(V,{modelValue:i.value.neuro_agent,"onUpdate:modelValue":o[0]||(o[0]=x=>i.value.neuro_agent=x),value:a.name,"hide-details":""},null,8,["modelValue","value"])]),n("td",I,[t(V,{modelValue:i.value.memory_agent,"onUpdate:modelValue":o[1]||(o[1]=x=>i.value.memory_agent=x),value:a.name,"hide-details":""},null,8,["modelValue","value"])])]))),128))])]),_:1})]),_:1})]),_:1})]),_:1})]),_:1}),t(p,null,{default:e(()=>[t(_,{md:"6",cols:"12"},{default:e(()=>[t(y,{variant:"outlined"},{default:e(()=>[t(v,null,{default:e(()=>[...o[7]||(o[7]=[d("Neuro Agent 工具集",-1)])]),_:1}),t(g,null,{default:e(()=>[t(M,{column:""},{default:e(()=>[(u(!0),m(A,null,k(h(c).allocations.neuro_agent,a=>(u(),b(w,{key:a},{default:e(()=>[d(f(a),1)]),_:2},1024))),128))]),_:1})]),_:1})]),_:1})]),_:1}),t(_,{md:"6",cols:"12"},{default:e(()=>[t(y,{variant:"outlined"},{default:e(()=>[t(v,null,{default:e(()=>[...o[8]||(o[8]=[d("Memory Agent 工具集",-1)])]),_:1}),t(g,null,{default:e(()=>[t(M,{column:""},{default:e(()=>[(u(!0),m(A,null,k(h(c).allocations.memory_agent,a=>(u(),b(w,{key:a},{default:e(()=>[d(f(a),1)]),_:2},1024))),128))]),_:1})]),_:1})]),_:1})]),_:1})]),_:1})]),_:1})}}});export{j as default};
1
+ import{d as F,C as D,a as R,k as W,x as E,m as G,b as s,c as b,o as u,w as e,e as t,g as n,f as d,n as m,F as A,p as k,h,t as f}from"./index-Sav9Djr5.js";const J={class:"d-flex mb-4"},O={class:"text-center"},I={class:"text-center"},j=F({__name:"ToolsTab",setup(L){const c=D(),r=R(),i=W({neuro_agent:[],memory_agent:[]});E(()=>c.allocations,l=>{i.value=JSON.parse(JSON.stringify(l||{neuro_agent:[],memory_agent:[]}))},{deep:!0,immediate:!0});async function S(){if(r.isConnected)try{await r.sendAdminWsMessage("set_agent_tool_allocations",{allocations:i.value}),console.log("Tool allocations saved successfully!")}catch(l){console.error("Failed to save allocations:",l)}}async function T(){if(r.isConnected)try{await r.sendAdminWsMessage("reload_tools")}catch(l){console.error("Failed to reload tools:",l)}}async function B(){if(r.isConnected)try{const[l,o]=await Promise.all([r.sendAdminWsMessage("get_all_tools"),r.sendAdminWsMessage("get_agent_tool_allocations")]);console.log("DEBUG: toolsResponse:",l),console.log("DEBUG: allocationsResponse:",o),c.handleAvailableToolsUpdate(l.tools),c.handleAllocationsUpdate(o.allocations)}catch(l){console.error("Failed to fetch tools initial data:",l)}}return G(()=>{B()}),(l,o)=>{const C=s("v-btn"),_=s("v-col"),p=s("v-row"),v=s("v-card-title"),V=s("v-checkbox-btn"),N=s("v-table"),g=s("v-card-text"),y=s("v-card"),w=s("v-chip"),M=s("v-chip-group"),U=s("v-container");return u(),b(U,{fluid:""},{default:e(()=>[t(p,null,{default:e(()=>[t(_,{cols:"12"},{default:e(()=>[n("div",J,[t(C,{onClick:T,class:"mr-2"},{default:e(()=>[...o[2]||(o[2]=[d("重载工具",-1)])]),_:1}),t(C,{onClick:S,color:"primary"},{default:e(()=>[...o[3]||(o[3]=[d("保存分配",-1)])]),_:1})]),o[4]||(o[4]=n("p",{class:"text-caption"},"在这里为 Agent 分配可用的工具标签。Neuro Agent 负责与观众互动,Memory Agent 负责在后台整理记忆。",-1))]),_:1})]),_:1}),t(p,null,{default:e(()=>[t(_,{cols:"12"},{default:e(()=>[t(y,{variant:"outlined"},{default:e(()=>[t(v,null,{default:e(()=>[...o[5]||(o[5]=[d("所有可用工具",-1)])]),_:1}),t(g,null,{default:e(()=>[t(N,{density:"compact"},{default:e(()=>[o[6]||(o[6]=n("thead",null,[n("tr",null,[n("th",{class:"text-left"},"工具名称"),n("th",{class:"text-left"},"描述"),n("th",{class:"text-center"},"Neuro Agent"),n("th",{class:"text-center"},"Memory Agent")])],-1)),n("tbody",null,[(u(!0),m(A,null,k(h(c).availableTools,a=>(u(),m("tr",{key:a.name},[n("td",null,f(a.name),1),n("td",null,f(a.description),1),n("td",O,[t(V,{modelValue:i.value.neuro_agent,"onUpdate:modelValue":o[0]||(o[0]=x=>i.value.neuro_agent=x),value:a.name,"hide-details":""},null,8,["modelValue","value"])]),n("td",I,[t(V,{modelValue:i.value.memory_agent,"onUpdate:modelValue":o[1]||(o[1]=x=>i.value.memory_agent=x),value:a.name,"hide-details":""},null,8,["modelValue","value"])])]))),128))])]),_:1})]),_:1})]),_:1})]),_:1})]),_:1}),t(p,null,{default:e(()=>[t(_,{md:"6",cols:"12"},{default:e(()=>[t(y,{variant:"outlined"},{default:e(()=>[t(v,null,{default:e(()=>[...o[7]||(o[7]=[d("Neuro Agent 工具集",-1)])]),_:1}),t(g,null,{default:e(()=>[t(M,{column:""},{default:e(()=>[(u(!0),m(A,null,k(h(c).allocations.neuro_agent,a=>(u(),b(w,{key:a},{default:e(()=>[d(f(a),1)]),_:2},1024))),128))]),_:1})]),_:1})]),_:1})]),_:1}),t(_,{md:"6",cols:"12"},{default:e(()=>[t(y,{variant:"outlined"},{default:e(()=>[t(v,null,{default:e(()=>[...o[8]||(o[8]=[d("Memory Agent 工具集",-1)])]),_:1}),t(g,null,{default:e(()=>[t(M,{column:""},{default:e(()=>[(u(!0),m(A,null,k(h(c).allocations.memory_agent,a=>(u(),b(w,{key:a},{default:e(()=>[d(f(a),1)]),_:2},1024))),128))]),_:1})]),_:1})]),_:1})]),_:1})]),_:1})]),_:1})}}});export{j as default};