@hlw-zbzs/ai 1.0.2 → 1.0.3

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/dist/index.mjs ADDED
@@ -0,0 +1,951 @@
1
+ var oe = Object.defineProperty;
2
+ var ie = (e, t, n) => t in e ? oe(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
3
+ var O = (e, t, n) => ie(e, typeof t != "symbol" ? t + "" : t, n);
4
+ import le from "openai";
5
+ import { defineStore as ae, storeToRefs as ce } from "pinia";
6
+ import { electronStorage as re, get as ue, toast as I, HlwSelect as de, HlwInput as G, HlwButton as R, useRefs as pe } from "@hlw-zbzs/vue";
7
+ import { ref as S, computed as A, defineComponent as D, openBlock as v, createElementBlock as h, createElementVNode as s, createVNode as _, unref as a, withCtx as H, createTextVNode as Y, toDisplayString as T, normalizeClass as P, isRef as me, onMounted as fe, Fragment as Z, renderList as ee, withModifiers as J, createCommentVNode as L, createBlock as j } from "vue";
8
+ import te from "primevue/tag";
9
+ import ve from "primevue/toggleswitch";
10
+ import { tools as se } from "@hlw-zbzs/core";
11
+ import ge from "primevue/slider";
12
+ import W from "primevue/inputnumber";
13
+ import he from "primevue/password";
14
+ const q = {
15
+ deepseek: {
16
+ type: "deepseek",
17
+ name: "DeepSeek",
18
+ tag: "超高性价比 / 深度思考",
19
+ enable: !0,
20
+ models: ["deepseek-chat", "deepseek-reasoner"],
21
+ model: "deepseek-chat",
22
+ apiUrl: "https://api.deepseek.com/v1",
23
+ website: "https://www.deepseek.com"
24
+ },
25
+ qwen: {
26
+ type: "qwen",
27
+ name: "通义千问",
28
+ tag: "阿里百炼 / 国产领先",
29
+ enable: !0,
30
+ models: ["qwen-max", "qwen-plus", "qwen-turbo", "qwen-long", "qwen2.5-72b-instruct"],
31
+ model: "qwen-plus",
32
+ apiUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
33
+ website: "https://tongyi.aliyun.com"
34
+ },
35
+ chatgpt: {
36
+ type: "chatgpt",
37
+ name: "ChatGPT",
38
+ tag: "OpenAI / 强大通用",
39
+ enable: !0,
40
+ models: ["gpt-4o", "gpt-4o-mini", "o1", "o3-mini", "gpt-4-turbo", "gpt-3.5-turbo"],
41
+ model: "gpt-4o-mini",
42
+ apiUrl: "https://api.openai.com/v1",
43
+ website: "https://openai.com"
44
+ },
45
+ zhipu: {
46
+ type: "zhipu",
47
+ name: "智谱 GLM",
48
+ tag: "清华基座 / 智能体",
49
+ enable: !0,
50
+ models: ["glm-4-plus", "glm-4-air", "glm-4-flash", "glm-4-long", "glm-zero-preview"],
51
+ model: "glm-4-flash",
52
+ apiUrl: "https://open.bigmodel.cn/api/paas/v4",
53
+ website: "https://www.zhipuai.cn"
54
+ },
55
+ doubao: {
56
+ type: "doubao",
57
+ name: "字节豆包",
58
+ tag: "火山引擎 / 低延迟",
59
+ enable: !0,
60
+ models: ["doubao-pro-32k", "doubao-lite-32k", "doubao-pro-128k"],
61
+ model: "doubao-pro-32k",
62
+ apiUrl: "https://ark.cn-beijing.volces.com/api/v3",
63
+ website: "https://www.doubao.com"
64
+ },
65
+ moonshot: {
66
+ type: "moonshot",
67
+ name: "Moonshot",
68
+ tag: "Kimi / 超长上下文",
69
+ enable: !0,
70
+ models: ["moonshot-v1-8k", "moonshot-v1-32k", "moonshot-v1-128k"],
71
+ model: "moonshot-v1-8k",
72
+ apiUrl: "https://api.moonshot.cn/v1",
73
+ website: "https://www.moonshot.cn"
74
+ },
75
+ claude: {
76
+ type: "claude",
77
+ name: "Claude",
78
+ tag: "Anthropic / 顶尖逻辑",
79
+ enable: !0,
80
+ models: ["claude-3-5-sonnet-20241022", "claude-3-5-haiku-20241022", "claude-3-opus-20240229"],
81
+ model: "claude-3-5-sonnet-20241022",
82
+ apiUrl: "https://api.anthropic.com/v1",
83
+ website: "https://claude.ai"
84
+ },
85
+ ollama: {
86
+ type: "ollama",
87
+ name: "Ollama",
88
+ tag: "本地私有 / 免密免Key",
89
+ free: !0,
90
+ enable: !0,
91
+ models: ["deepseek-r1", "llama3.3", "qwen2.5", "gemma2", "mistral"],
92
+ model: "deepseek-r1",
93
+ apiUrl: "http://localhost:11434/v1",
94
+ website: "https://ollama.com"
95
+ },
96
+ custom: {
97
+ type: "custom",
98
+ name: "自定义 API",
99
+ tag: "第三方中转 / 兼容协议",
100
+ enable: !0,
101
+ models: ["default"],
102
+ model: "default",
103
+ apiUrl: "https://api.openai.com/v1",
104
+ website: "https://openai.com"
105
+ }
106
+ }, F = Object.values(q);
107
+ function Dt(e) {
108
+ var t;
109
+ return ((t = q[e]) == null ? void 0 : t.name) || e;
110
+ }
111
+ class ne {
112
+ /**
113
+ * 构造函数项
114
+ * @param type 引擎类型名
115
+ * @param conf 配置项对象
116
+ */
117
+ constructor(t, n) {
118
+ O(this, "type");
119
+ O(this, "conf");
120
+ O(this, "client", null);
121
+ this.type = t, this.conf = { ...n }, this.init();
122
+ }
123
+ /**
124
+ * 初始化引擎
125
+ */
126
+ init() {
127
+ var i;
128
+ const t = (this.conf.url || "").trim().replace(/\/+$/, "") || ((i = q[this.type]) == null ? void 0 : i.apiUrl) || "https://api.openai.com/v1", n = (this.conf.key || "").trim() || "dummy-key";
129
+ this.client = new le({
130
+ baseURL: t,
131
+ apiKey: n,
132
+ dangerouslyAllowBrowser: !0
133
+ });
134
+ }
135
+ /**
136
+ * 保存配置项
137
+ * @param conf 目标配置项
138
+ */
139
+ save(t) {
140
+ Object.assign(this.conf, t), this.init();
141
+ }
142
+ /**
143
+ * 构建消息列
144
+ * @param option 选项配置项
145
+ * @returns 消息参数列
146
+ */
147
+ build(t) {
148
+ const n = [], i = t.sys ?? this.conf.sys;
149
+ i && i.trim() && n.push({ role: "system", content: i.trim() });
150
+ for (const o of t.list)
151
+ o.role === "system" && i || n.push({
152
+ role: o.role,
153
+ content: o.text
154
+ });
155
+ return n;
156
+ }
157
+ /**
158
+ * 发起对话聊
159
+ * @param option 选项配置项
160
+ * @returns 回复结果集
161
+ */
162
+ async chat(t) {
163
+ var w, $, f;
164
+ this.client || this.init();
165
+ const n = this.build(t), o = (w = (await this.client.chat.completions.create(
166
+ {
167
+ model: t.model || this.conf.model,
168
+ messages: n,
169
+ temperature: t.temp ?? this.conf.temp ?? 0.7,
170
+ max_tokens: t.tokens ?? this.conf.tokens ?? 2048,
171
+ stream: !1
172
+ },
173
+ { signal: t.signal }
174
+ )).choices) == null ? void 0 : w[0], u = (($ = o == null ? void 0 : o.message) == null ? void 0 : $.content) || "", p = ((f = o == null ? void 0 : o.message) == null ? void 0 : f.reasoning_content) || "";
175
+ return { text: u, think: p };
176
+ }
177
+ /**
178
+ * 流式对话聊
179
+ * @param option 选项配置项
180
+ * @param handler 回调处理器
181
+ * @returns 回复结果集
182
+ */
183
+ async stream(t, n = {}) {
184
+ var p, w, $, f, g, b;
185
+ this.client || this.init();
186
+ const i = this.build(t);
187
+ let o = "", u = "";
188
+ try {
189
+ const m = await this.client.chat.completions.create(
190
+ {
191
+ model: t.model || this.conf.model,
192
+ messages: i,
193
+ temperature: t.temp ?? this.conf.temp ?? 0.7,
194
+ max_tokens: t.tokens ?? this.conf.tokens ?? 2048,
195
+ stream: !0
196
+ },
197
+ { signal: t.signal }
198
+ );
199
+ for await (const d of m) {
200
+ const r = (w = (p = d.choices) == null ? void 0 : p[0]) == null ? void 0 : w.delta;
201
+ if (!r) continue;
202
+ const E = r == null ? void 0 : r.reasoning_content;
203
+ E && (u += E, ($ = n.onThink) == null || $.call(n, E)), r.content && (o += r.content, (f = n.onToken) == null || f.call(n, r.content));
204
+ }
205
+ return (g = n.onDone) == null || g.call(n, o, u), { text: o, think: u };
206
+ } catch (m) {
207
+ throw (b = n.onError) == null || b.call(n, m), m;
208
+ }
209
+ }
210
+ /**
211
+ * 测试连接性
212
+ * @param tempConfig 临时配置项
213
+ * @returns 测试结果集
214
+ */
215
+ async test(t) {
216
+ const n = { ...this.conf };
217
+ t && this.save(t);
218
+ const i = Date.now();
219
+ try {
220
+ return await this.chat({
221
+ list: [{ role: "user", text: "Hi" }],
222
+ tokens: 5
223
+ }), {
224
+ success: !0,
225
+ msg: "连接成功",
226
+ latency: Date.now() - i
227
+ };
228
+ } catch (o) {
229
+ return {
230
+ success: !1,
231
+ msg: (o == null ? void 0 : o.message) || "连接失败",
232
+ latency: Date.now() - i
233
+ };
234
+ } finally {
235
+ this.save(n);
236
+ }
237
+ }
238
+ }
239
+ function Mt(e, t) {
240
+ return new ne(e, t);
241
+ }
242
+ function K() {
243
+ const e = {};
244
+ for (const t of F)
245
+ e[t.type] = {
246
+ key: "",
247
+ url: t.apiUrl,
248
+ model: t.model,
249
+ temp: 0.7,
250
+ tokens: 2048,
251
+ sys: "你是一名专业热情的直播间智能助手,负责协助主播进行弹幕互动与话术生成。"
252
+ };
253
+ return e;
254
+ }
255
+ const ye = ae("ai", {
256
+ state: () => ({
257
+ // 当前引擎类
258
+ engine: "deepseek",
259
+ // 功能启用态
260
+ isEnabled: !0,
261
+ // 各引擎配置
262
+ configs: K(),
263
+ // 远程模型列
264
+ remoteList: []
265
+ }),
266
+ getters: {
267
+ // 当前配置项
268
+ conf: (e) => e.configs[e.engine] || K()[e.engine],
269
+ // 就绪状态态
270
+ isReady: (e) => {
271
+ var t, n;
272
+ return e.engine === "ollama" || !!((n = (t = e.configs[e.engine]) == null ? void 0 : t.key) != null && n.trim());
273
+ },
274
+ // 引擎列表项
275
+ list: (e) => e.remoteList.length > 0 ? e.remoteList : F,
276
+ // 当前信息项
277
+ info: (e) => e.remoteList.find((n) => n.type === e.engine) || q[e.engine] || q.deepseek
278
+ },
279
+ actions: {
280
+ /**
281
+ * 设置当前擎
282
+ * @param type 引擎类型名
283
+ */
284
+ set(e) {
285
+ this.engine = e;
286
+ },
287
+ /**
288
+ * 切换启用态
289
+ */
290
+ toggle() {
291
+ this.isEnabled = !this.isEnabled;
292
+ },
293
+ /**
294
+ * 保存配置项
295
+ * @param type 引擎类型名
296
+ * @param conf 配置项对象
297
+ */
298
+ save(e, t) {
299
+ this.configs[e] || (this.configs[e] = K()[e]), Object.assign(this.configs[e], t);
300
+ },
301
+ /**
302
+ * 重置配置项
303
+ * @param type 引擎类型名
304
+ */
305
+ reset(e) {
306
+ if (e) {
307
+ this.configs[e] = K()[e];
308
+ return;
309
+ }
310
+ this.configs = K(), this.engine = "deepseek", this.isEnabled = !0;
311
+ },
312
+ /**
313
+ * 同步模型列
314
+ */
315
+ async sync() {
316
+ try {
317
+ const e = await ue("/plugin-base/api.v1.ai/index");
318
+ if (e.code === 1 && Array.isArray(e.data) && e.data.length > 0) {
319
+ this.remoteList = e.data;
320
+ for (const t of e.data)
321
+ this.configs[t.type] || (this.configs[t.type] = {
322
+ key: "",
323
+ url: t.apiUrl,
324
+ model: t.model,
325
+ temp: 0.7,
326
+ tokens: 2048,
327
+ sys: "你是一名专业热情的直播间智能助手,负责协助主播进行弹幕互动与话术生成。"
328
+ });
329
+ return e.data;
330
+ }
331
+ } catch {
332
+ }
333
+ return this.remoteList.length > 0 ? this.remoteList : F;
334
+ }
335
+ },
336
+ persist: {
337
+ key: "ai.config",
338
+ storage: re
339
+ }
340
+ }), X = /* @__PURE__ */ new Map();
341
+ function B(e, t) {
342
+ let n = X.get(e);
343
+ return n ? n.save(t) : (n = new ne(e, t), X.set(e, n)), n;
344
+ }
345
+ function z() {
346
+ const e = ye(), { engine: t, isEnabled: n } = ce(e), i = S(!1), o = S(""), u = S("");
347
+ let p = null;
348
+ const w = A(() => B(e.engine, e.conf)), $ = A(() => e.info), f = A(() => e.conf), g = A(() => e.isReady), b = A(() => e.list);
349
+ function m(x) {
350
+ e.set(x);
351
+ }
352
+ function d() {
353
+ p && (p.abort(), p = null), i.value = !1;
354
+ }
355
+ async function r(x, k, V) {
356
+ if (!n.value) throw new Error("AI 功能已停用");
357
+ i.value = !0, o.value = "", u.value = "", p = new AbortController();
358
+ const c = V ? B(V, e.configs[V] || e.conf) : w.value;
359
+ try {
360
+ const l = typeof x == "string" ? [{ role: "user", text: x }] : x, y = await c.chat({
361
+ list: l,
362
+ signal: p.signal,
363
+ ...k
364
+ });
365
+ return o.value = y.text, u.value = y.think || "", y.text;
366
+ } finally {
367
+ i.value = !1, p = null;
368
+ }
369
+ }
370
+ async function E(x, k = {}, V) {
371
+ if (!n.value) throw new Error("AI 功能已停用");
372
+ i.value = !0, o.value = "", u.value = "", p = new AbortController();
373
+ const c = V ? B(V, e.configs[V] || e.conf) : w.value;
374
+ try {
375
+ const l = typeof x == "string" ? [{ role: "user", text: x }] : x;
376
+ return (await c.stream(
377
+ {
378
+ list: l,
379
+ signal: p.signal
380
+ },
381
+ {
382
+ onToken: (U) => {
383
+ var C;
384
+ o.value += U, (C = k.onToken) == null || C.call(k, U);
385
+ },
386
+ onThink: (U) => {
387
+ var C;
388
+ u.value += U, (C = k.onThink) == null || C.call(k, U);
389
+ },
390
+ onDone: (U, C) => {
391
+ var Q;
392
+ o.value = U, u.value = C || "", (Q = k.onDone) == null || Q.call(k, U, C);
393
+ },
394
+ onError: (U) => {
395
+ var C;
396
+ (C = k.onError) == null || C.call(k, U);
397
+ }
398
+ }
399
+ )).text;
400
+ } finally {
401
+ i.value = !1, p = null;
402
+ }
403
+ }
404
+ async function N(x, k) {
405
+ const V = x || e.engine, c = e.configs[V] || e.conf;
406
+ return B(V, c).test(k);
407
+ }
408
+ return {
409
+ store: e,
410
+ engine: t,
411
+ isEnabled: n,
412
+ conf: f,
413
+ info: $,
414
+ list: b,
415
+ isReady: g,
416
+ isLoading: A(() => i.value),
417
+ text: A(() => o.value),
418
+ think: A(() => u.value),
419
+ select: m,
420
+ chat: r,
421
+ stream: E,
422
+ test: N,
423
+ abort: d,
424
+ save: e.save.bind(e),
425
+ reset: e.reset.bind(e),
426
+ sync: e.sync.bind(e)
427
+ };
428
+ }
429
+ const ke = { class: "ai-header" }, be = { class: "header-right" }, _e = { class: "switch-wrap" }, we = /* @__PURE__ */ D({
430
+ __name: "header",
431
+ setup(e) {
432
+ const { info: t, isReady: n, isEnabled: i } = z();
433
+ function o() {
434
+ I(`AI 功能已${i.value ? "开启" : "停用"}`, i.value ? "success" : "info");
435
+ }
436
+ return (u, p) => (v(), h("div", ke, [
437
+ p[2] || (p[2] = s("div", { class: "header-title" }, [
438
+ s("i", { class: "pi pi-microchip title-icon" }),
439
+ s("span", { class: "title-text" }, "大模型配置与测试")
440
+ ], -1)),
441
+ s("div", be, [
442
+ _(a(te), {
443
+ severity: a(n) ? "success" : "warn",
444
+ rounded: "",
445
+ class: "status-tag"
446
+ }, {
447
+ icon: H(() => [
448
+ s("i", {
449
+ class: P(a(n) ? "pi pi-check-circle" : "pi pi-exclamation-circle")
450
+ }, null, 2)
451
+ ]),
452
+ default: H(() => [
453
+ Y(" " + T(a(n) ? `${a(t).name} 已就绪` : `${a(t).name} 未配 Key`), 1)
454
+ ]),
455
+ _: 1
456
+ }, 8, ["severity"]),
457
+ s("div", _e, [
458
+ p[1] || (p[1] = s("span", { class: "switch-label" }, "启用 AI:", -1)),
459
+ _(a(ve), {
460
+ modelValue: a(i),
461
+ "onUpdate:modelValue": p[0] || (p[0] = (w) => me(i) ? i.value = w : null),
462
+ onChange: o
463
+ }, null, 8, ["modelValue"])
464
+ ])
465
+ ])
466
+ ]));
467
+ }
468
+ }), M = (e, t) => {
469
+ const n = e.__vccOpts || e;
470
+ for (const [i, o] of t)
471
+ n[i] = o;
472
+ return n;
473
+ }, $e = /* @__PURE__ */ M(we, [["__scopeId", "data-v-fd7319b0"]]), xe = { class: "engine-section" }, Ve = { class: "engine-grid" }, Ce = ["onClick"], Ae = { class: "card-head" }, Ee = { class: "card-name" }, Ue = {
474
+ key: 0,
475
+ class: "free-badge"
476
+ }, Ie = ["onClick"], Te = { class: "card-desc" }, Se = /* @__PURE__ */ D({
477
+ __name: "grid",
478
+ emits: ["change"],
479
+ setup(e, { emit: t }) {
480
+ const n = t, { engine: i, list: o, select: u, sync: p } = z();
481
+ fe(() => {
482
+ p();
483
+ });
484
+ function w(f) {
485
+ f != null && f.website && (se.openExternal(f.website), I(`已为你打开【${f.name}】开发者控制台`, "info"));
486
+ }
487
+ function $(f) {
488
+ u(f.type), n("change", f.type);
489
+ }
490
+ return (f, g) => (v(), h("div", xe, [
491
+ g[1] || (g[1] = s("div", { class: "section-header" }, [
492
+ s("span", { class: "section-title" }, "选择大模型服务商"),
493
+ s("span", { class: "section-hint" }, "点击一键切换引擎")
494
+ ], -1)),
495
+ s("div", Ve, [
496
+ (v(!0), h(Z, null, ee(a(o), (b) => (v(), h("div", {
497
+ key: b.type,
498
+ class: P(["engine-card", { active: a(i) === b.type }]),
499
+ onClick: (m) => $(b)
500
+ }, [
501
+ s("div", Ae, [
502
+ s("span", Ee, T(b.name), 1),
503
+ b.free ? (v(), h("span", Ue, "免密")) : b.website ? (v(), h("span", {
504
+ key: 1,
505
+ class: "key-link",
506
+ title: "点击打开官网获取 Key",
507
+ onClick: J((m) => w(b), ["stop"])
508
+ }, [...g[0] || (g[0] = [
509
+ s("span", null, "获取Key", -1),
510
+ s("i", { class: "pi pi-external-link icon-link" }, null, -1)
511
+ ])], 8, Ie)) : L("", !0)
512
+ ]),
513
+ s("span", Te, T(b.tag), 1)
514
+ ], 10, Ce))), 128))
515
+ ])
516
+ ]));
517
+ }
518
+ }), Le = /* @__PURE__ */ M(Se, [["__scopeId", "data-v-d3fe9eca"]]), Ke = { class: "params-container" }, Re = { class: "params-fields" }, Pe = { class: "field-section" }, qe = { class: "form-row" }, De = { class: "form-field flex-2" }, Me = { class: "field-label" }, Ne = { class: "label-title" }, Oe = {
519
+ key: 0,
520
+ class: "req-star"
521
+ }, Be = {
522
+ key: 1,
523
+ class: "free-text"
524
+ }, He = { class: "form-field flex-1" }, ze = { class: "form-field" }, Ge = { class: "field-section" }, je = { class: "form-row" }, Fe = { class: "form-field flex-1" }, Je = { class: "field-label" }, Qe = { class: "slider-box" }, We = { class: "form-field flex-1" }, Xe = { class: "form-field" }, Ye = { class: "params-footer" }, Ze = { class: "footer-actions" }, et = /* @__PURE__ */ D({
525
+ __name: "params",
526
+ setup(e, { expose: t }) {
527
+ const {
528
+ engine: n,
529
+ conf: i,
530
+ info: o,
531
+ save: u,
532
+ reset: p,
533
+ test: w
534
+ } = z();
535
+ function $(c) {
536
+ c && se.openExternal(c);
537
+ }
538
+ const f = S(!1), g = S(null), b = A(() => (o.value.models || []).map((l) => ({
539
+ label: l,
540
+ value: l
541
+ }))), m = A({
542
+ get: () => i.value.temp ?? 0.7,
543
+ set: (c) => {
544
+ c != null && u(n.value, { temp: c });
545
+ }
546
+ }), d = A({
547
+ get: () => i.value.tokens ?? 2048,
548
+ set: (c) => {
549
+ c && u(n.value, { tokens: c });
550
+ }
551
+ });
552
+ function r() {
553
+ u(n.value, { key: (i.value.key || "").trim() });
554
+ }
555
+ function E(c) {
556
+ u(n.value, { url: String(c || "").trim() });
557
+ }
558
+ function N(c) {
559
+ const l = (c == null ? void 0 : c.value) !== void 0 ? c.value : c;
560
+ u(n.value, { model: String(l || "").trim() });
561
+ }
562
+ function x(c) {
563
+ u(n.value, { sys: String(c || "") });
564
+ }
565
+ async function k() {
566
+ f.value = !0, g.value = null;
567
+ try {
568
+ const c = await w();
569
+ g.value = c, c.success ? I(`连接成功,耗时 ${c.latency}ms`, "success") : I(`连接失败: ${c.msg}`, "error");
570
+ } catch (c) {
571
+ g.value = {
572
+ success: !1,
573
+ msg: (c == null ? void 0 : c.message) || "连接异常",
574
+ latency: 0
575
+ }, I(`连接异常: ${(c == null ? void 0 : c.message) || "未知错误"}`, "error");
576
+ } finally {
577
+ f.value = !1;
578
+ }
579
+ }
580
+ function V() {
581
+ p(n.value), g.value = null, I(`已恢复【${o.value.name}】为默认配置`, "info");
582
+ }
583
+ return t({
584
+ /**
585
+ * 清理测试态
586
+ */
587
+ clearTest: () => {
588
+ g.value = null;
589
+ }
590
+ }), (c, l) => (v(), h("div", Ke, [
591
+ s("div", Re, [
592
+ s("div", Pe, [
593
+ l[12] || (l[12] = s("div", { class: "section-header" }, [
594
+ s("span", { class: "section-title" }, "API 凭证与模型")
595
+ ], -1)),
596
+ s("div", qe, [
597
+ s("div", De, [
598
+ s("label", Me, [
599
+ s("span", Ne, [
600
+ l[8] || (l[8] = s("span", null, "API Key", -1)),
601
+ a(o).free ? (v(), h("span", Be, "(本地模型无需填写)")) : (v(), h("span", Oe, "*"))
602
+ ]),
603
+ a(o).website ? (v(), h("a", {
604
+ key: 0,
605
+ class: "portal-link",
606
+ title: "在浏览器中打开开发者平台获取 Key",
607
+ onClick: l[0] || (l[0] = J((y) => $(a(o).website), ["stop"]))
608
+ }, [
609
+ s("span", null, "获取 " + T(a(o).name) + " 密钥", 1),
610
+ l[9] || (l[9] = s("i", { class: "pi pi-external-link icon-link" }, null, -1))
611
+ ])) : L("", !0)
612
+ ]),
613
+ _(a(he), {
614
+ modelValue: a(i).key,
615
+ "onUpdate:modelValue": l[1] || (l[1] = (y) => a(i).key = y),
616
+ feedback: !1,
617
+ "toggle-mask": "",
618
+ fluid: "",
619
+ placeholder: a(o).free ? "免密模型" : "请输入 API Key (sk-...)",
620
+ onChange: r
621
+ }, null, 8, ["modelValue", "placeholder"])
622
+ ]),
623
+ s("div", He, [
624
+ l[10] || (l[10] = s("label", { class: "field-label" }, "模型 (Model)", -1)),
625
+ _(a(de), {
626
+ modelValue: a(i).model,
627
+ "onUpdate:modelValue": l[2] || (l[2] = (y) => a(i).model = y),
628
+ options: b.value,
629
+ "option-label": "label",
630
+ "option-value": "value",
631
+ editable: "",
632
+ fluid: "",
633
+ filter: "",
634
+ placeholder: "选择或输入模型",
635
+ onChange: N
636
+ }, null, 8, ["modelValue", "options"])
637
+ ])
638
+ ]),
639
+ s("div", ze, [
640
+ l[11] || (l[11] = s("label", { class: "field-label" }, "接口地址 (Base URL)", -1)),
641
+ _(a(G), {
642
+ modelValue: a(i).url,
643
+ "onUpdate:modelValue": [
644
+ l[3] || (l[3] = (y) => a(i).url = y),
645
+ E
646
+ ],
647
+ fluid: "",
648
+ clearable: "",
649
+ placeholder: "https://api.openai.com/v1"
650
+ }, null, 8, ["modelValue"])
651
+ ])
652
+ ]),
653
+ s("div", Ge, [
654
+ l[15] || (l[15] = s("div", { class: "section-header" }, [
655
+ s("span", { class: "section-title" }, "生成参数")
656
+ ], -1)),
657
+ s("div", je, [
658
+ s("div", Fe, [
659
+ s("label", Je, "随机温度 (Temperature): " + T(m.value), 1),
660
+ s("div", Qe, [
661
+ _(a(ge), {
662
+ modelValue: m.value,
663
+ "onUpdate:modelValue": l[4] || (l[4] = (y) => m.value = y),
664
+ min: 0,
665
+ max: 2,
666
+ step: 0.05,
667
+ class: "temp-slider"
668
+ }, null, 8, ["modelValue"]),
669
+ _(a(W), {
670
+ modelValue: m.value,
671
+ "onUpdate:modelValue": l[5] || (l[5] = (y) => m.value = y),
672
+ min: 0,
673
+ max: 2,
674
+ step: 0.05,
675
+ "min-fraction-digits": 2,
676
+ "max-fraction-digits": 2,
677
+ class: "temp-number"
678
+ }, null, 8, ["modelValue"])
679
+ ])
680
+ ]),
681
+ s("div", We, [
682
+ l[13] || (l[13] = s("label", { class: "field-label" }, "最大 Token 数", -1)),
683
+ _(a(W), {
684
+ modelValue: d.value,
685
+ "onUpdate:modelValue": l[6] || (l[6] = (y) => d.value = y),
686
+ min: 128,
687
+ max: 16384,
688
+ step: 256,
689
+ fluid: ""
690
+ }, null, 8, ["modelValue"])
691
+ ])
692
+ ]),
693
+ s("div", Xe, [
694
+ l[14] || (l[14] = s("label", { class: "field-label" }, "系统人设 (System Prompt)", -1)),
695
+ _(a(G), {
696
+ modelValue: a(i).sys,
697
+ "onUpdate:modelValue": [
698
+ l[7] || (l[7] = (y) => a(i).sys = y),
699
+ x
700
+ ],
701
+ type: "textarea",
702
+ fluid: "",
703
+ rows: 3,
704
+ placeholder: "定义 AI 的角色定位与回答风格..."
705
+ }, null, 8, ["modelValue"])
706
+ ])
707
+ ])
708
+ ]),
709
+ s("div", Ye, [
710
+ s("div", Ze, [
711
+ _(a(R), {
712
+ variant: "outlined",
713
+ loading: f.value,
714
+ icon: "pi pi-bolt",
715
+ label: "测试连接",
716
+ onClick: k
717
+ }, null, 8, ["loading"]),
718
+ _(a(R), {
719
+ variant: "outlined",
720
+ severity: "secondary",
721
+ icon: "pi pi-refresh",
722
+ label: "恢复默认",
723
+ onClick: V
724
+ })
725
+ ]),
726
+ g.value ? (v(), j(a(te), {
727
+ key: 0,
728
+ severity: g.value.success ? "success" : "danger",
729
+ rounded: "",
730
+ class: "result-tag"
731
+ }, {
732
+ icon: H(() => [
733
+ s("i", {
734
+ class: P(g.value.success ? "pi pi-check-circle" : "pi pi-times-circle")
735
+ }, null, 2)
736
+ ]),
737
+ default: H(() => [
738
+ Y(" " + T(g.value.success ? `已连通 (${g.value.latency}ms)` : "连接失败"), 1)
739
+ ]),
740
+ _: 1
741
+ }, 8, ["severity"])) : L("", !0)
742
+ ])
743
+ ]));
744
+ }
745
+ }), tt = /* @__PURE__ */ M(et, [["__scopeId", "data-v-83061ed2"]]), st = { class: "chat-wrapper" }, nt = { class: "prompt-bar" }, ot = { class: "chat-area" }, it = {
746
+ key: 0,
747
+ class: "chat-empty"
748
+ }, lt = {
749
+ key: 1,
750
+ class: "chat-list"
751
+ }, at = { class: "msg-bubble" }, ct = {
752
+ key: 0,
753
+ class: "think-box"
754
+ }, rt = { class: "think-content" }, ut = { class: "msg-text" }, dt = { class: "text-content" }, pt = { key: 0 }, mt = {
755
+ key: 1,
756
+ class: "loading-hint"
757
+ }, ft = {
758
+ key: 0,
759
+ class: "bubble-actions"
760
+ }, vt = ["onClick"], gt = { class: "chat-input-bar" }, ht = { class: "input-bottom-row" }, yt = { class: "action-buttons" }, kt = /* @__PURE__ */ D({
761
+ __name: "chat",
762
+ setup(e) {
763
+ const { isLoading: t, stream: n, abort: i } = z(), o = S(""), u = S([]);
764
+ function p(m) {
765
+ o.value = m;
766
+ }
767
+ async function w(m) {
768
+ if (m)
769
+ try {
770
+ await navigator.clipboard.writeText(m), I("已复制话术到剪贴板", "success");
771
+ } catch {
772
+ I("复制失败,请手动复制", "error");
773
+ }
774
+ }
775
+ function $(m) {
776
+ m.key === "Enter" && !m.shiftKey && (m.preventDefault(), o.value.trim() && !t.value && f());
777
+ }
778
+ async function f() {
779
+ const m = o.value.trim();
780
+ if (!m || t.value) return;
781
+ o.value = "", u.value.push({ role: "user", text: m });
782
+ const d = { role: "assistant", text: "", think: "" };
783
+ u.value.push(d);
784
+ try {
785
+ await n(
786
+ u.value.slice(0, -1),
787
+ {
788
+ onToken: (r) => {
789
+ d.text += r;
790
+ },
791
+ onThink: (r) => {
792
+ d.think || (d.think = ""), d.think += r;
793
+ },
794
+ onError: (r) => {
795
+ I(`生成错误: ${r.message}`, "error");
796
+ }
797
+ }
798
+ );
799
+ } catch (r) {
800
+ d.text = `[请求失败]: ${(r == null ? void 0 : r.message) || "网络异常"}`;
801
+ }
802
+ }
803
+ function g() {
804
+ i(), I("已中止当前生成", "info");
805
+ }
806
+ function b() {
807
+ u.value = [];
808
+ }
809
+ return (m, d) => (v(), h("div", st, [
810
+ s("div", nt, [
811
+ d[5] || (d[5] = s("span", { class: "prompt-label" }, "常用话术:", -1)),
812
+ s("span", {
813
+ class: "prompt-chip",
814
+ onClick: d[0] || (d[0] = (r) => p("帮我写一段幽默风趣的直播间求点赞话术"))
815
+ }, " 求点赞 "),
816
+ s("span", {
817
+ class: "prompt-chip",
818
+ onClick: d[1] || (d[1] = (r) => p("观众送出了嘉年华,写一段热情霸气的感谢词"))
819
+ }, " 感谢大哥 "),
820
+ s("span", {
821
+ class: "prompt-chip",
822
+ onClick: d[2] || (d[2] = (r) => p("有观众在弹幕质疑商品价格偏高,给出高情商回复话术"))
823
+ }, " 高情商解围 "),
824
+ s("span", {
825
+ class: "prompt-chip",
826
+ onClick: d[3] || (d[3] = (r) => p("直播间准备开始抽奖,帮我写一段炒热气氛的话术"))
827
+ }, " 抽奖倒计时 ")
828
+ ]),
829
+ s("div", ot, [
830
+ u.value.length === 0 ? (v(), h("div", it, [...d[6] || (d[6] = [
831
+ s("i", { class: "pi pi-microchip empty-icon" }, null, -1),
832
+ s("span", { class: "empty-title" }, "AI 对话演练沙箱", -1),
833
+ s("span", { class: "empty-desc" }, "选择服务商后,在下方输入话术需求或点击上方预设,实时体验大模型流式输出与思考推理", -1)
834
+ ])])) : (v(), h("div", lt, [
835
+ (v(!0), h(Z, null, ee(u.value, (r, E) => (v(), h("div", {
836
+ key: E,
837
+ class: P(["chat-row", r.role])
838
+ }, [
839
+ s("div", {
840
+ class: P(["role-tag", r.role])
841
+ }, T(r.role === "user" ? "主播" : "AI"), 3),
842
+ s("div", at, [
843
+ r.think ? (v(), h("div", ct, [
844
+ d[7] || (d[7] = s("div", { class: "think-header" }, [
845
+ s("i", { class: "pi pi-code" }),
846
+ s("span", null, "思考过程")
847
+ ], -1)),
848
+ s("div", rt, T(r.think), 1)
849
+ ])) : L("", !0),
850
+ s("div", ut, [
851
+ s("div", dt, [
852
+ r.text ? (v(), h("span", pt, T(r.text), 1)) : a(t) && E === u.value.length - 1 ? (v(), h("span", mt, " 正在思考与生成回复... ")) : L("", !0)
853
+ ]),
854
+ r.text ? (v(), h("div", ft, [
855
+ s("button", {
856
+ class: "copy-btn",
857
+ title: "复制话术内容",
858
+ onClick: J((N) => w(r.text), ["stop"])
859
+ }, [...d[8] || (d[8] = [
860
+ s("i", { class: "pi pi-copy" }, null, -1),
861
+ s("span", null, "复制话术", -1)
862
+ ])], 8, vt)
863
+ ])) : L("", !0)
864
+ ])
865
+ ])
866
+ ], 2))), 128))
867
+ ]))
868
+ ]),
869
+ s("div", gt, [
870
+ _(a(G), {
871
+ modelValue: o.value,
872
+ "onUpdate:modelValue": d[4] || (d[4] = (r) => o.value = r),
873
+ type: "textarea",
874
+ rows: 3,
875
+ placeholder: "输入提问内容 (快捷键 Enter 发送,Shift + Enter 换行)...",
876
+ disabled: a(t),
877
+ fluid: "",
878
+ onKeydown: $
879
+ }, null, 8, ["modelValue", "disabled"]),
880
+ s("div", ht, [
881
+ d[9] || (d[9] = s("span", { class: "shortcut-tip" }, "Enter 发送 / Shift + Enter 换行", -1)),
882
+ s("div", yt, [
883
+ _(a(R), {
884
+ variant: "outlined",
885
+ severity: "secondary",
886
+ icon: "pi pi-trash",
887
+ disabled: u.value.length === 0 || a(t),
888
+ label: "清空记录",
889
+ onClick: b
890
+ }, null, 8, ["disabled"]),
891
+ a(t) ? (v(), j(a(R), {
892
+ key: 0,
893
+ severity: "warn",
894
+ variant: "outlined",
895
+ icon: "pi pi-stop-circle",
896
+ label: "停止生成",
897
+ onClick: g
898
+ })) : (v(), j(a(R), {
899
+ key: 1,
900
+ severity: "primary",
901
+ icon: "pi pi-send",
902
+ disabled: !o.value.trim(),
903
+ label: "发送测试",
904
+ onClick: f
905
+ }, null, 8, ["disabled"]))
906
+ ])
907
+ ])
908
+ ])
909
+ ]));
910
+ }
911
+ }), bt = /* @__PURE__ */ M(kt, [["__scopeId", "data-v-e8146ded"]]), _t = { class: "hlw-ai" }, wt = { class: "ai-body" }, $t = { class: "left-pane" }, xt = { class: "pane-content" }, Vt = { class: "right-pane" }, Ct = /* @__PURE__ */ D({
912
+ __name: "ai",
913
+ setup(e) {
914
+ const { refs: t, setRefs: n } = pe();
915
+ function i() {
916
+ var o, u;
917
+ (u = (o = t.value.params) == null ? void 0 : o.clearTest) == null || u.call(o);
918
+ }
919
+ return (o, u) => (v(), h("div", _t, [
920
+ _($e),
921
+ s("div", wt, [
922
+ s("div", $t, [
923
+ s("div", xt, [
924
+ _(Le, { onChange: i }),
925
+ _(tt, {
926
+ ref: a(n)("params")
927
+ }, null, 512)
928
+ ])
929
+ ]),
930
+ s("div", Vt, [
931
+ _(bt)
932
+ ])
933
+ ])
934
+ ]));
935
+ }
936
+ }), Nt = /* @__PURE__ */ M(Ct, [["__scopeId", "data-v-2dd89a9e"]]);
937
+ export {
938
+ bt as AiChat,
939
+ Le as AiGrid,
940
+ $e as AiHeader,
941
+ tt as AiParams,
942
+ F as ENGINES,
943
+ ne as Engine,
944
+ Nt as HlwAi,
945
+ Mt as createEngine,
946
+ Dt as engineName,
947
+ q as engines,
948
+ K as getDefaults,
949
+ z as useAi,
950
+ ye as useAiStore
951
+ };