continue scaffolding and refine the basic foundation
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
import { protectRoute } from '~~/server/utils/auth';
|
||||
import { registerPendingGeneration } from '~~/server/utils/generation';
|
||||
import { createPendingGeneration } from '~~/server/utils/generation';
|
||||
import type { GenerateRequestBody } from '~~/server/types/chat';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await protectRoute(event);
|
||||
|
||||
const body = await readBody(event) as GenerateRequestBody;
|
||||
const { topicId, messages } = body;
|
||||
const { topicId, messages, regeneratesFrom } = body;
|
||||
|
||||
if (!topicId || !messages) {
|
||||
throw createError({
|
||||
@@ -22,12 +22,19 @@ export default defineEventHandler(async (event) => {
|
||||
});
|
||||
}
|
||||
|
||||
const generationId = `gen_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
||||
try {
|
||||
const generationId = await createPendingGeneration(event.context.user.id, topicId, messages, regeneratesFrom);
|
||||
|
||||
registerPendingGeneration(event.context.user.id, generationId, topicId, messages);
|
||||
|
||||
return {
|
||||
generationId,
|
||||
status: 'pending'
|
||||
};
|
||||
return {
|
||||
generationId,
|
||||
status: 'pending',
|
||||
regeneratesFrom
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Failed to create generation:', error);
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Failed to create generation'
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import { protectRoute } from '~~/server/utils/auth';
|
||||
import { getPendingGeneration, getActiveGeneration, isGenerationActive } from '~~/server/utils/generation';
|
||||
import type { GenerationStatus } from '~~/server/types/chat';
|
||||
import { getGenerationStatus } from '~~/server/utils/generation';
|
||||
import type { GenerationStatusResponse } from '~~/server/types/chat';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await protectRoute(event);
|
||||
@@ -14,39 +14,30 @@ export default defineEventHandler(async (event) => {
|
||||
});
|
||||
}
|
||||
|
||||
const pendingGeneration = getPendingGeneration(generationId);
|
||||
const isActive = isGenerationActive(generationId);
|
||||
const activeGeneration = getActiveGeneration(generationId);
|
||||
const generation = await getGenerationStatus(generationId);
|
||||
|
||||
if (!pendingGeneration && !activeGeneration) {
|
||||
if (!generation) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: 'Generation not found'
|
||||
});
|
||||
}
|
||||
|
||||
if (pendingGeneration) {
|
||||
const status: GenerationStatus = {
|
||||
generationId,
|
||||
status: 'pending',
|
||||
topicId: pendingGeneration.topicId
|
||||
};
|
||||
return status;
|
||||
// Verify ownership
|
||||
if (generation.userId !== event.context.user.id) {
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: 'Unauthorized'
|
||||
});
|
||||
}
|
||||
|
||||
if (isActive && activeGeneration) {
|
||||
const status: GenerationStatus = {
|
||||
generationId,
|
||||
status: 'active',
|
||||
content: activeGeneration.content,
|
||||
topicId: activeGeneration.topicId
|
||||
};
|
||||
return status;
|
||||
}
|
||||
|
||||
const status: GenerationStatus = {
|
||||
const status: GenerationStatusResponse = {
|
||||
generationId,
|
||||
status: 'completed'
|
||||
status: generation.status as any,
|
||||
topicId: generation.topicId,
|
||||
content: generation.content,
|
||||
error: generation.error || undefined
|
||||
};
|
||||
|
||||
return status;
|
||||
});
|
||||
@@ -1,8 +1,9 @@
|
||||
import { protectRoute } from '~~/server/utils/auth';
|
||||
import { getPendingGeneration, startGeneration, addClientToGeneration, removeClientFromGeneration, sendToClient } from '~~/server/utils/generation';
|
||||
import { startGeneration, addClientToGeneration, removeClientFromGeneration, sendToClient, isGenerationStreaming, getGenerationStatus } from '~~/server/utils/generation';
|
||||
import { eventHandler, setHeader, setResponseStatus } from 'h3';
|
||||
import { generations, messages } from '~~/db/schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { useDrizzle } from '~~/server/utils/drizzle';
|
||||
import { generations, messages } from '~~/db/schema';
|
||||
|
||||
export default eventHandler(async (event) => {
|
||||
await protectRoute(event);
|
||||
@@ -16,12 +17,20 @@ export default eventHandler(async (event) => {
|
||||
});
|
||||
}
|
||||
|
||||
const pendingGeneration = getPendingGeneration(generationId);
|
||||
|
||||
if (pendingGeneration && pendingGeneration.expired) {
|
||||
// Fetch generation from database
|
||||
const generation = await getGenerationStatus(generationId);
|
||||
if (!generation) {
|
||||
throw createError({
|
||||
statusCode: 410,
|
||||
statusMessage: 'Generation expired - no client connected within 60 seconds'
|
||||
statusCode: 404,
|
||||
statusMessage: 'Generation not found'
|
||||
});
|
||||
}
|
||||
|
||||
// Verify ownership
|
||||
if (generation.userId !== event.context.user.id) {
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: 'Unauthorized'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -32,36 +41,81 @@ export default eventHandler(async (event) => {
|
||||
|
||||
setResponseStatus(event, 200);
|
||||
|
||||
const shouldStartGeneration = pendingGeneration;
|
||||
|
||||
try {
|
||||
const stream = new ReadableStream({
|
||||
async start(controller) {
|
||||
addClientToGeneration(generationId, controller);
|
||||
try {
|
||||
// If generation is already completed, send the completed message
|
||||
if (generation.status === 'completed' && generation.messageId) {
|
||||
const db = useDrizzle();
|
||||
const [message] = await db
|
||||
.select()
|
||||
.from(messages)
|
||||
.where(eq(messages.id, generation.messageId));
|
||||
|
||||
if (shouldStartGeneration) {
|
||||
startGeneration(generationId, controller);
|
||||
} else {
|
||||
const generation = await useDrizzle().select().from(generations).where(eq(generations.id, getRouterParam(event, 'id')!))
|
||||
if (!generation) throw createError({ statusCode: 404, statusMessage: 'Generation not found' });
|
||||
const message = await useDrizzle().select().from(messages).where(eq(messages.id, generation[0].messageId!))
|
||||
if (!message) throw createError({ statusCode: 404, statusMessage: 'Message not found' });
|
||||
if (message) {
|
||||
sendToClient(controller, {
|
||||
type: 'complete',
|
||||
data: message
|
||||
});
|
||||
}
|
||||
controller.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// If generation failed, send the error
|
||||
if (generation.status === 'failed') {
|
||||
sendToClient(controller, {
|
||||
type: 'error',
|
||||
data: { error: generation.error || 'Generation failed' }
|
||||
});
|
||||
controller.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// If already streaming, just add this client
|
||||
if (isGenerationStreaming(generationId)) {
|
||||
addClientToGeneration(generationId, controller);
|
||||
} else {
|
||||
// Start generation if in pending status
|
||||
if (generation.status === 'pending') {
|
||||
// Fetch the original messages context (stored in topic messages)
|
||||
const db = useDrizzle();
|
||||
const topicMessages = await db
|
||||
.select()
|
||||
.from(messages)
|
||||
.where(eq(messages.topicId, generation.topicId));
|
||||
|
||||
const chatMessages = topicMessages.map(m => ({
|
||||
type: m.isUser ? 'user' as const : ('agent' as const),
|
||||
message: m.content
|
||||
}));
|
||||
|
||||
addClientToGeneration(generationId, controller);
|
||||
await startGeneration(generationId, generation.userId, generation.topicId, chatMessages, controller);
|
||||
}
|
||||
}
|
||||
|
||||
event.node.req.on('close', () => {
|
||||
removeClientFromGeneration(generationId, controller);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Stream start error:', error);
|
||||
sendToClient(controller, {
|
||||
type: 'complete',
|
||||
data: message[0].content
|
||||
type: 'error',
|
||||
data: { error: 'Stream initialization failed' }
|
||||
});
|
||||
controller.close();
|
||||
}
|
||||
|
||||
event.node.req.on('close', () => {
|
||||
removeClientFromGeneration(generationId, controller);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return sendStream(event, stream);
|
||||
} catch (error) {
|
||||
// assume it failed because the generation is complete so try to send the message
|
||||
console.error('Stream error:', error);
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Stream error'
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user