From 15f14d031866bb763241b4a9197c03fd606bbd6b Mon Sep 17 00:00:00 2001 From: Taylor Wilsdon Date: Mon, 16 Dec 2024 13:36:25 -0500 Subject: [PATCH] fix formatting --- .gitignore | 1 + package-lock.json | 70 +++-- src/lib/components/chat/Chat.svelte | 20 +- src/lib/components/chat/MessageInput.svelte | 14 +- src/lib/utils/google-drive-picker.ts | 323 ++++++++++---------- 5 files changed, 226 insertions(+), 202 deletions(-) diff --git a/.gitignore b/.gitignore index 32271f808..a3cea4514 100644 --- a/.gitignore +++ b/.gitignore @@ -307,3 +307,4 @@ dist cypress/videos cypress/screenshots .vscode/settings.json +.aider* diff --git a/package-lock.json b/package-lock.json index 6cf21ae1a..c2493960a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1815,9 +1815,10 @@ } }, "node_modules/@polka/url": { - "version": "1.0.0-next.25", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", - "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==" + "version": "1.0.0-next.28", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "license": "MIT" }, "node_modules/@popperjs/core": { "version": "2.11.8", @@ -2230,22 +2231,23 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.6.2.tgz", - "integrity": "sha512-ruogrSPXjckn5poUiZU8VYNCSPHq66SFR1AATvOikQxtP6LNI4niAZVX/AWZRe/EPDG3oY2DNJ9c5z7u0t2NAQ==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.11.1.tgz", + "integrity": "sha512-dAiHDEd+AOm20eYdMPV1a2eKBOc0s/7XsSs7PCoNv2kKS7BAoVRC9uzR+FQmxLtp8xuEo9z8CtrMQoszkThltQ==", "hasInstallScript": true, + "license": "MIT", "dependencies": { "@types/cookie": "^0.6.0", - "cookie": "^0.7.0", + "cookie": "^0.6.0", "devalue": "^5.1.0", - "esm-env": "^1.0.0", + "esm-env": "^1.2.1", "import-meta-resolve": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "sade": "^1.8.1", "set-cookie-parser": "^2.6.0", - "sirv": "^2.0.4", + "sirv": "^3.0.0", "tiny-glob": "^0.2.9" }, "bin": { @@ -2255,9 +2257,9 @@ "node": ">=18.13" }, "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1", + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.3" + "vite": "^5.0.3 || ^6.0.0" } }, "node_modules/@sveltejs/vite-plugin-svelte": { @@ -3955,9 +3957,10 @@ "dev": true }, "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3993,9 +3996,10 @@ "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -5240,9 +5244,10 @@ } }, "node_modules/esm-env": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", - "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.1.tgz", + "integrity": "sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng==", + "license": "MIT" }, "node_modules/espree": { "version": "9.6.1", @@ -7755,6 +7760,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "license": "MIT", "engines": { "node": ">=10" } @@ -7776,15 +7782,16 @@ } }, "node_modules/nanoid": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.6.tgz", - "integrity": "sha512-rRq0eMHoGZxlvaFOUdK1Ev83Bd1IgzzR+WJ3IbDJ7QOSdAxYjlurSPqFs9s4lJg29RT6nPwizFtJhQS6V5xgiA==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz", + "integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.js" }, @@ -8485,15 +8492,16 @@ "dev": true }, "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -9456,16 +9464,17 @@ } }, "node_modules/sirv": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", - "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz", + "integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==", + "license": "MIT", "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" }, "engines": { - "node": ">= 10" + "node": ">=18" } }, "node_modules/slash": { @@ -10334,6 +10343,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "license": "MIT", "engines": { "node": ">=6" } diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index bc55b0386..65b1f7fc1 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -385,8 +385,8 @@ // Configure fetch options with proper headers const fetchOptions = { headers: { - 'Authorization': fileData.headers.Authorization, - 'Accept': '*/*' + Authorization: fileData.headers.Authorization, + Accept: '*/*' }, method: 'GET' }; @@ -407,7 +407,7 @@ // Convert response to blob console.log('Converting response to blob...'); const fileBlob = await fileResponse.blob(); - + if (fileBlob.size === 0) { throw new Error('Retrieved file is empty'); } @@ -418,7 +418,7 @@ }); // Create File object with proper MIME type - const file = new File([fileBlob], fileData.name, { + const file = new File([fileBlob], fileData.name, { type: fileBlob.type || contentType }); @@ -441,7 +441,7 @@ } console.log('File uploaded successfully:', uploadedFile); - + // Update file item with upload results fileItem.status = 'uploaded'; fileItem.file = uploadedFile; @@ -449,15 +449,17 @@ fileItem.size = file.size; fileItem.collection_name = uploadedFile?.meta?.collection_name; fileItem.url = `${WEBUI_API_BASE_URL}/files/${uploadedFile.id}`; - + files = files; toast.success($i18n.t('File uploaded successfully')); } catch (e) { console.error('Error uploading file:', e); files = files.filter((f) => f.itemId !== tempItemId); - toast.error($i18n.t('Error uploading file: {{error}}', { - error: e.message || 'Unknown error' - })); + toast.error( + $i18n.t('Error uploading file: {{error}}', { + error: e.message || 'Unknown error' + }) + ); } }; diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index 4e85852e4..6d8bf6d35 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -90,7 +90,6 @@ }; const uploadFileHandler = async (file) => { - const tempItemId = uuidv4(); const fileItem = { type: 'file', @@ -138,7 +137,7 @@ name: fileItem.name, collection: uploadedFile?.meta?.collection_name }); - + if (uploadedFile.error) { console.warn('File upload warning:', uploadedFile.error); toast.warning(uploadedFile.error); @@ -147,7 +146,8 @@ fileItem.status = 'uploaded'; fileItem.file = uploadedFile; fileItem.id = uploadedFile.id; - fileItem.collection_name = uploadedFile?.meta?.collection_name || uploadedFile?.collection_name; + fileItem.collection_name = + uploadedFile?.meta?.collection_name || uploadedFile?.collection_name; fileItem.url = `${WEBUI_API_BASE_URL}/files/${uploadedFile.id}`; files = files; @@ -526,9 +526,11 @@ } } catch (error) { console.error('Google Drive Error:', error); - toast.error($i18n.t('Error accessing Google Drive: {{error}}', { - error: error.message - })); + toast.error( + $i18n.t('Error accessing Google Drive: {{error}}', { + error: error.message + }) + ); } }} onClose={async () => { diff --git a/src/lib/utils/google-drive-picker.ts b/src/lib/utils/google-drive-picker.ts index 737ba9c22..869174abf 100644 --- a/src/lib/utils/google-drive-picker.ts +++ b/src/lib/utils/google-drive-picker.ts @@ -1,16 +1,19 @@ // Google Drive Picker API configuration const API_KEY = import.meta.env.VITE_GOOGLE_API_KEY; const CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID; -const SCOPE = ['https://www.googleapis.com/auth/drive.readonly', 'https://www.googleapis.com/auth/drive.file']; +const SCOPE = [ + 'https://www.googleapis.com/auth/drive.readonly', + 'https://www.googleapis.com/auth/drive.file' +]; // Validate required credentials const validateCredentials = () => { - if (!API_KEY || !CLIENT_ID) { - throw new Error('Google Drive API credentials not configured'); - } - if (API_KEY === 'your-api-key' || CLIENT_ID === 'your-client-id') { - throw new Error('Please configure valid Google Drive API credentials'); - } + if (!API_KEY || !CLIENT_ID) { + throw new Error('Google Drive API credentials not configured'); + } + if (API_KEY === 'your-api-key' || CLIENT_ID === 'your-client-id') { + throw new Error('Please configure valid Google Drive API credentials'); + } }; let pickerApiLoaded = false; @@ -18,170 +21,176 @@ let oauthToken: string | null = null; let initialized = false; export const loadGoogleDriveApi = () => { - return new Promise((resolve, reject) => { - if (typeof gapi === 'undefined') { - const script = document.createElement('script'); - script.src = 'https://apis.google.com/js/api.js'; - script.onload = () => { - gapi.load('picker', () => { - pickerApiLoaded = true; - resolve(true); - }); - }; - script.onerror = reject; - document.body.appendChild(script); - } else { - gapi.load('picker', () => { - pickerApiLoaded = true; - resolve(true); - }); - } - }); + return new Promise((resolve, reject) => { + if (typeof gapi === 'undefined') { + const script = document.createElement('script'); + script.src = 'https://apis.google.com/js/api.js'; + script.onload = () => { + gapi.load('picker', () => { + pickerApiLoaded = true; + resolve(true); + }); + }; + script.onerror = reject; + document.body.appendChild(script); + } else { + gapi.load('picker', () => { + pickerApiLoaded = true; + resolve(true); + }); + } + }); }; export const loadGoogleAuthApi = () => { - return new Promise((resolve, reject) => { - if (typeof google === 'undefined') { - const script = document.createElement('script'); - script.src = 'https://accounts.google.com/gsi/client'; - script.onload = resolve; - script.onerror = reject; - document.body.appendChild(script); - } else { - resolve(true); - } - }); + return new Promise((resolve, reject) => { + if (typeof google === 'undefined') { + const script = document.createElement('script'); + script.src = 'https://accounts.google.com/gsi/client'; + script.onload = resolve; + script.onerror = reject; + document.body.appendChild(script); + } else { + resolve(true); + } + }); }; export const getAuthToken = async () => { - if (!oauthToken) { - return new Promise((resolve, reject) => { - const tokenClient = google.accounts.oauth2.initTokenClient({ - client_id: CLIENT_ID, - scope: SCOPE.join(' '), - callback: (response: any) => { - if (response.access_token) { - oauthToken = response.access_token; - resolve(oauthToken); - } else { - reject(new Error('Failed to get access token')); - } - }, - error_callback: (error: any) => { - reject(new Error(error.message || 'OAuth error occurred')); - } - }); - tokenClient.requestAccessToken(); - }); - } - return oauthToken; + if (!oauthToken) { + return new Promise((resolve, reject) => { + const tokenClient = google.accounts.oauth2.initTokenClient({ + client_id: CLIENT_ID, + scope: SCOPE.join(' '), + callback: (response: any) => { + if (response.access_token) { + oauthToken = response.access_token; + resolve(oauthToken); + } else { + reject(new Error('Failed to get access token')); + } + }, + error_callback: (error: any) => { + reject(new Error(error.message || 'OAuth error occurred')); + } + }); + tokenClient.requestAccessToken(); + }); + } + return oauthToken; }; const initialize = async () => { - if (!initialized) { - validateCredentials(); - await Promise.all([loadGoogleDriveApi(), loadGoogleAuthApi()]); - initialized = true; - } + if (!initialized) { + validateCredentials(); + await Promise.all([loadGoogleDriveApi(), loadGoogleAuthApi()]); + initialized = true; + } }; export const createPicker = () => { - return new Promise(async (resolve, reject) => { - try { - console.log('Initializing Google Drive Picker...'); - await initialize(); - console.log('Getting auth token...'); - const token = await getAuthToken(); - if (!token) { - console.error('Failed to get OAuth token'); - throw new Error('Unable to get OAuth token'); - } - console.log('Auth token obtained successfully'); + return new Promise(async (resolve, reject) => { + try { + console.log('Initializing Google Drive Picker...'); + await initialize(); + console.log('Getting auth token...'); + const token = await getAuthToken(); + if (!token) { + console.error('Failed to get OAuth token'); + throw new Error('Unable to get OAuth token'); + } + console.log('Auth token obtained successfully'); - const picker = new google.picker.PickerBuilder() - .enableFeature(google.picker.Feature.NAV_HIDDEN) - .enableFeature(google.picker.Feature.MULTISELECT_ENABLED) - .addView(new google.picker.DocsView() - .setIncludeFolders(false) - .setSelectFolderEnabled(false) - .setMimeTypes('application/pdf,text/plain,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.google-apps.document')) - .setOAuthToken(token) - .setDeveloperKey(API_KEY) - // Remove app ID setting as it's not needed and can cause 404 errors - .setCallback(async (data: any) => { - if (data[google.picker.Response.ACTION] === google.picker.Action.PICKED) { - try { - const doc = data[google.picker.Response.DOCUMENTS][0]; - const fileId = doc[google.picker.Document.ID]; - const fileName = doc[google.picker.Document.NAME]; - const fileUrl = doc[google.picker.Document.URL]; - - if (!fileId || !fileName) { - throw new Error('Required file details missing'); - } - - // Construct download URL based on MIME type - const mimeType = doc[google.picker.Document.MIME_TYPE]; + const picker = new google.picker.PickerBuilder() + .enableFeature(google.picker.Feature.NAV_HIDDEN) + .enableFeature(google.picker.Feature.MULTISELECT_ENABLED) + .addView( + new google.picker.DocsView() + .setIncludeFolders(false) + .setSelectFolderEnabled(false) + .setMimeTypes( + 'application/pdf,text/plain,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.google-apps.document' + ) + ) + .setOAuthToken(token) + .setDeveloperKey(API_KEY) + // Remove app ID setting as it's not needed and can cause 404 errors + .setCallback(async (data: any) => { + if (data[google.picker.Response.ACTION] === google.picker.Action.PICKED) { + try { + const doc = data[google.picker.Response.DOCUMENTS][0]; + const fileId = doc[google.picker.Document.ID]; + const fileName = doc[google.picker.Document.NAME]; + const fileUrl = doc[google.picker.Document.URL]; - let downloadUrl; - let exportFormat; - - if (mimeType.includes('google-apps')) { - // Handle Google Workspace files - if (mimeType.includes('document')) { - exportFormat = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; - } else if (mimeType.includes('presentation')) { - exportFormat = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'; - } else { - exportFormat = 'application/pdf'; - } - downloadUrl = `https://www.googleapis.com/drive/v3/files/${fileId}/export?mimeType=${encodeURIComponent(exportFormat)}`; - } else { - // Regular files use direct download URL - downloadUrl = `https://www.googleapis.com/drive/v3/files/${fileId}?alt=media`; - } - // Create a Blob from the file download - const response = await fetch(downloadUrl, { - headers: { - 'Authorization': `Bearer ${token}`, - 'Accept': '*/*' - } - }); + if (!fileId || !fileName) { + throw new Error('Required file details missing'); + } - if (!response.ok) { - const errorText = await response.text(); - console.error('Download failed:', { - status: response.status, - statusText: response.statusText, - error: errorText - }); - throw new Error(`Failed to download file (${response.status}): ${errorText}`); - } + // Construct download URL based on MIME type + const mimeType = doc[google.picker.Document.MIME_TYPE]; - const blob = await response.blob(); - const result = { - id: fileId, - name: fileName, - url: downloadUrl, - blob: blob, - headers: { - 'Authorization': `Bearer ${token}`, - 'Accept': '*/*' - } - }; - resolve(result); - } catch (error) { - reject(error); - } - } else if (data[google.picker.Response.ACTION] === google.picker.Action.CANCEL) { - resolve(null); - } - }) - .build(); - picker.setVisible(true); - } catch (error) { - console.error('Google Drive Picker error:', error); - reject(error); - } - }); + let downloadUrl; + let exportFormat; + + if (mimeType.includes('google-apps')) { + // Handle Google Workspace files + if (mimeType.includes('document')) { + exportFormat = + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; + } else if (mimeType.includes('presentation')) { + exportFormat = + 'application/vnd.openxmlformats-officedocument.presentationml.presentation'; + } else { + exportFormat = 'application/pdf'; + } + downloadUrl = `https://www.googleapis.com/drive/v3/files/${fileId}/export?mimeType=${encodeURIComponent(exportFormat)}`; + } else { + // Regular files use direct download URL + downloadUrl = `https://www.googleapis.com/drive/v3/files/${fileId}?alt=media`; + } + // Create a Blob from the file download + const response = await fetch(downloadUrl, { + headers: { + Authorization: `Bearer ${token}`, + Accept: '*/*' + } + }); + + if (!response.ok) { + const errorText = await response.text(); + console.error('Download failed:', { + status: response.status, + statusText: response.statusText, + error: errorText + }); + throw new Error(`Failed to download file (${response.status}): ${errorText}`); + } + + const blob = await response.blob(); + const result = { + id: fileId, + name: fileName, + url: downloadUrl, + blob: blob, + headers: { + Authorization: `Bearer ${token}`, + Accept: '*/*' + } + }; + resolve(result); + } catch (error) { + reject(error); + } + } else if (data[google.picker.Response.ACTION] === google.picker.Action.CANCEL) { + resolve(null); + } + }) + .build(); + picker.setVisible(true); + } catch (error) { + console.error('Google Drive Picker error:', error); + reject(error); + } + }); };