diff --git a/pages/admin/index.tsx b/pages/admin/index.tsx index e6dd75d..1eecc2a 100644 --- a/pages/admin/index.tsx +++ b/pages/admin/index.tsx @@ -3,21 +3,26 @@ import { NextPage } from "next"; import NextLink from "next/link"; import { Box, VStack, HStack, Heading, Text, Input, Button, Switch, - FormControl, FormLabel, FormHelperText, Divider, Alert, AlertIcon, + FormControl, FormLabel, FormHelperText, Alert, AlertIcon, InputGroup, InputRightElement, IconButton, Badge, Link, - useColorModeValue, Spinner, Textarea + useColorModeValue, Spinner, Textarea, RadioGroup, Radio, Code } from "@chakra-ui/react"; import { FiEye, FiEyeOff, FiSave, FiLogOut, FiArrowLeft } from "react-icons/fi"; import { CustomHead } from "@components"; +type ReplicateMode = "cloud" | "local"; + type Settings = { replicateApiToken: string; jigsawApiKey: string; modelVersion: string; replicateEnabled: boolean; + replicateMode: ReplicateMode; + localEndpoint: string; }; const DEFAULT_MODEL = "jigsawstack/text-translate:454df4c49941c05dea05175bd37686d0872c73c1f9366d1c2505db32ade52a89"; +const DEFAULT_LOCAL_ENDPOINT = "http://localhost:5030/predictions"; const AdminPage: NextPage = () => { const [authed, setAuthed] = useState(null); @@ -29,7 +34,9 @@ const AdminPage: NextPage = () => { replicateApiToken: "", jigsawApiKey: "", modelVersion: DEFAULT_MODEL, - replicateEnabled: false + replicateEnabled: false, + replicateMode: "cloud", + localEndpoint: DEFAULT_LOCAL_ENDPOINT }); const [newPassword, setNewPassword] = useState(""); const [saveMsg, setSaveMsg] = useState<{ type: "success" | "error"; text: string } | null>(null); @@ -41,8 +48,8 @@ const AdminPage: NextPage = () => { const cardBg = useColorModeValue("white", "gray.800"); const borderCol = useColorModeValue("gray.200", "gray.600"); + const codeBg = useColorModeValue("gray.100", "gray.700"); - // Check auth on load useEffect(() => { fetch("/api/admin/auth") .then(r => r.json()) @@ -50,7 +57,6 @@ const AdminPage: NextPage = () => { .catch(() => setAuthed(false)); }, []); - // Load settings when authed useEffect(() => { if (!authed) return; fetch("/api/admin/settings") @@ -69,9 +75,8 @@ const AdminPage: NextPage = () => { headers: { "Content-Type": "application/json" }, body: JSON.stringify({ password }) }); - if (res.ok) { - setAuthed(true); - } else { + if (res.ok) setAuthed(true); + else { const d = await res.json(); setLoginError(d.error ?? "Login failed"); } @@ -125,11 +130,7 @@ const AdminPage: NextPage = () => { body: JSON.stringify({ text: "Hello, world!", targetLanguage: "es" }) }); const d = await res.json(); - if (res.ok) { - setTestResult(`✓ Success: "${d.translation}"`); - } else { - setTestResult(`✗ Error: ${d.error}`); - } + setTestResult(res.ok ? `✓ "${d.translation}"` : `✗ ${d.error}`); } catch { setTestResult("✗ Network error"); } finally { @@ -137,7 +138,6 @@ const AdminPage: NextPage = () => { } }; - // Loading state if (authed === null) { return ( @@ -146,22 +146,14 @@ const AdminPage: NextPage = () => { ); } - // Login form if (!authed) { return ( <> Admin Login @@ -181,12 +173,7 @@ const AdminPage: NextPage = () => { /> Default: admin (set ADMIN_PASSWORD env var) - @@ -198,25 +185,21 @@ const AdminPage: NextPage = () => { ); } - // Admin panel return ( <> - + Admin Settings - + - {/* Replicate Section */} + + {/* ── Replicate Section ── */} Replicate AI Translation @@ -235,35 +218,103 @@ const AdminPage: NextPage = () => { /> + {/* Mode selector */} - Replicate API Token - - setSettings(s => ({ ...s, replicateApiToken: e.target.value }))} - placeholder="r8_..." - fontFamily="mono" - fontSize="sm" - /> - - : } - onClick={() => setShowToken(v => !v)} - /> - - - - Get your token at{" "} - - replicate.com/account/api-tokens - - + Translation Backend + setSettings(s => ({ ...s, replicateMode: v as ReplicateMode }))} + > + + + + Replicate Cloud + Uses replicate.com API + + + + + Local Docker (Cog) + Uses local container + + + + + {/* Cloud fields */} + {settings.replicateMode === "cloud" && ( + <> + + Replicate API Token + + setSettings(s => ({ ...s, replicateApiToken: e.target.value }))} + placeholder="r8_..." + fontFamily="mono" + fontSize="sm" + /> + + : } + onClick={() => setShowToken(v => !v)} + /> + + + + Get your token at{" "} + + replicate.com/account/api-tokens + + + + + + Model Version +