@lobehub/chat
Version:
Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.
153 lines (135 loc) • 5.15 kB
text/typescript
import isEqual from 'fast-deep-equal';
import { SWRResponse, mutate } from 'swr';
import { StateCreator } from 'zustand/vanilla';
import { useClientDataSWR } from '@/libs/swr';
import { aiModelService } from '@/services/aiModel';
import { AiInfraStore } from '@/store/aiInfra/store';
import {
AiModelSortMap,
AiProviderModelListItem,
CreateAiModelParams,
ToggleAiModelEnableParams,
} from '@/types/aiModel';
const FETCH_AI_PROVIDER_MODEL_LIST_KEY = 'FETCH_AI_PROVIDER_MODELS';
export interface AiModelAction {
batchToggleAiModels: (ids: string[], enabled: boolean) => Promise<void>;
batchUpdateAiModels: (models: AiProviderModelListItem[]) => Promise<void>;
clearModelsByProvider: (provider: string) => Promise<void>;
clearRemoteModels: (provider: string) => Promise<void>;
createNewAiModel: (params: CreateAiModelParams) => Promise<void>;
fetchRemoteModelList: (providerId: string) => Promise<void>;
internal_toggleAiModelLoading: (id: string, loading: boolean) => void;
refreshAiModelList: () => Promise<void>;
removeAiModel: (id: string, providerId: string) => Promise<void>;
toggleModelEnabled: (params: Omit<ToggleAiModelEnableParams, 'providerId'>) => Promise<void>;
updateAiModelsConfig: (
id: string,
providerId: string,
data: Partial<AiProviderModelListItem>,
) => Promise<void>;
updateAiModelsSort: (providerId: string, items: AiModelSortMap[]) => Promise<void>;
useFetchAiProviderModels: (id: string) => SWRResponse<AiProviderModelListItem[]>;
}
export const createAiModelSlice: StateCreator<
AiInfraStore,
[['zustand/devtools', never]],
[],
AiModelAction
> = (set, get) => ({
batchToggleAiModels: async (ids, enabled) => {
const { activeAiProvider } = get();
if (!activeAiProvider) return;
await aiModelService.batchToggleAiModels(activeAiProvider, ids, enabled);
await get().refreshAiModelList();
},
batchUpdateAiModels: async (models) => {
const { activeAiProvider: id } = get();
if (!id) return;
await aiModelService.batchUpdateAiModels(id, models);
await get().refreshAiModelList();
},
clearModelsByProvider: async (provider) => {
await aiModelService.clearModelsByProvider(provider);
await get().refreshAiModelList();
},
clearRemoteModels: async (provider) => {
await aiModelService.clearRemoteModels(provider);
await get().refreshAiModelList();
},
createNewAiModel: async (data) => {
await aiModelService.createAiModel(data);
await get().refreshAiModelList();
},
fetchRemoteModelList: async (providerId) => {
const { modelsService } = await import('@/services/models');
const data = await modelsService.getModels(providerId);
if (data) {
await get().batchUpdateAiModels(
data.map((model) => ({
...model,
abilities: {
files: model.files,
functionCall: model.functionCall,
reasoning: model.reasoning,
vision: model.vision,
},
enabled: model.enabled || false,
source: 'remote',
type: model.type || 'chat',
})),
);
await get().refreshAiModelList();
}
},
internal_toggleAiModelLoading: (id, loading) => {
set(
(state) => {
if (loading) return { aiModelLoadingIds: [...state.aiModelLoadingIds, id] };
return { aiModelLoadingIds: state.aiModelLoadingIds.filter((i) => i !== id) };
},
false,
'toggleAiModelLoading',
);
},
refreshAiModelList: async () => {
await mutate([FETCH_AI_PROVIDER_MODEL_LIST_KEY, get().activeAiProvider]);
// make refresh provide runtime state async, not block
get().refreshAiProviderRuntimeState();
},
removeAiModel: async (id, providerId) => {
await aiModelService.deleteAiModel({ id, providerId });
await get().refreshAiModelList();
},
toggleModelEnabled: async (params) => {
const { activeAiProvider } = get();
if (!activeAiProvider) return;
get().internal_toggleAiModelLoading(params.id, true);
await aiModelService.toggleModelEnabled({ ...params, providerId: activeAiProvider });
await get().refreshAiModelList();
get().internal_toggleAiModelLoading(params.id, false);
},
updateAiModelsConfig: async (id, providerId, data) => {
await aiModelService.updateAiModel(id, providerId, data);
await get().refreshAiModelList();
},
updateAiModelsSort: async (id, items) => {
await aiModelService.updateAiModelOrder(id, items);
await get().refreshAiModelList();
},
useFetchAiProviderModels: (id) =>
useClientDataSWR<AiProviderModelListItem[]>(
[FETCH_AI_PROVIDER_MODEL_LIST_KEY, id],
([, id]) => aiModelService.getAiProviderModelList(id as string),
{
onSuccess: (data) => {
// no need to update list if the list have been init and data is the same
if (get().isAiModelListInit && isEqual(data, get().aiProviderModelList)) return;
set(
{ aiProviderModelList: data, isAiModelListInit: true },
false,
`useFetchAiProviderModels/${id}`,
);
},
},
),
});