Small side quest. Added possibility to get the output also in html.
This commit is contained in:
parent
22ff45530d
commit
cf1674735d
@ -254,13 +254,14 @@ class TopicReader:
|
|||||||
|
|
||||||
return result.strip()
|
return result.strip()
|
||||||
|
|
||||||
def fetch_body_and_subtopics(self, heading_id: int, include_subtopics: bool = True) -> str:
|
def fetch_body_and_subtopics(self, heading_id: int, include_subtopics: bool = True, level_offset: int = 0) -> str:
|
||||||
"""
|
"""
|
||||||
Fetch body content and subtopics for a given heading.
|
Fetch body content and subtopics for a given heading with improved Markdown formatting.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
heading_id (int): ID of the heading to fetch.
|
heading_id (int): ID of the heading to fetch.
|
||||||
include_subtopics (bool): Whether to include subtopics in the result.
|
include_subtopics (bool): Whether to include subtopics in the result.
|
||||||
|
level_offset (int): Offset to adjust heading levels for proper nesting.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: Formatted string containing the heading content and subtopics.
|
str: Formatted string containing the heading content and subtopics.
|
||||||
@ -269,25 +270,50 @@ class TopicReader:
|
|||||||
self.db_manager.cursor.execute('SELECT level, title FROM headings WHERE id = ?', (heading_id,))
|
self.db_manager.cursor.execute('SELECT level, title FROM headings WHERE id = ?', (heading_id,))
|
||||||
level, title = self.db_manager.cursor.fetchone()
|
level, title = self.db_manager.cursor.fetchone()
|
||||||
|
|
||||||
# Fetch the content for this heading (the days in the calendar)
|
# Adjust the level based on the offset
|
||||||
|
adjusted_level = max(1, level - level_offset)
|
||||||
|
|
||||||
|
# Fetch the content for this heading
|
||||||
self.db_manager.cursor.execute('SELECT content FROM body WHERE heading_id = ?', (heading_id,))
|
self.db_manager.cursor.execute('SELECT content FROM body WHERE heading_id = ?', (heading_id,))
|
||||||
rows = self.db_manager.cursor.fetchall()
|
rows = self.db_manager.cursor.fetchall()
|
||||||
body_content = '\n'.join([row[0] for row in rows])
|
body_content = '\n'.join([row[0] for row in rows])
|
||||||
|
|
||||||
# Write the heading once and then its body content
|
# Construct the result with proper spacing
|
||||||
#result = f"\n{'#' * level} {title}\n{body_content.strip()}\n"
|
result = f"\n{'#' * adjusted_level} {title}\n\n"
|
||||||
result = f"{'#' * level} {title}\n\n{body_content.strip()}\n"
|
if body_content.strip():
|
||||||
|
result += f"{body_content.strip()}\n\n"
|
||||||
|
|
||||||
if include_subtopics:
|
if include_subtopics:
|
||||||
# Fetch all subtopics (e.g., days) that are children of the current heading
|
# Fetch all subtopics that are children of the current heading
|
||||||
subtopics = self._fetch_subtopics(heading_id, level)
|
subtopics = self._fetch_subtopics(heading_id, adjusted_level)
|
||||||
for subtopic_id, subtopic_level, subtopic_title in subtopics:
|
for subtopic_id, _, _ in subtopics:
|
||||||
# Recursively fetch subtopic content
|
# Recursively fetch subtopic content
|
||||||
subtopic_content = self.fetch_body_and_subtopics(subtopic_id, include_subtopics=True)
|
subtopic_content = self.fetch_body_and_subtopics(subtopic_id, include_subtopics=True, level_offset=level_offset)
|
||||||
result += subtopic_content
|
result += subtopic_content
|
||||||
|
|
||||||
#return result.strip() # Strip extra newlines
|
return result.strip() + "\n" # Ensure there's a newline at the end of each section
|
||||||
return result
|
|
||||||
|
def get_topic_content(self, input_title: str) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
Get the content of a topic based on the input title, including its topic chain and subtopics.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str or None: Formatted string containing the topic chain, content, and subtopics, or None if not found.
|
||||||
|
"""
|
||||||
|
heading_id = self.find_closest_heading(input_title)
|
||||||
|
if heading_id:
|
||||||
|
topic_chain = self.fetch_topic_chain(heading_id)
|
||||||
|
result = ""
|
||||||
|
for i, (id, title, level) in enumerate(topic_chain):
|
||||||
|
if id == heading_id:
|
||||||
|
# Fetch the full content for the selected topic and its subtopics
|
||||||
|
result += self.fetch_body_and_subtopics(id, include_subtopics=True, level_offset=i)
|
||||||
|
else:
|
||||||
|
# Include only the heading chain without duplicating content
|
||||||
|
result += f"\n{'#' * (level - i)} {title}\n\n"
|
||||||
|
return result.strip() + "\n" # Ensure there's a final newline
|
||||||
|
print(f"No topic found matching '{input_title}'.")
|
||||||
|
return None
|
||||||
|
|
||||||
def _fetch_subtopics(self, heading_id: int, parent_level: int) -> List[Tuple[int, int, str]]:
|
def _fetch_subtopics(self, heading_id: int, parent_level: int) -> List[Tuple[int, int, str]]:
|
||||||
"""
|
"""
|
||||||
@ -308,30 +334,6 @@ class TopicReader:
|
|||||||
''', (heading_id,))
|
''', (heading_id,))
|
||||||
return self.db_manager.cursor.fetchall()
|
return self.db_manager.cursor.fetchall()
|
||||||
|
|
||||||
|
|
||||||
def get_topic_content(self, input_title: str) -> Optional[str]:
|
|
||||||
"""
|
|
||||||
Get the content of a topic based on the input title, including its topic chain and subtopics.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str or None: Formatted string containing the topic chain, content, and subtopics, or None if not found.
|
|
||||||
"""
|
|
||||||
heading_id = self.find_closest_heading(input_title)
|
|
||||||
if heading_id:
|
|
||||||
topic_chain = self.fetch_topic_chain(heading_id)
|
|
||||||
result = ""
|
|
||||||
for id, title, level in topic_chain:
|
|
||||||
if id == heading_id:
|
|
||||||
# Fetch the full content for the selected topic and its subtopics
|
|
||||||
result += self.fetch_body_and_subtopics(id, include_subtopics=True)
|
|
||||||
else:
|
|
||||||
# Include only the heading chain without duplicating content
|
|
||||||
result += f"\n{'#' * level} {title}\n\n"
|
|
||||||
return result.strip() # Ensure there are no trailing newlines
|
|
||||||
print(f"No topic found matching '{input_title}'.")
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def find_closest_heading(self, input_title: str) -> Optional[int]:
|
def find_closest_heading(self, input_title: str) -> Optional[int]:
|
||||||
"""
|
"""
|
||||||
Find the closest matching heading to the input title using fuzzy matching.
|
Find the closest matching heading to the input title using fuzzy matching.
|
||||||
@ -357,8 +359,6 @@ class TopicReader:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def compute_file_hash(file_path: str) -> str:
|
def compute_file_hash(file_path: str) -> str:
|
||||||
"""
|
"""
|
||||||
Compute the MD5 hash of a file.
|
Compute the MD5 hash of a file.
|
||||||
@ -369,7 +369,6 @@ def compute_file_hash(file_path: str) -> str:
|
|||||||
hash_md5.update(chunk)
|
hash_md5.update(chunk)
|
||||||
return hash_md5.hexdigest()
|
return hash_md5.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def generate_calendar(year: int) -> str:
|
def generate_calendar(year: int) -> str:
|
||||||
"""Generate a markdown calendar for the specified year."""
|
"""Generate a markdown calendar for the specified year."""
|
||||||
calendar_markdown = f"# {year}\n\n"
|
calendar_markdown = f"# {year}\n\n"
|
||||||
@ -397,6 +396,38 @@ def generate_calendar(year: int) -> str:
|
|||||||
|
|
||||||
return calendar_markdown
|
return calendar_markdown
|
||||||
|
|
||||||
|
def convert_to_html(markdown_content: str) -> str:
|
||||||
|
"""
|
||||||
|
Convert Markdown content to HTML.
|
||||||
|
"""
|
||||||
|
md = MarkdownIt()
|
||||||
|
html_content = md.render(markdown_content)
|
||||||
|
|
||||||
|
# Wrap the content in a basic HTML structure
|
||||||
|
html_document = f"""
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Calendar</title>
|
||||||
|
<style>
|
||||||
|
body {{ font-family: Arial, sans-serif; line-height: 1.6; padding: 20px; }}
|
||||||
|
h1, h2, h3, h4, h5, h6 {{ margin-top: 24px; margin-bottom: 16px; }}
|
||||||
|
h1 {{ font-size: 2em; }}
|
||||||
|
h2 {{ font-size: 1.5em; }}
|
||||||
|
h3 {{ font-size: 1.25em; }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{html_content}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
return html_document
|
||||||
|
|
||||||
|
|
||||||
def bootstrap_calendar(year: int, db_manager: DatabaseManager, markdown_file: str):
|
def bootstrap_calendar(year: int, db_manager: DatabaseManager, markdown_file: str):
|
||||||
"""Generate and store a full year's markdown calendar in the database."""
|
"""Generate and store a full year's markdown calendar in the database."""
|
||||||
calendar_content = generate_calendar(year)
|
calendar_content = generate_calendar(year)
|
||||||
@ -435,6 +466,7 @@ def main():
|
|||||||
parser.add_argument('topic_title', nargs='?', type=str, help='Topic title to select (fuzzy matching enabled)')
|
parser.add_argument('topic_title', nargs='?', type=str, help='Topic title to select (fuzzy matching enabled)')
|
||||||
parser.add_argument('--bootstrap', action='store_true', help='Generate markdown calendar for the current year and load it to the database.')
|
parser.add_argument('--bootstrap', action='store_true', help='Generate markdown calendar for the current year and load it to the database.')
|
||||||
parser.add_argument('--ls', action='store_true', help='List all available headings.')
|
parser.add_argument('--ls', action='store_true', help='List all available headings.')
|
||||||
|
parser.add_argument('--html', action='store_true', help='Generate an HTML version of the output')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Use the provided or default file paths
|
# Use the provided or default file paths
|
||||||
@ -508,8 +540,17 @@ def main():
|
|||||||
# If content is found, write it back to the original markdown file
|
# If content is found, write it back to the original markdown file
|
||||||
with open(markdown_file, 'w', encoding='utf-8') as file:
|
with open(markdown_file, 'w', encoding='utf-8') as file:
|
||||||
file.write(result)
|
file.write(result)
|
||||||
|
file.write('\n')
|
||||||
print(f"Selected topic and subtopics written to {markdown_file}")
|
print(f"Selected topic and subtopics written to {markdown_file}")
|
||||||
|
|
||||||
|
# Generate HTML if --html option is specified
|
||||||
|
if args.html:
|
||||||
|
html_file = os.path.splitext(markdown_file)[0] + '.html'
|
||||||
|
html_content = convert_to_html(result)
|
||||||
|
with open(html_file, 'w', encoding='utf-8') as file:
|
||||||
|
file.write(html_content)
|
||||||
|
print(f"HTML version written to {html_file}")
|
||||||
|
|
||||||
# Update the document hash in the database
|
# Update the document hash in the database
|
||||||
new_file_hash = compute_file_hash(markdown_file)
|
new_file_hash = compute_file_hash(markdown_file)
|
||||||
document_manager.update_document_hash(document_id, new_file_hash)
|
document_manager.update_document_hash(document_id, new_file_hash)
|
||||||
@ -519,6 +560,16 @@ def main():
|
|||||||
else:
|
else:
|
||||||
print("No topic title provided. The database has been updated/added without modifying the file.")
|
print("No topic title provided. The database has been updated/added without modifying the file.")
|
||||||
|
|
||||||
|
# Generate HTML for the entire document if --html option is specified
|
||||||
|
if args.html:
|
||||||
|
with open(markdown_file, 'r', encoding='utf-8') as file:
|
||||||
|
markdown_content = file.read()
|
||||||
|
html_file = os.path.splitext(markdown_file)[0] + '.html'
|
||||||
|
html_content = convert_to_html(markdown_content)
|
||||||
|
with open(html_file, 'w', encoding='utf-8') as file:
|
||||||
|
file.write(html_content)
|
||||||
|
print(f"HTML version of the entire document written to {html_file}")
|
||||||
|
|
||||||
# Close the database connection
|
# Close the database connection
|
||||||
db_manager.close()
|
db_manager.close()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user