From 56300d8c8aaa8a9eb4af32782024fd00c4e65168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Go=CC=81mez=20Bachiller?= Date: Sun, 13 Oct 2024 14:25:43 +0000 Subject: [PATCH] feat: update base bot template --- .devcontainer/devcontainer.json | 10 +++++---- src/lib/ai/embeddings.ts | 6 ++--- src/lib/ai/resources.ts | 39 +++++++++++++++++++++++++++++++++ src/lib/ai/setup-registry.ts | 27 +++++++++++++++++++++++ src/lib/commands/start.ts | 6 +++++ src/lib/handlers/on-message.ts | 8 +++++++ src/lib/utils.ts | 4 ++++ src/main.ts | 19 +++++----------- 8 files changed, 99 insertions(+), 20 deletions(-) create mode 100644 src/lib/ai/resources.ts create mode 100644 src/lib/ai/setup-registry.ts create mode 100644 src/lib/commands/start.ts create mode 100644 src/lib/handlers/on-message.ts diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 5ef5919..ed4510b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -16,15 +16,14 @@ "mtxr.sqltools", "mtxr.sqltools-driver-pg", "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode", - "editorconfig.editorconfig" + "esbenp.prettier-vscode" ], "settings": { "editor.codeActionsOnSave": { "source.fixAll": "explicit", "source.fixAll.eslint": "explicit" }, - "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.defaultFormatter": "dbaeumer.vscode-eslint", "editor.formatOnSave": true, "eslint.format.enable": true, "sqltools.connections": [ @@ -37,7 +36,10 @@ "username": "postgres", "password": "postgres" } - ] + ], + "[typescript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + } } } } diff --git a/src/lib/ai/embeddings.ts b/src/lib/ai/embeddings.ts index 93ef50b..3f6b6c8 100644 --- a/src/lib/ai/embeddings.ts +++ b/src/lib/ai/embeddings.ts @@ -1,10 +1,10 @@ import { embed, embedMany } from 'ai' -import { cosineDistance, desc, sql } from 'drizzle-orm' +import { cosineDistance, desc, gt, sql } from 'drizzle-orm' -import { registry } from '../../setup-registry' import { db as database } from '../db' import { embeddings } from '../db/schema/embeddings' import { environment } from '../environment.mjs' +import { registry } from './setup-registry' const embeddingModel = registry.textEmbeddingModel(environment.MODEL_EMBEDDING) @@ -50,7 +50,7 @@ export const findRelevantContent = async ( const similarGuides = await database .select({ name: embeddings.content, similarity }) .from(embeddings) - // .where(gt(similarity, 0.1)) + .where(gt(similarity, 0.3)) .orderBy((t) => desc(t.similarity)) .limit(4) diff --git a/src/lib/ai/resources.ts b/src/lib/ai/resources.ts new file mode 100644 index 0000000..1c44499 --- /dev/null +++ b/src/lib/ai/resources.ts @@ -0,0 +1,39 @@ +import { db as database } from '../db' +import { embeddings as embeddingsTable } from '../db/schema/embeddings' +import { + insertResourceSchema, + type NewResourceParameters, + resources, +} from '../db/schema/resources' +import { generateEmbeddings } from './embeddings' + +export const createResource = async ( + input: NewResourceParameters, +): Promise => { + try { + const { content } = insertResourceSchema.parse(input) + + const [resource] = await database + .insert(resources) + .values({ content }) + .returning() + + if (!resource) { + return 'Resource not found' + } + + const embeddings = await generateEmbeddings(content) + await database.insert(embeddingsTable).values( + embeddings.map((embedding) => ({ + resourceId: resource.id, + ...embedding, + })), + ) + + return 'Resource successfully created and embedded.' + } catch (error) { + return error instanceof Error && error.message.length > 0 + ? error.message + : 'Error, please try again.' + } +} diff --git a/src/lib/ai/setup-registry.ts b/src/lib/ai/setup-registry.ts new file mode 100644 index 0000000..1c5c874 --- /dev/null +++ b/src/lib/ai/setup-registry.ts @@ -0,0 +1,27 @@ +import { openai as originalOpenAI } from '@ai-sdk/openai' +import { + experimental_createProviderRegistry as createProviderRegistry, + experimental_customProvider as customProvider, +} from 'ai' +import { ollama as originalOllama } from 'ollama-ai-provider' + +const ollama = customProvider({ + fallbackProvider: originalOllama, + languageModels: { + 'qwen-2_5': originalOllama('qwen2.5'), + }, +}) + +export const openai = customProvider({ + fallbackProvider: originalOpenAI, + languageModels: { + 'gpt-4o-mini': originalOpenAI('gpt-4o-mini', { + structuredOutputs: true, + }), + }, +}) + +export const registry = createProviderRegistry({ + ollama, + openai, +}) diff --git a/src/lib/commands/start.ts b/src/lib/commands/start.ts new file mode 100644 index 0000000..51c359b --- /dev/null +++ b/src/lib/commands/start.ts @@ -0,0 +1,6 @@ +import type { CommandContext, Context } from 'grammy' + +export async function start(context: CommandContext): Promise { + const content = 'Welcome, how can I help you?' + await context.reply(content) +} diff --git a/src/lib/handlers/on-message.ts b/src/lib/handlers/on-message.ts new file mode 100644 index 0000000..7a9d086 --- /dev/null +++ b/src/lib/handlers/on-message.ts @@ -0,0 +1,8 @@ +import { Composer } from 'grammy' + +export const onMessage = new Composer() + +onMessage.on('message:text', async (context) => { + const userMessage = context.message.text + await context.reply(userMessage) +}) diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 5e40b73..d426bf6 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,3 +1,7 @@ import { customAlphabet } from 'nanoid' export const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz0123456789') + +export function tomorrow(): Date { + return new Date(new Date().setDate(new Date().getDate() + 1)) +} diff --git a/src/main.ts b/src/main.ts index d7c0fa7..2c0114b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,24 +1,17 @@ import process from 'node:process' -import dotenv from 'dotenv' import { Bot } from 'grammy' -dotenv.config() +import { start } from './lib/commands/start' +import { environment } from './lib/environment.mjs' +import { onMessage } from './lib/handlers/on-message' async function main(): Promise { - const bot = new Bot(process.env.BOT_TOKEN ?? '') + const bot = new Bot(environment.BOT_TOKEN) - bot.command('start', async (context) => { - const content = 'Welcome, how can I help you?' + bot.command('start', start) - await context.reply(content) - }) - - bot.on('message:text', async (context) => { - const userMessage = context.message.text - - await context.reply(userMessage) - }) + bot.use(onMessage) // Enable graceful stop process.once('SIGINT', () => bot.stop())