0a9588abb7
- Add pagination support to findAll (page, limit query params) - Add findByTemplateId method to service - Add GET /by-template/:templateId endpoint to controller - Service already includes CRUD for QuestionBank and QuestionBankItem
94 lines
2.9 KiB
TypeScript
94 lines
2.9 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { Eye } from 'lucide-react';
|
|
import { settingsService } from '../services/settingsService';
|
|
import { useLanguage } from '../contexts/LanguageContext';
|
|
|
|
interface VisionModel {
|
|
id: string;
|
|
name: string;
|
|
modelId: string;
|
|
}
|
|
|
|
interface VisionModelSelectorProps {
|
|
isAdmin?: boolean;
|
|
}
|
|
|
|
const VisionModelSelector: React.FC<VisionModelSelectorProps> = ({ isAdmin = false }) => {
|
|
const { t } = useLanguage();
|
|
const [visionModels, setVisionModels] = useState<VisionModel[]>([]);
|
|
const [selectedModelId, setSelectedModelId] = useState<string>('');
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string>('');
|
|
|
|
useEffect(() => {
|
|
loadData();
|
|
}, []);
|
|
|
|
const loadData = async () => {
|
|
try {
|
|
setLoading(true);
|
|
setError('');
|
|
const [models, current] = await Promise.all([
|
|
settingsService.getVisionModels(),
|
|
settingsService.getVisionModel()
|
|
]);
|
|
console.log('Vision models loaded:', models);
|
|
console.log('Current vision model:', current);
|
|
setVisionModels(models || []);
|
|
setSelectedModelId(current?.visionModelId || '');
|
|
} catch (error) {
|
|
console.error(t('loadVisionModelFailed'), error);
|
|
setError(t('loadFailed'));
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleChange = async (modelId: string) => {
|
|
try {
|
|
setSelectedModelId(modelId);
|
|
await settingsService.updateVisionModel(modelId);
|
|
} catch (error) {
|
|
console.error(t('saveVisionModelFailed'), error);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="bg-white p-4 rounded-xl border border-slate-200 shadow-sm">
|
|
<div className="flex items-center gap-2 mb-4 text-slate-800 font-semibold border-b border-slate-100 pb-2">
|
|
<Eye className="w-4 h-4 text-purple-600" />
|
|
{t('visionModelSettings')}
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-xs font-medium text-slate-500 mb-1.5">
|
|
{t('defaultVisionModel')}
|
|
</label>
|
|
{error ? (
|
|
<div className="text-red-500 text-sm p-2 bg-red-50 rounded">
|
|
{error}
|
|
</div>
|
|
) : (
|
|
<select
|
|
value={selectedModelId}
|
|
onChange={(e) => handleChange(e.target.value)}
|
|
disabled={loading || !isAdmin}
|
|
className="w-full text-sm bg-slate-50 border border-slate-200 rounded-lg px-3 py-2 text-slate-700 focus:outline-none focus:border-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
>
|
|
<option value="">--- {t('selectVisionModel')} ---</option>
|
|
{visionModels.map(model => (
|
|
<option key={model.id} value={model.id}>
|
|
{model.name} ({model.modelId})
|
|
</option>
|
|
))}
|
|
</select>
|
|
)}
|
|
<p className="text-[10px] text-slate-400 mt-1">
|
|
{t('visionModelHelp')}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default VisionModelSelector; |