venice-dev-tools
Version:
unOfficial SDK for the Venice AI API
140 lines (126 loc) • 4.1 kB
text/typescript
/**
* Utility for processing files for multimodal messages
*/
import * as fs from 'fs';
import * as path from 'path';
import { ContentItem } from '@venice-dev-tools/core/src/types/multimodal';
// Import pdf-parse lazily to avoid loading it when not needed
// import pdfParse from 'pdf-parse';
/**
* Process a file for inclusion in a multimodal message
*
* @param filePath - Path to the file
* @param options - Options for processing the file
* @returns A content item or content items representing the file
*/
export async function processFile(filePath: string, options: { pdfMode?: 'image' | 'text' | 'both' } = {}): Promise<ContentItem | ContentItem[]> {
// Check if file exists
if (!fs.existsSync(filePath)) {
throw new Error(`File not found: ${filePath}`);
}
// Check file size (4.5MB limit)
const stats = fs.statSync(filePath);
const MAX_SIZE = 4.5 * 1024 * 1024; // 4.5MB
if (stats.size > MAX_SIZE) {
throw new Error(`File exceeds maximum size of 4.5MB: ${filePath}`);
}
// Determine file type based on extension
const ext = path.extname(filePath).toLowerCase();
// Handle different file types
if (['.jpg', '.jpeg', '.png', '.gif', '.webp'].includes(ext)) {
// Handle image files
return processImageFile(filePath, getMimeType(ext));
} else if (['.txt', '.md', '.html', '.htm'].includes(ext)) {
// Handle text files
return processTextFile(filePath, getMimeType(ext));
} else if (ext === '.pdf') {
const pdfMode = options.pdfMode || 'image';
if (pdfMode === 'image') {
// Current behavior
return processImageFile(filePath, 'application/pdf');
} else if (pdfMode === 'text') {
// Extract and return text only
const text = await extractTextFromPdf(filePath);
return {
type: 'text',
text: text
};
} else if (pdfMode === 'both') {
// Extract both text and image
const text = await extractTextFromPdf(filePath);
const image = processImageFile(filePath, 'application/pdf');
return [
{
type: 'text',
text: `PDF Text Content:\n${text}`
},
image
];
}
} else {
// For unknown types, default to binary/image handling
return processImageFile(filePath, 'application/octet-stream');
}
// Explicit return statement to ensure all code paths return a value
return processImageFile(filePath, 'application/octet-stream');
}
/**
* Process an image file
*/
function processImageFile(filePath: string, mimeType: string): ContentItem {
const fileData = fs.readFileSync(filePath);
const base64Data = fileData.toString('base64');
return {
type: 'image_url',
image_url: {
url: `data:${mimeType};base64,${base64Data}`
}
};
}
/**
* Process a text file
*/
function processTextFile(filePath: string, mimeType: string): ContentItem {
const content = fs.readFileSync(filePath, 'utf-8');
return {
type: 'text',
text: content
};
}
/**
* Get MIME type from file extension
*/
function getMimeType(ext: string): string {
const mimeMap: Record<string, string> = {
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.png': 'image/png',
'.gif': 'image/gif',
'.webp': 'image/webp',
'.pdf': 'application/pdf',
'.txt': 'text/plain',
'.md': 'text/markdown',
'.html': 'text/html',
'.htm': 'text/html'
};
return mimeMap[ext] || 'application/octet-stream';
}
/**
* Extract text from a PDF file
*/
async function extractTextFromPdf(filePath: string): Promise<string> {
const dataBuffer = fs.readFileSync(filePath);
try {
// Dynamically import pdf-parse only when needed
const pdfParse = (await import('pdf-parse')).default;
const data = await pdfParse(dataBuffer);
return data.text || 'No text content found in PDF';
} catch (error) {
if (error instanceof Error) {
console.error(`Error extracting text from PDF: ${error.message}`);
} else {
console.error('Error extracting text from PDF: Unknown error');
}
return 'Error extracting text from PDF';
}
}