Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions components/OpenAISettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { useState, useEffect } from "react";
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
Button,
FormControl,
FormLabel,
Input,
VStack,
useToast,
Text,
Box,
Divider,
} from "@chakra-ui/react";

interface OpenAISettingsProps {
isOpen: boolean;
onClose: () => void;
}

const OpenAISettings = ({ isOpen, onClose }: OpenAISettingsProps) => {
const [apiKey, setApiKey] = useState<string>("");
const [model, setModel] = useState<string>("gpt-4o-mini");
const [endpoint, setEndpoint] = useState<string>("https://api.openai.com/v1/chat/completions");
const toast = useToast();

// 加载保存的设置
useEffect(() => {
if (isOpen) {
const savedApiKey = localStorage.getItem("openai_api_key") || "";
const savedModel = localStorage.getItem("openai_model") || "gpt-4o-mini";
const savedEndpoint = localStorage.getItem("openai_endpoint") || "https://api.openai.com/v1/chat/completions";

setApiKey(savedApiKey);
setModel(savedModel);
setEndpoint(savedEndpoint);
}
}, [isOpen]);

const handleSave = () => {
// 保存到localStorage
localStorage.setItem("openai_api_key", apiKey);
localStorage.setItem("openai_model", model);
localStorage.setItem("openai_endpoint", endpoint);

// 更新环境变量(通过前端无法直接修改环境变量,这里只是模拟)
// 实际上这些值会在API请求时从localStorage中读取
window.sessionStorage.setItem("OPENAI_API_KEY", apiKey);
window.sessionStorage.setItem("OPENAI_MODEL", model);
window.sessionStorage.setItem("OPENAI_ENDPOINT", endpoint);

toast({
title: "设置已保存",
description: "OpenAI设置已成功保存。",
status: "success",
duration: 3000,
isClosable: true,
position: "top",
});

onClose();
};

return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent bg="gray.800">
<ModalHeader>OpenAI设置</ModalHeader>
<ModalCloseButton />
<ModalBody>
<VStack spacing={4}>
<Text>
配置OpenAI翻译服务的API密钥、模型和端点。这些设置将保存在浏览器中,不会上传到服务器。
</Text>

<Divider />

<FormControl>
<FormLabel>API密钥</FormLabel>
<Input
type="password"
placeholder="sk-..."
value={apiKey}
onChange={(e) => setApiKey(e.target.value)}
bg="gray.700"
borderColor="gray.600"
/>
</FormControl>

<FormControl>
<FormLabel>模型</FormLabel>
<Input
placeholder="gpt-4o-mini"
value={model}
onChange={(e) => setModel(e.target.value)}
bg="gray.700"
borderColor="gray.600"
/>
</FormControl>

<FormControl>
<FormLabel>API端点</FormLabel>
<Input
placeholder="https://api.openai.com/v1/chat/completions"
value={endpoint}
onChange={(e) => setEndpoint(e.target.value)}
bg="gray.700"
borderColor="gray.600"
/>
</FormControl>

<Box width="100%" p={3} bg="gray.700" borderRadius="md">
<Text fontSize="sm" color="gray.300">
常用模型:
</Text>
<Text fontSize="sm" color="gray.300">
- gpt-4o-mini (OpenAI)
</Text>
<Text fontSize="sm" color="gray.300">
- gpt-3.5-turbo (OpenAI)
</Text>
<Text fontSize="sm" color="gray.300">
- gpt-4o (OpenAI)
</Text>
<Text fontSize="sm" color="gray.300">
- claude-3-opus-20240229 (Anthropic)
</Text>
</Box>
</VStack>
</ModalBody>
<ModalFooter>
<Button variant="ghost" mr={3} onClick={onClose}>
取消
</Button>
<Button colorScheme="brand" onClick={handleSave}>
保存
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
};

export default OpenAISettings;
Loading
Loading