vectorplasticity commited on
Commit
cbd0089
·
verified ·
1 Parent(s): 66ee273

Fix search API calls - use correct parameter name 'query' instead of 'q'

Browse files
Files changed (1) hide show
  1. app/templates/dashboard.html +250 -20
app/templates/dashboard.html CHANGED
@@ -180,6 +180,24 @@
180
  border-radius: 10px;
181
  font-size: 0.85rem;
182
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  </style>
184
  </head>
185
  <body>
@@ -415,7 +433,7 @@
415
  <div class="col-md-8">
416
  <div class="search-box mb-3">
417
  <i class="bi bi-search"></i>
418
- <input type="text" class="form-control" id="model-search" placeholder="Search models...">
419
  </div>
420
  <input type="hidden" id="selected-model" name="model_name" required>
421
  </div>
@@ -427,6 +445,7 @@
427
  </div>
428
  <div id="model-results" class="row g-2 mt-2"></div>
429
  <div id="model-info" class="mt-3" style="display: none;"></div>
 
430
  </div>
431
 
432
  <!-- Step 3: Dataset Selection -->
@@ -436,7 +455,7 @@
436
  <div class="col-md-8">
437
  <div class="search-box mb-3">
438
  <i class="bi bi-search"></i>
439
- <input type="text" class="form-control" id="dataset-search" placeholder="Search datasets...">
440
  </div>
441
  <input type="hidden" id="selected-dataset" name="dataset_name" required>
442
  </div>
@@ -448,6 +467,7 @@
448
  </div>
449
  <div id="dataset-results" class="row g-2 mt-2"></div>
450
  <div id="dataset-config" class="mt-3" style="display: none;"></div>
 
451
  </div>
452
 
453
  <!-- Step 4: Training Configuration -->
@@ -624,7 +644,20 @@
624
  <i class="bi bi-box me-2"></i>Browse Models
625
  </div>
626
  <div class="card-body">
627
- <p class="text-muted">Search and select models from HuggingFace Hub</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
628
  </div>
629
  </div>
630
  </div>
@@ -636,7 +669,20 @@
636
  <i class="bi bi-database me-2"></i>Browse Datasets
637
  </div>
638
  <div class="card-body">
639
- <p class="text-muted">Search and select datasets from HuggingFace Hub</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
640
  </div>
641
  </div>
642
  </div>
@@ -679,6 +725,9 @@
679
  document.getElementById('section-' + sectionId).style.display = 'block';
680
  if (sectionId === 'dashboard') loadDashboard();
681
  if (sectionId === 'jobs') loadJobs();
 
 
 
682
  }
683
 
684
  async function loadDashboard() {
@@ -724,23 +773,69 @@
724
  document.querySelectorAll('.task-card').forEach(card => card.classList.remove('selected'));
725
  document.querySelector('.task-card[data-task="' + task + '"]').classList.add('selected');
726
  document.getElementById('selected-task').value = task;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
727
  }
728
 
729
  async function searchModels() {
730
- const query = document.getElementById('model-search').value;
731
- if (!query) return;
 
 
 
 
 
 
732
  try {
733
- const res = await fetch(API_BASE + '/models/search?q=' + encodeURIComponent(query) + '&task=' + (selectedTask || ''));
 
 
 
734
  const data = await res.json();
735
- renderModelResults(data.models || []);
 
736
  } catch (error) {
737
  console.error('Error searching models:', error);
 
738
  }
739
  }
740
 
741
  function renderModelResults(models) {
742
  const container = document.getElementById('model-results');
743
- container.innerHTML = models.slice(0, 12).map(model => '<div class="col-md-3"><div class="card task-card" onclick="selectModel(\'' + model.id + '\')"><div class="card-body py-2"><small class="fw-bold">' + model.id + '</small><br><small class="text-muted">' + formatBytes(model.size_bytes || 0) + '</small></div></div></div>').join('');
 
 
 
 
744
  }
745
 
746
  async function selectModel(modelId) {
@@ -748,31 +843,54 @@
748
  document.getElementById('selected-model').value = modelId;
749
  document.querySelectorAll('#model-results .task-card').forEach(card => card.classList.remove('selected'));
750
  if (event.currentTarget) event.currentTarget.classList.add('selected');
 
 
 
 
 
751
  try {
752
- const res = await fetch(API_BASE + '/models/' + encodeURIComponent(modelId) + '/info');
753
- const info = await res.json();
754
- const container = document.getElementById('model-info');
755
- container.style.display = 'block';
756
- container.innerHTML = '<div class="card"><div class="card-body"><h6>' + info.model_id + '</h6><div class="row"><div class="col-6"><small class="text-muted">Parameters:</small></div><div class="col-6 text-end"><small>' + (info.num_parameters || 'Unknown') + '</small></div></div><div class="row"><div class="col-6"><small class="text-muted">Architecture:</small></div><div class="col-6 text-end"><small>' + (info.architectures?.[0] || 'Unknown') + '</small></div></div></div></div>';
 
 
757
  } catch (error) {
758
  console.error('Error loading model info:', error);
 
759
  }
760
  }
761
 
762
  async function searchDatasets() {
763
- const query = document.getElementById('dataset-search').value;
764
- if (!query) return;
 
 
 
 
 
 
765
  try {
766
- const res = await fetch(API_BASE + '/datasets/search?q=' + encodeURIComponent(query));
 
 
 
767
  const data = await res.json();
768
- renderDatasetResults(data.datasets || []);
 
769
  } catch (error) {
770
  console.error('Error searching datasets:', error);
 
771
  }
772
  }
773
 
774
  function renderDatasetResults(datasets) {
775
  const container = document.getElementById('dataset-results');
 
 
 
 
776
  container.innerHTML = datasets.slice(0, 12).map(ds => '<div class="col-md-3"><div class="card task-card" onclick="selectDataset(\'' + ds.id + '\')"><div class="card-body py-2"><small class="fw-bold">' + ds.id + '</small><br><small class="text-muted">' + (ds.downloads?.toLocaleString() || 0) + ' downloads</small></div></div></div>').join('');
777
  }
778
 
@@ -783,6 +901,104 @@
783
  if (event.currentTarget) event.currentTarget.classList.add('selected');
784
  }
785
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
786
  async function loadJobs() {
787
  try {
788
  const res = await fetch(API_BASE + '/jobs/');
@@ -816,6 +1032,20 @@
816
 
817
  document.getElementById('training-form').addEventListener('submit', async (e) => {
818
  e.preventDefault();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
819
  const formData = {
820
  task_type: selectedTask,
821
  model_name: selectedModel,
@@ -845,11 +1075,11 @@
845
  alert('Training started! Job ID: ' + data.job_id);
846
  showSection('jobs');
847
  } else {
848
- alert('Error starting training: ' + (data.error || 'Unknown error'));
849
  }
850
  } catch (error) {
851
  console.error('Error starting training:', error);
852
- alert('Error starting training');
853
  }
854
  });
855
 
 
180
  border-radius: 10px;
181
  font-size: 0.85rem;
182
  }
183
+ .search-loading {
184
+ opacity: 0.6;
185
+ pointer-events: none;
186
+ }
187
+ .error-message {
188
+ background: #ffebee;
189
+ color: #c62828;
190
+ padding: 10px 15px;
191
+ border-radius: 8px;
192
+ margin-top: 10px;
193
+ }
194
+ .success-message {
195
+ background: #e8f5e9;
196
+ color: #2e7d32;
197
+ padding: 10px 15px;
198
+ border-radius: 8px;
199
+ margin-top: 10px;
200
+ }
201
  </style>
202
  </head>
203
  <body>
 
433
  <div class="col-md-8">
434
  <div class="search-box mb-3">
435
  <i class="bi bi-search"></i>
436
+ <input type="text" class="form-control" id="model-search" placeholder="Search models (e.g., gpt2, bert, llama)...">
437
  </div>
438
  <input type="hidden" id="selected-model" name="model_name" required>
439
  </div>
 
445
  </div>
446
  <div id="model-results" class="row g-2 mt-2"></div>
447
  <div id="model-info" class="mt-3" style="display: none;"></div>
448
+ <div id="model-recommendations" class="mt-3"></div>
449
  </div>
450
 
451
  <!-- Step 3: Dataset Selection -->
 
455
  <div class="col-md-8">
456
  <div class="search-box mb-3">
457
  <i class="bi bi-search"></i>
458
+ <input type="text" class="form-control" id="dataset-search" placeholder="Search datasets (e.g., squad, imdb, wikitext)...">
459
  </div>
460
  <input type="hidden" id="selected-dataset" name="dataset_name" required>
461
  </div>
 
467
  </div>
468
  <div id="dataset-results" class="row g-2 mt-2"></div>
469
  <div id="dataset-config" class="mt-3" style="display: none;"></div>
470
+ <div id="dataset-recommendations" class="mt-3"></div>
471
  </div>
472
 
473
  <!-- Step 4: Training Configuration -->
 
644
  <i class="bi bi-box me-2"></i>Browse Models
645
  </div>
646
  <div class="card-body">
647
+ <div class="row mb-3">
648
+ <div class="col-md-8">
649
+ <div class="search-box">
650
+ <i class="bi bi-search"></i>
651
+ <input type="text" class="form-control" id="models-page-search" placeholder="Search models...">
652
+ </div>
653
+ </div>
654
+ <div class="col-md-4">
655
+ <button type="button" class="btn btn-primary w-100" onclick="searchModelsPage()">
656
+ <i class="bi bi-search me-1"></i>Search
657
+ </button>
658
+ </div>
659
+ </div>
660
+ <div id="models-page-results" class="row g-3"></div>
661
  </div>
662
  </div>
663
  </div>
 
669
  <i class="bi bi-database me-2"></i>Browse Datasets
670
  </div>
671
  <div class="card-body">
672
+ <div class="row mb-3">
673
+ <div class="col-md-8">
674
+ <div class="search-box">
675
+ <i class="bi bi-search"></i>
676
+ <input type="text" class="form-control" id="datasets-page-search" placeholder="Search datasets...">
677
+ </div>
678
+ </div>
679
+ <div class="col-md-4">
680
+ <button type="button" class="btn btn-primary w-100" onclick="searchDatasetsPage()">
681
+ <i class="bi bi-search me-1"></i>Search
682
+ </button>
683
+ </div>
684
+ </div>
685
+ <div id="datasets-page-results" class="row g-3"></div>
686
  </div>
687
  </div>
688
  </div>
 
725
  document.getElementById('section-' + sectionId).style.display = 'block';
726
  if (sectionId === 'dashboard') loadDashboard();
727
  if (sectionId === 'jobs') loadJobs();
728
+ if (sectionId === 'new-training') loadRecommendations();
729
+ if (sectionId === 'models') loadPopularModels();
730
+ if (sectionId === 'datasets') loadPopularDatasets();
731
  }
732
 
733
  async function loadDashboard() {
 
773
  document.querySelectorAll('.task-card').forEach(card => card.classList.remove('selected'));
774
  document.querySelector('.task-card[data-task="' + task + '"]').classList.add('selected');
775
  document.getElementById('selected-task').value = task;
776
+ loadRecommendations();
777
+ }
778
+
779
+ async function loadRecommendations() {
780
+ if (!selectedTask) return;
781
+
782
+ try {
783
+ // Load model recommendations
784
+ const modelRecRes = await fetch(API_BASE + '/models/recommend/' + selectedTask);
785
+ if (modelRecRes.ok) {
786
+ const modelRecs = await modelRecRes.json();
787
+ const modelContainer = document.getElementById('model-recommendations');
788
+ if (modelRecs && modelRecs.length > 0) {
789
+ modelContainer.innerHTML = '<h6 class="mb-2">Recommended Models:</h6><div class="row g-2">' +
790
+ modelRecs.slice(0, 4).map(m => '<div class="col-md-3"><div class="card task-card" onclick="selectModel(\'' + m.model_id + '\')"><div class="card-body py-2"><small class="fw-bold">' + m.model_id + '</small><br><small class="text-muted">' + (m.size || '') + '</small></div></div></div>').join('') + '</div>';
791
+ }
792
+ }
793
+
794
+ // Load dataset recommendations
795
+ const datasetRecRes = await fetch(API_BASE + '/datasets/recommend/' + selectedTask);
796
+ if (datasetRecRes.ok) {
797
+ const datasetRecs = await datasetRecRes.json();
798
+ const datasetContainer = document.getElementById('dataset-recommendations');
799
+ if (datasetRecs && datasetRecs.length > 0) {
800
+ datasetContainer.innerHTML = '<h6 class="mb-2">Recommended Datasets:</h6><div class="row g-2">' +
801
+ datasetRecs.slice(0, 4).map(d => '<div class="col-md-3"><div class="card task-card" onclick="selectDataset(\'' + d.dataset_id + '\')"><div class="card-body py-2"><small class="fw-bold">' + d.dataset_id + '</small><br><small class="text-muted">' + (d.size || '') + '</small></div></div></div>').join('') + '</div>';
802
+ }
803
+ }
804
+ } catch (error) {
805
+ console.error('Error loading recommendations:', error);
806
+ }
807
  }
808
 
809
  async function searchModels() {
810
+ const query = document.getElementById('model-search').value.trim();
811
+ if (!query) {
812
+ alert('Please enter a search term');
813
+ return;
814
+ }
815
+ const container = document.getElementById('model-results');
816
+ container.innerHTML = '<div class="col-12 text-center"><div class="spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div></div>';
817
+
818
  try {
819
+ const res = await fetch(API_BASE + '/models/search?query=' + encodeURIComponent(query) + '&limit=12');
820
+ if (!res.ok) {
821
+ throw new Error('Search failed: ' + res.status);
822
+ }
823
  const data = await res.json();
824
+ console.log('Model search results:', data);
825
+ renderModelResults(data);
826
  } catch (error) {
827
  console.error('Error searching models:', error);
828
+ container.innerHTML = '<div class="col-12"><div class="error-message"><i class="bi bi-exclamation-triangle me-2"></i>Error searching models: ' + error.message + '</div></div>';
829
  }
830
  }
831
 
832
  function renderModelResults(models) {
833
  const container = document.getElementById('model-results');
834
+ if (!models || models.length === 0) {
835
+ container.innerHTML = '<div class="col-12 text-center text-muted py-3"><i class="bi bi-search fs-1 d-block mb-2"></i>No models found. Try a different search term.</div>';
836
+ return;
837
+ }
838
+ container.innerHTML = models.slice(0, 12).map(model => '<div class="col-md-3"><div class="card task-card" onclick="selectModel(\'' + (model.id || model.model_id) + '\')"><div class="card-body py-2"><small class="fw-bold">' + (model.id || model.model_id) + '</small><br><small class="text-muted">' + formatBytes(model.size_bytes || model.downloads || 0) + '</small></div></div></div>').join('');
839
  }
840
 
841
  async function selectModel(modelId) {
 
843
  document.getElementById('selected-model').value = modelId;
844
  document.querySelectorAll('#model-results .task-card').forEach(card => card.classList.remove('selected'));
845
  if (event.currentTarget) event.currentTarget.classList.add('selected');
846
+
847
+ const container = document.getElementById('model-info');
848
+ container.style.display = 'block';
849
+ container.innerHTML = '<div class="card"><div class="card-body"><div class="spinner-border spinner-border-sm" role="status"></div> Loading model info...</div></div>';
850
+
851
  try {
852
+ const res = await fetch(API_BASE + '/models/info/' + encodeURIComponent(modelId));
853
+ if (res.ok) {
854
+ const info = await res.json();
855
+ container.innerHTML = '<div class="card"><div class="card-body"><h6>' + info.model_id + '</h6><div class="row"><div class="col-6"><small class="text-muted">Downloads:</small></div><div class="col-6 text-end"><small>' + (info.downloads?.toLocaleString() || 'N/A') + '</small></div></div><div class="row"><div class="col-6"><small class="text-muted">Architecture:</small></div><div class="col-6 text-end"><small>' + (info.architectures?.[0] || info.architecture || 'Unknown') + '</small></div></div><div class="row"><div class="col-6"><small class="text-muted">Pipeline Tag:</small></div><div class="col-6 text-end"><small>' + (info.pipeline_tag || 'N/A') + '</small></div></div></div></div>';
856
+ } else {
857
+ container.innerHTML = '<div class="card"><div class="card-body"><small class="text-muted">Selected: ' + modelId + '</small></div></div>';
858
+ }
859
  } catch (error) {
860
  console.error('Error loading model info:', error);
861
+ container.innerHTML = '<div class="card"><div class="card-body"><small class="text-muted">Selected: ' + modelId + '</small></div></div>';
862
  }
863
  }
864
 
865
  async function searchDatasets() {
866
+ const query = document.getElementById('dataset-search').value.trim();
867
+ if (!query) {
868
+ alert('Please enter a search term');
869
+ return;
870
+ }
871
+ const container = document.getElementById('dataset-results');
872
+ container.innerHTML = '<div class="col-12 text-center"><div class="spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div></div>';
873
+
874
  try {
875
+ const res = await fetch(API_BASE + '/datasets/search?query=' + encodeURIComponent(query) + '&limit=12');
876
+ if (!res.ok) {
877
+ throw new Error('Search failed: ' + res.status);
878
+ }
879
  const data = await res.json();
880
+ console.log('Dataset search results:', data);
881
+ renderDatasetResults(data);
882
  } catch (error) {
883
  console.error('Error searching datasets:', error);
884
+ container.innerHTML = '<div class="col-12"><div class="error-message"><i class="bi bi-exclamation-triangle me-2"></i>Error searching datasets: ' + error.message + '</div></div>';
885
  }
886
  }
887
 
888
  function renderDatasetResults(datasets) {
889
  const container = document.getElementById('dataset-results');
890
+ if (!datasets || datasets.length === 0) {
891
+ container.innerHTML = '<div class="col-12 text-center text-muted py-3"><i class="bi bi-search fs-1 d-block mb-2"></i>No datasets found. Try a different search term.</div>';
892
+ return;
893
+ }
894
  container.innerHTML = datasets.slice(0, 12).map(ds => '<div class="col-md-3"><div class="card task-card" onclick="selectDataset(\'' + ds.id + '\')"><div class="card-body py-2"><small class="fw-bold">' + ds.id + '</small><br><small class="text-muted">' + (ds.downloads?.toLocaleString() || 0) + ' downloads</small></div></div></div>').join('');
895
  }
896
 
 
901
  if (event.currentTarget) event.currentTarget.classList.add('selected');
902
  }
903
 
904
+ async function loadPopularModels() {
905
+ const container = document.getElementById('models-page-results');
906
+ container.innerHTML = '<div class="col-12 text-center"><div class="spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div></div>';
907
+
908
+ try {
909
+ const res = await fetch(API_BASE + '/models/popular?limit=20');
910
+ if (res.ok) {
911
+ const data = await res.json();
912
+ renderModelsPage(data);
913
+ } else {
914
+ container.innerHTML = '<div class="col-12 text-center text-muted">No models found</div>';
915
+ }
916
+ } catch (error) {
917
+ console.error('Error loading popular models:', error);
918
+ container.innerHTML = '<div class="col-12 text-center text-muted">Error loading models</div>';
919
+ }
920
+ }
921
+
922
+ async function searchModelsPage() {
923
+ const query = document.getElementById('models-page-search').value.trim();
924
+ if (!query) {
925
+ loadPopularModels();
926
+ return;
927
+ }
928
+ const container = document.getElementById('models-page-results');
929
+ container.innerHTML = '<div class="col-12 text-center"><div class="spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div></div>';
930
+
931
+ try {
932
+ const res = await fetch(API_BASE + '/models/search?query=' + encodeURIComponent(query) + '&limit=20');
933
+ if (res.ok) {
934
+ const data = await res.json();
935
+ renderModelsPage(data);
936
+ } else {
937
+ container.innerHTML = '<div class="col-12 text-center text-muted">No models found</div>';
938
+ }
939
+ } catch (error) {
940
+ console.error('Error searching models:', error);
941
+ }
942
+ }
943
+
944
+ function renderModelsPage(models) {
945
+ const container = document.getElementById('models-page-results');
946
+ if (!models || models.length === 0) {
947
+ container.innerHTML = '<div class="col-12 text-center text-muted py-3">No models found</div>';
948
+ return;
949
+ }
950
+ container.innerHTML = models.map(m => '<div class="col-md-3"><div class="card model-card"><div class="card-body"><h6>' + (m.id || m.model_id) + '</h6><small class="text-muted d-block">' + (m.pipeline_tag || 'Unknown') + '</small><small class="text-muted">' + (m.downloads?.toLocaleString() || 0) + ' downloads</small></div></div></div>').join('');
951
+ }
952
+
953
+ async function loadPopularDatasets() {
954
+ const container = document.getElementById('datasets-page-results');
955
+ container.innerHTML = '<div class="col-12 text-center"><div class="spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div></div>';
956
+
957
+ try {
958
+ const res = await fetch(API_BASE + '/datasets/popular?limit=20');
959
+ if (res.ok) {
960
+ const data = await res.json();
961
+ renderDatasetsPage(data);
962
+ } else {
963
+ container.innerHTML = '<div class="col-12 text-center text-muted">No datasets found</div>';
964
+ }
965
+ } catch (error) {
966
+ console.error('Error loading popular datasets:', error);
967
+ container.innerHTML = '<div class="col-12 text-center text-muted">Error loading datasets</div>';
968
+ }
969
+ }
970
+
971
+ async function searchDatasetsPage() {
972
+ const query = document.getElementById('datasets-page-search').value.trim();
973
+ if (!query) {
974
+ loadPopularDatasets();
975
+ return;
976
+ }
977
+ const container = document.getElementById('datasets-page-results');
978
+ container.innerHTML = '<div class="col-12 text-center"><div class="spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div></div>';
979
+
980
+ try {
981
+ const res = await fetch(API_BASE + '/datasets/search?query=' + encodeURIComponent(query) + '&limit=20');
982
+ if (res.ok) {
983
+ const data = await res.json();
984
+ renderDatasetsPage(data);
985
+ } else {
986
+ container.innerHTML = '<div class="col-12 text-center text-muted">No datasets found</div>';
987
+ }
988
+ } catch (error) {
989
+ console.error('Error searching datasets:', error);
990
+ }
991
+ }
992
+
993
+ function renderDatasetsPage(datasets) {
994
+ const container = document.getElementById('datasets-page-results');
995
+ if (!datasets || datasets.length === 0) {
996
+ container.innerHTML = '<div class="col-12 text-center text-muted py-3">No datasets found</div>';
997
+ return;
998
+ }
999
+ container.innerHTML = datasets.map(d => '<div class="col-md-3"><div class="card model-card"><div class="card-body"><h6>' + (d.id || d.dataset_id) + '</h6><small class="text-muted d-block">' + (d.description?.substring(0, 50) || 'No description') + '</small><small class="text-muted">' + (d.downloads?.toLocaleString() || 0) + ' downloads</small></div></div></div>').join('');
1000
+ }
1001
+
1002
  async function loadJobs() {
1003
  try {
1004
  const res = await fetch(API_BASE + '/jobs/');
 
1032
 
1033
  document.getElementById('training-form').addEventListener('submit', async (e) => {
1034
  e.preventDefault();
1035
+
1036
+ if (!selectedTask) {
1037
+ alert('Please select a task type');
1038
+ return;
1039
+ }
1040
+ if (!selectedModel) {
1041
+ alert('Please select a model');
1042
+ return;
1043
+ }
1044
+ if (!selectedDataset) {
1045
+ alert('Please select a dataset');
1046
+ return;
1047
+ }
1048
+
1049
  const formData = {
1050
  task_type: selectedTask,
1051
  model_name: selectedModel,
 
1075
  alert('Training started! Job ID: ' + data.job_id);
1076
  showSection('jobs');
1077
  } else {
1078
+ alert('Error starting training: ' + (data.detail || data.error || 'Unknown error'));
1079
  }
1080
  } catch (error) {
1081
  console.error('Error starting training:', error);
1082
+ alert('Error starting training: ' + error.message);
1083
  }
1084
  });
1085