Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions frontend/components/APIKeyForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ import { useAPIKeyStore } from '@/frontend/stores/APIKeyStore';
import { Badge } from './ui/badge';

const formSchema = z.object({
google: z.string().trim().min(1, {
message: 'Google API key is required for Title Generation',
}),
google: z.string().trim().optional(),
openrouter: z.string().trim().optional(),
openai: z.string().trim().optional(),
});
Expand Down Expand Up @@ -81,7 +79,6 @@ const Form = () => {
placeholder="AIza..."
register={register}
error={errors.google}
required
/>

<ApiKeyField
Expand Down
21 changes: 13 additions & 8 deletions frontend/components/ChatInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { v4 as uuidv4 } from 'uuid';
import { StopIcon } from './ui/icons';
import { toast } from 'sonner';
import { useMessageSummary } from '../hooks/useMessageSummary';
import { MODEL_PROVIDERS } from '@/lib/constants';

interface ChatInputProps {
threadId: string;
Expand Down Expand Up @@ -67,6 +68,7 @@ function PureChatInput({

const navigate = useNavigate();
const { id } = useParams();
const { selectedModel } = useModelStore();

const isDisabled = useMemo(
() => !input.trim() || status === 'streaming' || status === 'submitted',
Expand All @@ -87,14 +89,16 @@ function PureChatInput({

const messageId = uuidv4();

if (!id) {
navigate(`/chat/${threadId}`);
await createThread(threadId);
complete(currentInput.trim(), {
body: { threadId, messageId, isTitle: true },
});
} else {
complete(currentInput.trim(), { body: { messageId, threadId } });
if (getModelConfig(selectedModel).provider === MODEL_PROVIDERS.GOOGLE) {
if (!id) {
navigate(`/chat/${threadId}`);
await createThread(threadId);
complete(currentInput.trim(), {
body: { threadId, messageId, isTitle: true },
});
} else {
complete(currentInput.trim(), { body: { messageId, threadId } });
}
}

const userMessage = createUserMessage(messageId, currentInput.trim());
Expand All @@ -113,6 +117,7 @@ function PureChatInput({
textareaRef,
threadId,
complete,
selectedModel,
]);

if (!canChat) {
Expand Down
22 changes: 14 additions & 8 deletions frontend/components/MessageEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import { Textarea } from './ui/textarea';
import { Button } from './ui/button';
import { useAPIKeyStore } from '@/frontend/stores/APIKeyStore';
import { toast } from 'sonner';
import { useModelStore } from '../stores/ModelStore';
import { MODEL_PROVIDERS } from '@/lib/constants';
import { getModelConfig } from '@/lib/models';

export default function MessageEditor({
threadId,
Expand All @@ -32,11 +35,12 @@ export default function MessageEditor({
}) {
const [draftContent, setDraftContent] = useState(content);
const getKey = useAPIKeyStore((state) => state.getKey);
const { selectedModel } = useModelStore();

const { complete } = useCompletion({
api: '/api/completion',
...(getKey('google') && {
headers: { 'X-Google-API-Key': getKey('google')! },
...(getKey(MODEL_PROVIDERS.GOOGLE) && {
headers: { 'X-Google-API-Key': getKey(MODEL_PROVIDERS.GOOGLE)! },
}),
onResponse: async (response) => {
try {
Expand Down Expand Up @@ -85,12 +89,14 @@ export default function MessageEditor({
return messages;
});

complete(draftContent, {
body: {
messageId: updatedMessage.id,
threadId,
},
});
if (getModelConfig(selectedModel).provider === MODEL_PROVIDERS.GOOGLE) {
complete(draftContent, {
body: {
messageId: updatedMessage.id,
threadId,
},
});
}
setMode('view');

// stop the current stream if any
Expand Down
5 changes: 3 additions & 2 deletions frontend/hooks/useMessageSummary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useCompletion } from '@ai-sdk/react';
import { useAPIKeyStore } from '@/frontend/stores/APIKeyStore';
import { toast } from 'sonner';
import { createMessageSummary, updateThread } from '@/frontend/dexie/queries';
import { MODEL_PROVIDERS } from '@/lib/constants';

interface MessageSummaryPayload {
title: string;
Expand All @@ -15,8 +16,8 @@ export const useMessageSummary = () => {

const { complete, isLoading } = useCompletion({
api: '/api/completion',
...(getKey('google') && {
headers: { 'X-Google-API-Key': getKey('google')! },
...(getKey(MODEL_PROVIDERS.GOOGLE) && {
headers: { 'X-Google-API-Key': getKey(MODEL_PROVIDERS.GOOGLE)! },
}),
onResponse: async (response) => {
try {
Expand Down
19 changes: 19 additions & 0 deletions lib/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Provider } from '@/frontend/stores/APIKeyStore';

const GOOGLE = 'google';
const OPEN_ROUTER = 'openrouter';
const OPEN_AI = 'openai';

export const MODEL_PROVIDERS: {
[key: string]: Provider;
} = {
GOOGLE,
OPEN_ROUTER,
OPEN_AI,
} as const;

export const MODEL_HEADER_KEYS: Record<Provider, string> = {
[OPEN_ROUTER]: 'X-OpenRouter-API-Key',
[GOOGLE]: 'X-Google-API-Key',
[OPEN_AI]: 'X-OpenAI-API-Key',
} as const;
25 changes: 13 additions & 12 deletions lib/models.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Provider } from '@/frontend/stores/APIKeyStore';
import { MODEL_HEADER_KEYS, MODEL_PROVIDERS } from '@/lib/constants';

export const AI_MODELS = [
'Deepseek R1 0528',
Expand All @@ -20,33 +21,33 @@ export type ModelConfig = {
export const MODEL_CONFIGS = {
'Deepseek R1 0528': {
modelId: 'deepseek/deepseek-r1-0528:free',
provider: 'openrouter',
headerKey: 'X-OpenRouter-API-Key',
provider: MODEL_PROVIDERS.OPEN_ROUTER,
headerKey: MODEL_HEADER_KEYS[MODEL_PROVIDERS.OPEN_ROUTER],
},
'Deepseek V3': {
modelId: 'deepseek/deepseek-chat-v3-0324:free',
provider: 'openrouter',
headerKey: 'X-OpenRouter-API-Key',
provider: MODEL_PROVIDERS.OPEN_ROUTER,
headerKey: MODEL_HEADER_KEYS[MODEL_PROVIDERS.OPEN_ROUTER],
},
'Gemini 2.5 Pro': {
modelId: 'gemini-2.5-pro-preview-05-06',
provider: 'google',
headerKey: 'X-Google-API-Key',
provider: MODEL_PROVIDERS.GOOGLE,
headerKey: MODEL_HEADER_KEYS[MODEL_PROVIDERS.GOOGLE],
},
'Gemini 2.5 Flash': {
modelId: 'gemini-2.5-flash-preview-04-17',
provider: 'google',
headerKey: 'X-Google-API-Key',
provider: MODEL_PROVIDERS.GOOGLE,
headerKey: MODEL_HEADER_KEYS[MODEL_PROVIDERS.GOOGLE],
},
'GPT-4o': {
modelId: 'gpt-4o',
provider: 'openai',
headerKey: 'X-OpenAI-API-Key',
provider: MODEL_PROVIDERS.OPEN_AI,
headerKey: MODEL_HEADER_KEYS[MODEL_PROVIDERS.OPEN_AI],
},
'GPT-4.1-mini': {
modelId: 'gpt-4.1-mini',
provider: 'openai',
headerKey: 'X-OpenAI-API-Key',
provider: MODEL_PROVIDERS.OPEN_AI,
headerKey: MODEL_HEADER_KEYS[MODEL_PROVIDERS.OPEN_AI],
},
} as const satisfies Record<AIModel, ModelConfig>;

Expand Down