feat: add chat and file management APIs, implement chat loading and saving functionality

- Introduced new API endpoints for chat management including posting and retrieving chat messages.
- Implemented file upload and deletion functionalities for chat and other files.
- Added utility functions for streaming text and loading chat data.
- Created TypeScript types for models and agents used in the application.
- Configured TypeScript settings for server and project.
- Added favicon and workspace configuration for pnpm.
This commit is contained in:
2025-04-14 12:19:30 +02:00
commit c0b5539f12
29 changed files with 12941 additions and 0 deletions

55
server/api/chat.post.ts Normal file
View File

@@ -0,0 +1,55 @@
import type { Message } from 'ai'
import { appendResponseMessages, appendClientMessage, streamText } from 'ai'
import { createWorkersAI } from 'workers-ai-provider'
import { loadChat } from '~~/server/utils/chat'
export default defineEventHandler(async (event) => {
const { id, message, model, agent } = await readBody(event)
console.log(model, agent)
const workersAI = createWorkersAI({ binding: hubAI() })
const previousMessages = await loadChat(id)
const messages = appendClientMessage({
messages: previousMessages,
message
})
const result = streamText({
model: workersAI('@cf/meta/llama-3.1-8b-instruct'),
// system, TODO: add system
// prompt, TODO: add prompt
messages,
// tools, TODO: add tools
async onFinish({ response }) {
await saveChat({
id,
messages: appendResponseMessages({
messages,
responseMessages: response.messages
})
})
}
})
result.consumeStream()
return result.toDataStreamResponse()
})
async function saveChat({ id, messages }: { id: string, messages: Message[] }) {
const hub = hubBlob()
await hub.delete(`chats/${id}.json`)
await $fetch('/api/chats', {
method: 'POST',
body: {
file: {
name: `${id}.json`,
content: JSON.stringify(messages, null, 2)
}
}
})
}

View File

@@ -0,0 +1,27 @@
import { streamToText } from '~~/server/utils/stream'
export default eventHandler(async (event) => {
const { pathname } = getRouterParams(event)
try {
const stream = await hubBlob().serve(event, `chats/${pathname}.json`)
if (!(stream instanceof ReadableStream)) {
throw new Error('Le stream n\'est pas valide')
}
const read = await streamToText(stream)
try {
return JSON.parse(read)
}
catch (jsonError) {
console.error('Erreur lors du parsing JSON:', jsonError)
return { error: 'Erreur de format JSON' }
}
}
catch (error) {
console.error('Erreur lors du traitement du stream:', error)
return { error: 'Erreur serveur' }
}
})

View File

@@ -0,0 +1,18 @@
export default eventHandler(async (event) => {
const body = await readBody(event)
const file = new File([body.file.content], body.file.name, { type: 'application/json' })
if (!file || !file.size) {
throw createError({ statusCode: 400, message: 'No file provided' })
}
ensureBlob(file, {
maxSize: '1MB',
types: ['application/jsonml+json', 'application/json']
})
return hubBlob().put(file.name, file, {
addRandomSuffix: false,
prefix: 'chats'
})
})

View File

@@ -0,0 +1,12 @@
import { z } from 'zod'
import { useValidatedBody } from 'h3-zod'
export default eventHandler(async (event) => {
const { pathname } = await useValidatedBody(event, {
pathname: z.string()
})
await hubBlob().del(pathname)
return sendNoContent(event)
})

View File

@@ -0,0 +1,3 @@
export default defineEventHandler(() => {
return hubBlob().list()
})

View File

@@ -0,0 +1,18 @@
export default eventHandler(async (event) => {
const form = await readFormData(event)
const file = form.get('file') as File
if (!file || !file.size) {
throw createError({ statusCode: 400, message: 'No file provided' })
}
ensureBlob(file, {
maxSize: '1MB',
types: ['image', 'pdf', 'application/pdf']
})
return hubBlob().put(file.name, file, {
addRandomSuffix: false,
prefix: 'files'
})
})