mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
Fix(google drive): google sheets creating a file (#1476)
* fixed upload to google drive with sheets * cleanup, remove unneeded scope
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import { createLogger } from '@/lib/logs/console/logger'
|
||||
import type { GoogleDriveToolParams, GoogleDriveUploadResponse } from '@/tools/google_drive/types'
|
||||
import { GOOGLE_WORKSPACE_MIME_TYPES, SOURCE_MIME_TYPES } from '@/tools/google_drive/utils'
|
||||
import {
|
||||
GOOGLE_WORKSPACE_MIME_TYPES,
|
||||
handleSheetsFormat,
|
||||
SOURCE_MIME_TYPES,
|
||||
} from '@/tools/google_drive/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
const logger = createLogger('GoogleDriveUploadTool')
|
||||
@@ -96,13 +100,27 @@ export const uploadTool: ToolConfig<GoogleDriveToolParams, GoogleDriveUploadResp
|
||||
throw new Error(data.error?.message || 'Failed to create file in Google Drive')
|
||||
}
|
||||
|
||||
// Now upload content to the created file
|
||||
const fileId = data.id
|
||||
const requestedMimeType = params?.mimeType || 'text/plain'
|
||||
const authHeader =
|
||||
response.headers.get('Authorization') || `Bearer ${params?.accessToken || ''}`
|
||||
|
||||
// For Google Workspace formats, use the appropriate source MIME type for content upload
|
||||
let preparedContent: string | undefined =
|
||||
typeof params?.content === 'string' ? (params?.content as string) : undefined
|
||||
|
||||
if (requestedMimeType === 'application/vnd.google-apps.spreadsheet' && params?.content) {
|
||||
const { csv, rowCount, columnCount } = handleSheetsFormat(params.content as unknown)
|
||||
if (csv !== undefined) {
|
||||
preparedContent = csv
|
||||
logger.info('Prepared CSV content for Google Sheets upload', {
|
||||
fileId,
|
||||
fileName: params?.fileName,
|
||||
rowCount,
|
||||
columnCount,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const uploadMimeType = GOOGLE_WORKSPACE_MIME_TYPES.includes(requestedMimeType)
|
||||
? SOURCE_MIME_TYPES[requestedMimeType] || 'text/plain'
|
||||
: requestedMimeType
|
||||
@@ -122,7 +140,7 @@ export const uploadTool: ToolConfig<GoogleDriveToolParams, GoogleDriveUploadResp
|
||||
Authorization: authHeader,
|
||||
'Content-Type': uploadMimeType,
|
||||
},
|
||||
body: params?.content || '',
|
||||
body: preparedContent !== undefined ? preparedContent : params?.content || '',
|
||||
}
|
||||
)
|
||||
|
||||
@@ -136,7 +154,6 @@ export const uploadTool: ToolConfig<GoogleDriveToolParams, GoogleDriveUploadResp
|
||||
throw new Error(uploadError.error?.message || 'Failed to upload content to file')
|
||||
}
|
||||
|
||||
// For Google Workspace documents, update the name again to ensure it sticks after conversion
|
||||
if (GOOGLE_WORKSPACE_MIME_TYPES.includes(requestedMimeType)) {
|
||||
logger.info('Updating file name to ensure it persists after conversion', {
|
||||
fileId,
|
||||
@@ -165,7 +182,6 @@ export const uploadTool: ToolConfig<GoogleDriveToolParams, GoogleDriveUploadResp
|
||||
}
|
||||
}
|
||||
|
||||
// Get the final file data
|
||||
const finalFileResponse = await fetch(
|
||||
`https://www.googleapis.com/drive/v3/files/${fileId}?supportsAllDrives=true&fields=id,name,mimeType,webViewLink,webContentLink,size,createdTime,modifiedTime,parents`,
|
||||
{
|
||||
|
||||
@@ -21,3 +21,76 @@ export const SOURCE_MIME_TYPES: Record<string, string> = {
|
||||
'application/vnd.google-apps.spreadsheet': 'text/csv',
|
||||
'application/vnd.google-apps.presentation': 'application/vnd.ms-powerpoint',
|
||||
}
|
||||
|
||||
export function handleSheetsFormat(input: unknown): {
|
||||
csv?: string
|
||||
rowCount: number
|
||||
columnCount: number
|
||||
} {
|
||||
let workingValue: unknown = input
|
||||
|
||||
if (typeof workingValue === 'string') {
|
||||
try {
|
||||
workingValue = JSON.parse(workingValue)
|
||||
} catch (_error) {
|
||||
const csvString = workingValue as string
|
||||
return { csv: csvString, rowCount: 0, columnCount: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
if (!Array.isArray(workingValue)) {
|
||||
return { rowCount: 0, columnCount: 0 }
|
||||
}
|
||||
|
||||
let table: unknown[] = workingValue
|
||||
|
||||
if (
|
||||
table.length > 0 &&
|
||||
typeof (table as any)[0] === 'object' &&
|
||||
(table as any)[0] !== null &&
|
||||
!Array.isArray((table as any)[0])
|
||||
) {
|
||||
const allKeys = new Set<string>()
|
||||
;(table as any[]).forEach((obj) => {
|
||||
if (obj && typeof obj === 'object') {
|
||||
Object.keys(obj).forEach((key) => allKeys.add(key))
|
||||
}
|
||||
})
|
||||
const headers = Array.from(allKeys)
|
||||
const rows = (table as any[]).map((obj) => {
|
||||
if (!obj || typeof obj !== 'object') {
|
||||
return Array(headers.length).fill('')
|
||||
}
|
||||
return headers.map((key) => {
|
||||
const value = (obj as Record<string, unknown>)[key]
|
||||
if (value !== null && typeof value === 'object') {
|
||||
return JSON.stringify(value)
|
||||
}
|
||||
return value === undefined ? '' : (value as any)
|
||||
})
|
||||
})
|
||||
table = [headers, ...rows]
|
||||
}
|
||||
|
||||
const escapeCell = (cell: unknown): string => {
|
||||
if (cell === null || cell === undefined) return ''
|
||||
const stringValue = String(cell)
|
||||
const mustQuote = /[",\n\r]/.test(stringValue)
|
||||
const doubledQuotes = stringValue.replace(/"/g, '""')
|
||||
return mustQuote ? `"${doubledQuotes}"` : doubledQuotes
|
||||
}
|
||||
|
||||
const rowsAsStrings = (table as unknown[]).map((row) => {
|
||||
if (!Array.isArray(row)) {
|
||||
return escapeCell(row)
|
||||
}
|
||||
return row.map((cell) => escapeCell(cell)).join(',')
|
||||
})
|
||||
|
||||
const csv = rowsAsStrings.join('\r\n')
|
||||
const rowCount = Array.isArray(table) ? (table as any[]).length : 0
|
||||
const columnCount =
|
||||
Array.isArray(table) && Array.isArray((table as any[])[0]) ? (table as any[])[0].length : 0
|
||||
|
||||
return { csv, rowCount, columnCount }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user