From 9f48a8f6bd61aa1958373f3a81aef158a8a1c3df Mon Sep 17 00:00:00 2001 From: an-lee Date: Tue, 21 May 2024 15:48:20 +0800 Subject: [PATCH] validate conversaton configuation & handle preset loading in poor network (#624) --- enjoy/src/i18n/en.json | 6 +++- enjoy/src/i18n/zh-CN.json | 6 +++- enjoy/src/main/db/models/conversation.ts | 18 +++++++++++ .../conversations/conversation-form.tsx | 13 ++------ enjoy/src/renderer/pages/conversations.tsx | 32 ++++++++++++++----- 5 files changed, 54 insertions(+), 21 deletions(-) diff --git a/enjoy/src/i18n/en.json b/enjoy/src/i18n/en.json index c739f617..b45e6b4d 100644 --- a/enjoy/src/i18n/en.json +++ b/enjoy/src/i18n/en.json @@ -91,7 +91,11 @@ "ttsBaseUrlDescription": "leave it blank if you don't have one", "notFound": "Conversation not found", "contentRequired": "Content required", - "failedToGenerateResponse": "Failed to generate response, please retry" + "failedToGenerateResponse": "Failed to generate response, please retry", + "modelIsRequired": "Model is required", + "ttsConfigurationsIsRequired": "TTS configurations is required", + "ttsModelIsRequired": "TTS model is required", + "ttsEngineIsRequired": "TTS engine is required" }, "pronunciationAssessment": { "pronunciationScore": "Pronunciation Score", diff --git a/enjoy/src/i18n/zh-CN.json b/enjoy/src/i18n/zh-CN.json index e9aee25c..f012144f 100644 --- a/enjoy/src/i18n/zh-CN.json +++ b/enjoy/src/i18n/zh-CN.json @@ -91,7 +91,11 @@ "ttsBaseUrlDescription": "留空则使用默认值", "notFound": "未找到对话", "contentRequired": "对话内容不能为空", - "failedToGenerateResponse": "生成失败,请重试" + "failedToGenerateResponse": "生成失败,请重试", + "modelIsRequired": "AI 模型不能为空", + "ttsConfigurationsIsRequired": "TTS 配置不能为空", + "ttsModelIsRequired": "TTS 模型不能为空", + "ttsEngineIsRequired": "TTS 引擎不能为空" }, "pronunciationAssessment": { "pronunciationScore": "发音得分", diff --git a/enjoy/src/main/db/models/conversation.ts b/enjoy/src/main/db/models/conversation.ts index 6c0456ef..8574653e 100644 --- a/enjoy/src/main/db/models/conversation.ts +++ b/enjoy/src/main/db/models/conversation.ts @@ -10,10 +10,12 @@ import { HasMany, DataType, AllowNull, + BeforeSave, } from "sequelize-typescript"; import { Message, Speech } from "@main/db/models"; import mainWindow from "@main/window"; import log from "@main/logger"; +import { t } from "i18next"; const logger = log.scope("db/models/conversation"); @Table({ @@ -64,6 +66,22 @@ export class Conversation extends Model { @HasMany(() => Message) messages: Message[]; + @BeforeSave + static validateConfiguration(conversation: Conversation) { + if (!conversation.model) throw new Error(t("models.conversation.modelIsRequired")); + if (conversation.type === 'tts') { + if (!conversation.configuration.tts) { + throw new Error(t("models.conversation.ttsConfigurationIsRequired")) + } + if (!conversation.configuration.tts.engine) { + throw new Error(t("models.conversation.ttsEngineIsRequired")) + } + if (!conversation.configuration.tts.model) { + throw new Error("models.conversation.ttsModelIsRequired") + } + } + } + @AfterCreate static notifyForCreate(conversation: Conversation) { this.notify(conversation, "create"); diff --git a/enjoy/src/renderer/components/conversations/conversation-form.tsx b/enjoy/src/renderer/components/conversations/conversation-form.tsx index 5af528ae..733d9309 100644 --- a/enjoy/src/renderer/components/conversations/conversation-form.tsx +++ b/enjoy/src/renderer/components/conversations/conversation-form.tsx @@ -74,8 +74,8 @@ export const ConversationForm = (props: { }) => { const { conversation, onFinish } = props; const [submitting, setSubmitting] = useState(false); - const [gptProviders, setGptProviders] = useState([]); - const [ttsProviders, setTtsProviders] = useState([]); + const [gptProviders, setGptProviders] = useState(GPT_PROVIDERS); + const [ttsProviders, setTtsProviders] = useState(TTS_PROVIDERS); const { EnjoyApp, webApi } = useContext(AppSettingsProviderContext); const { openai } = useContext(AISettingsProviderContext); const navigate = useNavigate(); @@ -234,15 +234,6 @@ export const ConversationForm = (props: { } }); - if (configuration.type === "tts") { - if (!configuration.tts?.engine) { - throw new Error(t("models.conversation.ttsEngineRequired")); - } - if (!configuration.tts?.model) { - throw new Error(t("models.conversation.ttsModelRequired")); - } - } - // use default base url if not set if (!configuration.baseUrl) { configuration.baseUrl = gptProviders[engine]?.baseUrl; diff --git a/enjoy/src/renderer/pages/conversations.tsx b/enjoy/src/renderer/pages/conversations.tsx index e2b26476..d7cf5039 100644 --- a/enjoy/src/renderer/pages/conversations.tsx +++ b/enjoy/src/renderer/pages/conversations.tsx @@ -11,7 +11,11 @@ import { ScrollArea, toast, } from "@renderer/components/ui"; -import { ConversationCard, ConversationForm } from "@renderer/components"; +import { + ConversationCard, + ConversationForm, + LoaderSpin, +} from "@renderer/components"; import { useState, useEffect, useContext, useReducer } from "react"; import { ChevronLeftIcon, LoaderIcon } from "lucide-react"; import { Link, useNavigate, useSearchParams } from "react-router-dom"; @@ -25,13 +29,6 @@ import { CONVERSATION_PRESETS } from "@/constants"; export default () => { const [searchParams] = useSearchParams(); - const [creating, setCreating] = useState(false); - const [preset, setPreset] = useState({}); - const [config, setConfig] = useState({ - gptPresets: [], - customPreset: {}, - ttsPreset: {}, - }); const { addDblistener, removeDbListener } = useContext(DbProviderContext); const { EnjoyApp, webApi } = useContext(AppSettingsProviderContext); const { currentEngine } = useContext(AISettingsProviderContext); @@ -39,6 +36,23 @@ export default () => { conversationsReducer, [] ); + const [creating, setCreating] = useState(false); + const [preset, setPreset] = useState({}); + const [config, setConfig] = useState({ + gptPresets: [], + customPreset: {}, + ttsPreset: { + key: "tts", + name: "TTS", + engine: currentEngine.name, + configuration: { + type: "tts", + tts: { + engine: currentEngine.name, + }, + }, + }, + }); const [hasMore, setHasMore] = useState(false); const [loading, setLoading] = useState(false); const navigate = useNavigate(); @@ -218,6 +232,8 @@ export default () => { {t("chooseFromPresetGpts")} + {config.gptPresets.length === 0 && } + {config.gptPresets.map((preset: any) => (