mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2026-01-21 03:51:15 -08:00
fix: legacy usage
This commit is contained in:
parent
0bf3816d1c
commit
4169972094
11 changed files with 144 additions and 136 deletions
|
|
@ -80,7 +80,7 @@ export const serviceInstances: {
|
|||
} as Partial<IPreferenceService>;
|
||||
})(),
|
||||
externalAPI: {
|
||||
getAIConfig: vi.fn(async () => ({ api: { model: 'test-model', provider: 'test-provider' }, modelParameters: {} })),
|
||||
getAIConfig: vi.fn(async () => ({ default: { model: 'test-model', provider: 'test-provider' }, modelParameters: {} })),
|
||||
getAIProviders: vi.fn(async () => []),
|
||||
generateFromAI: vi.fn(async function*() {
|
||||
// harmless await for linter
|
||||
|
|
|
|||
|
|
@ -602,10 +602,13 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => {
|
|||
id: 'test-agent',
|
||||
agentDefId: 'test-agent-def',
|
||||
aiApiConfig: {
|
||||
api: {
|
||||
default: {
|
||||
provider: 'openai',
|
||||
model: 'gpt-4',
|
||||
embeddingModel: 'text-embedding-ada-002',
|
||||
},
|
||||
embedding: {
|
||||
provider: 'openai',
|
||||
model: 'text-embedding-ada-002',
|
||||
},
|
||||
modelParameters: {},
|
||||
},
|
||||
|
|
@ -665,10 +668,14 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => {
|
|||
expect.any(String), // workspaceID
|
||||
'How to use AI agents',
|
||||
expect.objectContaining({
|
||||
api: expect.objectContaining({
|
||||
default: expect.objectContaining({
|
||||
provider: 'openai',
|
||||
model: 'gpt-4',
|
||||
}),
|
||||
embedding: expect.objectContaining({
|
||||
provider: 'openai',
|
||||
model: 'text-embedding-ada-002',
|
||||
}),
|
||||
}),
|
||||
10,
|
||||
0.7,
|
||||
|
|
@ -701,7 +708,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => {
|
|||
id: 'test-agent',
|
||||
agentDefId: 'test-agent-def',
|
||||
aiApiConfig: {
|
||||
api: {
|
||||
default: {
|
||||
provider: 'openai',
|
||||
model: 'gpt-4',
|
||||
},
|
||||
|
|
@ -772,7 +779,7 @@ describe('Wiki Search Plugin - Comprehensive Tests', () => {
|
|||
id: 'test-agent',
|
||||
agentDefId: 'test-agent-def',
|
||||
aiApiConfig: {
|
||||
api: {
|
||||
default: {
|
||||
provider: 'openai',
|
||||
model: 'gpt-4',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ export default {
|
|||
},
|
||||
],
|
||||
defaultConfig: {
|
||||
api: {
|
||||
default: {
|
||||
provider: 'siliconflow',
|
||||
model: 'Qwen/Qwen2.5-7B-Instruct',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -353,8 +353,8 @@ export class ExternalAPIService implements IExternalAPIService {
|
|||
async deleteFieldFromDefaultAIConfig(fieldPath: string): Promise<void> {
|
||||
this.ensureSettingsLoaded();
|
||||
|
||||
// Support nested field deletion like 'api.embeddingModel'
|
||||
const pathParts = fieldPath.split('.');
|
||||
// Support field deletion like 'embedding', 'speech', 'default'
|
||||
const parts = fieldPath.split('.');
|
||||
let current: Record<string, unknown> = this.userSettings.defaultConfig;
|
||||
|
||||
// Navigate to the parent object
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@ export interface IExternalAPIService {
|
|||
|
||||
/**
|
||||
* Delete a field from default AI configuration
|
||||
* @param fieldPath - Dot-separated path to the field (e.g., 'api.embeddingModel')
|
||||
* @param fieldPath - Dot-separated path to the field (e.g., 'embedding', 'speech', 'default')
|
||||
*/
|
||||
deleteFieldFromDefaultAIConfig(fieldPath: string): Promise<void>;
|
||||
|
||||
|
|
|
|||
|
|
@ -51,11 +51,11 @@ describe('ExternalAPI Add Provider with Embedding Model', () => {
|
|||
|
||||
Object.defineProperty(window.service.externalAPI, 'getAIConfig', {
|
||||
value: vi.fn().mockResolvedValue({
|
||||
api: {
|
||||
default: {
|
||||
provider: 'existing-provider',
|
||||
model: 'gpt-4o',
|
||||
// No embeddingModel initially
|
||||
},
|
||||
// No embedding initially
|
||||
modelParameters: {
|
||||
temperature: 0.7,
|
||||
systemPrompt: 'You are a helpful assistant.',
|
||||
|
|
@ -87,7 +87,7 @@ describe('ExternalAPI Add Provider with Embedding Model', () => {
|
|||
|
||||
// Mock observables for externalAPI
|
||||
const mockConfig: AiAPIConfig = {
|
||||
api: {
|
||||
default: {
|
||||
provider: 'existing-provider',
|
||||
model: 'gpt-4o',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -23,21 +23,71 @@ const mockEmbeddingModel: ModelInfo = {
|
|||
features: ['embedding' as ModelFeature],
|
||||
};
|
||||
|
||||
const mockSpeechModel: ModelInfo = {
|
||||
name: 'gpt-speech',
|
||||
caption: 'GPT Speech',
|
||||
features: ['speech' as ModelFeature],
|
||||
};
|
||||
|
||||
const mockImageModel: ModelInfo = {
|
||||
name: 'dall-e',
|
||||
caption: 'DALL-E',
|
||||
features: ['imageGeneration' as ModelFeature],
|
||||
};
|
||||
|
||||
const mockTranscriptionsModel: ModelInfo = {
|
||||
name: 'whisper',
|
||||
caption: 'Whisper',
|
||||
features: ['transcriptions' as ModelFeature],
|
||||
};
|
||||
|
||||
const mockFreeModel: ModelInfo = {
|
||||
name: 'gpt-free',
|
||||
caption: 'GPT Free',
|
||||
features: ['free' as ModelFeature],
|
||||
};
|
||||
|
||||
const mockProvider: AIProviderConfig = {
|
||||
provider: 'openai',
|
||||
apiKey: 'sk-test',
|
||||
baseURL: 'https://api.openai.com/v1',
|
||||
models: [mockLanguageModel, mockEmbeddingModel],
|
||||
models: [
|
||||
mockLanguageModel,
|
||||
mockEmbeddingModel,
|
||||
mockSpeechModel,
|
||||
mockImageModel,
|
||||
mockTranscriptionsModel,
|
||||
mockFreeModel,
|
||||
],
|
||||
providerClass: 'openai',
|
||||
isPreset: false,
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
const mockAIConfig = {
|
||||
api: {
|
||||
default: {
|
||||
provider: 'openai',
|
||||
model: 'gpt-4',
|
||||
embeddingModel: 'text-embedding-3-small',
|
||||
},
|
||||
embedding: {
|
||||
provider: 'openai',
|
||||
model: 'text-embedding-3-small',
|
||||
},
|
||||
speech: {
|
||||
provider: 'openai',
|
||||
model: 'gpt-speech',
|
||||
},
|
||||
imageGeneration: {
|
||||
provider: 'openai',
|
||||
model: 'dall-e',
|
||||
},
|
||||
transcriptions: {
|
||||
provider: 'openai',
|
||||
model: 'whisper',
|
||||
},
|
||||
free: {
|
||||
provider: 'openai',
|
||||
model: 'gpt-free',
|
||||
},
|
||||
modelParameters: {
|
||||
temperature: 0.7,
|
||||
|
|
@ -155,11 +205,11 @@ describe('ExternalAPI Component', () => {
|
|||
// Mock config with no embedding model
|
||||
Object.defineProperty(window.service.externalAPI, 'getAIConfig', {
|
||||
value: vi.fn().mockResolvedValue({
|
||||
api: {
|
||||
default: {
|
||||
provider: 'openai',
|
||||
model: 'gpt-4',
|
||||
// No embeddingModel
|
||||
},
|
||||
// No embedding
|
||||
modelParameters: {
|
||||
temperature: 0.7,
|
||||
systemPrompt: 'You are a helpful assistant.',
|
||||
|
|
@ -180,12 +230,9 @@ describe('ExternalAPI Component', () => {
|
|||
if (clearButton) {
|
||||
await user.click(clearButton as HTMLElement);
|
||||
|
||||
// Verify both model and provider fields are deleted when no embedding model exists
|
||||
// Verify default field is deleted
|
||||
await waitFor(() => {
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('api.model');
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('api.provider');
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('default');
|
||||
});
|
||||
|
||||
// Also verify that handleConfigChange was called to update local state
|
||||
|
|
@ -203,23 +250,25 @@ describe('ExternalAPI Component', () => {
|
|||
|
||||
// Verify the delete API was called
|
||||
await waitFor(() => {
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('api.model');
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('api.provider');
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('default');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should only clear model field when embedding model exists', async () => {
|
||||
it('should only clear default field when embedding model exists', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
// Mock config with embedding model - this should preserve the provider
|
||||
// Mock config with embedding model
|
||||
Object.defineProperty(window.service.externalAPI, 'getAIConfig', {
|
||||
value: vi.fn().mockResolvedValue({
|
||||
api: {
|
||||
default: {
|
||||
provider: 'openai',
|
||||
model: 'gpt-4',
|
||||
embeddingModel: 'text-embedding-3-small', // Has embedding model
|
||||
},
|
||||
embedding: {
|
||||
provider: 'openai',
|
||||
model: 'text-embedding-3-small',
|
||||
},
|
||||
modelParameters: {
|
||||
temperature: 0.7,
|
||||
|
|
@ -241,14 +290,11 @@ describe('ExternalAPI Component', () => {
|
|||
if (clearButton) {
|
||||
await user.click(clearButton as HTMLElement);
|
||||
|
||||
// Should only delete model, NOT provider (because embedding model uses the provider)
|
||||
// Should delete default field
|
||||
await waitFor(() => {
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('api.model');
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('default');
|
||||
});
|
||||
|
||||
// Should NOT delete provider when embedding model exists
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).not.toHaveBeenCalledWith('api.provider');
|
||||
|
||||
// Verify that handleConfigChange was called
|
||||
await waitFor(() => {
|
||||
expect(window.service.externalAPI.updateDefaultAIConfig).toHaveBeenCalled();
|
||||
|
|
@ -262,10 +308,8 @@ describe('ExternalAPI Component', () => {
|
|||
await user.keyboard('{Escape}');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('api.model');
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('default');
|
||||
});
|
||||
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).not.toHaveBeenCalledWith('api.provider');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -285,7 +329,7 @@ describe('ExternalAPI Component', () => {
|
|||
|
||||
// Verify the delete API was called
|
||||
await waitFor(() => {
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('api.embeddingModel');
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('embedding');
|
||||
});
|
||||
|
||||
// Also verify that handleConfigChange was called to update local state
|
||||
|
|
@ -303,7 +347,7 @@ describe('ExternalAPI Component', () => {
|
|||
|
||||
// Verify the delete API was called
|
||||
await waitFor(() => {
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('api.embeddingModel');
|
||||
expect(window.service.externalAPI.deleteFieldFromDefaultAIConfig).toHaveBeenCalledWith('embedding');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -316,19 +360,15 @@ describe('ExternalAPI Component', () => {
|
|||
// Create a simple test for ModelSelector clear functionality
|
||||
const { ModelSelector } = await import('../components/ModelSelector');
|
||||
|
||||
const testConfig = {
|
||||
api: {
|
||||
provider: 'openai',
|
||||
model: 'text-embedding-3-small',
|
||||
embeddingModel: 'text-embedding-3-small',
|
||||
},
|
||||
modelParameters: {},
|
||||
const testModel = {
|
||||
provider: 'openai',
|
||||
model: 'text-embedding-3-small',
|
||||
};
|
||||
|
||||
render(
|
||||
<TestWrapper>
|
||||
<ModelSelector
|
||||
selectedConfig={testConfig}
|
||||
selectedModel={testModel}
|
||||
modelOptions={[[mockProvider, mockEmbeddingModel]]}
|
||||
onChange={vi.fn()}
|
||||
onClear={mockOnClear}
|
||||
|
|
@ -346,6 +386,34 @@ describe('ExternalAPI Component', () => {
|
|||
}
|
||||
});
|
||||
|
||||
it('should display default models from backend config on initial load', async () => {
|
||||
await renderExternalAPI();
|
||||
|
||||
// Wait for all comboboxes to be rendered
|
||||
const comboboxes = screen.getAllByRole('combobox');
|
||||
|
||||
// We have 6 model selectors (default, embedding, speech, imageGeneration, transcriptions, free)
|
||||
expect(comboboxes).toHaveLength(6);
|
||||
|
||||
// Check that default model is displayed (first combobox)
|
||||
expect(comboboxes[0]).toHaveValue('gpt-4');
|
||||
|
||||
// Check that embedding model is displayed (second combobox)
|
||||
expect(comboboxes[1]).toHaveValue('text-embedding-3-small');
|
||||
|
||||
// Check that speech model is displayed (third combobox)
|
||||
expect(comboboxes[2]).toHaveValue('gpt-speech');
|
||||
|
||||
// Check that image generation model is displayed (fourth combobox)
|
||||
expect(comboboxes[3]).toHaveValue('dall-e');
|
||||
|
||||
// Check that transcriptions model is displayed (fifth combobox)
|
||||
expect(comboboxes[4]).toHaveValue('whisper');
|
||||
|
||||
// Check that free model is displayed (sixth combobox)
|
||||
expect(comboboxes[5]).toHaveValue('gpt-free');
|
||||
});
|
||||
|
||||
it('should render provider configuration section', async () => {
|
||||
await renderExternalAPI();
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { useAIConfigManagement } from '../useAIConfigManagement';
|
|||
|
||||
describe('useAIConfigManagement', () => {
|
||||
const mockAIConfig: AiAPIConfig = {
|
||||
api: {
|
||||
default: {
|
||||
provider: 'openai',
|
||||
model: 'gpt-4',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,32 +1,24 @@
|
|||
import { Autocomplete } from '@mui/material';
|
||||
import { AiAPIConfig } from '@services/agentInstance/promptConcat/promptConcatSchema';
|
||||
import { ModelSelection } from '@services/agentInstance/promptConcat/promptConcatSchema';
|
||||
import { AIProviderConfig, ModelInfo } from '@services/externalAPI/interface';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { TextField } from '../../../PreferenceComponents';
|
||||
|
||||
interface ModelSelectorProps {
|
||||
selectedConfig: AiAPIConfig | null;
|
||||
selectedModel: ModelSelection | undefined;
|
||||
modelOptions: Array<[AIProviderConfig, ModelInfo]>;
|
||||
onChange: (provider: string, model: string) => void;
|
||||
onClear?: () => void;
|
||||
onlyShowEnabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard to check if config has api field
|
||||
*/
|
||||
const hasApiField = (config: AiAPIConfig | null): config is AiAPIConfig & { api: { provider: string; model: string } } => {
|
||||
return config !== null && 'api' in config && typeof config.api === 'object' && config.api !== null &&
|
||||
'provider' in config.api && 'model' in config.api;
|
||||
};
|
||||
|
||||
export function ModelSelector({ selectedConfig, modelOptions, onChange, onClear, onlyShowEnabled }: ModelSelectorProps) {
|
||||
export function ModelSelector({ selectedModel, modelOptions, onChange, onClear, onlyShowEnabled }: ModelSelectorProps) {
|
||||
const { t } = useTranslation('agent');
|
||||
|
||||
const selectedValue = hasApiField(selectedConfig) && selectedConfig.api.model && selectedConfig.api.provider &&
|
||||
selectedConfig.api.model !== '' && selectedConfig.api.provider !== ''
|
||||
? modelOptions.find(m => m[0].provider === selectedConfig.api.provider && m[1].name === selectedConfig.api.model) || null
|
||||
const selectedValue = selectedModel && selectedModel.model && selectedModel.provider &&
|
||||
selectedModel.model !== '' && selectedModel.provider !== ''
|
||||
? modelOptions.find(m => m[0].provider === selectedModel.provider && m[1].name === selectedModel.model) || null
|
||||
: null;
|
||||
|
||||
const filteredModelOptions = onlyShowEnabled
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ describe('ProviderConfig Component', () => {
|
|||
|
||||
Object.defineProperty(window.service.externalAPI, 'getAIConfig', {
|
||||
value: vi.fn().mockResolvedValue({
|
||||
api: {
|
||||
default: {
|
||||
provider: 'openai',
|
||||
model: 'gpt-4',
|
||||
},
|
||||
|
|
@ -194,7 +194,7 @@ describe('ProviderConfig Component', () => {
|
|||
// Mock AI config to simulate no existing embedding model
|
||||
Object.defineProperty(window.service.externalAPI, 'getAIConfig', {
|
||||
value: vi.fn().mockResolvedValue({
|
||||
api: {
|
||||
default: {
|
||||
provider: '',
|
||||
model: '',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -107,72 +107,13 @@ export function ExternalAPI(props: Partial<ISectionProps>): React.JSX.Element {
|
|||
await handleConfigChange(updatedConfig);
|
||||
};
|
||||
|
||||
// Create default model config for ModelSelector
|
||||
const defaultModelConfig = config && config.default
|
||||
? {
|
||||
api: {
|
||||
provider: config.default.provider,
|
||||
model: config.default.model,
|
||||
},
|
||||
modelParameters: config.modelParameters,
|
||||
}
|
||||
: null;
|
||||
|
||||
// Create embedding config from current AI config
|
||||
// Use the provider that actually has the embedding model
|
||||
const embeddingConfig = config && config.embedding
|
||||
? {
|
||||
api: {
|
||||
provider: config.embedding.provider,
|
||||
model: config.embedding.model,
|
||||
},
|
||||
modelParameters: config.modelParameters,
|
||||
}
|
||||
: null;
|
||||
|
||||
// Create speech config from current AI config
|
||||
const speechConfig = config && config.speech
|
||||
? {
|
||||
api: {
|
||||
provider: config.speech.provider,
|
||||
model: config.speech.model,
|
||||
},
|
||||
modelParameters: config.modelParameters,
|
||||
}
|
||||
: null;
|
||||
|
||||
// Create image generation config from current AI config
|
||||
const imageGenerationConfig = config && config.imageGeneration
|
||||
? {
|
||||
api: {
|
||||
provider: config.imageGeneration.provider,
|
||||
model: config.imageGeneration.model,
|
||||
},
|
||||
modelParameters: config.modelParameters,
|
||||
}
|
||||
: null;
|
||||
|
||||
// Create transcriptions config from current AI config
|
||||
const transcriptionsConfig = config && config.transcriptions
|
||||
? {
|
||||
api: {
|
||||
provider: config.transcriptions.provider,
|
||||
model: config.transcriptions.model,
|
||||
},
|
||||
modelParameters: config.modelParameters,
|
||||
}
|
||||
: null;
|
||||
|
||||
// Create free model config from current AI config
|
||||
const freeModelConfig = config && config.free
|
||||
? {
|
||||
api: {
|
||||
provider: config.free.provider,
|
||||
model: config.free.model,
|
||||
},
|
||||
modelParameters: config.modelParameters,
|
||||
}
|
||||
: null;
|
||||
// Extract model selections directly from config
|
||||
const defaultModelConfig = config?.default;
|
||||
const embeddingConfig = config?.embedding;
|
||||
const speechConfig = config?.speech;
|
||||
const imageGenerationConfig = config?.imageGeneration;
|
||||
const transcriptionsConfig = config?.transcriptions;
|
||||
const freeModelConfig = config?.free;
|
||||
|
||||
const handleFreeModelClear = async () => {
|
||||
if (!config) return;
|
||||
|
|
@ -201,7 +142,7 @@ export function ExternalAPI(props: Partial<ISectionProps>): React.JSX.Element {
|
|||
secondary={t('Preference.DefaultAIModelSelectionDescription')}
|
||||
/>
|
||||
<ModelSelector
|
||||
selectedConfig={defaultModelConfig}
|
||||
selectedModel={defaultModelConfig}
|
||||
modelOptions={providers.flatMap(provider =>
|
||||
provider.models
|
||||
.filter(model => Array.isArray(model.features) && model.features.includes('language'))
|
||||
|
|
@ -218,7 +159,7 @@ export function ExternalAPI(props: Partial<ISectionProps>): React.JSX.Element {
|
|||
secondary={t('Preference.DefaultEmbeddingModelSelectionDescription')}
|
||||
/>
|
||||
<ModelSelector
|
||||
selectedConfig={embeddingConfig}
|
||||
selectedModel={embeddingConfig}
|
||||
modelOptions={providers.flatMap(provider =>
|
||||
provider.models
|
||||
.filter(model => Array.isArray(model.features) && model.features.includes('embedding'))
|
||||
|
|
@ -235,7 +176,7 @@ export function ExternalAPI(props: Partial<ISectionProps>): React.JSX.Element {
|
|||
secondary={t('Preference.DefaultSpeechModelSelectionDescription')}
|
||||
/>
|
||||
<ModelSelector
|
||||
selectedConfig={speechConfig}
|
||||
selectedModel={speechConfig}
|
||||
modelOptions={providers.flatMap(provider =>
|
||||
provider.models
|
||||
.filter(model => Array.isArray(model.features) && model.features.includes('speech'))
|
||||
|
|
@ -252,7 +193,7 @@ export function ExternalAPI(props: Partial<ISectionProps>): React.JSX.Element {
|
|||
secondary={t('Preference.DefaultImageGenerationModelSelectionDescription')}
|
||||
/>
|
||||
<ModelSelector
|
||||
selectedConfig={imageGenerationConfig}
|
||||
selectedModel={imageGenerationConfig}
|
||||
modelOptions={providers.flatMap(provider =>
|
||||
provider.models
|
||||
.filter(model => Array.isArray(model.features) && model.features.includes('imageGeneration'))
|
||||
|
|
@ -269,7 +210,7 @@ export function ExternalAPI(props: Partial<ISectionProps>): React.JSX.Element {
|
|||
secondary={t('Preference.DefaultTranscriptionsModelSelectionDescription')}
|
||||
/>
|
||||
<ModelSelector
|
||||
selectedConfig={transcriptionsConfig}
|
||||
selectedModel={transcriptionsConfig}
|
||||
modelOptions={providers.flatMap(provider =>
|
||||
provider.models
|
||||
.filter(model => Array.isArray(model.features) && model.features.includes('transcriptions'))
|
||||
|
|
@ -286,7 +227,7 @@ export function ExternalAPI(props: Partial<ISectionProps>): React.JSX.Element {
|
|||
secondary={t('Preference.DefaultFreeModelSelectionDescription')}
|
||||
/>
|
||||
<ModelSelector
|
||||
selectedConfig={freeModelConfig}
|
||||
selectedModel={freeModelConfig}
|
||||
modelOptions={providers.flatMap(provider =>
|
||||
provider.models
|
||||
.filter(model => Array.isArray(model.features) && model.features.includes('free'))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue