vector-inspector 0.3.11__py3-none-any.whl → 0.3.12__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 (30) hide show
  1. vector_inspector/__init__.py +1 -1
  2. vector_inspector/core/connection_manager.py +91 -19
  3. vector_inspector/core/connections/base_connection.py +43 -43
  4. vector_inspector/core/connections/chroma_connection.py +1 -1
  5. vector_inspector/core/connections/pgvector_connection.py +11 -171
  6. vector_inspector/core/connections/pinecone_connection.py +596 -99
  7. vector_inspector/core/connections/qdrant_connection.py +35 -44
  8. vector_inspector/core/embedding_utils.py +14 -5
  9. vector_inspector/core/logging.py +3 -1
  10. vector_inspector/main.py +42 -15
  11. vector_inspector/services/backup_restore_service.py +228 -15
  12. vector_inspector/services/settings_service.py +71 -19
  13. vector_inspector/ui/components/backup_restore_dialog.py +215 -101
  14. vector_inspector/ui/components/connection_manager_panel.py +155 -14
  15. vector_inspector/ui/dialogs/cross_db_migration.py +126 -99
  16. vector_inspector/ui/dialogs/settings_dialog.py +13 -6
  17. vector_inspector/ui/loading_screen.py +169 -0
  18. vector_inspector/ui/main_window.py +44 -19
  19. vector_inspector/ui/services/dialog_service.py +1 -0
  20. vector_inspector/ui/views/collection_browser.py +36 -34
  21. vector_inspector/ui/views/connection_view.py +7 -1
  22. vector_inspector/ui/views/info_panel.py +118 -52
  23. vector_inspector/ui/views/metadata_view.py +30 -31
  24. vector_inspector/ui/views/search_view.py +20 -19
  25. vector_inspector/ui/views/visualization_view.py +18 -15
  26. {vector_inspector-0.3.11.dist-info → vector_inspector-0.3.12.dist-info}/METADATA +17 -4
  27. {vector_inspector-0.3.11.dist-info → vector_inspector-0.3.12.dist-info}/RECORD +30 -28
  28. vector_inspector-0.3.12.dist-info/licenses/LICENSE +1 -0
  29. {vector_inspector-0.3.11.dist-info → vector_inspector-0.3.12.dist-info}/WHEEL +0 -0
  30. {vector_inspector-0.3.11.dist-info → vector_inspector-0.3.12.dist-info}/entry_points.txt +0 -0
@@ -1,19 +1,37 @@
1
1
  """Service for persisting application settings."""
2
2
 
3
- import json
4
3
  import base64
5
- from PySide6.QtCore import QObject, Signal
4
+ import json
6
5
  from pathlib import Path
7
- from typing import Dict, Any, Optional, List
6
+ from typing import Any, Optional
7
+
8
+ from PySide6.QtCore import QObject, Signal
9
+
8
10
  from vector_inspector.core.cache_manager import invalidate_cache_on_settings_change
9
11
  from vector_inspector.core.logging import log_error
10
12
 
11
13
 
12
14
  class SettingsService:
13
- """Handles loading and saving application settings."""
15
+ """Handles loading and saving application settings.
16
+
17
+ This is a singleton - all instances share the same settings data.
18
+ """
19
+
20
+ _instance = None
21
+ _initialized = False
22
+
23
+ def __new__(cls):
24
+ """Ensure only one instance exists (singleton pattern)."""
25
+ if cls._instance is None:
26
+ cls._instance = super().__new__(cls)
27
+ return cls._instance
14
28
 
15
29
  def __init__(self):
16
30
  """Initialize settings service."""
31
+ # Only initialize once
32
+ if SettingsService._initialized:
33
+ return
34
+ SettingsService._initialized = True
17
35
 
18
36
  # Expose a shared QObject-based signal emitter so UI can react to
19
37
  # settings changes without polling.
@@ -28,14 +46,14 @@ class SettingsService:
28
46
 
29
47
  self.settings_dir = Path.home() / ".vector-inspector"
30
48
  self.settings_file = self.settings_dir / "settings.json"
31
- self.settings: Dict[str, Any] = {}
49
+ self.settings: dict[str, Any] = {}
32
50
  self._load_settings()
33
51
 
34
52
  def _load_settings(self):
35
53
  """Load settings from file."""
36
54
  try:
37
55
  if self.settings_file.exists():
38
- with open(self.settings_file, "r", encoding="utf-8") as f:
56
+ with open(self.settings_file, encoding="utf-8") as f:
39
57
  self.settings = json.load(f)
40
58
  except Exception as e:
41
59
  log_error("Failed to load settings: %s", e)
@@ -52,11 +70,11 @@ class SettingsService:
52
70
  except Exception as e:
53
71
  log_error("Failed to save settings: %s", e)
54
72
 
55
- def get_last_connection(self) -> Optional[Dict[str, Any]]:
73
+ def get_last_connection(self) -> Optional[dict[str, Any]]:
56
74
  """Get the last connection configuration."""
57
75
  return self.settings.get("last_connection")
58
76
 
59
- def save_last_connection(self, config: Dict[str, Any]):
77
+ def save_last_connection(self, config: dict[str, Any]):
60
78
  """Save the last connection configuration."""
61
79
  self.settings["last_connection"] = config
62
80
  self._save_settings()
@@ -166,7 +184,7 @@ class SettingsService:
166
184
 
167
185
  def save_embedding_model(
168
186
  self,
169
- connection_id: str,
187
+ profile_name: str,
170
188
  collection_name: str,
171
189
  model_name: str,
172
190
  model_type: str = "user-configured",
@@ -174,7 +192,7 @@ class SettingsService:
174
192
  """Save embedding model mapping for a collection.
175
193
 
176
194
  Args:
177
- connection_id: Connection identifier
195
+ profile_name: Profile/connection name
178
196
  collection_name: Collection name
179
197
  model_name: Embedding model name (e.g., 'sentence-transformers/all-MiniLM-L6-v2')
180
198
  model_type: Type of configuration ('user-configured', 'auto-detected', 'stored')
@@ -182,7 +200,7 @@ class SettingsService:
182
200
  if "collection_embedding_models" not in self.settings:
183
201
  self.settings["collection_embedding_models"] = {}
184
202
 
185
- collection_key = f"{connection_id}:{collection_name}"
203
+ collection_key = f"{profile_name}:{collection_name}"
186
204
  self.settings["collection_embedding_models"][collection_key] = {
187
205
  "model": model_name,
188
206
  "type": model_type,
@@ -191,35 +209,69 @@ class SettingsService:
191
209
  self._save_settings()
192
210
 
193
211
  def get_embedding_model(
194
- self, connection_id: str, collection_name: str
195
- ) -> Optional[Dict[str, Any]]:
212
+ self,
213
+ profile_name: str,
214
+ collection_name: str,
215
+ ) -> Optional[dict[str, Any]]:
196
216
  """Get embedding model mapping for a collection.
197
217
 
198
218
  Args:
199
- connection_id: Connection identifier
219
+ profile_name: Profile/connection name
200
220
  collection_name: Collection name
201
221
 
202
222
  Returns:
203
223
  Dictionary with 'model', 'type', and 'timestamp' or None
204
224
  """
205
225
  collection_models = self.settings.get("collection_embedding_models", {})
206
- collection_key = f"{connection_id}:{collection_name}"
226
+ collection_key = f"{profile_name}:{collection_name}"
207
227
  return collection_models.get(collection_key)
208
228
 
209
- def remove_embedding_model(self, connection_id: str, collection_name: str):
229
+ def remove_embedding_model(
230
+ self,
231
+ profile_name: str,
232
+ collection_name: str,
233
+ ):
210
234
  """Remove embedding model mapping for a collection.
211
235
 
212
236
  Args:
213
- connection_id: Connection identifier
237
+ profile_name: Profile/connection name
214
238
  collection_name: Collection name
215
239
  """
216
240
  if "collection_embedding_models" not in self.settings:
217
241
  return
218
242
 
219
- collection_key = f"{connection_id}:{collection_name}"
243
+ collection_key = f"{profile_name}:{collection_name}"
220
244
  self.settings["collection_embedding_models"].pop(collection_key, None)
221
245
  self._save_settings()
222
246
 
247
+ def remove_profile_settings(self, profile_name: str):
248
+ """Remove all settings for a profile (e.g., when profile is deleted).
249
+
250
+ Args:
251
+ profile_name: Profile/connection name
252
+ """
253
+ if "collection_embedding_models" not in self.settings:
254
+ return
255
+
256
+ # Remove all keys that start with profile_name:
257
+ prefix = f"{profile_name}:"
258
+ keys_to_remove = [
259
+ key for key in self.settings["collection_embedding_models"] if key.startswith(prefix)
260
+ ]
261
+
262
+ for key in keys_to_remove:
263
+ self.settings["collection_embedding_models"].pop(key, None)
264
+
265
+ if keys_to_remove:
266
+ self._save_settings()
267
+ from vector_inspector.core.logging import log_info
268
+
269
+ log_info(
270
+ "Removed %d embedding model settings for profile: %s",
271
+ len(keys_to_remove),
272
+ profile_name,
273
+ )
274
+
223
275
  def _get_timestamp(self) -> str:
224
276
  """Get current timestamp as ISO string."""
225
277
  from datetime import datetime
@@ -267,7 +319,7 @@ class SettingsService:
267
319
  )
268
320
  self._save_settings()
269
321
 
270
- def get_custom_embedding_models(self, dimension: Optional[int] = None) -> List[Dict[str, Any]]:
322
+ def get_custom_embedding_models(self, dimension: Optional[int] = None) -> list[dict[str, Any]]:
271
323
  """Get list of custom embedding models.
272
324
 
273
325
  Args: