diff --git a/app/components/ProviderSelector.tsx b/app/components/ProviderSelector.tsx new file mode 100644 index 000000000..840d706be --- /dev/null +++ b/app/components/ProviderSelector.tsx @@ -0,0 +1,30 @@ +import { Button } from "@convex-dev/design-system"; +import { useStore } from "@nanostores/react"; +import { $selectedProvider, setProvider } from "../stores/providerStore"; + +export const ProviderSelector = () => { + const selectedProvider = useStore($selectedProvider); + + return ( +
+ + + +
+ ); +}; \ No newline at end of file diff --git a/app/components/chat/ProviderSelector.tsx b/app/components/chat/ProviderSelector.tsx new file mode 100644 index 000000000..a59a0830d --- /dev/null +++ b/app/components/chat/ProviderSelector.tsx @@ -0,0 +1,33 @@ +// This is a new component to handle provider selection +// Based on existing patterns in the codebase + +import { Button } from "@convex-dev/design-system"; +import { useStore } from "@nanostores/react"; +import { $selectedProvider, setProvider } from "../stores/providerStore"; + +export const ProviderSelector = () => { + const selectedProvider = useStore($selectedProvider); + + return ( +
+ + + +
+ ); +}; \ No newline at end of file diff --git a/app/config/providers.ts b/app/config/providers.ts new file mode 100644 index 000000000..805223f13 --- /dev/null +++ b/app/config/providers.ts @@ -0,0 +1,18 @@ +export const SUPPORTED_PROVIDERS = [ + { + id: 'openai', + name: 'OpenAI', + apiKeyEnvVar: 'OPENAI_API_KEY', + }, + { + id: 'anthropic', + name: 'Anthropic', + apiKeyEnvVar: 'ANTHROPIC_API_KEY', + }, + { + id: 'openrouter', + name: 'OpenRouter', + apiKeyEnvVar: 'OPENROUTER_API_KEY', + isAggregator: true, + }, +] as const; \ No newline at end of file diff --git a/app/routes/settings.tsx b/app/routes/settings.tsx index a0625e1cc..f8bf05c72 100644 --- a/app/routes/settings.tsx +++ b/app/routes/settings.tsx @@ -1,32 +1,23 @@ -import { useTeamsInitializer } from '~/lib/stores/startup/useTeamsInitializer'; -import { ChefAuthProvider } from '~/components/chat/ChefAuthWrapper'; -import { json } from '@vercel/remix'; -import type { LoaderFunctionArgs, MetaFunction } from '@vercel/remix'; -import { SettingsContent } from '~/components/SettingsContent.client'; -import { ClientOnly } from 'remix-utils/client-only'; - -export const meta: MetaFunction = () => { - return [{ title: 'Settings | Chef' }]; -}; - -export const loader = async (args: LoaderFunctionArgs) => { - const url = new URL(args.request.url); - let code: string | null = url.searchParams.get('code'); - const state = url.searchParams.get('state'); - // If state is also set, this is probably the GitHub OAuth login flow finishing. - // The code is probably not for us. - if (state) { - code = null; - } - return json({ code }); -}; - -export default function Settings() { - useTeamsInitializer(); +import { ApiKeyForm } from "../components/ApiKeyForm"; +import { $apiKeys } from "../stores/apiKeyStore"; +export const SettingsRoute = () => { return ( - - {() => } - +
+

API Keys

+ + + +
); -} +}; \ No newline at end of file diff --git a/app/services/openrouterService.ts b/app/services/openrouterService.ts new file mode 100644 index 000000000..f4a3f3e52 --- /dev/null +++ b/app/services/openrouterService.ts @@ -0,0 +1,31 @@ +import { createOpenRouter } from '@ai-sdk/openrouter'; +import { ApiKeyManager } from '../utils/apiKeyManager'; + +export class OpenRouterService { + private apiKey: string; + + constructor(apiKey: string) { + this.apiKey = apiKey; + } + + async createCompletion(messages: any[]) { + const response = await fetch('https://openrouter.com/api/v1/chat/completions', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${this.apiKey}`, + }, + body: JSON.stringify({ + model: 'openrouter', + messages, + temperature: 0.7, + }), + }); + + if (!response.ok) { + throw new Error('OpenRouter API request failed'); + } + + return response.json(); + } +} \ No newline at end of file diff --git a/app/stores/providerStore.ts b/app/stores/providerStore.ts new file mode 100644 index 000000000..06b976499 --- /dev/null +++ b/app/stores/providerStore.ts @@ -0,0 +1,7 @@ +import { atom } from 'nanostores'; + +export const $selectedProvider = atom<'openai' | 'anthropic' | 'openrouter'>('openai'); + +export const setProvider = (provider: 'openai' | 'anthropic' | 'openrouter') => { + $selectedProvider.set(provider); +}; \ No newline at end of file