Skip to content

Commit e336928

Browse files
committed
Fix: Add file upload success
1 parent b95b219 commit e336928

File tree

7 files changed

+110
-113
lines changed

7 files changed

+110
-113
lines changed

src/components/chat/FileAttachmentDisplay.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,10 @@ const FileAttachmentDisplay: React.FC<FileAttachmentDisplayProps> = ({
1919
}) => {
2020
let fileData: FileJsonData = {
2121
name: 'File',
22-
path: '',
2322
type: '',
2423
size: 0
2524
};
2625

27-
const filePath = content?.content;
28-
2926
// Handle MessageContent objects
3027
if (content && content.type === MessageContentType.File) {
3128
try {
@@ -40,7 +37,6 @@ const FileAttachmentDisplay: React.FC<FileAttachmentDisplayProps> = ({
4037
else if (file) {
4138
fileData = {
4239
name: file.name,
43-
path: file.webkitRelativePath || file.name,
4440
type: file.type,
4541
size: file.size
4642
};
@@ -51,7 +47,7 @@ const FileAttachmentDisplay: React.FC<FileAttachmentDisplayProps> = ({
5147
}
5248

5349
const fileSize = fileData.size ? formatFileSize(fileData.size) : '';
54-
const fileName = filePath ||fileData.name || 'File';
50+
const fileName = fileData.name || 'File';
5551

5652
// Detect file type to show appropriate icon
5753
const fileExtension = fileName.split('.').pop()?.toLowerCase() || '';

src/services/chat-service.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,11 +305,8 @@ export class ChatService {
305305
conversationUpdate(this.conversations);
306306
//#endregion
307307

308-
//#region Map messages to messages array
309-
console.log('Updated conversation:', updatedConversation);
308+
// Map messages to messages array
310309
const messages = MessageHelper.mapMessagesTreeToList(updatedConversation, false);
311-
console.log('Messages:', messages);
312-
//#endregion
313310

314311
//#region Streaming Special Message Handling
315312
// Create a placeholder for the streaming message
@@ -370,6 +367,8 @@ export class ChatService {
370367

371368
this.streamControllerMap.set(conversationId, streamController);
372369

370+
console.log('Messages:', messages);
371+
373372
// Send Chat Message to AI with streaming
374373
await this.aiService.getChatCompletion(
375374
messages,

src/services/file-upload-service.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,19 +114,19 @@ export class FileUploadService {
114114
throw new Error(`File ${file.name} exceeds size limit or is not supported by ${provider}`);
115115
}
116116

117-
const filePath = file.webkitRelativePath || file.name;
117+
const arrayBuffer = await this.readFile(file);
118+
const base64 = FileUploadService.bufferToBase64(arrayBuffer);
118119

119120
const fileData: FileJsonData = {
120121
name: file.name,
121-
path: filePath,
122122
type: file.type,
123123
size: file.size
124124
};
125125

126126
// Create a message content object for this file
127127
const fileContent: MessageContent = {
128128
type: MessageContentType.File,
129-
content: filePath, // Store the file path
129+
content: base64, // Store the file path
130130
dataJson: JSON.stringify(fileData)
131131
};
132132

@@ -135,4 +135,24 @@ export class FileUploadService {
135135

136136
return results;
137137
}
138-
}
138+
139+
public static bufferToBase64(buffer: ArrayBuffer): string {
140+
const bytes = new Uint8Array(buffer);
141+
let binary = '';
142+
for (let i = 0; i < bytes.byteLength; i++) {
143+
binary += String.fromCharCode(bytes[i]);
144+
}
145+
return btoa(binary);
146+
}
147+
148+
public static base64ToBuffer(base64: string): ArrayBuffer {
149+
const binary = atob(base64);
150+
const buffer = new ArrayBuffer(binary.length);
151+
const bytes = new Uint8Array(buffer);
152+
for (let i = 0; i < binary.length; i++) {
153+
bytes[i] = binary.charCodeAt(i);
154+
}
155+
return buffer;
156+
}
157+
158+
}

src/services/message-helper.ts

Lines changed: 75 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,7 @@
11
import { Conversation, FileJsonData, Message, MessageContent, MessageContentType } from "../types/chat";
22
import { DatabaseIntegrationService } from "./database-integration";
33
import { v4 as uuidv4 } from 'uuid';
4-
import { FileUploadService } from "./file-upload-service";
5-
6-
type OpenAIMessage_Text = {
7-
type: string;
8-
text: string;
9-
}
10-
11-
type OpenAIMessage_File = {
12-
type: string;
13-
data: ArrayBuffer;
14-
mimeType: string;
15-
fileName: string;
16-
}
4+
import { FilePart, CoreMessage, TextPart, CoreUserMessage, CoreAssistantMessage, CoreSystemMessage } from "ai";
175

186
export class MessageHelper {
197

@@ -330,36 +318,86 @@ export class MessageHelper {
330318
}).join('');
331319
}
332320

333-
public static async MessageContentToOpenAIFormat(messageContent: MessageContent[]): Promise<(OpenAIMessage_Text | OpenAIMessage_File | null)[]> {
334-
if (!messageContent || messageContent.length === 0) {
321+
public static MessagesContentToOpenAIFormat(msgs: Message[]): CoreMessage[] {
322+
if (!msgs || msgs.length === 0) {
335323
return [];
336324
}
325+
326+
console.log('before msgs: ', msgs);
337327

338-
const results = await Promise.all(messageContent.map(async (content) => {
339-
if(content.type === MessageContentType.Text) {
340-
const textContent: OpenAIMessage_Text = {
341-
type: 'text',
342-
text: content.content
343-
};
344-
return textContent;
328+
const results = msgs.map((msg) => {
329+
330+
if(msg.role === 'user') {
331+
const userMsg: CoreUserMessage = {
332+
role: 'user',
333+
content: msg.content.map((content) => {
334+
if(content.type === MessageContentType.Text) {
335+
const textContent: TextPart = {
336+
type: 'text',
337+
text: content.content
338+
};
339+
return textContent;
340+
}
341+
else if(content.type === MessageContentType.File) {
342+
const dataJson: FileJsonData = JSON.parse(content.dataJson) as FileJsonData;
343+
344+
console.log('Processing file: ', dataJson.name);
345+
346+
const fileContent: FilePart = {
347+
type: 'file',
348+
data: content.content,
349+
mimeType: 'application/pdf',
350+
filename: dataJson.name
351+
}
352+
return fileContent;
353+
}
354+
355+
const emptyText: TextPart = {
356+
type: 'text',
357+
text: ''
358+
};
359+
return emptyText;
360+
})
361+
}
362+
363+
return userMsg;
364+
}
365+
else if(msg.role === 'assistant') {
366+
let stringContent: string = '';
367+
368+
for(const content of msg.content) {
369+
if(content.type === MessageContentType.Text) {
370+
stringContent += content.content;
371+
}
372+
}
373+
374+
const assistantMsg: CoreAssistantMessage = {
375+
role: 'assistant',
376+
content: stringContent
377+
}
378+
379+
return assistantMsg;
345380
}
346-
else if(content.type === MessageContentType.File) {
347-
const dataJson: FileJsonData = JSON.parse(content.dataJson) as FileJsonData;
348-
349-
const fileBuffer = await FileUploadService.getInstance().readFile(dataJson.name);
350-
351-
const fileContent: OpenAIMessage_File = {
352-
type: 'file',
353-
data: fileBuffer,
354-
mimeType: dataJson.type,
355-
fileName: dataJson.name
356-
};
357-
return fileContent;
381+
else if(msg.role === 'system') {
382+
let stringContent: string = '';
383+
384+
for(const content of msg.content) {
385+
if(content.type === MessageContentType.Text) {
386+
stringContent += content.content;
387+
}
388+
}
389+
390+
const systemMsg: CoreSystemMessage = {
391+
role: 'system',
392+
content: stringContent
393+
}
394+
395+
return systemMsg;
358396
}
359-
return null;
360-
}));
397+
398+
});
361399

362-
return results;
400+
return results.filter((result) => result !== undefined) as CoreMessage[];
363401
}
364402

365403
public static insertMessageIdToFathterMessage(fatherMessage: Message, messageId: string): Message {

src/services/providers/common-provider-service.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,9 @@ export class CommonProviderHelper implements AiServiceProvider {
146146
toolChoice: ToolChoice<ToolSet> | undefined = undefined
147147
): Promise<Message> {
148148
try {
149-
const formattedMessages = messages.map(msg => ({
150-
role: msg.role,
151-
content: MessageHelper.MessageContentToText(msg.content)
152-
}));
149+
const formattedMessages = MessageHelper.MessagesContentToOpenAIFormat(messages);
150+
151+
console.log('formattedMessages: ', formattedMessages);
153152

154153
let fullText = '';
155154

src/services/providers/openai-service.ts

Lines changed: 4 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createOpenAI, openai, OpenAIProvider } from '@ai-sdk/openai';
2-
import { Message, MessageContentType } from '../../types/chat';
2+
import { Message } from '../../types/chat';
33
import { AiServiceProvider, CompletionOptions } from '../core/ai-service-provider';
44
import { StreamControlHandler } from '../streaming-control';
55
import { CommonProviderHelper } from './common-provider-service';
@@ -109,68 +109,14 @@ export class OpenAIService implements AiServiceProvider {
109109
options: CompletionOptions,
110110
streamController: StreamControlHandler
111111
): Promise<Message> {
112-
const isWebSearchActive = SettingsService.getInstance().getWebSearchActive();
113112

114-
// Check for file content in messages
115-
const messagesWithFiles = await this.processMessagesWithFiles(messages);
113+
const isWebSearchActive = SettingsService.getInstance().getWebSearchActive();
116114

117115
if (isWebSearchActive) {
118-
return this.getChatCompletionWithWebSearch(messagesWithFiles, options, streamController);
116+
return this.getChatCompletionWithWebSearch(messages, options, streamController);
119117
}
120118

121-
return this.commonProviderHelper.getChatCompletion(messagesWithFiles, options, streamController);
122-
}
123-
124-
/**
125-
* Process messages to handle file content for OpenAI
126-
* This converts file paths in messages to OpenAI file objects
127-
*/
128-
private async processMessagesWithFiles(messages: Message[]): Promise<Message[]> {
129-
const processedMessages: Message[] = [];
130-
131-
for (const message of messages) {
132-
let hasFileContent = false;
133-
const fileContents: { type: string; file_path: string; }[] = [];
134-
const textParts: string[] = [];
135-
136-
// Extract file content and text content
137-
for (const content of message.content) {
138-
if (content.type === MessageContentType.Text) {
139-
textParts.push(content.content);
140-
} else if (content.type === MessageContentType.File) {
141-
hasFileContent = true;
142-
// For OpenAI, we use the file_path format
143-
fileContents.push({
144-
type: 'file_path',
145-
file_path: content.content
146-
});
147-
}
148-
}
149-
150-
if (hasFileContent) {
151-
// Create a processed message with OpenAI format for files
152-
const processedMessage: Message = {
153-
...message,
154-
content: [{
155-
type: MessageContentType.Text,
156-
content: JSON.stringify({
157-
type: 'text',
158-
text: textParts.join(' ')
159-
}),
160-
dataJson: JSON.stringify({
161-
type: 'file_content',
162-
file_contents: fileContents
163-
})
164-
}]
165-
};
166-
processedMessages.push(processedMessage);
167-
} else {
168-
// No file content, keep original message
169-
processedMessages.push(message);
170-
}
171-
}
172-
173-
return processedMessages;
119+
return this.commonProviderHelper.getChatCompletion(messages, options, streamController);
174120
}
175121

176122
public async getChatCompletionWithWebSearch(

src/types/chat.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ export enum MessageContentType {
1111

1212
export interface FileJsonData{
1313
name: string;
14-
path: string;
1514
type: string;
1615
size: number;
1716
}

0 commit comments

Comments
 (0)