Commit 9c95d331 authored by Chunchi Che's avatar Chunchi Che

Merge branch 'feat/custom_ai_url' into 'main'

Enable custom ai server

See merge request !391
parents 5a0a8822 aff3ccf2
Pipeline #28434 passed with stages
in 11 minutes and 48 seconds
import { useConfig } from "@/config";
import { handleHttps } from ".."; import { handleHttps } from "..";
import { agentHeader } from "./util"; import { agentHeader, getAgentServer } from "./util";
const { agentServer } = useConfig();
const API_PATH = "v0/duels"; const API_PATH = "v0/duels";
interface CreateResp { interface CreateResp {
...@@ -14,7 +11,7 @@ interface CreateResp { ...@@ -14,7 +11,7 @@ interface CreateResp {
export async function createDuel(): Promise<CreateResp | undefined> { export async function createDuel(): Promise<CreateResp | undefined> {
const headers = agentHeader(); const headers = agentHeader();
const resp = await fetch(`${agentServer}/${API_PATH}`, { const resp = await fetch(`${getAgentServer()}/${API_PATH}`, {
method: "POST", method: "POST",
headers, headers,
redirect: "follow", redirect: "follow",
......
import { useConfig } from "@/config";
import { handleHttps } from ".."; import { handleHttps } from "..";
import { agentHeader } from "./util"; import { agentHeader, getAgentServer } from "./util";
const { agentServer } = useConfig();
const API_PATH = "/v0/duels"; const API_PATH = "/v0/duels";
export async function deleteDuel(duelId: string): Promise<void | undefined> { export async function deleteDuel(duelId: string): Promise<void | undefined> {
const headers = agentHeader(); const headers = agentHeader();
const apiPath = `${agentServer}/${API_PATH}/${duelId}`; const apiPath = `${getAgentServer()}/${API_PATH}/${duelId}`;
const resp = await fetch(apiPath, { const resp = await fetch(apiPath, {
method: "DELETE", method: "DELETE",
......
import { useConfig } from "@/config";
import { handleHttps } from ".."; import { handleHttps } from "..";
import { Input, MsgResponse } from "./schema"; import { Input, MsgResponse } from "./schema";
import { agentHeader } from "./util"; import { agentHeader, getAgentServer } from "./util";
const { agentServer } = useConfig();
const apiPath = (duelId: string) => `v0/duels/${duelId}/predict`; const apiPath = (duelId: string) => `v0/duels/${duelId}/predict`;
export interface PredictReq { export interface PredictReq {
...@@ -33,7 +30,7 @@ export async function predictDuel( ...@@ -33,7 +30,7 @@ export async function predictDuel(
"Content-Type": "application/json", "Content-Type": "application/json",
}; };
const resp = await fetch(`${agentServer}/${apiPath(duelId)}`, { const resp = await fetch(`${getAgentServer()}/${apiPath(duelId)}`, {
method: "POST", method: "POST",
headers, headers,
body: JSON.stringify(req), body: JSON.stringify(req),
......
import { useConfig } from "@/config";
import { settingStore } from "@/stores/settingStore";
const { agentServer } = useConfig();
export function agentHeader(): Headers { export function agentHeader(): Headers {
const myHeaders = new Headers(); const myHeaders = new Headers();
myHeaders.append("User-Agent", "Apifox/1.0.0 (https://apifox.com)"); myHeaders.append("User-Agent", "Apifox/1.0.0 (https://apifox.com)");
return myHeaders; return myHeaders;
} }
export function getAgentServer(): string {
return settingStore.ai.server ?? agentServer;
}
export interface AIConfig {
// custom AI model server
server?: string;
}
export const defaultAIConfig: AIConfig = {};
...@@ -3,6 +3,7 @@ import { pick } from "lodash-es"; ...@@ -3,6 +3,7 @@ import { pick } from "lodash-es";
import { proxy, subscribe } from "valtio"; import { proxy, subscribe } from "valtio";
import { type NeosStore } from "../shared"; import { type NeosStore } from "../shared";
import { AIConfig, defaultAIConfig } from "./ai";
import { AnimationConfig, defaultAnimationConfig } from "./animation"; import { AnimationConfig, defaultAnimationConfig } from "./animation";
import { AudioConfig, defaultAudioConfig } from "./audio"; import { AudioConfig, defaultAudioConfig } from "./audio";
...@@ -10,12 +11,13 @@ import { AudioConfig, defaultAudioConfig } from "./audio"; ...@@ -10,12 +11,13 @@ import { AudioConfig, defaultAudioConfig } from "./audio";
const NEO_SETTING_CONFIG = "__neo_setting_config__"; const NEO_SETTING_CONFIG = "__neo_setting_config__";
/** 设置项 */ /** 设置项 */
type SettingStoreConfig = Pick<SettingStore, "audio" | "animation">; type SettingStoreConfig = Pick<SettingStore, "audio" | "animation" | "ai">;
/** 默认设置 */ /** 默认设置 */
const defaultSettingConfig: SettingStoreConfig = { const defaultSettingConfig: SettingStoreConfig = {
audio: defaultAudioConfig, audio: defaultAudioConfig,
animation: defaultAnimationConfig, animation: defaultAnimationConfig,
ai: defaultAIConfig,
}; };
/** 获取默认设置 */ /** 获取默认设置 */
...@@ -28,6 +30,7 @@ function getDefaultSetting() { ...@@ -28,6 +30,7 @@ function getDefaultSetting() {
if (config.audio === undefined) config.audio = defaultAudioConfig; if (config.audio === undefined) config.audio = defaultAudioConfig;
if (config.animation === undefined) if (config.animation === undefined)
config.animation = defaultAnimationConfig; config.animation = defaultAnimationConfig;
if (config.ai === undefined) config.ai = defaultAIConfig;
return config; return config;
} }
} }
...@@ -44,6 +47,9 @@ class SettingStore implements NeosStore { ...@@ -44,6 +47,9 @@ class SettingStore implements NeosStore {
/** Animation Configuration */ /** Animation Configuration */
animation: AnimationConfig = defaultSetting.animation; animation: AnimationConfig = defaultSetting.animation;
/** AI Configuration */
ai: AIConfig = defaultSetting.ai;
/** 保存音频设置 */ /** 保存音频设置 */
saveAudioConfig(config: Partial<AudioConfig>): void { saveAudioConfig(config: Partial<AudioConfig>): void {
Object.assign(this.audio, config); Object.assign(this.audio, config);
...@@ -54,6 +60,11 @@ class SettingStore implements NeosStore { ...@@ -54,6 +60,11 @@ class SettingStore implements NeosStore {
Object.assign(this.animation, config); Object.assign(this.animation, config);
} }
/** save AI Configuration */
saveAIConfig(config: Partial<AIConfig>): void {
Object.assign(this.ai, config);
}
reset(): void { reset(): void {
const defaultSetting = getDefaultSetting(); const defaultSetting = getDefaultSetting();
this.audio = defaultSetting.audio; this.audio = defaultSetting.audio;
...@@ -69,7 +80,7 @@ subscribe(settingStore, () => { ...@@ -69,7 +80,7 @@ subscribe(settingStore, () => {
if (!isSSR()) { if (!isSSR()) {
localStorage.setItem( localStorage.setItem(
NEO_SETTING_CONFIG, NEO_SETTING_CONFIG,
JSON.stringify(pick(settingStore, ["audio", "animation"])), JSON.stringify(pick(settingStore, ["audio", "animation", "ai"])),
); );
} }
}); });
...@@ -203,7 +203,11 @@ ...@@ -203,7 +203,11 @@
"SwitchMusicAccordingToTheEnvironment": "根据环境切换音乐", "SwitchMusicAccordingToTheEnvironment": "根据环境切换音乐",
"LanguageSettings": "语言", "LanguageSettings": "语言",
"AnimationSettings": "动画", "AnimationSettings": "动画",
"AnimationSpeed": "动画速度" "AnimationSpeed": "动画速度",
"AISettings": "AI设置",
"CustomAIServer": "输入自定义AI模型服务器URL",
"ApplyAISettings": "应用",
"RecoverDefault": "恢复默认设置"
}, },
"DeckResults": { "DeckResults": {
"NoDeckGroupFound": "找不到相应卡组" "NoDeckGroupFound": "找不到相应卡组"
......
import { App, Button, Col, Input, Row } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { useConfig } from "@/config";
import { settingStore } from "@/stores/settingStore";
const { agentServer } = useConfig();
export const AISettings: React.FC = () => {
const { message } = App.useApp();
const [server, setServer] = useState<string>(
settingStore.ai.server ?? agentServer,
);
const onApply = () => {
settingStore.saveAIConfig({ server });
message.info("设置成功");
};
const onRestore = () => {
settingStore.saveAIConfig({ server: agentServer });
setServer(agentServer);
};
const { t: i18n } = useTranslation("SystemSettings");
return (
<div>
<Row style={{ marginBottom: "20px" }}>
<Col span={24}>
<p>{i18n("CustomAIServer")}</p>
</Col>
</Row>
<Row style={{ marginBottom: "20px" }}>
<Col span={24}>
<Input
placeholder="Text your URL"
value={server}
onChange={(e) => setServer(e.target.value)}
/>
</Col>
</Row>
<Row justify="end">
<Col>
<Button
type="primary"
style={{ marginRight: "8px" }}
onClick={onApply}
>
{i18n("ApplyAISettings")}
</Button>
<Button onClick={onRestore}>{i18n("RecoverDefault")}</Button>
</Col>
</Row>
</div>
);
};
import { import {
AudioFilled, AudioFilled,
OpenAIOutlined,
PlayCircleOutlined, PlayCircleOutlined,
TranslationOutlined, TranslationOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
...@@ -11,6 +12,7 @@ import { useTranslation } from "react-i18next"; ...@@ -11,6 +12,7 @@ import { useTranslation } from "react-i18next";
import { I18NSelector } from "../I18N"; import { I18NSelector } from "../I18N";
import { theme } from "../theme"; import { theme } from "../theme";
import { AISettings } from "./AISettings";
import { AnimationSetting } from "./Animation"; import { AnimationSetting } from "./Animation";
import { AudioSetting } from "./Audio"; import { AudioSetting } from "./Audio";
...@@ -52,6 +54,15 @@ export const Setting = (props: SettingProps) => { ...@@ -52,6 +54,15 @@ export const Setting = (props: SettingProps) => {
), ),
children: <AnimationSetting />, children: <AnimationSetting />,
}, },
{
key: "ai",
label: (
<>
{i18n("AISettings")} <OpenAIOutlined />
</>
),
children: <AISettings />,
},
]; ];
return <Tabs defaultActiveKey={defaultKey} items={items} />; return <Tabs defaultActiveKey={defaultKey} items={items} />;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment