mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-15 23:10:59 +00:00
feat: add disable_models_service configuration to manage model service availability and update related components
This commit is contained in:
@@ -22,6 +22,9 @@ class SystemRouterGroup(group.RouterGroup):
|
|||||||
'allow_modify_login_info': self.ap.instance_config.data.get('system', {}).get(
|
'allow_modify_login_info': self.ap.instance_config.data.get('system', {}).get(
|
||||||
'allow_modify_login_info', True
|
'allow_modify_login_info', True
|
||||||
),
|
),
|
||||||
|
'disable_models_service': self.ap.instance_config.data.get('space', {}).get(
|
||||||
|
'disable_models_service', False
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,12 @@ class ModelManager:
|
|||||||
|
|
||||||
await self.load_models_from_db()
|
await self.load_models_from_db()
|
||||||
|
|
||||||
|
# Check if space models service is disabled
|
||||||
|
space_config = self.ap.instance_config.data.get('space', {})
|
||||||
|
if space_config.get('disable_models_service', False):
|
||||||
|
self.ap.logger.info('LangBot Space Models service is disabled, skipping sync.')
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await self.sync_new_models_from_space()
|
await self.sync_new_models_from_space()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -78,3 +78,4 @@ space:
|
|||||||
models_gateway_api_url: 'https://api.langbot.cloud'
|
models_gateway_api_url: 'https://api.langbot.cloud'
|
||||||
# OAuth authorization page URL (user will be redirected here)
|
# OAuth authorization page URL (user will be redirected here)
|
||||||
oauth_authorize_url: 'https://space.langbot.app/auth/authorize'
|
oauth_authorize_url: 'https://space.langbot.app/auth/authorize'
|
||||||
|
disable_models_service: false
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { Switch } from '@/components/ui/switch';
|
|||||||
import { ControllerRenderProps } from 'react-hook-form';
|
import { ControllerRenderProps } from 'react-hook-form';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { httpClient } from '@/app/infra/http/HttpClient';
|
import { httpClient, systemInfo } from '@/app/infra/http/HttpClient';
|
||||||
import {
|
import {
|
||||||
LLMModel,
|
LLMModel,
|
||||||
Bot,
|
Bot,
|
||||||
@@ -98,7 +98,14 @@ export default function DynamicFormItemComponent({
|
|||||||
httpClient
|
httpClient
|
||||||
.getProviderLLMModels()
|
.getProviderLLMModels()
|
||||||
.then((resp) => {
|
.then((resp) => {
|
||||||
setLlmModels(resp.models);
|
let models = resp.models;
|
||||||
|
// Filter out space-chat-completions models when models service is disabled
|
||||||
|
if (systemInfo.disable_models_service) {
|
||||||
|
models = models.filter(
|
||||||
|
(m) => m.provider?.requester !== 'space-chat-completions',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setLlmModels(models);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
toast.error('Failed to get LLM model list: ' + err.message);
|
toast.error('Failed to get LLM model list: ' + err.message);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { Plus, Boxes } from 'lucide-react';
|
import { Plus, Boxes } from 'lucide-react';
|
||||||
import { httpClient } from '@/app/infra/http/HttpClient';
|
import { httpClient, systemInfo } from '@/app/infra/http/HttpClient';
|
||||||
import { ModelProvider } from '@/app/infra/entities/api';
|
import { ModelProvider } from '@/app/infra/entities/api';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { extractI18nObject } from '@/i18n/I18nProvider';
|
|
||||||
import ProviderForm from './component/provider-form/ProviderForm';
|
import ProviderForm from './component/provider-form/ProviderForm';
|
||||||
import { ProviderCard } from './components';
|
import { ProviderCard } from './components';
|
||||||
import {
|
import {
|
||||||
@@ -86,17 +85,13 @@ export default function ModelsDialog({
|
|||||||
const [isTesting, setIsTesting] = useState(false);
|
const [isTesting, setIsTesting] = useState(false);
|
||||||
const [testResult, setTestResult] = useState<TestResult | null>(null);
|
const [testResult, setTestResult] = useState<TestResult | null>(null);
|
||||||
|
|
||||||
const [requesterNameList, setRequesterNameList] = useState<
|
|
||||||
{ label: string; value: string }[]
|
|
||||||
>([]);
|
|
||||||
|
|
||||||
// Track if providers have been loaded initially
|
// Track if providers have been loaded initially
|
||||||
const [providersLoaded, setProvidersLoaded] = useState(false);
|
const [providersLoaded, setProvidersLoaded] = useState(false);
|
||||||
|
|
||||||
// Separate LangBot Models provider
|
// Separate LangBot Models provider (hide when models service is disabled)
|
||||||
const langbotProvider = providers.find(
|
const langbotProvider = systemInfo.disable_models_service
|
||||||
(p) => p.requester === LANGBOT_MODELS_PROVIDER_REQUESTER,
|
? undefined
|
||||||
);
|
: providers.find((p) => p.requester === LANGBOT_MODELS_PROVIDER_REQUESTER);
|
||||||
const otherProviders = providers.filter(
|
const otherProviders = providers.filter(
|
||||||
(p) => p.requester !== LANGBOT_MODELS_PROVIDER_REQUESTER,
|
(p) => p.requester !== LANGBOT_MODELS_PROVIDER_REQUESTER,
|
||||||
);
|
);
|
||||||
@@ -104,7 +99,6 @@ export default function ModelsDialog({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
loadUserInfo();
|
loadUserInfo();
|
||||||
loadRequesterLists();
|
|
||||||
loadProviders();
|
loadProviders();
|
||||||
}
|
}
|
||||||
}, [open]);
|
}, [open]);
|
||||||
@@ -134,20 +128,6 @@ export default function ModelsDialog({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadRequesterLists() {
|
|
||||||
try {
|
|
||||||
const llmRequesters = await httpClient.getProviderRequesters('llm');
|
|
||||||
setRequesterNameList(
|
|
||||||
llmRequesters.requesters.map((item) => ({
|
|
||||||
label: extractI18nObject(item.label),
|
|
||||||
value: item.name,
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Failed to load requester lists', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadProviders() {
|
async function loadProviders() {
|
||||||
try {
|
try {
|
||||||
const resp = await httpClient.getModelProviders();
|
const resp = await httpClient.getModelProviders();
|
||||||
@@ -397,7 +377,6 @@ export default function ModelsDialog({
|
|||||||
models={providerModels[provider.uuid]}
|
models={providerModels[provider.uuid]}
|
||||||
accountType={accountType}
|
accountType={accountType}
|
||||||
spaceCredits={spaceCredits}
|
spaceCredits={spaceCredits}
|
||||||
requesterNameList={requesterNameList}
|
|
||||||
addModelPopoverOpen={addModelPopoverOpen}
|
addModelPopoverOpen={addModelPopoverOpen}
|
||||||
editModelPopoverOpen={editModelPopoverOpen}
|
editModelPopoverOpen={editModelPopoverOpen}
|
||||||
deleteConfirmOpen={deleteConfirmOpen}
|
deleteConfirmOpen={deleteConfirmOpen}
|
||||||
@@ -462,7 +441,11 @@ export default function ModelsDialog({
|
|||||||
<div className="flex-shrink-0 mb-3 flex justify-between items-center">
|
<div className="flex-shrink-0 mb-3 flex justify-between items-center">
|
||||||
<span className="text-sm text-muted-foreground">
|
<span className="text-sm text-muted-foreground">
|
||||||
{otherProviders.length === 0
|
{otherProviders.length === 0
|
||||||
? t('models.addProviderHint')
|
? t(
|
||||||
|
systemInfo.disable_models_service
|
||||||
|
? 'models.addProviderHintSimple'
|
||||||
|
: 'models.addProviderHint',
|
||||||
|
)
|
||||||
: t('models.providerCount', { count: otherProviders.length })}
|
: t('models.providerCount', { count: otherProviders.length })}
|
||||||
</span>
|
</span>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
+148
-68
@@ -62,7 +62,13 @@ export default function ProviderForm({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [requesterList, setRequesterList] = useState<
|
const [requesterList, setRequesterList] = useState<
|
||||||
{ label: string; value: string; category: string; defaultUrl: string }[]
|
{
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
category: string;
|
||||||
|
defaultUrl: string;
|
||||||
|
description: string;
|
||||||
|
}[]
|
||||||
>([]);
|
>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -73,17 +79,20 @@ export default function ProviderForm({
|
|||||||
}, [providerId]);
|
}, [providerId]);
|
||||||
|
|
||||||
async function loadRequesters() {
|
async function loadRequesters() {
|
||||||
const resp = await httpClient.getProviderRequesters('llm');
|
const resp = await httpClient.getProviderRequesters();
|
||||||
setRequesterList(
|
setRequesterList(
|
||||||
resp.requesters.map((item) => ({
|
resp.requesters
|
||||||
label: extractI18nObject(item.label),
|
.filter((item) => item.name !== 'space-chat-completions')
|
||||||
value: item.name,
|
.map((item) => ({
|
||||||
category: item.spec.provider_category || 'manufacturer',
|
label: extractI18nObject(item.label),
|
||||||
defaultUrl:
|
value: item.name,
|
||||||
item.spec.config
|
category: item.spec.provider_category || 'manufacturer',
|
||||||
.find((c) => c.name === 'base_url')
|
defaultUrl:
|
||||||
?.default?.toString() || '',
|
item.spec.config
|
||||||
})),
|
.find((c) => c.name === 'base_url')
|
||||||
|
?.default?.toString() || '',
|
||||||
|
description: extractI18nObject(item.description),
|
||||||
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,63 +154,134 @@ export default function ProviderForm({
|
|||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="requester"
|
name="requester"
|
||||||
render={({ field }) => (
|
render={({ field }) => {
|
||||||
<FormItem>
|
const selectedRequester = requesterList.find(
|
||||||
<FormLabel>
|
(r) => r.value === field.value,
|
||||||
{t('models.requester')}
|
);
|
||||||
<span className="text-red-500">*</span>
|
return (
|
||||||
</FormLabel>
|
<FormItem>
|
||||||
<Select
|
<FormLabel>
|
||||||
onValueChange={(v) => {
|
{t('models.requester')}
|
||||||
field.onChange(v);
|
<span className="text-red-500">*</span>
|
||||||
const req = requesterList.find((r) => r.value === v);
|
</FormLabel>
|
||||||
// Auto-fill default URL when creating new provider
|
<Select
|
||||||
// or when base_url is empty in edit mode
|
onValueChange={(v) => {
|
||||||
if (req && (!providerId || !form.getValues('base_url'))) {
|
field.onChange(v);
|
||||||
form.setValue('base_url', req.defaultUrl);
|
const req = requesterList.find((r) => r.value === v);
|
||||||
}
|
// Auto-fill default URL when creating new provider
|
||||||
}}
|
// or when base_url is empty in edit mode
|
||||||
value={field.value}
|
if (req && (!providerId || !form.getValues('base_url'))) {
|
||||||
>
|
form.setValue('base_url', req.defaultUrl);
|
||||||
<SelectTrigger className="bg-background">
|
}
|
||||||
<SelectValue placeholder={t('models.selectRequester')} />
|
}}
|
||||||
</SelectTrigger>
|
value={field.value}
|
||||||
<SelectContent>
|
>
|
||||||
<SelectGroup>
|
<SelectTrigger className="bg-background">
|
||||||
<SelectLabel>{t('models.modelManufacturer')}</SelectLabel>
|
{selectedRequester ? (
|
||||||
{requesterList
|
<div className="flex items-center gap-2">
|
||||||
.filter((r) => r.category === 'manufacturer')
|
<img
|
||||||
.map((r) => (
|
src={httpClient.getProviderRequesterIconURL(
|
||||||
<SelectItem key={r.value} value={r.value}>
|
selectedRequester.value,
|
||||||
{r.label}
|
)}
|
||||||
</SelectItem>
|
alt={selectedRequester.label}
|
||||||
))}
|
className="h-5 w-5 rounded"
|
||||||
</SelectGroup>
|
/>
|
||||||
<SelectGroup>
|
<span>{selectedRequester.label}</span>
|
||||||
<SelectLabel>{t('models.aggregationPlatform')}</SelectLabel>
|
</div>
|
||||||
{requesterList
|
) : (
|
||||||
.filter((r) => r.category === 'maas')
|
<SelectValue placeholder={t('models.selectRequester')} />
|
||||||
.map((r) => (
|
)}
|
||||||
<SelectItem key={r.value} value={r.value}>
|
</SelectTrigger>
|
||||||
{r.label}
|
<SelectContent>
|
||||||
</SelectItem>
|
<SelectGroup>
|
||||||
))}
|
<SelectLabel>{t('models.builtin')}</SelectLabel>
|
||||||
</SelectGroup>
|
{requesterList
|
||||||
<SelectGroup>
|
.filter((r) => r.category === 'builtin')
|
||||||
<SelectLabel>{t('models.selfDeployed')}</SelectLabel>
|
.map((r) => (
|
||||||
{requesterList
|
<SelectItem key={r.value} value={r.value}>
|
||||||
.filter((r) => r.category === 'self-hosted')
|
<div className="flex items-center gap-2">
|
||||||
.map((r) => (
|
<img
|
||||||
<SelectItem key={r.value} value={r.value}>
|
src={httpClient.getProviderRequesterIconURL(
|
||||||
{r.label}
|
r.value,
|
||||||
</SelectItem>
|
)}
|
||||||
))}
|
alt={r.label}
|
||||||
</SelectGroup>
|
className="h-5 w-5 rounded"
|
||||||
</SelectContent>
|
/>
|
||||||
</Select>
|
<span>{r.label}</span>
|
||||||
<FormMessage />
|
</div>
|
||||||
</FormItem>
|
</SelectItem>
|
||||||
)}
|
))}
|
||||||
|
</SelectGroup>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectLabel>{t('models.modelManufacturer')}</SelectLabel>
|
||||||
|
{requesterList
|
||||||
|
.filter((r) => r.category === 'manufacturer')
|
||||||
|
.map((r) => (
|
||||||
|
<SelectItem key={r.value} value={r.value}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<img
|
||||||
|
src={httpClient.getProviderRequesterIconURL(
|
||||||
|
r.value,
|
||||||
|
)}
|
||||||
|
alt={r.label}
|
||||||
|
className="h-5 w-5 rounded"
|
||||||
|
/>
|
||||||
|
<span>{r.label}</span>
|
||||||
|
</div>
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectGroup>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectLabel>
|
||||||
|
{t('models.aggregationPlatform')}
|
||||||
|
</SelectLabel>
|
||||||
|
{requesterList
|
||||||
|
.filter((r) => r.category === 'maas')
|
||||||
|
.map((r) => (
|
||||||
|
<SelectItem key={r.value} value={r.value}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<img
|
||||||
|
src={httpClient.getProviderRequesterIconURL(
|
||||||
|
r.value,
|
||||||
|
)}
|
||||||
|
alt={r.label}
|
||||||
|
className="h-5 w-5 rounded"
|
||||||
|
/>
|
||||||
|
<span>{r.label}</span>
|
||||||
|
</div>
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectGroup>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectLabel>{t('models.selfDeployed')}</SelectLabel>
|
||||||
|
{requesterList
|
||||||
|
.filter((r) => r.category === 'self-hosted')
|
||||||
|
.map((r) => (
|
||||||
|
<SelectItem key={r.value} value={r.value}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<img
|
||||||
|
src={httpClient.getProviderRequesterIconURL(
|
||||||
|
r.value,
|
||||||
|
)}
|
||||||
|
alt={r.label}
|
||||||
|
className="h-5 w-5 rounded"
|
||||||
|
/>
|
||||||
|
<span>{r.label}</span>
|
||||||
|
</div>
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<FormMessage />
|
||||||
|
{selectedRequester?.description && (
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
{selectedRequester.description}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</FormItem>
|
||||||
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ interface ProviderCardProps {
|
|||||||
models?: ProviderModels;
|
models?: ProviderModels;
|
||||||
accountType: 'local' | 'space';
|
accountType: 'local' | 'space';
|
||||||
spaceCredits: number | null;
|
spaceCredits: number | null;
|
||||||
requesterNameList: { label: string; value: string }[];
|
|
||||||
// Popover states
|
// Popover states
|
||||||
addModelPopoverOpen: string | null;
|
addModelPopoverOpen: string | null;
|
||||||
editModelPopoverOpen: string | null;
|
editModelPopoverOpen: string | null;
|
||||||
@@ -94,7 +93,6 @@ export default function ProviderCard({
|
|||||||
models,
|
models,
|
||||||
accountType,
|
accountType,
|
||||||
spaceCredits,
|
spaceCredits,
|
||||||
requesterNameList,
|
|
||||||
addModelPopoverOpen,
|
addModelPopoverOpen,
|
||||||
editModelPopoverOpen,
|
editModelPopoverOpen,
|
||||||
deleteConfirmOpen,
|
deleteConfirmOpen,
|
||||||
@@ -128,12 +126,6 @@ export default function ProviderCard({
|
|||||||
const totalModels =
|
const totalModels =
|
||||||
(provider.llm_count || 0) + (provider.embedding_count || 0);
|
(provider.llm_count || 0) + (provider.embedding_count || 0);
|
||||||
|
|
||||||
const getRequesterLabel = (requester: string) => {
|
|
||||||
return (
|
|
||||||
requesterNameList.find((r) => r.value === requester)?.label || requester
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="mb-2">
|
<Card className="mb-2">
|
||||||
<Collapsible open={isExpanded} onOpenChange={onToggle}>
|
<Collapsible open={isExpanded} onOpenChange={onToggle}>
|
||||||
@@ -159,11 +151,7 @@ export default function ProviderCard({
|
|||||||
)}
|
)}
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<CardTitle className="text-base">
|
<CardTitle className="text-base">{provider.name}</CardTitle>
|
||||||
{isLangBotModels
|
|
||||||
? provider.name
|
|
||||||
: getRequesterLabel(provider.requester)}
|
|
||||||
</CardTitle>
|
|
||||||
<Badge variant="outline" className="text-xs">
|
<Badge variant="outline" className="text-xs">
|
||||||
{t('models.modelsCount', { count: totalModels })}
|
{t('models.modelsCount', { count: totalModels })}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
FormMessage,
|
FormMessage,
|
||||||
FormDescription,
|
FormDescription,
|
||||||
} from '@/components/ui/form';
|
} from '@/components/ui/form';
|
||||||
import { httpClient } from '@/app/infra/http/HttpClient';
|
import { httpClient, systemInfo } from '@/app/infra/http/HttpClient';
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
@@ -95,7 +95,14 @@ export default function KBForm({
|
|||||||
|
|
||||||
const getEmbeddingModelNameList = async () => {
|
const getEmbeddingModelNameList = async () => {
|
||||||
const resp = await httpClient.getProviderEmbeddingModels();
|
const resp = await httpClient.getProviderEmbeddingModels();
|
||||||
setEmbeddingModels(resp.models);
|
let models = resp.models;
|
||||||
|
// Filter out space-chat-completions models when models service is disabled
|
||||||
|
if (systemInfo.disable_models_service) {
|
||||||
|
models = models.filter(
|
||||||
|
(m) => m.provider?.requester !== 'space-chat-completions',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setEmbeddingModels(models);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = (data: z.infer<typeof formSchema>) => {
|
const onSubmit = (data: z.infer<typeof formSchema>) => {
|
||||||
|
|||||||
@@ -242,6 +242,7 @@ export interface ApiRespSystemInfo {
|
|||||||
cloud_service_url: string;
|
cloud_service_url: string;
|
||||||
enable_marketplace: boolean;
|
enable_marketplace: boolean;
|
||||||
allow_modify_login_info: boolean;
|
allow_modify_login_info: boolean;
|
||||||
|
disable_models_service: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiRespPluginSystemStatus {
|
export interface ApiRespPluginSystemStatus {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export class BackendClient extends BaseHttpClient {
|
|||||||
|
|
||||||
// ============ Provider API ============
|
// ============ Provider API ============
|
||||||
public getProviderRequesters(
|
public getProviderRequesters(
|
||||||
model_type: string,
|
model_type?: string,
|
||||||
): Promise<ApiRespProviderRequesters> {
|
): Promise<ApiRespProviderRequesters> {
|
||||||
return this.get('/api/v1/provider/requesters', { type: model_type });
|
return this.get('/api/v1/provider/requesters', { type: model_type });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export let systemInfo: ApiRespSystemInfo = {
|
|||||||
enable_marketplace: true,
|
enable_marketplace: true,
|
||||||
cloud_service_url: '',
|
cloud_service_url: '',
|
||||||
allow_modify_login_info: true,
|
allow_modify_login_info: true,
|
||||||
|
disable_models_service: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ const enUS = {
|
|||||||
editProvider: 'Edit Provider',
|
editProvider: 'Edit Provider',
|
||||||
addProvider: 'Add Provider',
|
addProvider: 'Add Provider',
|
||||||
addProviderHint: 'Add providers to use models from other sources',
|
addProviderHint: 'Add providers to use models from other sources',
|
||||||
|
addProviderHintSimple: 'Add providers to use models',
|
||||||
noProviders: 'No providers yet',
|
noProviders: 'No providers yet',
|
||||||
providerName: 'Provider Name',
|
providerName: 'Provider Name',
|
||||||
providerNameRequired: 'Provider name is required',
|
providerNameRequired: 'Provider name is required',
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ const jaJP = {
|
|||||||
addProvider: 'プロバイダーを追加',
|
addProvider: 'プロバイダーを追加',
|
||||||
addProviderHint:
|
addProviderHint:
|
||||||
'他のソースのモデルを使用するにはプロバイダーを追加してください',
|
'他のソースのモデルを使用するにはプロバイダーを追加してください',
|
||||||
|
addProviderHintSimple: 'モデルを使用するにはプロバイダーを追加してください',
|
||||||
noProviders: 'プロバイダーがありません',
|
noProviders: 'プロバイダーがありません',
|
||||||
providerName: 'プロバイダー名',
|
providerName: 'プロバイダー名',
|
||||||
providerNameRequired: 'プロバイダー名は必須です',
|
providerNameRequired: 'プロバイダー名は必須です',
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ const zhHans = {
|
|||||||
editProvider: '编辑供应商',
|
editProvider: '编辑供应商',
|
||||||
addProvider: '添加供应商',
|
addProvider: '添加供应商',
|
||||||
addProviderHint: '添加自定义供应商以使用其他来源的模型',
|
addProviderHint: '添加自定义供应商以使用其他来源的模型',
|
||||||
|
addProviderHintSimple: '添加自定义供应商以使用模型',
|
||||||
noProviders: '暂无自定义供应商',
|
noProviders: '暂无自定义供应商',
|
||||||
providerName: '供应商名称',
|
providerName: '供应商名称',
|
||||||
providerNameRequired: '供应商名称不能为空',
|
providerNameRequired: '供应商名称不能为空',
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ const zhHant = {
|
|||||||
editProvider: '編輯供應商',
|
editProvider: '編輯供應商',
|
||||||
addProvider: '新增供應商',
|
addProvider: '新增供應商',
|
||||||
addProviderHint: '新增供應商以使用其他來源的模型',
|
addProviderHint: '新增供應商以使用其他來源的模型',
|
||||||
|
addProviderHintSimple: '新增供應商以使用模型',
|
||||||
noProviders: '暫無供應商',
|
noProviders: '暫無供應商',
|
||||||
providerName: '供應商名稱',
|
providerName: '供應商名稱',
|
||||||
providerNameRequired: '供應商名稱不能為空',
|
providerNameRequired: '供應商名稱不能為空',
|
||||||
|
|||||||
Reference in New Issue
Block a user