vector-inspector 0.3.8__tar.gz → 0.3.9__tar.gz
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.
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/PKG-INFO +35 -24
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/README.md +34 -23
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/pyproject.toml +1 -1
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/connections/pgvector_connection.py +26 -1
- vector_inspector-0.3.9/src/vector_inspector/extensions/__init__.py +105 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/services/settings_service.py +76 -0
- vector_inspector-0.3.9/src/vector_inspector/ui/dialogs/settings_dialog.py +124 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/main_window.py +138 -1
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/views/metadata_view.py +45 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/views/search_view.py +146 -13
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/__main__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/config/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/config/known_embedding_models.json +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/cache_manager.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/connection_manager.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/connections/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/connections/base_connection.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/connections/chroma_connection.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/connections/pinecone_connection.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/connections/qdrant_connection.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/connections/qdrant_helpers/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/connections/qdrant_helpers/qdrant_embedding_resolver.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/connections/qdrant_helpers/qdrant_filter_builder.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/connections/template_connection.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/embedding_providers/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/embedding_providers/base_provider.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/embedding_providers/clip_provider.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/embedding_providers/provider_factory.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/embedding_providers/sentence_transformer_provider.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/embedding_utils.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/logging.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/model_registry.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/core/provider_factory.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/main.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/services/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/services/backup_helpers.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/services/backup_restore_service.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/services/credential_service.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/services/filter_service.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/services/import_export_service.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/services/profile_service.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/services/update_service.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/services/visualization_service.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/components/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/components/backup_restore_dialog.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/components/connection_manager_panel.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/components/filter_builder.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/components/item_dialog.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/components/loading_dialog.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/components/profile_manager_panel.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/components/splash_window.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/components/update_details_dialog.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/controllers/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/controllers/connection_controller.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/dialogs/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/dialogs/cross_db_migration.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/dialogs/embedding_config_dialog.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/dialogs/provider_type_dialog.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/main_window_shell.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/services/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/services/dialog_service.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/tabs.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/views/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/views/collection_browser.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/views/connection_view.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/views/info_panel.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/ui/views/visualization_view.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/utils/__init__.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/utils/lazy_imports.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/utils/version.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/tests/test_backup_helpers.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/tests/test_backup_restore_service.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/tests/test_chroma_connection.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/tests/test_filter_service.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/tests/test_pgvector_connection.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/tests/test_pinecone_connection.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/tests/test_qdrant_connection.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/tests/test_runner.py +0 -0
- {vector_inspector-0.3.8 → vector_inspector-0.3.9}/tests/test_settings_service.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: vector-inspector
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
4
4
|
Summary: A comprehensive desktop application for visualizing, querying, and managing vector database data
|
|
5
5
|
Author-Email: Anthony Dawson <anthonypdawson+github@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -32,29 +32,38 @@ Description-Content-Type: text/markdown
|
|
|
32
32
|
|
|
33
33
|
# Latest updates
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
|
|
35
|
+
- Major refactor and studio-ready architecture
|
|
36
|
+
- Refactored main window into modular components (InspectorShell, ProviderFactory, DialogService, ConnectionController, InspectorTabs)
|
|
37
|
+
- MainWindow is reusable as a widget; tab system is pluggable so Studio can extend or override tabs
|
|
38
|
+
|
|
39
|
+
- Data browser improvements
|
|
40
|
+
- Added Generate embeddings on edit (persisted per user)
|
|
41
|
+
|
|
42
|
+
- Settings / Preferences
|
|
43
|
+
- SettingsService persists preferences and exposes typed accessors (breadcrumb, search defaults, auto-embed, window geometry)
|
|
44
|
+
- SettingsService emits a setting_changed Qt signal so UI reacts immediately
|
|
45
|
+
- SettingsDialog (modal) added with add_section API and hook integration for extension panels
|
|
46
|
+
- Breadcrumb controls moved out of core so Pro (Vector Studio) injects them via the settings_panel_hook
|
|
47
|
+
|
|
48
|
+
- Extension hook for settings panels
|
|
49
|
+
- *settings_panel_hook* added to *vector_inspector.extensions*; Vector Studio registers breadcrumb controls at startup
|
|
50
|
+
|
|
51
|
+
- Breadcrumb and UI improvements
|
|
52
|
+
- Breadcrumb label now elides long trails (left/middle) and shows full trail on hover
|
|
53
|
+
- SearchView supports runtime elide-mode changes and responds to settings signals
|
|
54
|
+
|
|
55
|
+
- Window geometry persistence
|
|
56
|
+
- Main window saves/restores geometry when window.restore_geometry is enabled
|
|
57
|
+
|
|
58
|
+
- Pro (Vector Studio) features
|
|
59
|
+
- *Search Similar* (Pro): right-click any row in Data Browser or Search Results to run a vector-to-vector similarity search
|
|
60
|
+
- *table_context_menu* handler hardened for many embedding/id formats and includes fallbacks
|
|
61
|
+
- Vector Studio injects breadcrumb controls into Settings dialog via *settings_panel_hook*
|
|
62
|
+
|
|
63
|
+
- Tests and CI
|
|
64
|
+
- Added *tests/test_settings_injection.py* to assert settings panel hook registration
|
|
65
|
+
- Updated context-menu tests to use *log_info* and *assert* for pytest
|
|
66
|
+
- Local test run: 5 tests passed; GUI-heavy suite ~9s due to PySide6 startup
|
|
58
67
|
|
|
59
68
|
---
|
|
60
69
|
|
|
@@ -92,6 +101,8 @@ Vector Inspector bridges the gap between vector databases and user-friendly data
|
|
|
92
101
|
|
|
93
102
|
## Key Features
|
|
94
103
|
|
|
104
|
+
> **Note:** Some features listed below may be not started or currently in progress.
|
|
105
|
+
|
|
95
106
|
### 1. **Multi-Provider Support**
|
|
96
107
|
- Connect to vector databases:
|
|
97
108
|
- ChromaDB (persistent local storage)
|
|
@@ -1,28 +1,37 @@
|
|
|
1
1
|
# Latest updates
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
|
|
3
|
+
- Major refactor and studio-ready architecture
|
|
4
|
+
- Refactored main window into modular components (InspectorShell, ProviderFactory, DialogService, ConnectionController, InspectorTabs)
|
|
5
|
+
- MainWindow is reusable as a widget; tab system is pluggable so Studio can extend or override tabs
|
|
6
|
+
|
|
7
|
+
- Data browser improvements
|
|
8
|
+
- Added Generate embeddings on edit (persisted per user)
|
|
9
|
+
|
|
10
|
+
- Settings / Preferences
|
|
11
|
+
- SettingsService persists preferences and exposes typed accessors (breadcrumb, search defaults, auto-embed, window geometry)
|
|
12
|
+
- SettingsService emits a setting_changed Qt signal so UI reacts immediately
|
|
13
|
+
- SettingsDialog (modal) added with add_section API and hook integration for extension panels
|
|
14
|
+
- Breadcrumb controls moved out of core so Pro (Vector Studio) injects them via the settings_panel_hook
|
|
15
|
+
|
|
16
|
+
- Extension hook for settings panels
|
|
17
|
+
- *settings_panel_hook* added to *vector_inspector.extensions*; Vector Studio registers breadcrumb controls at startup
|
|
18
|
+
|
|
19
|
+
- Breadcrumb and UI improvements
|
|
20
|
+
- Breadcrumb label now elides long trails (left/middle) and shows full trail on hover
|
|
21
|
+
- SearchView supports runtime elide-mode changes and responds to settings signals
|
|
22
|
+
|
|
23
|
+
- Window geometry persistence
|
|
24
|
+
- Main window saves/restores geometry when window.restore_geometry is enabled
|
|
25
|
+
|
|
26
|
+
- Pro (Vector Studio) features
|
|
27
|
+
- *Search Similar* (Pro): right-click any row in Data Browser or Search Results to run a vector-to-vector similarity search
|
|
28
|
+
- *table_context_menu* handler hardened for many embedding/id formats and includes fallbacks
|
|
29
|
+
- Vector Studio injects breadcrumb controls into Settings dialog via *settings_panel_hook*
|
|
30
|
+
|
|
31
|
+
- Tests and CI
|
|
32
|
+
- Added *tests/test_settings_injection.py* to assert settings panel hook registration
|
|
33
|
+
- Updated context-menu tests to use *log_info* and *assert* for pytest
|
|
34
|
+
- Local test run: 5 tests passed; GUI-heavy suite ~9s due to PySide6 startup
|
|
26
35
|
|
|
27
36
|
---
|
|
28
37
|
|
|
@@ -60,6 +69,8 @@ Vector Inspector bridges the gap between vector databases and user-friendly data
|
|
|
60
69
|
|
|
61
70
|
## Key Features
|
|
62
71
|
|
|
72
|
+
> **Note:** Some features listed below may be not started or currently in progress.
|
|
73
|
+
|
|
63
74
|
### 1. **Multi-Provider Support**
|
|
64
75
|
- Connect to vector databases:
|
|
65
76
|
- ChromaDB (persistent local storage)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "vector-inspector"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.9"
|
|
4
4
|
description = "A comprehensive desktop application for visualizing, querying, and managing vector database data"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Anthony Dawson", email = "anthonypdawson+github@gmail.com" },
|
|
@@ -5,6 +5,8 @@ import json
|
|
|
5
5
|
import psycopg2
|
|
6
6
|
from psycopg2 import sql
|
|
7
7
|
|
|
8
|
+
from vector_inspector.core.logging import log_info
|
|
9
|
+
|
|
8
10
|
## No need to import register_vector; pgvector extension is enabled at table creation
|
|
9
11
|
from vector_inspector.core.connections.base_connection import VectorDBConnection
|
|
10
12
|
from vector_inspector.core.logging import log_error, log_info
|
|
@@ -1043,12 +1045,35 @@ class PgVectorConnection(VectorDBConnection):
|
|
|
1043
1045
|
Returns:
|
|
1044
1046
|
List of floats
|
|
1045
1047
|
"""
|
|
1048
|
+
log_info("[pgvector] _parse_vector raw value: %r (type: %s)", vector_str, type(vector_str))
|
|
1046
1049
|
if isinstance(vector_str, list):
|
|
1050
|
+
log_info("[pgvector] _parse_vector: already list, len=%d", len(vector_str))
|
|
1047
1051
|
return vector_str
|
|
1052
|
+
# Handle numpy arrays
|
|
1053
|
+
try:
|
|
1054
|
+
import numpy as np
|
|
1055
|
+
|
|
1056
|
+
if isinstance(vector_str, np.ndarray):
|
|
1057
|
+
log_info("[pgvector] _parse_vector: numpy array, shape=%s", vector_str.shape)
|
|
1058
|
+
return vector_str.tolist()
|
|
1059
|
+
except ImportError:
|
|
1060
|
+
pass
|
|
1048
1061
|
if isinstance(vector_str, str):
|
|
1049
1062
|
# Remove brackets and split by comma
|
|
1050
1063
|
vector_str = vector_str.strip("[]")
|
|
1051
|
-
|
|
1064
|
+
if not vector_str:
|
|
1065
|
+
log_info("[pgvector] _parse_vector: empty string after strip")
|
|
1066
|
+
return []
|
|
1067
|
+
try:
|
|
1068
|
+
parsed = [float(x) for x in vector_str.split(",")]
|
|
1069
|
+
log_info("[pgvector] _parse_vector: parsed list of len %d", len(parsed))
|
|
1070
|
+
return parsed
|
|
1071
|
+
except Exception as e:
|
|
1072
|
+
log_info(
|
|
1073
|
+
"[pgvector] _parse_vector: failed to parse '%s' with error: %s", vector_str, e
|
|
1074
|
+
)
|
|
1075
|
+
return []
|
|
1076
|
+
log_info("[pgvector] _parse_vector: unhandled type %s, returning []", type(vector_str))
|
|
1052
1077
|
return []
|
|
1053
1078
|
|
|
1054
1079
|
def compute_embeddings_for_documents(
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Extension points for Vector Inspector.
|
|
2
|
+
|
|
3
|
+
This module provides hooks and callbacks that allow pro versions
|
|
4
|
+
or plugins to extend core functionality without modifying the base code.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, ClassVar
|
|
8
|
+
from collections.abc import Callable
|
|
9
|
+
from PySide6.QtWidgets import QMenu, QTableWidget
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TableContextMenuHook:
|
|
13
|
+
"""Hook for adding custom context menu items to table widgets."""
|
|
14
|
+
|
|
15
|
+
_handlers: ClassVar[list[Callable]] = []
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def register(cls, handler: Callable):
|
|
19
|
+
"""Register a context menu handler.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
handler: Callable that takes (menu: QMenu, table: QTableWidget, row: int, data: Dict)
|
|
23
|
+
and adds menu items to the menu.
|
|
24
|
+
"""
|
|
25
|
+
if handler not in cls._handlers:
|
|
26
|
+
cls._handlers.append(handler)
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def unregister(cls, handler: Callable):
|
|
30
|
+
"""Unregister a context menu handler."""
|
|
31
|
+
if handler in cls._handlers:
|
|
32
|
+
cls._handlers.remove(handler)
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def trigger(
|
|
36
|
+
cls,
|
|
37
|
+
menu: QMenu,
|
|
38
|
+
table: QTableWidget,
|
|
39
|
+
row: int,
|
|
40
|
+
data: dict[str, Any] | None = None,
|
|
41
|
+
):
|
|
42
|
+
"""Trigger all registered handlers.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
menu: The QMenu to add items to
|
|
46
|
+
table: The QTableWidget that was right-clicked
|
|
47
|
+
row: The row number that was clicked
|
|
48
|
+
data: Optional data dictionary with context (ids, documents, metadatas, etc.)
|
|
49
|
+
"""
|
|
50
|
+
for handler in cls._handlers:
|
|
51
|
+
try:
|
|
52
|
+
handler(menu, table, row, data)
|
|
53
|
+
except Exception as e:
|
|
54
|
+
# Log but don't break if a handler fails
|
|
55
|
+
from vector_inspector.core.logging import log_error
|
|
56
|
+
|
|
57
|
+
log_error("Context menu handler error: %s", e)
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def clear(cls):
|
|
61
|
+
"""Clear all registered handlers."""
|
|
62
|
+
cls._handlers.clear()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# Global singleton instance
|
|
66
|
+
table_context_menu_hook = TableContextMenuHook()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class SettingsPanelHook:
|
|
70
|
+
"""Hook for adding custom sections to the Settings/Preferences dialog."""
|
|
71
|
+
|
|
72
|
+
_handlers: ClassVar[list[Callable]] = []
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def register(cls, handler: Callable):
|
|
76
|
+
"""Register a settings panel provider.
|
|
77
|
+
|
|
78
|
+
Handler signature: (parent_layout, settings_service, dialog)
|
|
79
|
+
where `parent_layout` is a QLayout the handler can add widgets to.
|
|
80
|
+
"""
|
|
81
|
+
if handler not in cls._handlers:
|
|
82
|
+
cls._handlers.append(handler)
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def unregister(cls, handler: Callable):
|
|
86
|
+
if handler in cls._handlers:
|
|
87
|
+
cls._handlers.remove(handler)
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
def trigger(cls, parent_layout, settings_service, dialog=None):
|
|
91
|
+
for handler in cls._handlers:
|
|
92
|
+
try:
|
|
93
|
+
handler(parent_layout, settings_service, dialog)
|
|
94
|
+
except Exception as e:
|
|
95
|
+
from vector_inspector.core.logging import log_error
|
|
96
|
+
|
|
97
|
+
log_error("Settings panel handler error: %s", e)
|
|
98
|
+
|
|
99
|
+
@classmethod
|
|
100
|
+
def clear(cls):
|
|
101
|
+
cls._handlers.clear()
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# Global singleton instance
|
|
105
|
+
settings_panel_hook = SettingsPanelHook()
|
{vector_inspector-0.3.8 → vector_inspector-0.3.9}/src/vector_inspector/services/settings_service.py
RENAMED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""Service for persisting application settings."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
import base64
|
|
5
|
+
from PySide6.QtCore import QObject, Signal
|
|
4
6
|
from pathlib import Path
|
|
5
7
|
from typing import Dict, Any, Optional, List
|
|
6
8
|
from vector_inspector.core.cache_manager import invalidate_cache_on_settings_change
|
|
@@ -12,6 +14,18 @@ class SettingsService:
|
|
|
12
14
|
|
|
13
15
|
def __init__(self):
|
|
14
16
|
"""Initialize settings service."""
|
|
17
|
+
|
|
18
|
+
# Expose a shared QObject-based signal emitter so UI can react to
|
|
19
|
+
# settings changes without polling.
|
|
20
|
+
class _Signals(QObject):
|
|
21
|
+
setting_changed = Signal(str, object)
|
|
22
|
+
|
|
23
|
+
# singleton-like per-process signals instance
|
|
24
|
+
try:
|
|
25
|
+
self.signals
|
|
26
|
+
except Exception:
|
|
27
|
+
self.signals = _Signals()
|
|
28
|
+
|
|
15
29
|
self.settings_dir = Path.home() / ".vector-inspector"
|
|
16
30
|
self.settings_file = self.settings_dir / "settings.json"
|
|
17
31
|
self.settings: Dict[str, Any] = {}
|
|
@@ -51,6 +65,62 @@ class SettingsService:
|
|
|
51
65
|
"""Get a setting value."""
|
|
52
66
|
return self.settings.get(key, default)
|
|
53
67
|
|
|
68
|
+
# Convenience accessors for common settings
|
|
69
|
+
def get_breadcrumb_enabled(self) -> bool:
|
|
70
|
+
return bool(self.settings.get("breadcrumb.enabled", True))
|
|
71
|
+
|
|
72
|
+
def set_breadcrumb_enabled(self, enabled: bool):
|
|
73
|
+
self.set("breadcrumb.enabled", bool(enabled))
|
|
74
|
+
|
|
75
|
+
def get_breadcrumb_elide_mode(self) -> str:
|
|
76
|
+
return str(self.settings.get("breadcrumb.elide_mode", "left"))
|
|
77
|
+
|
|
78
|
+
def set_breadcrumb_elide_mode(self, mode: str):
|
|
79
|
+
if mode not in ("left", "middle"):
|
|
80
|
+
mode = "left"
|
|
81
|
+
self.set("breadcrumb.elide_mode", mode)
|
|
82
|
+
|
|
83
|
+
def get_default_n_results(self) -> int:
|
|
84
|
+
return int(self.settings.get("search.default_n_results", 10))
|
|
85
|
+
|
|
86
|
+
def set_default_n_results(self, n: int):
|
|
87
|
+
self.set("search.default_n_results", int(n))
|
|
88
|
+
|
|
89
|
+
def get_auto_generate_embeddings(self) -> bool:
|
|
90
|
+
return bool(self.settings.get("embeddings.auto_generate", True))
|
|
91
|
+
|
|
92
|
+
def set_auto_generate_embeddings(self, enabled: bool):
|
|
93
|
+
self.set("embeddings.auto_generate", bool(enabled))
|
|
94
|
+
|
|
95
|
+
def get_window_restore_geometry(self) -> bool:
|
|
96
|
+
return bool(self.settings.get("window.restore_geometry", True))
|
|
97
|
+
|
|
98
|
+
def set_window_restore_geometry(self, enabled: bool):
|
|
99
|
+
self.set("window.restore_geometry", bool(enabled))
|
|
100
|
+
|
|
101
|
+
def set_window_geometry(self, geometry_bytes: bytes):
|
|
102
|
+
"""Save window geometry as base64 string."""
|
|
103
|
+
try:
|
|
104
|
+
if isinstance(geometry_bytes, str):
|
|
105
|
+
# assume base64 already
|
|
106
|
+
b64 = geometry_bytes
|
|
107
|
+
else:
|
|
108
|
+
b64 = base64.b64encode(bytes(geometry_bytes)).decode("ascii")
|
|
109
|
+
self.set("window.geometry", b64)
|
|
110
|
+
except Exception as e:
|
|
111
|
+
log_error("Failed to set window geometry: %s", e)
|
|
112
|
+
|
|
113
|
+
def get_window_geometry(self) -> Optional[bytes]:
|
|
114
|
+
"""Return geometry bytes or None."""
|
|
115
|
+
try:
|
|
116
|
+
b64 = self.settings.get("window.geometry")
|
|
117
|
+
if not b64:
|
|
118
|
+
return None
|
|
119
|
+
return base64.b64decode(b64)
|
|
120
|
+
except Exception as e:
|
|
121
|
+
log_error("Failed to get window geometry: %s", e)
|
|
122
|
+
return None
|
|
123
|
+
|
|
54
124
|
def get_cache_enabled(self) -> bool:
|
|
55
125
|
"""Get whether caching is enabled (default: True)."""
|
|
56
126
|
return self.settings.get("cache_enabled", True)
|
|
@@ -74,6 +144,12 @@ class SettingsService:
|
|
|
74
144
|
# Invalidate cache when settings change (only if cache is enabled)
|
|
75
145
|
if key != "cache_enabled": # Don't invalidate when toggling cache itself
|
|
76
146
|
invalidate_cache_on_settings_change()
|
|
147
|
+
# Emit change signal for UI/reactive components
|
|
148
|
+
try:
|
|
149
|
+
# Emit the raw python object (value) for convenience
|
|
150
|
+
self.signals.setting_changed.emit(key, value)
|
|
151
|
+
except Exception:
|
|
152
|
+
pass
|
|
77
153
|
|
|
78
154
|
def clear(self):
|
|
79
155
|
"""Clear all settings."""
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
from PySide6.QtWidgets import (
|
|
2
|
+
QDialog,
|
|
3
|
+
QVBoxLayout,
|
|
4
|
+
QHBoxLayout,
|
|
5
|
+
QLabel,
|
|
6
|
+
QCheckBox,
|
|
7
|
+
QComboBox,
|
|
8
|
+
QSpinBox,
|
|
9
|
+
QPushButton,
|
|
10
|
+
)
|
|
11
|
+
from PySide6.QtCore import Qt
|
|
12
|
+
|
|
13
|
+
from vector_inspector.services.settings_service import SettingsService
|
|
14
|
+
from vector_inspector.extensions import settings_panel_hook
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SettingsDialog(QDialog):
|
|
18
|
+
"""Modal settings dialog backed by SettingsService."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, settings_service: SettingsService = None, parent=None):
|
|
21
|
+
super().__init__(parent)
|
|
22
|
+
self.setWindowTitle("Preferences")
|
|
23
|
+
self.settings = settings_service or SettingsService()
|
|
24
|
+
self._init_ui()
|
|
25
|
+
self._load_values()
|
|
26
|
+
|
|
27
|
+
def _init_ui(self):
|
|
28
|
+
layout = QVBoxLayout(self)
|
|
29
|
+
|
|
30
|
+
# Breadcrumb controls are provided by pro extensions (vector-studio)
|
|
31
|
+
# via the settings_panel_hook. Core does not add breadcrumb options.
|
|
32
|
+
|
|
33
|
+
# Search defaults
|
|
34
|
+
search_layout = QHBoxLayout()
|
|
35
|
+
search_layout.addWidget(QLabel("Default results:"))
|
|
36
|
+
self.default_results = QSpinBox()
|
|
37
|
+
self.default_results.setMinimum(1)
|
|
38
|
+
self.default_results.setMaximum(1000)
|
|
39
|
+
search_layout.addWidget(self.default_results)
|
|
40
|
+
layout.addLayout(search_layout)
|
|
41
|
+
|
|
42
|
+
# Embeddings
|
|
43
|
+
self.auto_embed_checkbox = QCheckBox("Auto-generate embeddings for new text")
|
|
44
|
+
layout.addWidget(self.auto_embed_checkbox)
|
|
45
|
+
|
|
46
|
+
# Window geometry
|
|
47
|
+
self.restore_geometry_checkbox = QCheckBox("Restore window size/position on startup")
|
|
48
|
+
layout.addWidget(self.restore_geometry_checkbox)
|
|
49
|
+
|
|
50
|
+
# Buttons
|
|
51
|
+
btn_layout = QHBoxLayout()
|
|
52
|
+
self.apply_btn = QPushButton("Apply")
|
|
53
|
+
self.ok_btn = QPushButton("OK")
|
|
54
|
+
self.cancel_btn = QPushButton("Cancel")
|
|
55
|
+
self.reset_btn = QPushButton("Reset to defaults")
|
|
56
|
+
btn_layout.addWidget(self.reset_btn)
|
|
57
|
+
btn_layout.addStretch()
|
|
58
|
+
btn_layout.addWidget(self.apply_btn)
|
|
59
|
+
btn_layout.addWidget(self.ok_btn)
|
|
60
|
+
btn_layout.addWidget(self.cancel_btn)
|
|
61
|
+
# Allow external extensions to add sections before the buttons
|
|
62
|
+
try:
|
|
63
|
+
# Handlers receive (parent_layout, settings_service, dialog)
|
|
64
|
+
settings_panel_hook.trigger(layout, self.settings, self)
|
|
65
|
+
except Exception:
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
layout.addLayout(btn_layout)
|
|
69
|
+
|
|
70
|
+
# Signals
|
|
71
|
+
self.apply_btn.clicked.connect(self._apply)
|
|
72
|
+
self.ok_btn.clicked.connect(self._ok)
|
|
73
|
+
self.cancel_btn.clicked.connect(self.reject)
|
|
74
|
+
self.reset_btn.clicked.connect(self._reset_defaults)
|
|
75
|
+
|
|
76
|
+
# Immediate apply on change for some controls
|
|
77
|
+
self.default_results.valueChanged.connect(lambda v: self.settings.set_default_n_results(v))
|
|
78
|
+
self.auto_embed_checkbox.stateChanged.connect(
|
|
79
|
+
lambda s: self.settings.set_auto_generate_embeddings(bool(s))
|
|
80
|
+
)
|
|
81
|
+
self.restore_geometry_checkbox.stateChanged.connect(
|
|
82
|
+
lambda s: self.settings.set_window_restore_geometry(bool(s))
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Container for programmatic sections
|
|
86
|
+
self._extra_sections = []
|
|
87
|
+
|
|
88
|
+
def add_section(self, widget_or_layout):
|
|
89
|
+
"""Programmatically add a section (widget or layout) to the dialog.
|
|
90
|
+
|
|
91
|
+
`widget_or_layout` can be a QWidget or QLayout. It will be added
|
|
92
|
+
immediately to the dialog's main layout.
|
|
93
|
+
"""
|
|
94
|
+
try:
|
|
95
|
+
if hasattr(widget_or_layout, "setParent"):
|
|
96
|
+
# QWidget
|
|
97
|
+
self.layout().addWidget(widget_or_layout)
|
|
98
|
+
else:
|
|
99
|
+
# Assume QLayout
|
|
100
|
+
self.layout().addLayout(widget_or_layout)
|
|
101
|
+
self._extra_sections.append(widget_or_layout)
|
|
102
|
+
except Exception:
|
|
103
|
+
pass
|
|
104
|
+
|
|
105
|
+
def _load_values(self):
|
|
106
|
+
# Breadcrumb controls are not present in core dialog.
|
|
107
|
+
self.default_results.setValue(self.settings.get_default_n_results())
|
|
108
|
+
self.auto_embed_checkbox.setChecked(self.settings.get_auto_generate_embeddings())
|
|
109
|
+
self.restore_geometry_checkbox.setChecked(self.settings.get_window_restore_geometry())
|
|
110
|
+
|
|
111
|
+
def _apply(self):
|
|
112
|
+
# Values are already applied on change; ensure persistence and close
|
|
113
|
+
self.settings._save_settings()
|
|
114
|
+
|
|
115
|
+
def _ok(self):
|
|
116
|
+
self._apply()
|
|
117
|
+
self.accept()
|
|
118
|
+
|
|
119
|
+
def _reset_defaults(self):
|
|
120
|
+
# Reset to recommended defaults
|
|
121
|
+
self.default_results.setValue(10)
|
|
122
|
+
self.auto_embed_checkbox.setChecked(True)
|
|
123
|
+
self.restore_geometry_checkbox.setChecked(True)
|
|
124
|
+
self._apply()
|