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.
Files changed (63) hide show
  1. package/dist/ConfigService-7MEZXKJ5.js +21 -0
  2. package/dist/ConfigService-7MEZXKJ5.js.map +1 -0
  3. package/dist/ConfigService-BV57YYFW.mjs +4 -0
  4. package/dist/ConfigService-BV57YYFW.mjs.map +1 -0
  5. package/dist/ConfigService-BxK06xP6.d.mts +262 -0
  6. package/dist/ConfigService-BxK06xP6.d.ts +262 -0
  7. package/dist/audioDetection/index.d.mts +449 -0
  8. package/dist/audioDetection/index.d.ts +449 -0
  9. package/dist/audioDetection/index.js +1244 -0
  10. package/dist/audioDetection/index.js.map +1 -0
  11. package/dist/audioDetection/index.mjs +1227 -0
  12. package/dist/audioDetection/index.mjs.map +1 -0
  13. package/dist/chunk-5XUE72Y3.mjs +1001 -0
  14. package/dist/chunk-5XUE72Y3.mjs.map +1 -0
  15. package/dist/chunk-DQVPZTVC.js +1009 -0
  16. package/dist/chunk-DQVPZTVC.js.map +1 -0
  17. package/dist/chunk-NEPD75MX.mjs +467 -0
  18. package/dist/chunk-NEPD75MX.mjs.map +1 -0
  19. package/dist/chunk-OEDY7GI4.js +473 -0
  20. package/dist/chunk-OEDY7GI4.js.map +1 -0
  21. package/dist/chunk-TFQF2HDO.mjs +354 -0
  22. package/dist/chunk-TFQF2HDO.mjs.map +1 -0
  23. package/dist/chunk-TOC5FSHP.js +358 -0
  24. package/dist/chunk-TOC5FSHP.js.map +1 -0
  25. package/dist/imageCrop/index.d.mts +165 -0
  26. package/dist/imageCrop/index.d.ts +165 -0
  27. package/dist/imageCrop/index.js +559 -0
  28. package/dist/imageCrop/index.js.map +1 -0
  29. package/dist/imageCrop/index.mjs +540 -0
  30. package/dist/imageCrop/index.mjs.map +1 -0
  31. package/dist/index.d.mts +139 -0
  32. package/dist/index.d.ts +139 -0
  33. package/dist/index.js +670 -0
  34. package/dist/index.js.map +1 -1
  35. package/dist/index.mjs +662 -0
  36. package/dist/index.mjs.map +1 -1
  37. package/dist/mmd/index.d.mts +113 -2
  38. package/dist/mmd/index.d.ts +113 -2
  39. package/dist/mmd/index.js +484 -2
  40. package/dist/mmd/index.js.map +1 -1
  41. package/dist/mmd/index.mjs +482 -4
  42. package/dist/mmd/index.mjs.map +1 -1
  43. package/dist/testYourself/admin/index.d.mts +58 -0
  44. package/dist/testYourself/admin/index.d.ts +58 -0
  45. package/dist/testYourself/admin/index.js +17 -0
  46. package/dist/testYourself/admin/index.js.map +1 -0
  47. package/dist/testYourself/admin/index.mjs +4 -0
  48. package/dist/testYourself/admin/index.mjs.map +1 -0
  49. package/dist/testYourself/index.d.mts +6 -98
  50. package/dist/testYourself/index.d.ts +6 -98
  51. package/dist/testYourself/index.js +90 -334
  52. package/dist/testYourself/index.js.map +1 -1
  53. package/dist/testYourself/index.mjs +47 -333
  54. package/dist/testYourself/index.mjs.map +1 -1
  55. package/dist/testYourself/server/index.d.mts +1029 -0
  56. package/dist/testYourself/server/index.d.ts +1029 -0
  57. package/dist/testYourself/server/index.js +42 -0
  58. package/dist/testYourself/server/index.js.map +1 -0
  59. package/dist/testYourself/server/index.mjs +5 -0
  60. package/dist/testYourself/server/index.mjs.map +1 -0
  61. package/dist/universalFile/server/index.js +5 -5
  62. package/dist/universalFile/server/index.mjs +1 -1
  63. 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