From 342a5af8ffe0ba900fcf58cce49f700b43bf6bfc Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Mon, 11 Aug 2025 19:06:13 +0000 Subject: [PATCH] feat: Make DeepSeek the default model for paying users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Free users: Continue using "llama3-3-70b" as default model - Paid users: Now use "deepseek-r1-0528" (DeepSeek R1 0528 671B) as default - Added getDefaultModelId() function to determine appropriate default based on billing status - Model automatically updates when billing status changes (e.g., user upgrades) - Preserves user choice: only updates if user is still using default models - Updated related imports to use new constant names Fixes #188 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Marks --- frontend/src/hooks/useChatSession.ts | 4 +- frontend/src/routes/_auth.chat.$chatId.tsx | 4 +- frontend/src/state/LocalStateContext.tsx | 59 +++++++++++++++++++--- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/frontend/src/hooks/useChatSession.ts b/frontend/src/hooks/useChatSession.ts index 234183ce6..45bde9d34 100644 --- a/frontend/src/hooks/useChatSession.ts +++ b/frontend/src/hooks/useChatSession.ts @@ -1,6 +1,6 @@ import { useState, useCallback, useEffect, useMemo, useRef } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; -import { Chat, ChatMessage, DEFAULT_MODEL_ID } from "@/state/LocalStateContext"; +import { Chat, ChatMessage, FREE_USER_DEFAULT_MODEL_ID } from "@/state/LocalStateContext"; import { ChatContentPart } from "@/state/LocalStateContextDef"; import { fileToDataURL } from "@/utils/file"; import { BillingStatus } from "@/billing/billingApi"; @@ -380,7 +380,7 @@ async function generateTitle( // Use the OpenAI API to generate a concise title - use the default model const stream = openai.beta.chat.completions.stream({ - model: DEFAULT_MODEL_ID, // Use the default model instead of user selected model + model: FREE_USER_DEFAULT_MODEL_ID, // Use the free user default model for title generation messages: [ { role: "system", diff --git a/frontend/src/routes/_auth.chat.$chatId.tsx b/frontend/src/routes/_auth.chat.$chatId.tsx index 3ca03827e..0b4d52a38 100644 --- a/frontend/src/routes/_auth.chat.$chatId.tsx +++ b/frontend/src/routes/_auth.chat.$chatId.tsx @@ -5,7 +5,7 @@ import ChatBox from "@/components/ChatBox"; import { useOpenAI } from "@/ai/useOpenAi"; import { useLocalState } from "@/state/useLocalState"; import { Markdown, stripThinkingTags } from "@/components/markdown"; -import { ChatMessage, DEFAULT_MODEL_ID } from "@/state/LocalStateContext"; +import { ChatMessage, FREE_USER_DEFAULT_MODEL_ID } from "@/state/LocalStateContext"; import { Sidebar, SidebarToggle } from "@/components/Sidebar"; import { useQueryClient } from "@tanstack/react-query"; import { Button } from "@/components/ui/button"; @@ -422,7 +422,7 @@ END OF INSTRUCTIONS`; // 2. Stream the summary let summary = ""; const stream = openai.beta.chat.completions.stream({ - model: DEFAULT_MODEL_ID, // Use the default model instead of user selected model + model: FREE_USER_DEFAULT_MODEL_ID, // Use the free user default model for summarization messages: summarizationMessages, temperature: 0.3, max_tokens: 600, diff --git a/frontend/src/state/LocalStateContext.tsx b/frontend/src/state/LocalStateContext.tsx index bd6d7751e..3418e6b46 100644 --- a/frontend/src/state/LocalStateContext.tsx +++ b/frontend/src/state/LocalStateContext.tsx @@ -1,5 +1,5 @@ import { useOpenSecret } from "@opensecret/react"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import { BillingStatus } from "@/billing/billingApi"; import { LocalStateContext, Chat, HistoryItem, OpenSecretModel } from "./LocalStateContextDef"; import { aliasModelName } from "@/utils/utils"; @@ -12,36 +12,81 @@ export { type LocalState } from "./LocalStateContextDef"; -export const DEFAULT_MODEL_ID = "llama3-3-70b"; +export const FREE_USER_DEFAULT_MODEL_ID = "llama3-3-70b"; +export const PAID_USER_DEFAULT_MODEL_ID = "deepseek-r1-0528"; + +// Get default model based on user's billing status +export function getDefaultModelId(billingStatus: BillingStatus | null): string { + // If no billing status, assume free user + if (!billingStatus) { + return FREE_USER_DEFAULT_MODEL_ID; + } + + // Check if user has any paid plan (starter, pro, max, or team) + const planName = billingStatus.product_name?.toLowerCase() || ""; + const isPaidUser = + billingStatus.is_subscribed && + (planName.includes("starter") || + planName.includes("pro") || + planName.includes("max") || + planName.includes("team")); + + return isPaidUser ? PAID_USER_DEFAULT_MODEL_ID : FREE_USER_DEFAULT_MODEL_ID; +} export const LocalStateProvider = ({ children }: { children: React.ReactNode }) => { /** The model that should be assumed when a chat doesn't yet have one */ const llamaModel: OpenSecretModel = { - id: DEFAULT_MODEL_ID, + id: FREE_USER_DEFAULT_MODEL_ID, object: "model", created: Date.now(), owned_by: "meta", tasks: ["generate"] }; + const deepSeekModel: OpenSecretModel = { + id: PAID_USER_DEFAULT_MODEL_ID, + object: "model", + created: Date.now(), + owned_by: "deepseek", + tasks: ["generate"] + }; + const [localState, setLocalState] = useState({ userPrompt: "", systemPrompt: null as string | null, userImages: [] as File[], - model: aliasModelName(import.meta.env.VITE_DEV_MODEL_OVERRIDE) || DEFAULT_MODEL_ID, - availableModels: [llamaModel] as OpenSecretModel[], + model: aliasModelName(import.meta.env.VITE_DEV_MODEL_OVERRIDE) || FREE_USER_DEFAULT_MODEL_ID, + availableModels: [llamaModel, deepSeekModel] as OpenSecretModel[], billingStatus: null as BillingStatus | null, searchQuery: "", isSearchVisible: false, draftMessages: new Map() }); + // Update default model when billing status changes (only if model hasn't been explicitly set by user) + useEffect(() => { + // Only update if we're still using the default model and not overridden by dev env + if (!import.meta.env.VITE_DEV_MODEL_OVERRIDE) { + const currentModel = localState.model; + const isCurrentlyDefault = + currentModel === FREE_USER_DEFAULT_MODEL_ID || currentModel === PAID_USER_DEFAULT_MODEL_ID; + + if (isCurrentlyDefault) { + const newDefaultModel = getDefaultModelId(localState.billingStatus); + if (currentModel !== newDefaultModel) { + setLocalState((prev) => ({ ...prev, model: newDefaultModel })); + } + } + } + }, [localState.billingStatus, localState.model]); + const { get, put, list, del } = useOpenSecret(); async function persistChat(chat: Chat) { const chatToSave = { - /** If a model is missing, assume the default Llama and write it now */ - model: aliasModelName(chat.model) || DEFAULT_MODEL_ID, + /** If a model is missing, assume the appropriate default model based on billing status */ + model: aliasModelName(chat.model) || getDefaultModelId(localState.billingStatus), ...chat };