import { useState, useEffect, useMemo } from "react";
import Stack from "@mui/material/Stack";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import LoadingButton from "@mui/lab/LoadingButton";
import MenuItem from "@mui/material/MenuItem";
import FormControlLabel from "@mui/material/FormControlLabel";
import Switch from "@mui/material/Switch";
import { useI18n } from "../../hooks/I18n";
import Typography from "@mui/material/Typography";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import AccordionDetails from "@mui/material/AccordionDetails";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import AddIcon from "@mui/icons-material/Add";
import Alert from "@mui/material/Alert";
import Menu from "@mui/material/Menu";
import Grid from "@mui/material/Grid";
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
import { useAlert } from "../../hooks/Alert";
import { useApiList, useApiItem } from "../../hooks/Api";
import { useConfirm } from "../../hooks/Confirm";
import { apiTranslate } from "../../apis";
import Box from "@mui/material/Box";
import { limitNumber, limitFloat } from "../../libs/utils";
import ReusableAutocomplete from "./ReusableAutocomplete";
import ShowMoreButton from "./ShowMoreButton";
import {
OPT_TRANS_DEEPLX,
OPT_TRANS_OLLAMA,
OPT_TRANS_CUSTOMIZE,
OPT_TRANS_NIUTRANS,
OPT_TRANS_BUILTINAI,
DEFAULT_FETCH_LIMIT,
DEFAULT_FETCH_INTERVAL,
DEFAULT_HTTP_TIMEOUT,
DEFAULT_BATCH_INTERVAL,
DEFAULT_BATCH_SIZE,
DEFAULT_BATCH_LENGTH,
DEFAULT_CONTEXT_SIZE,
OPT_ALL_TYPES,
API_SPE_TYPES,
BUILTIN_STONES,
BUILTIN_PLACEHOLDERS,
BUILTIN_PLACETAGS,
} from "../../config";
function TestButton({ apiSlug, api }) {
const i18n = useI18n();
const alert = useAlert();
const [loading, setLoading] = useState(false);
const handleApiTest = async () => {
try {
setLoading(true);
const [text] = await apiTranslate({
apiSlug,
text: "hello world",
fromLang: "en",
toLang: "zh-CN",
apiSetting: api,
useCache: false,
});
if (!text) {
throw new Error("empty result");
}
alert.success(i18n("test_success"));
} catch (err) {
// alert.error(`${i18n("test_failed")}: ${err.message}`);
let msg = err.message;
try {
msg = JSON.stringify(JSON.parse(err.message), null, 2);
} catch (err) {
// skip
}
alert.error(
<>
{i18n("test_failed")}
{msg === err.message ? (
{msg}
) : (
{msg}
)}
>
);
} finally {
setLoading(false);
}
};
return (
{i18n("click_test")}
);
}
function ApiFields({ apiSlug, isUserApi, deleteApi }) {
const { api, update, reset } = useApiItem(apiSlug);
const i18n = useI18n();
const [formData, setFormData] = useState({});
const [isModified, setIsModified] = useState(false);
const [showMore, setShowMore] = useState(false);
const confirm = useConfirm();
useEffect(() => {
if (api) {
setFormData(api);
}
}, [api]);
useEffect(() => {
if (!api) return;
const hasChanged = JSON.stringify(api) !== JSON.stringify(formData);
setIsModified(hasChanged);
}, [api, formData]);
const handleChange = (e) => {
let { name, value, type, checked } = e.target;
if (type === "checkbox" || type === "switch") {
value = checked;
}
// if (value === "true") value = true;
// if (value === "false") value = false;
switch (name) {
case "fetchLimit":
value = limitNumber(value, 1, 100);
break;
case "fetchInterval":
value = limitNumber(value, 0, 5000);
break;
case "httpTimeout":
value = limitNumber(value, 5000, 60000);
break;
case "temperature":
value = limitFloat(value, 0, 2);
break;
case "maxTokens":
value = limitNumber(value, 0, 2 ** 15);
break;
case "batchInterval":
value = limitNumber(value, 100, 10000);
break;
case "batchSize":
value = limitNumber(value, 1, 100);
break;
case "batchLength":
value = limitNumber(value, 1000, 100000);
break;
case "contextSize":
value = limitNumber(value, 1, 20);
break;
default:
}
setFormData((prevData) => ({
...prevData,
[name]: value,
}));
};
const handleSave = () => {
// 过滤掉 api 对象中不存在的字段
// const updatedFields = Object.keys(formData).reduce((acc, key) => {
// if (api && Object.keys(api).includes(key)) {
// acc[key] = formData[key];
// }
// return acc;
// }, {});
// update(updatedFields);
update(formData);
};
const handleReset = () => {
reset();
};
const handleDelete = async () => {
const isConfirmed = await confirm({
confirmText: i18n("delete"),
cancelText: i18n("cancel"),
});
if (isConfirmed) {
deleteApi(apiSlug);
}
};
const {
url = "",
key = "",
model = "",
apiType,
systemPrompt = "",
// userPrompt = "",
customHeader = "",
customBody = "",
think = false,
thinkIgnore = "",
fetchLimit = DEFAULT_FETCH_LIMIT,
fetchInterval = DEFAULT_FETCH_INTERVAL,
httpTimeout = DEFAULT_HTTP_TIMEOUT,
dictNo = "",
memoryNo = "",
reqHook = "",
resHook = "",
temperature = 0,
maxTokens = 256,
apiName = "",
isDisabled = false,
useBatchFetch = false,
batchInterval = DEFAULT_BATCH_INTERVAL,
batchSize = DEFAULT_BATCH_SIZE,
batchLength = DEFAULT_BATCH_LENGTH,
useContext = false,
contextSize = DEFAULT_CONTEXT_SIZE,
tone = "neutral",
placeholder = BUILTIN_PLACEHOLDERS[0],
placetag = BUILTIN_PLACETAGS[0],
// aiTerms = false,
} = formData;
const keyHelper = useMemo(
() => (API_SPE_TYPES.mulkeys.has(apiType) ? i18n("mulkeys_help") : ""),
[apiType, i18n]
);
return (
{!API_SPE_TYPES.machine.has(apiType) &&
apiType !== OPT_TRANS_BUILTINAI && (
<>
>
)}
{API_SPE_TYPES.ai.has(apiType) && (
<>
{/* todo: 改成 ReusableAutocomplete 可选择和填写模型 */}
{/* */}
>
)}
{apiType === OPT_TRANS_OLLAMA && (
<>
>
)}
{apiType === OPT_TRANS_NIUTRANS && (
<>
>
)}
{apiType === OPT_TRANS_CUSTOMIZE && (
<>
{i18n("request_hook_helper")}
}
/>
{i18n("response_hook_helper")}
}
/>
>
)}
{API_SPE_TYPES.batch.has(api.apiType) && (
)}
{API_SPE_TYPES.context.has(api.apiType) && (
<>
{" "}
{" "}
>
)}
{showMore && (
<>
{BUILTIN_PLACEHOLDERS.map((item) => (
))}
{BUILTIN_PLACETAGS.map((item) => (
))}
{apiType !== OPT_TRANS_BUILTINAI && (
<>
{" "}
>
)}
{apiType !== OPT_TRANS_CUSTOMIZE &&
apiType !== OPT_TRANS_BUILTINAI && (
<>
{i18n("request_hook_helper")}
}
/>
{i18n("response_hook_helper")}
}
/>
>
)}
>
)}
{isUserApi && (
)}
}
label={i18n("is_disabled")}
/>
{/* {apiType === OPT_TRANS_CUSTOMIZE && {i18n("custom_api_help")}} */}
);
}
function ApiAccordion({ api, isUserApi, deleteApi }) {
const [expanded, setExpanded] = useState(false);
const handleChange = (e) => {
setExpanded((pre) => !pre);
};
return (
}>
{`[${api.apiType}] ${api.apiName}`}
{expanded && (
)}
);
}
export default function Apis() {
const i18n = useI18n();
const { userApis, builtinApis, addApi, deleteApi } = useApiList();
const apiTypes = useMemo(
() =>
OPT_ALL_TYPES.map((type) => ({
type,
label: type,
})),
[]
);
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const handleMenuItemClick = (apiType) => {
addApi(apiType);
handleClose();
};
return (
{i18n("about_api")}
{i18n("about_api_2")}
}
startIcon={}
>
{i18n("add")}
{userApis.map((api) => (
))}
{builtinApis.map((api) => (
))}
);
}