signalpilot-ai-internal 0.4.6__py3-none-any.whl → 0.4.7__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.
Potentially problematic release.
This version of signalpilot-ai-internal might be problematic. Click here for more details.
- signalpilot_ai_internal/_version.py +1 -1
- signalpilot_ai_internal/handlers.py +5 -1
- signalpilot_ai_internal/schema_search_config.yml +32 -0
- signalpilot_ai_internal/schema_search_service.py +109 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/package.json +2 -2
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/schemas/signalpilot-ai-internal/package.json.orig +1 -1
- signalpilot_ai_internal-0.4.7.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/839.4db23bddecbec684b06c.js +1 -0
- signalpilot_ai_internal-0.4.6.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/remoteEntry.61ef7b3a050c161d7a88.js → signalpilot_ai_internal-0.4.7.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/remoteEntry.2a797d447eeb725a28cf.js +1 -1
- {signalpilot_ai_internal-0.4.6.dist-info → signalpilot_ai_internal-0.4.7.dist-info}/METADATA +3 -2
- {signalpilot_ai_internal-0.4.6.dist-info → signalpilot_ai_internal-0.4.7.dist-info}/RECORD +40 -38
- signalpilot_ai_internal-0.4.6.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/839.0be091400e2f58fe8fd2.js +0 -1
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/etc/jupyter/jupyter_server_config.d/signalpilot_ai.json +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/install.json +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/schemas/signalpilot-ai-internal/plugin.json +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/104.04e170724f369fcbaf19.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/104.04e170724f369fcbaf19.js.LICENSE.txt +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/122.e2dadf63dc64d7b5f1ee.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/220.328403b5545f268b95c6.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/262.726e1da31a50868cb297.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/280.35d8c8b68815702a5238.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/280.35d8c8b68815702a5238.js.LICENSE.txt +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/353.72484b768a04f89bd3dd.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/364.dbec4c2dc12e7b050dcc.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/384.fa432bdb7fb6b1c95ad6.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/439.37e271d7a80336daabe2.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/476.9b4f05a99f5003f82094.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/481.73c7a9290b7d35a8b9c1.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/512.b58fc0093d080b8ee61c.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/553.b4042a795c91d9ff71ef.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/553.b4042a795c91d9ff71ef.js.LICENSE.txt +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/606.90aaaae46b73dc3c08fb.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/635.9720593ee20b768da3ca.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/713.8e6edc9a965bdd578ca7.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/742.91e7b516c8699eea3373.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/785.3aa564fc148b37d1d719.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/888.34054db17bcf6e87ec95.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/923.e80ae4c5cedc1d73f2a1.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/style.js +0 -0
- {signalpilot_ai_internal-0.4.6.data → signalpilot_ai_internal-0.4.7.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/third-party-licenses.json +0 -0
- {signalpilot_ai_internal-0.4.6.dist-info → signalpilot_ai_internal-0.4.7.dist-info}/WHEEL +0 -0
- {signalpilot_ai_internal-0.4.6.dist-info → signalpilot_ai_internal-0.4.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -12,6 +12,7 @@ from .cache_service import get_cache_service
|
|
|
12
12
|
from .cache_handlers import ChatHistoriesHandler, AppValuesHandler, CacheInfoHandler
|
|
13
13
|
from .unified_database_schema_service import UnifiedDatabaseSchemaHandler, UnifiedDatabaseQueryHandler
|
|
14
14
|
from .snowflake_schema_service import SnowflakeSchemaHandler, SnowflakeQueryHandler
|
|
15
|
+
from .schema_search_service import SchemaSearchHandler
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class HelloWorldHandler(APIHandler):
|
|
@@ -279,6 +280,7 @@ def setup_handlers(web_app):
|
|
|
279
280
|
# Database service endpoints
|
|
280
281
|
database_schema_route = url_path_join(base_url, "signalpilot-ai-internal", "database", "schema")
|
|
281
282
|
database_query_route = url_path_join(base_url, "signalpilot-ai-internal", "database", "query")
|
|
283
|
+
database_schema_search_route = url_path_join(base_url, "signalpilot-ai-internal", "database", "schema-search")
|
|
282
284
|
|
|
283
285
|
# MySQL service endpoints
|
|
284
286
|
mysql_schema_route = url_path_join(base_url, "signalpilot-ai-internal", "mysql", "schema")
|
|
@@ -309,6 +311,7 @@ def setup_handlers(web_app):
|
|
|
309
311
|
# Database service endpoints (unified for PostgreSQL and MySQL)
|
|
310
312
|
(database_schema_route, UnifiedDatabaseSchemaHandler),
|
|
311
313
|
(database_query_route, UnifiedDatabaseQueryHandler),
|
|
314
|
+
(database_schema_search_route, SchemaSearchHandler),
|
|
312
315
|
|
|
313
316
|
# MySQL service endpoints (use unified handler)
|
|
314
317
|
(mysql_schema_route, UnifiedDatabaseSchemaHandler),
|
|
@@ -339,7 +342,8 @@ def setup_handlers(web_app):
|
|
|
339
342
|
print(f" - Cache Info: {cache_info_route}")
|
|
340
343
|
print(f" - Database Schema: {database_schema_route}")
|
|
341
344
|
print(f" - Database Query: {database_query_route}")
|
|
345
|
+
print(f" - Database Schema Search: {database_schema_search_route}")
|
|
342
346
|
print(f" - MySQL Schema: {mysql_schema_route}")
|
|
343
347
|
print(f" - MySQL Query: {mysql_query_route}")
|
|
344
348
|
print(f" - Snowflake Schema: {snowflake_schema_route}")
|
|
345
|
-
print(f" - Snowflake Query: {snowflake_query_route}")
|
|
349
|
+
print(f" - Snowflake Query: {snowflake_query_route}")
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
logging:
|
|
2
|
+
level: "WARNING"
|
|
3
|
+
|
|
4
|
+
embedding:
|
|
5
|
+
location: "memory"
|
|
6
|
+
model: "multi-qa-MiniLM-L6-cos-v1"
|
|
7
|
+
metric: "cosine"
|
|
8
|
+
batch_size: 32
|
|
9
|
+
show_progress: false
|
|
10
|
+
cache_dir: "/tmp/.schema_search_cache"
|
|
11
|
+
|
|
12
|
+
chunking:
|
|
13
|
+
strategy: "raw"
|
|
14
|
+
max_tokens: 256
|
|
15
|
+
overlap_tokens: 50
|
|
16
|
+
model: "gpt-4o-mini"
|
|
17
|
+
|
|
18
|
+
search:
|
|
19
|
+
strategy: "hybrid"
|
|
20
|
+
initial_top_k: 20
|
|
21
|
+
rerank_top_k: 5
|
|
22
|
+
semantic_weight: 0.67
|
|
23
|
+
hops: 1
|
|
24
|
+
|
|
25
|
+
reranker:
|
|
26
|
+
model: null
|
|
27
|
+
|
|
28
|
+
schema:
|
|
29
|
+
include_columns: true
|
|
30
|
+
include_indices: true
|
|
31
|
+
include_foreign_keys: true
|
|
32
|
+
include_constraints: true
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from jupyter_server.base.handlers import APIHandler
|
|
9
|
+
import tornado
|
|
10
|
+
from schema_search import SchemaSearch
|
|
11
|
+
from sqlalchemy import create_engine
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SchemaSearchHandler(APIHandler):
|
|
15
|
+
CONFIG_PATH = Path(__file__).with_name("schema_search_config.yml")
|
|
16
|
+
|
|
17
|
+
def _get_database_url(self, explicit: Optional[str]) -> Optional[str]:
|
|
18
|
+
if isinstance(explicit, str) and explicit.strip():
|
|
19
|
+
return explicit.strip()
|
|
20
|
+
|
|
21
|
+
for key, value in os.environ.items():
|
|
22
|
+
if key.endswith("_CONNECTION_JSON") and isinstance(value, str) and value.strip().startswith("{"):
|
|
23
|
+
config = json.loads(value)
|
|
24
|
+
url = config.get("connectionUrl")
|
|
25
|
+
if url:
|
|
26
|
+
return url
|
|
27
|
+
return os.environ.get("DB_URL")
|
|
28
|
+
|
|
29
|
+
@tornado.web.authenticated
|
|
30
|
+
async def post(self):
|
|
31
|
+
body = self.get_json_body() or {}
|
|
32
|
+
queries = body.get("queries")
|
|
33
|
+
if isinstance(queries, str):
|
|
34
|
+
queries = [queries]
|
|
35
|
+
|
|
36
|
+
if not isinstance(queries, list):
|
|
37
|
+
self.set_status(400)
|
|
38
|
+
self.finish(json.dumps({"error": "queries parameter must be a list of strings"}))
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
queries = [q.strip() for q in queries if isinstance(q, str) and q.strip()]
|
|
42
|
+
|
|
43
|
+
if not queries:
|
|
44
|
+
self.set_status(400)
|
|
45
|
+
self.finish(json.dumps({"error": "queries parameter is required"}))
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
db_url = self._get_database_url(body.get("dbUrl"))
|
|
49
|
+
if not db_url:
|
|
50
|
+
self.set_status(400)
|
|
51
|
+
self.finish(json.dumps({"error": "Database connection URL is not configured"}))
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
db_url = db_url.strip()
|
|
55
|
+
db_url_lower = db_url.lower()
|
|
56
|
+
|
|
57
|
+
if db_url_lower.startswith("mysql://"):
|
|
58
|
+
db_url = "mysql+pymysql://" + db_url[len("mysql://"):]
|
|
59
|
+
db_url_lower = db_url.lower()
|
|
60
|
+
|
|
61
|
+
if db_url_lower.startswith("snowflake://"):
|
|
62
|
+
self._ensure_snowflake_dependencies()
|
|
63
|
+
elif db_url_lower.startswith("postgresql") or db_url_lower.startswith("postgres") or db_url_lower.startswith("mysql+pymysql"):
|
|
64
|
+
pass
|
|
65
|
+
else:
|
|
66
|
+
self.set_status(400)
|
|
67
|
+
self.finish(json.dumps({"error": "Schema search currently supports PostgreSQL, MySQL, or Snowflake connections"}))
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
engine = None
|
|
71
|
+
try:
|
|
72
|
+
engine = create_engine(db_url)
|
|
73
|
+
schema_search = SchemaSearch(engine=engine, config_path=str(self.CONFIG_PATH))
|
|
74
|
+
schema_search.index()
|
|
75
|
+
|
|
76
|
+
limit = body.get("limit")
|
|
77
|
+
if limit is not None:
|
|
78
|
+
limit = max(1, min(int(limit), 10))
|
|
79
|
+
else:
|
|
80
|
+
limit = 5
|
|
81
|
+
|
|
82
|
+
query_results = []
|
|
83
|
+
for query in queries:
|
|
84
|
+
result = schema_search.search(query, limit=limit)
|
|
85
|
+
query_results.append({
|
|
86
|
+
"query": query,
|
|
87
|
+
"results": result
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
self.finish(json.dumps({"results": query_results}))
|
|
91
|
+
except Exception as error:
|
|
92
|
+
self.set_status(500)
|
|
93
|
+
self.finish(json.dumps({"error": f"Schema search failed: {error}"}))
|
|
94
|
+
finally:
|
|
95
|
+
if engine is not None:
|
|
96
|
+
try:
|
|
97
|
+
engine.dispose()
|
|
98
|
+
except Exception:
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
def _install_package(self, package: str) -> None:
|
|
102
|
+
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
|
|
103
|
+
|
|
104
|
+
def _ensure_snowflake_dependencies(self) -> None:
|
|
105
|
+
try:
|
|
106
|
+
import snowflake.sqlalchemy # type: ignore # noqa: F401
|
|
107
|
+
except ImportError:
|
|
108
|
+
self._install_package("snowflake-sqlalchemy")
|
|
109
|
+
import snowflake.sqlalchemy # type: ignore # noqa: F401
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "signalpilot-ai-internal",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"description": "SignalPilot Agent - Your Jupyter Notebook Assistant",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
"outputDir": "signalpilot_ai_internal/labextension",
|
|
134
134
|
"schemaDir": "schema",
|
|
135
135
|
"_build": {
|
|
136
|
-
"load": "static/remoteEntry.
|
|
136
|
+
"load": "static/remoteEntry.2a797d447eeb725a28cf.js",
|
|
137
137
|
"extension": "./extension",
|
|
138
138
|
"style": "./style"
|
|
139
139
|
}
|