signalpilot-ai-internal 0.6.2__py3-none-any.whl → 0.7.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.
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 +115 -0
- signalpilot_ai_internal/html_export_template/README.md +23 -0
- signalpilot_ai_internal/html_export_template/conf.json +12 -0
- signalpilot_ai_internal/html_export_template/index.html.j2 +68 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/package.json +2 -2
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/schemas/signalpilot-ai-internal/package.json.orig +1 -1
- signalpilot_ai_internal-0.7.1.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/490.64082742bb093355f325.js +1 -0
- signalpilot_ai_internal-0.7.1.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/839.36369a64b4091ebf346c.js +1 -0
- signalpilot_ai_internal-0.6.2.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/remoteEntry.113fd565b968ed5ddfc0.js → signalpilot_ai_internal-0.7.1.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/remoteEntry.3dc6642d2a780c9a166d.js +1 -1
- {signalpilot_ai_internal-0.6.2.dist-info → signalpilot_ai_internal-0.7.1.dist-info}/METADATA +1 -1
- {signalpilot_ai_internal-0.6.2.dist-info → signalpilot_ai_internal-0.7.1.dist-info}/RECORD +39 -36
- signalpilot_ai_internal-0.6.2.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/188.1ace26ac1a5e246783bb.js +0 -1
- signalpilot_ai_internal-0.6.2.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/839.35ca24b793cb523218f9.js +0 -1
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/etc/jupyter/jupyter_server_config.d/signalpilot_ai.json +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/install.json +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/schemas/signalpilot-ai-internal/plugin.json +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/122.e2dadf63dc64d7b5f1ee.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/220.328403b5545f268b95c6.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/262.726e1da31a50868cb297.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/353.72484b768a04f89bd3dd.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/364.dbec4c2dc12e7b050dcc.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/384.fa432bdb7fb6b1c95ad6.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/439.37e271d7a80336daabe2.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/476.9b4f05a99f5003f82094.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/481.73c7a9290b7d35a8b9c1.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/512.b58fc0093d080b8ee61c.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/553.b4042a795c91d9ff71ef.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/553.b4042a795c91d9ff71ef.js.LICENSE.txt +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/635.9720593ee20b768da3ca.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/713.8e6edc9a965bdd578ca7.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/741.dc49867fafb03ea2ba4d.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/742.91e7b516c8699eea3373.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/785.3aa564fc148b37d1d719.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/888.34054db17bcf6e87ec95.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/898.4e9edb7f224152c1dcb4.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/898.4e9edb7f224152c1dcb4.js.LICENSE.txt +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/style.js +0 -0
- {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.1.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/third-party-licenses.json +0 -0
- {signalpilot_ai_internal-0.6.2.dist-info → signalpilot_ai_internal-0.7.1.dist-info}/WHEEL +0 -0
- {signalpilot_ai_internal-0.6.2.dist-info → signalpilot_ai_internal-0.7.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -506,6 +506,114 @@ class DeleteScannedDirectoryHandler(APIHandler):
|
|
|
506
506
|
"error": str(e)
|
|
507
507
|
}))
|
|
508
508
|
|
|
509
|
+
|
|
510
|
+
class NotebookToHTMLHandler(APIHandler):
|
|
511
|
+
"""Handler for converting notebooks to HTML using nbconvert"""
|
|
512
|
+
|
|
513
|
+
@tornado.web.authenticated
|
|
514
|
+
def post(self):
|
|
515
|
+
try:
|
|
516
|
+
# Parse request body
|
|
517
|
+
try:
|
|
518
|
+
data = json.loads(self.request.body.decode('utf-8'))
|
|
519
|
+
except json.JSONDecodeError:
|
|
520
|
+
self.set_status(400)
|
|
521
|
+
self.finish(json.dumps({
|
|
522
|
+
"error": "Invalid JSON in request body"
|
|
523
|
+
}))
|
|
524
|
+
return
|
|
525
|
+
|
|
526
|
+
# Get notebook path
|
|
527
|
+
notebook_path = data.get('notebook_path')
|
|
528
|
+
if not notebook_path:
|
|
529
|
+
self.set_status(400)
|
|
530
|
+
self.finish(json.dumps({
|
|
531
|
+
"error": "No notebook path provided"
|
|
532
|
+
}))
|
|
533
|
+
return
|
|
534
|
+
|
|
535
|
+
# Get export options with defaults
|
|
536
|
+
include_input = data.get('include_input', True)
|
|
537
|
+
include_output = data.get('include_output', True)
|
|
538
|
+
include_images = data.get('include_images', True)
|
|
539
|
+
|
|
540
|
+
# Convert to nbconvert options
|
|
541
|
+
exclude_input = not include_input
|
|
542
|
+
exclude_output = not include_output
|
|
543
|
+
|
|
544
|
+
try:
|
|
545
|
+
# Import nbconvert and nbformat
|
|
546
|
+
from nbconvert import HTMLExporter
|
|
547
|
+
from nbconvert.preprocessors import ExtractOutputPreprocessor
|
|
548
|
+
from nbformat import read
|
|
549
|
+
|
|
550
|
+
# Read the notebook file using nbformat
|
|
551
|
+
notebook_file_path = Path(notebook_path)
|
|
552
|
+
if not notebook_file_path.exists():
|
|
553
|
+
self.set_status(404)
|
|
554
|
+
self.finish(json.dumps({
|
|
555
|
+
"error": f"Notebook file not found: {notebook_path}"
|
|
556
|
+
}))
|
|
557
|
+
return
|
|
558
|
+
|
|
559
|
+
# Load notebook using nbformat.read (more robust)
|
|
560
|
+
with open(notebook_file_path, 'r', encoding='utf-8') as f:
|
|
561
|
+
notebook_content = read(f, as_version=4)
|
|
562
|
+
|
|
563
|
+
# Get the custom template path (relative to this file)
|
|
564
|
+
template_dir = Path(__file__).parent / 'html_export_template'
|
|
565
|
+
template_path = str(template_dir.resolve())
|
|
566
|
+
|
|
567
|
+
# Configure the HTML exporter with custom template
|
|
568
|
+
exporter = HTMLExporter(template_name=template_path)
|
|
569
|
+
|
|
570
|
+
# Set export options
|
|
571
|
+
exporter.exclude_input = exclude_input
|
|
572
|
+
exporter.exclude_output = exclude_output
|
|
573
|
+
exporter.exclude_input_prompt = True
|
|
574
|
+
exporter.exclude_output_prompt = True
|
|
575
|
+
|
|
576
|
+
# Configure image handling
|
|
577
|
+
if not include_images:
|
|
578
|
+
# Add preprocessor to exclude images
|
|
579
|
+
exporter.register_preprocessor(ExtractOutputPreprocessor(), enabled=True)
|
|
580
|
+
|
|
581
|
+
# Convert notebook to HTML - nbconvert handles everything
|
|
582
|
+
html_content, _ = exporter.from_notebook_node(notebook_content)
|
|
583
|
+
|
|
584
|
+
# Get absolute path for the notebook
|
|
585
|
+
workspace_notebook_path = str(notebook_file_path.absolute())
|
|
586
|
+
|
|
587
|
+
# Return the HTML content
|
|
588
|
+
self.finish(json.dumps({
|
|
589
|
+
"success": True,
|
|
590
|
+
"html_content": html_content,
|
|
591
|
+
"notebook_path": notebook_path,
|
|
592
|
+
"workspace_notebook_path": workspace_notebook_path,
|
|
593
|
+
"export_options": {
|
|
594
|
+
"include_input": include_input,
|
|
595
|
+
"include_output": include_output,
|
|
596
|
+
"include_images": include_images
|
|
597
|
+
}
|
|
598
|
+
}))
|
|
599
|
+
|
|
600
|
+
except ImportError as e:
|
|
601
|
+
self.set_status(500)
|
|
602
|
+
self.finish(json.dumps({
|
|
603
|
+
"error": f"Required packages not installed: {str(e)}. Please install them with: pip install nbconvert nbformat"
|
|
604
|
+
}))
|
|
605
|
+
except Exception as e:
|
|
606
|
+
self.set_status(500)
|
|
607
|
+
self.finish(json.dumps({
|
|
608
|
+
"error": f"Failed to convert notebook to HTML: {str(e)}"
|
|
609
|
+
}))
|
|
610
|
+
|
|
611
|
+
except Exception as e:
|
|
612
|
+
self.set_status(500)
|
|
613
|
+
self.finish(json.dumps({
|
|
614
|
+
"error": str(e)
|
|
615
|
+
}))
|
|
616
|
+
|
|
509
617
|
def setup_handlers(web_app):
|
|
510
618
|
host_pattern = ".*$"
|
|
511
619
|
base_url = web_app.settings["base_url"]
|
|
@@ -545,6 +653,9 @@ def setup_handlers(web_app):
|
|
|
545
653
|
snowflake_schema_route = url_path_join(base_url, "signalpilot-ai-internal", "snowflake", "schema")
|
|
546
654
|
snowflake_query_route = url_path_join(base_url, "signalpilot-ai-internal", "snowflake", "query")
|
|
547
655
|
|
|
656
|
+
# Notebook HTML export endpoint
|
|
657
|
+
notebook_html_route = url_path_join(base_url, "signalpilot-ai-internal", "notebook", "to-html")
|
|
658
|
+
|
|
548
659
|
handlers = [
|
|
549
660
|
# Original endpoint
|
|
550
661
|
(hello_route, HelloWorldHandler),
|
|
@@ -582,6 +693,9 @@ def setup_handlers(web_app):
|
|
|
582
693
|
# Snowflake service endpoints
|
|
583
694
|
(snowflake_schema_route, SnowflakeSchemaHandler),
|
|
584
695
|
(snowflake_query_route, SnowflakeQueryHandler),
|
|
696
|
+
|
|
697
|
+
# Notebook HTML export endpoint
|
|
698
|
+
(notebook_html_route, NotebookToHTMLHandler),
|
|
585
699
|
]
|
|
586
700
|
|
|
587
701
|
web_app.add_handlers(host_pattern, handlers)
|
|
@@ -609,3 +723,4 @@ def setup_handlers(web_app):
|
|
|
609
723
|
print(f" - MySQL Query: {mysql_query_route}")
|
|
610
724
|
print(f" - Snowflake Schema: {snowflake_schema_route}")
|
|
611
725
|
print(f" - Snowflake Query: {snowflake_query_route}")
|
|
726
|
+
print(f" - Notebook to HTML: {notebook_html_route}")
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# HTML Export Template with Code Toggle
|
|
2
|
+
|
|
3
|
+
This is a custom Jupyter NBConvert HTML template that adds a toggle to hide/show each code cell.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
The handler uses this template automatically. You can modify the notebook cells to control their visibility:
|
|
8
|
+
|
|
9
|
+
- By default, all code cells are hidden with a "Show Code" button
|
|
10
|
+
- To show a code cell by default, tag the cell with 'code_shown' in its metadata
|
|
11
|
+
|
|
12
|
+
## Template Files
|
|
13
|
+
|
|
14
|
+
- `index.html.j2` - The main template that extends lab/index.html.j2
|
|
15
|
+
- `conf.json` - Configuration for the template
|
|
16
|
+
- `README.md` - This file
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- Clean presentation with toggleable code cells
|
|
21
|
+
- Uses JQuery for smooth transitions
|
|
22
|
+
- Removes input/output prompts for cleaner appearance
|
|
23
|
+
- Responsive and modern styling
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{% extends 'lab/index.html.j2' %}
|
|
2
|
+
|
|
3
|
+
{% block html_head %}
|
|
4
|
+
{{ super() }}
|
|
5
|
+
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
|
|
6
|
+
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
|
|
7
|
+
crossorigin="anonymous"></script>
|
|
8
|
+
|
|
9
|
+
<script>
|
|
10
|
+
$(document).ready(function() {
|
|
11
|
+
$('.code_shower').on('click', function() {
|
|
12
|
+
var header = $(this);
|
|
13
|
+
var codecell = $(this).next();
|
|
14
|
+
|
|
15
|
+
// Ensure the codecell's parent is a flex column wrapper
|
|
16
|
+
var wrapper = codecell.parent();
|
|
17
|
+
wrapper.css('display', 'flex');
|
|
18
|
+
wrapper.css('flex-direction', 'column');
|
|
19
|
+
|
|
20
|
+
codecell.slideToggle(0, function() {
|
|
21
|
+
if (codecell.is(':hidden')) {
|
|
22
|
+
header.text("Show Code");
|
|
23
|
+
header.css("border-radius", "2px 2px 2px 2px");
|
|
24
|
+
} else {
|
|
25
|
+
header.text("Hide Code");
|
|
26
|
+
header.css("border-radius", "2px 2px 0px 0px");
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
$('.hidden_default').next().hide();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<style>
|
|
36
|
+
div.input {
|
|
37
|
+
flex-direction: column !important;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
div.input_area {
|
|
41
|
+
border-radius: 0px 0px 2px 2px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
div.code_shower {
|
|
45
|
+
background: lightgray;
|
|
46
|
+
padding: 5px 10px;
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
border-radius: 2px 2px 0px 0px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
</style>
|
|
52
|
+
{% endblock html_head %}
|
|
53
|
+
|
|
54
|
+
{% block input %}
|
|
55
|
+
{% if 'code_shown' in cell['metadata'].get('tags', []) %}
|
|
56
|
+
<div class="code_shower">Hide Code</div>
|
|
57
|
+
{% else %}
|
|
58
|
+
<div class="code_shower hidden_default">Show Code</div>
|
|
59
|
+
{% endif %}
|
|
60
|
+
|
|
61
|
+
{{ super() }}
|
|
62
|
+
{% endblock input %}
|
|
63
|
+
|
|
64
|
+
{% block output_prompt %}
|
|
65
|
+
{% endblock output_prompt %}
|
|
66
|
+
|
|
67
|
+
{% block in_prompt %}
|
|
68
|
+
{% endblock in_prompt %}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "signalpilot-ai-internal",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "SignalPilot Agent - Your Jupyter Notebook Assistant",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
"outputDir": "signalpilot_ai_internal/labextension",
|
|
135
135
|
"schemaDir": "schema",
|
|
136
136
|
"_build": {
|
|
137
|
-
"load": "static/remoteEntry.
|
|
137
|
+
"load": "static/remoteEntry.3dc6642d2a780c9a166d.js",
|
|
138
138
|
"extension": "./extension",
|
|
139
139
|
"style": "./style"
|
|
140
140
|
}
|