freeplane-and-yaml 0.1.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
File without changes
@@ -0,0 +1,40 @@
1
+ import sys
2
+ import os
3
+ from .convert import convert_yaml_file # Import your conversion logic
4
+
5
+
6
+ def main():
7
+ # Check for the correct number of arguments
8
+ if len(sys.argv) != 3:
9
+ print("Usage: convert input.yaml output_directory")
10
+ sys.exit(1)
11
+
12
+ # Parse arguments
13
+ input_file = sys.argv[1]
14
+ output_dir = sys.argv[2]
15
+
16
+ # Validate the input YAML file
17
+ if not input_file.endswith(".yaml"):
18
+ print(f"Error: {input_file} is not a valid YAML file.")
19
+ sys.exit(1)
20
+
21
+ if not os.path.isfile(input_file):
22
+ print(f"Error: Input file {input_file} does not exist.")
23
+ sys.exit(1)
24
+
25
+ # Validate the output directory
26
+ if not os.path.isdir(output_dir):
27
+ print(f"Error: Output directory {output_dir} does not exist.")
28
+ sys.exit(1)
29
+
30
+ # Generate the `.m` file name based on the input file
31
+ base_name = os.path.basename(input_file).replace(".yaml", ".mm")
32
+ output_file = os.path.join(output_dir, base_name)
33
+
34
+ # Perform the conversion
35
+ try:
36
+ convert_yaml_file(input_file, output_file)
37
+ print(f"Conversion complete: {output_file}")
38
+ except Exception as e:
39
+ print(f"Error during conversion: {e}")
40
+ sys.exit(1)
@@ -0,0 +1,100 @@
1
+ import yaml
2
+ from xml.etree.ElementTree import Element, SubElement, tostring
3
+ from xml.dom import minidom
4
+ import uuid
5
+ import argparse
6
+ import os
7
+
8
+ def generate_node_id():
9
+ """Generate a unique ID for a node."""
10
+ return f"ID_{str(uuid.uuid4()).replace('-', '_')}"
11
+
12
+ def create_note_element(note_text):
13
+ """Create a richcontent note element with the given text."""
14
+ richcontent = Element('richcontent', {
15
+ 'TYPE': 'NOTE',
16
+ 'CONTENT-TYPE': 'xml/'
17
+ })
18
+ html = SubElement(richcontent, 'html')
19
+ head = SubElement(html, 'head')
20
+ body = SubElement(html, 'body')
21
+ p = SubElement(body, 'p')
22
+ p.text = note_text
23
+ return richcontent
24
+
25
+ def add_node_recursive(parent_element, node_data, position=None):
26
+ """Recursively add nodes to the mind map."""
27
+ # Create node element with basic attributes
28
+ node_attrs = {
29
+ 'TEXT': node_data['title'],
30
+ 'ID': generate_node_id()
31
+ }
32
+ if position:
33
+ node_attrs['POSITION'] = position
34
+
35
+ node = SubElement(parent_element, 'node', node_attrs)
36
+
37
+ # Add note if present
38
+ if 'note' in node_data:
39
+ node.append(create_note_element(node_data['note']))
40
+
41
+ # Process children if present
42
+ if 'children' in node_data:
43
+ # Alternate positions for children
44
+ positions = ['right', 'left']
45
+ position_index = 0
46
+
47
+ for child_key, child_data in node_data['children'].items():
48
+ # Alternate between right and left for top-level children
49
+ child_position = positions[position_index % 2] if parent_element.tag == 'map' else None
50
+ position_index += 1
51
+ add_node_recursive(node, child_data, child_position)
52
+
53
+ def converter(yaml_content):
54
+ """Convert YAML content to Freeplane mind map format."""
55
+ # Parse YAML content
56
+ data = yaml.safe_load(yaml_content)
57
+
58
+ # Create the base map element
59
+ map_elem = Element('map', {'version': '1.9.13'})
60
+
61
+ # Add the root node and its children
62
+ add_node_recursive(map_elem, data['root'])
63
+
64
+ # Convert to string and pretty print
65
+ rough_string = tostring(map_elem, 'utf-8')
66
+ reparsed = minidom.parseString(rough_string)
67
+ pretty_xml = reparsed.toprettyxml(indent=" ")
68
+
69
+ # Add XML declaration
70
+ if not pretty_xml.startswith('<?xml'):
71
+ pretty_xml = '<?xml version="1.0" encoding="UTF-8"?>\n' + pretty_xml
72
+
73
+ return pretty_xml
74
+
75
+ def convert_yaml_file(yaml_file_path, output_file_path):
76
+ """Convert a YAML file to a Freeplane mind map file."""
77
+ with open(yaml_file_path, 'r', encoding='utf-8') as yaml_file:
78
+ yaml_content = yaml_file.read()
79
+
80
+ mind_map_xml = converter(yaml_content)
81
+
82
+ with open(output_file_path, 'w', encoding='utf-8') as mm_file:
83
+ mm_file.write(mind_map_xml)
84
+
85
+ # Example usage:
86
+ if __name__ == "__main__":
87
+ parser = argparse.ArgumentParser(description='Convert YAML file to Freeplane mind map')
88
+ parser.add_argument('input_file', help='Input YAML file path')
89
+ parser.add_argument('output_dir', help='Output directory for the mind map file')
90
+
91
+ args = parser.parse_args()
92
+
93
+ # Create output directory if it doesn't exist
94
+ os.makedirs(args.output_dir, exist_ok=True)
95
+
96
+ # Generate output filename based on input filename
97
+ input_basename = os.path.splitext(os.path.basename(args.input_file))[0]
98
+ output_file = os.path.join(args.output_dir, f"{input_basename}.mm")
99
+
100
+ convert_yaml_file(args.input_file, output_file)
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Romilly Cocking
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,133 @@
1
+ Metadata-Version: 2.1
2
+ Name: freeplane-and-yaml
3
+ Version: 0.1.1
4
+ Summary: A tool to convert YAML files to Freeplane MM format
5
+ Home-page: https://github.com/romilly/freeplane-and-yaml
6
+ Author: Romilly Cocking
7
+ Author-email: romilly.cocking@gmail.com
8
+ License: MIT
9
+ Platform: UNKNOWN
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.9
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: PyYAML
17
+
18
+ # YAML to Freeplane Converter
19
+
20
+ A Python tool that converts YAML files into Freeplane mind maps. This allows you to generate mind maps programmatically from structured YAML data.
21
+
22
+ The YAML file can be created using [Claude AI](https://claude.ai/chat/). A suitable prompt is given [below](#converting-documents-to-mind-maps-using-claude-ai).
23
+
24
+ You can read about how it got written using AI on [medium](https://medium.com/@romillyc/build-your-own-mind-map-tools-with-ai-b193564f2464?sk=b353aa7d16d6412e4aae8f3eab0ec554).
25
+ That's a friend link so you can read it even if you're not a subscriber.
26
+
27
+ ## Installation
28
+
29
+ First, clone this repository:
30
+
31
+ ```bash
32
+ # clone the project from GitHub
33
+ git clone https://github.com/romilly/freeplane-and-yaml.git
34
+ cd freeplane-and-yaml
35
+ ```
36
+
37
+ This project requires Python and should be run in a virtual environment:
38
+
39
+ ```bash
40
+ # Create and activate virtual environment
41
+ python -m venv venv
42
+ source venv/bin/activate # On Windows use: venv\Scripts\activate
43
+
44
+ # Install required packages
45
+ pip install pyyaml
46
+ ```
47
+
48
+ ## Usage
49
+
50
+ The code should be run from the `src` directory after activating the virtual environment. Your YAML file should follow the schema defined in `schema/mindmap-schema.json`. Here's an example structure:
51
+
52
+ ```yaml
53
+ root:
54
+ title: "Your Main Topic"
55
+ note: "Optional note for the main topic"
56
+ children:
57
+ subtopic1:
58
+ title: "Subtopic 1"
59
+ note: "Optional note for subtopic 1"
60
+ children:
61
+ # ... more nested topics
62
+ subtopic2:
63
+ title: "Subtopic 2"
64
+ # ... and so on
65
+ ```
66
+
67
+ ### YAML Schema Requirements
68
+
69
+ The YAML must conform to these rules:
70
+ - Must have a root node with a title and at least one child
71
+ - Each node requires a title
72
+ - Notes are optional
73
+ - Child node keys must be alphanumeric (including underscores)
74
+ - No additional properties are allowed beyond title, note, and children
75
+
76
+ For full schema details, see `schema/mindmap-schema.json`.
77
+
78
+ ### Converting Documents to Mind Maps using Claude AI
79
+
80
+ You can use Claude Sonnet to automatically convert documents (PDFs, articles, specifications, etc.) into the required YAML format. Here's the workflow:
81
+
82
+ 1. Share your document and the schema (from `schema/mindmap-schema.json`)with Claude Sonnet.
83
+ 2. Use this prompt:
84
+ ```
85
+ I've uploaded a document and a schema file. I'd like you to summarise the document as a yaml file following the schema that I uploaded.
86
+ ```
87
+ 3. Claude will generate a YAML file that follows the schema
88
+ 4. Save Claude's output as a .yaml file
89
+ 5. Convert it to a mind map using this tool
90
+
91
+ This workflow is useful for:
92
+ - Summarizing academic papers
93
+ - Converting product requirements documents (PRDs)
94
+ - Creating structured summaries of technical documentation
95
+ - Organizing research notes
96
+
97
+ ### Converting YAML to Mind Map
98
+
99
+ To convert a YAML file to a Freeplane mind map:
100
+
101
+ ```python
102
+ from freeplane_and_yaml.convert_yaml_to_freeplane import convert_yaml_file
103
+
104
+ # Convert YAML to mind map
105
+ convert_yaml_file('path/to/your/input.yaml', 'output.mm')
106
+ ```
107
+
108
+ The generated `.mm` file can be opened in Freeplane. When you first open the file, Freeplane will show this warning dialog because the file wasn't created by Freeplane itself:
109
+
110
+ ![Freeplane Warning Dialog](images/warning-dialog.png)
111
+
112
+ This is normal and expected — click OK to load the mind map.
113
+
114
+ Here's an example of how the output looks:
115
+
116
+ ![Example Mind Map](images/Screenshot%20at%202025-02-12%2010-43-23.png)
117
+
118
+ ## Features
119
+
120
+ - Converts YAML structured data to Freeplane mind map format
121
+ - Supports hierarchical node structure
122
+ - Includes node titles and optional notes
123
+ - Automatically alternates between right and left positions for top-level nodes
124
+ - Generates unique IDs for each node
125
+ - Validates input against JSON schema
126
+
127
+ ## License
128
+
129
+ Apologiresd to readers from the USA. This README uses UK spelling.
130
+
131
+ This project is licensed under the MIT Licence — see the [LICENCE](LICENSE) file for details.
132
+
133
+
@@ -0,0 +1,9 @@
1
+ freeplane_and_yaml/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ freeplane_and_yaml/cli.py,sha256=qeUJXw2MqCf6Kv7c-K63-srGj339beL4JTrAXi5_-3c,1213
3
+ freeplane_and_yaml/convert.py,sha256=dyQLt2FlmCgsQOnutnp1DyLXzqk-guazL8TZwTH0vHI,3440
4
+ freeplane_and_yaml-0.1.1.dist-info/LICENSE,sha256=gCmvBRHqGZibjt4wyMG81SeYWMKuhoGFVQh_Kn1wZ98,1072
5
+ freeplane_and_yaml-0.1.1.dist-info/METADATA,sha256=rK9H4NH6Z7rx89SzQs8c-ZtccsPrztOl6ukMyJ0CO78,4420
6
+ freeplane_and_yaml-0.1.1.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
7
+ freeplane_and_yaml-0.1.1.dist-info/entry_points.txt,sha256=kWuCk_RZlzcO9h7yk7uJ4dtJiccQxBocEuQPVt6qzxo,57
8
+ freeplane_and_yaml-0.1.1.dist-info/top_level.txt,sha256=UY6T4vy985r4DAfWpM1D_n6t0cEis5SxtfkPPd-xDhQ,19
9
+ freeplane_and_yaml-0.1.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.45.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ convert = freeplane_and_yaml.cli:main
3
+
@@ -0,0 +1 @@
1
+ freeplane_and_yaml