VisionModelSelector.tsx 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import React, { useState, useEffect } from 'react';
  2. import { Eye } from 'lucide-react';
  3. import { settingsService } from '../services/settingsService';
  4. import { useLanguage } from '../contexts/LanguageContext';
  5. interface VisionModel {
  6. id: string;
  7. name: string;
  8. modelId: string;
  9. }
  10. interface VisionModelSelectorProps {
  11. isAdmin?: boolean;
  12. }
  13. const VisionModelSelector: React.FC<VisionModelSelectorProps> = ({ isAdmin = false }) => {
  14. const { t } = useLanguage();
  15. const [visionModels, setVisionModels] = useState<VisionModel[]>([]);
  16. const [selectedModelId, setSelectedModelId] = useState<string>('');
  17. const [loading, setLoading] = useState(true);
  18. const [error, setError] = useState<string>('');
  19. useEffect(() => {
  20. loadData();
  21. }, []);
  22. const loadData = async () => {
  23. try {
  24. setLoading(true);
  25. setError('');
  26. const [models, current] = await Promise.all([
  27. settingsService.getVisionModels(),
  28. settingsService.getVisionModel()
  29. ]);
  30. console.log('Vision models loaded:', models);
  31. console.log('Current vision model:', current);
  32. setVisionModels(models || []);
  33. setSelectedModelId(current?.visionModelId || '');
  34. } catch (error) {
  35. console.error(t('loadVisionModelFailed'), error);
  36. setError(t('loadFailed'));
  37. } finally {
  38. setLoading(false);
  39. }
  40. };
  41. const handleChange = async (modelId: string) => {
  42. try {
  43. setSelectedModelId(modelId);
  44. await settingsService.updateVisionModel(modelId);
  45. } catch (error) {
  46. console.error(t('saveVisionModelFailed'), error);
  47. }
  48. };
  49. return (
  50. <div className="bg-white p-4 rounded-xl border border-slate-200 shadow-sm">
  51. <div className="flex items-center gap-2 mb-4 text-slate-800 font-semibold border-b border-slate-100 pb-2">
  52. <Eye className="w-4 h-4 text-purple-600" />
  53. {t('visionModelSettings')}
  54. </div>
  55. <div>
  56. <label className="block text-xs font-medium text-slate-500 mb-1.5">
  57. {t('defaultVisionModel')}
  58. </label>
  59. {error ? (
  60. <div className="text-red-500 text-sm p-2 bg-red-50 rounded">
  61. {error}
  62. </div>
  63. ) : (
  64. <select
  65. value={selectedModelId}
  66. onChange={(e) => handleChange(e.target.value)}
  67. disabled={loading || !isAdmin}
  68. 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"
  69. >
  70. <option value="">--- {t('selectVisionModel')} ---</option>
  71. {visionModels.map(model => (
  72. <option key={model.id} value={model.id}>
  73. {model.name} ({model.modelId})
  74. </option>
  75. ))}
  76. </select>
  77. )}
  78. <p className="text-[10px] text-slate-400 mt-1">
  79. {t('visionModelHelp')}
  80. </p>
  81. </div>
  82. </div>
  83. );
  84. };
  85. export default VisionModelSelector;