style(nextjs): changes settings llm selection layout
This commit is contained in:
parent
801f103c2a
commit
fad0e48437
1 changed files with 118 additions and 57 deletions
|
|
@ -1,8 +1,7 @@
|
|||
"use client";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Header from "../dashboard/components/Header";
|
||||
import Wrapper from "@/components/Wrapper";
|
||||
import { Settings, Key, Loader2 } from "lucide-react";
|
||||
import { Loader2, Download, CheckCircle } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { RootState } from "@/store/store";
|
||||
import { useSelector } from "react-redux";
|
||||
|
|
@ -45,6 +44,14 @@ const SettingsPage = () => {
|
|||
status: string;
|
||||
done: boolean;
|
||||
} | null>(null);
|
||||
const [showDownloadModal, setShowDownloadModal] = useState<boolean>(false);
|
||||
|
||||
const downloadProgress = React.useMemo(() => {
|
||||
if (downloadingModel && downloadingModel.downloaded !== null && downloadingModel.size !== null) {
|
||||
return Math.round((downloadingModel.downloaded / downloadingModel.size) * 100);
|
||||
}
|
||||
return 0;
|
||||
}, [downloadingModel?.downloaded, downloadingModel?.size]);
|
||||
|
||||
const handleSaveConfig = async () => {
|
||||
try {
|
||||
|
|
@ -55,17 +62,18 @@ const SettingsPage = () => {
|
|||
isDisabled: true,
|
||||
text: "Saving Configuration..."
|
||||
}));
|
||||
|
||||
|
||||
await handleSaveLLMConfig(llmConfig);
|
||||
|
||||
|
||||
if (llmConfig.LLM === "ollama" && llmConfig.OLLAMA_MODEL) {
|
||||
const isPulled = await checkIfSelectedOllamaModelIsPulled(llmConfig.OLLAMA_MODEL);
|
||||
if (!isPulled) {
|
||||
setShowDownloadModal(true);
|
||||
await handleModelDownload();
|
||||
}
|
||||
}
|
||||
|
||||
toast.success("Configuration saved successfully");
|
||||
|
||||
toast.info("Configuration saved successfully");
|
||||
setIsLoading(false);
|
||||
setButtonState(prev => ({
|
||||
...prev,
|
||||
|
|
@ -76,7 +84,7 @@ const SettingsPage = () => {
|
|||
router.back();
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
toast.error(
|
||||
toast.info(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Failed to save configuration"
|
||||
|
|
@ -97,6 +105,7 @@ const SettingsPage = () => {
|
|||
} catch (error) {
|
||||
console.error("Error downloading model:", error);
|
||||
setDownloadingModel(null);
|
||||
setShowDownloadModal(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -115,8 +124,9 @@ const SettingsPage = () => {
|
|||
|
||||
if (downloadingModel && downloadingModel.done) {
|
||||
setTimeout(() => {
|
||||
setShowDownloadModal(false);
|
||||
setDownloadingModel(null);
|
||||
toast.success("Model downloaded successfully!");
|
||||
toast.info("Model downloaded successfully!");
|
||||
}, 2000);
|
||||
}
|
||||
}, [downloadingModel]);
|
||||
|
|
@ -132,64 +142,115 @@ const SettingsPage = () => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[#E9E8F8] font-instrument_sans">
|
||||
<div className="h-screen bg-gradient-to-b font-instrument_sans from-gray-50 to-white flex flex-col overflow-hidden">
|
||||
<Header />
|
||||
<Wrapper className="lg:w-[80%]">
|
||||
<div className="py-8 space-y-6">
|
||||
{/* Settings Header */}
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<Settings className="w-8 h-8 text-blue-600" />
|
||||
<h1 className="text-2xl font-semibold text-gray-900">Settings</h1>
|
||||
</div>
|
||||
<main className="flex-1 container mx-auto px-4 max-w-3xl overflow-hidden flex flex-col">
|
||||
{/* LLM Selection Component */}
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<LLMProviderSelection
|
||||
initialLLMConfig={llmConfig}
|
||||
onConfigChange={setLlmConfig}
|
||||
buttonState={buttonState}
|
||||
setButtonState={setButtonState}
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* API Configuration Section */}
|
||||
<div className="bg-white rounded-xl shadow-sm p-6">
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<Key className="w-5 h-5 text-blue-600" />
|
||||
<h2 className="text-lg font-medium text-gray-900">
|
||||
API Configuration
|
||||
</h2>
|
||||
</div>
|
||||
{/* Fixed Bottom Button */}
|
||||
<div className="flex-shrink-0 bg-white border-t border-gray-200 p-4">
|
||||
<div className="container mx-auto max-w-3xl">
|
||||
<button
|
||||
onClick={handleSaveConfig}
|
||||
disabled={buttonState.isDisabled}
|
||||
className={`w-full font-semibold py-3 px-4 rounded-lg transition-all duration-500 ${buttonState.isDisabled
|
||||
? "bg-gray-400 cursor-not-allowed"
|
||||
: "bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 focus:ring-4 focus:ring-blue-200"
|
||||
} text-white`}
|
||||
>
|
||||
{buttonState.isLoading ? (
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<Loader2 className="w-4 h-4 animate-spin" />
|
||||
{buttonState.text}
|
||||
</div>
|
||||
) : (
|
||||
buttonState.text
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* LLM Selection Component */}
|
||||
<div className="h-[600px]">
|
||||
<LLMProviderSelection
|
||||
initialLLMConfig={llmConfig}
|
||||
onConfigChange={setLlmConfig}
|
||||
buttonState={buttonState}
|
||||
setButtonState={setButtonState}
|
||||
/>
|
||||
</div>
|
||||
{/* Download Progress Modal */}
|
||||
{showDownloadModal && downloadingModel && (
|
||||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4">
|
||||
<div className="bg-white/95 backdrop-blur-md rounded-xl shadow-2xl max-w-md w-full p-6 relative">
|
||||
{/* Modal Content */}
|
||||
<div className="text-center">
|
||||
{/* Icon */}
|
||||
<div className="mb-4">
|
||||
{downloadingModel.done ? (
|
||||
<CheckCircle className="w-12 h-12 text-green-600 mx-auto" />
|
||||
) : (
|
||||
<Download className="w-12 h-12 text-blue-600 mx-auto animate-pulse" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Save Button */}
|
||||
<button
|
||||
onClick={handleSaveConfig}
|
||||
disabled={buttonState.isDisabled}
|
||||
className={`mt-8 w-full font-semibold py-3 px-4 rounded-lg transition-all duration-500 ${buttonState.isDisabled
|
||||
? "bg-gray-400 cursor-not-allowed"
|
||||
: "bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-700 hover:to-indigo-700 focus:ring-4 focus:ring-blue-200"
|
||||
} text-white`}
|
||||
>
|
||||
{buttonState.isLoading ? (
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<Loader2 className="w-4 h-4 animate-spin" />
|
||||
{buttonState.text}
|
||||
</div>
|
||||
) : (
|
||||
buttonState.text
|
||||
)}
|
||||
</button>
|
||||
{/* Title */}
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">
|
||||
{downloadingModel.done ? "Download Complete!" : "Downloading Model"}
|
||||
</h3>
|
||||
|
||||
{llmConfig.LLM === "ollama" &&
|
||||
downloadingModel?.status &&
|
||||
downloadingModel.status !== "pulled" && (
|
||||
<div className="mt-3 text-sm bg-green-100 rounded-lg p-2 font-semibold capitalize text-center text-gray-600">
|
||||
{downloadingModel.status}
|
||||
{/* Model Name */}
|
||||
<p className="text-sm text-gray-600 mb-6">
|
||||
{llmConfig.OLLAMA_MODEL}
|
||||
</p>
|
||||
|
||||
{/* Progress Bar */}
|
||||
{downloadProgress > 0 && (
|
||||
<div className="mb-4">
|
||||
<div className="w-full bg-gray-200 rounded-full h-3 overflow-hidden">
|
||||
<div
|
||||
className="bg-blue-600 h-3 rounded-full transition-all duration-300 ease-out"
|
||||
style={{ width: `${downloadProgress}%` }}
|
||||
/>
|
||||
</div>
|
||||
<p className="text-sm text-gray-600 mt-2">
|
||||
{downloadProgress}% Complete
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Status */}
|
||||
{downloadingModel.status && (
|
||||
<div className="flex items-center justify-center gap-2 mb-4">
|
||||
<CheckCircle className="w-4 h-4 text-green-600" />
|
||||
<span className="text-sm font-medium text-green-700 capitalize">
|
||||
{downloadingModel.status}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Status Message */}
|
||||
{downloadingModel.status && downloadingModel.status !== "pulled" && (
|
||||
<div className="text-xs text-gray-500">
|
||||
{downloadingModel.status === "downloading" && "Downloading model files..."}
|
||||
{downloadingModel.status === "verifying" && "Verifying model integrity..."}
|
||||
{downloadingModel.status === "pulling" && "Pulling model from registry..."}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Download Info */}
|
||||
{downloadingModel.downloaded && downloadingModel.size && (
|
||||
<div className="mt-4 p-3 bg-gray-50 rounded-lg">
|
||||
<div className="flex justify-between text-xs text-gray-600">
|
||||
<span>Downloaded: {(downloadingModel.downloaded / 1024 / 1024).toFixed(1)} MB</span>
|
||||
<span>Total: {(downloadingModel.size / 1024 / 1024).toFixed(1)} MB</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Wrapper>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue