mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-30 13:59:22 +07:00
🐛 fix: fixed changelog pages and open again (#10285)
* feat: fixed changelog pages and open again * fix: add discover use dynamic import * fix: update the routers * fix: change the pre build mts
This commit is contained in:
@@ -1499,11 +1499,12 @@ const qwenChatModels: AIChatModelCard[] = [
|
||||
},
|
||||
{
|
||||
abilities: {
|
||||
vision: true,
|
||||
reasoning: true,
|
||||
vision: true,
|
||||
},
|
||||
contextWindowTokens: 131_072,
|
||||
description: 'Qwen3 VL 32B 思考模式(开源版),针对高难度强推理与长视频理解场景,提供顶尖的视觉+文本推理能力。',
|
||||
description:
|
||||
'Qwen3 VL 32B 思考模式(开源版),针对高难度强推理与长视频理解场景,提供顶尖的视觉+文本推理能力。',
|
||||
displayName: 'Qwen3 VL 32B Thinking',
|
||||
id: 'qwen3-vl-32b-thinking',
|
||||
maxOutput: 32_768,
|
||||
@@ -1525,7 +1526,8 @@ const qwenChatModels: AIChatModelCard[] = [
|
||||
vision: true,
|
||||
},
|
||||
contextWindowTokens: 131_072,
|
||||
description: 'Qwen3 VL 32B 非思考模式(Instruct),适用于非思考指令场景,保持强大的视觉理解能力。',
|
||||
description:
|
||||
'Qwen3 VL 32B 非思考模式(Instruct),适用于非思考指令场景,保持强大的视觉理解能力。',
|
||||
displayName: 'Qwen3 VL 32B Instruct',
|
||||
id: 'qwen3-vl-32b-instruct',
|
||||
maxOutput: 32_768,
|
||||
|
||||
@@ -138,10 +138,10 @@ export interface OpenAICompatibleFactoryOptions<T extends Record<string, any> =
|
||||
useToolsCalling?: boolean;
|
||||
};
|
||||
models?:
|
||||
| ((params: { client: OpenAI }) => Promise<ChatModelCard[]>)
|
||||
| {
|
||||
transformModel?: (model: OpenAI.Model) => ChatModelCard;
|
||||
};
|
||||
| ((params: { client: OpenAI }) => Promise<ChatModelCard[]>)
|
||||
| {
|
||||
transformModel?: (model: OpenAI.Model) => ChatModelCard;
|
||||
};
|
||||
provider: string;
|
||||
responses?: {
|
||||
handlePayload?: (
|
||||
@@ -317,9 +317,9 @@ export const createOpenAICompatibleRuntime = <T extends Record<string, any> = an
|
||||
const postPayload = chatCompletion?.handlePayload
|
||||
? chatCompletion.handlePayload(processedPayload, this._options)
|
||||
: ({
|
||||
...processedPayload,
|
||||
stream: processedPayload.stream ?? true,
|
||||
} as OpenAI.ChatCompletionCreateParamsStreaming);
|
||||
...processedPayload,
|
||||
stream: processedPayload.stream ?? true,
|
||||
} as OpenAI.ChatCompletionCreateParamsStreaming);
|
||||
|
||||
if ((postPayload as any).apiMode === 'responses') {
|
||||
return this.handleResponseAPIMode(processedPayload, options);
|
||||
@@ -385,13 +385,13 @@ export const createOpenAICompatibleRuntime = <T extends Record<string, any> = an
|
||||
return StreamingResponse(
|
||||
chatCompletion?.handleStream
|
||||
? chatCompletion.handleStream(prod, {
|
||||
callbacks: streamOptions.callbacks,
|
||||
inputStartAt,
|
||||
})
|
||||
callbacks: streamOptions.callbacks,
|
||||
inputStartAt,
|
||||
})
|
||||
: OpenAIStream(prod, {
|
||||
...streamOptions,
|
||||
inputStartAt,
|
||||
}),
|
||||
...streamOptions,
|
||||
inputStartAt,
|
||||
}),
|
||||
{
|
||||
headers: options?.headers,
|
||||
},
|
||||
@@ -415,9 +415,9 @@ export const createOpenAICompatibleRuntime = <T extends Record<string, any> = an
|
||||
return StreamingResponse(
|
||||
chatCompletion?.handleStream
|
||||
? chatCompletion.handleStream(stream, {
|
||||
callbacks: streamOptions.callbacks,
|
||||
inputStartAt,
|
||||
})
|
||||
callbacks: streamOptions.callbacks,
|
||||
inputStartAt,
|
||||
})
|
||||
: OpenAIStream(stream, { ...streamOptions, enableStreaming: false, inputStartAt }),
|
||||
{
|
||||
headers: options?.headers,
|
||||
@@ -839,11 +839,11 @@ export const createOpenAICompatibleRuntime = <T extends Record<string, any> = an
|
||||
...res,
|
||||
...(reasoning || reasoning_effort
|
||||
? {
|
||||
reasoning: {
|
||||
...reasoning,
|
||||
...(reasoning_effort && { effort: reasoning_effort }),
|
||||
},
|
||||
}
|
||||
reasoning: {
|
||||
...reasoning,
|
||||
...(reasoning_effort && { effort: reasoning_effort }),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
input,
|
||||
...(max_tokens && { max_output_tokens: max_tokens }),
|
||||
|
||||
@@ -10,11 +10,11 @@ dotenv.config();
|
||||
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
||||
const partialBuildPages = [
|
||||
// no need for desktop
|
||||
{
|
||||
name: 'changelog',
|
||||
disabled: isDesktop,
|
||||
paths: ['src/app/[variants]/(main)/changelog'],
|
||||
},
|
||||
// {
|
||||
// name: 'changelog',
|
||||
// disabled: isDesktop,
|
||||
// paths: ['src/app/[variants]/(main)/changelog'],
|
||||
// },
|
||||
{
|
||||
name: 'auth',
|
||||
disabled: isDesktop,
|
||||
|
||||
@@ -18,7 +18,7 @@ const Page = (props: { isMobile: boolean }) => {
|
||||
const { isMobile } = props;
|
||||
const { hideDocs } = useServerConfigStore(featureFlagsSelectors);
|
||||
|
||||
const { data } = useSWR('changelog-index', async () => {
|
||||
const { data = [] } = useSWR('changelog-index', async () => {
|
||||
const changelogService = new ChangelogService();
|
||||
return await changelogService.getChangelogIndex();
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useResponsive, useTheme } from 'antd-style';
|
||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||
import { memo, useEffect, useRef } from 'react';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
@@ -13,7 +14,6 @@ import SettingsContent from '../SettingsContent';
|
||||
import { LayoutProps } from '../type';
|
||||
import Header from './Header';
|
||||
import SideBar from './SideBar';
|
||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||
|
||||
const Layout = memo<LayoutProps>(() => {
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
@@ -22,21 +22,23 @@ const Layout = memo<LayoutProps>(() => {
|
||||
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
|
||||
const [activeTabState, setActiveTabState] = useMergedState({
|
||||
active: searchParams.get('active') as SettingsTabs ? searchParams.get('active') as SettingsTabs : SettingsTabs.Common,
|
||||
}, {
|
||||
onChange: (obj: {
|
||||
active: SettingsTabs;
|
||||
provider?: string;
|
||||
}) => {
|
||||
if (obj.provider) {
|
||||
setSearchParams({ active: obj.active, provider: obj.provider });
|
||||
} else {
|
||||
searchParams.delete('provider');
|
||||
setSearchParams({ active: obj.active });
|
||||
}
|
||||
const [activeTabState, setActiveTabState] = useMergedState(
|
||||
{
|
||||
active: (searchParams.get('active') as SettingsTabs)
|
||||
? (searchParams.get('active') as SettingsTabs)
|
||||
: SettingsTabs.Common,
|
||||
},
|
||||
});
|
||||
{
|
||||
onChange: (obj: { active: SettingsTabs; provider?: string }) => {
|
||||
if (obj.provider) {
|
||||
setSearchParams({ active: obj.active, provider: obj.provider });
|
||||
} else {
|
||||
searchParams.delete('provider');
|
||||
setSearchParams({ active: obj.active });
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const setActiveTab = (tab: SettingsTabs) => {
|
||||
if (tab === SettingsTabs.Provider) {
|
||||
@@ -57,7 +59,9 @@ const Layout = memo<LayoutProps>(() => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const category = <CategoryContent activeTab={activeTabState.active} onMenuSelect={setActiveTab} />;
|
||||
const category = (
|
||||
<CategoryContent activeTab={activeTabState.active} onMenuSelect={setActiveTab} />
|
||||
);
|
||||
|
||||
return (
|
||||
<Flexbox
|
||||
|
||||
@@ -33,9 +33,12 @@ const ProviderCard = memo<ProviderCardProps>(
|
||||
return (
|
||||
<Flexbox className={cx(styles.container)} gap={24}>
|
||||
<Flexbox gap={12} padding={16} width={'100%'}>
|
||||
<div onClick={() => {
|
||||
onProviderSelect(id);
|
||||
}} style={{ cursor: 'pointer' }}>
|
||||
<div
|
||||
onClick={() => {
|
||||
onProviderSelect(id);
|
||||
}}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
<Flexbox gap={12} width={'100%'}>
|
||||
<Flexbox align={'center'} horizontal justify={'space-between'}>
|
||||
{source === 'builtin' ? (
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
'use client';
|
||||
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { isCustomBranding } from '@/const/version';
|
||||
|
||||
import DesktopLayout from '../_layout/Desktop';
|
||||
import MobileLayout from '../_layout/Mobile';
|
||||
import ProviderDetailPage from '../detail';
|
||||
import Footer from './Footer';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
const Page = (props: { mobile?: boolean }) => {
|
||||
const [SearchParams, setSearchParams] = useSearchParams();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
import Loading from '@/components/Loading/BrandTextLoading';
|
||||
|
||||
const NewAPI = dynamic(() => import('./newapi'), { loading: () => <Loading />, ssr: false });
|
||||
@@ -7,17 +8,26 @@ const VertexAI = dynamic(() => import('./vertexai'), { loading: () => <Loading /
|
||||
const GitHub = dynamic(() => import('./github'), { loading: () => <Loading />, ssr: false });
|
||||
const Ollama = dynamic(() => import('./ollama'), { loading: () => <Loading />, ssr: false });
|
||||
const ComfyUI = dynamic(() => import('./comfyui'), { loading: () => <Loading />, ssr: false });
|
||||
const Cloudflare = dynamic(() => import('./cloudflare'), { loading: () => <Loading />, ssr: false });
|
||||
const Cloudflare = dynamic(() => import('./cloudflare'), {
|
||||
loading: () => <Loading />,
|
||||
ssr: false,
|
||||
});
|
||||
const Bedrock = dynamic(() => import('./bedrock'), { loading: () => <Loading />, ssr: false });
|
||||
const AzureAI = dynamic(() => import('./azureai'), { loading: () => <Loading />, ssr: false });
|
||||
const Azure = dynamic(() => import('./azure'), { loading: () => <Loading />, ssr: false });
|
||||
const ProviderGrid = dynamic(() => import('../(list)/ProviderGrid'), { loading: () => <Loading />, ssr: false });
|
||||
const DefaultPage = dynamic(() => import('./default/ProviderDetialPage'), { loading: () => <Loading />, ssr: false });
|
||||
const ProviderGrid = dynamic(() => import('../(list)/ProviderGrid'), {
|
||||
loading: () => <Loading />,
|
||||
ssr: false,
|
||||
});
|
||||
const DefaultPage = dynamic(() => import('./default/ProviderDetialPage'), {
|
||||
loading: () => <Loading />,
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
type ProviderDetailPageProps = {
|
||||
id?: string | null;
|
||||
onProviderSelect: (provider: string) => void;
|
||||
}
|
||||
};
|
||||
|
||||
const ProviderDetailPage = (props: ProviderDetailPageProps) => {
|
||||
const { id, onProviderSelect } = props;
|
||||
|
||||
@@ -40,6 +40,16 @@ const ChatLayout = dynamic(() => import('./(main)/chat/_layout/Desktop'), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
// Changelog components
|
||||
const ChangelogPage = dynamic(() => import('./(main)/changelog/index').then((m) => m.DesktopPage), {
|
||||
loading: () => <Loading />,
|
||||
ssr: false,
|
||||
});
|
||||
const ChangelogLayout = dynamic(() => import('./(main)/changelog/_layout/Desktop'), {
|
||||
loading: () => <Loading />,
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
// Discover List components
|
||||
const DesktopHomePage = dynamic(
|
||||
() => import('./(main)/discover/(list)/(home)/index').then((m) => m.DesktopHomePage),
|
||||
@@ -256,6 +266,7 @@ const KnowledgeErrorBoundary = createErrorBoundary('/knowledge');
|
||||
const SettingsErrorBoundary = createErrorBoundary('/settings');
|
||||
const ImageErrorBoundary = createErrorBoundary('/image');
|
||||
const ProfileErrorBoundary = createErrorBoundary('/profile');
|
||||
const ChangelogErrorBoundary = createErrorBoundary('/changelog');
|
||||
const RootErrorBoundary = createErrorBoundary('/chat'); // Root level falls back to chat
|
||||
|
||||
// Root layout wrapper component
|
||||
@@ -455,6 +466,18 @@ export const createDesktopRouter = (locale: Locales) =>
|
||||
path: 'profile',
|
||||
},
|
||||
|
||||
// changelog routes
|
||||
{
|
||||
children: [
|
||||
{
|
||||
element: <ChangelogPage />,
|
||||
index: true,
|
||||
},
|
||||
],
|
||||
element: <ChangelogLayout locale={locale} />,
|
||||
errorElement: <ChangelogErrorBoundary />,
|
||||
path: 'changelog',
|
||||
},
|
||||
// Default route - redirect to chat
|
||||
{
|
||||
index: true,
|
||||
|
||||
@@ -41,6 +41,15 @@ const ChatLayout = dynamic(() => import('./(main)/chat/_layout/Mobile'), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
// Changelog components
|
||||
const ChangelogPage = dynamic(() => import('./(main)/changelog/index').then((m) => m.MobilePage), {
|
||||
loading: () => <Loading />,
|
||||
ssr: false,
|
||||
});
|
||||
const ChangelogLayout = dynamic(() => import('./(main)/changelog/_layout/Mobile'), {
|
||||
loading: () => <Loading />,
|
||||
ssr: false,
|
||||
});
|
||||
// Discover List components
|
||||
const MobileHomePage = dynamic(
|
||||
() => import('./(main)/discover/(list)/(home)/index').then((m) => m.MobileHomePage),
|
||||
@@ -272,6 +281,7 @@ const createErrorBoundary = (resetPath: string) => {
|
||||
// Create error boundaries for each route
|
||||
const ChatErrorBoundary = createErrorBoundary('/chat');
|
||||
const DiscoverErrorBoundary = createErrorBoundary('/discover');
|
||||
const ChangelogErrorBoundary = createErrorBoundary('/changelog');
|
||||
const KnowledgeErrorBoundary = createErrorBoundary('/knowledge');
|
||||
const SettingsErrorBoundary = createErrorBoundary('/settings');
|
||||
const ImageErrorBoundary = createErrorBoundary('/image');
|
||||
@@ -499,6 +509,19 @@ export const createMobileRouter = (locale: Locales) =>
|
||||
path: 'me',
|
||||
},
|
||||
|
||||
// changelog routes
|
||||
{
|
||||
children: [
|
||||
{
|
||||
element: <ChangelogPage />,
|
||||
index: true,
|
||||
},
|
||||
],
|
||||
element: <ChangelogLayout locale={locale} />,
|
||||
errorElement: <ChangelogErrorBoundary />,
|
||||
path: 'changelog',
|
||||
},
|
||||
|
||||
// Default route - redirect to chat
|
||||
{
|
||||
index: true,
|
||||
|
||||
@@ -17,8 +17,8 @@ import {
|
||||
} from 'lucide-react';
|
||||
import { PropsWithChildren, memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import type { MenuProps } from '@/components/Menu';
|
||||
import { enableAuth } from '@/const/auth';
|
||||
@@ -135,7 +135,11 @@ export const useMenu = () => {
|
||||
icon: <Icon icon={Cloudy} />,
|
||||
key: 'cloud',
|
||||
label: (
|
||||
<a href={`${OFFICIAL_URL}?utm_source=${UTM_SOURCE}`} rel="noopener noreferrer" target="_blank">
|
||||
<a
|
||||
href={`${OFFICIAL_URL}?utm_source=${UTM_SOURCE}`}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{t('userPanel.cloud', { name: LOBE_CHAT_CLOUD })}
|
||||
</a>
|
||||
),
|
||||
@@ -148,7 +152,7 @@ export const useMenu = () => {
|
||||
{t('changelog')}
|
||||
</a>
|
||||
) : (
|
||||
<Link to="/changelog/modal">{t('changelog')}</Link>
|
||||
<Link to="/changelog">{t('changelog')}</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import type {
|
||||
AgentInstruction,
|
||||
AgentState,
|
||||
} from '@lobechat/agent-runtime';
|
||||
import type { AgentInstruction, AgentState } from '@lobechat/agent-runtime';
|
||||
|
||||
import { createAgentExecutors } from '@/store/chat/agents/createAgentExecutors';
|
||||
import type { OperationType } from '@/store/chat/slices/operation/types';
|
||||
|
||||
Reference in New Issue
Block a user