mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-29 19:12:27 +08:00
well this at least allows for streaming responses when no tool calls are made
This commit is contained in:
parent
263c869091
commit
d1edf59f97
@ -87,9 +87,13 @@ export async function setupStreamingResponse(
|
|||||||
// Handle content updates
|
// Handle content updates
|
||||||
if (message.content) {
|
if (message.content) {
|
||||||
receivedAnyContent = true;
|
receivedAnyContent = true;
|
||||||
|
|
||||||
|
console.log(`[${responseId}] Received content chunk of length ${message.content.length}, preview: "${message.content.substring(0, 50)}${message.content.length > 50 ? '...' : ''}"`);
|
||||||
|
|
||||||
|
// Add to our accumulated response
|
||||||
assistantResponse += message.content;
|
assistantResponse += message.content;
|
||||||
|
|
||||||
// Update the UI immediately
|
// Update the UI immediately with each chunk
|
||||||
onContentUpdate(assistantResponse);
|
onContentUpdate(assistantResponse);
|
||||||
|
|
||||||
// Reset timeout since we got content
|
// Reset timeout since we got content
|
||||||
|
@ -430,13 +430,27 @@ export class OllamaService extends BaseAIService {
|
|||||||
|
|
||||||
// Call the callback with the current chunk content
|
// Call the callback with the current chunk content
|
||||||
if (opts.streamCallback) {
|
if (opts.streamCallback) {
|
||||||
await StreamProcessor.sendChunkToCallback(
|
// For chunks with content, send the content directly
|
||||||
opts.streamCallback,
|
if (chunk.message?.content) {
|
||||||
chunk.message?.content || '',
|
log.info(`Sending direct chunk #${chunkCount} with content: "${chunk.message.content.substring(0, 50)}${chunk.message.content.length > 50 ? '...' : ''}"`);
|
||||||
false, // Never mark as done during processing
|
|
||||||
chunk,
|
await StreamProcessor.sendChunkToCallback(
|
||||||
chunkCount
|
opts.streamCallback,
|
||||||
);
|
chunk.message.content,
|
||||||
|
!!chunk.done, // Mark as done if done flag is set
|
||||||
|
chunk,
|
||||||
|
chunkCount
|
||||||
|
);
|
||||||
|
} else if (chunk.done) {
|
||||||
|
// Send empty done message for final chunk with no content
|
||||||
|
await StreamProcessor.sendChunkToCallback(
|
||||||
|
opts.streamCallback,
|
||||||
|
'',
|
||||||
|
true,
|
||||||
|
chunk,
|
||||||
|
chunkCount
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is the done chunk, log it
|
// If this is the done chunk, log it
|
||||||
@ -446,7 +460,9 @@ export class OllamaService extends BaseAIService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send one final callback with done=true after all chunks have been processed
|
// Send one final callback with done=true after all chunks have been processed
|
||||||
if (opts.streamCallback) {
|
// Only send this if the last chunk didn't already have done=true
|
||||||
|
if (opts.streamCallback && (!finalChunk || !finalChunk.done)) {
|
||||||
|
log.info(`Sending explicit final callback with done=true flag after all chunks processed`);
|
||||||
await StreamProcessor.sendFinalCallback(opts.streamCallback, completeText);
|
await StreamProcessor.sendFinalCallback(opts.streamCallback, completeText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,9 +40,9 @@ export class StreamProcessor {
|
|||||||
let textToAdd = '';
|
let textToAdd = '';
|
||||||
let logged = false;
|
let logged = false;
|
||||||
|
|
||||||
// Log first chunk and periodic updates
|
// Enhanced logging for content chunks and completion status
|
||||||
if (chunkCount === 1 || chunkCount % 10 === 0) {
|
if (chunkCount === 1 || chunkCount % 10 === 0 || chunk.done) {
|
||||||
log.info(`Processing ${options.providerName} stream chunk #${chunkCount}, done=${!!chunk.done}, has content=${!!chunk.message?.content}`);
|
log.info(`Processing ${options.providerName} stream chunk #${chunkCount}, done=${!!chunk.done}, has content=${!!chunk.message?.content}, content length=${chunk.message?.content?.length || 0}`);
|
||||||
logged = true;
|
logged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,10 +52,19 @@ export class StreamProcessor {
|
|||||||
const newCompleteText = completeText + textToAdd;
|
const newCompleteText = completeText + textToAdd;
|
||||||
|
|
||||||
if (chunkCount === 1) {
|
if (chunkCount === 1) {
|
||||||
log.info(`First content chunk: "${textToAdd.substring(0, 50)}${textToAdd.length > 50 ? '...' : ''}"`);
|
// Log the first chunk more verbosely for debugging
|
||||||
|
log.info(`First content chunk [${chunk.message.content.length} chars]: "${textToAdd.substring(0, 100)}${textToAdd.length > 100 ? '...' : ''}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For final chunks with done=true, log more information
|
||||||
|
if (chunk.done) {
|
||||||
|
log.info(`Final content chunk received with done=true flag. Length: ${chunk.message.content.length}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { completeText: newCompleteText, logged };
|
return { completeText: newCompleteText, logged };
|
||||||
|
} else if (chunk.done) {
|
||||||
|
// If it's the final chunk with no content, log this case
|
||||||
|
log.info(`Empty final chunk received with done=true flag`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { completeText, logged };
|
return { completeText, logged };
|
||||||
@ -72,7 +81,15 @@ export class StreamProcessor {
|
|||||||
chunkNumber: number
|
chunkNumber: number
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const result = callback(content || '', done, chunk);
|
// Log all done=true callbacks and first chunk for debugging
|
||||||
|
if (done || chunkNumber === 1) {
|
||||||
|
log.info(`Sending chunk to callback: chunkNumber=${chunkNumber}, contentLength=${content?.length || 0}, done=${done}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always make sure we have a string for content
|
||||||
|
const safeContent = content || '';
|
||||||
|
|
||||||
|
const result = callback(safeContent, done, chunk);
|
||||||
// Handle both Promise and void return types
|
// Handle both Promise and void return types
|
||||||
if (result instanceof Promise) {
|
if (result instanceof Promise) {
|
||||||
await result;
|
await result;
|
||||||
@ -81,6 +98,10 @@ export class StreamProcessor {
|
|||||||
if (chunkNumber === 1) {
|
if (chunkNumber === 1) {
|
||||||
log.info(`Successfully called streamCallback with first chunk`);
|
log.info(`Successfully called streamCallback with first chunk`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (done) {
|
||||||
|
log.info(`Successfully called streamCallback with done=true flag`);
|
||||||
|
}
|
||||||
} catch (callbackError) {
|
} catch (callbackError) {
|
||||||
log.error(`Error in streamCallback: ${callbackError}`);
|
log.error(`Error in streamCallback: ${callbackError}`);
|
||||||
}
|
}
|
||||||
@ -94,12 +115,18 @@ export class StreamProcessor {
|
|||||||
completeText: string
|
completeText: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
log.info(`Sending final done=true callback after processing all chunks`);
|
log.info(`Sending explicit final done=true callback after processing all chunks. Complete text length: ${completeText?.length || 0}`);
|
||||||
const result = callback('', true, { done: true });
|
|
||||||
|
// Pass the complete text instead of empty string for better UX
|
||||||
|
// The client will know it's done based on the done=true flag
|
||||||
|
const result = callback(completeText || '', true, { done: true, complete: true });
|
||||||
|
|
||||||
// Handle both Promise and void return types
|
// Handle both Promise and void return types
|
||||||
if (result instanceof Promise) {
|
if (result instanceof Promise) {
|
||||||
await result;
|
await result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.info(`Final callback sent successfully with done=true flag`);
|
||||||
} catch (finalCallbackError) {
|
} catch (finalCallbackError) {
|
||||||
log.error(`Error in final streamCallback: ${finalCallbackError}`);
|
log.error(`Error in final streamCallback: ${finalCallbackError}`);
|
||||||
}
|
}
|
||||||
|
@ -1163,18 +1163,22 @@ class RestChatService {
|
|||||||
if (chunk.text) {
|
if (chunk.text) {
|
||||||
messageContent += chunk.text;
|
messageContent += chunk.text;
|
||||||
|
|
||||||
// Send the chunk content via WebSocket
|
// Enhanced logging for each chunk
|
||||||
|
log.info(`Received stream chunk from ${service.getName()} with ${chunk.text.length} chars of text, done=${!!chunk.done}`);
|
||||||
|
|
||||||
|
// Send each individual chunk via WebSocket as it arrives
|
||||||
wsService.sendMessageToAllClients({
|
wsService.sendMessageToAllClients({
|
||||||
type: 'llm-stream',
|
type: 'llm-stream',
|
||||||
sessionId,
|
sessionId,
|
||||||
content: chunk.text,
|
content: chunk.text,
|
||||||
|
done: !!chunk.done, // Include done flag with each chunk
|
||||||
// Include any raw data from the provider that might contain thinking/tool info
|
// Include any raw data from the provider that might contain thinking/tool info
|
||||||
...(chunk.raw ? { raw: chunk.raw } : {})
|
...(chunk.raw ? { raw: chunk.raw } : {})
|
||||||
} as LLMStreamMessage);
|
} as LLMStreamMessage);
|
||||||
|
|
||||||
// Log the first chunk (useful for debugging)
|
// Log the first chunk (useful for debugging)
|
||||||
if (messageContent.length === chunk.text.length) {
|
if (messageContent.length === chunk.text.length) {
|
||||||
log.info(`First stream chunk received from ${service.getName()}`);
|
log.info(`First stream chunk received from ${service.getName()}: "${chunk.text.substring(0, 50)}${chunk.text.length > 50 ? '...' : ''}"`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1198,15 +1202,23 @@ class RestChatService {
|
|||||||
|
|
||||||
// Signal completion when done
|
// Signal completion when done
|
||||||
if (chunk.done) {
|
if (chunk.done) {
|
||||||
log.info(`Stream completed from ${service.getName()}`);
|
log.info(`Stream completed from ${service.getName()}, total content: ${messageContent.length} chars`);
|
||||||
|
|
||||||
// Send the final message with both content and done flag together
|
// Only send final done message if it wasn't already sent with content
|
||||||
wsService.sendMessageToAllClients({
|
// This ensures we don't duplicate the content but still mark completion
|
||||||
type: 'llm-stream',
|
if (!chunk.text) {
|
||||||
sessionId,
|
// Send final message with both content and done flag together
|
||||||
content: messageContent, // Send the accumulated content
|
wsService.sendMessageToAllClients({
|
||||||
done: true
|
type: 'llm-stream',
|
||||||
} as LLMStreamMessage);
|
sessionId,
|
||||||
|
content: messageContent, // Send the accumulated content
|
||||||
|
done: true
|
||||||
|
} as LLMStreamMessage);
|
||||||
|
|
||||||
|
log.info(`Sent explicit final completion message with accumulated content`);
|
||||||
|
} else {
|
||||||
|
log.info(`Final done flag was already sent with content chunk, no need for extra message`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user