@admin-layout/demo-perplexity-browser 12.2.4-alpha.2 → 12.2.4-alpha.4

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 (79) hide show
  1. package/lib/api/index.d.ts +2 -0
  2. package/lib/api/index.d.ts.map +1 -0
  3. package/lib/api/llm.d.ts +34 -0
  4. package/lib/api/llm.d.ts.map +1 -0
  5. package/lib/api/llm.js +200 -0
  6. package/lib/api/llm.js.map +1 -0
  7. package/lib/api/stt.d.ts +21 -0
  8. package/lib/api/stt.d.ts.map +1 -0
  9. package/lib/api/stt.js +111 -0
  10. package/lib/api/stt.js.map +1 -0
  11. package/lib/components/AttachmentPreview.d.ts +10 -0
  12. package/lib/components/AttachmentPreview.d.ts.map +1 -0
  13. package/lib/components/AttachmentPreview.js +50 -0
  14. package/lib/components/AttachmentPreview.js.map +1 -0
  15. package/lib/components/AudioRecorder.d.ts +8 -0
  16. package/lib/components/AudioRecorder.d.ts.map +1 -0
  17. package/lib/components/AudioRecorder.js +221 -0
  18. package/lib/components/AudioRecorder.js.map +1 -0
  19. package/lib/components/AudioVisualizer.d.ts +7 -0
  20. package/lib/components/AudioVisualizer.d.ts.map +1 -0
  21. package/lib/components/AudioVisualizer.js +116 -0
  22. package/lib/components/AudioVisualizer.js.map +1 -0
  23. package/lib/components/ChatFiles.d.ts +8 -0
  24. package/lib/components/ChatFiles.d.ts.map +1 -0
  25. package/lib/components/ChatFiles.js +76 -0
  26. package/lib/components/ChatFiles.js.map +1 -0
  27. package/lib/components/ChatScreenshot.d.ts +7 -0
  28. package/lib/components/ChatScreenshot.d.ts.map +1 -0
  29. package/lib/components/ChatScreenshot.js +113 -0
  30. package/lib/components/ChatScreenshot.js.map +1 -0
  31. package/lib/components/SearchBar.d.ts +9 -1
  32. package/lib/components/SearchBar.d.ts.map +1 -1
  33. package/lib/components/SearchBar.js +176 -240
  34. package/lib/components/SearchBar.js.map +1 -1
  35. package/lib/config/constants.d.ts +108 -0
  36. package/lib/config/constants.d.ts.map +1 -0
  37. package/lib/config/constants.js +115 -0
  38. package/lib/config/constants.js.map +1 -0
  39. package/lib/config/env.d.ts +20 -0
  40. package/lib/config/env.d.ts.map +1 -0
  41. package/lib/config/env.js +22 -0
  42. package/lib/config/env.js.map +1 -0
  43. package/lib/config/index.d.ts +4 -0
  44. package/lib/config/index.d.ts.map +1 -0
  45. package/lib/config/providers.d.ts +54 -0
  46. package/lib/config/providers.d.ts.map +1 -0
  47. package/lib/config/providers.js +65 -0
  48. package/lib/config/providers.js.map +1 -0
  49. package/lib/pages/home/HomePage.d.ts +1 -3
  50. package/lib/pages/home/HomePage.d.ts.map +1 -1
  51. package/lib/pages/home/HomePage.js +232 -4
  52. package/lib/pages/home/HomePage.js.map +1 -1
  53. package/lib/platform/browser.d.ts +18 -0
  54. package/lib/platform/browser.d.ts.map +1 -0
  55. package/lib/platform/context.d.ts +76 -0
  56. package/lib/platform/context.d.ts.map +1 -0
  57. package/lib/platform/index.d.ts +25 -0
  58. package/lib/platform/index.d.ts.map +1 -0
  59. package/lib/platform/tauri.d.ts +35 -0
  60. package/lib/platform/tauri.d.ts.map +1 -0
  61. package/lib/platform/types.d.ts +164 -0
  62. package/lib/platform/types.d.ts.map +1 -0
  63. package/lib/state/chatMachine.d.ts +554 -0
  64. package/lib/state/chatMachine.d.ts.map +1 -0
  65. package/lib/state/chatMachine.js +458 -0
  66. package/lib/state/chatMachine.js.map +1 -0
  67. package/lib/state/index.d.ts +3 -0
  68. package/lib/state/index.d.ts.map +1 -0
  69. package/lib/state/useChatWithPlatform.d.ts +43 -0
  70. package/lib/state/useChatWithPlatform.d.ts.map +1 -0
  71. package/lib/types/chat.d.ts +56 -0
  72. package/lib/types/chat.d.ts.map +1 -0
  73. package/lib/types/index.d.ts +2 -0
  74. package/lib/types/index.d.ts.map +1 -0
  75. package/lib/utils/chatStorage.d.ts +25 -0
  76. package/lib/utils/chatStorage.d.ts.map +1 -0
  77. package/lib/utils/chatStorage.js +17 -0
  78. package/lib/utils/chatStorage.js.map +1 -0
  79. package/package.json +9 -5
@@ -0,0 +1,2 @@
1
+ export * from './llm';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { type LLMProvider, type LLMModel } from '../config/providers';
2
+ import type { ChatMessage } from '../types/chat';
3
+ export interface LLMRequestParams {
4
+ messages: ChatMessage[];
5
+ systemPrompt?: string;
6
+ imagesBase64?: string[];
7
+ provider?: LLMProvider;
8
+ model?: LLMModel;
9
+ apiKey?: string;
10
+ temperature?: number;
11
+ maxTokens?: number;
12
+ stream?: boolean;
13
+ }
14
+ export interface LLMStreamChunk {
15
+ content: string;
16
+ done: boolean;
17
+ }
18
+ /**
19
+ * Fetch LLM response with streaming support
20
+ * Automatically selects the best model based on task type:
21
+ * - Vision tasks (images present) → llama-4-scout-17b (vision model)
22
+ * - Text-only tasks → gpt-oss-120B (faster, default)
23
+ * Returns an async generator that yields content chunks
24
+ */
25
+ export declare function fetchLLMResponse(params: LLMRequestParams): AsyncGenerator<string, void, unknown>;
26
+ /**
27
+ * Fetch LLM response without streaming (returns complete response)
28
+ */
29
+ export declare function fetchLLMResponseComplete(params: LLMRequestParams): Promise<string>;
30
+ /**
31
+ * Quick helper to send a single message and get response
32
+ */
33
+ export declare function quickChat(userMessage: string, systemPrompt?: string): Promise<string>;
34
+ //# sourceMappingURL=llm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/api/llm.ts"],"names":[],"mappings":"AACA,OAAO,EAA8C,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAElH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACjB;AA8FD;;;;;;GAMG;AACH,wBAAuB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAqHvG;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAQxF;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAM3F"}
package/lib/api/llm.js ADDED
@@ -0,0 +1,200 @@
1
+ import {fetch as fetch$1}from'@tauri-apps/plugin-http';import {getCurrentProviderWithKey}from'../config/providers.js';import {LLM_CONFIG}from'../config/constants.js';// ============= Helper Functions =============
2
+ /**
3
+ * Build the request body for OpenAI-compatible APIs
4
+ */
5
+ function buildRequestBody(params, modelId) {
6
+ const {
7
+ messages,
8
+ systemPrompt,
9
+ imagesBase64,
10
+ temperature = 0.7,
11
+ maxTokens,
12
+ stream = true
13
+ } = params;
14
+ // Build message array with optional system prompt
15
+ const fullMessages = [];
16
+ if (systemPrompt) {
17
+ fullMessages.push({
18
+ role: 'system',
19
+ content: systemPrompt
20
+ });
21
+ }
22
+ // Handle images in the last user message if present
23
+ if (imagesBase64 && imagesBase64.length > 0 && messages.length > 0) {
24
+ const lastUserIndex = messages.map(m => m.role).lastIndexOf('user');
25
+ messages.forEach((msg, index) => {
26
+ if (index === lastUserIndex && msg.role === 'user') {
27
+ // Convert to multimodal message with images
28
+ const content = [{
29
+ type: 'text',
30
+ text: msg.content
31
+ }];
32
+ imagesBase64.forEach(base64 => {
33
+ content.push({
34
+ type: 'image_url',
35
+ image_url: {
36
+ url: `data:image/png;base64,${base64}`
37
+ }
38
+ });
39
+ });
40
+ fullMessages.push({
41
+ role: 'user',
42
+ content: content
43
+ });
44
+ } else {
45
+ fullMessages.push(msg);
46
+ }
47
+ });
48
+ } else {
49
+ fullMessages.push(...messages);
50
+ }
51
+ const body = {
52
+ model: modelId,
53
+ messages: fullMessages,
54
+ temperature,
55
+ stream
56
+ };
57
+ if (maxTokens) {
58
+ body.max_tokens = maxTokens;
59
+ }
60
+ return body;
61
+ }
62
+ /**
63
+ * Parse SSE stream data
64
+ */
65
+ function parseSSELine(line) {
66
+ if (!line.startsWith('data: ')) return null;
67
+ const data = line.slice(6).trim();
68
+ if (data === '[DONE]') return null;
69
+ try {
70
+ const parsed = JSON.parse(data);
71
+ return parsed.choices?.[0]?.delta?.content || null;
72
+ } catch {
73
+ return null;
74
+ }
75
+ }
76
+ /**
77
+ * Detect if running in Tauri environment
78
+ */
79
+ function isTauriEnvironment() {
80
+ return typeof window !== 'undefined' && !!window.__TAURI__;
81
+ }
82
+ /**
83
+ * Get the appropriate fetch function based on environment
84
+ */
85
+ function getFetchFunction() {
86
+ if (isTauriEnvironment()) {
87
+ return fetch$1;
88
+ }
89
+ return fetch;
90
+ }
91
+ // ============= Main Functions =============
92
+ /**
93
+ * Fetch LLM response with streaming support
94
+ * Automatically selects the best model based on task type:
95
+ * - Vision tasks (images present) → llama-4-scout-17b (vision model)
96
+ * - Text-only tasks → gpt-oss-120B (faster, default)
97
+ * Returns an async generator that yields content chunks
98
+ */
99
+ async function* fetchLLMResponse(params) {
100
+ // Get current provider config or use overrides
101
+ const config = getCurrentProviderWithKey();
102
+ let provider = params.provider || config?.provider;
103
+ let model = params.model || config?.model;
104
+ const apiKey = params.apiKey || config?.apiKey;
105
+ // Auto-select model based on task type (only for Groq provider)
106
+ if (!params.model && provider?.id === 'groq' && params.imagesBase64 && params.imagesBase64.length > 0) {
107
+ // Vision task detected → use llama-4-scout-17b
108
+ console.log('🔄 [LLM] Vision task detected, switching to llama-4-scout-17b');
109
+ model = LLM_CONFIG.MODELS.GROQ_VISION_SCOUT;
110
+ }
111
+ // Otherwise use the default model (gpt-oss-120B for text-only)
112
+ if (!provider) {
113
+ throw new Error('No LLM provider configured. Please select a provider in settings.');
114
+ }
115
+ if (!apiKey) {
116
+ throw new Error(`No API key configured for ${provider.name}. Please add your API key in settings or set the ${provider.envKey} environment variable.`);
117
+ }
118
+ if (!model) {
119
+ throw new Error(`No model selected for ${provider.name}.`);
120
+ }
121
+ console.log('🤖 [LLM] Using model:', model.name, '(' + model.id + ')');
122
+ console.log('🌐 [LLM] Environment:', isTauriEnvironment() ? 'Tauri' : 'Browser');
123
+ const url = `${provider.baseUrl}/chat/completions`;
124
+ const body = buildRequestBody(params, model.id);
125
+ // Build headers
126
+ const headers = {
127
+ Authorization: `Bearer ${apiKey}`,
128
+ 'Content-Type': 'application/json'
129
+ };
130
+ // OpenRouter requires additional headers
131
+ if (provider.id === 'openrouter') {
132
+ headers['HTTP-Referer'] = 'https://perplexity-demo.app';
133
+ headers['X-Title'] = 'Perplexity Demo Chat';
134
+ }
135
+ // Use tauriFetch for Tauri environment, fallback to regular fetch
136
+ const fetchFunction = getFetchFunction();
137
+ let response;
138
+ try {
139
+ response = await fetchFunction(url, {
140
+ method: 'POST',
141
+ headers,
142
+ body: JSON.stringify(body)
143
+ });
144
+ } catch (e) {
145
+ throw new Error(`Network error: ${e instanceof Error ? e.message : String(e)}`);
146
+ }
147
+ if (!response.ok) {
148
+ let errorMessage;
149
+ try {
150
+ const errorData = await response.json();
151
+ errorMessage = errorData.error?.message || errorData.message || response.statusText;
152
+ } catch {
153
+ errorMessage = response.statusText;
154
+ }
155
+ throw new Error(`${provider.name} API error (${response.status}): ${errorMessage}`);
156
+ }
157
+ // Handle streaming response
158
+ if (params.stream !== false && response.body) {
159
+ const reader = response.body.getReader();
160
+ const decoder = new TextDecoder();
161
+ let buffer = '';
162
+ try {
163
+ while (true) {
164
+ const {
165
+ done,
166
+ value
167
+ } = await reader.read();
168
+ if (done) break;
169
+ buffer += decoder.decode(value, {
170
+ stream: true
171
+ });
172
+ // Process complete lines
173
+ const lines = buffer.split('\n');
174
+ buffer = lines.pop() || ''; // Keep incomplete line in buffer
175
+ for (const line of lines) {
176
+ const content = parseSSELine(line);
177
+ if (content) {
178
+ yield content;
179
+ }
180
+ }
181
+ }
182
+ // Process any remaining buffer
183
+ if (buffer) {
184
+ const content = parseSSELine(buffer);
185
+ if (content) {
186
+ yield content;
187
+ }
188
+ }
189
+ } finally {
190
+ reader.releaseLock();
191
+ }
192
+ } else {
193
+ // Non-streaming response
194
+ const data = await response.json();
195
+ const content = data.choices?.[0]?.message?.content;
196
+ if (content) {
197
+ yield content;
198
+ }
199
+ }
200
+ }export{fetchLLMResponse};//# sourceMappingURL=llm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.js","sources":["../../src/api/llm.ts"],"sourcesContent":[null],"names":["tauriFetch"],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Speech-to-Text (STT) API using Groq's Whisper model
3
+ * Uses whisper-large-v3-turbo for accurate transcription
4
+ */
5
+ export interface STTParams {
6
+ audio: Blob;
7
+ language?: string;
8
+ prompt?: string;
9
+ }
10
+ export interface STTResponse {
11
+ text: string;
12
+ }
13
+ /**
14
+ * Transcribe audio using Groq's Whisper API
15
+ *
16
+ * @param params - STT parameters including audio blob
17
+ * @returns Transcribed text
18
+ * @throws Error if API key is missing or request fails
19
+ */
20
+ export declare function transcribeAudio(params: STTParams): Promise<string>;
21
+ //# sourceMappingURL=stt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stt.d.ts","sourceRoot":"","sources":["../../src/api/stt.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA+CH,MAAM,WAAW,SAAS;IACtB,KAAK,EAAE,IAAI,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;CAChB;AAID;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CA0ExE"}
package/lib/api/stt.js ADDED
@@ -0,0 +1,111 @@
1
+ import {fetch as fetch$1}from'@tauri-apps/plugin-http';import {getApiKey}from'../config/env.js';import {LLM_CONFIG}from'../config/constants.js';/**
2
+ * Speech-to-Text (STT) API using Groq's Whisper model
3
+ * Uses whisper-large-v3-turbo for accurate transcription
4
+ */
5
+ // ============= Constants =============
6
+ const GROQ_STT_URL = LLM_CONFIG.ENDPOINTS.GROQ_STT;
7
+ const WHISPER_MODEL = LLM_CONFIG.STT.MODEL;
8
+ // ============= Helper Functions =============
9
+ /**
10
+ * Check if running in Tauri environment
11
+ */
12
+ function isTauriEnvironment() {
13
+ return typeof window !== 'undefined' && '__TAURI__' in window;
14
+ }
15
+ /**
16
+ * Get the appropriate fetch function based on environment
17
+ */
18
+ function getFetchFunction() {
19
+ return isTauriEnvironment() ? fetch$1 : fetch;
20
+ }
21
+ /**
22
+ * Get file extension based on mime type
23
+ */
24
+ function getFileExtension(mimeType) {
25
+ const mimeToExt = {
26
+ 'audio/webm': 'webm',
27
+ 'audio/webm;codecs=opus': 'webm',
28
+ 'audio/ogg': 'ogg',
29
+ 'audio/ogg;codecs=opus': 'ogg',
30
+ 'audio/mp4': 'm4a',
31
+ 'audio/mpeg': 'mp3',
32
+ 'audio/wav': 'wav',
33
+ 'audio/x-wav': 'wav',
34
+ 'audio/flac': 'flac'
35
+ };
36
+ return mimeToExt[mimeType] || 'webm';
37
+ }
38
+ // ============= Main STT Function =============
39
+ /**
40
+ * Transcribe audio using Groq's Whisper API
41
+ *
42
+ * @param params - STT parameters including audio blob
43
+ * @returns Transcribed text
44
+ * @throws Error if API key is missing or request fails
45
+ */
46
+ async function transcribeAudio(params) {
47
+ const {
48
+ audio,
49
+ language = LLM_CONFIG.STT.DEFAULT_LANGUAGE,
50
+ prompt
51
+ } = params;
52
+ // Get API key from environment
53
+ const apiKey = getApiKey(LLM_CONFIG.ENV_KEYS.GROQ_API_KEY);
54
+ if (!apiKey) {
55
+ throw new Error(`${LLM_CONFIG.ENV_KEYS.GROQ_API_KEY} not configured. Please set it in your environment variables.`);
56
+ }
57
+ // Validate audio
58
+ if (!audio || audio.size === 0) {
59
+ throw new Error('Audio file is empty or not provided');
60
+ }
61
+ console.log('🎙️ [STT] Transcribing audio:', {
62
+ size: audio.size,
63
+ type: audio.type,
64
+ model: WHISPER_MODEL,
65
+ language
66
+ });
67
+ // Build form data
68
+ const formData = new FormData();
69
+ // Get proper file extension based on mime type
70
+ const extension = getFileExtension(audio.type);
71
+ const filename = `audio.${extension}`;
72
+ // Convert blob to proper file format with correct extension
73
+ const audioFile = new File([audio], filename, {
74
+ type: audio.type || 'audio/webm'
75
+ });
76
+ formData.append('file', audioFile);
77
+ formData.append('model', WHISPER_MODEL);
78
+ if (prompt) {
79
+ formData.append('prompt', prompt);
80
+ }
81
+ // Make request
82
+ const fetchFn = getFetchFunction();
83
+ try {
84
+ const response = await fetchFn(GROQ_STT_URL, {
85
+ method: 'POST',
86
+ headers: {
87
+ Authorization: `Bearer ${apiKey}`
88
+ },
89
+ body: formData
90
+ });
91
+ if (!response.ok) {
92
+ const errorText = await response.text();
93
+ let errorMessage;
94
+ try {
95
+ const errorJson = JSON.parse(errorText);
96
+ errorMessage = errorJson.error?.message || errorJson.message || errorText;
97
+ } catch {
98
+ errorMessage = errorText || response.statusText;
99
+ }
100
+ throw new Error(`STT API error (${response.status}): ${errorMessage}`);
101
+ }
102
+ const data = await response.json();
103
+ console.log('✅ [STT] Transcription complete:', data.text?.substring(0, 100) + '...');
104
+ return data.text || '';
105
+ } catch (error) {
106
+ if (error instanceof Error) {
107
+ throw error;
108
+ }
109
+ throw new Error(`STT request failed: ${String(error)}`);
110
+ }
111
+ }export{transcribeAudio};//# sourceMappingURL=stt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stt.js","sources":["../../src/api/stt.ts"],"sourcesContent":[null],"names":["tauriFetch"],"mappings":"gJAAA;;;AAGG;AAMH;AAEA,MAAM,YAAY,GAAG,UAAU,CAAC,SAAS,CAAC,QAAQ;AAClD,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK;AAE1C;AAEA;;AAEG;AACH,SAAS,kBAAkB,GAAA;SACvB,OAAO,WAAa,WAAK,eAAe,IAAW;AACvD;AAEA;;AAEG;AACH,SAAS,gBAAgB,GAAA;SACrB,kBAAO,EAAkB,GAAGA,UAAa,KAAE;AAC/C;AAEA;;AAEG;AACH,SAAS,gBAAgB,CAAC,QAAgB,EAAA;AACtC,EAAA,MAAA,YAAe;AACX,IAAA,YAAA,EAAA,MAAc;AACd,IAAA,wBAAA,EAAA,MAA0B;AAC1B,IAAA,WAAA,EAAA,KAAa;AACb,IAAA,uBAAA,EAAA,KAAyB;AACzB,IAAA,WAAA,EAAA,KAAa;AACb,IAAA,YAAA,EAAA,KAAc;AACd,IAAA,WAAA,EAAA,KAAa;AACb,IAAA,aAAA,EAAA,KAAe;AACf,IAAA,YAAA,EAAA;;AAEJ,EAAA,OAAA,kBAAiB,CAAA,IAAS;AAC9B;AAcA;AAEA;;;;;;AAMG;AACI,eAAe,eAAe,CAAC,MAAiB,EAAA;AACnD,EAAA,MAAA;IAEA,KAAA;IACA,QAAM,GAAA,UAAS,CAAA,GAAU,CAAA,gBAAW;IACpC;YACI;;QAKJ,MAAA,GAAA,SAAiB,CAAA,UAAA,CAAA,QAAA,CAAA,YAAA,CAAA;MACjB,CAAA,QAAU;AACN,IAAA,MAAA,IAAM,KAAI,CAAA,CAAA,EAAK,UAAC,CAAA,QAAA,CAAA,YAAA,CAAA,6DAAuC,CAAA,CAAA;;AAG3D;YACQ,IAAE,KAAM,CAAA,IAAI,KAAA,CAAA,EAAA;UAChB,IAAM,KAAK,CAAC,qCAAI,CAAA;AAChB,EAAA;SACA,CAAA,GAAA,CAAA,+BAAQ,EAAA;AACX,IAAA,IAAE,EAAA,KAAA,CAAA,IAAA;IAEH,IAAA,EAAA,KAAA,CAAA,IAAA;AACA,IAAA,KAAA,EAAM,aAAW;IAEjB;IACA;AACA;QAEA,QAAA,GAAA,IAAA,QAAA,EAAA;;AAEA,EAAA,MAAA,SAAS,GAAO,gBAAQ,CAAS,KAAE,CAAA,IAAA,CAAA;AACnC,EAAA,MAAA,QAAS,GAAM,CAAC,QAAO,SAAE,CAAA,CAAA;;AAGrB,EAAA,MAAA,SAAS,GAAA,IAAO,WAAU,CAAA,EAAA,QAAQ,EAAA;IACtC,IAAC,EAAA,KAAA,CAAA,IAAA,IAAA;IAED;AACA,EAAA,QAAM,CAAA,MAAO,CAAA,MAAG,EAAA,SAAA,CAAgB;AAEhC,EAAA,QAAK,CAAA,MAAA,CAAA,OAAA,EAAA,aAAA,CAAA;AACD,EAAA,IAAA,MAAA,EAAM;AACF,IAAA,QAAA,CAAA,OAAQ,QAAM,EAAA,MAAA,CAAA;AACd,EAAA;;AAEC,EAAA,MAAA,OAAA,GAAA,gBAAA,EAAA;AACD,EAAA,IAAA;AACH,IAAA,MAAC,QAAC,GAAA,MAAA,OAAA,CAAA,YAAA,EAAA;AAEH,MAAA,MAAI,EAAC,MAAA;AACD,MAAA,OAAA,EAAA;AACA,QAAA,uBAAyB,EAAA,MAAA,CAAA;AACzB,OAAA;;AAEI,KAAA,CAAA;iBACH,CAAA,EAAA,EAAA;AAAC,MAAA,MAAA,SAAO,GAAA,MAAA,QAAA,CAAA,IAAA,EAAA;AACL,MAAA,IAAA,YAAA;;cAEJ,SAAU,GAAA,IAAM,CAAA,KAAA,CAAA,SAAkB,CAAA;QACtC,YAAC,GAAA,SAAA,CAAA,KAAA,EAAA,OAAA,IAAA,SAAA,CAAA,OAAA,IAAA,SAAA;AAED,MAAA,CAAA,CAAA,MAAM;AAEN,QAAA,YAAY,mCAAmC;AAE/C,MAAA;MACH,MAAA,IAAA,KAAA,CAAA,CAAA,eAAA,EAAA,QAAA,CAAA,MAAA,CAAA,GAAA,EAAA,YAAA,CAAA,CAAA,CAAA;IAAC;AACE,IAAA,MAAA,IAAI,GAAK,MAAA,QAAY,CAAA,IAAO,EAAC;AACzB,IAAA,OAAA,CAAA,GAAA,CAAA,iCAAY,EAAA,IAAA,CAAA,IAAA,EAAA,SAAA,CAAA,CAAA,EAAA,GAAA,CAAA,GAAA,KAAA,CAAA;WACf,IAAA,CAAA,IAAA,IAAA,EAAA;WACD,KAAM,EAAI;IACd,IAAC,KAAA,YAAA,KAAA,EAAA;AACL,MAAC,MAAA,KAAA;;;;"}
@@ -0,0 +1,10 @@
1
+ import type { AttachedFile } from '../types/chat';
2
+ interface AttachmentPreviewProps {
3
+ attachment: AttachedFile;
4
+ showPreview?: boolean;
5
+ isCancellable?: boolean;
6
+ onRemove?: (id: string) => void;
7
+ }
8
+ export declare function AttachmentPreview({ attachment, showPreview, isCancellable, onRemove, }: AttachmentPreviewProps): import("react/jsx-runtime").JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=AttachmentPreview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttachmentPreview.d.ts","sourceRoot":"","sources":["../../src/components/AttachmentPreview.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,UAAU,sBAAsB;IAC5B,UAAU,EAAE,YAAY,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,wBAAgB,iBAAiB,CAAC,EAC9B,UAAU,EACV,WAAmB,EACnB,aAAoB,EACpB,QAAQ,GACX,EAAE,sBAAsB,2CA4CxB"}
@@ -0,0 +1,50 @@
1
+ import {jsxs,jsx}from'react/jsx-runtime';import {X,Camera,Image,FileText}from'lucide-react';function AttachmentPreview({
2
+ attachment,
3
+ showPreview = false,
4
+ isCancellable = true,
5
+ onRemove
6
+ }) {
7
+ const isImage = !!attachment.dataUrl && attachment.dataUrl.startsWith('data:image/');
8
+ const getFileIcon = () => {
9
+ if (attachment.type === 'screenshot') return jsx(Camera, {
10
+ className: "h-3.5 w-3.5 text-muted-foreground"
11
+ });
12
+ if (isImage) return jsx(Image, {
13
+ className: "h-3.5 w-3.5 text-muted-foreground"
14
+ });
15
+ return jsx(FileText, {
16
+ className: "h-3.5 w-3.5 text-muted-foreground"
17
+ });
18
+ };
19
+ return jsxs("div", {
20
+ className: "relative group inline-flex items-center gap-2 rounded-xl bg-secondary/60 border border-border/50 px-3 py-2 text-sm",
21
+ children: [showPreview && isImage && attachment.dataUrl ? jsx("div", {
22
+ className: "w-8 h-8 rounded-lg overflow-hidden flex-shrink-0 bg-muted",
23
+ children: jsx("img", {
24
+ src: attachment.dataUrl,
25
+ alt: attachment.name,
26
+ className: "w-full h-full object-cover"
27
+ })
28
+ }) : jsx("div", {
29
+ className: "w-7 h-7 rounded-lg bg-muted flex items-center justify-center flex-shrink-0",
30
+ children: getFileIcon()
31
+ }), jsxs("div", {
32
+ className: "flex flex-col min-w-0 max-w-[140px]",
33
+ children: [jsx("span", {
34
+ className: "truncate text-xs font-medium text-foreground",
35
+ children: attachment.name
36
+ }), attachment.size && jsx("span", {
37
+ className: "text-[10px] text-muted-foreground",
38
+ children: attachment.size < 1024 * 1024 ? `${(attachment.size / 1024).toFixed(1)} KB` : `${(attachment.size / (1024 * 1024)).toFixed(1)} MB`
39
+ })]
40
+ }), isCancellable && onRemove && jsx("button", {
41
+ type: "button",
42
+ onClick: () => onRemove(attachment.id),
43
+ className: "absolute -top-2 -right-2 h-4 w-4 rounded-full bg-destructive text-destructive-foreground opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center shadow-md hover:bg-destructive/90",
44
+ "aria-label": `Remove ${attachment.name}`,
45
+ children: jsx(X, {
46
+ className: "h-2.5 w-2.5"
47
+ })
48
+ })]
49
+ });
50
+ }export{AttachmentPreview};//# sourceMappingURL=AttachmentPreview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttachmentPreview.js","sources":["../../src/components/AttachmentPreview.tsx"],"sourcesContent":[null],"names":["_jsx","ImageIcon"],"mappings":"4FAUM,SAAU,iBAAiB,CAAC;AAM9B,EAAA;aAEM,GAAA,KAAW;AACb,EAAA,aAAI,GAAA,IAAU;AAAwB,EAAA;AACtC,CAAA,EAAA;AAAa,EAAA,MAAA,OAAA,GAAA,CAAO,WAAC,CAAA,qBAAoB,CAAA,OAAA,CAAA,UAAA,CAAA,cAAsC;AAC/E,EAAA,MAAA,cAAQ,MAAQ;AACpB,IAAA,IAAE,UAAA,CAAA,IAAA,KAAA,YAAA,EAAA,OAAAA,GAAA,CAAA,MAAA,EAAA;AAEF,MAAA,SACI,EAAA;AAgBoB,KAAA,CAAA;AACA,IAAA,IAAA,OAAA,EAAA,OAAAA,GAAA,CAACC,KAAK,EAAA;AAiBlC,MAAC,SAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,8 @@
1
+ interface AudioRecorderProps {
2
+ onTranscriptionComplete: (text: string) => void;
3
+ onCancel: () => void;
4
+ onError?: (error: string) => void;
5
+ }
6
+ export declare function AudioRecorder({ onTranscriptionComplete, onCancel, onError }: AudioRecorderProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=AudioRecorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudioRecorder.d.ts","sourceRoot":"","sources":["../../src/components/AudioRecorder.tsx"],"names":[],"mappings":"AAKA,UAAU,kBAAkB;IACxB,uBAAuB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAID,wBAAgB,aAAa,CAAC,EAAE,uBAAuB,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,kBAAkB,2CA8N/F"}