VisionModelSelector.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  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="">
  71. {loading ? t('loading') : visionModels.length === 0 ? t('noVisionModels') : `--- ${t('selectVisionModel')} ---`}
  72. </option>
  73. {visionModels.map(model => (
  74. <option key={model.id} value={model.id}>
  75. {model.name} ({model.modelId})
  76. </option>
  77. ))}
  78. </select>
  79. )}
  80. <p className="text-[10px] text-slate-400 mt-1">
  81. {t('visionModelHelp')}
  82. </p>
  83. </div>
  84. </div>
  85. );
  86. };
  87. export default VisionModelSelector;