From 68e3c33a261d6436adaa525a5df5952ea01411c5 Mon Sep 17 00:00:00 2001 From: "Thomas G. Lopes" <26071571+TGlide@users.noreply.github.com> Date: Wed, 18 Jun 2025 12:47:20 +0100 Subject: [PATCH] add web search --- README.md | 2 +- src/lib/backend/convex/conversations.ts | 2 ++ src/lib/backend/convex/messages.ts | 2 ++ src/lib/backend/convex/schema.ts | 1 + src/lib/state/settings.svelte.ts | 1 + src/routes/api/generate-message/+server.ts | 11 ++++++++++- src/routes/chat/+layout.svelte | 13 +++++++++++++ src/routes/chat/[id]/+page.svelte | 6 ++++++ 8 files changed, 36 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8f77369..554858c 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ TODO: add instructions ### Extra -- [ ] Web Search +- [x] Web Search - [ ] Chat branching - [ ] Regenerate message - [ ] Image generation diff --git a/src/lib/backend/convex/conversations.ts b/src/lib/backend/convex/conversations.ts index aaf2b78..46353db 100644 --- a/src/lib/backend/convex/conversations.ts +++ b/src/lib/backend/convex/conversations.ts @@ -89,6 +89,7 @@ export const createAndAddMessage = mutation({ content: v.string(), role: messageRoleValidator, session_token: v.string(), + web_search_enabled: v.optional(v.boolean()), images: v.optional(v.array(v.object({ url: v.string(), storage_id: v.string(), @@ -123,6 +124,7 @@ export const createAndAddMessage = mutation({ role: args.role, conversation_id: conversationId, session_token: args.session_token, + web_search_enabled: args.web_search_enabled, images: args.images, }); diff --git a/src/lib/backend/convex/messages.ts b/src/lib/backend/convex/messages.ts index 3df1f1f..e01fd31 100644 --- a/src/lib/backend/convex/messages.ts +++ b/src/lib/backend/convex/messages.ts @@ -40,6 +40,7 @@ export const create = mutation({ model_id: v.optional(v.string()), provider: v.optional(providerValidator), token_count: v.optional(v.number()), + web_search_enabled: v.optional(v.boolean()), // Optional image attachments images: v.optional(v.array(v.object({ url: v.string(), @@ -78,6 +79,7 @@ export const create = mutation({ model_id: args.model_id, provider: args.provider, token_count: args.token_count, + web_search_enabled: args.web_search_enabled, // Optional image attachments images: args.images, }), diff --git a/src/lib/backend/convex/schema.ts b/src/lib/backend/convex/schema.ts index 3304de7..ba5b537 100644 --- a/src/lib/backend/convex/schema.ts +++ b/src/lib/backend/convex/schema.ts @@ -69,5 +69,6 @@ export default defineSchema({ ), cost_usd: v.optional(v.number()), generation_id: v.optional(v.string()), + web_search_enabled: v.optional(v.boolean()), }).index('by_conversation', ['conversation_id']), }); diff --git a/src/lib/state/settings.svelte.ts b/src/lib/state/settings.svelte.ts index 5daa98d..5e3d33e 100644 --- a/src/lib/state/settings.svelte.ts +++ b/src/lib/state/settings.svelte.ts @@ -2,4 +2,5 @@ import { createPersistedObj } from '$lib/spells/persisted-obj.svelte'; export const settings = createPersistedObj('settings', { modelId: undefined as string | undefined, + webSearchEnabled: false, }); diff --git a/src/routes/api/generate-message/+server.ts b/src/routes/api/generate-message/+server.ts index 9f629e6..e4347af 100644 --- a/src/routes/api/generate-message/+server.ts +++ b/src/routes/api/generate-message/+server.ts @@ -20,6 +20,7 @@ const reqBodySchema = z.object({ session_token: z.string(), conversation_id: z.string().optional(), + web_search_enabled: z.boolean().optional(), images: z .array( z.object({ @@ -291,10 +292,16 @@ ${attachedRules.map((r) => `- ${r.name}: ${r.rule}`).join('\n')}`, return; } + // Check if web search is enabled for the last user message + const lastUserMessage = messages.filter(m => m.role === 'user').pop(); + const webSearchEnabled = lastUserMessage?.web_search_enabled ?? false; + + const modelId = webSearchEnabled ? `${model.model_id}:online` : model.model_id; + const streamResult = await ResultAsync.fromPromise( openai.chat.completions.create( { - model: model.model_id, + model: modelId, messages: messagesToSend, temperature: 0.7, stream: true, @@ -523,6 +530,7 @@ export const POST: RequestHandler = async ({ request }) => { content: args.message, role: 'user', images: args.images, + web_search_enabled: args.web_search_enabled, session_token: sessionToken, }), (e) => `Failed to create conversation: ${e}` @@ -558,6 +566,7 @@ export const POST: RequestHandler = async ({ request }) => { model_id: args.model_id, role: 'user', images: args.images, + web_search_enabled: args.web_search_enabled, }), (e) => `Failed to create user message: ${e}` ); diff --git a/src/routes/chat/+layout.svelte b/src/routes/chat/+layout.svelte index 8cfb006..fef4409 100644 --- a/src/routes/chat/+layout.svelte +++ b/src/routes/chat/+layout.svelte @@ -38,6 +38,7 @@ import Settings2Icon from '~icons/lucide/settings-2'; import UploadIcon from '~icons/lucide/upload'; import XIcon from '~icons/lucide/x'; + import SearchIcon from '~icons/lucide/search'; import { callGenerateMessage } from '../api/generate-message/call.js'; import { callCancelGeneration } from '../api/cancel-generation/call.js'; import ModelPicker from './model-picker.svelte'; @@ -102,6 +103,7 @@ conversation_id: page.params.id ?? undefined, model_id: settings.modelId, images: imagesCopy.length > 0 ? imagesCopy : undefined, + web_search_enabled: settings.webSearchEnabled, }); if (res.isErr()) { @@ -788,6 +790,17 @@