mirror of https://github.com/usememos/memos.git
feat: implement AI connection test in frontend
- Add test connection button with loading states in AI settings - Integrate connection test API with proper error handling - Update tag recommendation settings with improved UI Signed-off-by: ChaoLiu <chaoliu719@gmail.com>
This commit is contained in:
parent
69f946844b
commit
30202db710
|
|
@ -9,6 +9,7 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
|
import { workspaceServiceClient } from "@/grpcweb";
|
||||||
import { workspaceStore } from "@/store";
|
import { workspaceStore } from "@/store";
|
||||||
import { workspaceSettingNamePrefix } from "@/store/common";
|
import { workspaceSettingNamePrefix } from "@/store/common";
|
||||||
import { WorkspaceSetting_AiSetting, WorkspaceSetting_Key } from "@/types/proto/api/v1/workspace_service";
|
import { WorkspaceSetting_AiSetting, WorkspaceSetting_Key } from "@/types/proto/api/v1/workspace_service";
|
||||||
|
|
@ -20,6 +21,7 @@ const AISettings = observer(() => {
|
||||||
const [originalSetting, setOriginalSetting] = useState<WorkspaceSetting_AiSetting>(workspaceStore.state.aiSetting);
|
const [originalSetting, setOriginalSetting] = useState<WorkspaceSetting_AiSetting>(workspaceStore.state.aiSetting);
|
||||||
const [aiSetting, setAiSetting] = useState<WorkspaceSetting_AiSetting>(originalSetting);
|
const [aiSetting, setAiSetting] = useState<WorkspaceSetting_AiSetting>(originalSetting);
|
||||||
const [showApiKey, setShowApiKey] = useState(false);
|
const [showApiKey, setShowApiKey] = useState(false);
|
||||||
|
const [isTestingConnection, setIsTestingConnection] = useState(false);
|
||||||
|
|
||||||
const updatePartialSetting = (partial: Partial<WorkspaceSetting_AiSetting>) => {
|
const updatePartialSetting = (partial: Partial<WorkspaceSetting_AiSetting>) => {
|
||||||
setAiSetting(WorkspaceSetting_AiSetting.fromPartial({ ...aiSetting, ...partial }));
|
setAiSetting(WorkspaceSetting_AiSetting.fromPartial({ ...aiSetting, ...partial }));
|
||||||
|
|
@ -62,6 +64,34 @@ const AISettings = observer(() => {
|
||||||
|
|
||||||
const resetSetting = () => setAiSetting(originalSetting);
|
const resetSetting = () => setAiSetting(originalSetting);
|
||||||
|
|
||||||
|
const testConnection = async () => {
|
||||||
|
if (!aiSetting.baseUrl || !aiSetting.apiKey || !aiSetting.model) {
|
||||||
|
toast.error(t("setting.ai-section.test-connection-incomplete"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsTestingConnection(true);
|
||||||
|
try {
|
||||||
|
const response = await workspaceServiceClient.testAiConnection({
|
||||||
|
baseUrl: aiSetting.baseUrl || "https://api.openai.com/v1",
|
||||||
|
apiKey: aiSetting.apiKey,
|
||||||
|
model: aiSetting.model,
|
||||||
|
timeoutSeconds: aiSetting.timeoutSeconds || 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
toast.success(t("setting.ai-section.test-connection-success"));
|
||||||
|
} else {
|
||||||
|
toast.error(`${t("setting.ai-section.test-connection-failed")}: ${response.message}`);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error("AI connection test failed:", error);
|
||||||
|
toast.error(`${t("setting.ai-section.test-connection-failed")}: ${error.message || error}`);
|
||||||
|
} finally {
|
||||||
|
setIsTestingConnection(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 只比较全局AI配置的变化,不包括子功能配置
|
// 只比较全局AI配置的变化,不包括子功能配置
|
||||||
const globalSettingChanged = !isEqual(
|
const globalSettingChanged = !isEqual(
|
||||||
{
|
{
|
||||||
|
|
@ -188,13 +218,22 @@ const AISettings = observer(() => {
|
||||||
|
|
||||||
{/* Action Buttons */}
|
{/* Action Buttons */}
|
||||||
{aiSetting.enableAi && (
|
{aiSetting.enableAi && (
|
||||||
<div className="w-full flex flex-row justify-end items-center gap-2 mt-4">
|
<div className="w-full flex flex-row justify-between items-center gap-2 mt-4">
|
||||||
<Button variant="outline" onClick={resetSetting} disabled={!globalSettingChanged}>
|
<Button
|
||||||
{t("common.cancel")}
|
variant="outline"
|
||||||
</Button>
|
onClick={testConnection}
|
||||||
<Button onClick={updateSetting} disabled={!globalSettingChanged}>
|
disabled={isTestingConnection || !aiSetting.baseUrl || !aiSetting.apiKey || !aiSetting.model}
|
||||||
{t("common.save")}
|
>
|
||||||
|
{isTestingConnection ? t("setting.ai-section.testing-connection") : t("setting.ai-section.test-connection")}
|
||||||
</Button>
|
</Button>
|
||||||
|
<div className="flex flex-row items-center gap-2">
|
||||||
|
<Button variant="outline" onClick={resetSetting} disabled={!globalSettingChanged}>
|
||||||
|
{t("common.cancel")}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={updateSetting} disabled={!globalSettingChanged}>
|
||||||
|
{t("common.save")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ const TagRecommendationSection = observer(({ aiSetting, onSettingChange, disable
|
||||||
systemPrompt: "",
|
systemPrompt: "",
|
||||||
requestsPerMinute: 10,
|
requestsPerMinute: 10,
|
||||||
});
|
});
|
||||||
|
|
||||||
setOriginalTagConfig(newTagConfig);
|
setOriginalTagConfig(newTagConfig);
|
||||||
setTagConfig(newTagConfig);
|
setTagConfig(newTagConfig);
|
||||||
}, [aiSetting]);
|
}, [aiSetting]);
|
||||||
|
|
@ -80,7 +80,7 @@ const TagRecommendationSection = observer(({ aiSetting, onSettingChange, disable
|
||||||
name: `${workspaceSettingNamePrefix}${WorkspaceSetting_Key.AI}`,
|
name: `${workspaceSettingNamePrefix}${WorkspaceSetting_Key.AI}`,
|
||||||
aiSetting: newAiSetting,
|
aiSetting: newAiSetting,
|
||||||
});
|
});
|
||||||
|
|
||||||
setOriginalTagConfig(newTagConfig);
|
setOriginalTagConfig(newTagConfig);
|
||||||
setTagConfig(newTagConfig);
|
setTagConfig(newTagConfig);
|
||||||
onSettingChange(newAiSetting);
|
onSettingChange(newAiSetting);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue