refactor: openAI config system setting (#1333)

This commit is contained in:
boojack
2023-03-11 12:26:40 +08:00
committed by GitHub
parent 7c92805aac
commit e5cbb8cd56
8 changed files with 108 additions and 181 deletions

View File

@ -19,6 +19,4 @@ type SystemStatus struct {
// Customized server profile, including server name and external url. // Customized server profile, including server name and external url.
CustomizedProfile CustomizedProfile `json:"customizedProfile"` CustomizedProfile CustomizedProfile `json:"customizedProfile"`
StorageServiceID int `json:"storageServiceId"` StorageServiceID int `json:"storageServiceId"`
// OpenAI API Host
OpenAIAPIHost string `json:"openAIApiHost"`
} }

View File

@ -27,10 +27,8 @@ const (
SystemSettingCustomizedProfileName SystemSettingName = "customizedProfile" SystemSettingCustomizedProfileName SystemSettingName = "customizedProfile"
// SystemSettingStorageServiceIDName is the key type of storage service ID. // SystemSettingStorageServiceIDName is the key type of storage service ID.
SystemSettingStorageServiceIDName SystemSettingName = "storageServiceId" SystemSettingStorageServiceIDName SystemSettingName = "storageServiceId"
// SystemSettingOpenAIAPIKeyName is the key type of OpenAI API key. // SystemSettingOpenAIConfigName is the key type of OpenAI config.
SystemSettingOpenAIAPIKeyName SystemSettingName = "openAIApiKey" SystemSettingOpenAIConfigName SystemSettingName = "openAIConfig"
// SystemSettingOpenAIAPIHost is the key type of OpenAI API path.
SystemSettingOpenAIAPIHost SystemSettingName = "openAIApiHost"
) )
// CustomizedProfile is the struct definition for SystemSettingCustomizedProfileName system setting item. // CustomizedProfile is the struct definition for SystemSettingCustomizedProfileName system setting item.
@ -49,6 +47,11 @@ type CustomizedProfile struct {
ExternalURL string `json:"externalUrl"` ExternalURL string `json:"externalUrl"`
} }
type OpenAIConfig struct {
Key string `json:"key"`
Host string `json:"host"`
}
func (key SystemSettingName) String() string { func (key SystemSettingName) String() string {
switch key { switch key {
case SystemSettingServerID: case SystemSettingServerID:
@ -67,24 +70,17 @@ func (key SystemSettingName) String() string {
return "customizedProfile" return "customizedProfile"
case SystemSettingStorageServiceIDName: case SystemSettingStorageServiceIDName:
return "storageServiceId" return "storageServiceId"
case SystemSettingOpenAIAPIKeyName: case SystemSettingOpenAIConfigName:
return "openAIApiKey" return "openAIConfig"
case SystemSettingOpenAIAPIHost:
return "openAIApiHost"
} }
return "" return ""
} }
var (
SystemSettingAllowSignUpValue = []bool{true, false}
SystemSettingDisablePublicMemosValue = []bool{true, false}
)
type SystemSetting struct { type SystemSetting struct {
Name SystemSettingName Name SystemSettingName `json:"name"`
// Value is a JSON string with basic value. // Value is a JSON string with basic value.
Value string Value string `json:"value"`
Description string Description string `json:"description"`
} }
type SystemSettingUpsert struct { type SystemSettingUpsert struct {
@ -102,35 +98,12 @@ func (upsert SystemSettingUpsert) Validate() error {
if err != nil { if err != nil {
return fmt.Errorf("failed to unmarshal system setting allow signup value") return fmt.Errorf("failed to unmarshal system setting allow signup value")
} }
invalid := true
for _, v := range SystemSettingAllowSignUpValue {
if value == v {
invalid = false
break
}
}
if invalid {
return fmt.Errorf("invalid system setting allow signup value")
}
} else if upsert.Name == SystemSettingDisablePublicMemosName { } else if upsert.Name == SystemSettingDisablePublicMemosName {
value := false value := false
err := json.Unmarshal([]byte(upsert.Value), &value) err := json.Unmarshal([]byte(upsert.Value), &value)
if err != nil { if err != nil {
return fmt.Errorf("failed to unmarshal system setting disable public memos value") return fmt.Errorf("failed to unmarshal system setting disable public memos value")
} }
invalid := true
for _, v := range SystemSettingDisablePublicMemosValue {
if value == v {
invalid = false
break
}
}
if invalid {
return fmt.Errorf("invalid system setting disable public memos value")
}
} else if upsert.Name == SystemSettingAdditionalStyleName { } else if upsert.Name == SystemSettingAdditionalStyleName {
value := "" value := ""
err := json.Unmarshal([]byte(upsert.Value), &value) err := json.Unmarshal([]byte(upsert.Value), &value)
@ -169,17 +142,11 @@ func (upsert SystemSettingUpsert) Validate() error {
return fmt.Errorf("failed to unmarshal system setting storage service id value") return fmt.Errorf("failed to unmarshal system setting storage service id value")
} }
return nil return nil
} else if upsert.Name == SystemSettingOpenAIAPIKeyName { } else if upsert.Name == SystemSettingOpenAIConfigName {
value := "" value := OpenAIConfig{}
err := json.Unmarshal([]byte(upsert.Value), &value) err := json.Unmarshal([]byte(upsert.Value), &value)
if err != nil { if err != nil {
return fmt.Errorf("failed to unmarshal system setting openai api key value") return fmt.Errorf("failed to unmarshal system setting openai api config value")
}
} else if upsert.Name == SystemSettingOpenAIAPIHost {
value := ""
err := json.Unmarshal([]byte(upsert.Value), &value)
if err != nil {
return fmt.Errorf("failed to unmarshal system setting openai api host value")
} }
} else { } else {
return fmt.Errorf("invalid system setting name") return fmt.Errorf("invalid system setting name")

View File

@ -13,39 +13,24 @@ import (
func (s *Server) registerOpenAIRoutes(g *echo.Group) { func (s *Server) registerOpenAIRoutes(g *echo.Group) {
g.POST("/openai/chat-completion", func(c echo.Context) error { g.POST("/openai/chat-completion", func(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
openAIApiKeySetting, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{ openAIConfigSetting, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{
Name: api.SystemSettingOpenAIAPIKeyName, Name: api.SystemSettingOpenAIConfigName,
}) })
if err != nil && common.ErrorCode(err) != common.NotFound { if err != nil && common.ErrorCode(err) != common.NotFound {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find openai api key").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find openai key").SetInternal(err)
} }
openAIApiHostSetting, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{ openAIConfig := api.OpenAIConfig{}
Name: api.SystemSettingOpenAIAPIHost, if openAIConfigSetting != nil {
}) err = json.Unmarshal([]byte(openAIConfigSetting.Value), &openAIConfig)
if err != nil && common.ErrorCode(err) != common.NotFound {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find openai api host").SetInternal(err)
}
openAIApiKey := ""
if openAIApiKeySetting != nil {
err = json.Unmarshal([]byte(openAIApiKeySetting.Value), &openAIApiKey)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal system setting value").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal openai system setting value").SetInternal(err)
} }
} }
if openAIApiKey == "" { if openAIConfig.Key == "" {
return echo.NewHTTPError(http.StatusBadRequest, "OpenAI API key not set") return echo.NewHTTPError(http.StatusBadRequest, "OpenAI API key not set")
} }
openAIApiHost := ""
if openAIApiHostSetting != nil {
err = json.Unmarshal([]byte(openAIApiHostSetting.Value), &openAIApiHost)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal system setting value").SetInternal(err)
}
}
completionRequest := api.OpenAICompletionRequest{} completionRequest := api.OpenAICompletionRequest{}
if err := json.NewDecoder(c.Request().Body).Decode(&completionRequest); err != nil { if err := json.NewDecoder(c.Request().Body).Decode(&completionRequest); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post chat completion request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post chat completion request").SetInternal(err)
@ -54,7 +39,7 @@ func (s *Server) registerOpenAIRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusBadRequest, "Prompt is required") return echo.NewHTTPError(http.StatusBadRequest, "Prompt is required")
} }
result, err := openai.PostChatCompletion(completionRequest.Prompt, openAIApiKey, openAIApiHost) result, err := openai.PostChatCompletion(completionRequest.Prompt, openAIConfig.Key, openAIConfig.Host)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to post chat completion").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to post chat completion").SetInternal(err)
} }
@ -64,39 +49,24 @@ func (s *Server) registerOpenAIRoutes(g *echo.Group) {
g.POST("/openai/text-completion", func(c echo.Context) error { g.POST("/openai/text-completion", func(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
openAIApiKeySetting, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{ openAIConfigSetting, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{
Name: api.SystemSettingOpenAIAPIKeyName, Name: api.SystemSettingOpenAIConfigName,
}) })
if err != nil && common.ErrorCode(err) != common.NotFound { if err != nil && common.ErrorCode(err) != common.NotFound {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find openai api key").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find openai key").SetInternal(err)
} }
openAIApiHostSetting, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{ openAIConfig := api.OpenAIConfig{}
Name: api.SystemSettingOpenAIAPIHost, if openAIConfigSetting != nil {
}) err = json.Unmarshal([]byte(openAIConfigSetting.Value), &openAIConfig)
if err != nil && common.ErrorCode(err) != common.NotFound {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find openai api host").SetInternal(err)
}
openAIApiKey := ""
if openAIApiKeySetting != nil {
err = json.Unmarshal([]byte(openAIApiKeySetting.Value), &openAIApiKey)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal system setting value").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal openai system setting value").SetInternal(err)
} }
} }
if openAIApiKey == "" { if openAIConfig.Key == "" {
return echo.NewHTTPError(http.StatusBadRequest, "OpenAI API key not set") return echo.NewHTTPError(http.StatusBadRequest, "OpenAI API key not set")
} }
openAIApiHost := ""
if openAIApiHostSetting != nil {
err = json.Unmarshal([]byte(openAIApiHostSetting.Value), &openAIApiHost)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal system setting value").SetInternal(err)
}
}
textCompletion := api.OpenAICompletionRequest{} textCompletion := api.OpenAICompletionRequest{}
if err := json.NewDecoder(c.Request().Body).Decode(&textCompletion); err != nil { if err := json.NewDecoder(c.Request().Body).Decode(&textCompletion); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post text completion request").SetInternal(err) return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post text completion request").SetInternal(err)
@ -105,7 +75,7 @@ func (s *Server) registerOpenAIRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusBadRequest, "Prompt is required") return echo.NewHTTPError(http.StatusBadRequest, "Prompt is required")
} }
result, err := openai.PostTextCompletion(textCompletion.Prompt, openAIApiKey, openAIApiHost) result, err := openai.PostTextCompletion(textCompletion.Prompt, openAIConfig.Key, openAIConfig.Host)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to post text completion").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to post text completion").SetInternal(err)
} }
@ -115,21 +85,24 @@ func (s *Server) registerOpenAIRoutes(g *echo.Group) {
g.GET("/openai/enabled", func(c echo.Context) error { g.GET("/openai/enabled", func(c echo.Context) error {
ctx := c.Request().Context() ctx := c.Request().Context()
openAIApiKeySetting, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{ openAIConfigSetting, err := s.Store.FindSystemSetting(ctx, &api.SystemSettingFind{
Name: api.SystemSettingOpenAIAPIKeyName, Name: api.SystemSettingOpenAIConfigName,
}) })
if err != nil && common.ErrorCode(err) != common.NotFound { if err != nil && common.ErrorCode(err) != common.NotFound {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find openai api key").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find openai key").SetInternal(err)
} }
openAIApiKey := "" openAIConfig := api.OpenAIConfig{}
if openAIApiKeySetting != nil { if openAIConfigSetting != nil {
err = json.Unmarshal([]byte(openAIApiKeySetting.Value), &openAIApiKey) err = json.Unmarshal([]byte(openAIConfigSetting.Value), &openAIConfig)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal system setting value").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal openai system setting value").SetInternal(err)
} }
} }
if openAIConfig.Key == "" {
return echo.NewHTTPError(http.StatusBadRequest, "OpenAI API key not set")
}
return c.JSON(http.StatusOK, composeResponse(openAIApiKey != "")) return c.JSON(http.StatusOK, composeResponse(openAIConfig.Key != ""))
}) })
} }

View File

@ -52,7 +52,6 @@ func (s *Server) registerSystemRoutes(g *echo.Group) {
ExternalURL: "", ExternalURL: "",
}, },
StorageServiceID: 0, StorageServiceID: 0,
OpenAIAPIHost: "",
} }
systemSettingList, err := s.Store.FindSystemSettingList(ctx, &api.SystemSettingFind{}) systemSettingList, err := s.Store.FindSystemSettingList(ctx, &api.SystemSettingFind{})
@ -60,49 +59,33 @@ func (s *Server) registerSystemRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find system setting list").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find system setting list").SetInternal(err)
} }
for _, systemSetting := range systemSettingList { for _, systemSetting := range systemSettingList {
if systemSetting.Name == api.SystemSettingServerID || systemSetting.Name == api.SystemSettingSecretSessionName || systemSetting.Name == api.SystemSettingOpenAIAPIKeyName { if systemSetting.Name == api.SystemSettingServerID || systemSetting.Name == api.SystemSettingSecretSessionName || systemSetting.Name == api.SystemSettingOpenAIConfigName {
continue continue
} }
var value interface{} var baseValue interface{}
err := json.Unmarshal([]byte(systemSetting.Value), &value) err := json.Unmarshal([]byte(systemSetting.Value), &baseValue)
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal system setting value").SetInternal(err) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal system setting value").SetInternal(err)
} }
if systemSetting.Name == api.SystemSettingAllowSignUpName { if systemSetting.Name == api.SystemSettingAllowSignUpName {
systemStatus.AllowSignUp = value.(bool) systemStatus.AllowSignUp = baseValue.(bool)
} else if systemSetting.Name == api.SystemSettingDisablePublicMemosName { } else if systemSetting.Name == api.SystemSettingDisablePublicMemosName {
systemStatus.DisablePublicMemos = value.(bool) systemStatus.DisablePublicMemos = baseValue.(bool)
} else if systemSetting.Name == api.SystemSettingAdditionalStyleName { } else if systemSetting.Name == api.SystemSettingAdditionalStyleName {
systemStatus.AdditionalStyle = value.(string) systemStatus.AdditionalStyle = baseValue.(string)
} else if systemSetting.Name == api.SystemSettingAdditionalScriptName { } else if systemSetting.Name == api.SystemSettingAdditionalScriptName {
systemStatus.AdditionalScript = value.(string) systemStatus.AdditionalScript = baseValue.(string)
} else if systemSetting.Name == api.SystemSettingCustomizedProfileName { } else if systemSetting.Name == api.SystemSettingCustomizedProfileName {
valueMap := value.(map[string]interface{}) customizedProfile := api.CustomizedProfile{}
systemStatus.CustomizedProfile = api.CustomizedProfile{} err := json.Unmarshal([]byte(systemSetting.Value), &customizedProfile)
if v := valueMap["name"]; v != nil { if err != nil {
systemStatus.CustomizedProfile.Name = v.(string) return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal system setting customized profile value").SetInternal(err)
}
if v := valueMap["logoUrl"]; v != nil {
systemStatus.CustomizedProfile.LogoURL = v.(string)
}
if v := valueMap["description"]; v != nil {
systemStatus.CustomizedProfile.Description = v.(string)
}
if v := valueMap["locale"]; v != nil {
systemStatus.CustomizedProfile.Locale = v.(string)
}
if v := valueMap["appearance"]; v != nil {
systemStatus.CustomizedProfile.Appearance = v.(string)
}
if v := valueMap["externalUrl"]; v != nil {
systemStatus.CustomizedProfile.ExternalURL = v.(string)
} }
systemStatus.CustomizedProfile = customizedProfile
} else if systemSetting.Name == api.SystemSettingStorageServiceIDName { } else if systemSetting.Name == api.SystemSettingStorageServiceIDName {
systemStatus.StorageServiceID = int(value.(float64)) systemStatus.StorageServiceID = int(baseValue.(float64))
} else if systemSetting.Name == api.SystemSettingOpenAIAPIHost {
systemStatus.OpenAIAPIHost = value.(string)
} }
} }

View File

@ -5,16 +5,12 @@ import { Button, Divider, Input, Switch, Textarea } from "@mui/joy";
import { useGlobalStore } from "../../store/module"; import { useGlobalStore } from "../../store/module";
import * as api from "../../helpers/api"; import * as api from "../../helpers/api";
import showUpdateCustomizedProfileDialog from "../UpdateCustomizedProfileDialog"; import showUpdateCustomizedProfileDialog from "../UpdateCustomizedProfileDialog";
import { useAppDispatch } from "../../store";
import { setGlobalState } from "../../store/reducer/global";
import "@/less/settings/system-section.less"; import "@/less/settings/system-section.less";
interface State { interface State {
dbSize: number; dbSize: number;
allowSignUp: boolean; allowSignUp: boolean;
disablePublicMemos: boolean; disablePublicMemos: boolean;
openAIApiKey: string;
openAIApiHost: string;
additionalStyle: string; additionalStyle: string;
additionalScript: string; additionalScript: string;
} }
@ -36,13 +32,13 @@ const SystemSection = () => {
dbSize: systemStatus.dbSize, dbSize: systemStatus.dbSize,
allowSignUp: systemStatus.allowSignUp, allowSignUp: systemStatus.allowSignUp,
additionalStyle: systemStatus.additionalStyle, additionalStyle: systemStatus.additionalStyle,
openAIApiKey: "",
openAIApiHost: systemStatus.openAIApiHost,
additionalScript: systemStatus.additionalScript, additionalScript: systemStatus.additionalScript,
disablePublicMemos: systemStatus.disablePublicMemos, disablePublicMemos: systemStatus.disablePublicMemos,
}); });
const [openAIConfig, setOpenAIConfig] = useState<OpenAIConfig>({
const dispatch = useAppDispatch(); key: "",
host: "",
});
useEffect(() => { useEffect(() => {
globalStore.fetchSystemStatus(); globalStore.fetchSystemStatus();
@ -50,16 +46,24 @@ const SystemSection = () => {
useEffect(() => { useEffect(() => {
setState({ setState({
...state,
dbSize: systemStatus.dbSize, dbSize: systemStatus.dbSize,
allowSignUp: systemStatus.allowSignUp, allowSignUp: systemStatus.allowSignUp,
additionalStyle: systemStatus.additionalStyle, additionalStyle: systemStatus.additionalStyle,
openAIApiKey: "",
openAIApiHost: systemStatus.openAIApiHost,
additionalScript: systemStatus.additionalScript, additionalScript: systemStatus.additionalScript,
disablePublicMemos: systemStatus.disablePublicMemos, disablePublicMemos: systemStatus.disablePublicMemos,
}); });
}, [systemStatus]); }, [systemStatus]);
useEffect(() => {
api.getSystemSetting().then(({ data: { data: systemSettings } }) => {
const openAIConfigSetting = systemSettings.find((setting) => setting.name === "openAIConfig");
if (openAIConfigSetting) {
setOpenAIConfig(JSON.parse(openAIConfigSetting.value));
}
});
}, []);
const handleAllowSignUpChanged = async (value: boolean) => { const handleAllowSignUpChanged = async (value: boolean) => {
setState({ setState({
...state, ...state,
@ -86,46 +90,33 @@ const SystemSection = () => {
toast.success(t("message.succeed-vacuum-database")); toast.success(t("message.succeed-vacuum-database"));
}; };
const handleOpenAIApiKeyChanged = (value: string) => { const handleOpenAIConfigKeyChanged = (value: string) => {
setState({ setOpenAIConfig({
...state, ...openAIConfig,
openAIApiKey: value, key: value,
}); });
}; };
const handleSaveOpenAIApiKey = async () => { const handleSaveOpenAIConfig = async () => {
try { try {
await api.upsertSystemSetting({ await api.upsertSystemSetting({
name: "openAIApiKey", name: "openAIConfig",
value: JSON.stringify(state.openAIApiKey), value: JSON.stringify(openAIConfig),
}); });
} catch (error) { } catch (error) {
console.error(error); console.error(error);
return; return;
} }
toast.success("OpenAI Api Key updated"); toast.success("OpenAI Config updated");
}; };
const handleOpenAIApiHostChanged = (value: string) => { const handleOpenAIConfigHostChanged = (value: string) => {
setState({ setOpenAIConfig({
...state, ...openAIConfig,
openAIApiHost: value, host: value,
}); });
}; };
const handleSaveOpenAIApiHost = async () => {
try {
await api.upsertSystemSetting({
name: "openAIApiHost",
value: JSON.stringify(state.openAIApiHost),
});
} catch (error) {
console.error(error);
return;
}
toast.success("OpenAI Api Host updated");
};
const handleAdditionalStyleChanged = (value: string) => { const handleAdditionalStyleChanged = (value: string) => {
setState({ setState({
...state, ...state,
@ -171,8 +162,7 @@ const SystemSection = () => {
...state, ...state,
disablePublicMemos: value, disablePublicMemos: value,
}); });
// Update global store immediately as MemoEditor/Selector is dependent on this value. globalStore.setSystemStatus({ disablePublicMemos: value });
dispatch(setGlobalState({ systemStatus: { ...systemStatus, disablePublicMemos: value } }));
await api.upsertSystemSetting({ await api.upsertSystemSetting({
name: "disablePublicMemos", name: "disablePublicMemos",
value: JSON.stringify(value), value: JSON.stringify(value),
@ -206,7 +196,7 @@ const SystemSection = () => {
<Divider className="!mt-3 !my-4" /> <Divider className="!mt-3 !my-4" />
<div className="form-label"> <div className="form-label">
<span className="normal-text">OpenAI API Key</span> <span className="normal-text">OpenAI API Key</span>
<Button onClick={handleSaveOpenAIApiKey}>{t("common.save")}</Button> <Button onClick={handleSaveOpenAIConfig}>{t("common.save")}</Button>
</div> </div>
<Input <Input
className="w-full" className="w-full"
@ -215,12 +205,11 @@ const SystemSection = () => {
fontSize: "14px", fontSize: "14px",
}} }}
placeholder="Write only" placeholder="Write only"
value={state.openAIApiKey} value={openAIConfig.key}
onChange={(event) => handleOpenAIApiKeyChanged(event.target.value)} onChange={(event) => handleOpenAIConfigKeyChanged(event.target.value)}
/> />
<div className="form-label mt-2"> <div className="form-label mt-2">
<span className="normal-text">OpenAI API Host</span> <span className="normal-text">OpenAI API Host</span>
<Button onClick={handleSaveOpenAIApiHost}>{t("common.save")}</Button>
</div> </div>
<Input <Input
className="w-full" className="w-full"
@ -229,8 +218,8 @@ const SystemSection = () => {
fontSize: "14px", fontSize: "14px",
}} }}
placeholder="OpenAI Host. Default: https://api.openai.com" placeholder="OpenAI Host. Default: https://api.openai.com"
value={state.openAIApiHost} value={openAIConfig.host}
onChange={(event) => handleOpenAIApiHostChanged(event.target.value)} onChange={(event) => handleOpenAIConfigHostChanged(event.target.value)}
/> />
<Divider className="!mt-3 !my-4" /> <Divider className="!mt-3 !my-4" />
<div className="form-label"> <div className="form-label">

View File

@ -10,6 +10,10 @@ export function getSystemStatus() {
return axios.get<ResponseObject<SystemStatus>>("/api/status"); return axios.get<ResponseObject<SystemStatus>>("/api/status");
} }
export function getSystemSetting() {
return axios.get<ResponseObject<SystemSetting[]>>("/api/system/setting");
}
export function upsertSystemSetting(systemSetting: SystemSetting) { export function upsertSystemSetting(systemSetting: SystemSetting) {
return axios.post<ResponseObject<SystemSetting>>("/api/system/setting", systemSetting); return axios.post<ResponseObject<SystemSetting>>("/api/system/setting", systemSetting);
} }

View File

@ -22,7 +22,6 @@ export const initialGlobalState = async () => {
appearance: "system", appearance: "system",
externalUrl: "", externalUrl: "",
}, },
openAIApiHost: "",
} as SystemStatus, } as SystemStatus,
}; };
@ -75,6 +74,16 @@ export const useGlobalStore = () => {
store.dispatch(setGlobalState({ systemStatus: systemStatus })); store.dispatch(setGlobalState({ systemStatus: systemStatus }));
return systemStatus; return systemStatus;
}, },
setSystemStatus: (systemStatus: Partial<SystemStatus>) => {
store.dispatch(
setGlobalState({
systemStatus: {
...state.systemStatus,
...systemStatus,
},
})
);
},
setLocale: (locale: Locale) => { setLocale: (locale: Locale) => {
store.dispatch(setLocale(locale)); store.dispatch(setLocale(locale));
}, },

View File

@ -12,6 +12,11 @@ interface CustomizedProfile {
externalUrl: string; externalUrl: string;
} }
interface OpenAIConfig {
key: string;
host: string;
}
interface SystemStatus { interface SystemStatus {
host?: User; host?: User;
profile: Profile; profile: Profile;
@ -23,7 +28,6 @@ interface SystemStatus {
additionalScript: string; additionalScript: string;
customizedProfile: CustomizedProfile; customizedProfile: CustomizedProfile;
storageServiceId: number; storageServiceId: number;
openAIApiHost: string;
} }
interface SystemSetting { interface SystemSetting {