vector-inspector 0.2.6__py3-none-any.whl → 0.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. vector_inspector/config/__init__.py +4 -0
  2. vector_inspector/config/known_embedding_models.json +432 -0
  3. vector_inspector/core/cache_manager.py +159 -0
  4. vector_inspector/core/connection_manager.py +277 -0
  5. vector_inspector/core/connections/__init__.py +2 -1
  6. vector_inspector/core/connections/base_connection.py +42 -1
  7. vector_inspector/core/connections/chroma_connection.py +137 -16
  8. vector_inspector/core/connections/pinecone_connection.py +768 -0
  9. vector_inspector/core/connections/qdrant_connection.py +62 -8
  10. vector_inspector/core/embedding_providers/__init__.py +14 -0
  11. vector_inspector/core/embedding_providers/base_provider.py +128 -0
  12. vector_inspector/core/embedding_providers/clip_provider.py +260 -0
  13. vector_inspector/core/embedding_providers/provider_factory.py +176 -0
  14. vector_inspector/core/embedding_providers/sentence_transformer_provider.py +203 -0
  15. vector_inspector/core/embedding_utils.py +167 -0
  16. vector_inspector/core/model_registry.py +205 -0
  17. vector_inspector/services/backup_restore_service.py +19 -29
  18. vector_inspector/services/credential_service.py +130 -0
  19. vector_inspector/services/filter_service.py +1 -1
  20. vector_inspector/services/profile_service.py +409 -0
  21. vector_inspector/services/settings_service.py +136 -1
  22. vector_inspector/ui/components/connection_manager_panel.py +327 -0
  23. vector_inspector/ui/components/profile_manager_panel.py +565 -0
  24. vector_inspector/ui/dialogs/__init__.py +6 -0
  25. vector_inspector/ui/dialogs/cross_db_migration.py +383 -0
  26. vector_inspector/ui/dialogs/embedding_config_dialog.py +315 -0
  27. vector_inspector/ui/dialogs/provider_type_dialog.py +189 -0
  28. vector_inspector/ui/main_window.py +456 -190
  29. vector_inspector/ui/views/connection_view.py +55 -10
  30. vector_inspector/ui/views/info_panel.py +272 -55
  31. vector_inspector/ui/views/metadata_view.py +71 -3
  32. vector_inspector/ui/views/search_view.py +44 -4
  33. vector_inspector/ui/views/visualization_view.py +19 -5
  34. {vector_inspector-0.2.6.dist-info → vector_inspector-0.3.1.dist-info}/METADATA +3 -1
  35. vector_inspector-0.3.1.dist-info/RECORD +55 -0
  36. vector_inspector-0.2.6.dist-info/RECORD +0 -35
  37. {vector_inspector-0.2.6.dist-info → vector_inspector-0.3.1.dist-info}/WHEEL +0 -0
  38. {vector_inspector-0.2.6.dist-info → vector_inspector-0.3.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,565 @@
1
+ """Profile management UI for saved connection profiles."""
2
+
3
+ from typing import Optional
4
+ from PySide6.QtWidgets import (
5
+ QWidget, QVBoxLayout, QHBoxLayout, QListWidget, QListWidgetItem,
6
+ QPushButton, QMenu, QMessageBox, QLabel, QDialog, QFormLayout,
7
+ QLineEdit, QComboBox, QRadioButton, QButtonGroup, QGroupBox,
8
+ QFileDialog, QCheckBox, QProgressDialog
9
+ )
10
+ from PySide6.QtCore import Qt, Signal
11
+
12
+ from vector_inspector.services.profile_service import ProfileService, ConnectionProfile
13
+
14
+
15
+ class ProfileManagerPanel(QWidget):
16
+ """Panel for managing saved connection profiles.
17
+
18
+ Signals:
19
+ connect_profile: Emitted when user wants to connect to a profile (profile_id)
20
+ """
21
+
22
+ connect_profile = Signal(str) # profile_id
23
+
24
+ def __init__(self, profile_service: ProfileService, parent=None):
25
+ """
26
+ Initialize profile manager panel.
27
+
28
+ Args:
29
+ profile_service: The ProfileService instance
30
+ parent: Parent widget
31
+ """
32
+ super().__init__(parent)
33
+ self.profile_service = profile_service
34
+
35
+ self._setup_ui()
36
+ self._connect_signals()
37
+ self._refresh_profiles()
38
+
39
+ def _setup_ui(self):
40
+ """Setup the UI."""
41
+ layout = QVBoxLayout(self)
42
+ layout.setContentsMargins(0, 0, 0, 0)
43
+
44
+ # Header
45
+ header_layout = QHBoxLayout()
46
+ header_label = QLabel("Saved Profiles")
47
+ header_label.setStyleSheet("font-weight: bold; font-size: 12px;")
48
+ header_layout.addWidget(header_label)
49
+ header_layout.addStretch()
50
+
51
+ # New profile button
52
+ self.new_profile_btn = QPushButton("+")
53
+ self.new_profile_btn.setMaximumWidth(30)
54
+ self.new_profile_btn.setToolTip("Create new profile")
55
+ self.new_profile_btn.clicked.connect(self._create_profile)
56
+ header_layout.addWidget(self.new_profile_btn)
57
+
58
+ layout.addLayout(header_layout)
59
+
60
+ # Profile list
61
+ self.profile_list = QListWidget()
62
+ self.profile_list.setContextMenuPolicy(Qt.CustomContextMenu)
63
+ self.profile_list.customContextMenuRequested.connect(self._show_context_menu)
64
+ self.profile_list.itemDoubleClicked.connect(self._on_profile_double_clicked)
65
+ layout.addWidget(self.profile_list)
66
+
67
+ # Action buttons
68
+ button_layout = QHBoxLayout()
69
+
70
+ self.connect_btn = QPushButton("Connect")
71
+ self.connect_btn.clicked.connect(self._connect_selected_profile)
72
+ button_layout.addWidget(self.connect_btn)
73
+
74
+ self.edit_btn = QPushButton("Edit")
75
+ self.edit_btn.clicked.connect(self._edit_selected_profile)
76
+ button_layout.addWidget(self.edit_btn)
77
+
78
+ self.delete_btn = QPushButton("Delete")
79
+ self.delete_btn.clicked.connect(self._delete_selected_profile)
80
+ button_layout.addWidget(self.delete_btn)
81
+
82
+ layout.addLayout(button_layout)
83
+
84
+ def _connect_signals(self):
85
+ """Connect to profile service signals."""
86
+ self.profile_service.profile_added.connect(self._refresh_profiles)
87
+ self.profile_service.profile_updated.connect(self._refresh_profiles)
88
+ self.profile_service.profile_deleted.connect(self._refresh_profiles)
89
+
90
+ def _refresh_profiles(self):
91
+ """Refresh the profile list."""
92
+ self.profile_list.clear()
93
+
94
+ profiles = self.profile_service.get_all_profiles()
95
+ for profile in profiles:
96
+ item = QListWidgetItem(f"{profile.name} ({profile.provider})")
97
+ item.setData(Qt.UserRole, profile.id)
98
+ self.profile_list.addItem(item)
99
+
100
+ def _on_profile_double_clicked(self, item: QListWidgetItem):
101
+ """Handle profile double-click to connect."""
102
+ profile_id = item.data(Qt.UserRole)
103
+ if profile_id:
104
+ self.connect_profile.emit(profile_id)
105
+
106
+ def _connect_selected_profile(self):
107
+ """Connect to the selected profile."""
108
+ current_item = self.profile_list.currentItem()
109
+ if not current_item:
110
+ QMessageBox.warning(self, "No Selection", "Please select a profile to connect.")
111
+ return
112
+
113
+ profile_id = current_item.data(Qt.UserRole)
114
+ self.connect_profile.emit(profile_id)
115
+
116
+ def _edit_selected_profile(self):
117
+ """Edit the selected profile."""
118
+ current_item = self.profile_list.currentItem()
119
+ if not current_item:
120
+ QMessageBox.warning(self, "No Selection", "Please select a profile to edit.")
121
+ return
122
+
123
+ profile_id = current_item.data(Qt.UserRole)
124
+ profile = self.profile_service.get_profile(profile_id)
125
+ if not profile:
126
+ return
127
+
128
+ dialog = ProfileEditorDialog(self.profile_service, profile, parent=self)
129
+ dialog.exec()
130
+
131
+ def _delete_selected_profile(self):
132
+ """Delete the selected profile."""
133
+ current_item = self.profile_list.currentItem()
134
+ if not current_item:
135
+ QMessageBox.warning(self, "No Selection", "Please select a profile to delete.")
136
+ return
137
+
138
+ profile_id = current_item.data(Qt.UserRole)
139
+ profile = self.profile_service.get_profile(profile_id)
140
+ if not profile:
141
+ return
142
+
143
+ reply = QMessageBox.question(
144
+ self,
145
+ "Delete Profile",
146
+ f"Delete profile '{profile.name}'?\n\nThis will also delete any saved credentials.",
147
+ QMessageBox.Yes | QMessageBox.No
148
+ )
149
+
150
+ if reply == QMessageBox.Yes:
151
+ self.profile_service.delete_profile(profile_id)
152
+
153
+ def _create_profile(self):
154
+ """Create a new profile."""
155
+ dialog = ProfileEditorDialog(self.profile_service, parent=self)
156
+ dialog.exec()
157
+
158
+ def _show_context_menu(self, pos):
159
+ """Show context menu for profile."""
160
+ item = self.profile_list.itemAt(pos)
161
+ if not item:
162
+ return
163
+
164
+ profile_id = item.data(Qt.UserRole)
165
+ profile = self.profile_service.get_profile(profile_id)
166
+ if not profile:
167
+ return
168
+
169
+ menu = QMenu(self)
170
+
171
+ connect_action = menu.addAction("Connect")
172
+ connect_action.triggered.connect(lambda: self.connect_profile.emit(profile_id))
173
+
174
+ menu.addSeparator()
175
+
176
+ edit_action = menu.addAction("Edit")
177
+ edit_action.triggered.connect(lambda: self._edit_profile(profile_id))
178
+
179
+ duplicate_action = menu.addAction("Duplicate")
180
+ duplicate_action.triggered.connect(lambda: self._duplicate_profile(profile_id))
181
+
182
+ menu.addSeparator()
183
+
184
+ delete_action = menu.addAction("Delete")
185
+ delete_action.triggered.connect(lambda: self._delete_profile(profile_id))
186
+
187
+ menu.exec_(self.profile_list.mapToGlobal(pos))
188
+
189
+ def _edit_profile(self, profile_id: str):
190
+ """Edit a profile."""
191
+ profile = self.profile_service.get_profile(profile_id)
192
+ if profile:
193
+ dialog = ProfileEditorDialog(self.profile_service, profile, parent=self)
194
+ dialog.exec()
195
+
196
+ def _duplicate_profile(self, profile_id: str):
197
+ """Duplicate a profile."""
198
+ profile = self.profile_service.get_profile(profile_id)
199
+ if not profile:
200
+ return
201
+
202
+ from PySide6.QtWidgets import QInputDialog
203
+ new_name, ok = QInputDialog.getText(
204
+ self,
205
+ "Duplicate Profile",
206
+ "Enter name for duplicated profile:",
207
+ text=f"{profile.name} (Copy)"
208
+ )
209
+
210
+ if ok and new_name:
211
+ self.profile_service.duplicate_profile(profile_id, new_name)
212
+
213
+ def _delete_profile(self, profile_id: str):
214
+ """Delete a profile."""
215
+ profile = self.profile_service.get_profile(profile_id)
216
+ if not profile:
217
+ return
218
+
219
+ reply = QMessageBox.question(
220
+ self,
221
+ "Delete Profile",
222
+ f"Delete profile '{profile.name}'?",
223
+ QMessageBox.Yes | QMessageBox.No
224
+ )
225
+
226
+ if reply == QMessageBox.Yes:
227
+ self.profile_service.delete_profile(profile_id)
228
+
229
+
230
+ class ProfileEditorDialog(QDialog):
231
+ """Dialog for creating/editing connection profiles."""
232
+
233
+ def __init__(self, profile_service: ProfileService, profile: Optional[ConnectionProfile] = None, parent=None):
234
+ """
235
+ Initialize profile editor dialog.
236
+
237
+ Args:
238
+ profile_service: The ProfileService instance
239
+ profile: Existing profile to edit (None for new profile)
240
+ parent: Parent widget
241
+ """
242
+ super().__init__(parent)
243
+ self.profile_service = profile_service
244
+ self.profile = profile
245
+ self.is_edit_mode = profile is not None
246
+
247
+ self.setWindowTitle("Edit Profile" if self.is_edit_mode else "New Profile")
248
+ self.setMinimumWidth(500)
249
+
250
+ self._setup_ui()
251
+
252
+ if self.is_edit_mode:
253
+ self._load_profile_data()
254
+
255
+ def _setup_ui(self):
256
+ """Setup the UI."""
257
+ layout = QVBoxLayout(self)
258
+
259
+ form_layout = QFormLayout()
260
+
261
+ # Profile name
262
+ self.name_input = QLineEdit()
263
+ form_layout.addRow("Profile Name:", self.name_input)
264
+
265
+ # Provider
266
+ self.provider_combo = QComboBox()
267
+ self.provider_combo.addItem("ChromaDB", "chromadb")
268
+ self.provider_combo.addItem("Qdrant", "qdrant")
269
+ self.provider_combo.addItem("Pinecone", "pinecone")
270
+ self.provider_combo.currentIndexChanged.connect(self._on_provider_changed)
271
+ form_layout.addRow("Provider:", self.provider_combo)
272
+
273
+ layout.addLayout(form_layout)
274
+
275
+ # Connection type group
276
+ type_group = QGroupBox("Connection Type")
277
+ type_layout = QVBoxLayout()
278
+
279
+ self.button_group = QButtonGroup()
280
+
281
+ self.persistent_radio = QRadioButton("Persistent (Local File)")
282
+ self.persistent_radio.setChecked(True)
283
+ self.persistent_radio.toggled.connect(self._on_type_changed)
284
+
285
+ self.http_radio = QRadioButton("HTTP (Remote Server)")
286
+
287
+ self.ephemeral_radio = QRadioButton("Ephemeral (In-Memory)")
288
+
289
+ self.button_group.addButton(self.persistent_radio)
290
+ self.button_group.addButton(self.http_radio)
291
+ self.button_group.addButton(self.ephemeral_radio)
292
+
293
+ type_layout.addWidget(self.persistent_radio)
294
+ type_layout.addWidget(self.http_radio)
295
+ type_layout.addWidget(self.ephemeral_radio)
296
+ type_group.setLayout(type_layout)
297
+
298
+ layout.addWidget(type_group)
299
+
300
+ # Connection details
301
+ details_group = QGroupBox("Connection Details")
302
+ details_layout = QFormLayout()
303
+
304
+ # Persistent path
305
+ self.path_layout = QHBoxLayout()
306
+ self.path_input = QLineEdit()
307
+ self.path_browse_btn = QPushButton("Browse...")
308
+ self.path_browse_btn.clicked.connect(self._browse_for_path)
309
+ self.path_layout.addWidget(self.path_input)
310
+ self.path_layout.addWidget(self.path_browse_btn)
311
+ details_layout.addRow("Path:", self.path_layout)
312
+
313
+ # HTTP settings
314
+ self.host_input = QLineEdit("localhost")
315
+ details_layout.addRow("Host:", self.host_input)
316
+
317
+ self.port_input = QLineEdit("8000")
318
+ details_layout.addRow("Port:", self.port_input)
319
+
320
+ self.api_key_input = QLineEdit()
321
+ self.api_key_input.setEchoMode(QLineEdit.Password)
322
+ details_layout.addRow("API Key:", self.api_key_input)
323
+
324
+ details_group.setLayout(details_layout)
325
+ layout.addWidget(details_group)
326
+
327
+ # Test connection button
328
+ self.test_btn = QPushButton("Test Connection")
329
+ self.test_btn.clicked.connect(self._test_connection)
330
+ layout.addWidget(self.test_btn)
331
+
332
+ # Buttons
333
+ button_layout = QHBoxLayout()
334
+
335
+ self.save_btn = QPushButton("Save")
336
+ self.save_btn.clicked.connect(self._save_profile)
337
+ button_layout.addWidget(self.save_btn)
338
+
339
+ self.cancel_btn = QPushButton("Cancel")
340
+ self.cancel_btn.clicked.connect(self.reject)
341
+ button_layout.addWidget(self.cancel_btn)
342
+
343
+ layout.addLayout(button_layout)
344
+
345
+ # Initial state
346
+ self._on_type_changed()
347
+
348
+ def _on_provider_changed(self):
349
+ """Handle provider change."""
350
+ provider = self.provider_combo.currentData()
351
+
352
+ # Update default port
353
+ if provider == "qdrant":
354
+ if self.port_input.text() == "8000":
355
+ self.port_input.setText("6333")
356
+ elif provider == "chromadb":
357
+ if self.port_input.text() == "6333":
358
+ self.port_input.setText("8000")
359
+
360
+ # For Pinecone, disable persistent/ephemeral modes and only show API key
361
+ if provider == "pinecone":
362
+ self.persistent_radio.setEnabled(False)
363
+ self.http_radio.setEnabled(True)
364
+ self.http_radio.setChecked(True)
365
+ self.ephemeral_radio.setEnabled(False)
366
+ self.path_input.setEnabled(False)
367
+ self.path_browse_btn.setEnabled(False)
368
+ self.host_input.setEnabled(False)
369
+ self.port_input.setEnabled(False)
370
+ self.api_key_input.setEnabled(True)
371
+ else:
372
+ self.persistent_radio.setEnabled(True)
373
+ self.http_radio.setEnabled(True)
374
+ self.ephemeral_radio.setEnabled(True)
375
+ # Show/hide API key field
376
+ is_http = self.http_radio.isChecked()
377
+ self.api_key_input.setEnabled(is_http and provider == "qdrant")
378
+ # Update other fields based on connection type
379
+ self._on_type_changed()
380
+
381
+ def _on_type_changed(self):
382
+ """Handle connection type change."""
383
+ is_persistent = self.persistent_radio.isChecked()
384
+ is_http = self.http_radio.isChecked()
385
+
386
+ provider = self.provider_combo.currentData()
387
+
388
+ # Pinecone always uses API key, no path/host/port
389
+ if provider == "pinecone":
390
+ self.path_input.setEnabled(False)
391
+ self.path_browse_btn.setEnabled(False)
392
+ self.host_input.setEnabled(False)
393
+ self.port_input.setEnabled(False)
394
+ self.api_key_input.setEnabled(True)
395
+ else:
396
+ # Show/hide relevant fields
397
+ self.path_input.setEnabled(is_persistent)
398
+ self.path_browse_btn.setEnabled(is_persistent)
399
+ self.host_input.setEnabled(is_http)
400
+ self.port_input.setEnabled(is_http)
401
+ self.api_key_input.setEnabled(is_http and provider == "qdrant")
402
+
403
+ def _browse_for_path(self):
404
+ """Browse for persistent storage path."""
405
+ path = QFileDialog.getExistingDirectory(
406
+ self,
407
+ "Select Database Directory",
408
+ self.path_input.text()
409
+ )
410
+ if path:
411
+ self.path_input.setText(path)
412
+
413
+ def _load_profile_data(self):
414
+ """Load existing profile data into form."""
415
+ if not self.profile:
416
+ return
417
+
418
+ # Get profile with credentials
419
+ profile_data = self.profile_service.get_profile_with_credentials(self.profile.id)
420
+ if not profile_data:
421
+ return
422
+
423
+ self.name_input.setText(profile_data["name"])
424
+
425
+ # Set provider
426
+ index = self.provider_combo.findData(profile_data["provider"])
427
+ if index >= 0:
428
+ self.provider_combo.setCurrentIndex(index)
429
+
430
+ config = profile_data.get("config", {})
431
+ conn_type = config.get("type", "persistent")
432
+
433
+ # Set connection type
434
+ if conn_type == "cloud":
435
+ # Pinecone cloud connection
436
+ self.http_radio.setChecked(True)
437
+ elif conn_type == "persistent":
438
+ self.persistent_radio.setChecked(True)
439
+ self.path_input.setText(config.get("path", ""))
440
+ elif conn_type == "http":
441
+ self.http_radio.setChecked(True)
442
+ self.host_input.setText(config.get("host", "localhost"))
443
+ self.port_input.setText(str(config.get("port", "8000")))
444
+ else:
445
+ self.ephemeral_radio.setChecked(True)
446
+
447
+ # Load credentials
448
+ credentials = profile_data.get("credentials", {})
449
+ if "api_key" in credentials:
450
+ self.api_key_input.setText(credentials["api_key"])
451
+
452
+ def _test_connection(self):
453
+ """Test the connection with current settings."""
454
+ # Get config
455
+ config = self._get_config()
456
+ provider = self.provider_combo.currentData()
457
+
458
+ # Create connection
459
+ from vector_inspector.core.connections.chroma_connection import ChromaDBConnection
460
+ from vector_inspector.core.connections.qdrant_connection import QdrantConnection
461
+ from vector_inspector.core.connections.pinecone_connection import PineconeConnection
462
+
463
+ try:
464
+ if provider == "pinecone":
465
+ api_key = self.api_key_input.text()
466
+ if not api_key:
467
+ QMessageBox.warning(self, "Missing API Key", "Pinecone requires an API key.")
468
+ return
469
+ conn = PineconeConnection(api_key=api_key)
470
+ elif provider == "chromadb":
471
+ conn = ChromaDBConnection(**self._get_connection_kwargs(config))
472
+ else:
473
+ conn = QdrantConnection(**self._get_connection_kwargs(config))
474
+
475
+ # Test connection
476
+ progress = QProgressDialog("Testing connection...", None, 0, 0, self)
477
+ progress.setWindowModality(Qt.WindowModal)
478
+ progress.show()
479
+
480
+ success = conn.connect()
481
+ progress.close()
482
+
483
+ if success:
484
+ QMessageBox.information(self, "Success", "Connection test successful!")
485
+ conn.disconnect()
486
+ else:
487
+ QMessageBox.warning(self, "Failed", "Connection test failed.")
488
+ except Exception as e:
489
+ QMessageBox.critical(self, "Error", f"Connection test error: {e}")
490
+
491
+ def _get_config(self) -> dict:
492
+ """Get configuration from form."""
493
+ config = {}
494
+ provider = self.provider_combo.currentData()
495
+
496
+ # Pinecone uses cloud connection type
497
+ if provider == "pinecone":
498
+ config["type"] = "cloud"
499
+ elif self.persistent_radio.isChecked():
500
+ config["type"] = "persistent"
501
+ config["path"] = self.path_input.text()
502
+ elif self.http_radio.isChecked():
503
+ config["type"] = "http"
504
+ config["host"] = self.host_input.text()
505
+ config["port"] = int(self.port_input.text())
506
+ else:
507
+ config["type"] = "ephemeral"
508
+
509
+ return config
510
+
511
+ def _get_connection_kwargs(self, config: dict) -> dict:
512
+ """Get kwargs for creating connection."""
513
+ kwargs = {}
514
+
515
+ if config["type"] == "persistent":
516
+ kwargs["path"] = config["path"]
517
+ elif config["type"] == "http":
518
+ kwargs["host"] = config["host"]
519
+ kwargs["port"] = config["port"]
520
+ if self.api_key_input.text():
521
+ kwargs["api_key"] = self.api_key_input.text()
522
+
523
+ return kwargs
524
+
525
+ def _save_profile(self):
526
+ """Save the profile."""
527
+ name = self.name_input.text().strip()
528
+ if not name:
529
+ QMessageBox.warning(self, "Invalid Input", "Please enter a profile name.")
530
+ return
531
+
532
+ provider = self.provider_combo.currentData()
533
+ config = self._get_config()
534
+
535
+ # Get credentials
536
+ credentials = {}
537
+ if provider == "pinecone":
538
+ # Pinecone always requires API key
539
+ if self.api_key_input.text():
540
+ credentials["api_key"] = self.api_key_input.text()
541
+ else:
542
+ QMessageBox.warning(self, "Missing API Key", "Pinecone requires an API key.")
543
+ return
544
+ elif self.api_key_input.text() and self.http_radio.isChecked():
545
+ credentials["api_key"] = self.api_key_input.text()
546
+
547
+ if self.is_edit_mode:
548
+ # Update existing profile
549
+ self.profile_service.update_profile(
550
+ self.profile.id,
551
+ name=name,
552
+ config=config,
553
+ credentials=credentials if credentials else None
554
+ )
555
+ else:
556
+ # Create new profile
557
+ self.profile_service.create_profile(
558
+ name=name,
559
+ provider=provider,
560
+ config=config,
561
+ credentials=credentials if credentials else None
562
+ )
563
+
564
+ self.accept()
565
+
@@ -0,0 +1,6 @@
1
+ """UI Dialogs for vector-inspector."""
2
+
3
+ from .embedding_config_dialog import EmbeddingConfigDialog
4
+ from .provider_type_dialog import ProviderTypeDialog
5
+
6
+ __all__ = ['EmbeddingConfigDialog', 'ProviderTypeDialog']