From 5b8b6de3b5317dd70e5bf78cc755dd71c220a1f4 Mon Sep 17 00:00:00 2001 From: Tianyi Date: Sat, 1 Mar 2025 22:19:09 +0800 Subject: [PATCH] =?UTF-8?q?feat(model):=20=E5=A2=9E=E5=8A=A0=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E6=9C=8D=E5=8A=A1=E5=95=86=E9=80=89=E6=8B=A9=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在模型配置中添加服务商选择选项 - 实现服务商切换时自动选择该服务商下的第一个可用模型 - 优化模型选择界面,仅显示当前选中服务商的模型 - 添加摘要模型服务商选择功能 - 移除授权页面的 Saas 相关功能 - 调整聊天页面的模型选择逻辑 --- app/components/auth.tsx | 58 ++------------------- app/components/chat.tsx | 58 ++++++++++++++++----- app/components/model-config.tsx | 91 ++++++++++++++++++++++++++++----- app/locales/cn.ts | 12 ++--- app/locales/en.ts | 7 +-- 5 files changed, 135 insertions(+), 91 deletions(-) diff --git a/app/components/auth.tsx b/app/components/auth.tsx index 5375bda3f..433572f2b 100644 --- a/app/components/auth.tsx +++ b/app/components/auth.tsx @@ -2,22 +2,16 @@ import styles from "./auth.module.scss"; import { IconButton } from "./button"; import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; -import { Path, SAAS_CHAT_URL } from "../constant"; +import { Path } from "../constant"; import { useAccessStore } from "../store"; import Locale from "../locales"; -import Delete from "../icons/close.svg"; -import Arrow from "../icons/arrow.svg"; -import Logo from "../icons/logo.svg"; import { useMobileScreen } from "@/app/utils"; import BotIcon from "../icons/bot.svg"; import { getClientConfig } from "../config/client"; import { PasswordInput } from "./ui-lib"; import LeftIcon from "@/app/icons/left.svg"; import { safeLocalStorage } from "@/app/utils"; -import { - trackSettingsPageGuideToCPaymentClick, - trackAuthorizationPageButtonToCPaymentClick, -} from "../utils/auth-settings-events"; + import clsx from "clsx"; const storage = safeLocalStorage(); @@ -25,19 +19,8 @@ const storage = safeLocalStorage(); export function AuthPage() { const navigate = useNavigate(); const accessStore = useAccessStore(); - const goHome = () => navigate(Path.Home); const goChat = () => navigate(Path.Chat); - const goSaas = () => { - trackAuthorizationPageButtonToCPaymentClick(); - window.location.href = SAAS_CHAT_URL; - }; - - const resetAccessCode = () => { - accessStore.update((access) => { - access.openaiApiKey = ""; - access.accessCode = ""; - }); - }; // Reset access code to empty string + // Reset access code to empty string useEffect(() => { if (getClientConfig()?.isApp) { @@ -115,17 +98,10 @@ export function AuthPage() { type="primary" onClick={goChat} /> - { - goSaas(); - }} - /> ); } - function TopBanner() { const [isHovered, setIsHovered] = useState(false); const [isVisible, setIsVisible] = useState(true); @@ -159,31 +135,5 @@ function TopBanner() { if (!isVisible) { return null; } - return ( -
-
- - - {Locale.Auth.TopTips} - { - trackSettingsPageGuideToCPaymentClick(); - }} - > - {Locale.Settings.Access.SaasStart.ChatNow} - - - -
- {(isHovered || isMobile) && ( - - )} -
- ); + return null; } diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 6691403e6..b983799d1 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -67,14 +67,14 @@ import { copyToClipboard, getMessageImages, getMessageTextContent, + getModelSizes, isDalle3, isVisionModel, safeLocalStorage, - getModelSizes, - supportsCustomSize, - useMobileScreen, selectOrCopy, showPlugins, + supportsCustomSize, + useMobileScreen, } from "../utils"; import { uploadImage as uploadImageRemote } from "@/app/utils/chat"; @@ -535,11 +535,10 @@ export function ChatActions(props: { const defaultModel = filteredModels.find((m) => m.isDefault); if (defaultModel) { - const arr = [ + return [ defaultModel, ...filteredModels.filter((m) => m !== defaultModel), ]; - return arr; } else { return filteredModels; } @@ -553,6 +552,7 @@ export function ChatActions(props: { return model?.displayName ?? ""; }, [models, currentModel, currentProviderName]); const [showModelSelector, setShowModelSelector] = useState(false); + const [showProviderSelector, setShowProviderSelector] = useState(false); const [showPluginSelector, setShowPluginSelector] = useState(false); const [showUploadImage, setShowUploadImage] = useState(false); @@ -673,23 +673,55 @@ export function ChatActions(props: { }} /> + setShowProviderSelector(true)} + text={currentProviderName} + icon={} + /> + setShowModelSelector(true)} text={currentModelName} icon={} /> + {showProviderSelector && ( + ({ + title: name, + value: value, + }))} + onClose={() => setShowProviderSelector(false)} + onSelection={(s) => { + if (s.length === 0) return; + const provider = s[0] as ServiceProvider; + chatStore.updateTargetSession(session, (session) => { + session.mask.modelConfig.providerName = provider; + const filteredModels = models.filter( + (m) => m.available && m.provider?.providerName === provider, + ); + if (filteredModels.length > 0) { + // 选择新的服务商后,自动选择该服务商下的第一个模型 + session.mask.modelConfig.model = filteredModels[0] + .name as ModelType; + session.mask.syncGlobalConfig = false; + } + }); + showToast(s[0]); + }} + /> + )} + {showModelSelector && ( ({ - title: `${m.displayName}${ - m?.provider?.providerName - ? " (" + m?.provider?.providerName + ")" - : "" - }`, - value: `${m.name}@${m?.provider?.providerName}`, - }))} + items={models + .filter((m) => m.provider?.providerName === currentProviderName) + .map((m) => ({ + title: m.displayName, + value: `${m.name}@${m?.provider?.providerName}`, + }))} onClose={() => setShowModelSelector(false)} onSelection={(s) => { if (s.length === 0) return; diff --git a/app/components/model-config.tsx b/app/components/model-config.tsx index e845bfeac..8b089e4de 100644 --- a/app/components/model-config.tsx +++ b/app/components/model-config.tsx @@ -5,7 +5,6 @@ import Locale from "../locales"; import { InputRange } from "./input-range"; import { ListItem, Select } from "./ui-lib"; import { useAllModels } from "../utils/hooks"; -import { groupBy } from "lodash-es"; import styles from "./model-config.module.scss"; import { getModelProvider } from "../utils/model"; @@ -14,15 +13,43 @@ export function ModelConfigList(props: { updateConfig: (updater: (config: ModelConfig) => void) => void; }) { const allModels = useAllModels(); - const groupModels = groupBy( - allModels.filter((v) => v.available), - "provider.providerName", + const filteredModels = allModels.filter( + (v) => + v.available && + v.provider?.providerName === props.modelConfig.providerName, ); const value = `${props.modelConfig.model}@${props.modelConfig?.providerName}`; const compressModelValue = `${props.modelConfig.compressModel}@${props.modelConfig?.compressProviderName}`; return ( <> + + + + @@ -241,6 +264,37 @@ export function ModelConfigList(props: { } > + + + {allModels - .filter((v) => v.available) + .filter( + (v) => + v.available && + (!props.modelConfig.compressProviderName || + v.provider?.providerName === + props.modelConfig.compressProviderName), + ) .map((v, i) => ( ))} diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 077deaf64..afa7c316e 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -25,9 +25,6 @@ const cn = { Input: "在此处填写访问码", Confirm: "确认", Later: "稍后再说", - // SaasTips: "配置太麻烦,想要立即使用", - // TopTips: - // "🥳 NextChat AI 首发优惠,立刻解锁 OpenAI o1, GPT-4o, Claude-3.5 等最新大模型", }, ChatItem: { ChatItemCount: (count: number) => `${count} 条对话`, @@ -540,14 +537,15 @@ const cn = { }, }, - // 增加厂商选项 - ServiceProvider: "服务提供商", - Model: "模型 (model)", CompressModel: { Title: "对话摘要模型", SubTitle: "用于压缩历史记录、生成对话标题的模型", }, + CompressProvider: { + Title: "摘要模型服务商", + SubTitle: "选择生成摘要的模型服务商", + }, Temperature: { Title: "随机性 (temperature)", SubTitle: "值越大,回复越随机", @@ -629,7 +627,7 @@ const cn = { Prompt: { History: (content: string) => "这是历史聊天总结作为前情提要:" + content, Topic: - "使用四到五个字直接返回这句话的简要主题,不要解释、不要标点、不要语气词、不要多余文本,不要加粗,如果没有主题,请直接返回“闲聊”", + '使用四到五个字直接返回这句话的简要主题,不要解释、不要标点、不要语气词、不要多余文本,不要加粗,如果没有主题,请直接返回"闲聊"', Summarize: "简要总结一下对话内容,用作后续的上下文提示 prompt,控制在 200 字以内", }, diff --git a/app/locales/en.ts b/app/locales/en.ts index 8fecf8bf7..f15a533c9 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -26,9 +26,6 @@ const en: LocaleType = { Input: "access code", Confirm: "Confirm", Later: "Later", - SaasTips: "Too Complex, Use Immediately Now", - TopTips: - "🥳 NextChat AI launch promotion: Instantly unlock the latest models like OpenAI o1, GPT-4o, Claude-3.5!", }, ChatItem: { ChatItemCount: (count: number) => `${count} messages`, @@ -626,6 +623,10 @@ const en: LocaleType = { SubTitle: "Higher values result in more random responses", }, }, + CompressProvider: { + Title: "Summary Model Provider", + SubTitle: "Select a provider for the summary model", + }, }, Store: { DefaultTopic: "New Conversation",