ai-chat-embed 0.1.0
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 +302 -0
- package/dist/ai-chat-embed.min.js +1 -0
- package/package.json +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 zhoumingle
|
|
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,302 @@
|
|
|
1
|
+
# ai-chat-embed(AI助手组件)
|
|
2
|
+
|
|
3
|
+
将 AI-Chat 聊天组件球嵌入任意网站,**只需一行 `<script>`,无需依赖任何框架、无需构建工具**。
|
|
4
|
+
|
|
5
|
+
## 跨框架接入(核心特性)
|
|
6
|
+
|
|
7
|
+
`ai-chat-embed` 的核心目标就是 **跨框架、跨技术栈**:
|
|
8
|
+
|
|
9
|
+
- React / Next.js / Vue / Angular / Svelte
|
|
10
|
+
- 原生 HTML / 传统多页(JSP、PHP、Rails 模板)
|
|
11
|
+
- jQuery、低代码平台、自定义脚本区块
|
|
12
|
+
|
|
13
|
+
你无需把业务项目改造成 Vue3,只要页面能插入 `<script>` 即可接入。
|
|
14
|
+
|
|
15
|
+
> 本包基于 [ai-suspended-ball-chat](https://www.npmjs.com/package/ai-suspended-ball-chat) 封装,将其能力扩展到任意前端技术栈。
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
**《组件落地场景体验1-AI简历助手》**: [点击直达案例1🔗](https://luckycola.com.cn/public/resume/?t=123456789#/resume)
|
|
20
|
+
|
|
21
|
+
**《组件落地场景体验2-AI编程助手》**: [点击直达案例2🔗](https://luckycola.com.cn/public/dist/onlineCodeEditor.html?t=123456789#/editor)
|
|
22
|
+
|
|
23
|
+
> **🔔 温馨提示:** 如果您觉得阅读文档困难,也可以选择咨询*在线AI助手*: [🤖点击直达咨询→](https://luckycola.com.cn/public/dist/aiAgent.html?openChat=1&t=123456789#/)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## ✨ 特性
|
|
28
|
+
|
|
29
|
+
- 🚀 **即插即用**:只需 `<script>` + `AIChatEmbed.init()` 即可挂载
|
|
30
|
+
- 🧩 **跨框架接入**:React / Vue / Angular / jQuery / 原生 HTML 通用
|
|
31
|
+
- 🪄 **双模式渲染**:支持 `ball` 悬浮球模式与 `panel` 内嵌面板模式
|
|
32
|
+
- 🔁 **实例化调用**:`const chat = await init()` 后可 `sendMessage / update / destroy`
|
|
33
|
+
- 📡 **加载生命周期回调**:支持 `onEmbedLoading / onEmbedReady / onEmbedError`
|
|
34
|
+
- 🧱 **资源自动加载**:自动拉取 Vue、lodash、组件 UMD(支持自定义 CDN 地址)
|
|
35
|
+
- 🧠 **能力透传**:原组件方法可通过实例动态透传,减少封装层跟随升级成本
|
|
36
|
+
|
|
37
|
+
> 说明:本包重点解决“跨技术栈嵌入与生命周期管理”,具体 AI 业务能力(流式、语音、图片上传、历史记录等)由底层 `ai-suspended-ball-chat` 提供并透传。
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 一、两种模式
|
|
42
|
+
|
|
43
|
+
### 悬浮球模式(默认)
|
|
44
|
+
|
|
45
|
+
页面右侧出现可拖拽的悬浮球,点击弹出聊天面板,适合全站挂载。
|
|
46
|
+
|
|
47
|
+
```html
|
|
48
|
+
<script src="https://unpkg.com/ai-chat-embed/dist/ai-chat-embed.min.js"></script>
|
|
49
|
+
<script>
|
|
50
|
+
AIChatEmbed.init({
|
|
51
|
+
url: "https://your-api-endpoint.com/chat",
|
|
52
|
+
appName: "my-app",
|
|
53
|
+
domainName: "user123",
|
|
54
|
+
enableStreaming: true
|
|
55
|
+
});
|
|
56
|
+
// mode 默认为 "ball",可省略
|
|
57
|
+
</script>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 面板模式
|
|
61
|
+
|
|
62
|
+
ChatPanel 内嵌在指定容器中,适合嵌入页面某个固定区域(如侧边栏、弹窗内)。
|
|
63
|
+
|
|
64
|
+
```html
|
|
65
|
+
<div id="my-chat-area" style="width:400px;height:600px;"></div>
|
|
66
|
+
|
|
67
|
+
<script src="https://unpkg.com/ai-chat-embed/dist/ai-chat-embed.min.js"></script>
|
|
68
|
+
<script>
|
|
69
|
+
AIChatEmbed.init({
|
|
70
|
+
mode: "panel",
|
|
71
|
+
mountTo: "#my-chat-area",
|
|
72
|
+
url: "https://your-api-endpoint.com/chat",
|
|
73
|
+
appName: "my-app",
|
|
74
|
+
domainName: "user123",
|
|
75
|
+
enableStreaming: true,
|
|
76
|
+
showCloseButton: false
|
|
77
|
+
});
|
|
78
|
+
</script>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## 二、多技术栈接入示例
|
|
82
|
+
|
|
83
|
+
### React(useEffect)
|
|
84
|
+
|
|
85
|
+
```jsx
|
|
86
|
+
import { useEffect } from "react";
|
|
87
|
+
|
|
88
|
+
export default function Page() {
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
let chat;
|
|
91
|
+
const boot = async () => {
|
|
92
|
+
chat = await window.AIChatEmbed.init({
|
|
93
|
+
url: "https://your-api-endpoint.com/chat",
|
|
94
|
+
appName: "react-app",
|
|
95
|
+
domainName: "react-user",
|
|
96
|
+
mode: "ball"
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
boot();
|
|
100
|
+
|
|
101
|
+
return () => {
|
|
102
|
+
chat?.destroy();
|
|
103
|
+
};
|
|
104
|
+
}, []);
|
|
105
|
+
|
|
106
|
+
return <div>My React Page</div>;
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
> 前提:页面已通过 `<script src=\"https://unpkg.com/ai-chat-embed/dist/ai-chat-embed.min.js\"></script>` 加载 SDK。
|
|
111
|
+
|
|
112
|
+
### 原生 HTML
|
|
113
|
+
|
|
114
|
+
```html
|
|
115
|
+
<script src="https://unpkg.com/ai-chat-embed/dist/ai-chat-embed.min.js"></script>
|
|
116
|
+
<script>
|
|
117
|
+
(async function () {
|
|
118
|
+
const chat = await AIChatEmbed.init({
|
|
119
|
+
url: "https://your-api-endpoint.com/chat",
|
|
120
|
+
appName: "native-page",
|
|
121
|
+
domainName: "user-001",
|
|
122
|
+
mode: "ball"
|
|
123
|
+
});
|
|
124
|
+
// 主动发一条欢迎消息
|
|
125
|
+
chat.sendMessage("你好,介绍一下你的能力");
|
|
126
|
+
})();
|
|
127
|
+
</script>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### jQuery 页面
|
|
131
|
+
|
|
132
|
+
```html
|
|
133
|
+
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
|
134
|
+
<script src="https://unpkg.com/ai-chat-embed/dist/ai-chat-embed.min.js"></script>
|
|
135
|
+
<script>
|
|
136
|
+
$(async function () {
|
|
137
|
+
const chat = await AIChatEmbed.init({
|
|
138
|
+
url: "https://your-api-endpoint.com/chat",
|
|
139
|
+
appName: "jquery-app",
|
|
140
|
+
domainName: "jquery-user",
|
|
141
|
+
mode: "panel",
|
|
142
|
+
mountTo: "#chat-container"
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
$("#send-btn").on("click", function () {
|
|
146
|
+
chat.sendMessage($("#msg").val());
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
</script>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Vue 2 (Options API)
|
|
153
|
+
|
|
154
|
+
```vue
|
|
155
|
+
<template>
|
|
156
|
+
<div>My Vue 2 Page</div>
|
|
157
|
+
</template>
|
|
158
|
+
|
|
159
|
+
<script>
|
|
160
|
+
export default {
|
|
161
|
+
data() {
|
|
162
|
+
return {
|
|
163
|
+
chat: null
|
|
164
|
+
};
|
|
165
|
+
},
|
|
166
|
+
async mounted() {
|
|
167
|
+
this.chat = await window.AIChatEmbed.init({
|
|
168
|
+
url: "https://your-api-endpoint.com/chat",
|
|
169
|
+
appName: "vue2-app",
|
|
170
|
+
domainName: "vue2-user",
|
|
171
|
+
mode: "ball"
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
beforeDestroy() {
|
|
175
|
+
this.chat?.destroy();
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
</script>
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
> 前提:页面已通过 `<script src="https://unpkg.com/ai-chat-embed/dist/ai-chat-embed.min.js"></script>` 加载 SDK。
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
## 三、API
|
|
185
|
+
|
|
186
|
+
### `AIChatEmbed.init(options)`
|
|
187
|
+
|
|
188
|
+
初始化并挂载组件,返回 Promise。同一页面重复调用不会重复挂载。
|
|
189
|
+
|
|
190
|
+
```js
|
|
191
|
+
const chat = await AIChatEmbed.init({
|
|
192
|
+
url: "https://your-api-endpoint.com/chat",
|
|
193
|
+
appName: "my-app",
|
|
194
|
+
domainName: "user123",
|
|
195
|
+
enableStreaming: true,
|
|
196
|
+
callbacks: {
|
|
197
|
+
onUserMessage: (msg) => console.log("用户发送:", msg),
|
|
198
|
+
onAssistantMessage: (msg) => console.log("AI 回复:", msg),
|
|
199
|
+
onError: (err) => console.error("出错:", err)
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
可选:你可以在 `init` 传入封装层生命周期回调,处理首次 CDN 资源加载时的业务 loading:
|
|
205
|
+
|
|
206
|
+
```js
|
|
207
|
+
const chat = await AIChatEmbed.init({
|
|
208
|
+
// ...你的业务配置
|
|
209
|
+
onEmbedLoading: (loading, meta) => {
|
|
210
|
+
// loading=true 开始加载外部资源,false 结束
|
|
211
|
+
// meta: { mode, containerId }
|
|
212
|
+
},
|
|
213
|
+
onEmbedReady: (meta) => {
|
|
214
|
+
// 首次挂载完成后触发(含 elapsedMs)
|
|
215
|
+
},
|
|
216
|
+
onEmbedError: (error, meta) => {
|
|
217
|
+
// 资源加载失败或初始化失败时触发
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### `chat.update(options)`
|
|
223
|
+
|
|
224
|
+
通过实例动态更新组件配置(如切换标题、接口地址等),无需重新挂载。
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
chat.update({ title: "新的助手名称" });
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### 主动调用能力(关键入口)
|
|
231
|
+
|
|
232
|
+
初始化返回的实例可直接调用:
|
|
233
|
+
|
|
234
|
+
```js
|
|
235
|
+
const chat = await AIChatEmbed.init({ /* ... */ });
|
|
236
|
+
chat.sendMessage("你好,帮我总结今日工作");
|
|
237
|
+
chat.getChatState();
|
|
238
|
+
chat.stopRequest();
|
|
239
|
+
chat.clearHistory();
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
实例也支持通用调用和动态方法透传(便于对齐底层组件升级):
|
|
243
|
+
|
|
244
|
+
```js
|
|
245
|
+
chat.invoke("sendMessage", "你好");
|
|
246
|
+
// 如果底层组件存在 someNewMethod,会自动透传
|
|
247
|
+
chat.someNewMethod?.("arg1");
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### `chat.destroy()`
|
|
251
|
+
|
|
252
|
+
通过实例卸载并移除组件,彻底清理 DOM。
|
|
253
|
+
|
|
254
|
+
```js
|
|
255
|
+
chat.destroy();
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## 四、配置说明
|
|
259
|
+
|
|
260
|
+
以下参数由本包提供,用于控制资源加载和挂载行为:
|
|
261
|
+
|
|
262
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
263
|
+
| ------ | ------ | -------- | ------ |
|
|
264
|
+
| `mode` | `"ball"` \| `"panel"` | `"ball"` | 悬浮球模式或内嵌面板模式 |
|
|
265
|
+
| `mountTo` | string \| HTMLElement | `"body"` | 挂载目标,支持 CSS 选择器或元素引用 |
|
|
266
|
+
| `containerId` | string | `"ai-chat-embed-root"` / `"ai-chat-panel-root"` | 挂载容器的 `id`,ball/panel 模式各有默认值 |
|
|
267
|
+
| `vueUrl` | string | unpkg Vue3 CDN | 自定义 Vue3 全局构建地址 |
|
|
268
|
+
| `lodashUrl` | string | unpkg lodash CDN | 自定义 lodash 全局构建地址(需包含 `_.cloneDeep`) |
|
|
269
|
+
| `chatLibUrl` | string | unpkg 原组件 UMD 地址 | 自定义原组件 UMD 加载地址,可以按需按选择版本,默认‘正式版’ |
|
|
270
|
+
| `onEmbedLoading` | function | - | 封装层资源加载状态回调:`(loading, meta)` |
|
|
271
|
+
| `onEmbedReady` | function | - | 封装层初始化完成回调:`(meta)` |
|
|
272
|
+
| `onEmbedError` | function | - | 封装层初始化失败回调:`(error, meta)` |
|
|
273
|
+
|
|
274
|
+
> 其余所有配置(`url`、`appName`、`domainName`、`title`、`callbacks`、`enableStreaming` 等)会直接透传给底层 `SuspendedBallChat` 组件。完整配置参考原包文档:[ai-suspended-ball-chat](https://www.npmjs.com/package/ai-suspended-ball-chat)
|
|
275
|
+
|
|
276
|
+
## 五、适用场景
|
|
277
|
+
|
|
278
|
+
- 营销页、活动页快速集成 AI 客服
|
|
279
|
+
- React / Angular / Svelte 等非 Vue 项目
|
|
280
|
+
- 传统 JSP、PHP 等多页应用
|
|
281
|
+
- 低代码平台的自定义 HTML 区块
|
|
282
|
+
|
|
283
|
+
## 六、高级扩展能力支持
|
|
284
|
+
- 如需支持 Mermaid 渲染,请在页面中提前引入:`https://unpkg.com/mermaid@11.10.1/dist/mermaid.min.js`
|
|
285
|
+
- 如需支持 ECharts 渲染,请在页面中提前引入:`https://unpkg.com/echarts@5.0.0/dist/echarts.min.js`
|
|
286
|
+
|
|
287
|
+
## 七、chatLibUrl版本
|
|
288
|
+
- 正式版本: https://unpkg.com/ai-suspended-ball-chat@latest/dist/suspended-ball-chat.umd.js
|
|
289
|
+
- alpha版本: https://unpkg.com/ai-suspended-ball-chat@0.3.61-alpha.1/dist/suspended-ball-chat.umd.js
|
|
290
|
+
- beta版本: https://unpkg.com/ai-suspended-ball-chat@0.3.61-beta.1/dist/suspended-ball-chat.umd.js
|
|
291
|
+
|
|
292
|
+
### Q: 不同版本功能上是否有差异?
|
|
293
|
+
|
|
294
|
+
A: 是的,当前有三个版本: 正式版、beta版本、alpha版本。他们的差异如下:
|
|
295
|
+
|
|
296
|
+
- **正式版**: 稳定版,功能最新且齐全,但此版本不支持“**独立协议的深度思考模式**”,但是你可以通过后端将“思考内容”用`<details><summary >`包裹间接实现这个功能.
|
|
297
|
+
|
|
298
|
+
- **beta版本**: 这是一个差异版本,对齐正式版90%的功能,支持“**独立协议的深度思考模式**”,但是此版本不支持“渲染自定义组件”等功能。
|
|
299
|
+
|
|
300
|
+
- **alpha版本**: 这是一个实验版本, 对齐正式版100%的功能, 唯一的差异是此版本已经将“对话列表虚拟化”了以提升性能,此版本和主版本一样不支持“**独立协议的深度思考模式**”, 可能存在一些未知Bug,谨慎使用.
|
|
301
|
+
|
|
302
|
+
**总结: 根据您的需求选择需要的版本, 无特殊需求建议使用正式版。**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var AIChatEmbed=(()=>{var A=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var $=Object.prototype.hasOwnProperty;var F=(e,t)=>{for(var o in t)A(e,o,{get:t[o],enumerable:!0})},T=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of R(t))!$.call(e,r)&&r!==o&&A(e,r,{get:()=>t[r],enumerable:!(n=D(t,r))||n.enumerable});return e};var _=e=>T(A({},"__esModule",{value:!0}),e);var Q={};F(Q,{default:()=>J,init:()=>V});var v={vueUrl:"https://unpkg.com/vue@3/dist/vue.global.prod.js",lodashUrl:"https://unpkg.com/lodash@4.17.21/lodash.min.js",chatLibUrl:"https://unpkg.com/ai-suspended-ball-chat/dist/suspended-ball-chat.umd.js",mode:"ball",mountTo:"body",containerId:"ai-chat-embed-root"},u={},f=null,l=new Map,y=new Map;function h(e,...t){if(typeof e=="function")try{e(...t)}catch{}}function H(){if(typeof window>"u"||typeof document>"u")throw new Error("AIChatEmbed can only run in browser environments.")}function S(e,t){if(typeof t=="function"&&t())return Promise.resolve();if(l.has(e))return l.get(e);let o=document.querySelector(`script[data-ai-chat-embed-src="${e}"]`);if(o){let r=o.getAttribute("data-ai-chat-embed-loaded"),d=o.getAttribute("data-ai-chat-embed-error");if(r==="1"){let a=Promise.resolve();return l.set(e,a),a}if(d==="1")o.remove();else{let a=new Promise((E,c)=>{o.addEventListener("load",()=>E(),{once:!0}),o.addEventListener("error",()=>{o.setAttribute("data-ai-chat-embed-error","1"),c(new Error(`Failed loading script: ${e}`))},{once:!0})});return a.catch(()=>{l.delete(e)}),l.set(e,a),a}}let n=new Promise((r,d)=>{let a=document.createElement("script");a.src=e,a.async=!0,a.setAttribute("data-ai-chat-embed-src",e),a.onload=()=>{a.setAttribute("data-ai-chat-embed-loaded","1"),r()},a.onerror=()=>{a.setAttribute("data-ai-chat-embed-error","1"),d(new Error(`Failed loading script: ${e}`))},document.head.appendChild(a)});return n.catch(()=>{l.delete(e)}),l.set(e,n),n}function I(e){let t=[window.SuspendedBallChat,window.suspendedBallChat,window.AISuspendedBallChat,window.aiSuspendedBallChat,window.AiSuspendedBallChat,window.AI_SUSPENDED_BALL_CHAT,window["ai-suspended-ball-chat"]];for(let o of t)if(o&&o.SuspendedBallChat)return o;for(let o of e){let n=window[o];if(n&&typeof n=="object"&&n.SuspendedBallChat)return n}return null}function K(){window.Vue&&(typeof window.Vue.component!="function"&&(window.Vue.component=function(){return this}),typeof window.Vue.extend!="function"&&(window.Vue.extend=function(t){return function(n){return{...t,props:n}}}),typeof window.Vue.set!="function"&&(window.Vue.set=function(t,o,n){return t[o]=n,n}),typeof window.Vue.delete!="function"&&(window.Vue.delete=function(t,o){delete t[o]}))}async function q(e){return f||(f=(async()=>{await S(e.vueUrl,()=>!!(window.Vue&&window.Vue.createApp)),await S(e.lodashUrl,()=>!!(window._&&typeof window._.cloneDeep=="function")),K();let t=new Set(Object.keys(window));await S(e.chatLibUrl,()=>!!I([]));let o=Object.keys(window).filter(d=>!t.has(d)),n=window.Vue;if(!n||!n.createApp||!n.h||!n.reactive||!n.ref)throw new Error("Vue 3 runtime not found after loading script.");let r=I(o)||I([]);if(!r||!r.SuspendedBallChat)throw new Error("Cannot find SuspendedBallChat export from ai-suspended-ball-chat.");if(!r.ChatPanel)throw new Error("Cannot find ChatPanel export from ai-suspended-ball-chat.");return{vue:n,chatLib:r}})().catch(t=>{throw f=null,t}),f)}function N(e){if(!e||e==="body")return document.body;if(typeof e=="string"){let t=document.querySelector(e);if(!t)throw new Error(`mountTo selector not found: ${e}`);return t}if(e instanceof HTMLElement)return e;throw new Error("mountTo must be a CSS selector, HTMLElement, or 'body'.")}function z(e){let t=N(e.mountTo),o=e.containerId,n=document.getElementById(o),r=!1;return n?n.parentNode||t.appendChild(n):(n=document.createElement("div"),n.id=o,t.appendChild(n),r=!0),{container:n,createdContainer:r}}function B(e){let t={...e};return delete t.vueUrl,delete t.lodashUrl,delete t.chatLibUrl,delete t.mode,delete t.mountTo,delete t.containerId,delete t.onEmbedLoading,delete t.onEmbedReady,delete t.onEmbedError,t}async function V(e={}){H();let t=e.mode||v.mode;if(t!=="ball"&&t!=="panel")throw new Error(`Invalid mode "${t}". Use "ball" or "panel".`);let o=t==="panel"?"ai-chat-panel-root":v.containerId,n={...v,containerId:o,...e,mode:t},r=n.containerId,d={mode:t,containerId:n.containerId};if(u[r])return h(e.onEmbedReady,d),u[r].publicApi;if(y.has(r))return y.get(r);let a=(async()=>{let E=Date.now();h(e.onEmbedLoading,!0,d);try{let k=function(i,...s){let p=g.value;if(!p||typeof p[i]!="function")throw new Error(`Method "${i}" is unavailable before component ready.`);return p[i](...s)},{vue:c,chatLib:m}=await q(n),{container:w,createdContainer:P}=z(n),C=c.reactive(B(e)),g=c.ref(null),x=t==="panel"?m.ChatPanel:m.SuspendedBallChat,b=c.createApp({name:"AIChatEmbedRoot",render(){return c.h(x,{...C,ref:g})}});typeof m.install=="function"&&b.use(m),b.mount(w);let M={update(i={}){if(!u[r])throw new Error("Instance already destroyed.");Object.assign(C,B(i))},destroy(){u[r]&&(b.unmount(),P&&w.parentNode&&w.parentNode.removeChild(w),delete u[r],Object.keys(u).length===0&&(f=null,l.clear()))},invoke(i,...s){return k(i,...s)}},L=new Proxy(M,{get(i,s,p){if(Reflect.has(i,s))return Reflect.get(i,s,p);if(typeof s=="string"&&!["then","catch","finally"].includes(s))return(...j)=>i.invoke(s,...j)}});return u[r]={app:b,componentProps:C,componentRef:g,container:w,createdContainer:P,publicApi:L},h(e.onEmbedReady,{...d,elapsedMs:Date.now()-E}),L}catch(c){throw h(e.onEmbedError,c,d),c}finally{h(e.onEmbedLoading,!1,d),y.delete(r)}})();return y.set(r,a),a}var G={init:V},U=G;typeof window<"u"&&(window.AIChatEmbed=U);var J=U;return _(Q);})();
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ai-chat-embed",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Framework-agnostic embed wrapper for ai-suspended-ball-chat",
|
|
6
|
+
"main": "dist/ai-chat-embed.min.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"default": "./dist/ai-chat-embed.min.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"clean": "rimraf dist",
|
|
21
|
+
"dev": "concurrently -k \"npm:build:watch\" \"npm:serve\" \"npm:mock\"",
|
|
22
|
+
"dev:web": "concurrently -k \"npm:build:watch\" \"npm:serve\"",
|
|
23
|
+
"serve": "serve . -l 5173",
|
|
24
|
+
"mock": "node mock/server.js",
|
|
25
|
+
"build": "esbuild src/ai-chat-embed.js --bundle --format=iife --global-name=AIChatEmbed --minify --outfile=dist/ai-chat-embed.min.js",
|
|
26
|
+
"build:dev": "esbuild src/ai-chat-embed.js --bundle --format=iife --global-name=AIChatEmbed --sourcemap --outfile=dist/ai-chat-embed.js",
|
|
27
|
+
"build:watch": "esbuild src/ai-chat-embed.js --bundle --format=iife --global-name=AIChatEmbed --sourcemap --outfile=dist/ai-chat-embed.js --watch",
|
|
28
|
+
"test": "vitest run --environment jsdom",
|
|
29
|
+
"test:watch": "vitest --environment jsdom",
|
|
30
|
+
"test:coverage": "vitest run --environment jsdom --coverage",
|
|
31
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
35
|
+
"concurrently": "^9.2.1",
|
|
36
|
+
"cors": "^2.8.5",
|
|
37
|
+
"jsdom": "^24.1.3",
|
|
38
|
+
"express": "^4.21.2",
|
|
39
|
+
"rimraf": "^6.0.1",
|
|
40
|
+
"serve": "^14.2.5",
|
|
41
|
+
"esbuild": "^0.27.0",
|
|
42
|
+
"vitest": "^3.2.4"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"ai",
|
|
46
|
+
"chat",
|
|
47
|
+
"embed",
|
|
48
|
+
"widget",
|
|
49
|
+
"vue3",
|
|
50
|
+
"react",
|
|
51
|
+
"angular",
|
|
52
|
+
"jquery",
|
|
53
|
+
"jsp",
|
|
54
|
+
"php",
|
|
55
|
+
"html",
|
|
56
|
+
"css",
|
|
57
|
+
"javascript",
|
|
58
|
+
"typescript",
|
|
59
|
+
"framework-agnostic",
|
|
60
|
+
"mermaid",
|
|
61
|
+
"echarts"
|
|
62
|
+
],
|
|
63
|
+
"license": "MIT",
|
|
64
|
+
"author": "ai-chat-embed team",
|
|
65
|
+
"repository": {
|
|
66
|
+
"type": "git",
|
|
67
|
+
"url": "https://github.com/mingle98/ai-chat-embed.git"
|
|
68
|
+
},
|
|
69
|
+
"bugs": {
|
|
70
|
+
"url": "https://github.com/mingle98/ai-chat-embed/issues"
|
|
71
|
+
},
|
|
72
|
+
"homepage": "https://github.com/mingle98/ai-chat-embed#readme"
|
|
73
|
+
}
|