signalpilot-ai-internal 0.6.2__py3-none-any.whl → 0.7.0__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.

Files changed (41) hide show
  1. signalpilot_ai_internal/_version.py +1 -1
  2. signalpilot_ai_internal/handlers.py +115 -0
  3. signalpilot_ai_internal/html_export_template/README.md +23 -0
  4. signalpilot_ai_internal/html_export_template/conf.json +12 -0
  5. signalpilot_ai_internal/html_export_template/index.html.j2 +68 -0
  6. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/package.json +2 -2
  7. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/schemas/signalpilot-ai-internal/package.json.orig +1 -1
  8. signalpilot_ai_internal-0.7.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/490.64082742bb093355f325.js +1 -0
  9. signalpilot_ai_internal-0.7.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/839.36369a64b4091ebf346c.js +1 -0
  10. signalpilot_ai_internal-0.6.2.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/remoteEntry.113fd565b968ed5ddfc0.js → signalpilot_ai_internal-0.7.0.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/remoteEntry.c1c2aff8be2db6bbb193.js +1 -1
  11. {signalpilot_ai_internal-0.6.2.dist-info → signalpilot_ai_internal-0.7.0.dist-info}/METADATA +1 -1
  12. {signalpilot_ai_internal-0.6.2.dist-info → signalpilot_ai_internal-0.7.0.dist-info}/RECORD +39 -36
  13. signalpilot_ai_internal-0.6.2.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/188.1ace26ac1a5e246783bb.js +0 -1
  14. signalpilot_ai_internal-0.6.2.data/data/share/jupyter/labextensions/signalpilot-ai-internal/static/839.35ca24b793cb523218f9.js +0 -1
  15. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/etc/jupyter/jupyter_server_config.d/signalpilot_ai.json +0 -0
  16. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/install.json +0 -0
  17. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/schemas/signalpilot-ai-internal/plugin.json +0 -0
  18. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/122.e2dadf63dc64d7b5f1ee.js +0 -0
  19. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/220.328403b5545f268b95c6.js +0 -0
  20. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/262.726e1da31a50868cb297.js +0 -0
  21. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/353.72484b768a04f89bd3dd.js +0 -0
  22. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/364.dbec4c2dc12e7b050dcc.js +0 -0
  23. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/384.fa432bdb7fb6b1c95ad6.js +0 -0
  24. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/439.37e271d7a80336daabe2.js +0 -0
  25. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/476.9b4f05a99f5003f82094.js +0 -0
  26. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/481.73c7a9290b7d35a8b9c1.js +0 -0
  27. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/512.b58fc0093d080b8ee61c.js +0 -0
  28. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/553.b4042a795c91d9ff71ef.js +0 -0
  29. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/553.b4042a795c91d9ff71ef.js.LICENSE.txt +0 -0
  30. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/635.9720593ee20b768da3ca.js +0 -0
  31. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/713.8e6edc9a965bdd578ca7.js +0 -0
  32. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/741.dc49867fafb03ea2ba4d.js +0 -0
  33. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/742.91e7b516c8699eea3373.js +0 -0
  34. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/785.3aa564fc148b37d1d719.js +0 -0
  35. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/888.34054db17bcf6e87ec95.js +0 -0
  36. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/898.4e9edb7f224152c1dcb4.js +0 -0
  37. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/898.4e9edb7f224152c1dcb4.js.LICENSE.txt +0 -0
  38. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/style.js +0 -0
  39. {signalpilot_ai_internal-0.6.2.data → signalpilot_ai_internal-0.7.0.data}/data/share/jupyter/labextensions/signalpilot-ai-internal/static/third-party-licenses.json +0 -0
  40. {signalpilot_ai_internal-0.6.2.dist-info → signalpilot_ai_internal-0.7.0.dist-info}/WHEEL +0 -0
  41. {signalpilot_ai_internal-0.6.2.dist-info → signalpilot_ai_internal-0.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
1
1
  # This file is auto-generated by Hatchling. As such, do not:
2
2
  # - modify
3
3
  # - track in version control e.g. be sure to add to .gitignore
4
- __version__ = VERSION = '0.6.2'
4
+ __version__ = VERSION = '0.7.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,12 @@
1
+ {
2
+ "base_template": "lab",
3
+ "mimetypes": {
4
+ "text/html": true
5
+ },
6
+ "preprocessors": {
7
+ "100-pygments": {
8
+ "type": "nbconvert.preprocessors.CSSHTMLHeaderPreprocessor",
9
+ "enabled": true
10
+ }
11
+ }
12
+ }
@@ -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.6.2",
3
+ "version": "0.7.0",
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.113fd565b968ed5ddfc0.js",
137
+ "load": "static/remoteEntry.c1c2aff8be2db6bbb193.js",
138
138
  "extension": "./extension",
139
139
  "style": "./style"
140
140
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signalpilot-ai-internal",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "SignalPilot Agent - Your Jupyter Notebook Assistant",
5
5
  "keywords": [
6
6
  "jupyter",