diff --git a/src-ui/logics/configs/config_page_setter/ui_config_setter.js b/src-ui/logics/configs/config_page_setter/ui_config_setter.js index 5b228cb4..f3790a6c 100644 --- a/src-ui/logics/configs/config_page_setter/ui_config_setter.js +++ b/src-ui/logics/configs/config_page_setter/ui_config_setter.js @@ -221,14 +221,155 @@ export const SETTINGS_ARRAY = [ logics_template_id: "get_set", base_endpoint_name: "selected_translation_compute_device", }, + // DeepL { Category: "Translation", Base_Name: "DeepLAuthKey", default_value: "", ui_template_id: "input", - logics_template_id: "get_set", + logics_template_id: "get_set_delete", base_endpoint_name: "deepl_auth_key", }, + // Plamo + { + Category: "Translation", + Base_Name: "PlamoAuthKey", + default_value: "", + ui_template_id: "input", + logics_template_id: "get_set_delete", + base_endpoint_name: "plamo_auth_key", + }, + { + Category: "Translation", + Base_Name: "SelectablePlamoModelList", + default_value: [], + ui_template_id: "list", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selectable_plamo_model_list", + response_transform: "arrayToObject", + }, + { + Category: "Translation", + Base_Name: "SelectedPlamoModel", + default_value: "", + ui_template_id: "select", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selected_plamo_model", + }, + // Gemini + { + Category: "Translation", + Base_Name: "GeminiAuthKey", + default_value: "", + ui_template_id: "input", + logics_template_id: "get_set_delete", + base_endpoint_name: "gemini_auth_key", + }, + { + Category: "Translation", + Base_Name: "SelectableGeminiModelList", + default_value: [], + ui_template_id: "list", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selectable_gemini_model_list", + response_transform: "arrayToObject", + }, + { + Category: "Translation", + Base_Name: "SelectedGeminiModel", + default_value: "", + ui_template_id: "select", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selected_gemini_model", + }, + // OpenAI + { + Category: "Translation", + Base_Name: "OpenAIAuthKey", + default_value: "", + ui_template_id: "input", + logics_template_id: "get_set_delete", + base_endpoint_name: "openai_auth_key", + }, + { + Category: "Translation", + Base_Name: "SelectableOpenAIModelList", + default_value: [], + ui_template_id: "list", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selectable_openai_model_list", + response_transform: "arrayToObject", + }, + { + Category: "Translation", + Base_Name: "SelectedOpenAIModel", + default_value: "", + ui_template_id: "select", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selected_openai_model", + }, + // LM Studio + { + Category: "Translation", + Base_Name: "LMStudioURL", + default_value: "", + ui_template_id: "input", + logics_template_id: "get_set", + base_endpoint_name: "lmstudio_url", + }, + { + Category: "Translation", + Base_Name: "SelectableLMStudioModelList", + default_value: [], + ui_template_id: "list", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selectable_lmstudio_model_list", + response_transform: "arrayToObject", + }, + { + Category: "Translation", + Base_Name: "SelectedLMStudioModel", + default_value: "", + ui_template_id: "select", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selected_lmstudio_model", + }, + // Ollama + { + Category: "Translation", + Base_Name: "OllamaURL", + default_value: "", + ui_template_id: "input", + logics_template_id: "get_set", + base_endpoint_name: "ollama_url", + }, + { + Category: "Translation", + Base_Name: "SelectableOllamaModelList", + default_value: [], + ui_template_id: "list", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selectable_ollama_model_list", + response_transform: "arrayToObject", + }, + { + Category: "Translation", + Base_Name: "SelectedOllamaModel", + default_value: "", + ui_template_id: "select", + logics_template_id: "get_set", + add_endpoint_run_array: ["from_backend"], + base_endpoint_name: "selected_ollama_model", + }, // Transcription // Mic @@ -558,24 +699,19 @@ for (const setting_data of SETTINGS_ARRAY) { const buildCategoryApiFromSettings = (settings, settingsArray, Category, extraFunctions = {}) => { const api = {}; const filtered = settingsArray.filter((s) => s.Category === Category); + const COMMON_PROPS = [ "current", "update", "get", "set", "toggle", "setSuccess", "delete", "deleteSuccess", "updateFromBackend" ]; for (const s of filtered) { const base = s.Base_Name; - const currentKey = `current${base}`; - const updateKey = `update${base}`; - const getKey = `get${base}`; - const setKey = `set${base}`; - const toggleKey = `toggle${base}`; - const setSuccessKey = `setSuccess${base}`; - const updateFromBackendKey = `updateFromBackend${base}`; - if (settings[currentKey] !== undefined) api[currentKey] = settings[currentKey]; - if (settings[updateKey] !== undefined) api[updateKey] = settings[updateKey]; - if (typeof settings[getKey] === "function") api[getKey] = settings[getKey]; - if (typeof settings[setKey] === "function") api[setKey] = settings[setKey]; - if (typeof settings[toggleKey] === "function") api[toggleKey] = settings[toggleKey]; - if (typeof settings[setSuccessKey] === "function") api[setSuccessKey] = settings[setSuccessKey]; - if (typeof settings[updateFromBackendKey] === "function") api[updateFromBackendKey] = settings[updateFromBackendKey]; + COMMON_PROPS.forEach(prop => { + const key = `${prop}${base}`; + const settingValue = settings[key]; + + if (settingValue !== undefined) { + api[key] = settingValue; + } + }); if (s.logics_template_id === "weight_download_status") { const updateDownloadProgressKey = `updateDownloadProgress${base}`; @@ -589,6 +725,8 @@ const buildCategoryApiFromSettings = (settings, settingsArray, Category, extraFu if (typeof settings[pendingKey] === "function") api[pendingKey] = settings[pendingKey]; if (typeof settings[downloadedKey] === "function") api[downloadedKey] = settings[downloadedKey]; if (typeof settings[downloadKey] === "function") api[downloadKey] = settings[downloadKey]; + + const updateFromBackendKey = `updateFromBackend${base}`; if (typeof settings[updateFromBackendKey] === "function") api[updateFromBackendKey] = settings[updateFromBackendKey]; } } diff --git a/src-ui/logics/configs/config_page_setter/useSettingsLogics.js b/src-ui/logics/configs/config_page_setter/useSettingsLogics.js index a00d816b..35fe4152 100644 --- a/src-ui/logics/configs/config_page_setter/useSettingsLogics.js +++ b/src-ui/logics/configs/config_page_setter/useSettingsLogics.js @@ -1,7 +1,7 @@ import * as stores from "@store"; import { useStdoutToPython } from "@useStdoutToPython"; import { useNotificationStatus } from "@logics_common"; -import { arrayToObject } from "@utils"; +import { arrayToObject, arrayToIdLabel } from "@utils"; const transformResponse = (transformName, payload) => { if (!transformName) return payload; @@ -9,6 +9,8 @@ const transformResponse = (transformName, payload) => { switch (transformName) { case "arrayToObject": return arrayToObject(payload); + case "arrayToIdLabel": + return arrayToIdLabel(payload); default: return payload; } @@ -55,8 +57,10 @@ export const useSettingsLogics = (settingsArray, Category) => { const updateFromBackendExportName = `updateFromBackend${base}`; const getExportName = `get${base}`; const setExportName = `set${base}`; + const deleteExportName = `delete${base}`; const toggleExportName = `toggle${base}`; const setSuccessExportName = `setSuccess${base}`; + const deleteSuccessExportName = `deleteSuccess${base}`; const runExportName = `runSuccess${base}`; @@ -75,6 +79,13 @@ export const useSettingsLogics = (settingsArray, Category) => { }; }; + const buildDelete = () => { + return (value) => { + if (pending) pending(); + asyncStdoutToPython(`/delete/data/${s.base_endpoint_name}`, value); + }; + }; + const buildRun = () => { return () => { asyncStdoutToPython(`/run/${s.base_endpoint_name}`); @@ -91,6 +102,14 @@ export const useSettingsLogics = (settingsArray, Category) => { }; }; + const buildDeleteSuccess = (transformName) => { + return (payload) => { + const transformed = transformResponse(transformName, payload); + if (update) update(transformed); + showNotification_SaveSuccess(); + }; + }; + const buildUpdateFromBackend = (transformName) => { return (payload) => { const transformed = transformResponse(transformName, payload); @@ -120,6 +139,15 @@ export const useSettingsLogics = (settingsArray, Category) => { continue; } + if (s.logics_template_id === "get_set_delete") { + result[getExportName] = buildGet(); + result[setExportName] = buildSet(); + result[setSuccessExportName] = buildSetSuccess(s.response_transform ?? null); + result[deleteExportName] = buildDelete(); + result[deleteSuccessExportName] = buildDeleteSuccess(s.response_transform ?? null); + continue; + } + if (s.logics_template_id === "toggle_enable_disable") { result[getExportName] = buildGet(); result[toggleExportName] = () => { @@ -281,6 +309,39 @@ export const useSliderLogic = ({ }; }; + +export const useSaveButtonLogic = ({ + variable, + state, + setFunction, + deleteFunction +}) => { + const [input_value, setInputValue] = useState(variable); + + const onChangeFunction = (value) => { + setInputValue(value); + }; + + const saveFunction = () => { + if (input_value === "" || input_value === null) { + return deleteFunction(); + } + setFunction(input_value); + }; + + useEffect(() => { + if (state === "pending") return; + setInputValue(variable); + + }, [variable]); + + return { + variable: input_value, + onChangeFunction: onChangeFunction, + saveFunction: saveFunction, + }; +}; + const createMarks = (min, max, marks_step = 1, labelFormatter = (value) => value) => { const marks = []; let variable = min; diff --git a/src-ui/logics/configs/index.js b/src-ui/logics/configs/index.js index 1b20c3c6..42676fdd 100644 --- a/src-ui/logics/configs/index.js +++ b/src-ui/logics/configs/index.js @@ -18,4 +18,5 @@ export { useSettingBoxScrollPosition } from "./config_page_setter/_aux/useSettin export { useSliderLogic, + useSaveButtonLogic, } from "./config_page_setter/useSettingsLogics.js"; \ No newline at end of file diff --git a/src-ui/logics/ui_configs.js b/src-ui/logics/ui_configs.js index dc941165..191693c8 100644 --- a/src-ui/logics/ui_configs.js +++ b/src-ui/logics/ui_configs.js @@ -128,5 +128,9 @@ export const whisper_weight_type_status = [ { id: "large-v3-turbo", capacity: "1.58GB"}, ].map(item => ({ ...item, is_downloaded: false, progress: null })); + +export const deepl_auth_key_url = "https://www.deepl.com/ja/your-account/keys"; + + export const supporters_data_url = "https://shiinasakamoto.github.io/vrct_supporters/assets/supporters/data.json"; export const supporters_images_url = "https://ShiinaSakamoto.github.io/vrct_supporters/assets/supporters"; \ No newline at end of file diff --git a/src-ui/logics/useReceiveRoutes.js b/src-ui/logics/useReceiveRoutes.js index 5a6e6384..e9936936 100644 --- a/src-ui/logics/useReceiveRoutes.js +++ b/src-ui/logics/useReceiveRoutes.js @@ -210,6 +210,7 @@ const buildRouteMetaList = () => { const ep = s.base_endpoint_name; const hookName = `use${category}`; const setSuccessMethodName = `setSuccess${base}`; + const deleteSuccessMethodName = `deleteSuccess${base}`; const updateFromBackendMethodName = `updateFromBackend${base}`; @@ -231,6 +232,15 @@ const buildRouteMetaList = () => { method_name: updateFromBackendMethodName, }); + if (s.logics_template_id === "get_set_delete") { + generated.push({ + endpoint: `/delete/data/${ep}`, + ns: namespace_module, + hook_name: hookName, + method_name: deleteSuccessMethodName, + }); + } + if (s.logics_template_id !== "get_list") { generated.push({ endpoint: `/set/data/${ep}`, diff --git a/src-ui/logics/utils.js b/src-ui/logics/utils.js index 2f5f8bdc..bf7d3f19 100644 --- a/src-ui/logics/utils.js +++ b/src-ui/logics/utils.js @@ -5,6 +5,13 @@ export const arrayToObject = (array) => { }, {}); }; +export const arrayToIdLabel = (array) => { + return array.map((element) => ({ + id: element, + label: element, + })); +}; + export const chunkArray = (array, size) => { const chunked = []; for (let i = 0; i < array.length; i += size) { diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.jsx b/src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.jsx new file mode 100644 index 00000000..7df7b16f --- /dev/null +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.jsx @@ -0,0 +1,13 @@ +import styles from "./_OpenWebpageButton.module.scss"; +import ExternalLink from "@images/external_link.svg?react"; + +export const _OpenWebpageButton = (props) => { + return ( +
+ +

{props.open_webpage_label}

+ +
+
+ ); +}; \ No newline at end of file diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.module.scss b/src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.module.scss new file mode 100644 index 00000000..fd300952 --- /dev/null +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/_atoms/_open_webpage_button/_OpenWebpageButton.module.scss @@ -0,0 +1,32 @@ +.open_webpage_button_wrapper { + display: flex; + justify-content: center; + align-items: center; +} + +.open_webpage_button { + padding: 0.6rem 2.8rem; + display: flex; + gap: 1rem; + justify-content: center; + align-items: center; + border-radius: 0.4rem; + cursor: pointer; + flex-shrink: 0; + &:hover { + background-color: var(--dark_825_color); + } + &:active { + background-color: var(--dark_900_color); + } +} + +.open_webpage_text { + font-size: 1.2rem; +} + +.external_link_svg { + color: var(--dark_500_color); + width: 1.6rem; + flex-shrink: 0; +} \ No newline at end of file diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx b/src-ui/views/app/config_page/setting_section/setting_box/_components/auth_key/AuthKey.jsx similarity index 72% rename from src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx rename to src-ui/views/app/config_page/setting_section/setting_box/_components/auth_key/AuthKey.jsx index effdd2c9..85ae9928 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/auth_key/AuthKey.jsx @@ -1,13 +1,12 @@ -import styles from "./DeeplAuthKey.module.scss"; +import styles from "./AuthKey.module.scss"; import { useI18n } from "@useI18n"; import clsx from "clsx"; import CircularProgress from "@mui/material/CircularProgress"; -import ExternalLink from "@images/external_link.svg?react"; import { _Entry } from "../_atoms/_entry/_Entry"; import { useState, useRef } from "react"; import { useEffect } from "react"; -export const DeeplAuthKey = (props) => { +export const AuthKey = (props) => { const { t } = useI18n(); const [is_editable, seIsEditable] = useState(false); const entryRef = useRef(null); @@ -56,17 +55,4 @@ export const DeeplAuthKey = (props) => { ); -}; - - -export const OpenWebpage_DeeplAuthKey = () => { - const { t } = useI18n(); - return ( -
- -

{t("config_page.translation.deepl_auth_key.open_auth_key_webpage")}

- -
-
- ); }; \ No newline at end of file diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.module.scss b/src-ui/views/app/config_page/setting_section/setting_box/_components/auth_key/AuthKey.module.scss similarity index 65% rename from src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.module.scss rename to src-ui/views/app/config_page/setting_section/setting_box/_components/auth_key/AuthKey.module.scss index 1f5a530e..ce58182c 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_components/deepl_auth_key/DeeplAuthKey.module.scss +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/auth_key/AuthKey.module.scss @@ -62,37 +62,4 @@ .save_button_label { font-size: 1.4rem; -} - -.open_webpage_button_wrapper { - display: flex; - justify-content: center; - align-items: center; -} - -.open_webpage_button { - padding: 0.6rem 2.8rem; - display: flex; - gap: 1rem; - justify-content: center; - align-items: center; - border-radius: 0.4rem; - cursor: pointer; - flex-shrink: 0; - &:hover { - background-color: var(--dark_825_color); - } - &:active { - background-color: var(--dark_900_color); - } -} - -.open_webpage_text { - font-size: 1.2rem; -} - -.external_link_svg { - color: var(--dark_500_color); - width: 1.6rem; - flex-shrink: 0; } \ No newline at end of file diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/index.js b/src-ui/views/app/config_page/setting_section/setting_box/_components/index.js index db5ad1cb..2e7b54ca 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_components/index.js +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/index.js @@ -1,6 +1,6 @@ export { ActionButton } from "./action_button/ActionButton"; export { ComputeDevice } from "./compute_device/ComputeDevice"; -export { DeeplAuthKey, OpenWebpage_DeeplAuthKey } from "./deepl_auth_key/DeeplAuthKey"; +export { AuthKey } from "./auth_key/AuthKey"; export { DropdownMenu, MultiDropdownMenu } from "./dropdown_menu/DropdownMenu"; export { Entry } from "./entry/Entry"; export { EntryWithSaveButton } from "./entry_with_save_button/EntryWithSaveButton"; diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_components/label_component/LabelComponent.jsx b/src-ui/views/app/config_page/setting_section/setting_box/_components/label_component/LabelComponent.jsx index a4a520db..ffcb9a89 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_components/label_component/LabelComponent.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/_components/label_component/LabelComponent.jsx @@ -1,4 +1,5 @@ import styles from "./LabelComponent.module.scss"; +import { _OpenWebpageButton } from "../_atoms/_open_webpage_button/_OpenWebpageButton"; export const LabelComponent = (props) => { return ( @@ -8,6 +9,7 @@ export const LabelComponent = (props) => { ?

{props.desc}

: null } + {props.webpage_url && <_OpenWebpageButton webpage_url={props.webpage_url} open_webpage_label={props.open_webpage_label} /> } ); }; \ No newline at end of file diff --git a/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx b/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx index 96378587..0c0845e1 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/_templates/Templates.jsx @@ -12,8 +12,7 @@ import { EntryWithSaveButton, HotkeysEntry, RadioButton, - OpenWebpage_DeeplAuthKey, - DeeplAuthKey, + AuthKey, ActionButton, ComputeDevice, WordFilter, @@ -96,7 +95,7 @@ const CommonContainer = ({ if (label_type === "label_component") { return ( - + ); @@ -109,7 +108,7 @@ const CommonContainer = ({ } else if (label_type === "label_only") { return ( - + ); } @@ -143,15 +142,13 @@ export const RadioButtonContainer = (props) => ( ); -export const DeeplAuthKeyContainer = (props) => { +export const AuthKeyContainer = (props) => { + const webpage_settings = { + webpage_url: props.webpage_url, + open_webpage_label: props.open_webpage_label, + }; return ( - -
- - -
- -
+ ); }; diff --git a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx index cb5ad232..7ad243ff 100644 --- a/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx +++ b/src-ui/views/app/config_page/setting_section/setting_box/translation/Translation.jsx @@ -6,12 +6,17 @@ import { useStore_IsBreakPoint } from "@store"; import { useTranslation, + + useSaveButtonLogic, } from "@logics_configs"; import { DownloadModelsContainer, - DeeplAuthKeyContainer, + AuthKeyContainer, MultiDropdownMenuContainer, + EntryWithSaveButtonContainer, + RadioButtonContainer, + DropdownMenuContainer, useOnMouseLeaveDropdownMenu, } from "../_templates/Templates"; @@ -22,12 +27,29 @@ import { LabelComponent, } from "../_components"; +import { deepl_auth_key_url } from "@ui_configs"; + export const Translation = () => { return ( <> - + + + + + + + + + + + + + + + + ); }; @@ -203,34 +225,28 @@ const TranslationComputeDevice_Box = () => { ); }; -const DeeplAuthKey_Box = () => { +const DeepLAuthKey_Box = () => { const { t } = useI18n(); const { currentDeepLAuthKey, setDeepLAuthKey, deleteDeepLAuthKey } = useTranslation(); - const [input_value, seInputValue] = useState(currentDeepLAuthKey.data); - const onChangeFunction = (value) => { - seInputValue(value); - }; - - const saveFunction = () => { - if (input_value === "") return deleteDeepLAuthKey(); - setDeepLAuthKey(input_value); - }; - - useEffect(() => { - if (currentDeepLAuthKey.state === "pending") return; - seInputValue(currentDeepLAuthKey.data); - }, [currentDeepLAuthKey]); + const { variable, onChangeFunction, saveFunction } = useSaveButtonLogic({ + variable: currentDeepLAuthKey.data, + state: currentDeepLAuthKey.state, + setFunction: setDeepLAuthKey, + deleteFunction: deleteDeepLAuthKey, + }); return ( <> - { ); }; +const PlamoAuthKey_Box = () => { + const { t } = useI18n(); + const { currentPlamoAuthKey, setPlamoAuthKey, deletePlamoAuthKey } = useTranslation(); + + const { variable, onChangeFunction, saveFunction } = useSaveButtonLogic({ + variable: currentPlamoAuthKey.data, + state: currentPlamoAuthKey.state, + setFunction: setPlamoAuthKey, + deleteFunction: deletePlamoAuthKey, + }); + + return ( + <> + + + ); +}; +const PlamoModelContainer = () => { + const { t } = useI18n(); + const { + currentSelectablePlamoModelList, + + currentSelectedPlamoModel, + setSelectedPlamoModel, + } = useTranslation(); + + if (currentSelectablePlamoModelList.data.length === 0) return null; + + const selectFunction = (selected_data) => { + setSelectedPlamoModel(selected_data.selected_id); + }; + + return ( + + ); +}; + + + +const GeminiAuthKey_Box = () => { + const { t } = useI18n(); + const { currentGeminiAuthKey, setGeminiAuthKey, deleteGeminiAuthKey } = useTranslation(); + + const { variable, onChangeFunction, saveFunction } = useSaveButtonLogic({ + variable: currentGeminiAuthKey.data, + state: currentGeminiAuthKey.state, + setFunction: setGeminiAuthKey, + deleteFunction: deleteGeminiAuthKey, + }); + + return ( + <> + + + ); +}; +const GeminiModelContainer = () => { + const { t } = useI18n(); + const { + currentSelectableGeminiModelList, + + currentSelectedGeminiModel, + setSelectedGeminiModel, + } = useTranslation(); + + if (currentSelectableGeminiModelList.data.length === 0) return null; + + const selectFunction = (selected_data) => { + setSelectedGeminiModel(selected_data.selected_id); + }; + + return ( + + ); +}; + + +const OpenAIAuthKey_Box = () => { + const { t } = useI18n(); + const { currentOpenAIAuthKey, setOpenAIAuthKey, deleteOpenAIAuthKey } = useTranslation(); + + const { variable, onChangeFunction, saveFunction } = useSaveButtonLogic({ + variable: currentOpenAIAuthKey.data, + state: currentOpenAIAuthKey.state, + setFunction: setOpenAIAuthKey, + deleteFunction: deleteOpenAIAuthKey, + }); + + return ( + <> + + + ); +}; +const OpenAIModelContainer = () => { + const { t } = useI18n(); + const { + currentSelectableOpenAIModelList, + + currentSelectedOpenAIModel, + setSelectedOpenAIModel, + } = useTranslation(); + + if (currentSelectableOpenAIModelList.data.length === 0) return null; + + const selectFunction = (selected_data) => { + setSelectedOpenAIModel(selected_data.selected_id); + }; + + return ( + + ); +}; + + + +const LMStudioURL_Box = () => { + const { t } = useI18n(); + const { currentLMStudioURL, setLMStudioURL, deleteLMStudioURL } = useTranslation(); + + const { variable, onChangeFunction, saveFunction } = useSaveButtonLogic({ + variable: currentLMStudioURL.data, + state: currentLMStudioURL.state, + setFunction: setLMStudioURL, + deleteFunction: deleteLMStudioURL, + }); + + return ( + <> + + + ); +}; +const LMStudioModelContainer = () => { + const { t } = useI18n(); + const { + currentSelectableLMStudioModelList, + + currentSelectedLMStudioModel, + setSelectedLMStudioModel, + } = useTranslation(); + + if (currentSelectableLMStudioModelList.data.length === 0) return null; + + const selectFunction = (selected_data) => { + setSelectedLMStudioModel(selected_data.selected_id); + }; + + return ( + + ); +}; + +const OllamaModelContainer = () => { + const { t } = useI18n(); + const { + currentSelectableOllamaModelList, + + currentSelectedOllamaModel, + setSelectedOllamaModel, + } = useTranslation(); + + if (currentSelectableOllamaModelList.data.length === 0) return null; + + const selectFunction = (selected_data) => { + setSelectedOllamaModel(selected_data.selected_id); + }; + + return ( + + ); +}; + + // Duplicate const transformDeviceArray = (devices) => { const name_counts = Object.values(devices).reduce((counts, device) => {