Prak2005 commited on
Commit
b2bc1b8
Β·
verified Β·
1 Parent(s): 0728473

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +64 -377
app.py CHANGED
@@ -23,7 +23,6 @@ import requests
23
  from PIL import Image as PilImage
24
  import io
25
  import tempfile
26
- import time
27
  from datetime import datetime
28
 
29
  # Set up logging
@@ -33,9 +32,6 @@ logging.basicConfig(
33
  )
34
  logger = logging.getLogger(__name__)
35
 
36
- # Get Gemini API key from Hugging Face Space secrets
37
- GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
38
-
39
  class MarkdownToPDFConverter:
40
  """
41
  Class to convert Markdown content to PDF using ReportLab.
@@ -49,8 +45,7 @@ class MarkdownToPDFConverter:
49
  base_font_size: int = 10,
50
  heading_scale: Dict[int, float] = None,
51
  include_toc: bool = True,
52
- code_style: str = "github",
53
- color_theme: str = "Default"
54
  ):
55
  """
56
  Initialize the converter with configuration options.
@@ -64,7 +59,6 @@ class MarkdownToPDFConverter:
64
  heading_scale: Dictionary of heading levels to font size multipliers
65
  include_toc: Whether to include a table of contents
66
  code_style: Style to use for code blocks
67
- color_theme: Color theme for the PDF
68
  """
69
  self.output_path = output_path
70
  self.page_size = A4 if page_size.upper() == "A4" else letter
@@ -81,7 +75,6 @@ class MarkdownToPDFConverter:
81
  }
82
  self.include_toc = include_toc
83
  self.code_style = code_style
84
- self.color_theme = color_theme
85
 
86
  # Initialize styles
87
  self.styles = getSampleStyleSheet()
@@ -93,18 +86,6 @@ class MarkdownToPDFConverter:
93
 
94
  def _setup_styles(self) -> None:
95
  """Set up custom paragraph styles for the document."""
96
- # Color theme configuration
97
- theme_colors = {
98
- "Default": {"headings": HexColor('#000000'), "code_bg": HexColor('#EEEEEE')},
99
- "Modern": {"headings": HexColor('#2962FF'), "code_bg": HexColor('#F5F5F5')},
100
- "Professional": {"headings": HexColor('#1565C0'), "code_bg": HexColor('#F8F9FA')},
101
- "Creative": {"headings": HexColor('#6200EA'), "code_bg": HexColor('#F3E5F5')},
102
- "Elegant": {"headings": HexColor('#00695C'), "code_bg": HexColor('#E0F2F1')}
103
- }
104
-
105
- # Use selected theme or default
106
- theme = theme_colors.get(self.color_theme, theme_colors["Default"])
107
-
108
  # Modify existing Normal style
109
  self.styles['Normal'].fontName = self.font_name
110
  self.styles['Normal'].fontSize = self.base_font_size
@@ -125,7 +106,6 @@ class MarkdownToPDFConverter:
125
  self.styles[heading_name].leading = int(self.base_font_size * size_multiplier * 1.2)
126
  self.styles[heading_name].spaceAfter = self.base_font_size
127
  self.styles[heading_name].spaceBefore = self.base_font_size * (1 + (0.2 * (7 - level)))
128
- self.styles[heading_name].textColor = theme["headings"]
129
  else:
130
  # Create new style
131
  self.styles.add(
@@ -137,7 +117,6 @@ class MarkdownToPDFConverter:
137
  leading=int(self.base_font_size * size_multiplier * 1.2),
138
  spaceAfter=self.base_font_size,
139
  spaceBefore=self.base_font_size * (1 + (0.2 * (7 - level))),
140
- textColor=theme["headings"]
141
  )
142
  )
143
 
@@ -151,26 +130,12 @@ class MarkdownToPDFConverter:
151
  spaceAfter=self.base_font_size,
152
  spaceBefore=self.base_font_size,
153
  leftIndent=self.base_font_size,
154
- backgroundColor=theme["code_bg"],
155
  borderWidth=0,
156
  borderPadding=self.base_font_size * 0.5,
157
  )
158
  )
159
 
160
- # Blockquote style
161
- self.styles.add(
162
- ParagraphStyle(
163
- name='Blockquote',
164
- parent=self.styles['Normal'],
165
- leftIndent=self.base_font_size * 2,
166
- rightIndent=self.base_font_size,
167
- fontStyle='italic',
168
- spaceAfter=self.base_font_size,
169
- spaceBefore=self.base_font_size,
170
- textColor=HexColor('#555555'),
171
- )
172
- )
173
-
174
  # List item style
175
  self.styles.add(
176
  ParagraphStyle(
@@ -188,7 +153,6 @@ class MarkdownToPDFConverter:
188
  parent=self.styles['Heading1'],
189
  fontSize=int(self.base_font_size * 1.5),
190
  spaceAfter=self.base_font_size * 1.5,
191
- textColor=theme["headings"],
192
  )
193
  )
194
 
@@ -278,8 +242,7 @@ class MarkdownToPDFConverter:
278
  base_font_size=self.base_font_size,
279
  heading_scale=self.heading_scale,
280
  include_toc=separate_toc,
281
- code_style=self.code_style,
282
- color_theme=self.color_theme
283
  )
284
  converter.convert_file(file_path)
285
 
@@ -355,19 +318,6 @@ class MarkdownToPDFConverter:
355
  Preformatted(code, self.styles['CodeBlock'])
356
  )
357
 
358
- elif element.name == 'blockquote':
359
- # Process blockquote content
360
- blockquote_text = ""
361
- for child in element.children:
362
- if hasattr(child, 'name') and child.name:
363
- blockquote_text += self._process_inline_elements(child)
364
- else:
365
- blockquote_text += str(child)
366
-
367
- self.elements.append(
368
- Paragraph(blockquote_text, self.styles['Blockquote'])
369
- )
370
-
371
  elif element.name == 'img':
372
  src = element.get('src', '')
373
  alt = element.get('alt', 'Image')
@@ -428,7 +378,7 @@ class MarkdownToPDFConverter:
428
 
429
  elif element.name == 'ul' or element.name == 'ol':
430
  list_items = []
431
- is_ordered = element.name == 'ol'
432
 
433
  for item in element.find_all('li', recursive=False):
434
  text = self._process_inline_elements(item)
@@ -439,21 +389,12 @@ class MarkdownToPDFConverter:
439
  )
440
  )
441
 
442
- if is_ordered:
443
- self.elements.append(
444
- ListFlowable(
445
- list_items,
446
- bulletType='1',
447
- start=1,
448
- bulletFormat='%s.'
449
- )
450
- )
451
- else:
452
  self.elements.append(
453
  ListFlowable(
454
  list_items,
455
- bulletType='bullet',
456
- bulletFormat='%s'
 
457
  )
458
  )
459
 
@@ -651,7 +592,7 @@ class MarkdownToPDFAgent:
651
  try:
652
  from langchain_google_genai import ChatGoogleGenerativeAI
653
 
654
- api_key = api_key or os.getenv("GEMINI_API_KEY") or GEMINI_API_KEY
655
  if not api_key:
656
  logger.warning("No Google API key provided. Agent will run without LLM enhancement.")
657
  return False
@@ -753,8 +694,7 @@ class MarkdownToPDFAgent:
753
  return '\n'.join(result_lines)
754
 
755
  def process_file(self, input_path: str, output_path: str = None, enhance: bool = False,
756
- enhancement_instructions: str = None, page_size: str = "A4",
757
- color_theme: str = "Default") -> str:
758
  """
759
  Process a single markdown file and convert it to PDF.
760
 
@@ -764,7 +704,6 @@ class MarkdownToPDFAgent:
764
  enhance: Whether to enhance the content with LLM
765
  enhancement_instructions: Specific instructions for enhancement
766
  page_size: Page size for the PDF ("A4" or "letter")
767
- color_theme: Color theme for the PDF
768
 
769
  Returns:
770
  Path to the generated PDF
@@ -790,8 +729,7 @@ class MarkdownToPDFAgent:
790
  # Configure converter
791
  self.converter = MarkdownToPDFConverter(
792
  output_path=output_path,
793
- page_size=page_size,
794
- color_theme=color_theme
795
  )
796
 
797
  # Convert to PDF
@@ -803,7 +741,7 @@ class MarkdownToPDFAgent:
803
  def process_directory(self, input_dir: str, output_dir: str = None, pattern: str = "*.md",
804
  enhance: bool = False, merge: bool = False,
805
  output_filename: str = "merged_document.pdf",
806
- page_size: str = "A4", color_theme: str = "Default") -> List[str]:
807
  """
808
  Process all markdown files in a directory.
809
 
@@ -815,7 +753,6 @@ class MarkdownToPDFAgent:
815
  merge: Whether to merge all files into a single PDF
816
  output_filename: Filename for merged PDF
817
  page_size: Page size for the PDF ("A4" or "letter")
818
- color_theme: Color theme for the PDF
819
 
820
  Returns:
821
  List of paths to generated PDFs
@@ -867,8 +804,7 @@ class MarkdownToPDFAgent:
867
  output_path = os.path.join(output_dir, output_filename)
868
  self.converter = MarkdownToPDFConverter(
869
  output_path=output_path,
870
- page_size=page_size,
871
- color_theme=color_theme
872
  )
873
  self.converter.convert_content(merged_content)
874
 
@@ -878,8 +814,7 @@ class MarkdownToPDFAgent:
878
  output_path = os.path.join(output_dir, output_filename)
879
  self.converter = MarkdownToPDFConverter(
880
  output_path=output_path,
881
- page_size=page_size,
882
- color_theme=color_theme
883
  )
884
  self.converter.convert_multiple_files(md_files, merge=True)
885
 
@@ -896,8 +831,7 @@ class MarkdownToPDFAgent:
896
  md_file,
897
  output_path,
898
  enhance=enhance,
899
- page_size=page_size,
900
- color_theme=color_theme
901
  )
902
 
903
  if processed_file:
@@ -905,159 +839,10 @@ class MarkdownToPDFAgent:
905
 
906
  return output_files
907
 
908
- # Sample markdown templates
909
- SAMPLE_TEMPLATES = {
910
- "report": """# Professional Report
911
-
912
- ## Executive Summary
913
-
914
- This report presents an analysis of the key findings, methodologies, and recommendations for consideration.
915
-
916
- ## Introduction
917
-
918
- In this section, we provide context and background information essential for understanding the purpose and scope of this report.
919
-
920
- ## Methodology
921
-
922
- Our approach included the following steps:
923
-
924
- 1. Data collection from multiple sources
925
- 2. Rigorous analysis using industry-standard techniques
926
- 3. Validation of findings through peer review
927
- 4. Development of actionable recommendations
928
-
929
- ## Key Findings
930
-
931
- | Area | Status | Impact |
932
- |------|--------|--------|
933
- | Operations | Satisfactory | Medium |
934
- | Finance | Needs Improvement | High |
935
- | Marketing | Excellent | Medium |
936
-
937
- ## Recommendations
938
-
939
- - Implement process improvements in the finance department
940
- - Continue successful marketing strategies
941
- - Monitor operational metrics quarterly
942
-
943
- ## Conclusion
944
-
945
- The analysis reveals several opportunities for improvement while highlighting existing strengths.
946
-
947
- > **Note:** This report should be reviewed by all stakeholders before implementation.
948
- """,
949
-
950
- "documentation": """# Product Documentation
951
-
952
- ## Overview
953
-
954
- This document provides comprehensive information about the product, its features, and usage instructions.
955
-
956
- ## Features
957
-
958
- - **Fast Processing**: Optimized algorithms ensure quick results
959
- - **User-Friendly Interface**: Intuitive design for ease of use
960
- - **Advanced Analytics**: In-depth insights and reporting
961
- - **Secure Storage**: End-to-end encryption for all data
962
-
963
- ## Installation
964
-
965
- ```bash
966
- # Install via package manager
967
- npm install product-name
968
-
969
- # Initialize with configuration
970
- product-init --config=standard
971
- ```
972
-
973
- ## Usage Examples
974
-
975
- Here's a simple example of how to use the main features:
976
-
977
- ```javascript
978
- import { Product } from 'product-name';
979
-
980
- // Initialize with settings
981
- const myProduct = new Product({
982
- mode: 'advanced',
983
- logging: true
984
- });
985
-
986
- // Process data
987
- const results = myProduct.analyze(data);
988
- console.log(results);
989
- ```
990
-
991
- ## Troubleshooting
992
-
993
- | Issue | Solution |
994
- |-------|----------|
995
- | Connection Error | Check network settings and firewall |
996
- | Performance Issues | Increase memory allocation in config |
997
- | Data Import Failure | Verify file format compatibility |
998
-
999
- ## Support
1000
-
1001
- For additional assistance, contact [email protected] or visit our help center.
1002
- """,
1003
-
1004
- "article": """# The Future of Technology: Trends to Watch
1005
-
1006
- ## Introduction
1007
-
1008
- Technology continues to evolve at an unprecedented pace, transforming how we live, work, and interact. This article explores emerging trends that will shape our future.
1009
-
1010
- ## Artificial Intelligence Advancements
1011
-
1012
- AI systems are becoming increasingly sophisticated, with applications across:
1013
-
1014
- - **Healthcare**: Diagnostic tools and personalized treatment plans
1015
- - **Finance**: Algorithmic trading and fraud detection
1016
- - **Manufacturing**: Predictive maintenance and quality control
1017
- - **Transportation**: Autonomous vehicles and smart traffic management
1018
-
1019
- Recent research has shown that AI can now outperform human experts in specific domains while complementing human skills in others.
1020
-
1021
- ## Sustainable Technology
1022
-
1023
- As environmental concerns mount, sustainable technology is gaining prominence:
1024
-
1025
- 1. Renewable energy systems with improved efficiency
1026
- 2. Eco-friendly materials for hardware manufacturing
1027
- 3. Energy-optimized algorithms and software
1028
- 4. Circular economy approaches to technology lifecycle
1029
-
1030
- ## Decentralized Systems
1031
-
1032
- Blockchain and related technologies are enabling new decentralized approaches:
1033
-
1034
- ```
1035
- Traditional Model β†’ Decentralized Alternative
1036
- Central Database β†’ Distributed Ledger
1037
- Single Authority β†’ Consensus Mechanism
1038
- Opaque Processes β†’ Transparent Verification
1039
- ```
1040
-
1041
- ## Conclusion
1042
-
1043
- These technological trends promise significant benefits but also present challenges that require thoughtful approaches to governance, ethics, and implementation.
1044
-
1045
- > "The best way to predict the future is to invent it." - Alan Kay
1046
- """
1047
- }
1048
-
1049
  # Gradio Interface for Hugging Face
1050
- def load_sample(template_choice="Basic"):
1051
- """Load a sample markdown document based on template choice."""
1052
- if template_choice == "Report":
1053
- return SAMPLE_TEMPLATES["report"]
1054
- elif template_choice == "Documentation":
1055
- return SAMPLE_TEMPLATES["documentation"]
1056
- elif template_choice == "Article":
1057
- return SAMPLE_TEMPLATES["article"]
1058
- else:
1059
- # Default basic sample
1060
- return """# Sample Markdown Document
1061
 
1062
  ## Introduction
1063
  This is a sample markdown document to demonstrate the capabilities of **MarkdownMuse**. You can use this as a starting point for your own documents.
@@ -1085,8 +870,7 @@ def hello_world():
1085
  """
1086
 
1087
  def process_markdown(markdown_text, page_size, font_size, font_name,
1088
- margin_size, include_toc, color_theme, use_ai,
1089
- enhancement_instructions=None):
1090
  """
1091
  Process markdown text and generate a PDF.
1092
 
@@ -1098,7 +882,7 @@ def process_markdown(markdown_text, page_size, font_size, font_name,
1098
  output_path = temp_file.name
1099
  temp_file.close()
1100
 
1101
- # Initialize the agent
1102
  agent = MarkdownToPDFAgent()
1103
 
1104
  # Configure converter
@@ -1108,17 +892,12 @@ def process_markdown(markdown_text, page_size, font_size, font_name,
1108
  base_font_size=font_size,
1109
  font_name=font_name,
1110
  margins=(margin_size, margin_size, margin_size, margin_size),
1111
- include_toc=include_toc,
1112
- color_theme=color_theme
1113
  )
1114
 
1115
- # Check for API key in environment if AI enhancement is enabled
1116
  enhance = False
1117
-
1118
- if use_ai:
1119
- # Use the API key from Hugging Face secrets if available
1120
- api_key = GEMINI_API_KEY
1121
-
1122
  if api_key:
1123
  success = agent.setup_from_gemini(api_key)
1124
  enhance = success
@@ -1134,9 +913,8 @@ def process_markdown(markdown_text, page_size, font_size, font_name,
1134
  temp_md_path,
1135
  output_path,
1136
  enhance=enhance,
1137
- enhancement_instructions=enhancement_instructions,
1138
- page_size=page_size.lower(),
1139
- color_theme=color_theme
1140
  )
1141
 
1142
  # Remove the temporary md file
@@ -1150,116 +928,29 @@ def process_markdown(markdown_text, page_size, font_size, font_name,
1150
  logger.error(f"Error processing markdown: {e}")
1151
  return None
1152
 
1153
- def upload_handler(files):
1154
- """Handle file uploads and extract markdown content"""
1155
- if not files:
1156
- return ""
1157
-
1158
- # Get the first file
1159
- file = files[0]
1160
-
1161
- try:
1162
- # Read the file content
1163
- if hasattr(file, 'read'):
1164
- # File is a file-like object
1165
- content = file.read().decode('utf-8')
1166
- else:
1167
- # File is a path
1168
- with open(file, 'r', encoding='utf-8') as f:
1169
- content = f.read()
1170
-
1171
- return content
1172
- except Exception as e:
1173
- logger.error(f"Error reading uploaded file: {e}")
1174
- return f"Error reading file: {str(e)}"
1175
-
1176
- # Define custom CSS for improved UI
1177
- custom_css = """
1178
- .gradio-container {
1179
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
1180
- }
1181
-
1182
- .app-header {
1183
- text-align: center;
1184
- margin-bottom: 2rem;
1185
- }
1186
-
1187
- .app-header h1 {
1188
- font-size: 2.5rem;
1189
- font-weight: 700;
1190
- color: #2E7D32;
1191
- margin-bottom: 0.5rem;
1192
- }
1193
-
1194
- .app-header p {
1195
- font-size: 1.1rem;
1196
- color: #6c757d;
1197
- }
1198
-
1199
- .template-selector {
1200
- margin-bottom: 1rem;
1201
- }
1202
-
1203
- footer {
1204
- text-align: center;
1205
- margin-top: 2rem;
1206
- padding-top: 1rem;
1207
- border-top: 1px solid #e9ecef;
1208
- color: #6c757d;
1209
- }
1210
-
1211
- .output-container {
1212
- border: 1px solid #e9ecef;
1213
- border-radius: 0.5rem;
1214
- padding: 1rem;
1215
- margin-top: 1rem;
1216
- }
1217
- """
1218
-
1219
- # Define the Gradio interface - Using a simpler structure without tabs to fix the error
1220
- with gr.Blocks(title="MarkdownMuse", css=custom_css, theme=gr.themes.Soft()) as app:
1221
- # App header
1222
- gr.HTML(
1223
  """
1224
- <div class="app-header">
1225
- <h1>πŸ“ MarkdownMuse</h1>
1226
- <p>Transform your Markdown files into beautifully formatted PDFs with ease</p>
1227
- </div>
1228
  """
1229
  )
1230
 
1231
- # Two column layout - left for input, right for templates/settings
1232
  with gr.Row():
1233
- # Left column - Main input
1234
- with gr.Column(scale=3):
 
1235
  markdown_input = gr.TextArea(
1236
  placeholder="Enter your markdown content here...",
1237
  label="Markdown Content",
1238
- lines=20,
1239
- elem_id="markdown-input"
1240
  )
1241
 
1242
- # Upload file option
1243
- gr.Markdown("### πŸ“€ Or upload a file")
1244
- uploaded_file = gr.File(
1245
- label="Upload Markdown File",
1246
- file_types=[".md", ".markdown", ".txt"],
1247
- file_count="single"
1248
- )
1249
- upload_btn = gr.Button("Load from File")
1250
 
1251
- # Right column - Templates and settings
1252
- with gr.Column(scale=1):
1253
- gr.Markdown("### πŸ“‹ Templates")
1254
- template_selector = gr.Dropdown(
1255
- choices=["Basic", "Report", "Documentation", "Article"],
1256
- value="Basic",
1257
- label="Choose a template",
1258
- elem_classes="template-selector"
1259
- )
1260
- sample_btn = gr.Button("Load Template")
1261
-
1262
- with gr.Accordion("βš™οΈ PDF Settings", open=True):
1263
  page_size = gr.Radio(
1264
  ["A4", "Letter"],
1265
  label="Page Size",
@@ -1293,21 +984,18 @@ with gr.Blocks(title="MarkdownMuse", css=custom_css, theme=gr.themes.Soft()) as
1293
  label="Include Table of Contents"
1294
  )
1295
 
1296
- color_theme = gr.Dropdown(
1297
- ["Default", "Modern", "Professional", "Creative", "Elegant"],
1298
- value="Modern",
1299
- label="Color Theme"
1300
- )
1301
-
1302
  with gr.Accordion("🧠 AI Enhancement", open=False):
1303
  use_ai = gr.Checkbox(
1304
- value=True,
1305
  label="Enable AI Enhancement"
1306
  )
1307
 
1308
- # Show API key status
1309
- api_status = "API Key: Available from Hugging Face Secrets" if GEMINI_API_KEY else "API Key: Not configured"
1310
- gr.Markdown(f"**{api_status}**")
 
 
 
1311
 
1312
  enhancement_instructions = gr.TextArea(
1313
  placeholder="Optional: Provide specific instructions for how the AI should enhance your markdown...",
@@ -1315,25 +1003,24 @@ with gr.Blocks(title="MarkdownMuse", css=custom_css, theme=gr.themes.Soft()) as
1315
  lines=3,
1316
  visible=True
1317
  )
1318
-
1319
- # Convert button and output
1320
- convert_btn = gr.Button("πŸ”„ Convert to PDF", variant="primary", size="lg")
1321
- output_pdf = gr.File(label="Generated PDF")
 
 
 
1322
 
1323
  # Set up event handlers
1324
- sample_btn.click(
1325
- load_sample,
1326
- inputs=[template_selector],
1327
- outputs=markdown_input
1328
- )
1329
 
1330
- upload_btn.click(
1331
- upload_handler,
1332
- inputs=[uploaded_file],
1333
- outputs=markdown_input
 
1334
  )
1335
 
1336
- # Connect the conversion button to the processing function
1337
  convert_btn.click(
1338
  process_markdown,
1339
  inputs=[
@@ -1343,20 +1030,20 @@ with gr.Blocks(title="MarkdownMuse", css=custom_css, theme=gr.themes.Soft()) as
1343
  font_name,
1344
  margin_size,
1345
  include_toc,
1346
- color_theme,
1347
  use_ai,
 
1348
  enhancement_instructions
1349
  ],
1350
  outputs=output_pdf
1351
  )
1352
 
1353
- # Footer
1354
- gr.HTML(
1355
- f"""
1356
- <footer>
1357
- <p>Made with ❀️ using Gradio and ReportLab</p>
1358
- <p>Β© {datetime.now().year} MarkdownMuse | Deployed on Hugging Face Spaces</p>
1359
- </footer>
1360
  """
1361
  )
1362
 
 
23
  from PIL import Image as PilImage
24
  import io
25
  import tempfile
 
26
  from datetime import datetime
27
 
28
  # Set up logging
 
32
  )
33
  logger = logging.getLogger(__name__)
34
 
 
 
 
35
  class MarkdownToPDFConverter:
36
  """
37
  Class to convert Markdown content to PDF using ReportLab.
 
45
  base_font_size: int = 10,
46
  heading_scale: Dict[int, float] = None,
47
  include_toc: bool = True,
48
+ code_style: str = "github"
 
49
  ):
50
  """
51
  Initialize the converter with configuration options.
 
59
  heading_scale: Dictionary of heading levels to font size multipliers
60
  include_toc: Whether to include a table of contents
61
  code_style: Style to use for code blocks
 
62
  """
63
  self.output_path = output_path
64
  self.page_size = A4 if page_size.upper() == "A4" else letter
 
75
  }
76
  self.include_toc = include_toc
77
  self.code_style = code_style
 
78
 
79
  # Initialize styles
80
  self.styles = getSampleStyleSheet()
 
86
 
87
  def _setup_styles(self) -> None:
88
  """Set up custom paragraph styles for the document."""
 
 
 
 
 
 
 
 
 
 
 
 
89
  # Modify existing Normal style
90
  self.styles['Normal'].fontName = self.font_name
91
  self.styles['Normal'].fontSize = self.base_font_size
 
106
  self.styles[heading_name].leading = int(self.base_font_size * size_multiplier * 1.2)
107
  self.styles[heading_name].spaceAfter = self.base_font_size
108
  self.styles[heading_name].spaceBefore = self.base_font_size * (1 + (0.2 * (7 - level)))
 
109
  else:
110
  # Create new style
111
  self.styles.add(
 
117
  leading=int(self.base_font_size * size_multiplier * 1.2),
118
  spaceAfter=self.base_font_size,
119
  spaceBefore=self.base_font_size * (1 + (0.2 * (7 - level))),
 
120
  )
121
  )
122
 
 
130
  spaceAfter=self.base_font_size,
131
  spaceBefore=self.base_font_size,
132
  leftIndent=self.base_font_size,
133
+ backgroundColor=HexColor('#EEEEEE'),
134
  borderWidth=0,
135
  borderPadding=self.base_font_size * 0.5,
136
  )
137
  )
138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  # List item style
140
  self.styles.add(
141
  ParagraphStyle(
 
153
  parent=self.styles['Heading1'],
154
  fontSize=int(self.base_font_size * 1.5),
155
  spaceAfter=self.base_font_size * 1.5,
 
156
  )
157
  )
158
 
 
242
  base_font_size=self.base_font_size,
243
  heading_scale=self.heading_scale,
244
  include_toc=separate_toc,
245
+ code_style=self.code_style
 
246
  )
247
  converter.convert_file(file_path)
248
 
 
318
  Preformatted(code, self.styles['CodeBlock'])
319
  )
320
 
 
 
 
 
 
 
 
 
 
 
 
 
 
321
  elif element.name == 'img':
322
  src = element.get('src', '')
323
  alt = element.get('alt', 'Image')
 
378
 
379
  elif element.name == 'ul' or element.name == 'ol':
380
  list_items = []
381
+ bullet_type = 'bullet' if element.name == 'ul' else 'numbered'
382
 
383
  for item in element.find_all('li', recursive=False):
384
  text = self._process_inline_elements(item)
 
389
  )
390
  )
391
 
 
 
 
 
 
 
 
 
 
 
392
  self.elements.append(
393
  ListFlowable(
394
  list_items,
395
+ bulletType=bullet_type,
396
+ start=1 if bullet_type == 'numbered' else None,
397
+ bulletFormat='%s.' if bullet_type == 'numbered' else '%s'
398
  )
399
  )
400
 
 
592
  try:
593
  from langchain_google_genai import ChatGoogleGenerativeAI
594
 
595
+ api_key = api_key or os.getenv("GOOGLE_API_KEY")
596
  if not api_key:
597
  logger.warning("No Google API key provided. Agent will run without LLM enhancement.")
598
  return False
 
694
  return '\n'.join(result_lines)
695
 
696
  def process_file(self, input_path: str, output_path: str = None, enhance: bool = False,
697
+ enhancement_instructions: str = None, page_size: str = "A4") -> str:
 
698
  """
699
  Process a single markdown file and convert it to PDF.
700
 
 
704
  enhance: Whether to enhance the content with LLM
705
  enhancement_instructions: Specific instructions for enhancement
706
  page_size: Page size for the PDF ("A4" or "letter")
 
707
 
708
  Returns:
709
  Path to the generated PDF
 
729
  # Configure converter
730
  self.converter = MarkdownToPDFConverter(
731
  output_path=output_path,
732
+ page_size=page_size
 
733
  )
734
 
735
  # Convert to PDF
 
741
  def process_directory(self, input_dir: str, output_dir: str = None, pattern: str = "*.md",
742
  enhance: bool = False, merge: bool = False,
743
  output_filename: str = "merged_document.pdf",
744
+ page_size: str = "A4") -> List[str]:
745
  """
746
  Process all markdown files in a directory.
747
 
 
753
  merge: Whether to merge all files into a single PDF
754
  output_filename: Filename for merged PDF
755
  page_size: Page size for the PDF ("A4" or "letter")
 
756
 
757
  Returns:
758
  List of paths to generated PDFs
 
804
  output_path = os.path.join(output_dir, output_filename)
805
  self.converter = MarkdownToPDFConverter(
806
  output_path=output_path,
807
+ page_size=page_size
 
808
  )
809
  self.converter.convert_content(merged_content)
810
 
 
814
  output_path = os.path.join(output_dir, output_filename)
815
  self.converter = MarkdownToPDFConverter(
816
  output_path=output_path,
817
+ page_size=page_size
 
818
  )
819
  self.converter.convert_multiple_files(md_files, merge=True)
820
 
 
831
  md_file,
832
  output_path,
833
  enhance=enhance,
834
+ page_size=page_size
 
835
  )
836
 
837
  if processed_file:
 
839
 
840
  return output_files
841
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
842
  # Gradio Interface for Hugging Face
843
+ def load_sample():
844
+ """Load a sample markdown document."""
845
+ return """# Sample Markdown Document
 
 
 
 
 
 
 
 
846
 
847
  ## Introduction
848
  This is a sample markdown document to demonstrate the capabilities of **MarkdownMuse**. You can use this as a starting point for your own documents.
 
870
  """
871
 
872
  def process_markdown(markdown_text, page_size, font_size, font_name,
873
+ margin_size, include_toc, use_ai, api_key, enhancement_instructions):
 
874
  """
875
  Process markdown text and generate a PDF.
876
 
 
882
  output_path = temp_file.name
883
  temp_file.close()
884
 
885
+ # Initialize the agent and process the markdown
886
  agent = MarkdownToPDFAgent()
887
 
888
  # Configure converter
 
892
  base_font_size=font_size,
893
  font_name=font_name,
894
  margins=(margin_size, margin_size, margin_size, margin_size),
895
+ include_toc=include_toc
 
896
  )
897
 
898
+ # Setup AI enhancement if requested
899
  enhance = False
900
+ if use_ai and api_key:
 
 
 
 
901
  if api_key:
902
  success = agent.setup_from_gemini(api_key)
903
  enhance = success
 
913
  temp_md_path,
914
  output_path,
915
  enhance=enhance,
916
+ enhancement_instructions=enhancement_instructions if enhancement_instructions else None,
917
+ page_size=page_size.lower()
 
918
  )
919
 
920
  # Remove the temporary md file
 
928
  logger.error(f"Error processing markdown: {e}")
929
  return None
930
 
931
+ # Define the Gradio interface
932
+ with gr.Blocks(title="MarkdownMuse", theme=gr.themes.Soft()) as app:
933
+ gr.Markdown(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
934
  """
935
+ # πŸ“ MarkdownMuse
936
+
937
+ Transform your Markdown files into beautifully formatted PDFs with ease.
 
938
  """
939
  )
940
 
 
941
  with gr.Row():
942
+ with gr.Column(scale=1):
943
+ gr.Markdown("### πŸ“ Input")
944
+
945
  markdown_input = gr.TextArea(
946
  placeholder="Enter your markdown content here...",
947
  label="Markdown Content",
948
+ lines=15
 
949
  )
950
 
951
+ sample_btn = gr.Button("πŸ“‹ Load Sample")
 
 
 
 
 
 
 
952
 
953
+ with gr.Accordion("βš™οΈ PDF Settings", open=False):
 
 
 
 
 
 
 
 
 
 
 
954
  page_size = gr.Radio(
955
  ["A4", "Letter"],
956
  label="Page Size",
 
984
  label="Include Table of Contents"
985
  )
986
 
 
 
 
 
 
 
987
  with gr.Accordion("🧠 AI Enhancement", open=False):
988
  use_ai = gr.Checkbox(
989
+ value=False,
990
  label="Enable AI Enhancement"
991
  )
992
 
993
+ api_key = gr.Textbox(
994
+ placeholder="Enter your Google Gemini API key...",
995
+ label="Google Gemini API Key",
996
+ type="password",
997
+ visible=True
998
+ )
999
 
1000
  enhancement_instructions = gr.TextArea(
1001
  placeholder="Optional: Provide specific instructions for how the AI should enhance your markdown...",
 
1003
  lines=3,
1004
  visible=True
1005
  )
1006
+
1007
+ convert_btn = gr.Button("πŸ”„ Convert to PDF", variant="primary")
1008
+
1009
+ with gr.Column(scale=1):
1010
+ gr.Markdown("### πŸ“‹ Output")
1011
+
1012
+ output_pdf = gr.File(label="Generated PDF")
1013
 
1014
  # Set up event handlers
1015
+ sample_btn.click(load_sample, outputs=markdown_input)
 
 
 
 
1016
 
1017
+ # Add visibility toggle for API key based on checkbox
1018
+ use_ai.change(
1019
+ lambda x: [gr.update(visible=x), gr.update(visible=x)],
1020
+ inputs=[use_ai],
1021
+ outputs=[api_key, enhancement_instructions]
1022
  )
1023
 
 
1024
  convert_btn.click(
1025
  process_markdown,
1026
  inputs=[
 
1030
  font_name,
1031
  margin_size,
1032
  include_toc,
 
1033
  use_ai,
1034
+ api_key,
1035
  enhancement_instructions
1036
  ],
1037
  outputs=output_pdf
1038
  )
1039
 
1040
+ gr.Markdown(
1041
+ """
1042
+ ### πŸ“š About MarkdownMuse
1043
+
1044
+ This tool allows you to convert Markdown documents to beautifully formatted PDFs. Use the options to customize your output.
1045
+
1046
+ Made with ❀️ using Gradio and ReportLab | © 2024
1047
  """
1048
  )
1049