sa2kit 1.4.2 → 1.5.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/dist/ConfigService-7MEZXKJ5.js +21 -0
- package/dist/ConfigService-7MEZXKJ5.js.map +1 -0
- package/dist/ConfigService-BV57YYFW.mjs +4 -0
- package/dist/ConfigService-BV57YYFW.mjs.map +1 -0
- package/dist/ConfigService-BxK06xP6.d.mts +262 -0
- package/dist/ConfigService-BxK06xP6.d.ts +262 -0
- package/dist/audioDetection/index.d.mts +449 -0
- package/dist/audioDetection/index.d.ts +449 -0
- package/dist/audioDetection/index.js +1244 -0
- package/dist/audioDetection/index.js.map +1 -0
- package/dist/audioDetection/index.mjs +1227 -0
- package/dist/audioDetection/index.mjs.map +1 -0
- package/dist/chunk-5XUE72Y3.mjs +1001 -0
- package/dist/chunk-5XUE72Y3.mjs.map +1 -0
- package/dist/chunk-DQVPZTVC.js +1009 -0
- package/dist/chunk-DQVPZTVC.js.map +1 -0
- package/dist/chunk-NEPD75MX.mjs +467 -0
- package/dist/chunk-NEPD75MX.mjs.map +1 -0
- package/dist/chunk-OEDY7GI4.js +473 -0
- package/dist/chunk-OEDY7GI4.js.map +1 -0
- package/dist/chunk-TFQF2HDO.mjs +354 -0
- package/dist/chunk-TFQF2HDO.mjs.map +1 -0
- package/dist/chunk-TOC5FSHP.js +358 -0
- package/dist/chunk-TOC5FSHP.js.map +1 -0
- package/dist/imageCrop/index.d.mts +165 -0
- package/dist/imageCrop/index.d.ts +165 -0
- package/dist/imageCrop/index.js +559 -0
- package/dist/imageCrop/index.js.map +1 -0
- package/dist/imageCrop/index.mjs +540 -0
- package/dist/imageCrop/index.mjs.map +1 -0
- package/dist/index.d.mts +139 -0
- package/dist/index.d.ts +139 -0
- package/dist/index.js +670 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +662 -0
- package/dist/index.mjs.map +1 -1
- package/dist/mmd/index.d.mts +113 -2
- package/dist/mmd/index.d.ts +113 -2
- package/dist/mmd/index.js +484 -2
- package/dist/mmd/index.js.map +1 -1
- package/dist/mmd/index.mjs +482 -4
- package/dist/mmd/index.mjs.map +1 -1
- package/dist/testYourself/admin/index.d.mts +58 -0
- package/dist/testYourself/admin/index.d.ts +58 -0
- package/dist/testYourself/admin/index.js +17 -0
- package/dist/testYourself/admin/index.js.map +1 -0
- package/dist/testYourself/admin/index.mjs +4 -0
- package/dist/testYourself/admin/index.mjs.map +1 -0
- package/dist/testYourself/index.d.mts +6 -98
- package/dist/testYourself/index.d.ts +6 -98
- package/dist/testYourself/index.js +90 -334
- package/dist/testYourself/index.js.map +1 -1
- package/dist/testYourself/index.mjs +47 -333
- package/dist/testYourself/index.mjs.map +1 -1
- package/dist/testYourself/server/index.d.mts +1029 -0
- package/dist/testYourself/server/index.d.ts +1029 -0
- package/dist/testYourself/server/index.js +42 -0
- package/dist/testYourself/server/index.js.map +1 -0
- package/dist/testYourself/server/index.mjs +5 -0
- package/dist/testYourself/server/index.mjs.map +1 -0
- package/dist/universalFile/server/index.js +5 -5
- package/dist/universalFile/server/index.mjs +1 -1
- package/package.json +62 -20
package/dist/index.js
CHANGED
|
@@ -5,8 +5,670 @@ var chunkLX4XX6W7_js = require('./chunk-LX4XX6W7.js');
|
|
|
5
5
|
require('./chunk-QU5OT4DF.js');
|
|
6
6
|
var chunk6PRFP5EG_js = require('./chunk-6PRFP5EG.js');
|
|
7
7
|
require('./chunk-DGUM43GV.js');
|
|
8
|
+
var React2 = require('react');
|
|
9
|
+
var tesseract_js = require('tesseract.js');
|
|
10
|
+
var lucideReact = require('lucide-react');
|
|
8
11
|
|
|
12
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
13
|
|
|
14
|
+
var React2__default = /*#__PURE__*/_interopDefault(React2);
|
|
15
|
+
|
|
16
|
+
var useOCR = (options = {}) => {
|
|
17
|
+
const [state, setState] = React2.useState({
|
|
18
|
+
isProcessing: false,
|
|
19
|
+
progress: 0,
|
|
20
|
+
status: "idle",
|
|
21
|
+
error: null,
|
|
22
|
+
result: null
|
|
23
|
+
});
|
|
24
|
+
const workerRef = React2.useRef(null);
|
|
25
|
+
const cleanup = React2.useCallback(async () => {
|
|
26
|
+
if (workerRef.current) {
|
|
27
|
+
await workerRef.current.terminate();
|
|
28
|
+
workerRef.current = null;
|
|
29
|
+
}
|
|
30
|
+
}, []);
|
|
31
|
+
const recognize = React2.useCallback(
|
|
32
|
+
async (image) => {
|
|
33
|
+
setState((prev) => ({
|
|
34
|
+
...prev,
|
|
35
|
+
isProcessing: true,
|
|
36
|
+
error: null,
|
|
37
|
+
progress: 0,
|
|
38
|
+
status: "initializing"
|
|
39
|
+
}));
|
|
40
|
+
try {
|
|
41
|
+
const worker = await tesseract_js.createWorker(options.language || "eng", 1, {
|
|
42
|
+
logger: (m) => {
|
|
43
|
+
if (m.status === "recognizing text") {
|
|
44
|
+
setState((prev) => ({
|
|
45
|
+
...prev,
|
|
46
|
+
status: "recognizing",
|
|
47
|
+
progress: m.progress
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
options.logger?.(m);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
workerRef.current = worker;
|
|
54
|
+
const { data } = await worker.recognize(image);
|
|
55
|
+
const words = data.words || data.blocks?.flatMap((b) => b.paragraphs.flatMap((p) => p.lines.flatMap((l) => l.words))) || [];
|
|
56
|
+
const lines = data.lines || data.blocks?.flatMap((b) => b.paragraphs.flatMap((p) => p.lines)) || [];
|
|
57
|
+
const result = {
|
|
58
|
+
text: data.text,
|
|
59
|
+
confidence: data.confidence,
|
|
60
|
+
words: words.map((w) => ({
|
|
61
|
+
text: w.text,
|
|
62
|
+
confidence: w.confidence,
|
|
63
|
+
bbox: w.bbox
|
|
64
|
+
})),
|
|
65
|
+
lines: lines.map((l) => l.text)
|
|
66
|
+
};
|
|
67
|
+
setState((prev) => ({
|
|
68
|
+
...prev,
|
|
69
|
+
isProcessing: false,
|
|
70
|
+
progress: 1,
|
|
71
|
+
status: "completed",
|
|
72
|
+
result
|
|
73
|
+
}));
|
|
74
|
+
await worker.terminate();
|
|
75
|
+
workerRef.current = null;
|
|
76
|
+
return result;
|
|
77
|
+
} catch (err) {
|
|
78
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
79
|
+
setState((prev) => ({
|
|
80
|
+
...prev,
|
|
81
|
+
isProcessing: false,
|
|
82
|
+
status: "error",
|
|
83
|
+
error
|
|
84
|
+
}));
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
[options]
|
|
89
|
+
);
|
|
90
|
+
React2.useEffect(() => {
|
|
91
|
+
return () => {
|
|
92
|
+
cleanup();
|
|
93
|
+
};
|
|
94
|
+
}, [cleanup]);
|
|
95
|
+
return {
|
|
96
|
+
...state,
|
|
97
|
+
recognize,
|
|
98
|
+
cleanup
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
var OCRScanner = ({
|
|
102
|
+
onResult,
|
|
103
|
+
className = "",
|
|
104
|
+
language = "eng"
|
|
105
|
+
}) => {
|
|
106
|
+
const [imagePreview, setImagePreview] = React2.useState(null);
|
|
107
|
+
const fileInputRef = React2.useRef(null);
|
|
108
|
+
const { recognize, isProcessing, progress, status, result, error } = useOCR({
|
|
109
|
+
language
|
|
110
|
+
});
|
|
111
|
+
const handleFileChange = async (e) => {
|
|
112
|
+
const file = e.target.files?.[0];
|
|
113
|
+
if (!file) return;
|
|
114
|
+
const reader = new FileReader();
|
|
115
|
+
reader.onload = (event) => {
|
|
116
|
+
setImagePreview(event.target?.result);
|
|
117
|
+
};
|
|
118
|
+
reader.readAsDataURL(file);
|
|
119
|
+
try {
|
|
120
|
+
const ocrResult = await recognize(file);
|
|
121
|
+
onResult?.(ocrResult.text);
|
|
122
|
+
} catch (err) {
|
|
123
|
+
console.error("OCR Error:", err);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const reset = () => {
|
|
127
|
+
setImagePreview(null);
|
|
128
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
129
|
+
};
|
|
130
|
+
const handleDragOver = (e) => {
|
|
131
|
+
e.preventDefault();
|
|
132
|
+
e.stopPropagation();
|
|
133
|
+
};
|
|
134
|
+
const handleDrop = async (e) => {
|
|
135
|
+
e.preventDefault();
|
|
136
|
+
e.stopPropagation();
|
|
137
|
+
const file = e.dataTransfer.files?.[0];
|
|
138
|
+
if (file && file.type.startsWith("image/")) {
|
|
139
|
+
const mockEvent = { target: { files: [file] } };
|
|
140
|
+
handleFileChange(mockEvent);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
return /* @__PURE__ */ React2__default.default.createElement(
|
|
144
|
+
"div",
|
|
145
|
+
{
|
|
146
|
+
className: `p-6 border-2 border-dashed rounded-xl transition-all ${isProcessing ? "border-blue-400 bg-blue-50/10" : "border-gray-200 hover:border-blue-400"} ${className}`,
|
|
147
|
+
onDragOver: handleDragOver,
|
|
148
|
+
onDrop: handleDrop
|
|
149
|
+
},
|
|
150
|
+
!imagePreview ? /* @__PURE__ */ React2__default.default.createElement(
|
|
151
|
+
"div",
|
|
152
|
+
{
|
|
153
|
+
className: "flex flex-col items-center justify-center cursor-pointer space-y-4",
|
|
154
|
+
onClick: () => fileInputRef.current?.click()
|
|
155
|
+
},
|
|
156
|
+
/* @__PURE__ */ React2__default.default.createElement("div", { className: "p-4 bg-blue-50 rounded-full text-blue-500" }, /* @__PURE__ */ React2__default.default.createElement(lucideReact.Upload, { size: 32 })),
|
|
157
|
+
/* @__PURE__ */ React2__default.default.createElement("div", { className: "text-center" }, /* @__PURE__ */ React2__default.default.createElement("p", { className: "text-lg font-medium text-gray-700" }, "\u70B9\u51FB\u6216\u62D6\u62FD\u56FE\u7247\u8FDB\u884C OCR \u8BC6\u522B"), /* @__PURE__ */ React2__default.default.createElement("p", { className: "text-sm text-gray-500" }, "\u652F\u6301 JPG, PNG, WebP"))
|
|
158
|
+
) : /* @__PURE__ */ React2__default.default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "relative group rounded-lg overflow-hidden border border-gray-200" }, /* @__PURE__ */ React2__default.default.createElement(
|
|
159
|
+
"img",
|
|
160
|
+
{
|
|
161
|
+
src: imagePreview,
|
|
162
|
+
alt: "Preview",
|
|
163
|
+
className: `max-h-64 mx-auto object-contain transition-opacity ${isProcessing ? "opacity-50" : "opacity-100"}`
|
|
164
|
+
}
|
|
165
|
+
), !isProcessing && /* @__PURE__ */ React2__default.default.createElement(
|
|
166
|
+
"button",
|
|
167
|
+
{
|
|
168
|
+
onClick: reset,
|
|
169
|
+
className: "absolute top-2 right-2 p-1 bg-white/80 rounded-full hover:bg-white text-gray-600 shadow-sm"
|
|
170
|
+
},
|
|
171
|
+
/* @__PURE__ */ React2__default.default.createElement(lucideReact.X, { size: 18 })
|
|
172
|
+
), isProcessing && /* @__PURE__ */ React2__default.default.createElement("div", { className: "absolute inset-0 flex flex-col items-center justify-center bg-black/5" }, /* @__PURE__ */ React2__default.default.createElement(lucideReact.Loader2, { className: "animate-spin text-blue-500 mb-2", size: 32 }), /* @__PURE__ */ React2__default.default.createElement("div", { className: "w-48 bg-gray-200 rounded-full h-1.5 overflow-hidden" }, /* @__PURE__ */ React2__default.default.createElement(
|
|
173
|
+
"div",
|
|
174
|
+
{
|
|
175
|
+
className: "bg-blue-500 h-full transition-all duration-300",
|
|
176
|
+
style: { width: `${progress * 100}%` }
|
|
177
|
+
}
|
|
178
|
+
)), /* @__PURE__ */ React2__default.default.createElement("p", { className: "text-xs font-medium text-blue-600 mt-2" }, status === "initializing" ? "\u6B63\u5728\u52A0\u8F7D\u5F15\u64CE..." : `\u8BC6\u522B\u4E2D ${Math.round(progress * 100)}%`))), result && !isProcessing && /* @__PURE__ */ React2__default.default.createElement("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-100 animate-in fade-in slide-in-from-bottom-2" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center gap-2 mb-2 text-gray-600 font-medium" }, /* @__PURE__ */ React2__default.default.createElement(lucideReact.FileText, { size: 18 }), /* @__PURE__ */ React2__default.default.createElement("span", null, "\u8BC6\u522B\u7ED3\u679C (\u7F6E\u4FE1\u5EA6: ", Math.round(result.confidence), "%)")), /* @__PURE__ */ React2__default.default.createElement("pre", { className: "text-sm text-gray-800 whitespace-pre-wrap font-sans" }, result.text)), error && /* @__PURE__ */ React2__default.default.createElement("div", { className: "p-3 bg-red-50 text-red-600 text-sm rounded-lg border border-red-100" }, "\u8BC6\u522B\u5931\u8D25: ", error.message)),
|
|
179
|
+
/* @__PURE__ */ React2__default.default.createElement(
|
|
180
|
+
"input",
|
|
181
|
+
{
|
|
182
|
+
type: "file",
|
|
183
|
+
ref: fileInputRef,
|
|
184
|
+
className: "hidden",
|
|
185
|
+
accept: "image/*",
|
|
186
|
+
onChange: handleFileChange,
|
|
187
|
+
disabled: isProcessing
|
|
188
|
+
}
|
|
189
|
+
)
|
|
190
|
+
);
|
|
191
|
+
};
|
|
192
|
+
var useBackgroundRemoval = (options = {}) => {
|
|
193
|
+
const [state, setState] = React2.useState({
|
|
194
|
+
isProcessing: false,
|
|
195
|
+
progress: 0,
|
|
196
|
+
status: "idle",
|
|
197
|
+
error: null,
|
|
198
|
+
resultBlob: null,
|
|
199
|
+
resultUrl: null
|
|
200
|
+
});
|
|
201
|
+
const remove = React2.useCallback(async (image) => {
|
|
202
|
+
setState((prev) => ({
|
|
203
|
+
...prev,
|
|
204
|
+
isProcessing: true,
|
|
205
|
+
error: null,
|
|
206
|
+
progress: 0,
|
|
207
|
+
status: "initializing"
|
|
208
|
+
}));
|
|
209
|
+
try {
|
|
210
|
+
const originalKeys = Object.keys;
|
|
211
|
+
const win = typeof window !== "undefined" ? window : globalThis;
|
|
212
|
+
const originalProcess = win.process;
|
|
213
|
+
let backgroundRemoval;
|
|
214
|
+
try {
|
|
215
|
+
Object.keys = function(obj) {
|
|
216
|
+
if (obj === null || obj === void 0) return [];
|
|
217
|
+
return originalKeys.call(Object, obj);
|
|
218
|
+
};
|
|
219
|
+
if (typeof window !== "undefined") {
|
|
220
|
+
try {
|
|
221
|
+
Object.defineProperty(win, "process", {
|
|
222
|
+
value: { env: {}, versions: {}, release: { name: "node" } },
|
|
223
|
+
configurable: true,
|
|
224
|
+
writable: true
|
|
225
|
+
});
|
|
226
|
+
} catch (e) {
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
backgroundRemoval = await import('@imgly/background-removal');
|
|
230
|
+
} finally {
|
|
231
|
+
Object.keys = originalKeys;
|
|
232
|
+
if (typeof window !== "undefined" && originalProcess) {
|
|
233
|
+
try {
|
|
234
|
+
Object.defineProperty(win, "process", {
|
|
235
|
+
value: originalProcess,
|
|
236
|
+
configurable: true,
|
|
237
|
+
writable: true
|
|
238
|
+
});
|
|
239
|
+
} catch (e) {
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
const { removeBackground } = backgroundRemoval;
|
|
244
|
+
const config = {
|
|
245
|
+
progress: (status, progress) => {
|
|
246
|
+
setState((prev) => ({
|
|
247
|
+
...prev,
|
|
248
|
+
status,
|
|
249
|
+
progress
|
|
250
|
+
}));
|
|
251
|
+
options.progress?.(status, progress);
|
|
252
|
+
},
|
|
253
|
+
model: options.model || "small",
|
|
254
|
+
publicPath: options.publicPath,
|
|
255
|
+
fetchArgs: options.fetchArgs
|
|
256
|
+
};
|
|
257
|
+
const blob = await removeBackground(image, config);
|
|
258
|
+
const url = URL.createObjectURL(blob);
|
|
259
|
+
setState((prev) => ({
|
|
260
|
+
...prev,
|
|
261
|
+
isProcessing: false,
|
|
262
|
+
progress: 1,
|
|
263
|
+
status: "completed",
|
|
264
|
+
resultBlob: blob,
|
|
265
|
+
resultUrl: url
|
|
266
|
+
}));
|
|
267
|
+
return { blob, url };
|
|
268
|
+
} catch (err) {
|
|
269
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
270
|
+
console.error("AI Background Removal Error:", msg);
|
|
271
|
+
setState((prev) => ({
|
|
272
|
+
...prev,
|
|
273
|
+
isProcessing: false,
|
|
274
|
+
status: "error",
|
|
275
|
+
error: new Error(msg)
|
|
276
|
+
}));
|
|
277
|
+
throw err;
|
|
278
|
+
}
|
|
279
|
+
}, [options]);
|
|
280
|
+
const cleanup = React2.useCallback(() => {
|
|
281
|
+
if (state.resultUrl) {
|
|
282
|
+
URL.revokeObjectURL(state.resultUrl);
|
|
283
|
+
}
|
|
284
|
+
}, [state.resultUrl]);
|
|
285
|
+
React2.useEffect(() => {
|
|
286
|
+
return () => cleanup();
|
|
287
|
+
}, [cleanup]);
|
|
288
|
+
return {
|
|
289
|
+
...state,
|
|
290
|
+
remove,
|
|
291
|
+
cleanup
|
|
292
|
+
};
|
|
293
|
+
};
|
|
294
|
+
var BackgroundRemover = ({
|
|
295
|
+
onResult,
|
|
296
|
+
className = ""
|
|
297
|
+
}) => {
|
|
298
|
+
const [imagePreview, setImagePreview] = React2.useState(null);
|
|
299
|
+
const fileInputRef = React2.useRef(null);
|
|
300
|
+
const { remove, isProcessing, progress, status, resultUrl, error } = useBackgroundRemoval();
|
|
301
|
+
const handleFileChange = async (e) => {
|
|
302
|
+
const file = e.target.files?.[0];
|
|
303
|
+
if (!file) return;
|
|
304
|
+
const reader = new FileReader();
|
|
305
|
+
reader.onload = (event) => {
|
|
306
|
+
setImagePreview(event.target?.result);
|
|
307
|
+
};
|
|
308
|
+
reader.readAsDataURL(file);
|
|
309
|
+
try {
|
|
310
|
+
const { blob, url } = await remove(file);
|
|
311
|
+
onResult?.(blob, url);
|
|
312
|
+
} catch (err) {
|
|
313
|
+
console.error("Background Removal Error:", err);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
const reset = () => {
|
|
317
|
+
setImagePreview(null);
|
|
318
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
319
|
+
};
|
|
320
|
+
const downloadResult = () => {
|
|
321
|
+
if (!resultUrl) return;
|
|
322
|
+
const a = document.createElement("a");
|
|
323
|
+
a.href = resultUrl;
|
|
324
|
+
a.download = "removed_background.png";
|
|
325
|
+
a.click();
|
|
326
|
+
};
|
|
327
|
+
return /* @__PURE__ */ React2__default.default.createElement("div", { className: `p-6 border-2 border-dashed rounded-xl transition-all ${isProcessing ? "border-purple-400 bg-purple-50/10" : "border-gray-200 hover:border-purple-400"} ${className}` }, !imagePreview ? /* @__PURE__ */ React2__default.default.createElement(
|
|
328
|
+
"div",
|
|
329
|
+
{
|
|
330
|
+
className: "flex flex-col items-center justify-center cursor-pointer space-y-4",
|
|
331
|
+
onClick: () => fileInputRef.current?.click()
|
|
332
|
+
},
|
|
333
|
+
/* @__PURE__ */ React2__default.default.createElement("div", { className: "p-4 bg-purple-50 rounded-full text-purple-500" }, /* @__PURE__ */ React2__default.default.createElement(lucideReact.Eraser, { size: 32 })),
|
|
334
|
+
/* @__PURE__ */ React2__default.default.createElement("div", { className: "text-center" }, /* @__PURE__ */ React2__default.default.createElement("p", { className: "text-lg font-medium text-gray-700" }, "\u4E0A\u4F20\u56FE\u7247\u79FB\u9664\u80CC\u666F"), /* @__PURE__ */ React2__default.default.createElement("p", { className: "text-sm text-gray-500" }, "\u5EFA\u8BAE\u4F7F\u7528\u4E3B\u4F53\u660E\u786E\u7684\u56FE\u7247"))
|
|
335
|
+
) : /* @__PURE__ */ React2__default.default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React2__default.default.createElement("p", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider" }, "\u539F\u56FE"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "relative rounded-lg overflow-hidden border border-gray-200 bg-gray-50" }, /* @__PURE__ */ React2__default.default.createElement("img", { src: imagePreview, alt: "Original", className: "max-h-64 mx-auto object-contain" }))), /* @__PURE__ */ React2__default.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React2__default.default.createElement("p", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider" }, "\u5904\u7406\u7ED3\u679C"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "relative rounded-lg overflow-hidden border border-gray-200 bg-grid-slate-100 bg-[size:20px_20px]" }, resultUrl ? /* @__PURE__ */ React2__default.default.createElement("img", { src: resultUrl, alt: "Result", className: "max-h-64 mx-auto object-contain animate-in fade-in zoom-in-95 duration-500" }) : /* @__PURE__ */ React2__default.default.createElement("div", { className: "h-64 flex flex-col items-center justify-center text-gray-400" }, isProcessing ? /* @__PURE__ */ React2__default.default.createElement(React2__default.default.Fragment, null, /* @__PURE__ */ React2__default.default.createElement(lucideReact.Loader2, { className: "animate-spin text-purple-500 mb-2", size: 32 }), /* @__PURE__ */ React2__default.default.createElement("div", { className: "w-32 bg-gray-200 rounded-full h-1.5 overflow-hidden" }, /* @__PURE__ */ React2__default.default.createElement(
|
|
336
|
+
"div",
|
|
337
|
+
{
|
|
338
|
+
className: "bg-purple-500 h-full transition-all duration-300",
|
|
339
|
+
style: { width: `${progress * 100}%` }
|
|
340
|
+
}
|
|
341
|
+
)), /* @__PURE__ */ React2__default.default.createElement("p", { className: "text-[10px] mt-2 font-mono uppercase" }, status.replace(/-/g, " "))) : /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-sm italic" }, "\u7B49\u5F85\u5904\u7406..."))))), /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex justify-between items-center pt-2" }, !isProcessing && /* @__PURE__ */ React2__default.default.createElement(
|
|
342
|
+
"button",
|
|
343
|
+
{
|
|
344
|
+
onClick: reset,
|
|
345
|
+
className: "flex items-center gap-2 px-4 py-2 text-sm font-medium text-gray-600 hover:text-gray-900 transition-colors"
|
|
346
|
+
},
|
|
347
|
+
/* @__PURE__ */ React2__default.default.createElement(lucideReact.X, { size: 16 }),
|
|
348
|
+
"\u91CD\u65B0\u5F00\u59CB"
|
|
349
|
+
), resultUrl && !isProcessing && /* @__PURE__ */ React2__default.default.createElement(
|
|
350
|
+
"button",
|
|
351
|
+
{
|
|
352
|
+
onClick: downloadResult,
|
|
353
|
+
className: "flex items-center gap-2 px-6 py-2 bg-purple-600 hover:bg-purple-700 text-white rounded-lg shadow-sm transition-all"
|
|
354
|
+
},
|
|
355
|
+
/* @__PURE__ */ React2__default.default.createElement(lucideReact.Download, { size: 16 }),
|
|
356
|
+
"\u4E0B\u8F7D PNG"
|
|
357
|
+
)), error && /* @__PURE__ */ React2__default.default.createElement("div", { className: "p-3 bg-red-50 text-red-600 text-sm rounded-lg border border-red-100" }, "\u5904\u7406\u5931\u8D25: ", error.message)), /* @__PURE__ */ React2__default.default.createElement(
|
|
358
|
+
"input",
|
|
359
|
+
{
|
|
360
|
+
type: "file",
|
|
361
|
+
ref: fileInputRef,
|
|
362
|
+
className: "hidden",
|
|
363
|
+
accept: "image/*",
|
|
364
|
+
onChange: handleFileChange,
|
|
365
|
+
disabled: isProcessing
|
|
366
|
+
}
|
|
367
|
+
));
|
|
368
|
+
};
|
|
369
|
+
var useSentimentAnalysis = (options = {}) => {
|
|
370
|
+
const [state, setState] = React2.useState({
|
|
371
|
+
isProcessing: false,
|
|
372
|
+
status: "idle",
|
|
373
|
+
error: null,
|
|
374
|
+
result: null
|
|
375
|
+
});
|
|
376
|
+
const pipelineRef = React2.useRef(null);
|
|
377
|
+
const analyze = React2.useCallback(async (text) => {
|
|
378
|
+
setState((prev) => ({
|
|
379
|
+
...prev,
|
|
380
|
+
isProcessing: true,
|
|
381
|
+
error: null,
|
|
382
|
+
status: "loading model"
|
|
383
|
+
}));
|
|
384
|
+
try {
|
|
385
|
+
if (!pipelineRef.current) {
|
|
386
|
+
const originalKeys = Object.keys;
|
|
387
|
+
const win = typeof window !== "undefined" ? window : globalThis;
|
|
388
|
+
const originalProcess = win.process;
|
|
389
|
+
let transformers;
|
|
390
|
+
try {
|
|
391
|
+
Object.keys = function(obj) {
|
|
392
|
+
if (obj === null || obj === void 0) return [];
|
|
393
|
+
return originalKeys.call(Object, obj);
|
|
394
|
+
};
|
|
395
|
+
if (typeof window !== "undefined") {
|
|
396
|
+
try {
|
|
397
|
+
Object.defineProperty(win, "process", {
|
|
398
|
+
value: { env: {}, versions: {}, release: { name: "node" }, nextTick: (cb) => setTimeout(cb, 0) },
|
|
399
|
+
configurable: true,
|
|
400
|
+
writable: true
|
|
401
|
+
});
|
|
402
|
+
} catch (e) {
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
transformers = await import('@xenova/transformers');
|
|
406
|
+
} finally {
|
|
407
|
+
Object.keys = originalKeys;
|
|
408
|
+
if (typeof window !== "undefined" && originalProcess) {
|
|
409
|
+
try {
|
|
410
|
+
Object.defineProperty(win, "process", { value: originalProcess, configurable: true, writable: true });
|
|
411
|
+
} catch (e) {
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const { pipeline, env } = transformers;
|
|
416
|
+
env.allowLocalModels = false;
|
|
417
|
+
if (env.backends?.onnx) {
|
|
418
|
+
env.backends.onnx.wasm.proxy = true;
|
|
419
|
+
}
|
|
420
|
+
const defaultModel = "Xenova/distilbert-base-multilingual-cased-sentiments-student";
|
|
421
|
+
pipelineRef.current = await pipeline("sentiment-analysis", options.model || defaultModel);
|
|
422
|
+
}
|
|
423
|
+
setState((prev) => ({ ...prev, status: "analyzing" }));
|
|
424
|
+
const output = await pipelineRef.current(text);
|
|
425
|
+
const resultData = output[0];
|
|
426
|
+
const label = resultData.label.toLowerCase();
|
|
427
|
+
let sentiment = "neutral";
|
|
428
|
+
const negativeKeywords = ["\u7D2F", "\u60E8", "\u7EDD\u671B", "\u96BE\u53D7", "\u4F24\u5FC3", "\u5DEE", "\u574F", "\u7CDF", "\u4E0D\u884C"];
|
|
429
|
+
const hasNegativeKeyword = negativeKeywords.some((k) => text.includes(k));
|
|
430
|
+
if (label.includes("positive") && !hasNegativeKeyword) {
|
|
431
|
+
sentiment = "positive";
|
|
432
|
+
} else if (label.includes("negative") || label.includes("0") || hasNegativeKeyword) {
|
|
433
|
+
sentiment = "negative";
|
|
434
|
+
}
|
|
435
|
+
const result = {
|
|
436
|
+
label: resultData.label,
|
|
437
|
+
score: resultData.score,
|
|
438
|
+
sentiment
|
|
439
|
+
};
|
|
440
|
+
setState((prev) => ({
|
|
441
|
+
...prev,
|
|
442
|
+
isProcessing: false,
|
|
443
|
+
status: "completed",
|
|
444
|
+
result
|
|
445
|
+
}));
|
|
446
|
+
return result;
|
|
447
|
+
} catch (err) {
|
|
448
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
449
|
+
console.error("AI Sentiment Error:", msg);
|
|
450
|
+
setState((prev) => ({ ...prev, isProcessing: false, status: "error", error: new Error(msg) }));
|
|
451
|
+
throw err;
|
|
452
|
+
}
|
|
453
|
+
}, [options.model]);
|
|
454
|
+
return { ...state, analyze };
|
|
455
|
+
};
|
|
456
|
+
var SentimentAnalyzer = ({
|
|
457
|
+
onResult,
|
|
458
|
+
className = "",
|
|
459
|
+
placeholder = "\u8F93\u5165\u4E00\u6BB5\u4E2D\u6587\u6216\u82F1\u6587\uFF0C\u5206\u6790\u5176\u60C5\u611F\u503E\u5411..."
|
|
460
|
+
}) => {
|
|
461
|
+
const [text, setText] = React2.useState("");
|
|
462
|
+
const { analyze, isProcessing, status, result, error } = useSentimentAnalysis();
|
|
463
|
+
const handleAnalyze = async () => {
|
|
464
|
+
if (!text.trim() || isProcessing) return;
|
|
465
|
+
try {
|
|
466
|
+
const res = await analyze(text);
|
|
467
|
+
onResult?.(res);
|
|
468
|
+
} catch (err) {
|
|
469
|
+
console.error("Sentiment Analysis Error:", err);
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
const getSentimentIcon = () => {
|
|
473
|
+
if (!result) return null;
|
|
474
|
+
switch (result.sentiment) {
|
|
475
|
+
case "positive":
|
|
476
|
+
return /* @__PURE__ */ React2__default.default.createElement(lucideReact.Smile, { className: "text-green-500", size: 24 });
|
|
477
|
+
case "negative":
|
|
478
|
+
return /* @__PURE__ */ React2__default.default.createElement(lucideReact.Frown, { className: "text-red-500", size: 24 });
|
|
479
|
+
default:
|
|
480
|
+
return /* @__PURE__ */ React2__default.default.createElement(lucideReact.Meh, { className: "text-yellow-500", size: 24 });
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
const getSentimentColor = () => {
|
|
484
|
+
if (!result) return "";
|
|
485
|
+
switch (result.sentiment) {
|
|
486
|
+
case "positive":
|
|
487
|
+
return "bg-green-50 border-green-200 text-green-700";
|
|
488
|
+
case "negative":
|
|
489
|
+
return "bg-red-50 border-red-200 text-red-700";
|
|
490
|
+
default:
|
|
491
|
+
return "bg-yellow-50 border-yellow-200 text-yellow-700";
|
|
492
|
+
}
|
|
493
|
+
};
|
|
494
|
+
return /* @__PURE__ */ React2__default.default.createElement("div", { className: `p-6 border rounded-xl bg-white dark:bg-gray-800 shadow-sm ${className}` }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center gap-2 mb-4 text-gray-700 dark:text-gray-300 font-medium" }, /* @__PURE__ */ React2__default.default.createElement(lucideReact.MessageSquare, { size: 20 }), /* @__PURE__ */ React2__default.default.createElement("span", null, "\u6587\u672C\u60C5\u611F\u5206\u6790")), /* @__PURE__ */ React2__default.default.createElement("div", { className: "relative" }, /* @__PURE__ */ React2__default.default.createElement(
|
|
495
|
+
"textarea",
|
|
496
|
+
{
|
|
497
|
+
value: text,
|
|
498
|
+
onChange: (e) => setText(e.target.value),
|
|
499
|
+
placeholder,
|
|
500
|
+
className: "w-full h-32 p-4 bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all outline-none resize-none text-gray-800 dark:text-gray-200",
|
|
501
|
+
disabled: isProcessing
|
|
502
|
+
}
|
|
503
|
+
), /* @__PURE__ */ React2__default.default.createElement(
|
|
504
|
+
"button",
|
|
505
|
+
{
|
|
506
|
+
onClick: handleAnalyze,
|
|
507
|
+
disabled: !text.trim() || isProcessing,
|
|
508
|
+
className: "absolute bottom-3 right-3 p-2 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white rounded-md transition-colors shadow-sm"
|
|
509
|
+
},
|
|
510
|
+
isProcessing ? /* @__PURE__ */ React2__default.default.createElement(lucideReact.Loader2, { className: "animate-spin", size: 18 }) : /* @__PURE__ */ React2__default.default.createElement(lucideReact.Send, { size: 18 })
|
|
511
|
+
)), isProcessing && /* @__PURE__ */ React2__default.default.createElement("div", { className: "mt-4 flex items-center gap-2 text-sm text-blue-600 animate-pulse" }, /* @__PURE__ */ React2__default.default.createElement(lucideReact.Loader2, { size: 14, className: "animate-spin" }), /* @__PURE__ */ React2__default.default.createElement("span", null, "\u6B63\u5728\u5206\u6790 (\u9996\u6B21\u8FD0\u884C\u5C06\u52A0\u8F7D\u6A21\u578B\u8D44\u6E90)...")), result && !isProcessing && /* @__PURE__ */ React2__default.default.createElement("div", { className: `mt-4 p-4 border rounded-lg flex items-center gap-4 animate-in fade-in slide-in-from-top-2 ${getSentimentColor()}` }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "p-2 bg-white rounded-full shadow-sm" }, getSentimentIcon()), /* @__PURE__ */ React2__default.default.createElement("div", null, /* @__PURE__ */ React2__default.default.createElement("p", { className: "font-bold text-lg capitalize" }, result.sentiment), /* @__PURE__ */ React2__default.default.createElement("p", { className: "text-sm opacity-80" }, "\u7F6E\u4FE1\u5EA6: ", (result.score * 100).toFixed(1), "% (", result.label, ")"))), error && /* @__PURE__ */ React2__default.default.createElement("div", { className: "mt-4 p-3 bg-red-50 text-red-600 text-sm rounded-lg border border-red-100" }, "\u5206\u6790\u5931\u8D25: ", error.message));
|
|
512
|
+
};
|
|
513
|
+
var useTextGeneration = (options = {}) => {
|
|
514
|
+
const [state, setState] = React2.useState({
|
|
515
|
+
isProcessing: false,
|
|
516
|
+
status: "idle",
|
|
517
|
+
error: null,
|
|
518
|
+
result: null
|
|
519
|
+
});
|
|
520
|
+
const pipelineRef = React2.useRef(null);
|
|
521
|
+
const generate = React2.useCallback(async (prompt) => {
|
|
522
|
+
console.log("[AI] Generating for prompt:", prompt);
|
|
523
|
+
setState((prev) => ({
|
|
524
|
+
...prev,
|
|
525
|
+
isProcessing: true,
|
|
526
|
+
error: null,
|
|
527
|
+
status: "initializing"
|
|
528
|
+
}));
|
|
529
|
+
try {
|
|
530
|
+
if (!pipelineRef.current) {
|
|
531
|
+
const originalKeys = Object.keys;
|
|
532
|
+
const win = typeof window !== "undefined" ? window : globalThis;
|
|
533
|
+
const originalProcess = win.process;
|
|
534
|
+
let transformers;
|
|
535
|
+
try {
|
|
536
|
+
Object.keys = function(obj) {
|
|
537
|
+
if (obj === null || obj === void 0) return [];
|
|
538
|
+
return originalKeys.call(Object, obj);
|
|
539
|
+
};
|
|
540
|
+
if (typeof window !== "undefined") {
|
|
541
|
+
try {
|
|
542
|
+
Object.defineProperty(win, "process", {
|
|
543
|
+
value: { env: {}, versions: {}, release: { name: "node" }, nextTick: (cb) => setTimeout(cb, 0), cwd: () => "/", browser: true },
|
|
544
|
+
configurable: true,
|
|
545
|
+
writable: true
|
|
546
|
+
});
|
|
547
|
+
} catch (e) {
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
transformers = await import('@xenova/transformers');
|
|
551
|
+
} finally {
|
|
552
|
+
Object.keys = originalKeys;
|
|
553
|
+
if (typeof window !== "undefined" && originalProcess) {
|
|
554
|
+
try {
|
|
555
|
+
Object.defineProperty(win, "process", { value: originalProcess, configurable: true, writable: true });
|
|
556
|
+
} catch (e) {
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
const { pipeline, env } = transformers;
|
|
561
|
+
env.allowLocalModels = false;
|
|
562
|
+
if (env.backends?.onnx) {
|
|
563
|
+
env.backends.onnx.wasm.proxy = true;
|
|
564
|
+
}
|
|
565
|
+
const modelName = options.model || "Xenova/LaMini-Flan-T5-77M";
|
|
566
|
+
pipelineRef.current = await pipeline("text2text-generation", modelName, {
|
|
567
|
+
progress_callback: (info) => {
|
|
568
|
+
if (info.status === "progress") {
|
|
569
|
+
setState((prev) => ({ ...prev, status: `loading model: ${Math.round(info.progress)}%` }));
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
setState((prev) => ({ ...prev, status: "thinking" }));
|
|
575
|
+
const output = await pipelineRef.current(prompt, {
|
|
576
|
+
max_new_tokens: options.max_new_tokens || 64,
|
|
577
|
+
temperature: options.temperature || 0.5,
|
|
578
|
+
// 稍微提高温度
|
|
579
|
+
do_sample: true,
|
|
580
|
+
// 开启采样,避免空输出
|
|
581
|
+
top_k: 50,
|
|
582
|
+
repetition_penalty: 1.1
|
|
583
|
+
});
|
|
584
|
+
const result = output[0].generated_text || "";
|
|
585
|
+
console.log("[AI] Raw result:", result);
|
|
586
|
+
setState((prev) => ({
|
|
587
|
+
...prev,
|
|
588
|
+
isProcessing: false,
|
|
589
|
+
status: "completed",
|
|
590
|
+
result
|
|
591
|
+
}));
|
|
592
|
+
return result;
|
|
593
|
+
} catch (err) {
|
|
594
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
595
|
+
console.error("[AI] Error:", err);
|
|
596
|
+
setState((prev) => ({ ...prev, isProcessing: false, status: "error", error: new Error(msg) }));
|
|
597
|
+
throw err;
|
|
598
|
+
}
|
|
599
|
+
}, [options.model, options.max_new_tokens, options.temperature]);
|
|
600
|
+
return { ...state, generate };
|
|
601
|
+
};
|
|
602
|
+
var SmartAssistant = ({ className = "" }) => {
|
|
603
|
+
const [input, setInput] = React2.useState("");
|
|
604
|
+
const [chatHistory, setChatHistory] = React2.useState([]);
|
|
605
|
+
const scrollRef = React2.useRef(null);
|
|
606
|
+
const { generate, isProcessing: isGenerating, status: genStatus } = useTextGeneration();
|
|
607
|
+
React2.useEffect(() => {
|
|
608
|
+
if (scrollRef.current) {
|
|
609
|
+
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
|
610
|
+
}
|
|
611
|
+
}, [chatHistory, isGenerating]);
|
|
612
|
+
const handleSend = async () => {
|
|
613
|
+
if (!input.trim() || isGenerating) return;
|
|
614
|
+
const userMessage = input.trim();
|
|
615
|
+
setInput("");
|
|
616
|
+
setChatHistory((prev) => [...prev, { role: "user", content: userMessage }]);
|
|
617
|
+
let finalContent = "";
|
|
618
|
+
const lowerMessage = userMessage.toLowerCase();
|
|
619
|
+
if (lowerMessage.includes("\u4F60\u597D") || lowerMessage.includes("hello") || lowerMessage.includes("hi")) {
|
|
620
|
+
finalContent = "\u4F60\u597D\u5440\uFF01\u6211\u662F sa2kit \u7684\u672C\u5730 AI \u52A9\u624B\uFF0C\u5F88\u9AD8\u5174\u80FD\u548C\u4F60\u804A\u5929\u3002\u{1F60A}";
|
|
621
|
+
} else if (lowerMessage.includes("\u8C01") || lowerMessage.includes("who are you")) {
|
|
622
|
+
finalContent = "\u6211\u662F\u4E00\u4E2A\u5B8C\u5168\u8FD0\u884C\u5728\u4F60\u6D4F\u89C8\u5668\u672C\u5730\u7684\u5C0F\u578B AI \u6A21\u578B\uFF0C\u6211\u4E0D\u9700\u8981\u670D\u52A1\u5668\uFF0C\u975E\u5E38\u4FDD\u62A4\u4F60\u7684\u9690\u79C1\u3002";
|
|
623
|
+
} else if (lowerMessage.includes("\u5929\u6C14")) {
|
|
624
|
+
finalContent = "\u867D\u7136\u6211\u770B\u4E0D\u89C1\u5916\u9762\u7684\u9633\u5149\uFF0C\u4F46\u542C\u4F60\u7684\u8BED\u6C14\uFF0C\u4ECA\u5929\u4E00\u5B9A\u662F\u4E2A\u9002\u5408\u51FA\u95E8\u7684\u597D\u5929\u6C14\uFF01\u2600\uFE0F";
|
|
625
|
+
} else if (lowerMessage.includes("\u7D2F") || lowerMessage.includes("\u96BE\u8FC7") || lowerMessage.includes("\u7EDD\u671B")) {
|
|
626
|
+
finalContent = "\u542C\u8D77\u6765\u4F60\u73B0\u5728\u5FC3\u60C5\u4E0D\u592A\u597D... \u62B1\u62B1\u4F60\uFF0C\u6211\u4F1A\u4E00\u76F4\u5728\u8FD9\u91CC\u966A\u4F60\u804A\u5929\u7684\u3002\u2764\uFE0F";
|
|
627
|
+
}
|
|
628
|
+
if (finalContent) {
|
|
629
|
+
setTimeout(() => {
|
|
630
|
+
setChatHistory((prev) => [...prev, { role: "assistant", content: finalContent }]);
|
|
631
|
+
}, 500);
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
const prompt = `\u5BF9\u8BDD\u3002
|
|
635
|
+
\u4EBA\u8BF4\uFF1A\u201C${userMessage}\u201D
|
|
636
|
+
AI\u56DE\u5E94\uFF1A\u201C`;
|
|
637
|
+
try {
|
|
638
|
+
const response = await generate(prompt);
|
|
639
|
+
let modelOutput = response.replace(/^AI回应:|^AI:|^Assistant:|^回答:|^答:|^Answer:/i, "").replace(/[. ]*Positive[. ]*|[. ]*Negative[. ]*|[. ]*Neutral[. ]*/gi, "").replace(/^["'“]|["'”]$/g, "").trim();
|
|
640
|
+
const isEnglishTrash = /[a-zA-Z]{5,}/.test(modelOutput) && !/[一-龥]/.test(modelOutput);
|
|
641
|
+
const isTooShort = modelOutput.length < 1;
|
|
642
|
+
if (isEnglishTrash || isTooShort) {
|
|
643
|
+
console.warn("[AI] Model failure, triggering smart recovery. Raw was:", response);
|
|
644
|
+
modelOutput = "\u55EF\u55EF\uFF0C\u6211\u6B63\u5728\u542C\u3002\u5173\u4E8E\u201C" + userMessage.slice(0, 6) + "...\u201D\uFF0C\u4F60\u8FD8\u6709\u4EC0\u4E48\u60F3\u5206\u4EAB\u7684\u5417\uFF1F";
|
|
645
|
+
}
|
|
646
|
+
setChatHistory((prev) => [...prev, { role: "assistant", content: modelOutput }]);
|
|
647
|
+
} catch (err) {
|
|
648
|
+
setChatHistory((prev) => [...prev, { role: "assistant", content: "\uFF08\u672C\u5730\u6A21\u578B\u601D\u8003\u8FC7\u5EA6\uFF0C\u6682\u65F6\u4F11\u606F\u4E2D...\uFF09" }]);
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
return /* @__PURE__ */ React2__default.default.createElement("div", { className: `flex flex-col h-[500px] bg-white dark:bg-gray-800 rounded-xl shadow-inner border border-gray-100 dark:border-gray-700 overflow-hidden ${className}` }, /* @__PURE__ */ React2__default.default.createElement("div", { ref: scrollRef, className: "flex-1 overflow-y-auto p-4 space-y-4 bg-gray-50/50 dark:bg-gray-900/50" }, chatHistory.length === 0 && /* @__PURE__ */ React2__default.default.createElement("div", { className: "h-full flex flex-col items-center justify-center text-gray-400 space-y-2" }, /* @__PURE__ */ React2__default.default.createElement(lucideReact.Bot, { size: 48, className: "opacity-20" }), /* @__PURE__ */ React2__default.default.createElement("p", { className: "text-sm italic text-center px-8 text-gray-400 font-sans" }, "\u4F60\u597D\uFF01\u6211\u662F 100% \u672C\u5730\u8FD0\u884C\u7684 AI\u3002", /* @__PURE__ */ React2__default.default.createElement("br", null), "\u4F60\u53EF\u4EE5\u548C\u6211\u804A\u804A\u5929\uFF0C\u6211\u4F1A\u5C1D\u8BD5\u7406\u89E3\u4F60\u7684\u610F\u601D\u3002")), chatHistory.map((msg, i) => /* @__PURE__ */ React2__default.default.createElement("div", { key: i, className: `flex ${msg.role === "user" ? "justify-end" : "justify-start"} animate-in fade-in slide-in-from-bottom-2` }, /* @__PURE__ */ React2__default.default.createElement("div", { className: `flex gap-3 max-w-[85%] ${msg.role === "user" ? "flex-row-reverse" : ""}` }, /* @__PURE__ */ React2__default.default.createElement("div", { className: `p-2 rounded-lg h-fit ${msg.role === "user" ? "bg-blue-100 text-blue-600" : "bg-white dark:bg-gray-700 shadow-sm border border-gray-100 dark:border-gray-600 text-gray-400"}` }, msg.role === "user" ? /* @__PURE__ */ React2__default.default.createElement(lucideReact.User, { size: 18 }) : /* @__PURE__ */ React2__default.default.createElement(lucideReact.Bot, { size: 18 })), /* @__PURE__ */ React2__default.default.createElement("div", { className: `p-3 rounded-2xl shadow-sm text-sm ${msg.role === "user" ? "bg-blue-600 text-white rounded-tr-none" : "bg-white dark:bg-gray-700 text-gray-800 dark:text-gray-200 rounded-tl-none border border-gray-100 dark:border-gray-600 leading-relaxed"}` }, msg.content)))), isGenerating && /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex justify-start" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex gap-3 items-center bg-white dark:bg-gray-700 p-3 rounded-2xl rounded-tl-none border border-gray-100 dark:border-gray-600" }, /* @__PURE__ */ React2__default.default.createElement(lucideReact.Loader2, { className: "animate-spin text-blue-500", size: 16 }), /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-xs text-gray-500 font-medium" }, "\u601D\u8003\u4E2D..."), /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-[10px] text-blue-400 font-mono tracking-tighter" }, genStatus))))), /* @__PURE__ */ React2__default.default.createElement("div", { className: "p-4 bg-white dark:bg-gray-800 border-t border-gray-100 dark:border-gray-700" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "relative flex items-center gap-2" }, /* @__PURE__ */ React2__default.default.createElement(
|
|
652
|
+
"input",
|
|
653
|
+
{
|
|
654
|
+
type: "text",
|
|
655
|
+
value: input,
|
|
656
|
+
onChange: (e) => setInput(e.target.value),
|
|
657
|
+
onKeyDown: (e) => e.key === "Enter" && handleSend(),
|
|
658
|
+
placeholder: "\u8F93\u5165\u6587\u5B57...",
|
|
659
|
+
className: "flex-1 bg-gray-50 dark:bg-gray-900 border-none rounded-full px-5 py-3 pr-12 text-sm focus:ring-2 focus:ring-blue-500 outline-none dark:text-white text-gray-800",
|
|
660
|
+
disabled: isGenerating
|
|
661
|
+
}
|
|
662
|
+
), /* @__PURE__ */ React2__default.default.createElement(
|
|
663
|
+
"button",
|
|
664
|
+
{
|
|
665
|
+
onClick: handleSend,
|
|
666
|
+
disabled: !input.trim() || isGenerating,
|
|
667
|
+
className: "absolute right-1 p-2.5 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white rounded-full transition-all shadow-md active:scale-95 flex items-center justify-center"
|
|
668
|
+
},
|
|
669
|
+
/* @__PURE__ */ React2__default.default.createElement(lucideReact.Send, { size: 18 })
|
|
670
|
+
))));
|
|
671
|
+
};
|
|
10
672
|
|
|
11
673
|
Object.defineProperty(exports, "arrayUtils", {
|
|
12
674
|
enumerable: true,
|
|
@@ -80,5 +742,13 @@ Object.defineProperty(exports, "logger", {
|
|
|
80
742
|
enumerable: true,
|
|
81
743
|
get: function () { return chunk6PRFP5EG_js.logger; }
|
|
82
744
|
});
|
|
745
|
+
exports.BackgroundRemover = BackgroundRemover;
|
|
746
|
+
exports.OCRScanner = OCRScanner;
|
|
747
|
+
exports.SentimentAnalyzer = SentimentAnalyzer;
|
|
748
|
+
exports.SmartAssistant = SmartAssistant;
|
|
749
|
+
exports.useBackgroundRemoval = useBackgroundRemoval;
|
|
750
|
+
exports.useOCR = useOCR;
|
|
751
|
+
exports.useSentimentAnalysis = useSentimentAnalysis;
|
|
752
|
+
exports.useTextGeneration = useTextGeneration;
|
|
83
753
|
//# sourceMappingURL=index.js.map
|
|
84
754
|
//# sourceMappingURL=index.js.map
|