@widgetic/chat 0.1.4 → 0.1.5
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/components/Chat.svelte +205 -81
- package/dist/components/Chat.svelte.d.ts +12 -2
- package/dist/components/ChatMessages.svelte +68 -15
- package/dist/config.js +6 -6
- package/dist/constants/colors.js +1 -1
- package/dist/services/chatService.js +169 -280
- package/dist/stores/chatStore.d.ts +1 -0
- package/dist/stores/chatStore.js +214 -113
- package/dist/types/attachment.js +1 -1
- package/dist/types/config.d.ts +5 -0
- package/dist/types/config.js +2 -1
- package/dist/utils/fileUtils.js +57 -108
- package/dist/utils/logger.js +7 -19
- package/package.json +1 -1
- package/dist/types/api-temp.d.ts +0 -61
- package/dist/types/api-temp.js +0 -42
package/dist/utils/fileUtils.js
CHANGED
|
@@ -1,43 +1,7 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
12
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
-
function step(op) {
|
|
15
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
-
switch (op[0]) {
|
|
20
|
-
case 0: case 1: t = op; break;
|
|
21
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
-
default:
|
|
25
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
-
if (t[2]) _.ops.pop();
|
|
30
|
-
_.trys.pop(); continue;
|
|
31
|
-
}
|
|
32
|
-
op = body.call(thisArg, _);
|
|
33
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
1
|
/**
|
|
38
2
|
* File type configuration mapping
|
|
39
3
|
*/
|
|
40
|
-
export
|
|
4
|
+
export const fileTypeConfig = {
|
|
41
5
|
image: {
|
|
42
6
|
type: 'image',
|
|
43
7
|
icon: 'image',
|
|
@@ -73,7 +37,7 @@ export var fileTypeConfig = {
|
|
|
73
37
|
export function detectFileType(mimeType, fileName) {
|
|
74
38
|
// Check by file extension first for special cases
|
|
75
39
|
if (fileName) {
|
|
76
|
-
|
|
40
|
+
const extension = getFileExtension(fileName);
|
|
77
41
|
if (extension === 'mermaid' || extension === 'md') {
|
|
78
42
|
return 'document';
|
|
79
43
|
}
|
|
@@ -96,33 +60,33 @@ export function detectFileType(mimeType, fileName) {
|
|
|
96
60
|
* Validate a file for upload
|
|
97
61
|
*/
|
|
98
62
|
export function validateFile(file, config) {
|
|
99
|
-
|
|
100
|
-
|
|
63
|
+
const fileType = detectFileType(file.type, file.name);
|
|
64
|
+
const typeConfig = fileTypeConfig[fileType];
|
|
101
65
|
// Check file size
|
|
102
|
-
|
|
66
|
+
const maxSize = config?.maxSize || typeConfig.maxSize;
|
|
103
67
|
if (file.size > maxSize) {
|
|
104
68
|
return {
|
|
105
69
|
valid: false,
|
|
106
|
-
error:
|
|
70
|
+
error: `File too large. Maximum size is ${formatFileSize(maxSize)}`,
|
|
107
71
|
code: 'FILE_TOO_LARGE'
|
|
108
72
|
};
|
|
109
73
|
}
|
|
110
74
|
// Check file type - handle both MIME types and file extensions
|
|
111
|
-
|
|
112
|
-
|
|
75
|
+
const allowedTypes = config?.allowedTypes || typeConfig.accept;
|
|
76
|
+
const extension = getFileExtension(file.name);
|
|
113
77
|
if (!allowedTypes.includes('*/*')) {
|
|
114
78
|
// Check if MIME type is allowed
|
|
115
|
-
|
|
79
|
+
const mimeTypeAllowed = allowedTypes.includes(file.type);
|
|
116
80
|
// Check if file extension is explicitly allowed (e.g., .mermaid)
|
|
117
|
-
|
|
81
|
+
const extensionAllowed = allowedTypes.includes(`.${extension}`) || allowedTypes.includes(extension);
|
|
118
82
|
// Special handling for .mermaid and .md files with text/plain MIME type
|
|
119
|
-
|
|
83
|
+
const isSpecialTextFile = (extension === 'mermaid' || extension === 'md') &&
|
|
120
84
|
file.type === 'text/plain' &&
|
|
121
85
|
(allowedTypes.includes('text/plain') || allowedTypes.includes('text/markdown'));
|
|
122
86
|
if (!mimeTypeAllowed && !extensionAllowed && !isSpecialTextFile) {
|
|
123
87
|
return {
|
|
124
88
|
valid: false,
|
|
125
|
-
error:
|
|
89
|
+
error: `File type not supported. Allowed types: ${allowedTypes.join(', ')}`,
|
|
126
90
|
code: 'INVALID_TYPE'
|
|
127
91
|
};
|
|
128
92
|
}
|
|
@@ -135,16 +99,15 @@ export function validateFile(file, config) {
|
|
|
135
99
|
* Validate multiple files
|
|
136
100
|
*/
|
|
137
101
|
export function validateFiles(files, config) {
|
|
138
|
-
if (
|
|
102
|
+
if (config?.maxFiles && files.length > config.maxFiles) {
|
|
139
103
|
return {
|
|
140
104
|
valid: false,
|
|
141
|
-
error:
|
|
105
|
+
error: `Too many files. Maximum allowed: ${config.maxFiles}`,
|
|
142
106
|
code: 'TOO_MANY_FILES'
|
|
143
107
|
};
|
|
144
108
|
}
|
|
145
|
-
for (
|
|
146
|
-
|
|
147
|
-
var validation = validateFile(file, config);
|
|
109
|
+
for (const file of files) {
|
|
110
|
+
const validation = validateFile(file, config);
|
|
148
111
|
if (!validation.valid) {
|
|
149
112
|
return validation;
|
|
150
113
|
}
|
|
@@ -159,37 +122,35 @@ export function validateFiles(files, config) {
|
|
|
159
122
|
export function formatFileSize(bytes) {
|
|
160
123
|
if (bytes === 0)
|
|
161
124
|
return '0 B';
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return
|
|
125
|
+
const k = 1024;
|
|
126
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
127
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
128
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
|
|
166
129
|
}
|
|
167
130
|
/**
|
|
168
131
|
* Get file extension from filename
|
|
169
132
|
*/
|
|
170
133
|
export function getFileExtension(filename) {
|
|
171
|
-
|
|
172
|
-
return ((_a = filename.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
|
|
134
|
+
return filename.split('.').pop()?.toLowerCase() || '';
|
|
173
135
|
}
|
|
174
136
|
/**
|
|
175
137
|
* Generate unique file ID
|
|
176
138
|
*/
|
|
177
139
|
export function generateFileId() {
|
|
178
|
-
return
|
|
140
|
+
return `file_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
179
141
|
}
|
|
180
142
|
/**
|
|
181
143
|
* Create a preview URL for supported file types
|
|
182
144
|
*/
|
|
183
145
|
export function createFilePreview(file) {
|
|
184
|
-
return new Promise(
|
|
185
|
-
|
|
146
|
+
return new Promise((resolve) => {
|
|
147
|
+
const fileType = detectFileType(file.type, file.name);
|
|
186
148
|
if (fileType === 'image') {
|
|
187
|
-
|
|
188
|
-
reader.onload =
|
|
189
|
-
|
|
190
|
-
resolve(((_a = e.target) === null || _a === void 0 ? void 0 : _a.result) || null);
|
|
149
|
+
const reader = new FileReader();
|
|
150
|
+
reader.onload = (e) => {
|
|
151
|
+
resolve(e.target?.result || null);
|
|
191
152
|
};
|
|
192
|
-
reader.onerror =
|
|
153
|
+
reader.onerror = () => resolve(null);
|
|
193
154
|
reader.readAsDataURL(file);
|
|
194
155
|
}
|
|
195
156
|
else {
|
|
@@ -200,39 +161,27 @@ export function createFilePreview(file) {
|
|
|
200
161
|
/**
|
|
201
162
|
* Create a pending attachment from a file
|
|
202
163
|
*/
|
|
203
|
-
export function createPendingAttachment(file) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
file: file,
|
|
216
|
-
type: fileType,
|
|
217
|
-
preview: preview || undefined,
|
|
218
|
-
uploadStatus: 'pending',
|
|
219
|
-
uploadProgress: 0,
|
|
220
|
-
retryCount: 0
|
|
221
|
-
}];
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
});
|
|
164
|
+
export async function createPendingAttachment(file) {
|
|
165
|
+
const fileType = detectFileType(file.type, file.name);
|
|
166
|
+
const preview = await createFilePreview(file);
|
|
167
|
+
return {
|
|
168
|
+
id: generateFileId(),
|
|
169
|
+
file,
|
|
170
|
+
type: fileType,
|
|
171
|
+
preview: preview || undefined,
|
|
172
|
+
uploadStatus: 'pending',
|
|
173
|
+
uploadProgress: 0,
|
|
174
|
+
retryCount: 0
|
|
175
|
+
};
|
|
225
176
|
}
|
|
226
177
|
/**
|
|
227
178
|
* Get MIME type accept string for file input
|
|
228
179
|
*/
|
|
229
180
|
export function getAcceptString(types) {
|
|
230
|
-
|
|
231
|
-
for (
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
for (var _a = 0, _b = config.accept; _a < _b.length; _a++) {
|
|
235
|
-
var mimeType = _b[_a];
|
|
181
|
+
const acceptTypes = new Set();
|
|
182
|
+
for (const type of types) {
|
|
183
|
+
const config = fileTypeConfig[type];
|
|
184
|
+
for (const mimeType of config.accept) {
|
|
236
185
|
acceptTypes.add(mimeType);
|
|
237
186
|
}
|
|
238
187
|
}
|
|
@@ -242,31 +191,31 @@ export function getAcceptString(types) {
|
|
|
242
191
|
* Check if file supports preview
|
|
243
192
|
*/
|
|
244
193
|
export function supportsPreview(file) {
|
|
245
|
-
|
|
194
|
+
const fileType = detectFileType(file.type, file.name);
|
|
246
195
|
return fileTypeConfig[fileType].preview;
|
|
247
196
|
}
|
|
248
197
|
/**
|
|
249
198
|
* Get appropriate icon for file type
|
|
250
199
|
*/
|
|
251
200
|
export function getFileIcon(file) {
|
|
252
|
-
|
|
201
|
+
const fileType = detectFileType(file.type, file.name);
|
|
253
202
|
return fileTypeConfig[fileType].icon;
|
|
254
203
|
}
|
|
255
204
|
/**
|
|
256
205
|
* Compress image file if needed
|
|
257
206
|
*/
|
|
258
207
|
export function compressImage(file, options) {
|
|
259
|
-
return new Promise(
|
|
208
|
+
return new Promise((resolve, reject) => {
|
|
260
209
|
if (!file.type.startsWith('image/')) {
|
|
261
210
|
resolve(file);
|
|
262
211
|
return;
|
|
263
212
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
img.onload =
|
|
268
|
-
|
|
269
|
-
|
|
213
|
+
const canvas = document.createElement('canvas');
|
|
214
|
+
const ctx = canvas.getContext('2d');
|
|
215
|
+
const img = new Image();
|
|
216
|
+
img.onload = () => {
|
|
217
|
+
const { maxWidth = 1920, maxHeight = 1080, quality = 0.8 } = options;
|
|
218
|
+
let { width, height } = img;
|
|
270
219
|
// Calculate new dimensions
|
|
271
220
|
if (width > maxWidth) {
|
|
272
221
|
height = (height * maxWidth) / width;
|
|
@@ -279,10 +228,10 @@ export function compressImage(file, options) {
|
|
|
279
228
|
canvas.width = width;
|
|
280
229
|
canvas.height = height;
|
|
281
230
|
// Draw and compress
|
|
282
|
-
ctx
|
|
283
|
-
canvas.toBlob(
|
|
231
|
+
ctx?.drawImage(img, 0, 0, width, height);
|
|
232
|
+
canvas.toBlob((blob) => {
|
|
284
233
|
if (blob) {
|
|
285
|
-
|
|
234
|
+
const compressedFile = new File([blob], file.name, {
|
|
286
235
|
type: file.type,
|
|
287
236
|
lastModified: Date.now()
|
|
288
237
|
});
|
|
@@ -293,7 +242,7 @@ export function compressImage(file, options) {
|
|
|
293
242
|
}
|
|
294
243
|
}, file.type, quality);
|
|
295
244
|
};
|
|
296
|
-
img.onerror =
|
|
245
|
+
img.onerror = () => resolve(file);
|
|
297
246
|
img.src = URL.createObjectURL(file);
|
|
298
247
|
});
|
|
299
248
|
}
|
package/dist/utils/logger.js
CHANGED
|
@@ -1,28 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
let logsEnabled = true;
|
|
2
2
|
export function setLogsEnabled(enabled) {
|
|
3
3
|
logsEnabled = enabled;
|
|
4
4
|
}
|
|
5
|
-
export function chatLog() {
|
|
6
|
-
var args = [];
|
|
7
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
8
|
-
args[_i] = arguments[_i];
|
|
9
|
-
}
|
|
5
|
+
export function chatLog(...args) {
|
|
10
6
|
if (logsEnabled)
|
|
11
|
-
console.log
|
|
7
|
+
console.log(...args);
|
|
12
8
|
}
|
|
13
|
-
export function chatWarn() {
|
|
14
|
-
var args = [];
|
|
15
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
16
|
-
args[_i] = arguments[_i];
|
|
17
|
-
}
|
|
9
|
+
export function chatWarn(...args) {
|
|
18
10
|
if (logsEnabled)
|
|
19
|
-
console.warn
|
|
11
|
+
console.warn(...args);
|
|
20
12
|
}
|
|
21
|
-
export function chatError() {
|
|
22
|
-
var args = [];
|
|
23
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
24
|
-
args[_i] = arguments[_i];
|
|
25
|
-
}
|
|
13
|
+
export function chatError(...args) {
|
|
26
14
|
// Errors are always shown regardless of showLogs
|
|
27
|
-
console.error
|
|
15
|
+
console.error(...args);
|
|
28
16
|
}
|
package/package.json
CHANGED
package/dist/types/api-temp.d.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Temporary API type definitions until @widgetic/api-sdk is properly linked
|
|
3
|
-
* This file should be removed once the SDK deployment is complete
|
|
4
|
-
*/
|
|
5
|
-
export interface Message {
|
|
6
|
-
id: string;
|
|
7
|
-
conversationId: string;
|
|
8
|
-
messageContent?: string | null;
|
|
9
|
-
messageType: 'user' | 'assistant';
|
|
10
|
-
attachments?: ContentItemOutput[];
|
|
11
|
-
isCommit?: boolean;
|
|
12
|
-
userId: string;
|
|
13
|
-
createdAt: Date;
|
|
14
|
-
updatedAt: Date;
|
|
15
|
-
}
|
|
16
|
-
export interface Conversation {
|
|
17
|
-
id: string;
|
|
18
|
-
title: string;
|
|
19
|
-
completed: boolean;
|
|
20
|
-
createdAt: Date;
|
|
21
|
-
updatedAt: Date;
|
|
22
|
-
}
|
|
23
|
-
export interface ContentItemOutput {
|
|
24
|
-
id: string;
|
|
25
|
-
url: string;
|
|
26
|
-
file_type: string;
|
|
27
|
-
file_name?: string | null;
|
|
28
|
-
file_size?: number | null;
|
|
29
|
-
metadata?: Record<string, any> | null;
|
|
30
|
-
created_at: string;
|
|
31
|
-
display_order: number;
|
|
32
|
-
}
|
|
33
|
-
export interface CreateConversationRequest {
|
|
34
|
-
title: string;
|
|
35
|
-
completed: boolean;
|
|
36
|
-
}
|
|
37
|
-
export interface CreateMessageRequest {
|
|
38
|
-
messageContent: string;
|
|
39
|
-
messageType: 'user' | 'assistant';
|
|
40
|
-
attachments?: any[];
|
|
41
|
-
}
|
|
42
|
-
export declare class ConversationsApi {
|
|
43
|
-
constructor(configuration?: any);
|
|
44
|
-
getConversations(params: {
|
|
45
|
-
canvasId: string;
|
|
46
|
-
componentId: string;
|
|
47
|
-
}): Promise<void>;
|
|
48
|
-
createConversation(params: {
|
|
49
|
-
canvasId: string;
|
|
50
|
-
componentId: string;
|
|
51
|
-
createConversationRequest: CreateConversationRequest;
|
|
52
|
-
}): Promise<Conversation>;
|
|
53
|
-
}
|
|
54
|
-
export declare class MessagesApi {
|
|
55
|
-
constructor(configuration?: any);
|
|
56
|
-
getMessages(conversationId: string): Promise<Message[]>;
|
|
57
|
-
createMessage(params: {
|
|
58
|
-
conversationId: string;
|
|
59
|
-
createMessageRequest: CreateMessageRequest;
|
|
60
|
-
}): Promise<Message>;
|
|
61
|
-
}
|
package/dist/types/api-temp.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Temporary API type definitions until @widgetic/api-sdk is properly linked
|
|
3
|
-
* This file should be removed once the SDK deployment is complete
|
|
4
|
-
*/
|
|
5
|
-
// Mock API classes for temporary use
|
|
6
|
-
export class ConversationsApi {
|
|
7
|
-
constructor(configuration) { }
|
|
8
|
-
async getConversations(params) {
|
|
9
|
-
// Mock implementation
|
|
10
|
-
}
|
|
11
|
-
async createConversation(params) {
|
|
12
|
-
// Mock implementation
|
|
13
|
-
return {
|
|
14
|
-
id: `conv_${Date.now()}`,
|
|
15
|
-
title: params.createConversationRequest.title,
|
|
16
|
-
completed: params.createConversationRequest.completed,
|
|
17
|
-
createdAt: new Date(),
|
|
18
|
-
updatedAt: new Date()
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
export class MessagesApi {
|
|
23
|
-
constructor(configuration) { }
|
|
24
|
-
async getMessages(conversationId) {
|
|
25
|
-
// Mock implementation
|
|
26
|
-
return [];
|
|
27
|
-
}
|
|
28
|
-
async createMessage(params) {
|
|
29
|
-
// Mock implementation
|
|
30
|
-
return {
|
|
31
|
-
id: `msg_${Date.now()}`,
|
|
32
|
-
conversationId: params.conversationId,
|
|
33
|
-
messageType: params.createMessageRequest.messageType,
|
|
34
|
-
messageContent: params.createMessageRequest.messageContent,
|
|
35
|
-
isCommit: false,
|
|
36
|
-
userId: 'test_user',
|
|
37
|
-
createdAt: new Date(),
|
|
38
|
-
updatedAt: new Date(),
|
|
39
|
-
attachments: []
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
}
|