Create start.py

#4
by Prak2005 - opened
Files changed (1) hide show
  1. start.py +732 -0
start.py ADDED
@@ -0,0 +1,732 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ import tempfile
4
+ import base64
5
+ from pathlib import Path
6
+ import time
7
+ from datetime import datetime
8
+
9
+ # Import the MarkdownToPDFAgent class from your module
10
+ try:
11
+ from app import MarkdownToPDFAgent, MarkdownToPDFConverter
12
+ except ImportError as e:
13
+ st.error(f"Error importing MarkdownToPDFAgent: {e}")
14
+ st.stop()
15
+
16
+ def download_link(object_to_download, download_filename, download_link_text):
17
+ """
18
+ Generates a link to download the given object_to_download.
19
+
20
+ Parameters:
21
+ object_to_download (str, Path): The file path to download
22
+ download_filename (str): filename that will be downloaded
23
+ download_link_text (str): Text to display for download link
24
+
25
+ Returns:
26
+ (str): the download link as HTML
27
+ """
28
+ if isinstance(object_to_download, str) or isinstance(object_to_download, Path):
29
+ with open(object_to_download, 'rb') as f:
30
+ object_to_download = f.read()
31
+
32
+ b64 = base64.b64encode(object_to_download).decode()
33
+ return f'<a href="data:application/pdf;base64,{b64}" download="{download_filename}" class="download-btn">{download_link_text}</a>'
34
+
35
+ def main():
36
+ st.set_page_config(
37
+ page_title="MarkdownMuse",
38
+ page_icon="πŸ“",
39
+ layout="wide",
40
+ initial_sidebar_state="expanded"
41
+ )
42
+
43
+ # Apply custom CSS
44
+ st.markdown('''
45
+ <style>
46
+ .main .block-container {
47
+ padding-top: 2rem;
48
+ padding-bottom: 2rem;
49
+ }
50
+ h1, h2, h3, h4, h5, h6 {
51
+ font-family: 'Helvetica Neue', sans-serif;
52
+ }
53
+ .stButton>button {
54
+ background-color: #4CAF50;
55
+ color: white;
56
+ font-weight: 500;
57
+ border-radius: 6px;
58
+ border: none;
59
+ padding: 0.5rem 1rem;
60
+ transition: all 0.3s;
61
+ }
62
+ .stButton>button:hover {
63
+ background-color: #45a049;
64
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
65
+ }
66
+ .css-1v3fvcr {
67
+ background-color: #f8f9fa;
68
+ }
69
+ .stTextInput>div>div>input, .stTextArea>div>div>textarea {
70
+ border-radius: 6px;
71
+ border: 1px solid #ced4da;
72
+ }
73
+ .stSidebar .sidebar-content {
74
+ background-color: #f8f9fa;
75
+ }
76
+ iframe {
77
+ border: 1px solid #e9ecef;
78
+ border-radius: 8px;
79
+ box-shadow: 0 4px 6px rgba(0,0,0,0.05);
80
+ }
81
+ /* PDF Container Styling */
82
+ .pdf-container {
83
+ background-color: white;
84
+ border-radius: 10px;
85
+ padding: 20px;
86
+ box-shadow: 0 4px 12px rgba(0,0,0,0.08);
87
+ margin-bottom: 20px;
88
+ }
89
+ /* Empty state styling */
90
+ .empty-state {
91
+ display: flex;
92
+ flex-direction: column;
93
+ align-items: center;
94
+ justify-content: center;
95
+ padding: 3rem;
96
+ background-color: #f8f9fa;
97
+ border-radius: 10px;
98
+ border: 2px dashed #dee2e6;
99
+ margin: 1rem 0;
100
+ }
101
+ .empty-state img {
102
+ width: 120px;
103
+ margin-bottom: 1.5rem;
104
+ opacity: 0.7;
105
+ }
106
+ /* Success message styling */
107
+ .success-msg {
108
+ background-color: #d4edda;
109
+ color: #155724;
110
+ padding: 10px 15px;
111
+ border-radius: 6px;
112
+ margin-bottom: 15px;
113
+ animation: fadeIn 0.5s;
114
+ }
115
+ @keyframes fadeIn {
116
+ from { opacity: 0; }
117
+ to { opacity: 1; }
118
+ }
119
+ .download-btn {
120
+ display: inline-block;
121
+ background-color: #1976D2;
122
+ color: white;
123
+ text-decoration: none;
124
+ padding: 10px 18px;
125
+ border-radius: 6px;
126
+ margin: 0.5rem 0;
127
+ text-align: center;
128
+ transition: all 0.3s;
129
+ font-weight: 500;
130
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
131
+ }
132
+ .download-btn:hover {
133
+ background-color: #1565C0;
134
+ box-shadow: 0 4px 8px rgba(0,0,0,0.15);
135
+ transform: translateY(-1px);
136
+ }
137
+ /* Tab styling */
138
+ .stTabs [data-baseweb="tab-list"] {
139
+ gap: 8px;
140
+ }
141
+ .stTabs [data-baseweb="tab"] {
142
+ height: 40px;
143
+ white-space: pre-wrap;
144
+ background-color: #f8f9fa;
145
+ border-radius: 4px 4px 0 0;
146
+ gap: 1px;
147
+ padding-top: 10px;
148
+ padding-bottom: 10px;
149
+ }
150
+ .stTabs [aria-selected="true"] {
151
+ background-color: #e9ecef;
152
+ border-bottom: 2px solid #1976D2;
153
+ }
154
+ .success-msg {
155
+ padding: 1rem;
156
+ background-color: #d4edda;
157
+ color: #155724;
158
+ border-radius: 6px;
159
+ margin-bottom: 1rem;
160
+ }
161
+ .info-msg {
162
+ padding: 1rem;
163
+ background-color: #d1ecf1;
164
+ color: #0c5460;
165
+ border-radius: 6px;
166
+ margin-bottom: 1rem;
167
+ }
168
+ .pdf-container {
169
+ background-color: white;
170
+ border-radius: 8px;
171
+ padding: 1rem;
172
+ box-shadow: 0 4px 8px rgba(0,0,0,0.05);
173
+ }
174
+ .app-header {
175
+ text-align: center;
176
+ margin-bottom: 2rem;
177
+ }
178
+ .app-header h1 {
179
+ color: #2E7D32;
180
+ margin-bottom: 0.5rem;
181
+ }
182
+ .app-header p {
183
+ color: #6c757d;
184
+ font-size: 1.1rem;
185
+ }
186
+ .footer {
187
+ text-align: center;
188
+ margin-top: 2rem;
189
+ padding: 1rem;
190
+ border-top: 1px solid #e9ecef;
191
+ color: #6c757d;
192
+ }
193
+ </style>
194
+ ''', unsafe_allow_html=True)
195
+
196
+ # App header with logo and title
197
+ st.markdown(
198
+ '''
199
+ <div class="app-header">
200
+ <h1>πŸ“ MarkdownMuse</h1>
201
+ <p>Transform your Markdown files into beautifully formatted PDFs with ease</p>
202
+ </div>
203
+ ''',
204
+ unsafe_allow_html=True
205
+ )
206
+
207
+ # Initialize agent with error handling
208
+ try:
209
+ agent = MarkdownToPDFAgent()
210
+ except Exception as e:
211
+ st.error(f"Error initializing MarkdownToPDFAgent: {e}")
212
+ st.info("Please make sure all required dependencies are installed. Run 'pip install -r requirements.txt' in your terminal.")
213
+ st.stop()
214
+
215
+ # Sidebar for configuration with improved styling
216
+ with st.sidebar:
217
+ st.markdown("<h2 style='text-align: center; color: #2E7D32;'>βš™οΈ Configuration</h2>", unsafe_allow_html=True)
218
+ st.markdown("<hr style='margin: 0.5rem 0 1.5rem 0; opacity: 0.3;'>", unsafe_allow_html=True)
219
+
220
+ # LLM Options with better UI
221
+ st.markdown("<h3 style='color: #1976D2;'>🧠 AI Enhancement</h3>", unsafe_allow_html=True)
222
+ use_ai = st.checkbox("Enable AI enhancement", value=False, help="Use AI to improve formatting and structure of your markdown content")
223
+
224
+ if use_ai:
225
+ with st.sidebar:
226
+ llm_provider = st.selectbox(
227
+ "Select AI Provider",
228
+ ["OpenAI", "Google Gemini", "None"],
229
+ index=1,
230
+ format_func=lambda x: {"OpenAI": "πŸ€– OpenAI", "Google Gemini": "πŸŒ€ Google Gemini", "None": "❌ None"}[x]
231
+ )
232
+
233
+ if llm_provider != "None":
234
+ api_key_container = st.container()
235
+ with api_key_container:
236
+ st.markdown(f"<div style='background-color: #f8f9fa; padding: 0.75rem; border-radius: 6px; border-left: 4px solid #1976D2;'><strong>{llm_provider} API Key:</strong></div>", unsafe_allow_html=True)
237
+ api_key = st.text_input(
238
+ "",
239
+ type="password",
240
+ help=f"Your {llm_provider} API key. Leave empty to use environment variable.",
241
+ placeholder="Enter API key or leave empty to use environment variable"
242
+ )
243
+
244
+ # Custom enhancement instructions with better UI
245
+ st.markdown("<div style='margin-top: 1rem;'></div>", unsafe_allow_html=True)
246
+ st.markdown("<div style='background-color: #f8f9fa; padding: 0.75rem; border-radius: 6px; border-left: 4px solid #1976D2;'><strong>Enhancement Instructions:</strong></div>", unsafe_allow_html=True)
247
+ custom_instructions = st.text_area(
248
+ "",
249
+ height=120,
250
+ help="Provide specific instructions for how the AI should enhance your markdown.",
251
+ placeholder="Example: Improve formatting, add section numbers, enhance tables, etc."
252
+ )
253
+
254
+ # PDF Options with improved UI
255
+ with st.sidebar:
256
+ st.markdown("<h3 style='color: #1976D2; margin-top: 2rem;'>πŸ“„ PDF Settings</h3>", unsafe_allow_html=True)
257
+
258
+ # Create columns for layout
259
+ col1, col2 = st.columns(2)
260
+ with col1:
261
+ page_size = st.selectbox(
262
+ "Page Size",
263
+ ["A4", "Letter"],
264
+ index=0,
265
+ help="Select the paper size for your PDF"
266
+ )
267
+ with col2:
268
+ include_toc = st.checkbox(
269
+ "Table of Contents",
270
+ value=True,
271
+ help="Include an automatic table of contents at the beginning of the PDF"
272
+ )
273
+
274
+ # Font size with visual indicator
275
+ font_size = st.slider(
276
+ "Base Font Size",
277
+ min_value=8,
278
+ max_value=14,
279
+ value=10,
280
+ step=1,
281
+ format="%d pt",
282
+ help="Set the base font size for normal text. Headings will scale proportionally."
283
+ )
284
+
285
+ # Advanced settings with better styling
286
+ with st.expander("πŸ”§ Advanced PDF Settings"):
287
+ st.markdown("<div style='padding: 0.5rem 0;'></div>", unsafe_allow_html=True)
288
+
289
+ font_name = st.selectbox(
290
+ "Font Family",
291
+ ["Helvetica", "Times-Roman", "Courier"],
292
+ index=0,
293
+ help="Select the primary font family for your document"
294
+ )
295
+
296
+ margins = st.slider(
297
+ "Margins",
298
+ min_value=0.5,
299
+ max_value=2.0,
300
+ value=0.75,
301
+ step=0.25,
302
+ format="%.2f inches",
303
+ help="Set the page margins (applies to all sides)"
304
+ )
305
+
306
+ # Add theme selection
307
+ color_theme = st.selectbox(
308
+ "Color Theme",
309
+ ["Default", "Professional", "Modern", "Classic"],
310
+ index=0,
311
+ help="Select a color theme for your PDF (affects headings and accents)"
312
+ )
313
+
314
+ # Add a separator between sidebar and main content
315
+ st.markdown("<hr style='margin: 1.5rem 0; opacity: 0.2;'>", unsafe_allow_html=True)
316
+
317
+ # Left and Right columns for input and preview with improved styling
318
+ left_col, right_col = st.columns([1, 1], gap="large")
319
+
320
+ with left_col:
321
+ st.markdown("<h2 style='color: #1976D2;'>πŸ“ Input</h2>", unsafe_allow_html=True)
322
+
323
+ # Input method selector with icons
324
+ input_method = st.radio(
325
+ "Choose input method:",
326
+ options=["Enter Markdown", "Upload File(s)"],
327
+ format_func=lambda x: f"✏️ {x}" if x == "Enter Markdown" else f"πŸ“‚ {x}",
328
+ horizontal=True,
329
+ help="Choose how you want to provide your markdown content"
330
+ )
331
+
332
+ if input_method == "Enter Markdown":
333
+ # Add a sample button to help users
334
+ sample_col1, sample_col2 = st.columns([3, 1])
335
+ with sample_col1:
336
+ st.markdown("<p style='margin-bottom: 0.5rem;'>Enter or paste your markdown content below:</p>", unsafe_allow_html=True)
337
+ with sample_col2:
338
+ if st.button("πŸ“‹ Load Sample", help="Load a sample markdown document to see how it works"):
339
+ markdown_content = """# Sample Markdown Document
340
+
341
+ ## Introduction
342
+ This is a sample markdown document to demonstrate the capabilities of **MarkdownMuse**. You can use this as a starting point for your own documents.
343
+
344
+ ## Features
345
+ - Convert markdown to PDF
346
+ - Support for tables and code blocks
347
+ - AI enhancement options
348
+
349
+ ### Code Example
350
+ ```python
351
+ def hello_world():
352
+ print("Hello from MarkdownMuse!")
353
+ return True
354
+ ```
355
+
356
+ ## Table Example
357
+ | Feature | Description | Status |
358
+ |---------|-------------|---------|
359
+ | Markdown Conversion | Convert MD to PDF | βœ… |
360
+ | AI Enhancement | Improve content with AI | βœ… |
361
+ | Custom Styling | Apply custom styles | βœ… |
362
+
363
+ > **Note:** This is just a sample document. Feel free to modify it or create your own!
364
+ """
365
+ else:
366
+ markdown_content = st.session_state.get('markdown_content', '')
367
+
368
+ # Improved text area with syntax highlighting hint
369
+ st.markdown("<div style='background-color: #f8f9fa; padding: 0.5rem; border-radius: 6px; margin-bottom: 0.5rem; font-size: 0.8rem;'>πŸ’‘ <strong>Tip:</strong> Use markdown syntax for formatting - headings (#), bold (**), lists (-), code blocks (```), and more!</div>", unsafe_allow_html=True)
370
+
371
+ markdown_content = st.text_area(
372
+ "",
373
+ value=markdown_content,
374
+ height=400,
375
+ placeholder="# Your Markdown Content Here\n\nStart typing or paste your markdown...",
376
+ key="markdown_content"
377
+ )
378
+
379
+ # Styled convert button
380
+ convert_button = st.button("πŸ”„ Convert to PDF", use_container_width=True)
381
+
382
+ if convert_button and markdown_content:
383
+ with st.spinner("Converting to PDF..."):
384
+ # Configure AI if selected
385
+ if use_ai and llm_provider != "None":
386
+ if llm_provider == "OpenAI":
387
+ agent.setup_from_openai(api_key)
388
+ elif llm_provider == "Google Gemini":
389
+ agent.setup_from_gemini(api_key)
390
+
391
+ # Create a temporary file for the markdown content
392
+ with tempfile.NamedTemporaryFile(suffix='.md', delete=False) as temp_md_file:
393
+ temp_md_path = temp_md_file.name
394
+ temp_md_file.write(markdown_content.encode('utf-8'))
395
+
396
+ # Create temporary output file
397
+ temp_pdf_path = f"{temp_md_path}.pdf"
398
+
399
+ # Process the file
400
+ output_file = agent.process_file(
401
+ temp_md_path,
402
+ temp_pdf_path,
403
+ enhance=use_ai and llm_provider != "None",
404
+ enhancement_instructions=custom_instructions if use_ai and custom_instructions else None,
405
+ page_size=page_size.lower()
406
+ )
407
+
408
+ # Apply font size and other settings to the converter
409
+ if output_file:
410
+ agent.converter.base_font_size = font_size
411
+ if 'font_name' in locals():
412
+ agent.converter.font_name = font_name
413
+ if 'margins' in locals():
414
+ agent.converter.margins = (margins, margins, margins, margins)
415
+ agent.converter.include_toc = include_toc
416
+
417
+ # Remove the temporary md file
418
+ os.unlink(temp_md_path)
419
+
420
+ # Display output
421
+ if output_file:
422
+ st.markdown("<div class='success-msg'><strong>βœ… Success!</strong> PDF created successfully!</div>", unsafe_allow_html=True)
423
+ with open(output_file, "rb") as pdf_file:
424
+ pdf_bytes = pdf_file.read()
425
+
426
+ with right_col:
427
+ st.markdown("<h2 style='color: #1976D2;'>πŸ“‹ PDF Output</h2>", unsafe_allow_html=True)
428
+
429
+ # Create a container for the PDF viewer with better styling
430
+ st.markdown("<div class='pdf-container'>", unsafe_allow_html=True)
431
+
432
+ # Add download button with stats
433
+ file_size = len(pdf_bytes) / 1024 # Size in KB
434
+ download_container = st.container()
435
+ with download_container:
436
+ download_col1, download_col2 = st.columns([3, 1])
437
+ with download_col1:
438
+ st.markdown(
439
+ download_link(pdf_bytes, "output.pdf", "πŸ“₯ Download PDF"),
440
+ unsafe_allow_html=True
441
+ )
442
+ with download_col2:
443
+ st.markdown(f"<div style='text-align: right; color: #6c757d; padding-top: 0.5rem;'>{file_size:.1f} KB</div>", unsafe_allow_html=True)
444
+
445
+ # Add a timestamp
446
+ timestamp = datetime.now().strftime("%B %d, %Y at %I:%M %p")
447
+ st.markdown(f"<div style='color: #6c757d; font-size: 0.8rem; margin-bottom: 1rem;'>Generated on {timestamp}</div>", unsafe_allow_html=True)
448
+
449
+ # Display PDF using HTML iframe with base64 encoding and improved styling
450
+ b64_pdf = base64.b64encode(pdf_bytes).decode('utf-8')
451
+ pdf_display = f'<iframe src="data:application/pdf;base64,{b64_pdf}" width="100%" height="500" type="application/pdf"></iframe>'
452
+ st.markdown(pdf_display, unsafe_allow_html=True)
453
+
454
+ # Close the container div
455
+ st.markdown("</div>", unsafe_allow_html=True)
456
+
457
+ # Add a share section
458
+ with st.expander("πŸ”— Share Options"):
459
+ st.markdown("<p>Share your PDF with others:</p>", unsafe_allow_html=True)
460
+ share_col1, share_col2, share_col3 = st.columns(3)
461
+ with share_col1:
462
+ st.button("πŸ“§ Email", use_container_width=True, key="email_single")
463
+ with share_col2:
464
+ st.button("πŸ’¬ Message", use_container_width=True, key="message_single")
465
+ with share_col3:
466
+ st.button("πŸ”— Copy Link", use_container_width=True, key="copy_single")
467
+
468
+ # Clean up temporary files
469
+ os.unlink(output_file)
470
+ else:
471
+ st.markdown("<div style='padding: 1rem; background-color: #f8d7da; color: #721c24; border-radius: 6px; margin-bottom: 1rem;'><strong>❌ Error:</strong> Failed to generate PDF. Check logs for details.</div>", unsafe_allow_html=True)
472
+
473
+ else: # Upload File(s)
474
+ # Enhanced file uploader with visual cues
475
+ st.markdown("<div style='background-color: #f8f9fa; padding: 0.5rem; border-radius: 6px; margin-bottom: 0.5rem; font-size: 0.8rem;'>πŸ’‘ <strong>Tip:</strong> You can upload multiple files and choose to merge them into a single PDF</div>", unsafe_allow_html=True)
476
+
477
+ uploaded_files = st.file_uploader(
478
+ "Upload Markdown File(s)",
479
+ type=['md', 'markdown', 'txt'],
480
+ accept_multiple_files=True,
481
+ help="Select one or more markdown files to convert"
482
+ )
483
+
484
+ # Show options only if files are uploaded
485
+ if uploaded_files:
486
+ st.markdown(f"<div style='background-color: #e8f4f8; padding: 0.75rem; border-radius: 6px; margin: 0.5rem 0;'><strong>πŸ“‚ {len(uploaded_files)} file(s) selected</strong></div>", unsafe_allow_html=True)
487
+ merge_files = st.checkbox(
488
+ "Merge multiple files into a single PDF",
489
+ value=False,
490
+ help="Combine all uploaded files into one PDF document"
491
+ )
492
+ else:
493
+ merge_files = False
494
+ st.markdown("<div style='background-color: #f8f9fa; padding: 0.75rem; border-radius: 6px; margin: 0.5rem 0; color: #6c757d;'><em>No files selected. Upload markdown files to continue.</em></div>", unsafe_allow_html=True)
495
+
496
+ # Styled convert button
497
+ convert_disabled = len(uploaded_files) == 0
498
+ convert_button = st.button(
499
+ "πŸ”„ Convert to PDF",
500
+ disabled=convert_disabled,
501
+ use_container_width=True
502
+ )
503
+
504
+ if convert_button and uploaded_files:
505
+ with st.spinner("Converting to PDF..."):
506
+ # Configure AI if selected
507
+ if use_ai and llm_provider != "None":
508
+ if llm_provider == "OpenAI":
509
+ agent.setup_from_openai(api_key)
510
+ elif llm_provider == "Google Gemini":
511
+ agent.setup_from_gemini(api_key)
512
+
513
+ # Create a temporary directory
514
+ temp_dir = tempfile.mkdtemp()
515
+ output_dir = tempfile.mkdtemp()
516
+
517
+ # Save uploaded files to temporary directory
518
+ temp_files = []
519
+ for uploaded_file in uploaded_files:
520
+ # Create temporary file
521
+ temp_file_path = os.path.join(temp_dir, uploaded_file.name)
522
+ with open(temp_file_path, "wb") as f:
523
+ f.write(uploaded_file.getbuffer())
524
+ temp_files.append(temp_file_path)
525
+
526
+ if merge_files:
527
+ # Merge all files
528
+ output_file = os.path.join(output_dir, "merged_document.pdf")
529
+ result = agent.process_directory(
530
+ temp_dir,
531
+ output_dir,
532
+ pattern="*.*", # Get all files in temp directory
533
+ enhance=use_ai and llm_provider != "None",
534
+ merge=True,
535
+ output_filename="merged_document.pdf",
536
+ page_size=page_size.lower()
537
+ )
538
+
539
+ # Apply font size and other settings to the converter
540
+ if result and len(result) > 0:
541
+ agent.converter.base_font_size = font_size
542
+ if 'font_name' in locals():
543
+ agent.converter.font_name = font_name
544
+ if 'margins' in locals():
545
+ agent.converter.margins = (margins, margins, margins, margins)
546
+ agent.converter.include_toc = include_toc
547
+
548
+ if result and len(result) > 0:
549
+ with open(result[0], "rb") as pdf_file:
550
+ pdf_bytes = pdf_file.read()
551
+
552
+ with right_col:
553
+ st.markdown("<h2 style='color: #1976D2;'>πŸ“‹ PDF Output</h2>", unsafe_allow_html=True)
554
+
555
+ # Create a container for the PDF viewer with better styling
556
+ st.markdown("<div class='pdf-container'>", unsafe_allow_html=True)
557
+
558
+ # Add download button with stats
559
+ file_size = len(pdf_bytes) / 1024 # Size in KB
560
+ download_container = st.container()
561
+ with download_container:
562
+ download_col1, download_col2 = st.columns([3, 1])
563
+ with download_col1:
564
+ st.markdown(
565
+ download_link(pdf_bytes, "merged_document.pdf", "πŸ“₯ Download Merged PDF"),
566
+ unsafe_allow_html=True
567
+ )
568
+ with download_col2:
569
+ st.markdown(f"<div style='text-align: right; color: #6c757d; padding-top: 0.5rem;'>{file_size:.1f} KB</div>", unsafe_allow_html=True)
570
+
571
+ # Add a timestamp and file count
572
+ timestamp = datetime.now().strftime("%B %d, %Y at %I:%M %p")
573
+ st.markdown(f"<div style='color: #6c757d; font-size: 0.8rem; margin-bottom: 1rem;'>Generated on {timestamp} | Merged {len(uploaded_files)} files</div>", unsafe_allow_html=True)
574
+
575
+ # Display PDF using HTML iframe with base64 encoding and improved styling
576
+ b64_pdf = base64.b64encode(pdf_bytes).decode('utf-8')
577
+ pdf_display = f'<iframe src="data:application/pdf;base64,{b64_pdf}" width="100%" height="500" type="application/pdf"></iframe>'
578
+ st.markdown(pdf_display, unsafe_allow_html=True)
579
+
580
+ # Close the container div
581
+ st.markdown("</div>", unsafe_allow_html=True)
582
+
583
+ # Add a share section
584
+ with st.expander("πŸ”— Share Options"):
585
+ st.markdown("<p>Share your PDF with others:</p>", unsafe_allow_html=True)
586
+ share_col1, share_col2, share_col3 = st.columns(3)
587
+ with share_col1:
588
+ st.button("πŸ“§ Email", use_container_width=True, key="email_merged")
589
+ with share_col2:
590
+ st.button("πŸ’¬ Message", use_container_width=True, key="message_merged")
591
+ with share_col3:
592
+ st.button("πŸ”— Copy Link", use_container_width=True, key="copy_merged")
593
+ else:
594
+ st.error("Failed to generate merged PDF.")
595
+
596
+ else:
597
+ # Process each file individually
598
+ all_results = []
599
+ for temp_file in temp_files:
600
+ output_file = os.path.join(output_dir, os.path.basename(temp_file).replace('.md', '.pdf'))
601
+ result = agent.process_file(
602
+ temp_file,
603
+ output_file,
604
+ enhance=use_ai and llm_provider != "None",
605
+ enhancement_instructions=custom_instructions if use_ai and custom_instructions else None,
606
+ page_size=page_size.lower()
607
+ )
608
+
609
+ # Apply font size and other settings to the converter
610
+ if result:
611
+ agent.converter.base_font_size = font_size
612
+ if 'font_name' in locals():
613
+ agent.converter.font_name = font_name
614
+ if 'margins' in locals():
615
+ agent.converter.margins = (margins, margins, margins, margins)
616
+ agent.converter.include_toc = include_toc
617
+ if result:
618
+ all_results.append(result)
619
+
620
+ if all_results:
621
+ with right_col:
622
+ # Add a header for multiple PDFs
623
+ st.markdown(f"<h2 style='color: #1976D2;'>πŸ“‹ PDF Output ({len(all_results)} files)</h2>", unsafe_allow_html=True)
624
+
625
+ # Create tabs for each PDF
626
+ if len(all_results) > 1:
627
+ tabs = st.tabs([f"File {idx+1}: {os.path.basename(pdf_path)}" for idx, pdf_path in enumerate(all_results)])
628
+
629
+ for idx, (tab, pdf_path) in enumerate(zip(tabs, all_results)):
630
+ with tab:
631
+ with open(pdf_path, "rb") as pdf_file:
632
+ pdf_bytes = pdf_file.read()
633
+
634
+ file_name = os.path.basename(pdf_path)
635
+
636
+ # Create a container for the PDF viewer with better styling
637
+ st.markdown("<div class='pdf-container'>", unsafe_allow_html=True)
638
+
639
+ # Add download button with stats
640
+ file_size = len(pdf_bytes) / 1024 # Size in KB
641
+ download_container = st.container()
642
+ with download_container:
643
+ download_col1, download_col2 = st.columns([3, 1])
644
+ with download_col1:
645
+ st.markdown(
646
+ download_link(pdf_bytes, file_name, f"πŸ“₯ Download {file_name}"),
647
+ unsafe_allow_html=True
648
+ )
649
+ with download_col2:
650
+ st.markdown(f"<div style='text-align: right; color: #6c757d; padding-top: 0.5rem;'>{file_size:.1f} KB</div>", unsafe_allow_html=True)
651
+
652
+ # Add a timestamp
653
+ timestamp = datetime.now().strftime("%B %d, %Y at %I:%M %p")
654
+ st.markdown(f"<div style='color: #6c757d; font-size: 0.8rem; margin-bottom: 1rem;'>Generated on {timestamp}</div>", unsafe_allow_html=True)
655
+
656
+ # Display PDF using HTML iframe with base64 encoding and improved styling
657
+ b64_pdf = base64.b64encode(pdf_bytes).decode('utf-8')
658
+ pdf_display = f'<iframe src="data:application/pdf;base64,{b64_pdf}" width="100%" height="500" type="application/pdf"></iframe>'
659
+ st.markdown(pdf_display, unsafe_allow_html=True)
660
+
661
+ # Close the container div
662
+ st.markdown("</div>", unsafe_allow_html=True)
663
+ else:
664
+ # Just one PDF, no need for tabs
665
+ for idx, pdf_path in enumerate(all_results):
666
+ with open(pdf_path, "rb") as pdf_file:
667
+ pdf_bytes = pdf_file.read()
668
+
669
+ file_name = os.path.basename(pdf_path)
670
+
671
+ # Create a container for the PDF viewer with better styling
672
+ st.markdown("<div class='pdf-container'>", unsafe_allow_html=True)
673
+
674
+ # Add download button with stats
675
+ file_size = len(pdf_bytes) / 1024 # Size in KB
676
+ download_container = st.container()
677
+ with download_container:
678
+ download_col1, download_col2 = st.columns([3, 1])
679
+ with download_col1:
680
+ st.markdown(
681
+ download_link(pdf_bytes, file_name, f"πŸ“₯ Download {file_name}"),
682
+ unsafe_allow_html=True
683
+ )
684
+ with download_col2:
685
+ st.markdown(f"<div style='text-align: right; color: #6c757d; padding-top: 0.5rem;'>{file_size:.1f} KB</div>", unsafe_allow_html=True)
686
+
687
+ # Add a timestamp
688
+ timestamp = datetime.now().strftime("%B %d, %Y at %I:%M %p")
689
+ st.markdown(f"<div style='color: #6c757d; font-size: 0.8rem; margin-bottom: 1rem;'>Generated on {timestamp}</div>", unsafe_allow_html=True)
690
+
691
+ # Display PDF using HTML iframe with base64 encoding and improved styling
692
+ b64_pdf = base64.b64encode(pdf_bytes).decode('utf-8')
693
+ pdf_display = f'<iframe src="data:application/pdf;base64,{b64_pdf}" width="100%" height="500" type="application/pdf"></iframe>'
694
+ st.markdown(pdf_display, unsafe_allow_html=True)
695
+
696
+ # Close the container div
697
+ st.markdown("</div>", unsafe_allow_html=True)
698
+ else:
699
+ st.error("Failed to generate PDFs.")
700
+
701
+
702
+ # Enhanced initial empty state for the right column
703
+ with right_col:
704
+ if "pdf_bytes" not in locals():
705
+ st.markdown("<h2 style='color: #1976D2;'>πŸ“‹ PDF Output</h2>", unsafe_allow_html=True)
706
+
707
+ # Create a more visually appealing empty state
708
+ st.markdown(
709
+ """
710
+ <div style="text-align: center; padding: 2rem; background-color: #f8f9fa; border-radius: 8px; margin-top: 1rem; border: 1px dashed #ced4da;">
711
+ <img src="https://cdn-icons-png.flaticon.com/512/5610/5610944.png" width="100" style="opacity: 0.5; margin-bottom: 1rem;">
712
+ <h3 style="color: #6c757d; font-weight: normal; margin-bottom: 0.5rem;">No PDF Generated Yet</h3>
713
+ <p style="color: #6c757d;">Your PDF will appear here after conversion.<br>Use the options on the left to get started.</p>
714
+ </div>
715
+ """,
716
+ unsafe_allow_html=True
717
+ )
718
+
719
+ # Add footer with current year
720
+ current_year = datetime.now().year
721
+ st.markdown(
722
+ f'''
723
+ <div class="footer">
724
+ <p>Made with ❀️ using Streamlit and the MarkdownToPDF Agent</p>
725
+ <p>Β© {current_year} MarkdownMuse | Last updated: {datetime.now().strftime('%B %Y')}</p>
726
+ </div>
727
+ ''',
728
+ unsafe_allow_html=True
729
+ )
730
+
731
+ if __name__ == "__main__":
732
+ main()