mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-26 13:19:34 +07:00
🔧 chore: sync cloud changes (#10307)
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -103,8 +103,8 @@ vertex-ai-key.json
|
||||
.local/
|
||||
.claude/
|
||||
.mcp.json
|
||||
|
||||
CLAUDE.local.md
|
||||
.agent/
|
||||
|
||||
# MCP tools
|
||||
.serena/**
|
||||
|
||||
@@ -283,6 +283,7 @@
|
||||
"business": "Business Cooperation",
|
||||
"support": "Email Support"
|
||||
},
|
||||
"new": "NEW",
|
||||
"oauth": "SSO Login",
|
||||
"officialSite": "Official Website",
|
||||
"ok": "OK",
|
||||
|
||||
@@ -283,6 +283,7 @@
|
||||
"business": "商务合作",
|
||||
"support": "邮件支持"
|
||||
},
|
||||
"new": "新",
|
||||
"oauth": "SSO 登录",
|
||||
"officialSite": "官方网站",
|
||||
"ok": "确定",
|
||||
|
||||
@@ -423,6 +423,7 @@ export interface EnabledAiModel {
|
||||
id: string;
|
||||
parameters?: ModelParamsSchema;
|
||||
providerId: string;
|
||||
releasedAt?: string;
|
||||
settings?: AiModelSettings;
|
||||
sort?: number;
|
||||
type: AiModelType;
|
||||
|
||||
@@ -39,3 +39,7 @@ export const lastMonth = () => monthsAgo(1).endOf('month');
|
||||
export function getYYYYmmddHHMMss(date: Date) {
|
||||
return dayjs(date).format('YYYYMMDD_HHmmss');
|
||||
}
|
||||
|
||||
export const isNewReleaseDate = (date: string, days = 14) => {
|
||||
return dayjs().diff(dayjs(date), 'day') < days;
|
||||
};
|
||||
|
||||
@@ -21,12 +21,11 @@ import { createErrorResponse } from '@/utils/errorResponse';
|
||||
import { checkAuthMethod } from './utils';
|
||||
|
||||
type CreateRuntime = (jwtPayload: ClientSecretPayload) => ModelRuntime;
|
||||
type RequestOptions = { createRuntime?: CreateRuntime; params: Promise<{ provider: string }> };
|
||||
type RequestOptions = { createRuntime?: CreateRuntime; params: Promise<{ provider?: string }> };
|
||||
|
||||
export type RequestHandler = (
|
||||
req: Request,
|
||||
options: RequestOptions & {
|
||||
createRuntime?: CreateRuntime;
|
||||
jwtPayload: ClientSecretPayload;
|
||||
},
|
||||
) => Promise<Response>;
|
||||
|
||||
@@ -14,7 +14,7 @@ import { getTracePayload } from '@/utils/trace';
|
||||
export const maxDuration = 300;
|
||||
|
||||
export const POST = checkAuth(async (req: Request, { params, jwtPayload, createRuntime }) => {
|
||||
const { provider } = await params;
|
||||
const provider = (await params)!.provider!;
|
||||
|
||||
try {
|
||||
// ============ 1. init chat model ============ //
|
||||
|
||||
@@ -6,7 +6,7 @@ import { initModelRuntimeWithUserPayload } from '@/server/modules/ModelRuntime';
|
||||
import { createErrorResponse } from '@/utils/errorResponse';
|
||||
|
||||
export const POST = checkAuth(async (req, { params, jwtPayload }) => {
|
||||
const { provider } = await params;
|
||||
const provider = (await params)!.provider!;
|
||||
|
||||
try {
|
||||
const agentRuntime = await initModelRuntimeWithUserPayload(provider, jwtPayload);
|
||||
|
||||
@@ -10,7 +10,7 @@ import { createErrorResponse } from '@/utils/errorResponse';
|
||||
const noNeedAPIKey = (provider: string) => [ModelProvider.OpenRouter].includes(provider as any);
|
||||
|
||||
export const GET = checkAuth(async (req, { params, jwtPayload }) => {
|
||||
const { provider } = await params;
|
||||
const provider = (await params)!.provider!;
|
||||
|
||||
try {
|
||||
const hasDefaultApiKey = jwtPayload.apiKey || 'dont-need-api-key-for-model-list';
|
||||
|
||||
@@ -45,7 +45,7 @@ export const preferredRegion = [
|
||||
// );
|
||||
|
||||
export const POST = checkAuth(async (req: Request, { params, jwtPayload }) => {
|
||||
const { provider } = await params;
|
||||
const provider = (await params)!.provider!;
|
||||
|
||||
try {
|
||||
// ============ 1. init chat model ============ //
|
||||
|
||||
@@ -4,7 +4,7 @@ import { App, Switch } from 'antd';
|
||||
import { createStyles, useTheme } from 'antd-style';
|
||||
import { LucidePencil, TrashIcon } from 'lucide-react';
|
||||
import { AiModelSourceEnum, AiProviderModelListItem } from 'model-bank';
|
||||
import { memo, use, useState } from 'react';
|
||||
import React, { memo, use, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
getTextInputUnitRate,
|
||||
getTextOutputUnitRate,
|
||||
} from '@/utils/pricing';
|
||||
import { isNewReleaseDate } from '@/utils/time';
|
||||
|
||||
import ModelConfigModal from './ModelConfigModal';
|
||||
import { ProviderSettingsContext } from './ProviderSettingsContext';
|
||||
@@ -162,6 +163,70 @@ const ModelItem = memo<ModelItemProps>(
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const NewTag =
|
||||
releasedAt && isNewReleaseDate(releasedAt) ? (
|
||||
<Tag color="blue" style={{ marginLeft: 8 }}>
|
||||
{t('new', { ns: 'common' })}
|
||||
</Tag>
|
||||
) : null;
|
||||
|
||||
const ModelIdTag = (
|
||||
<Tag onClick={copyModelId} style={{ cursor: 'pointer', marginRight: 0 }}>
|
||||
{id}
|
||||
</Tag>
|
||||
);
|
||||
|
||||
const EnableSwitch = (
|
||||
<Switch
|
||||
checked={checked}
|
||||
loading={isModelLoading}
|
||||
onChange={async (e) => {
|
||||
setChecked(e);
|
||||
await toggleModelEnabled({ enabled: e, id, source, type });
|
||||
}}
|
||||
size={'small'}
|
||||
/>
|
||||
);
|
||||
|
||||
const Actions =
|
||||
modelEditable &&
|
||||
((style?: React.CSSProperties) => (
|
||||
<Flexbox className={styles.config} horizontal style={style}>
|
||||
<ActionIcon
|
||||
icon={LucidePencil}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setShowConfig(true);
|
||||
}}
|
||||
size={'small'}
|
||||
title={t('providerModels.item.config')}
|
||||
/>
|
||||
{source !== AiModelSourceEnum.Builtin && (
|
||||
<ActionIcon
|
||||
icon={TrashIcon}
|
||||
onClick={() => {
|
||||
modal.confirm({
|
||||
centered: true,
|
||||
okButtonProps: {
|
||||
danger: true,
|
||||
type: 'primary',
|
||||
},
|
||||
onOk: async () => {
|
||||
await removeAiModel(id, activeAiProvider!);
|
||||
message.success(t('providerModels.item.delete.success'));
|
||||
},
|
||||
title: t('providerModels.item.delete.confirm', {
|
||||
displayName: displayName || id,
|
||||
}),
|
||||
});
|
||||
}}
|
||||
size={'small'}
|
||||
title={t('providerModels.item.delete.title')}
|
||||
/>
|
||||
)}
|
||||
</Flexbox>
|
||||
));
|
||||
|
||||
const dom = isMobile ? (
|
||||
<Flexbox
|
||||
align={'center'}
|
||||
@@ -195,58 +260,14 @@ const ModelItem = memo<ModelItemProps>(
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
<div>
|
||||
<Tag onClick={copyModelId} style={{ cursor: 'pointer', marginRight: 0 }}>
|
||||
{id}
|
||||
</Tag>
|
||||
{ModelIdTag}
|
||||
{NewTag}
|
||||
</div>
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
<Flexbox align={'center'} gap={4} horizontal>
|
||||
{modelEditable && (
|
||||
<Flexbox className={styles.config} horizontal style={{ opacity: 1 }}>
|
||||
<ActionIcon
|
||||
icon={LucidePencil}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setShowConfig(true);
|
||||
}}
|
||||
size={'small'}
|
||||
title={t('providerModels.item.config')}
|
||||
/>
|
||||
{source !== AiModelSourceEnum.Builtin && (
|
||||
<ActionIcon
|
||||
icon={TrashIcon}
|
||||
onClick={() => {
|
||||
modal.confirm({
|
||||
centered: true,
|
||||
okButtonProps: {
|
||||
danger: true,
|
||||
type: 'primary',
|
||||
},
|
||||
onOk: async () => {
|
||||
await removeAiModel(id, activeAiProvider!);
|
||||
message.success(t('providerModels.item.delete.success'));
|
||||
},
|
||||
title: t('providerModels.item.delete.confirm', {
|
||||
displayName: displayName || id,
|
||||
}),
|
||||
});
|
||||
}}
|
||||
size={'small'}
|
||||
title={t('providerModels.item.delete.title')}
|
||||
/>
|
||||
)}
|
||||
</Flexbox>
|
||||
)}
|
||||
<Switch
|
||||
checked={checked}
|
||||
loading={isModelLoading}
|
||||
onChange={async (e) => {
|
||||
setChecked(e);
|
||||
await toggleModelEnabled({ enabled: e, id, source, type });
|
||||
}}
|
||||
size={'small'}
|
||||
/>
|
||||
{Actions && Actions({ opacity: 1 })}
|
||||
{EnableSwitch}
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
) : (
|
||||
@@ -264,45 +285,9 @@ const ModelItem = memo<ModelItemProps>(
|
||||
<Flexbox flex={1} gap={2} style={{ minWidth: 0 }}>
|
||||
<Flexbox align={'center'} gap={8} horizontal>
|
||||
{displayName || id}
|
||||
<Tag onClick={copyModelId} style={{ cursor: 'pointer', marginRight: 0 }}>
|
||||
{id}
|
||||
</Tag>
|
||||
{modelEditable && (
|
||||
<Flexbox className={styles.config} horizontal>
|
||||
<ActionIcon
|
||||
icon={LucidePencil}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setShowConfig(true);
|
||||
}}
|
||||
size={'small'}
|
||||
title={t('providerModels.item.config')}
|
||||
/>
|
||||
{source !== AiModelSourceEnum.Builtin && (
|
||||
<ActionIcon
|
||||
icon={TrashIcon}
|
||||
onClick={() => {
|
||||
modal.confirm({
|
||||
centered: true,
|
||||
okButtonProps: {
|
||||
danger: true,
|
||||
type: 'primary',
|
||||
},
|
||||
onOk: async () => {
|
||||
await removeAiModel(id, activeAiProvider!);
|
||||
message.success(t('providerModels.item.delete.success'));
|
||||
},
|
||||
title: t('providerModels.item.delete.confirm', {
|
||||
displayName: displayName || id,
|
||||
}),
|
||||
});
|
||||
}}
|
||||
size={'small'}
|
||||
title={t('providerModels.item.delete.title')}
|
||||
/>
|
||||
)}
|
||||
</Flexbox>
|
||||
)}
|
||||
{ModelIdTag}
|
||||
{NewTag}
|
||||
{Actions && Actions()}
|
||||
</Flexbox>
|
||||
<Flexbox align={'baseline'} gap={8} horizontal>
|
||||
{content.length > 0 && (
|
||||
@@ -329,15 +314,7 @@ const ModelItem = memo<ModelItemProps>(
|
||||
{/* <ActionIcon icon={Recycle} style={{ color: theme.colorWarning }} />*/}
|
||||
{/* </Tooltip>*/}
|
||||
{/*)}*/}
|
||||
<Switch
|
||||
checked={checked}
|
||||
loading={isModelLoading}
|
||||
onChange={async (e) => {
|
||||
setChecked(e);
|
||||
await toggleModelEnabled({ enabled: e, id, source, type });
|
||||
}}
|
||||
size={'small'}
|
||||
/>
|
||||
{EnableSwitch}
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
);
|
||||
|
||||
@@ -286,6 +286,7 @@ export default {
|
||||
business: '商务合作',
|
||||
support: '邮件支持',
|
||||
},
|
||||
new: '新',
|
||||
oauth: 'SSO 登录',
|
||||
officialSite: '官方网站',
|
||||
ok: '确定',
|
||||
|
||||
Reference in New Issue
Block a user