1- import type { Message } from '$lib/types/database' ;
2-
3- export interface LlamaCppServerProps {
4- build_info : string ;
5- model_path : string ;
6- n_ctx : number ;
7- modalities ?: {
8- vision : boolean ;
9- audio : boolean ;
10- } ;
11- }
1+ import type {
2+ ApiChatMessageContentPart ,
3+ ApiChatMessageData ,
4+ ApiChatCompletionRequest ,
5+ ApiChatCompletionStreamChunk ,
6+ ApiChatCompletionResponse ,
7+ ApiLlamaCppServerProps
8+ } from '$lib/types/api' ;
9+
10+ import type {
11+ DatabaseMessage ,
12+ DatabaseMessageExtra ,
13+ DatabaseMessageExtraImageFile ,
14+ DatabaseMessageExtraTextFile
15+ } from '$lib/types/database'
1216
1317export class ChatService {
1418 private baseUrl : string ;
@@ -19,7 +23,7 @@ export class ChatService {
1923 }
2024
2125 async sendMessage (
22- messages : ChatMessageData [ ] ,
26+ messages : ApiChatMessageData [ ] ,
2327 options : {
2428 stream ?: boolean ;
2529 temperature ?: number ;
@@ -35,7 +39,7 @@ export class ChatService {
3539 this . abort ( ) ;
3640 this . abortController = new AbortController ( ) ;
3741
38- const requestBody : ChatCompletionRequest = {
42+ const requestBody : ApiChatCompletionRequest = {
3943 messages : messages . map ( ( msg ) => ( {
4044 role : msg . role ,
4145 content : msg . content
@@ -119,7 +123,7 @@ export class ChatService {
119123 }
120124
121125 try {
122- const parsed : ChatCompletionStreamChunk = JSON . parse ( data ) ;
126+ const parsed : ApiChatCompletionStreamChunk = JSON . parse ( data ) ;
123127 const content = parsed . choices [ 0 ] ?. delta ?. content ;
124128 if ( content ) {
125129 fullResponse += content ;
@@ -161,7 +165,7 @@ export class ChatService {
161165 onError ?: ( error : Error ) => void
162166 ) : Promise < string > {
163167 try {
164- const data : ChatCompletionResponse = await response . json ( ) ;
168+ const data : ApiChatCompletionResponse = await response . json ( ) ;
165169 const content = data . choices [ 0 ] ?. message ?. content || '' ;
166170
167171 onComplete ?.( content ) ;
@@ -177,10 +181,57 @@ export class ChatService {
177181 }
178182
179183 /**
180- * Unified method to send chat completions supporting both ChatMessageData and Message types
184+ * Convert Message with extras to ApiChatMessageData format for API requests
185+ */
186+ private static convertMessageToChatData ( message : DatabaseMessage & { extra ?: DatabaseMessageExtra [ ] } ) : ApiChatMessageData {
187+ // If no extras, return simple text message
188+ if ( ! message . extra || message . extra . length === 0 ) {
189+ return {
190+ role : message . role as 'user' | 'assistant' | 'system' ,
191+ content : message . content
192+ } ;
193+ }
194+
195+ // Build multimodal content array
196+ const contentParts : ApiChatMessageContentPart [ ] = [ ] ;
197+
198+ // Add text content first
199+ if ( message . content ) {
200+ contentParts . push ( {
201+ type : 'text' ,
202+ text : message . content
203+ } ) ;
204+ }
205+
206+ // Add image files
207+ const imageFiles = message . extra . filter ( ( extra ) : extra is DatabaseMessageExtraImageFile => extra . type === 'imageFile' ) ;
208+ imageFiles . forEach ( ( image ) => {
209+ contentParts . push ( {
210+ type : 'image_url' ,
211+ image_url : { url : image . base64Url }
212+ } ) ;
213+ } ) ;
214+
215+ // Add text files as additional text content
216+ const textFiles = message . extra . filter ( ( extra ) : extra is DatabaseMessageExtraTextFile => extra . type === 'textFile' ) ;
217+ textFiles . forEach ( ( textFile ) => {
218+ contentParts . push ( {
219+ type : 'text' ,
220+ text : `\n\n--- File: ${ textFile . name } ---\n${ textFile . content } `
221+ } ) ;
222+ } ) ;
223+
224+ return {
225+ role : message . role as 'user' | 'assistant' | 'system' ,
226+ content : contentParts
227+ } ;
228+ }
229+
230+ /**
231+ * Unified method to send chat completions supporting both ApiChatMessageData and Message types
181232 */
182233 async sendChatCompletion (
183- messages : ChatMessageData [ ] | Message [ ] ,
234+ messages : ( ApiChatMessageData [ ] | DatabaseMessage [ ] ) | ( DatabaseMessage & { extra ?: DatabaseMessageExtra [ ] } ) [ ] ,
184235 options : {
185236 stream ?: boolean ;
186237 temperature ?: number ;
@@ -190,12 +241,16 @@ export class ChatService {
190241 onError ?: ( error : Error ) => void ;
191242 } = { }
192243 ) : Promise < string | void > {
193- // Normalize messages to ChatMessageData format
194- const normalizedMessages : ChatMessageData [ ] = messages . map ( ( msg ) => ( {
195- role : msg . role as ChatMessageData [ 'role' ] ,
196- content : msg . content ,
197- timestamp : 'timestamp' in msg ? msg . timestamp : undefined
198- } ) ) ;
244+ // Handle both array formats and convert messages with extras
245+ const normalizedMessages : ApiChatMessageData [ ] = messages . map ( ( msg ) => {
246+ // Check if this is already a ApiChatMessageData object
247+ if ( 'content' in msg && ( typeof msg . content === 'string' || Array . isArray ( msg . content ) ) ) {
248+ return msg as ApiChatMessageData ;
249+ }
250+
251+ // Convert DatabaseMessage with extras to ApiChatMessageData
252+ return ChatService . convertMessageToChatData ( msg as DatabaseMessage & { extra ?: DatabaseMessageExtra [ ] } ) ;
253+ } ) ;
199254
200255 // Set default options for API compatibility
201256 const finalOptions = {
@@ -212,7 +267,7 @@ export class ChatService {
212267 * Static method for backward compatibility with ApiService
213268 */
214269 static async sendChatCompletion (
215- messages : Message [ ] ,
270+ messages : DatabaseMessage [ ] ,
216271 onChunk ?: ( content : string ) => void ,
217272 onComplete ?: ( ) => void ,
218273 onError ?: ( error : Error ) => void
@@ -232,7 +287,7 @@ export class ChatService {
232287 /**
233288 * Get server properties - static method for API compatibility
234289 */
235- static async getServerProps ( ) : Promise < LlamaCppServerProps > {
290+ static async getServerProps ( ) : Promise < ApiLlamaCppServerProps > {
236291 try {
237292 const response = await fetch ( `${ import . meta. env . VITE_BASE_URL } /props` , {
238293 headers : {
0 commit comments