ai-agent-plugin 0.0.1
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.
- package/LICENSE +21 -0
- package/README.md +214 -0
- package/dist/ai-agent.esm.js +1 -0
- package/dist/ai-agent.js +1 -0
- package/dist/ai-agent.min.js +1 -0
- package/dist/types/ai-agent.d.ts +112 -0
- package/dist/types/types/index.d.ts +161 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 hujinbin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# AI Agent Plugin
|
|
2
|
+
|
|
3
|
+
一个能在 Vue、React、jQuery 等多框架项目中通用的 AI Agent 前端插件,采用原生 JavaScript + TypeScript + UMD 模块化规范,确保跨框架兼容性。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🔥 新增预览功能
|
|
8
|
+
|
|
9
|
+
本项目已集成 TypeScript 示例和多框架预览页面,支持本地快速预览和调试。
|
|
10
|
+
|
|
11
|
+
- 启动预览命令:
|
|
12
|
+
```bash
|
|
13
|
+
npm run serve
|
|
14
|
+
```
|
|
15
|
+
- 默认端口:**9000**
|
|
16
|
+
- 预览入口:
|
|
17
|
+
- http://localhost:9000/
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 特性
|
|
21
|
+
|
|
22
|
+
- ✅ 跨框架兼容:支持 Vue、React、jQuery 等任意前端项目
|
|
23
|
+
- ✅ 样式隔离:避免与宿主项目样式冲突
|
|
24
|
+
- ✅ 主题定制:支持浅色/深色主题
|
|
25
|
+
- ✅ 位置灵活:支持四角悬浮定位
|
|
26
|
+
- ✅ 简单易用:引入即可使用,无复杂配置
|
|
27
|
+
|
|
28
|
+
## 安装
|
|
29
|
+
|
|
30
|
+
### 直接引入
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<script src="path/to/ai-agent.min.js"></script>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### NPM 安装
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install ai-agent-plugin --save
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## TypeScript 示例与预览
|
|
43
|
+
|
|
44
|
+
项目内 `examples/typescript` 目录下,包含完整的 React/Vue/jQuery TypeScript 示例代码和预览页面。
|
|
45
|
+
|
|
46
|
+
- 进入示例目录并安装依赖:
|
|
47
|
+
```bash
|
|
48
|
+
cd examples/typescript
|
|
49
|
+
npm install
|
|
50
|
+
npm start
|
|
51
|
+
```
|
|
52
|
+
- 访问对应页面即可预览和调试。
|
|
53
|
+
|
|
54
|
+
## 使用方法
|
|
55
|
+
|
|
56
|
+
### 在 jQuery 项目中使用
|
|
57
|
+
|
|
58
|
+
```html
|
|
59
|
+
<!DOCTYPE html>
|
|
60
|
+
<html>
|
|
61
|
+
<head>
|
|
62
|
+
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
63
|
+
<script src="path/to/ai-agent.min.js"></script> <!-- 引入插件 -->
|
|
64
|
+
</head>
|
|
65
|
+
<body>
|
|
66
|
+
<h1>jQuery 项目</h1>
|
|
67
|
+
<script>
|
|
68
|
+
$(document).ready(function() {
|
|
69
|
+
// 初始化 AI Agent
|
|
70
|
+
window.aiAgent = new AIAgent({
|
|
71
|
+
host: 'http://localhost:8080', // 后端站点主机(插件会在该 host 下拼接 /api/ai/chat/... 路径)
|
|
72
|
+
// 说明:为向后兼容,如果仍传入 apiUrl(示例中旧字段),插件也会识别并适配
|
|
73
|
+
secret: 'your-api-secret-key', // API 密钥(必填)
|
|
74
|
+
stream: false, // 是否启用流式响应
|
|
75
|
+
title: 'jQuery AI 助手',
|
|
76
|
+
position: 'bottom-right'
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
</script>
|
|
80
|
+
</body>
|
|
81
|
+
</html>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 在 React 项目中使用
|
|
85
|
+
|
|
86
|
+
```jsx
|
|
87
|
+
import React, { useEffect } from 'react';
|
|
88
|
+
// 引入 AI Agent 插件
|
|
89
|
+
import AIAgent from 'ai-agent-plugin';
|
|
90
|
+
// 或通过 script 标签引入后,使用全局变量 window.AIAgent
|
|
91
|
+
|
|
92
|
+
function App() {
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
// 初始化 AI Agent
|
|
95
|
+
const aiAgent = new AIAgent({
|
|
96
|
+
host: 'http://localhost:8080', // 后端站点主机(可选)
|
|
97
|
+
// 如果未提供 host,插件会回退到内置默认 host:
|
|
98
|
+
// http://localhost:8080
|
|
99
|
+
// 注意:当您提供远程(非 localhost)host 时,secret 为必填,用于后端鉴权
|
|
100
|
+
secret: 'your-api-secret-key', // API 密钥(当使用真实远端 host 时必填)
|
|
101
|
+
stream: true, // 启用流式响应
|
|
102
|
+
theme: 'dark',
|
|
103
|
+
title: 'React AI 助手'
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// 组件卸载时销毁插件
|
|
107
|
+
return () => aiAgent.destroy();
|
|
108
|
+
}, []);
|
|
109
|
+
|
|
110
|
+
return <div>React 项目</div>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export default App;
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 在 Vue 项目中使用
|
|
117
|
+
|
|
118
|
+
```vue
|
|
119
|
+
<template>
|
|
120
|
+
<div>Vue 项目</div>
|
|
121
|
+
</template>
|
|
122
|
+
|
|
123
|
+
<script>
|
|
124
|
+
import AIAgent from 'ai-agent-plugin';
|
|
125
|
+
// 或通过 script 标签引入后,使用全局变量 window.AIAgent
|
|
126
|
+
|
|
127
|
+
export default {
|
|
128
|
+
mounted() {
|
|
129
|
+
// 初始化 AI Agent
|
|
130
|
+
this.aiAgent = new AIAgent({
|
|
131
|
+
host: 'http://localhost:8080', // 后端站点主机
|
|
132
|
+
// 兼容旧字段:如果仍使用 apiUrl,插件会自动转换为 host
|
|
133
|
+
secret: 'your-api-secret-key', // API 密钥(必填)
|
|
134
|
+
stream: false, // 普通响应模式
|
|
135
|
+
title: 'Vue AI 助手',
|
|
136
|
+
position: 'bottom-left'
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
beforeDestroy() {
|
|
140
|
+
// 组件销毁前清理插件
|
|
141
|
+
if (this.aiAgent) this.aiAgent.destroy();
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
</script>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## 配置选项
|
|
148
|
+
|
|
149
|
+
| 选项 | 类型 | 默认值 | 必填 | 说明 |
|
|
150
|
+
|------|------|--------|------|------|
|
|
151
|
+
| **secret** | String | - | ✅ | API 密钥/令牌,必须提供 |
|
|
152
|
+
| apiUrl | String | '/api/ai/chat' | - | 后端 AI 接口地址 |
|
|
153
|
+
| host | String | 'http://localhost:8080' | - | 后端站点主机,插件会拼接 /api/ai/chat/... 路径(向后兼容:仍支持旧字段 `apiUrl`) |
|
|
154
|
+
| stream | Boolean | false | - | 是否启用流式响应 |
|
|
155
|
+
| theme | String | 'light' | - | 主题,可选:'light'/'dark' |
|
|
156
|
+
| position | String | 'bottom-right' | - | 位置,可选:'bottom-right'/'bottom-left'/'top-right'/'top-left' |
|
|
157
|
+
| title | String | 'AI 助手' | - | 面板标题 |
|
|
158
|
+
| placeholder | String | '请输入问题...' | - | 输入框占位文本 |
|
|
159
|
+
|
|
160
|
+
## 后端接口说明
|
|
161
|
+
|
|
162
|
+
插件支持以下后端接口格式:
|
|
163
|
+
|
|
164
|
+
### 普通模式接口
|
|
165
|
+
```
|
|
166
|
+
POST /api/ai/chat/completion
|
|
167
|
+
Content-Type: application/json
|
|
168
|
+
Authorization: Bearer your-api-secret-key
|
|
169
|
+
|
|
170
|
+
{
|
|
171
|
+
"content": "用户输入的消息"
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### 流式模式接口
|
|
176
|
+
```
|
|
177
|
+
POST /api/ai/chat/stream
|
|
178
|
+
Content-Type: application/json
|
|
179
|
+
Authorization: Bearer your-api-secret-key
|
|
180
|
+
|
|
181
|
+
{
|
|
182
|
+
"messages": [
|
|
183
|
+
{"role": "user", "content": "用户输入的消息"}
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
流式响应格式为 Server-Sent Events (SSE),响应头:`Content-Type: text/event-stream`
|
|
189
|
+
|
|
190
|
+
## 方法
|
|
191
|
+
|
|
192
|
+
| 方法 | 说明 |
|
|
193
|
+
|------|------|
|
|
194
|
+
| destroy() | 销毁插件,清理 DOM 和事件 |
|
|
195
|
+
| togglePanel() | 切换面板显示/隐藏 |
|
|
196
|
+
| closePanel() | 关闭面板 |
|
|
197
|
+
| sendMessage(text) | 发送消息到 AI 接口 |
|
|
198
|
+
|
|
199
|
+
## 开发
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# 安装依赖
|
|
203
|
+
npm install
|
|
204
|
+
|
|
205
|
+
# 开发模式
|
|
206
|
+
npm run dev
|
|
207
|
+
|
|
208
|
+
# 构建生产版本
|
|
209
|
+
npm run build
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## 许可证
|
|
213
|
+
|
|
214
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var n={904(n,e,t){t.d(e,{A:()=>s});var a=t(601),o=t.n(a),i=t(314),r=t.n(i)()(o());r.push([n.id,'/**\n * AI Agent 插件样式\n * 使用独立的命名空间和前缀,避免与宿主项目样式冲突\n * 使用 CSS 变量支持主题自定义\n */\n\n/* CSS 变量定义 - 默认浅色主题 */\n:root {\n --ai-agent-primary: #4096ff;\n --ai-agent-primary-hover: #2e80ff;\n --ai-agent-bg: #ffffff;\n --ai-agent-text: #333333;\n --ai-agent-border: #eeeeee;\n --ai-agent-msg-ai-bg: #f5f5f5;\n --ai-agent-msg-user-bg: #4096ff;\n --ai-agent-header-bg: #f5f5f5;\n}\n\n/* 触发按钮 */\n.ai-agent-btn {\n position: fixed;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border: none;\n border-radius: 20px;\n background: var(--ai-agent-primary);\n color: white;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0,0,0,0.15);\n transition: all 0.3s;\n z-index: 9999;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n font-size: 14px;\n}\n\n.ai-agent-btn:hover { \n background: var(--ai-agent-primary-hover); \n box-shadow: 0 4px 12px rgba(0,0,0,0.2);\n}\n\n.ai-agent-btn-text { \n display: none; \n}\n\n@media (min-width: 768px) { \n .ai-agent-btn-text { \n display: inline; \n } \n}\n\n/* 对话面板 */\n.ai-agent-panel {\n position: fixed;\n width: 360px;\n height: 500px;\n max-height: 80vh;\n display: flex;\n flex-direction: column;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.15);\n background: var(--ai-agent-bg);\n z-index: 10000;\n overflow: hidden;\n transition: all 0.3s;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n font-size: 14px;\n color: var(--ai-agent-text);\n}\n\n/* 主题:浅色 */\n.ai-agent-theme-light { \n --ai-agent-bg: #ffffff;\n --ai-agent-text: #333333;\n --ai-agent-border: #eeeeee;\n --ai-agent-msg-ai-bg: #f5f5f5;\n --ai-agent-header-bg: #f5f5f5;\n}\n\n.ai-agent-theme-light .ai-agent-panel-header { \n background: var(--ai-agent-header-bg); \n border-bottom: 1px solid var(--ai-agent-border); \n}\n\n.ai-agent-theme-light .ai-agent-close { \n color: #666; \n}\n\n.ai-agent-theme-light .ai-agent-msg-ai .ai-agent-msg-content { \n background: var(--ai-agent-msg-ai-bg); \n color: var(--ai-agent-text); \n}\n\n.ai-agent-theme-light .ai-agent-msg-user .ai-agent-msg-content { \n background: var(--ai-agent-msg-user-bg); \n color: white; \n}\n\n.ai-agent-theme-light .ai-agent-input { \n background: var(--ai-agent-bg); \n color: var(--ai-agent-text); \n border-top: 1px solid var(--ai-agent-border);\n}\n\n/* 主题:深色 */\n.ai-agent-theme-dark { \n --ai-agent-bg: #1e1e1e;\n --ai-agent-text: #f0f0f0;\n --ai-agent-border: #3c3c3c;\n --ai-agent-msg-ai-bg: #3c3c3c;\n --ai-agent-header-bg: #2c2c2c;\n}\n\n.ai-agent-theme-dark .ai-agent-panel-header { \n background: var(--ai-agent-header-bg); \n border-bottom: 1px solid var(--ai-agent-border); \n}\n\n.ai-agent-theme-dark .ai-agent-close { \n color: #ccc; \n}\n\n.ai-agent-theme-dark .ai-agent-msg-ai .ai-agent-msg-content { \n background: var(--ai-agent-msg-ai-bg); \n color: var(--ai-agent-text); \n}\n\n.ai-agent-theme-dark .ai-agent-msg-user .ai-agent-msg-content { \n background: var(--ai-agent-msg-user-bg); \n color: white; \n}\n\n.ai-agent-theme-dark .ai-agent-input { \n background: var(--ai-agent-bg); \n color: var(--ai-agent-text); \n border-top: 1px solid var(--ai-agent-border);\n}\n\n.ai-agent-theme-dark .ai-agent-input::placeholder {\n color: #aaa;\n}\n\n/* 位置 */\n.ai-agent-pos-bottom-right { \n bottom: 70px; \n right: 20px; \n}\n\n.ai-agent-pos-bottom-left { \n bottom: 70px; \n left: 20px; \n}\n\n.ai-agent-pos-top-right { \n top: 70px; \n right: 20px; \n}\n\n.ai-agent-pos-top-left { \n top: 70px; \n left: 20px; \n}\n\n/* 面板头部 */\n.ai-agent-panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n}\n\n.ai-agent-panel-header h3 { \n margin: 0; \n font-size: 16px; \n font-weight: 600; \n}\n\n.ai-agent-close {\n background: none;\n border: none;\n font-size: 22px;\n cursor: pointer;\n line-height: 1;\n padding: 0 5px;\n}\n\n.ai-agent-close:hover {\n opacity: 0.8;\n}\n\n/* 消息区域 */\n.ai-agent-messages {\n flex: 1;\n padding: 12px;\n overflow-y: auto;\n scrollbar-width: thin;\n}\n\n/* 设置滚动条样式 */\n.ai-agent-messages::-webkit-scrollbar {\n width: 6px;\n}\n\n.ai-agent-messages::-webkit-scrollbar-track {\n background: transparent; \n}\n\n.ai-agent-messages::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.1);\n border-radius: 3px;\n}\n\n.ai-agent-theme-dark .ai-agent-messages::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.1);\n}\n\n.ai-agent-msg {\n margin-bottom: 12px;\n display: flex;\n gap: 8px;\n}\n\n.ai-agent-msg-ai { \n justify-content: flex-start; \n}\n\n.ai-agent-msg-user { \n justify-content: flex-end; \n}\n\n.ai-agent-msg-content {\n max-width: 80%;\n padding: 10px 14px;\n border-radius: 16px;\n line-height: 1.5;\n word-break: break-word;\n}\n\n/* 加载中动画 */\n.ai-agent-loading-dots {\n display: flex;\n gap: 4px;\n justify-content: center;\n align-items: center;\n height: 20px;\n}\n\n.ai-agent-loading-dots span {\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background-color: currentColor;\n opacity: 0.6;\n animation: ai-agent-pulse 1.4s infinite ease-in-out both;\n}\n\n.ai-agent-loading-dots span:nth-child(1) {\n animation-delay: -0.32s;\n}\n\n.ai-agent-loading-dots span:nth-child(2) {\n animation-delay: -0.16s;\n}\n\n@keyframes ai-agent-pulse {\n 0%, 80%, 100% { \n transform: scale(0.6);\n } \n 40% { \n transform: scale(1);\n }\n}\n\n/* 输入区域 */\n.ai-agent-input-wrap {\n display: flex;\n border-top: 1px solid var(--ai-agent-border);\n height: 36px;\n}\n\n.ai-agent-input {\n flex: 1;\n padding: 12px 16px;\n border: none;\n outline: none;\n font-size: 14px;\n font-family: inherit;\n}\n\n.ai-agent-send {\n padding: 0 16px;\n border: none;\n background: var(--ai-agent-primary);\n color: white;\n cursor: pointer;\n font-size: 14px;\n transition: background 0.2s;\n margin-top: 0;\n}\n\n.ai-agent-send:hover { \n background: var(--ai-agent-primary-hover); \n}\n\n/* 响应式适配 */\n@media (max-width: 480px) {\n .ai-agent-panel {\n width: calc(100% - 40px);\n max-width: 360px;\n height: 400px;\n }\n \n .ai-agent-pos-bottom-right,\n .ai-agent-pos-bottom-left { \n bottom: 60px;\n }\n \n .ai-agent-pos-top-right,\n .ai-agent-pos-top-left { \n top: 60px;\n }\n}',""]);const s=r},314(n){n.exports=function(n){var e=[];return e.toString=function(){return this.map(function(e){var t="",a=void 0!==e[5];return e[4]&&(t+="@supports (".concat(e[4],") {")),e[2]&&(t+="@media ".concat(e[2]," {")),a&&(t+="@layer".concat(e[5].length>0?" ".concat(e[5]):""," {")),t+=n(e),a&&(t+="}"),e[2]&&(t+="}"),e[4]&&(t+="}"),t}).join("")},e.i=function(n,t,a,o,i){"string"==typeof n&&(n=[[null,n,void 0]]);var r={};if(a)for(var s=0;s<this.length;s++){var l=this[s][0];null!=l&&(r[l]=!0)}for(var c=0;c<n.length;c++){var p=[].concat(n[c]);a&&r[p[0]]||(void 0!==i&&(void 0===p[5]||(p[1]="@layer".concat(p[5].length>0?" ".concat(p[5]):""," {").concat(p[1],"}")),p[5]=i),t&&(p[2]?(p[1]="@media ".concat(p[2]," {").concat(p[1],"}"),p[2]=t):p[2]=t),o&&(p[4]?(p[1]="@supports (".concat(p[4],") {").concat(p[1],"}"),p[4]=o):p[4]="".concat(o)),e.push(p))}},e}},601(n){n.exports=function(n){return n[1]}},72(n){var e=[];function t(n){for(var t=-1,a=0;a<e.length;a++)if(e[a].identifier===n){t=a;break}return t}function a(n,a){for(var i={},r=[],s=0;s<n.length;s++){var l=n[s],c=a.base?l[0]+a.base:l[0],p=i[c]||0,g="".concat(c," ").concat(p);i[c]=p+1;var d=t(g),h={css:l[1],media:l[2],sourceMap:l[3],supports:l[4],layer:l[5]};if(-1!==d)e[d].references++,e[d].updater(h);else{var u=o(h,a);a.byIndex=s,e.splice(s,0,{identifier:g,updater:u,references:1})}r.push(g)}return r}function o(n,e){var t=e.domAPI(e);t.update(n);return function(e){if(e){if(e.css===n.css&&e.media===n.media&&e.sourceMap===n.sourceMap&&e.supports===n.supports&&e.layer===n.layer)return;t.update(n=e)}else t.remove()}}n.exports=function(n,o){var i=a(n=n||[],o=o||{});return function(n){n=n||[];for(var r=0;r<i.length;r++){var s=t(i[r]);e[s].references--}for(var l=a(n,o),c=0;c<i.length;c++){var p=t(i[c]);0===e[p].references&&(e[p].updater(),e.splice(p,1))}i=l}}},659(n){var e={};n.exports=function(n,t){var a=function(n){if(void 0===e[n]){var t=document.querySelector(n);if(window.HTMLIFrameElement&&t instanceof window.HTMLIFrameElement)try{t=t.contentDocument.head}catch(n){t=null}e[n]=t}return e[n]}(n);if(!a)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");a.appendChild(t)}},540(n){n.exports=function(n){var e=document.createElement("style");return n.setAttributes(e,n.attributes),n.insert(e,n.options),e}},56(n,e,t){n.exports=function(n){var e=t.nc;e&&n.setAttribute("nonce",e)}},825(n){n.exports=function(n){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var e=n.insertStyleElement(n);return{update:function(t){!function(n,e,t){var a="";t.supports&&(a+="@supports (".concat(t.supports,") {")),t.media&&(a+="@media ".concat(t.media," {"));var o=void 0!==t.layer;o&&(a+="@layer".concat(t.layer.length>0?" ".concat(t.layer):""," {")),a+=t.css,o&&(a+="}"),t.media&&(a+="}"),t.supports&&(a+="}");var i=t.sourceMap;i&&"undefined"!=typeof btoa&&(a+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),e.styleTagTransform(a,n,e.options)}(e,n,t)},remove:function(){!function(n){if(null===n.parentNode)return!1;n.parentNode.removeChild(n)}(e)}}}},113(n){n.exports=function(n,e){if(e.styleSheet)e.styleSheet.cssText=n;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(n))}}}},e={};function t(a){var o=e[a];if(void 0!==o)return o.exports;var i=e[a]={id:a,exports:{}};return n[a](i,i.exports,t),i.exports}t.n=n=>{var e=n&&n.__esModule?()=>n.default:()=>n;return t.d(e,{a:e}),e},t.d=(n,e)=>{for(var a in e)t.o(e,a)&&!t.o(n,a)&&Object.defineProperty(n,a,{enumerable:!0,get:e[a]})},t.o=(n,e)=>Object.prototype.hasOwnProperty.call(n,e),t.nc=void 0;var a=t(72),o=t.n(a),i=t(825),r=t.n(i),s=t(659),l=t.n(s),c=t(56),p=t.n(c),g=t(540),d=t.n(g),h=t(113),u=t.n(h),m=t(904),f={};f.styleTagTransform=u(),f.setAttributes=p(),f.insert=l().bind(null,"head"),f.domAPI=r(),f.insertStyleElement=d();o()(m.A,f);m.A&&m.A.locals&&m.A.locals;var b=function(){return b=Object.assign||function(n){for(var e,t=1,a=arguments.length;t<a;t++)for(var o in e=arguments[t])Object.prototype.hasOwnProperty.call(e,o)&&(n[o]=e[o]);return n},b.apply(this,arguments)},v=function(){function n(e){void 0===e&&(e={}),this.chatHistory=[],this.isOpen=!1,this.panelEl=null,this.buttonEl=null;var t=e.host&&""!==e.host.trim(),a=t?e.host.trim().replace(/\/+$/,""):"",o=a.includes("localhost")||a.includes("127.0.0.1")||!t;if(!e.secret&&!o)throw new Error("AI Agent: secret 参数为必填项,请提供 API 密钥");this.options=b({host:a||"",secret:e.secret||"demo-key",stream:e.stream||!1,theme:e.theme||"light",position:e.position||"bottom-right",placeholder:e.placeholder||"请输入问题...",title:e.title||"AI 助手"},e);var i=this.options.host&&""!==this.options.host?this.options.host:n.DEFAULT_HOST,r=function(n){return i.replace(/\/+$/,"")+"/"+n.replace(/^\/+/,"")},s=r("api/ai/chat");this.endpoints={completion:s+"/completion",stream:s+"/stream",streamSimple:s+"/stream-simple",streamConfig:s+"/stream-config",session:r("api/ai/session"),platforms:r("api/ai/platforms"),fileExtraction:r("api/ai/file/extraction")},this.init()}return n.prototype.init=function(){this.createTriggerButton(),this.createChatPanel(),this.injectStyles(),document.body.appendChild(this.buttonEl)},n.prototype.createTriggerButton=function(){var n=this;this.buttonEl=document.createElement("button"),this.buttonEl.className="ai-agent-btn";var e={"bottom-right":{bottom:"20px",right:"20px"},"bottom-left":{bottom:"20px",left:"20px"},"top-right":{top:"20px",right:"20px"},"top-left":{top:"20px",left:"20px"}},t=e[this.options.position]||e["bottom-right"];Object.assign(this.buttonEl.style,t),this.buttonEl.innerHTML='\n <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M12 1L3 5V11C3 16.55 6.84 21.74 12 23C17.16 21.74 21 16.55 21 11V5L12 1Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n <path d="M12 12L12 19" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n <path d="M12 8H12.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>\n <span class="ai-agent-btn-text">'.concat(this.options.title,"</span>\n "),this.buttonEl.addEventListener("click",function(){return n.togglePanel()})},n.prototype.createChatPanel=function(){var n=this;this.panelEl=document.createElement("div"),this.panelEl.className="ai-agent-panel ai-agent-theme-".concat(this.options.theme," ai-agent-pos-").concat(this.options.position),this.panelEl.style.display="none",this.panelEl.innerHTML='\n <div class="ai-agent-panel-header">\n <h3>'.concat(this.options.title,'</h3>\n <button class="ai-agent-close">×</button>\n </div>\n <div class="ai-agent-messages"></div>\n <div class="ai-agent-input-wrap">\n <input type="text" placeholder="').concat(this.options.placeholder,'" class="ai-agent-input" />\n <button class="ai-agent-send">发送</button>\n </div>\n ');var e=this.panelEl.querySelector(".ai-agent-close");e&&e.addEventListener("click",function(){return n.closePanel()});var t=this.panelEl.querySelector(".ai-agent-input"),a=this.panelEl.querySelector(".ai-agent-send");t&&a&&(t.addEventListener("keypress",function(e){"Enter"===e.key&&t.value.trim()&&n.sendMessage(t.value)}),a.addEventListener("click",function(){t.value.trim()&&n.sendMessage(t.value)})),document.body.appendChild(this.panelEl)},n.prototype.injectStyles=function(){var n=document.createElement("style");n.setAttribute("ai-agent-dynamic-styles","");var e={"bottom-right":"bottom: 70px; right: 20px;","bottom-left":"bottom: 70px; left: 20px;","top-right":"top: 70px; right: 20px;","top-left":"top: 70px; left: 20px;"},t={"bottom-right":"bottom: 20px; right: 20px;","bottom-left":"bottom: 20px; left: 20px;","top-right":"top: 20px; right: 20px;","top-left":"top: 20px; left: 20px;"},a=this.options.position,o="";if(this.options.colors){var i=this.options.colors;i.primary&&(o+="--ai-agent-primary: ".concat(i.primary,";\n")),i.primaryHover&&(o+="--ai-agent-primary-hover: ".concat(i.primaryHover,";\n")),i.background&&(o+="--ai-agent-bg: ".concat(i.background,";\n")),i.text&&(o+="--ai-agent-text: ".concat(i.text,";\n")),i.border&&(o+="--ai-agent-border: ".concat(i.border,";\n")),i.aiMessageBg&&(o+="--ai-agent-msg-ai-bg: ".concat(i.aiMessageBg,";\n")),i.userMessageBg?o+="--ai-agent-msg-user-bg: ".concat(i.userMessageBg,";\n"):i.primary&&(o+="--ai-agent-msg-user-bg: ".concat(i.primary,";\n")),i.headerBg&&(o+="--ai-agent-header-bg: ".concat(i.headerBg,";\n"))}n.textContent="\n ".concat(o?".ai-agent-theme-".concat(this.options.theme," {\n").concat(o,"}"):"","\n .ai-agent-panel.ai-agent-pos-").concat(a," {\n ").concat(e[a]||e["bottom-right"],"\n }\n .ai-agent-btn {\n ").concat(t[a]||t["bottom-right"],"\n }\n "),document.head.appendChild(n)},n.prototype.togglePanel=function(){if(this.isOpen=!this.isOpen,this.panelEl&&(this.panelEl.style.display=this.isOpen?"flex":"none",this.isOpen)){var n=this.panelEl.querySelector(".ai-agent-input");n&&setTimeout(function(){return n.focus()},300)}},n.prototype.closePanel=function(){this.isOpen=!1,this.panelEl&&(this.panelEl.style.display="none")},n.prototype.sendMessage=function(n){if(n.trim()&&this.panelEl){var e=this.panelEl.querySelector(".ai-agent-input"),t=this.panelEl.querySelector(".ai-agent-messages");e&&t&&(this.addMessage("user",n),t.appendChild(this.createMessageEl("user",n)),e.value="",t.scrollTop=t.scrollHeight,this.options.stream?this.sendStreamMessage(n,t):this.sendNormalMessage(n,t))}},n.prototype.sendNormalMessage=function(n,e){var t=this,a=this.showLoading(e),o=this.endpoints.completion;try{console.info("[AIAgent] 普通请求 URL ->",o)}catch(n){}fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(this.options.secret)},body:JSON.stringify({content:n})}).then(function(n){if(!n.ok)throw new Error("HTTP ".concat(n.status,": ").concat(n.statusText));return n.json()}).then(function(n){var o,i,r;t.removeLoading(a);var s="";try{n&&200===n.code&&(null===(i=null===(o=n.data)||void 0===o?void 0:o.choices)||void 0===i?void 0:i.length)>0&&(s=(null===(r=n.data.choices[0].message)||void 0===r?void 0:r.content)||""),s||(s="抱歉,AI暂时无法回复,请稍后再试~")}catch(n){console.warn("解析AI回复数据失败:",n),s="数据解析异常,请检查接口返回格式~"}t.addMessage("ai",s),e.appendChild(t.createMessageEl("ai",s)),e.scrollTop=e.scrollHeight}).catch(function(n){t.removeLoading(a);var o="网络异常,请稍后再试~";"TypeError"===n.name&&n.message.includes("Failed to fetch")?o="网络连接失败,请检查网络连接或API地址配置~":n.message.includes("HTTP 404")?o="API接口地址不存在,请检查 host 配置~":n.message.includes("HTTP 401")||n.message.includes("HTTP 403")?o="API密钥验证失败,请检查secret配置~":n.message.includes("HTTP 500")&&(o="服务器内部错误,请联系管理员~"),console.error("AI 接口调用失败:",n),t.addMessage("ai",o),e.appendChild(t.createMessageEl("ai",o)),e.scrollTop=e.scrollHeight})},n.prototype.sendStreamMessage=function(n,e){var t=this,a=this.createMessageEl("ai","");e.appendChild(a),e.scrollTop=e.scrollHeight;var o=a.querySelector(".ai-agent-msg-content"),i="",r=this.endpoints.stream;try{console.info("[AIAgent] 流式请求 URL ->",r)}catch(n){}try{console.info("[AIAgent] 将向流式接口发送 POST 请求,URL ->",r)}catch(n){}fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(this.options.secret)},body:JSON.stringify({content:n})}).then(function(n){var a;if(!n.ok)throw new Error("API响应异常: "+n.status);var r=n.headers.get("Content-Type");if(!r||!r.includes("text/event-stream"))throw new Error("不是流式响应格式");var s=null===(a=n.body)||void 0===a?void 0:a.getReader();if(!s)throw new Error("无法获取响应流");var l=new TextDecoder,c=function(){return s.read().then(function(n){var a,r=n.done,s=n.value;if(!r){for(var p=0,g=l.decode(s,{stream:!0}).split("\n");p<g.length;p++){var d=g[p];if(d.startsWith("data: ")){var h=d.slice(6);if("[DONE]"===h)return void t.addMessage("ai",i);try{var u=JSON.parse(h);if((null===(a=u.choices)||void 0===a?void 0:a.length)>0){var m=u.choices[0].delta;m.content&&(i+=m.content,o.textContent=i,e.scrollTop=e.scrollHeight)}}catch(n){console.debug("SSE数据解析跳过:",h)}}}return c()}t.addMessage("ai",i)})};return c()}).catch(function(n){console.error("流式接口调用失败:",n);var e="流式接口异常,请稍后再试~";"TypeError"===n.name&&n.message.includes("Failed to fetch")?e="网络连接失败,请检查网络连接或API地址配置~":n.message.includes("不是流式响应格式")?e="服务器不支持流式响应,请尝试关闭stream选项~":n.message.includes("无法获取响应流")&&(e="流式数据读取失败,请检查浏览器兼容性~"),o.textContent=e,t.addMessage("ai",e)})},n.prototype.showLoading=function(n){var e="loading-"+Date.now(),t=document.createElement("div");return t.className="ai-agent-msg ai-agent-msg-ai ai-agent-loading",t.id=e,t.innerHTML='\n <div class="ai-agent-msg-content">\n <div class="ai-agent-loading-dots">\n <span></span><span></span><span></span>\n </div>\n </div>\n ',n.appendChild(t),n.scrollTop=n.scrollHeight,e},n.prototype.removeLoading=function(n){var e=document.getElementById(n);e&&e.parentNode&&e.parentNode.removeChild(e)},n.prototype.addMessage=function(n,e){this.chatHistory.push({role:n,content:e}),this.chatHistory.length>20&&this.chatHistory.shift()},n.prototype.createMessageEl=function(n,e){var t=document.createElement("div");t.className="ai-agent-msg ai-agent-msg-".concat(n);var a=e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/\n/g,"<br>");return t.innerHTML='<div class="ai-agent-msg-content">'.concat(a,"</div>"),t},n.prototype.destroy=function(){this.buttonEl&&this.buttonEl.parentNode&&(this.buttonEl.parentNode.removeChild(this.buttonEl),this.buttonEl=null),this.panelEl&&this.panelEl.parentNode&&(this.panelEl.parentNode.removeChild(this.panelEl),this.panelEl=null);var n=document.querySelector("style[ai-agent-dynamic-styles]");n&&n.parentNode&&n.parentNode.removeChild(n),this.chatHistory=[]},n.DEFAULT_HOST="http://localhost:8080",n}();const x=v;export{x as default};
|
package/dist/ai-agent.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(n,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define("AIAgent",[],e):"object"==typeof exports?exports.AIAgent=e():n.AIAgent=e()}(this,()=>(()=>{"use strict";var n={904(n,e,t){t.d(e,{A:()=>s});var a=t(601),o=t.n(a),i=t(314),r=t.n(i)()(o());r.push([n.id,'/**\n * AI Agent 插件样式\n * 使用独立的命名空间和前缀,避免与宿主项目样式冲突\n * 使用 CSS 变量支持主题自定义\n */\n\n/* CSS 变量定义 - 默认浅色主题 */\n:root {\n --ai-agent-primary: #4096ff;\n --ai-agent-primary-hover: #2e80ff;\n --ai-agent-bg: #ffffff;\n --ai-agent-text: #333333;\n --ai-agent-border: #eeeeee;\n --ai-agent-msg-ai-bg: #f5f5f5;\n --ai-agent-msg-user-bg: #4096ff;\n --ai-agent-header-bg: #f5f5f5;\n}\n\n/* 触发按钮 */\n.ai-agent-btn {\n position: fixed;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border: none;\n border-radius: 20px;\n background: var(--ai-agent-primary);\n color: white;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0,0,0,0.15);\n transition: all 0.3s;\n z-index: 9999;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n font-size: 14px;\n}\n\n.ai-agent-btn:hover { \n background: var(--ai-agent-primary-hover); \n box-shadow: 0 4px 12px rgba(0,0,0,0.2);\n}\n\n.ai-agent-btn-text { \n display: none; \n}\n\n@media (min-width: 768px) { \n .ai-agent-btn-text { \n display: inline; \n } \n}\n\n/* 对话面板 */\n.ai-agent-panel {\n position: fixed;\n width: 360px;\n height: 500px;\n max-height: 80vh;\n display: flex;\n flex-direction: column;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.15);\n background: var(--ai-agent-bg);\n z-index: 10000;\n overflow: hidden;\n transition: all 0.3s;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n font-size: 14px;\n color: var(--ai-agent-text);\n}\n\n/* 主题:浅色 */\n.ai-agent-theme-light { \n --ai-agent-bg: #ffffff;\n --ai-agent-text: #333333;\n --ai-agent-border: #eeeeee;\n --ai-agent-msg-ai-bg: #f5f5f5;\n --ai-agent-header-bg: #f5f5f5;\n}\n\n.ai-agent-theme-light .ai-agent-panel-header { \n background: var(--ai-agent-header-bg); \n border-bottom: 1px solid var(--ai-agent-border); \n}\n\n.ai-agent-theme-light .ai-agent-close { \n color: #666; \n}\n\n.ai-agent-theme-light .ai-agent-msg-ai .ai-agent-msg-content { \n background: var(--ai-agent-msg-ai-bg); \n color: var(--ai-agent-text); \n}\n\n.ai-agent-theme-light .ai-agent-msg-user .ai-agent-msg-content { \n background: var(--ai-agent-msg-user-bg); \n color: white; \n}\n\n.ai-agent-theme-light .ai-agent-input { \n background: var(--ai-agent-bg); \n color: var(--ai-agent-text); \n border-top: 1px solid var(--ai-agent-border);\n}\n\n/* 主题:深色 */\n.ai-agent-theme-dark { \n --ai-agent-bg: #1e1e1e;\n --ai-agent-text: #f0f0f0;\n --ai-agent-border: #3c3c3c;\n --ai-agent-msg-ai-bg: #3c3c3c;\n --ai-agent-header-bg: #2c2c2c;\n}\n\n.ai-agent-theme-dark .ai-agent-panel-header { \n background: var(--ai-agent-header-bg); \n border-bottom: 1px solid var(--ai-agent-border); \n}\n\n.ai-agent-theme-dark .ai-agent-close { \n color: #ccc; \n}\n\n.ai-agent-theme-dark .ai-agent-msg-ai .ai-agent-msg-content { \n background: var(--ai-agent-msg-ai-bg); \n color: var(--ai-agent-text); \n}\n\n.ai-agent-theme-dark .ai-agent-msg-user .ai-agent-msg-content { \n background: var(--ai-agent-msg-user-bg); \n color: white; \n}\n\n.ai-agent-theme-dark .ai-agent-input { \n background: var(--ai-agent-bg); \n color: var(--ai-agent-text); \n border-top: 1px solid var(--ai-agent-border);\n}\n\n.ai-agent-theme-dark .ai-agent-input::placeholder {\n color: #aaa;\n}\n\n/* 位置 */\n.ai-agent-pos-bottom-right { \n bottom: 70px; \n right: 20px; \n}\n\n.ai-agent-pos-bottom-left { \n bottom: 70px; \n left: 20px; \n}\n\n.ai-agent-pos-top-right { \n top: 70px; \n right: 20px; \n}\n\n.ai-agent-pos-top-left { \n top: 70px; \n left: 20px; \n}\n\n/* 面板头部 */\n.ai-agent-panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n}\n\n.ai-agent-panel-header h3 { \n margin: 0; \n font-size: 16px; \n font-weight: 600; \n}\n\n.ai-agent-close {\n background: none;\n border: none;\n font-size: 22px;\n cursor: pointer;\n line-height: 1;\n padding: 0 5px;\n}\n\n.ai-agent-close:hover {\n opacity: 0.8;\n}\n\n/* 消息区域 */\n.ai-agent-messages {\n flex: 1;\n padding: 12px;\n overflow-y: auto;\n scrollbar-width: thin;\n}\n\n/* 设置滚动条样式 */\n.ai-agent-messages::-webkit-scrollbar {\n width: 6px;\n}\n\n.ai-agent-messages::-webkit-scrollbar-track {\n background: transparent; \n}\n\n.ai-agent-messages::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.1);\n border-radius: 3px;\n}\n\n.ai-agent-theme-dark .ai-agent-messages::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.1);\n}\n\n.ai-agent-msg {\n margin-bottom: 12px;\n display: flex;\n gap: 8px;\n}\n\n.ai-agent-msg-ai { \n justify-content: flex-start; \n}\n\n.ai-agent-msg-user { \n justify-content: flex-end; \n}\n\n.ai-agent-msg-content {\n max-width: 80%;\n padding: 10px 14px;\n border-radius: 16px;\n line-height: 1.5;\n word-break: break-word;\n}\n\n/* 加载中动画 */\n.ai-agent-loading-dots {\n display: flex;\n gap: 4px;\n justify-content: center;\n align-items: center;\n height: 20px;\n}\n\n.ai-agent-loading-dots span {\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background-color: currentColor;\n opacity: 0.6;\n animation: ai-agent-pulse 1.4s infinite ease-in-out both;\n}\n\n.ai-agent-loading-dots span:nth-child(1) {\n animation-delay: -0.32s;\n}\n\n.ai-agent-loading-dots span:nth-child(2) {\n animation-delay: -0.16s;\n}\n\n@keyframes ai-agent-pulse {\n 0%, 80%, 100% { \n transform: scale(0.6);\n } \n 40% { \n transform: scale(1);\n }\n}\n\n/* 输入区域 */\n.ai-agent-input-wrap {\n display: flex;\n border-top: 1px solid var(--ai-agent-border);\n height: 36px;\n}\n\n.ai-agent-input {\n flex: 1;\n padding: 12px 16px;\n border: none;\n outline: none;\n font-size: 14px;\n font-family: inherit;\n}\n\n.ai-agent-send {\n padding: 0 16px;\n border: none;\n background: var(--ai-agent-primary);\n color: white;\n cursor: pointer;\n font-size: 14px;\n transition: background 0.2s;\n margin-top: 0;\n}\n\n.ai-agent-send:hover { \n background: var(--ai-agent-primary-hover); \n}\n\n/* 响应式适配 */\n@media (max-width: 480px) {\n .ai-agent-panel {\n width: calc(100% - 40px);\n max-width: 360px;\n height: 400px;\n }\n \n .ai-agent-pos-bottom-right,\n .ai-agent-pos-bottom-left { \n bottom: 60px;\n }\n \n .ai-agent-pos-top-right,\n .ai-agent-pos-top-left { \n top: 60px;\n }\n}',""]);const s=r},314(n){n.exports=function(n){var e=[];return e.toString=function(){return this.map(function(e){var t="",a=void 0!==e[5];return e[4]&&(t+="@supports (".concat(e[4],") {")),e[2]&&(t+="@media ".concat(e[2]," {")),a&&(t+="@layer".concat(e[5].length>0?" ".concat(e[5]):""," {")),t+=n(e),a&&(t+="}"),e[2]&&(t+="}"),e[4]&&(t+="}"),t}).join("")},e.i=function(n,t,a,o,i){"string"==typeof n&&(n=[[null,n,void 0]]);var r={};if(a)for(var s=0;s<this.length;s++){var l=this[s][0];null!=l&&(r[l]=!0)}for(var c=0;c<n.length;c++){var p=[].concat(n[c]);a&&r[p[0]]||(void 0!==i&&(void 0===p[5]||(p[1]="@layer".concat(p[5].length>0?" ".concat(p[5]):""," {").concat(p[1],"}")),p[5]=i),t&&(p[2]?(p[1]="@media ".concat(p[2]," {").concat(p[1],"}"),p[2]=t):p[2]=t),o&&(p[4]?(p[1]="@supports (".concat(p[4],") {").concat(p[1],"}"),p[4]=o):p[4]="".concat(o)),e.push(p))}},e}},601(n){n.exports=function(n){return n[1]}},72(n){var e=[];function t(n){for(var t=-1,a=0;a<e.length;a++)if(e[a].identifier===n){t=a;break}return t}function a(n,a){for(var i={},r=[],s=0;s<n.length;s++){var l=n[s],c=a.base?l[0]+a.base:l[0],p=i[c]||0,g="".concat(c," ").concat(p);i[c]=p+1;var d=t(g),h={css:l[1],media:l[2],sourceMap:l[3],supports:l[4],layer:l[5]};if(-1!==d)e[d].references++,e[d].updater(h);else{var u=o(h,a);a.byIndex=s,e.splice(s,0,{identifier:g,updater:u,references:1})}r.push(g)}return r}function o(n,e){var t=e.domAPI(e);t.update(n);return function(e){if(e){if(e.css===n.css&&e.media===n.media&&e.sourceMap===n.sourceMap&&e.supports===n.supports&&e.layer===n.layer)return;t.update(n=e)}else t.remove()}}n.exports=function(n,o){var i=a(n=n||[],o=o||{});return function(n){n=n||[];for(var r=0;r<i.length;r++){var s=t(i[r]);e[s].references--}for(var l=a(n,o),c=0;c<i.length;c++){var p=t(i[c]);0===e[p].references&&(e[p].updater(),e.splice(p,1))}i=l}}},659(n){var e={};n.exports=function(n,t){var a=function(n){if(void 0===e[n]){var t=document.querySelector(n);if(window.HTMLIFrameElement&&t instanceof window.HTMLIFrameElement)try{t=t.contentDocument.head}catch(n){t=null}e[n]=t}return e[n]}(n);if(!a)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");a.appendChild(t)}},540(n){n.exports=function(n){var e=document.createElement("style");return n.setAttributes(e,n.attributes),n.insert(e,n.options),e}},56(n,e,t){n.exports=function(n){var e=t.nc;e&&n.setAttribute("nonce",e)}},825(n){n.exports=function(n){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var e=n.insertStyleElement(n);return{update:function(t){!function(n,e,t){var a="";t.supports&&(a+="@supports (".concat(t.supports,") {")),t.media&&(a+="@media ".concat(t.media," {"));var o=void 0!==t.layer;o&&(a+="@layer".concat(t.layer.length>0?" ".concat(t.layer):""," {")),a+=t.css,o&&(a+="}"),t.media&&(a+="}"),t.supports&&(a+="}");var i=t.sourceMap;i&&"undefined"!=typeof btoa&&(a+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),e.styleTagTransform(a,n,e.options)}(e,n,t)},remove:function(){!function(n){if(null===n.parentNode)return!1;n.parentNode.removeChild(n)}(e)}}}},113(n){n.exports=function(n,e){if(e.styleSheet)e.styleSheet.cssText=n;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(n))}}}},e={};function t(a){var o=e[a];if(void 0!==o)return o.exports;var i=e[a]={id:a,exports:{}};return n[a](i,i.exports,t),i.exports}t.n=n=>{var e=n&&n.__esModule?()=>n.default:()=>n;return t.d(e,{a:e}),e},t.d=(n,e)=>{for(var a in e)t.o(e,a)&&!t.o(n,a)&&Object.defineProperty(n,a,{enumerable:!0,get:e[a]})},t.o=(n,e)=>Object.prototype.hasOwnProperty.call(n,e),t.nc=void 0;var a={};t.d(a,{default:()=>y});var o=t(72),i=t.n(o),r=t(825),s=t.n(r),l=t(659),c=t.n(l),p=t(56),g=t.n(p),d=t(540),h=t.n(d),u=t(113),m=t.n(u),f=t(904),b={};b.styleTagTransform=m(),b.setAttributes=g(),b.insert=c().bind(null,"head"),b.domAPI=s(),b.insertStyleElement=h();i()(f.A,b);f.A&&f.A.locals&&f.A.locals;var v=function(){return v=Object.assign||function(n){for(var e,t=1,a=arguments.length;t<a;t++)for(var o in e=arguments[t])Object.prototype.hasOwnProperty.call(e,o)&&(n[o]=e[o]);return n},v.apply(this,arguments)},x=function(){function n(e){void 0===e&&(e={}),this.chatHistory=[],this.isOpen=!1,this.panelEl=null,this.buttonEl=null;var t=e.host&&""!==e.host.trim(),a=t?e.host.trim().replace(/\/+$/,""):"",o=a.includes("localhost")||a.includes("127.0.0.1")||!t;if(!e.secret&&!o)throw new Error("AI Agent: secret 参数为必填项,请提供 API 密钥");this.options=v({host:a||"",secret:e.secret||"demo-key",stream:e.stream||!1,theme:e.theme||"light",position:e.position||"bottom-right",placeholder:e.placeholder||"请输入问题...",title:e.title||"AI 助手"},e);var i=this.options.host&&""!==this.options.host?this.options.host:n.DEFAULT_HOST,r=function(n){return i.replace(/\/+$/,"")+"/"+n.replace(/^\/+/,"")},s=r("api/ai/chat");this.endpoints={completion:s+"/completion",stream:s+"/stream",streamSimple:s+"/stream-simple",streamConfig:s+"/stream-config",session:r("api/ai/session"),platforms:r("api/ai/platforms"),fileExtraction:r("api/ai/file/extraction")},this.init()}return n.prototype.init=function(){this.createTriggerButton(),this.createChatPanel(),this.injectStyles(),document.body.appendChild(this.buttonEl)},n.prototype.createTriggerButton=function(){var n=this;this.buttonEl=document.createElement("button"),this.buttonEl.className="ai-agent-btn";var e={"bottom-right":{bottom:"20px",right:"20px"},"bottom-left":{bottom:"20px",left:"20px"},"top-right":{top:"20px",right:"20px"},"top-left":{top:"20px",left:"20px"}},t=e[this.options.position]||e["bottom-right"];Object.assign(this.buttonEl.style,t),this.buttonEl.innerHTML='\n <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M12 1L3 5V11C3 16.55 6.84 21.74 12 23C17.16 21.74 21 16.55 21 11V5L12 1Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n <path d="M12 12L12 19" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n <path d="M12 8H12.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>\n <span class="ai-agent-btn-text">'.concat(this.options.title,"</span>\n "),this.buttonEl.addEventListener("click",function(){return n.togglePanel()})},n.prototype.createChatPanel=function(){var n=this;this.panelEl=document.createElement("div"),this.panelEl.className="ai-agent-panel ai-agent-theme-".concat(this.options.theme," ai-agent-pos-").concat(this.options.position),this.panelEl.style.display="none",this.panelEl.innerHTML='\n <div class="ai-agent-panel-header">\n <h3>'.concat(this.options.title,'</h3>\n <button class="ai-agent-close">×</button>\n </div>\n <div class="ai-agent-messages"></div>\n <div class="ai-agent-input-wrap">\n <input type="text" placeholder="').concat(this.options.placeholder,'" class="ai-agent-input" />\n <button class="ai-agent-send">发送</button>\n </div>\n ');var e=this.panelEl.querySelector(".ai-agent-close");e&&e.addEventListener("click",function(){return n.closePanel()});var t=this.panelEl.querySelector(".ai-agent-input"),a=this.panelEl.querySelector(".ai-agent-send");t&&a&&(t.addEventListener("keypress",function(e){"Enter"===e.key&&t.value.trim()&&n.sendMessage(t.value)}),a.addEventListener("click",function(){t.value.trim()&&n.sendMessage(t.value)})),document.body.appendChild(this.panelEl)},n.prototype.injectStyles=function(){var n=document.createElement("style");n.setAttribute("ai-agent-dynamic-styles","");var e={"bottom-right":"bottom: 70px; right: 20px;","bottom-left":"bottom: 70px; left: 20px;","top-right":"top: 70px; right: 20px;","top-left":"top: 70px; left: 20px;"},t={"bottom-right":"bottom: 20px; right: 20px;","bottom-left":"bottom: 20px; left: 20px;","top-right":"top: 20px; right: 20px;","top-left":"top: 20px; left: 20px;"},a=this.options.position,o="";if(this.options.colors){var i=this.options.colors;i.primary&&(o+="--ai-agent-primary: ".concat(i.primary,";\n")),i.primaryHover&&(o+="--ai-agent-primary-hover: ".concat(i.primaryHover,";\n")),i.background&&(o+="--ai-agent-bg: ".concat(i.background,";\n")),i.text&&(o+="--ai-agent-text: ".concat(i.text,";\n")),i.border&&(o+="--ai-agent-border: ".concat(i.border,";\n")),i.aiMessageBg&&(o+="--ai-agent-msg-ai-bg: ".concat(i.aiMessageBg,";\n")),i.userMessageBg?o+="--ai-agent-msg-user-bg: ".concat(i.userMessageBg,";\n"):i.primary&&(o+="--ai-agent-msg-user-bg: ".concat(i.primary,";\n")),i.headerBg&&(o+="--ai-agent-header-bg: ".concat(i.headerBg,";\n"))}n.textContent="\n ".concat(o?".ai-agent-theme-".concat(this.options.theme," {\n").concat(o,"}"):"","\n .ai-agent-panel.ai-agent-pos-").concat(a," {\n ").concat(e[a]||e["bottom-right"],"\n }\n .ai-agent-btn {\n ").concat(t[a]||t["bottom-right"],"\n }\n "),document.head.appendChild(n)},n.prototype.togglePanel=function(){if(this.isOpen=!this.isOpen,this.panelEl&&(this.panelEl.style.display=this.isOpen?"flex":"none",this.isOpen)){var n=this.panelEl.querySelector(".ai-agent-input");n&&setTimeout(function(){return n.focus()},300)}},n.prototype.closePanel=function(){this.isOpen=!1,this.panelEl&&(this.panelEl.style.display="none")},n.prototype.sendMessage=function(n){if(n.trim()&&this.panelEl){var e=this.panelEl.querySelector(".ai-agent-input"),t=this.panelEl.querySelector(".ai-agent-messages");e&&t&&(this.addMessage("user",n),t.appendChild(this.createMessageEl("user",n)),e.value="",t.scrollTop=t.scrollHeight,this.options.stream?this.sendStreamMessage(n,t):this.sendNormalMessage(n,t))}},n.prototype.sendNormalMessage=function(n,e){var t=this,a=this.showLoading(e),o=this.endpoints.completion;try{console.info("[AIAgent] 普通请求 URL ->",o)}catch(n){}fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(this.options.secret)},body:JSON.stringify({content:n})}).then(function(n){if(!n.ok)throw new Error("HTTP ".concat(n.status,": ").concat(n.statusText));return n.json()}).then(function(n){var o,i,r;t.removeLoading(a);var s="";try{n&&200===n.code&&(null===(i=null===(o=n.data)||void 0===o?void 0:o.choices)||void 0===i?void 0:i.length)>0&&(s=(null===(r=n.data.choices[0].message)||void 0===r?void 0:r.content)||""),s||(s="抱歉,AI暂时无法回复,请稍后再试~")}catch(n){console.warn("解析AI回复数据失败:",n),s="数据解析异常,请检查接口返回格式~"}t.addMessage("ai",s),e.appendChild(t.createMessageEl("ai",s)),e.scrollTop=e.scrollHeight}).catch(function(n){t.removeLoading(a);var o="网络异常,请稍后再试~";"TypeError"===n.name&&n.message.includes("Failed to fetch")?o="网络连接失败,请检查网络连接或API地址配置~":n.message.includes("HTTP 404")?o="API接口地址不存在,请检查 host 配置~":n.message.includes("HTTP 401")||n.message.includes("HTTP 403")?o="API密钥验证失败,请检查secret配置~":n.message.includes("HTTP 500")&&(o="服务器内部错误,请联系管理员~"),console.error("AI 接口调用失败:",n),t.addMessage("ai",o),e.appendChild(t.createMessageEl("ai",o)),e.scrollTop=e.scrollHeight})},n.prototype.sendStreamMessage=function(n,e){var t=this,a=this.createMessageEl("ai","");e.appendChild(a),e.scrollTop=e.scrollHeight;var o=a.querySelector(".ai-agent-msg-content"),i="",r=this.endpoints.stream;try{console.info("[AIAgent] 流式请求 URL ->",r)}catch(n){}try{console.info("[AIAgent] 将向流式接口发送 POST 请求,URL ->",r)}catch(n){}fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(this.options.secret)},body:JSON.stringify({content:n})}).then(function(n){var a;if(!n.ok)throw new Error("API响应异常: "+n.status);var r=n.headers.get("Content-Type");if(!r||!r.includes("text/event-stream"))throw new Error("不是流式响应格式");var s=null===(a=n.body)||void 0===a?void 0:a.getReader();if(!s)throw new Error("无法获取响应流");var l=new TextDecoder,c=function(){return s.read().then(function(n){var a,r=n.done,s=n.value;if(!r){for(var p=0,g=l.decode(s,{stream:!0}).split("\n");p<g.length;p++){var d=g[p];if(d.startsWith("data: ")){var h=d.slice(6);if("[DONE]"===h)return void t.addMessage("ai",i);try{var u=JSON.parse(h);if((null===(a=u.choices)||void 0===a?void 0:a.length)>0){var m=u.choices[0].delta;m.content&&(i+=m.content,o.textContent=i,e.scrollTop=e.scrollHeight)}}catch(n){console.debug("SSE数据解析跳过:",h)}}}return c()}t.addMessage("ai",i)})};return c()}).catch(function(n){console.error("流式接口调用失败:",n);var e="流式接口异常,请稍后再试~";"TypeError"===n.name&&n.message.includes("Failed to fetch")?e="网络连接失败,请检查网络连接或API地址配置~":n.message.includes("不是流式响应格式")?e="服务器不支持流式响应,请尝试关闭stream选项~":n.message.includes("无法获取响应流")&&(e="流式数据读取失败,请检查浏览器兼容性~"),o.textContent=e,t.addMessage("ai",e)})},n.prototype.showLoading=function(n){var e="loading-"+Date.now(),t=document.createElement("div");return t.className="ai-agent-msg ai-agent-msg-ai ai-agent-loading",t.id=e,t.innerHTML='\n <div class="ai-agent-msg-content">\n <div class="ai-agent-loading-dots">\n <span></span><span></span><span></span>\n </div>\n </div>\n ',n.appendChild(t),n.scrollTop=n.scrollHeight,e},n.prototype.removeLoading=function(n){var e=document.getElementById(n);e&&e.parentNode&&e.parentNode.removeChild(e)},n.prototype.addMessage=function(n,e){this.chatHistory.push({role:n,content:e}),this.chatHistory.length>20&&this.chatHistory.shift()},n.prototype.createMessageEl=function(n,e){var t=document.createElement("div");t.className="ai-agent-msg ai-agent-msg-".concat(n);var a=e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/\n/g,"<br>");return t.innerHTML='<div class="ai-agent-msg-content">'.concat(a,"</div>"),t},n.prototype.destroy=function(){this.buttonEl&&this.buttonEl.parentNode&&(this.buttonEl.parentNode.removeChild(this.buttonEl),this.buttonEl=null),this.panelEl&&this.panelEl.parentNode&&(this.panelEl.parentNode.removeChild(this.panelEl),this.panelEl=null);var n=document.querySelector("style[ai-agent-dynamic-styles]");n&&n.parentNode&&n.parentNode.removeChild(n),this.chatHistory=[]},n.DEFAULT_HOST="http://localhost:8080",n}();const y=x;return a=a.default})());
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(n,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define("AIAgent",[],e):"object"==typeof exports?exports.AIAgent=e():n.AIAgent=e()}(this,()=>(()=>{"use strict";var n={904(n,e,t){t.d(e,{A:()=>s});var a=t(601),o=t.n(a),i=t(314),r=t.n(i)()(o());r.push([n.id,'/**\n * AI Agent 插件样式\n * 使用独立的命名空间和前缀,避免与宿主项目样式冲突\n * 使用 CSS 变量支持主题自定义\n */\n\n/* CSS 变量定义 - 默认浅色主题 */\n:root {\n --ai-agent-primary: #4096ff;\n --ai-agent-primary-hover: #2e80ff;\n --ai-agent-bg: #ffffff;\n --ai-agent-text: #333333;\n --ai-agent-border: #eeeeee;\n --ai-agent-msg-ai-bg: #f5f5f5;\n --ai-agent-msg-user-bg: #4096ff;\n --ai-agent-header-bg: #f5f5f5;\n}\n\n/* 触发按钮 */\n.ai-agent-btn {\n position: fixed;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border: none;\n border-radius: 20px;\n background: var(--ai-agent-primary);\n color: white;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0,0,0,0.15);\n transition: all 0.3s;\n z-index: 9999;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n font-size: 14px;\n}\n\n.ai-agent-btn:hover { \n background: var(--ai-agent-primary-hover); \n box-shadow: 0 4px 12px rgba(0,0,0,0.2);\n}\n\n.ai-agent-btn-text { \n display: none; \n}\n\n@media (min-width: 768px) { \n .ai-agent-btn-text { \n display: inline; \n } \n}\n\n/* 对话面板 */\n.ai-agent-panel {\n position: fixed;\n width: 360px;\n height: 500px;\n max-height: 80vh;\n display: flex;\n flex-direction: column;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.15);\n background: var(--ai-agent-bg);\n z-index: 10000;\n overflow: hidden;\n transition: all 0.3s;\n font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;\n font-size: 14px;\n color: var(--ai-agent-text);\n}\n\n/* 主题:浅色 */\n.ai-agent-theme-light { \n --ai-agent-bg: #ffffff;\n --ai-agent-text: #333333;\n --ai-agent-border: #eeeeee;\n --ai-agent-msg-ai-bg: #f5f5f5;\n --ai-agent-header-bg: #f5f5f5;\n}\n\n.ai-agent-theme-light .ai-agent-panel-header { \n background: var(--ai-agent-header-bg); \n border-bottom: 1px solid var(--ai-agent-border); \n}\n\n.ai-agent-theme-light .ai-agent-close { \n color: #666; \n}\n\n.ai-agent-theme-light .ai-agent-msg-ai .ai-agent-msg-content { \n background: var(--ai-agent-msg-ai-bg); \n color: var(--ai-agent-text); \n}\n\n.ai-agent-theme-light .ai-agent-msg-user .ai-agent-msg-content { \n background: var(--ai-agent-msg-user-bg); \n color: white; \n}\n\n.ai-agent-theme-light .ai-agent-input { \n background: var(--ai-agent-bg); \n color: var(--ai-agent-text); \n border-top: 1px solid var(--ai-agent-border);\n}\n\n/* 主题:深色 */\n.ai-agent-theme-dark { \n --ai-agent-bg: #1e1e1e;\n --ai-agent-text: #f0f0f0;\n --ai-agent-border: #3c3c3c;\n --ai-agent-msg-ai-bg: #3c3c3c;\n --ai-agent-header-bg: #2c2c2c;\n}\n\n.ai-agent-theme-dark .ai-agent-panel-header { \n background: var(--ai-agent-header-bg); \n border-bottom: 1px solid var(--ai-agent-border); \n}\n\n.ai-agent-theme-dark .ai-agent-close { \n color: #ccc; \n}\n\n.ai-agent-theme-dark .ai-agent-msg-ai .ai-agent-msg-content { \n background: var(--ai-agent-msg-ai-bg); \n color: var(--ai-agent-text); \n}\n\n.ai-agent-theme-dark .ai-agent-msg-user .ai-agent-msg-content { \n background: var(--ai-agent-msg-user-bg); \n color: white; \n}\n\n.ai-agent-theme-dark .ai-agent-input { \n background: var(--ai-agent-bg); \n color: var(--ai-agent-text); \n border-top: 1px solid var(--ai-agent-border);\n}\n\n.ai-agent-theme-dark .ai-agent-input::placeholder {\n color: #aaa;\n}\n\n/* 位置 */\n.ai-agent-pos-bottom-right { \n bottom: 70px; \n right: 20px; \n}\n\n.ai-agent-pos-bottom-left { \n bottom: 70px; \n left: 20px; \n}\n\n.ai-agent-pos-top-right { \n top: 70px; \n right: 20px; \n}\n\n.ai-agent-pos-top-left { \n top: 70px; \n left: 20px; \n}\n\n/* 面板头部 */\n.ai-agent-panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n}\n\n.ai-agent-panel-header h3 { \n margin: 0; \n font-size: 16px; \n font-weight: 600; \n}\n\n.ai-agent-close {\n background: none;\n border: none;\n font-size: 22px;\n cursor: pointer;\n line-height: 1;\n padding: 0 5px;\n}\n\n.ai-agent-close:hover {\n opacity: 0.8;\n}\n\n/* 消息区域 */\n.ai-agent-messages {\n flex: 1;\n padding: 12px;\n overflow-y: auto;\n scrollbar-width: thin;\n}\n\n/* 设置滚动条样式 */\n.ai-agent-messages::-webkit-scrollbar {\n width: 6px;\n}\n\n.ai-agent-messages::-webkit-scrollbar-track {\n background: transparent; \n}\n\n.ai-agent-messages::-webkit-scrollbar-thumb {\n background: rgba(0, 0, 0, 0.1);\n border-radius: 3px;\n}\n\n.ai-agent-theme-dark .ai-agent-messages::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.1);\n}\n\n.ai-agent-msg {\n margin-bottom: 12px;\n display: flex;\n gap: 8px;\n}\n\n.ai-agent-msg-ai { \n justify-content: flex-start; \n}\n\n.ai-agent-msg-user { \n justify-content: flex-end; \n}\n\n.ai-agent-msg-content {\n max-width: 80%;\n padding: 10px 14px;\n border-radius: 16px;\n line-height: 1.5;\n word-break: break-word;\n}\n\n/* 加载中动画 */\n.ai-agent-loading-dots {\n display: flex;\n gap: 4px;\n justify-content: center;\n align-items: center;\n height: 20px;\n}\n\n.ai-agent-loading-dots span {\n display: inline-block;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background-color: currentColor;\n opacity: 0.6;\n animation: ai-agent-pulse 1.4s infinite ease-in-out both;\n}\n\n.ai-agent-loading-dots span:nth-child(1) {\n animation-delay: -0.32s;\n}\n\n.ai-agent-loading-dots span:nth-child(2) {\n animation-delay: -0.16s;\n}\n\n@keyframes ai-agent-pulse {\n 0%, 80%, 100% { \n transform: scale(0.6);\n } \n 40% { \n transform: scale(1);\n }\n}\n\n/* 输入区域 */\n.ai-agent-input-wrap {\n display: flex;\n border-top: 1px solid var(--ai-agent-border);\n height: 36px;\n}\n\n.ai-agent-input {\n flex: 1;\n padding: 12px 16px;\n border: none;\n outline: none;\n font-size: 14px;\n font-family: inherit;\n}\n\n.ai-agent-send {\n padding: 0 16px;\n border: none;\n background: var(--ai-agent-primary);\n color: white;\n cursor: pointer;\n font-size: 14px;\n transition: background 0.2s;\n margin-top: 0;\n}\n\n.ai-agent-send:hover { \n background: var(--ai-agent-primary-hover); \n}\n\n/* 响应式适配 */\n@media (max-width: 480px) {\n .ai-agent-panel {\n width: calc(100% - 40px);\n max-width: 360px;\n height: 400px;\n }\n \n .ai-agent-pos-bottom-right,\n .ai-agent-pos-bottom-left { \n bottom: 60px;\n }\n \n .ai-agent-pos-top-right,\n .ai-agent-pos-top-left { \n top: 60px;\n }\n}',""]);const s=r},314(n){n.exports=function(n){var e=[];return e.toString=function(){return this.map(function(e){var t="",a=void 0!==e[5];return e[4]&&(t+="@supports (".concat(e[4],") {")),e[2]&&(t+="@media ".concat(e[2]," {")),a&&(t+="@layer".concat(e[5].length>0?" ".concat(e[5]):""," {")),t+=n(e),a&&(t+="}"),e[2]&&(t+="}"),e[4]&&(t+="}"),t}).join("")},e.i=function(n,t,a,o,i){"string"==typeof n&&(n=[[null,n,void 0]]);var r={};if(a)for(var s=0;s<this.length;s++){var l=this[s][0];null!=l&&(r[l]=!0)}for(var c=0;c<n.length;c++){var p=[].concat(n[c]);a&&r[p[0]]||(void 0!==i&&(void 0===p[5]||(p[1]="@layer".concat(p[5].length>0?" ".concat(p[5]):""," {").concat(p[1],"}")),p[5]=i),t&&(p[2]?(p[1]="@media ".concat(p[2]," {").concat(p[1],"}"),p[2]=t):p[2]=t),o&&(p[4]?(p[1]="@supports (".concat(p[4],") {").concat(p[1],"}"),p[4]=o):p[4]="".concat(o)),e.push(p))}},e}},601(n){n.exports=function(n){return n[1]}},72(n){var e=[];function t(n){for(var t=-1,a=0;a<e.length;a++)if(e[a].identifier===n){t=a;break}return t}function a(n,a){for(var i={},r=[],s=0;s<n.length;s++){var l=n[s],c=a.base?l[0]+a.base:l[0],p=i[c]||0,g="".concat(c," ").concat(p);i[c]=p+1;var d=t(g),h={css:l[1],media:l[2],sourceMap:l[3],supports:l[4],layer:l[5]};if(-1!==d)e[d].references++,e[d].updater(h);else{var u=o(h,a);a.byIndex=s,e.splice(s,0,{identifier:g,updater:u,references:1})}r.push(g)}return r}function o(n,e){var t=e.domAPI(e);t.update(n);return function(e){if(e){if(e.css===n.css&&e.media===n.media&&e.sourceMap===n.sourceMap&&e.supports===n.supports&&e.layer===n.layer)return;t.update(n=e)}else t.remove()}}n.exports=function(n,o){var i=a(n=n||[],o=o||{});return function(n){n=n||[];for(var r=0;r<i.length;r++){var s=t(i[r]);e[s].references--}for(var l=a(n,o),c=0;c<i.length;c++){var p=t(i[c]);0===e[p].references&&(e[p].updater(),e.splice(p,1))}i=l}}},659(n){var e={};n.exports=function(n,t){var a=function(n){if(void 0===e[n]){var t=document.querySelector(n);if(window.HTMLIFrameElement&&t instanceof window.HTMLIFrameElement)try{t=t.contentDocument.head}catch(n){t=null}e[n]=t}return e[n]}(n);if(!a)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");a.appendChild(t)}},540(n){n.exports=function(n){var e=document.createElement("style");return n.setAttributes(e,n.attributes),n.insert(e,n.options),e}},56(n,e,t){n.exports=function(n){var e=t.nc;e&&n.setAttribute("nonce",e)}},825(n){n.exports=function(n){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var e=n.insertStyleElement(n);return{update:function(t){!function(n,e,t){var a="";t.supports&&(a+="@supports (".concat(t.supports,") {")),t.media&&(a+="@media ".concat(t.media," {"));var o=void 0!==t.layer;o&&(a+="@layer".concat(t.layer.length>0?" ".concat(t.layer):""," {")),a+=t.css,o&&(a+="}"),t.media&&(a+="}"),t.supports&&(a+="}");var i=t.sourceMap;i&&"undefined"!=typeof btoa&&(a+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),e.styleTagTransform(a,n,e.options)}(e,n,t)},remove:function(){!function(n){if(null===n.parentNode)return!1;n.parentNode.removeChild(n)}(e)}}}},113(n){n.exports=function(n,e){if(e.styleSheet)e.styleSheet.cssText=n;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(n))}}}},e={};function t(a){var o=e[a];if(void 0!==o)return o.exports;var i=e[a]={id:a,exports:{}};return n[a](i,i.exports,t),i.exports}t.n=n=>{var e=n&&n.__esModule?()=>n.default:()=>n;return t.d(e,{a:e}),e},t.d=(n,e)=>{for(var a in e)t.o(e,a)&&!t.o(n,a)&&Object.defineProperty(n,a,{enumerable:!0,get:e[a]})},t.o=(n,e)=>Object.prototype.hasOwnProperty.call(n,e),t.nc=void 0;var a={};t.d(a,{default:()=>y});var o=t(72),i=t.n(o),r=t(825),s=t.n(r),l=t(659),c=t.n(l),p=t(56),g=t.n(p),d=t(540),h=t.n(d),u=t(113),m=t.n(u),f=t(904),b={};b.styleTagTransform=m(),b.setAttributes=g(),b.insert=c().bind(null,"head"),b.domAPI=s(),b.insertStyleElement=h();i()(f.A,b);f.A&&f.A.locals&&f.A.locals;var v=function(){return v=Object.assign||function(n){for(var e,t=1,a=arguments.length;t<a;t++)for(var o in e=arguments[t])Object.prototype.hasOwnProperty.call(e,o)&&(n[o]=e[o]);return n},v.apply(this,arguments)},x=function(){function n(e){void 0===e&&(e={}),this.chatHistory=[],this.isOpen=!1,this.panelEl=null,this.buttonEl=null;var t=e.host&&""!==e.host.trim(),a=t?e.host.trim().replace(/\/+$/,""):"",o=a.includes("localhost")||a.includes("127.0.0.1")||!t;if(!e.secret&&!o)throw new Error("AI Agent: secret 参数为必填项,请提供 API 密钥");this.options=v({host:a||"",secret:e.secret||"demo-key",stream:e.stream||!1,theme:e.theme||"light",position:e.position||"bottom-right",placeholder:e.placeholder||"请输入问题...",title:e.title||"AI 助手"},e);var i=this.options.host&&""!==this.options.host?this.options.host:n.DEFAULT_HOST,r=function(n){return i.replace(/\/+$/,"")+"/"+n.replace(/^\/+/,"")},s=r("api/ai/chat");this.endpoints={completion:s+"/completion",stream:s+"/stream",streamSimple:s+"/stream-simple",streamConfig:s+"/stream-config",session:r("api/ai/session"),platforms:r("api/ai/platforms"),fileExtraction:r("api/ai/file/extraction")},this.init()}return n.prototype.init=function(){this.createTriggerButton(),this.createChatPanel(),this.injectStyles(),document.body.appendChild(this.buttonEl)},n.prototype.createTriggerButton=function(){var n=this;this.buttonEl=document.createElement("button"),this.buttonEl.className="ai-agent-btn";var e={"bottom-right":{bottom:"20px",right:"20px"},"bottom-left":{bottom:"20px",left:"20px"},"top-right":{top:"20px",right:"20px"},"top-left":{top:"20px",left:"20px"}},t=e[this.options.position]||e["bottom-right"];Object.assign(this.buttonEl.style,t),this.buttonEl.innerHTML='\n <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M12 1L3 5V11C3 16.55 6.84 21.74 12 23C17.16 21.74 21 16.55 21 11V5L12 1Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n <path d="M12 12L12 19" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n <path d="M12 8H12.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>\n <span class="ai-agent-btn-text">'.concat(this.options.title,"</span>\n "),this.buttonEl.addEventListener("click",function(){return n.togglePanel()})},n.prototype.createChatPanel=function(){var n=this;this.panelEl=document.createElement("div"),this.panelEl.className="ai-agent-panel ai-agent-theme-".concat(this.options.theme," ai-agent-pos-").concat(this.options.position),this.panelEl.style.display="none",this.panelEl.innerHTML='\n <div class="ai-agent-panel-header">\n <h3>'.concat(this.options.title,'</h3>\n <button class="ai-agent-close">×</button>\n </div>\n <div class="ai-agent-messages"></div>\n <div class="ai-agent-input-wrap">\n <input type="text" placeholder="').concat(this.options.placeholder,'" class="ai-agent-input" />\n <button class="ai-agent-send">发送</button>\n </div>\n ');var e=this.panelEl.querySelector(".ai-agent-close");e&&e.addEventListener("click",function(){return n.closePanel()});var t=this.panelEl.querySelector(".ai-agent-input"),a=this.panelEl.querySelector(".ai-agent-send");t&&a&&(t.addEventListener("keypress",function(e){"Enter"===e.key&&t.value.trim()&&n.sendMessage(t.value)}),a.addEventListener("click",function(){t.value.trim()&&n.sendMessage(t.value)})),document.body.appendChild(this.panelEl)},n.prototype.injectStyles=function(){var n=document.createElement("style");n.setAttribute("ai-agent-dynamic-styles","");var e={"bottom-right":"bottom: 70px; right: 20px;","bottom-left":"bottom: 70px; left: 20px;","top-right":"top: 70px; right: 20px;","top-left":"top: 70px; left: 20px;"},t={"bottom-right":"bottom: 20px; right: 20px;","bottom-left":"bottom: 20px; left: 20px;","top-right":"top: 20px; right: 20px;","top-left":"top: 20px; left: 20px;"},a=this.options.position,o="";if(this.options.colors){var i=this.options.colors;i.primary&&(o+="--ai-agent-primary: ".concat(i.primary,";\n")),i.primaryHover&&(o+="--ai-agent-primary-hover: ".concat(i.primaryHover,";\n")),i.background&&(o+="--ai-agent-bg: ".concat(i.background,";\n")),i.text&&(o+="--ai-agent-text: ".concat(i.text,";\n")),i.border&&(o+="--ai-agent-border: ".concat(i.border,";\n")),i.aiMessageBg&&(o+="--ai-agent-msg-ai-bg: ".concat(i.aiMessageBg,";\n")),i.userMessageBg?o+="--ai-agent-msg-user-bg: ".concat(i.userMessageBg,";\n"):i.primary&&(o+="--ai-agent-msg-user-bg: ".concat(i.primary,";\n")),i.headerBg&&(o+="--ai-agent-header-bg: ".concat(i.headerBg,";\n"))}n.textContent="\n ".concat(o?".ai-agent-theme-".concat(this.options.theme," {\n").concat(o,"}"):"","\n .ai-agent-panel.ai-agent-pos-").concat(a," {\n ").concat(e[a]||e["bottom-right"],"\n }\n .ai-agent-btn {\n ").concat(t[a]||t["bottom-right"],"\n }\n "),document.head.appendChild(n)},n.prototype.togglePanel=function(){if(this.isOpen=!this.isOpen,this.panelEl&&(this.panelEl.style.display=this.isOpen?"flex":"none",this.isOpen)){var n=this.panelEl.querySelector(".ai-agent-input");n&&setTimeout(function(){return n.focus()},300)}},n.prototype.closePanel=function(){this.isOpen=!1,this.panelEl&&(this.panelEl.style.display="none")},n.prototype.sendMessage=function(n){if(n.trim()&&this.panelEl){var e=this.panelEl.querySelector(".ai-agent-input"),t=this.panelEl.querySelector(".ai-agent-messages");e&&t&&(this.addMessage("user",n),t.appendChild(this.createMessageEl("user",n)),e.value="",t.scrollTop=t.scrollHeight,this.options.stream?this.sendStreamMessage(n,t):this.sendNormalMessage(n,t))}},n.prototype.sendNormalMessage=function(n,e){var t=this,a=this.showLoading(e),o=this.endpoints.completion;try{console.info("[AIAgent] 普通请求 URL ->",o)}catch(n){}fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(this.options.secret)},body:JSON.stringify({content:n})}).then(function(n){if(!n.ok)throw new Error("HTTP ".concat(n.status,": ").concat(n.statusText));return n.json()}).then(function(n){var o,i,r;t.removeLoading(a);var s="";try{n&&200===n.code&&(null===(i=null===(o=n.data)||void 0===o?void 0:o.choices)||void 0===i?void 0:i.length)>0&&(s=(null===(r=n.data.choices[0].message)||void 0===r?void 0:r.content)||""),s||(s="抱歉,AI暂时无法回复,请稍后再试~")}catch(n){console.warn("解析AI回复数据失败:",n),s="数据解析异常,请检查接口返回格式~"}t.addMessage("ai",s),e.appendChild(t.createMessageEl("ai",s)),e.scrollTop=e.scrollHeight}).catch(function(n){t.removeLoading(a);var o="网络异常,请稍后再试~";"TypeError"===n.name&&n.message.includes("Failed to fetch")?o="网络连接失败,请检查网络连接或API地址配置~":n.message.includes("HTTP 404")?o="API接口地址不存在,请检查 host 配置~":n.message.includes("HTTP 401")||n.message.includes("HTTP 403")?o="API密钥验证失败,请检查secret配置~":n.message.includes("HTTP 500")&&(o="服务器内部错误,请联系管理员~"),console.error("AI 接口调用失败:",n),t.addMessage("ai",o),e.appendChild(t.createMessageEl("ai",o)),e.scrollTop=e.scrollHeight})},n.prototype.sendStreamMessage=function(n,e){var t=this,a=this.createMessageEl("ai","");e.appendChild(a),e.scrollTop=e.scrollHeight;var o=a.querySelector(".ai-agent-msg-content"),i="",r=this.endpoints.stream;try{console.info("[AIAgent] 流式请求 URL ->",r)}catch(n){}try{console.info("[AIAgent] 将向流式接口发送 POST 请求,URL ->",r)}catch(n){}fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(this.options.secret)},body:JSON.stringify({content:n})}).then(function(n){var a;if(!n.ok)throw new Error("API响应异常: "+n.status);var r=n.headers.get("Content-Type");if(!r||!r.includes("text/event-stream"))throw new Error("不是流式响应格式");var s=null===(a=n.body)||void 0===a?void 0:a.getReader();if(!s)throw new Error("无法获取响应流");var l=new TextDecoder,c=function(){return s.read().then(function(n){var a,r=n.done,s=n.value;if(!r){for(var p=0,g=l.decode(s,{stream:!0}).split("\n");p<g.length;p++){var d=g[p];if(d.startsWith("data: ")){var h=d.slice(6);if("[DONE]"===h)return void t.addMessage("ai",i);try{var u=JSON.parse(h);if((null===(a=u.choices)||void 0===a?void 0:a.length)>0){var m=u.choices[0].delta;m.content&&(i+=m.content,o.textContent=i,e.scrollTop=e.scrollHeight)}}catch(n){console.debug("SSE数据解析跳过:",h)}}}return c()}t.addMessage("ai",i)})};return c()}).catch(function(n){console.error("流式接口调用失败:",n);var e="流式接口异常,请稍后再试~";"TypeError"===n.name&&n.message.includes("Failed to fetch")?e="网络连接失败,请检查网络连接或API地址配置~":n.message.includes("不是流式响应格式")?e="服务器不支持流式响应,请尝试关闭stream选项~":n.message.includes("无法获取响应流")&&(e="流式数据读取失败,请检查浏览器兼容性~"),o.textContent=e,t.addMessage("ai",e)})},n.prototype.showLoading=function(n){var e="loading-"+Date.now(),t=document.createElement("div");return t.className="ai-agent-msg ai-agent-msg-ai ai-agent-loading",t.id=e,t.innerHTML='\n <div class="ai-agent-msg-content">\n <div class="ai-agent-loading-dots">\n <span></span><span></span><span></span>\n </div>\n </div>\n ',n.appendChild(t),n.scrollTop=n.scrollHeight,e},n.prototype.removeLoading=function(n){var e=document.getElementById(n);e&&e.parentNode&&e.parentNode.removeChild(e)},n.prototype.addMessage=function(n,e){this.chatHistory.push({role:n,content:e}),this.chatHistory.length>20&&this.chatHistory.shift()},n.prototype.createMessageEl=function(n,e){var t=document.createElement("div");t.className="ai-agent-msg ai-agent-msg-".concat(n);var a=e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/\n/g,"<br>");return t.innerHTML='<div class="ai-agent-msg-content">'.concat(a,"</div>"),t},n.prototype.destroy=function(){this.buttonEl&&this.buttonEl.parentNode&&(this.buttonEl.parentNode.removeChild(this.buttonEl),this.buttonEl=null),this.panelEl&&this.panelEl.parentNode&&(this.panelEl.parentNode.removeChild(this.panelEl),this.panelEl=null);var n=document.querySelector("style[ai-agent-dynamic-styles]");n&&n.parentNode&&n.parentNode.removeChild(n),this.chatHistory=[]},n.DEFAULT_HOST="http://localhost:8080",n}();const y=x;return a=a.default})());
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AIAgent - 跨框架通用的AI对话助手插件
|
|
3
|
+
* 支持Vue、React、jQuery等多种框架
|
|
4
|
+
* 采用TypeScript + UMD模块化规范实现
|
|
5
|
+
*/
|
|
6
|
+
import './styles/ai-agent.css';
|
|
7
|
+
import { AIAgentOptions } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* AIAgent类 - 插件的主类
|
|
10
|
+
*/
|
|
11
|
+
declare class AIAgent {
|
|
12
|
+
/**
|
|
13
|
+
* 配置选项
|
|
14
|
+
*/
|
|
15
|
+
private options;
|
|
16
|
+
private static DEFAULT_HOST;
|
|
17
|
+
private endpoints;
|
|
18
|
+
/**
|
|
19
|
+
* 对话历史记录
|
|
20
|
+
*/
|
|
21
|
+
private chatHistory;
|
|
22
|
+
/**
|
|
23
|
+
* 面板是否展开
|
|
24
|
+
*/
|
|
25
|
+
private isOpen;
|
|
26
|
+
/**
|
|
27
|
+
* 对话面板DOM元素
|
|
28
|
+
*/
|
|
29
|
+
private panelEl;
|
|
30
|
+
/**
|
|
31
|
+
* 触发按钮DOM元素
|
|
32
|
+
*/
|
|
33
|
+
private buttonEl;
|
|
34
|
+
/**
|
|
35
|
+
* 创建AIAgent实例
|
|
36
|
+
* @param options 配置选项
|
|
37
|
+
*/
|
|
38
|
+
constructor(options?: AIAgentOptions);
|
|
39
|
+
/**
|
|
40
|
+
* 初始化插件
|
|
41
|
+
* 创建界面、绑定事件
|
|
42
|
+
*/
|
|
43
|
+
private init;
|
|
44
|
+
/**
|
|
45
|
+
* 创建悬浮触发按钮
|
|
46
|
+
*/
|
|
47
|
+
private createTriggerButton;
|
|
48
|
+
/**
|
|
49
|
+
* 创建对话面板
|
|
50
|
+
*/
|
|
51
|
+
private createChatPanel;
|
|
52
|
+
/**
|
|
53
|
+
* 注入样式(避免与宿主项目冲突)
|
|
54
|
+
* 为了确保代码的模块化,样式已移至单独的CSS文件
|
|
55
|
+
* 但此方法保留,便于动态注入特定样式
|
|
56
|
+
*/
|
|
57
|
+
private injectStyles;
|
|
58
|
+
/**
|
|
59
|
+
* 切换面板显示/隐藏
|
|
60
|
+
*/
|
|
61
|
+
togglePanel(): void;
|
|
62
|
+
/**
|
|
63
|
+
* 关闭面板
|
|
64
|
+
*/
|
|
65
|
+
closePanel(): void;
|
|
66
|
+
/**
|
|
67
|
+
* 发送消息到后端 AI 接口
|
|
68
|
+
* @param text 用户输入的消息文本
|
|
69
|
+
*/
|
|
70
|
+
sendMessage(text: string): void;
|
|
71
|
+
/**
|
|
72
|
+
* 发送普通模式消息
|
|
73
|
+
* @param text 用户消息
|
|
74
|
+
* @param messagesEl 消息容器
|
|
75
|
+
*/
|
|
76
|
+
private sendNormalMessage;
|
|
77
|
+
/**
|
|
78
|
+
* 发送流式模式消息
|
|
79
|
+
* @param text 用户消息
|
|
80
|
+
* @param messagesEl 消息容器
|
|
81
|
+
*/
|
|
82
|
+
private sendStreamMessage;
|
|
83
|
+
/**
|
|
84
|
+
* 显示加载中状态
|
|
85
|
+
* @param messagesEl 消息容器元素
|
|
86
|
+
* @returns 加载状态的唯一ID
|
|
87
|
+
*/
|
|
88
|
+
private showLoading;
|
|
89
|
+
/**
|
|
90
|
+
* 移除加载中状态
|
|
91
|
+
* @param loadingId 加载状态的唯一ID
|
|
92
|
+
*/
|
|
93
|
+
private removeLoading;
|
|
94
|
+
/**
|
|
95
|
+
* 添加消息到历史记录
|
|
96
|
+
* @param role 角色:'user' 或 'ai'
|
|
97
|
+
* @param content 消息内容
|
|
98
|
+
*/
|
|
99
|
+
private addMessage;
|
|
100
|
+
/**
|
|
101
|
+
* 创建消息 DOM 元素
|
|
102
|
+
* @param role 角色:'user' 或 'ai'
|
|
103
|
+
* @param content 消息内容
|
|
104
|
+
* @returns 消息DOM元素
|
|
105
|
+
*/
|
|
106
|
+
private createMessageEl;
|
|
107
|
+
/**
|
|
108
|
+
* 销毁插件(清理 DOM 和事件)
|
|
109
|
+
*/
|
|
110
|
+
destroy(): void;
|
|
111
|
+
}
|
|
112
|
+
export default AIAgent;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Agent 插件的配置选项接口
|
|
3
|
+
*/
|
|
4
|
+
export interface AIAgentOptions {
|
|
5
|
+
/**
|
|
6
|
+
* 后端站点域名或基础地址,例如 https://example.com 或 http://localhost:8080
|
|
7
|
+
* 插件会在该 host 下拼接 /ai/chat/completion 或 /ai/chat/stream
|
|
8
|
+
* @default '' (使用内置本地回退)
|
|
9
|
+
*/
|
|
10
|
+
host?: string;
|
|
11
|
+
/**
|
|
12
|
+
* API 密钥/令牌
|
|
13
|
+
* @required true
|
|
14
|
+
*/
|
|
15
|
+
secret?: string;
|
|
16
|
+
/**
|
|
17
|
+
* 是否启用流式响应
|
|
18
|
+
* @default false
|
|
19
|
+
*/
|
|
20
|
+
stream?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* 主题:light / dark
|
|
23
|
+
* @default 'light'
|
|
24
|
+
*/
|
|
25
|
+
theme?: 'light' | 'dark';
|
|
26
|
+
/**
|
|
27
|
+
* 自定义主题色值配置
|
|
28
|
+
*/
|
|
29
|
+
colors?: {
|
|
30
|
+
/**
|
|
31
|
+
* 主色调 (按钮、用户消息气泡等)
|
|
32
|
+
* @default '#4096ff'
|
|
33
|
+
*/
|
|
34
|
+
primary?: string;
|
|
35
|
+
/**
|
|
36
|
+
* 主色调悬停态
|
|
37
|
+
* @default '#2e80ff'
|
|
38
|
+
*/
|
|
39
|
+
primaryHover?: string;
|
|
40
|
+
/**
|
|
41
|
+
* 背景色
|
|
42
|
+
* @default 浅色主题: '#ffffff', 深色主题: '#1e1e1e'
|
|
43
|
+
*/
|
|
44
|
+
background?: string;
|
|
45
|
+
/**
|
|
46
|
+
* 文本颜色
|
|
47
|
+
* @default 浅色主题: '#333333', 深色主题: '#f0f0f0'
|
|
48
|
+
*/
|
|
49
|
+
text?: string;
|
|
50
|
+
/**
|
|
51
|
+
* 边框颜色
|
|
52
|
+
* @default 浅色主题: '#eeeeee', 深色主题: '#3c3c3c'
|
|
53
|
+
*/
|
|
54
|
+
border?: string;
|
|
55
|
+
/**
|
|
56
|
+
* AI 消息气泡背景色
|
|
57
|
+
* @default 浅色主题: '#f5f5f5', 深色主题: '#3c3c3c'
|
|
58
|
+
*/
|
|
59
|
+
aiMessageBg?: string;
|
|
60
|
+
/**
|
|
61
|
+
* 用户消息气泡背景色 (通常使用主色调)
|
|
62
|
+
* @default 与 primary 相同
|
|
63
|
+
*/
|
|
64
|
+
userMessageBg?: string;
|
|
65
|
+
/**
|
|
66
|
+
* 头部背景色
|
|
67
|
+
* @default 浅色主题: '#f5f5f5', 深色主题: '#2c2c2c'
|
|
68
|
+
*/
|
|
69
|
+
headerBg?: string;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* 位置:bottom-left/right, top-left/right
|
|
73
|
+
* @default 'bottom-right'
|
|
74
|
+
*/
|
|
75
|
+
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
76
|
+
/**
|
|
77
|
+
* 输入框占位文本
|
|
78
|
+
* @default '请输入问题...'
|
|
79
|
+
*/
|
|
80
|
+
placeholder?: string;
|
|
81
|
+
/**
|
|
82
|
+
* 面板标题
|
|
83
|
+
* @default 'AI 助手'
|
|
84
|
+
*/
|
|
85
|
+
title?: string;
|
|
86
|
+
/**
|
|
87
|
+
* 其他自定义选项
|
|
88
|
+
*/
|
|
89
|
+
[key: string]: any;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 聊天消息接口
|
|
93
|
+
*/
|
|
94
|
+
export interface ChatMessage {
|
|
95
|
+
/**
|
|
96
|
+
* 消息发送角色:'user' 或 'ai'
|
|
97
|
+
*/
|
|
98
|
+
role: 'user' | 'ai';
|
|
99
|
+
/**
|
|
100
|
+
* 消息内容
|
|
101
|
+
*/
|
|
102
|
+
content: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* API响应接口(普通模式)
|
|
106
|
+
*/
|
|
107
|
+
export interface ApiResponse {
|
|
108
|
+
code: number;
|
|
109
|
+
data: {
|
|
110
|
+
choices: Array<{
|
|
111
|
+
message: {
|
|
112
|
+
content: string;
|
|
113
|
+
role: string;
|
|
114
|
+
};
|
|
115
|
+
}>;
|
|
116
|
+
};
|
|
117
|
+
msg: string;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 流式响应数据块接口
|
|
121
|
+
*/
|
|
122
|
+
export interface StreamChunk {
|
|
123
|
+
id: string;
|
|
124
|
+
object: string;
|
|
125
|
+
created: number;
|
|
126
|
+
model: string;
|
|
127
|
+
choices: Array<{
|
|
128
|
+
index: number;
|
|
129
|
+
delta: {
|
|
130
|
+
role?: string;
|
|
131
|
+
content?: string;
|
|
132
|
+
};
|
|
133
|
+
finish_reason?: string;
|
|
134
|
+
usage?: {
|
|
135
|
+
prompt_tokens: number;
|
|
136
|
+
completion_tokens: number;
|
|
137
|
+
total_tokens: number;
|
|
138
|
+
};
|
|
139
|
+
}>;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 流式请求体接口
|
|
143
|
+
*/
|
|
144
|
+
export interface StreamRequest {
|
|
145
|
+
messages: ChatMessage[];
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 简单请求体接口
|
|
149
|
+
*/
|
|
150
|
+
export interface SimpleRequest {
|
|
151
|
+
content: string;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* 位置样式映射类型
|
|
155
|
+
*/
|
|
156
|
+
export type PositionStyleKey = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
157
|
+
export type PositionStyles = {
|
|
158
|
+
[key in PositionStyleKey]: {
|
|
159
|
+
[cssProperty: string]: string;
|
|
160
|
+
};
|
|
161
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ai-agent-plugin",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "跨框架通用的AI Agent前端插件",
|
|
5
|
+
"main": "dist/ai-agent.js",
|
|
6
|
+
"module": "dist/ai-agent.esm.js",
|
|
7
|
+
"types": "dist/types/ai-agent.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist/",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "webpack --mode=production",
|
|
15
|
+
"dev": "webpack serve --mode=development --watch",
|
|
16
|
+
"serve": "webpack serve --mode=development --open",
|
|
17
|
+
"test": "jest",
|
|
18
|
+
"test:watch": "jest --watch",
|
|
19
|
+
"test:coverage": "jest --coverage"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"ai",
|
|
23
|
+
"agent",
|
|
24
|
+
"chatbot",
|
|
25
|
+
"umd",
|
|
26
|
+
"cross-framework",
|
|
27
|
+
"typescript",
|
|
28
|
+
"vue",
|
|
29
|
+
"react",
|
|
30
|
+
"jquery"
|
|
31
|
+
],
|
|
32
|
+
"author": "hujinbin",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"homepage": "https://github.com/hujinbin/ai-agent",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/hujinbin/ai-agent.git"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/hujinbin/ai-agent/issues"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@babel/core": "^7.28.4",
|
|
44
|
+
"@babel/preset-env": "^7.28.3",
|
|
45
|
+
"@testing-library/dom": "^10.4.1",
|
|
46
|
+
"@types/jest": "^30.0.0",
|
|
47
|
+
"@types/jsdom": "^27.0.0",
|
|
48
|
+
"babel-loader": "^9.2.1",
|
|
49
|
+
"css-loader": "^6.8.1",
|
|
50
|
+
"html-webpack-plugin": "^5.6.4",
|
|
51
|
+
"jest": "^29.7.0",
|
|
52
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
53
|
+
"jsdom": "^27.0.1",
|
|
54
|
+
"style-loader": "^3.3.3",
|
|
55
|
+
"terser-webpack-plugin": "^5.3.9",
|
|
56
|
+
"ts-jest": "^29.4.6",
|
|
57
|
+
"ts-loader": "^9.5.4",
|
|
58
|
+
"typescript": "^5.9.2",
|
|
59
|
+
"webpack": "^5.88.0",
|
|
60
|
+
"webpack-cli": "^5.1.4",
|
|
61
|
+
"webpack-dev-server": "^5.2.2"
|
|
62
|
+
}
|
|
63
|
+
}
|