euler314 commited on
Commit
c40dca1
·
verified ·
1 Parent(s): 58633fe

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +95 -191
app.py CHANGED
@@ -10,7 +10,6 @@ from PIL import Image
10
  import fitz # PyMuPDF
11
  import time
12
  import re
13
- import json
14
 
15
  # Set page configuration
16
  st.set_page_config(
@@ -25,7 +24,7 @@ def is_pdflatex_installed():
25
  return shutil.which("pdflatex") is not None
26
 
27
  # Function to convert LaTeX to PDF
28
- def latex_to_pdf(latex_code, output_dir=None):
29
  # Check if pdflatex is installed
30
  if not is_pdflatex_installed():
31
  st.error("pdflatex not found. Debug info:")
@@ -35,12 +34,9 @@ def latex_to_pdf(latex_code, output_dir=None):
35
  return None, "", "Error: pdflatex is not installed or not in PATH."
36
 
37
  with tempfile.TemporaryDirectory() as temp_dir:
38
- if output_dir is None:
39
- output_dir = temp_dir
40
-
41
  temp_path = Path(temp_dir)
42
  tex_file = temp_path / "document.tex"
43
- pdf_file = Path(output_dir) / "document.pdf"
44
 
45
  # Write LaTeX code to file
46
  with open(tex_file, "w") as f:
@@ -49,7 +45,7 @@ def latex_to_pdf(latex_code, output_dir=None):
49
  try:
50
  # Run pdflatex to compile the LaTeX file
51
  process = subprocess.run(
52
- ["pdflatex", "-interaction=nonstopmode", "-output-directory", output_dir, str(tex_file)],
53
  capture_output=True,
54
  text=True
55
  )
@@ -64,6 +60,11 @@ def latex_to_pdf(latex_code, output_dir=None):
64
  except Exception as e:
65
  return None, "", str(e)
66
 
 
 
 
 
 
67
  # Convert PDF to image for preview
68
  def render_pdf_preview(pdf_data):
69
  if not pdf_data:
@@ -78,7 +79,7 @@ def render_pdf_preview(pdf_data):
78
 
79
  # Render pages as images
80
  images = []
81
- for page_num in range(min(5, len(pdf_document))): # Preview first 5 pages max
82
  page = pdf_document.load_page(page_num)
83
  pix = page.get_pixmap(matrix=fitz.Matrix(2, 2)) # Zoom factor 2 for better resolution
84
  img_data = pix.tobytes("png")
@@ -91,11 +92,6 @@ def render_pdf_preview(pdf_data):
91
  st.error(f"Error rendering PDF preview: {str(e)}")
92
  return None
93
 
94
- # Function to create download link for PDF
95
- def get_download_link(pdf_data, filename="document.pdf"):
96
- b64_pdf = base64.b64encode(pdf_data).decode()
97
- return f'<a href="data:application/pdf;base64,{b64_pdf}" download="{filename}" class="download-button">Download PDF</a>'
98
-
99
  # Function to parse LaTeX errors
100
  def parse_latex_errors(output):
101
  errors = []
@@ -113,10 +109,20 @@ def parse_latex_errors(output):
113
 
114
  return errors, warnings
115
 
116
- # Function to extract document structure
117
  def extract_document_structure(latex_code):
118
  structure = []
119
 
 
 
 
 
 
 
 
 
 
 
120
  # Find sections, subsections, etc.
121
  section_pattern = r'\\(section|subsection|subsubsection|chapter|part)\{([^}]+)\}'
122
  matches = re.finditer(section_pattern, latex_code)
@@ -238,57 +244,6 @@ Your conclusion here.
238
  \end{document}
239
  """
240
 
241
- # Ace Editor component for syntax highlighting
242
- def create_ace_editor():
243
- ace_editor_html = """
244
- <div id="editor" style="height: 600px; width: 100%; border-radius: 4px;"></div>
245
- <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.24.1/ace.js"></script>
246
- <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.24.1/ext-language_tools.js"></script>
247
- <script>
248
- // Create the editor
249
- var editor = ace.edit("editor");
250
- editor.setTheme("ace/theme/tomorrow_night_eighties");
251
- editor.session.setMode("ace/mode/latex");
252
- editor.setValue(JSON.parse('{latex_content}'));
253
- editor.clearSelection();
254
-
255
- // Enable advanced features
256
- editor.setOptions({
257
- enableBasicAutocompletion: true,
258
- enableSnippets: true,
259
- enableLiveAutocompletion: true,
260
- showPrintMargin: false,
261
- fontSize: 14,
262
- fontFamily: "'Fira Code', 'Courier New', monospace",
263
- scrollPastEnd: 0.5
264
- });
265
-
266
- // Function to update Streamlit with the content
267
- function updateStreamlit() {
268
- const content = editor.getValue();
269
- if (window.Streamlit) {
270
- window.Streamlit.setComponentValue(content);
271
- }
272
- }
273
-
274
- // Add change event listener
275
- editor.session.on('change', function() {
276
- updateStreamlit();
277
- });
278
-
279
- // Initialize Streamlit component communication
280
- function onStreamlitLoad() {
281
- updateStreamlit();
282
- }
283
-
284
- if (window.Streamlit) {
285
- window.Streamlit.setComponentReady();
286
- window.Streamlit.onCustomComponentReady(onStreamlitLoad);
287
- }
288
- </script>
289
- """
290
- return ace_editor_html
291
-
292
  # Enhanced VSCode-like advanced styling
293
  st.markdown("""
294
  <style>
@@ -312,6 +267,18 @@ st.markdown("""
312
  background-color: #1177bb;
313
  }
314
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  /* VS Code-like editor container */
316
  .editor-container {
317
  background-color: #1e1e1e;
@@ -363,27 +330,33 @@ st.markdown("""
363
  font-size: 12px;
364
  }
365
 
366
- /* Activity bar */
367
- .activity-bar {
368
- width: 50px;
369
- background-color: #333333;
370
  display: flex;
371
- flex-direction: column;
372
  align-items: center;
373
- padding-top: 10px;
374
  }
375
 
376
- .activity-icon {
377
- width: 30px;
378
- height: 30px;
379
- margin-bottom: 20px;
380
- opacity: 0.7;
381
  cursor: pointer;
382
- text-align: center;
 
 
 
 
383
  }
384
 
385
- .activity-icon:hover {
386
- opacity: 1;
 
 
 
387
  }
388
 
389
  /* Terminal/console styling */
@@ -472,35 +445,6 @@ st.markdown("""
472
  gap: 5px;
473
  }
474
 
475
- /* Toolbar */
476
- .toolbar {
477
- background-color: #2d2d2d;
478
- padding: 5px;
479
- display: flex;
480
- gap: 5px;
481
- align-items: center;
482
- }
483
-
484
- .toolbar-button {
485
- background-color: transparent;
486
- border: none;
487
- color: #cccccc;
488
- padding: 5px;
489
- cursor: pointer;
490
- border-radius: 2px;
491
- }
492
-
493
- .toolbar-button:hover {
494
- background-color: #3c3c3c;
495
- }
496
-
497
- .toolbar-separator {
498
- width: 1px;
499
- height: 20px;
500
- background-color: #555;
501
- margin: 0 5px;
502
- }
503
-
504
  /* Messages */
505
  .stInfo {
506
  background-color: #063b49;
@@ -545,39 +489,7 @@ st.markdown("""
545
  color: white;
546
  }
547
 
548
- /* Custom file explorer */
549
- .file-explorer {
550
- background-color: #252526;
551
- border: 1px solid #2d2d2d;
552
- border-radius: 4px;
553
- padding: 0;
554
- margin-top: 10px;
555
- }
556
-
557
- .file-header {
558
- background-color: #2d2d2d;
559
- padding: 5px 10px;
560
- font-weight: bold;
561
- font-size: 13px;
562
- }
563
-
564
- .file-item {
565
- padding: 5px 10px;
566
- display: flex;
567
- align-items: center;
568
- cursor: pointer;
569
- }
570
-
571
- .file-item:hover {
572
- background-color: #2a2d2e;
573
- }
574
-
575
- .file-icon {
576
- margin-right: 5px;
577
- opacity: 0.7;
578
- }
579
-
580
- /* Enhanced styles for problems panel */
581
  .problems-panel {
582
  background-color: #252526;
583
  border: 1px solid #2d2d2d;
@@ -644,81 +556,58 @@ st.markdown("""
644
  </style>
645
  """, unsafe_allow_html=True)
646
 
647
- # Create editor with custom HTML component
648
- def create_editor_component(key, height=600):
649
- # Get the current value from session state or use default
650
- content = st.session_state.get(key, "")
651
-
652
- # Create Ace editor with proper LaTeX content escaping
653
- escaped_content = json.dumps(content)
654
- editor_html = create_ace_editor().replace('{latex_content}', escaped_content)
655
-
656
- # Create component
657
- component = st.components.v1.html(editor_html, height=height, scrolling=False)
658
-
659
- # Return the latest value
660
- return component if component is not None else content
661
 
662
  # Build a VS Code-like toolbar
663
  def render_toolbar():
664
  toolbar_html = """
665
  <div class="toolbar">
666
- <button class="toolbar-button" title="Bold" onclick="insertTextAtCursor('\\\\textbf{}')">
667
  <strong>B</strong>
668
  </button>
669
- <button class="toolbar-button" title="Italic" onclick="insertTextAtCursor('\\\\textit{}')">
670
  <em>I</em>
671
  </button>
672
- <button class="toolbar-button" title="Math" onclick="insertTextAtCursor('$ $')">
673
 
674
  </button>
675
  <div class="toolbar-separator"></div>
676
- <button class="toolbar-button" title="Section" onclick="insertTextAtCursor('\\\\section{}')">
677
  §
678
  </button>
679
- <button class="toolbar-button" title="Subsection" onclick="insertTextAtCursor('\\\\subsection{}')">
680
  §§
681
  </button>
682
  <div class="toolbar-separator"></div>
683
- <button class="toolbar-button" title="Itemize" onclick="insertTextAtCursor('\\\\begin{itemize}\\n\\t\\\\item \\n\\\\end{itemize}')">
684
 
685
  </button>
686
- <button class="toolbar-button" title="Enumerate" onclick="insertTextAtCursor('\\\\begin{enumerate}\\n\\t\\\\item \\n\\\\end{enumerate}')">
687
  1.
688
  </button>
689
  <div class="toolbar-separator"></div>
690
- <button class="toolbar-button" title="Equation" onclick="insertTextAtCursor('\\\\begin{equation}\\n \\n\\\\end{equation}')">
691
  =
692
  </button>
693
- <button class="toolbar-button" title="Figure" onclick="insertTextAtCursor('\\\\begin{figure}\\n\\t\\\\centering\\n\\t\\\\includegraphics[width=0.8\\\\textwidth]{image}\\n\\t\\\\caption{Caption}\\n\\t\\\\label{fig:label}\\n\\\\end{figure}')">
694
  🖼
695
  </button>
696
- <button class="toolbar-button" title="Table" onclick="insertTextAtCursor('\\\\begin{table}\\n\\t\\\\centering\\n\\t\\\\begin{tabular}{ccc}\\n\\t\\tA & B & C \\\\\\\\\\n\\t\\t1 & 2 & 3 \\\\\\\\\\n\\t\\\\end{tabular}\\n\\t\\\\caption{Caption}\\n\\t\\\\label{tab:label}\\n\\\\end{table}')">
697
 
698
  </button>
699
  </div>
700
-
701
- <script>
702
- function insertTextAtCursor(text) {
703
- var editor = ace.edit("editor");
704
- editor.insert(text);
705
- editor.focus();
706
- }
707
- </script>
708
  """
709
  st.markdown(toolbar_html, unsafe_allow_html=True)
710
 
711
- # VS Code-style editor tabs
712
- def render_editor_tabs(active_tab="document.tex"):
713
- tab_html = f"""
714
- <div class="tab-bar">
715
- <div class="tab active">
716
- <span class="tab-icon">📄</span> {active_tab}
717
- </div>
718
- </div>
719
- """
720
- st.markdown(tab_html, unsafe_allow_html=True)
721
-
722
  # VS Code-style status bar
723
  def render_status_bar():
724
  status_html = """
@@ -752,7 +641,7 @@ def render_document_outline(structure):
752
  indent = "&nbsp;" * (level * 4)
753
 
754
  st.markdown(
755
- f'<div class="outline-item" title="Go to {item["type"]}: {title}">'
756
  f'<span>{type_icon}</span>'
757
  f'<span class="outline-item-text">{indent}{title}</span>'
758
  f'</div>',
@@ -795,6 +684,13 @@ def render_problems(errors, warnings):
795
 
796
  # Render document information panel
797
  def render_document_info(latex_code):
 
 
 
 
 
 
 
798
  # Calculate basic document stats
799
  word_count = len(re.findall(r'\b\w+\b', latex_code))
800
  char_count = len(latex_code)
@@ -872,10 +768,15 @@ def main():
872
  # Toolbar
873
  render_toolbar()
874
 
875
- # Initialize Ace editor
876
- latex_code = create_editor_component("ace_editor", height=500)
877
- if latex_code is not None:
878
- st.session_state.latex_code = latex_code
 
 
 
 
 
879
 
880
  # Status bar
881
  render_status_bar()
@@ -1014,8 +915,11 @@ def main():
1014
  st.info("Click 'Compile' to generate PDF output")
1015
 
1016
  with output_tabs[1]:
1017
- # Document structure/outline view
1018
- structure = extract_document_structure(st.session_state.latex_code)
 
 
 
1019
  render_document_outline(structure)
1020
 
1021
  with output_tabs[2]:
 
10
  import fitz # PyMuPDF
11
  import time
12
  import re
 
13
 
14
  # Set page configuration
15
  st.set_page_config(
 
24
  return shutil.which("pdflatex") is not None
25
 
26
  # Function to convert LaTeX to PDF
27
+ def latex_to_pdf(latex_code):
28
  # Check if pdflatex is installed
29
  if not is_pdflatex_installed():
30
  st.error("pdflatex not found. Debug info:")
 
34
  return None, "", "Error: pdflatex is not installed or not in PATH."
35
 
36
  with tempfile.TemporaryDirectory() as temp_dir:
 
 
 
37
  temp_path = Path(temp_dir)
38
  tex_file = temp_path / "document.tex"
39
+ pdf_file = temp_path / "document.pdf"
40
 
41
  # Write LaTeX code to file
42
  with open(tex_file, "w") as f:
 
45
  try:
46
  # Run pdflatex to compile the LaTeX file
47
  process = subprocess.run(
48
+ ["pdflatex", "-interaction=nonstopmode", "-output-directory", temp_dir, str(tex_file)],
49
  capture_output=True,
50
  text=True
51
  )
 
60
  except Exception as e:
61
  return None, "", str(e)
62
 
63
+ # Function to create download link for PDF
64
+ def get_download_link(pdf_data, filename="document.pdf"):
65
+ b64_pdf = base64.b64encode(pdf_data).decode()
66
+ return f'<a href="data:application/pdf;base64,{b64_pdf}" download="{filename}" class="download-button">Download PDF</a>'
67
+
68
  # Convert PDF to image for preview
69
  def render_pdf_preview(pdf_data):
70
  if not pdf_data:
 
79
 
80
  # Render pages as images
81
  images = []
82
+ for page_num in range(min(3, len(pdf_document))): # Preview first 3 pages max
83
  page = pdf_document.load_page(page_num)
84
  pix = page.get_pixmap(matrix=fitz.Matrix(2, 2)) # Zoom factor 2 for better resolution
85
  img_data = pix.tobytes("png")
 
92
  st.error(f"Error rendering PDF preview: {str(e)}")
93
  return None
94
 
 
 
 
 
 
95
  # Function to parse LaTeX errors
96
  def parse_latex_errors(output):
97
  errors = []
 
109
 
110
  return errors, warnings
111
 
112
+ # Function to extract document structure - fixed to handle non-string input
113
  def extract_document_structure(latex_code):
114
  structure = []
115
 
116
+ # Ensure latex_code is a string
117
+ if latex_code is None:
118
+ return structure
119
+
120
+ if not isinstance(latex_code, str):
121
+ try:
122
+ latex_code = str(latex_code)
123
+ except:
124
+ return structure
125
+
126
  # Find sections, subsections, etc.
127
  section_pattern = r'\\(section|subsection|subsubsection|chapter|part)\{([^}]+)\}'
128
  matches = re.finditer(section_pattern, latex_code)
 
244
  \end{document}
245
  """
246
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  # Enhanced VSCode-like advanced styling
248
  st.markdown("""
249
  <style>
 
267
  background-color: #1177bb;
268
  }
269
 
270
+ /* VS Code-like editor */
271
+ .stTextArea textarea {
272
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace !important;
273
+ font-size: 14px !important;
274
+ line-height: 1.5 !important;
275
+ background-color: #1e1e1e !important;
276
+ color: #d4d4d4 !important;
277
+ padding: 10px !important;
278
+ border-radius: 4px !important;
279
+ border: 1px solid #252526 !important;
280
+ }
281
+
282
  /* VS Code-like editor container */
283
  .editor-container {
284
  background-color: #1e1e1e;
 
330
  font-size: 12px;
331
  }
332
 
333
+ /* Toolbar */
334
+ .toolbar {
335
+ background-color: #2d2d2d;
336
+ padding: 5px;
337
  display: flex;
338
+ gap: 5px;
339
  align-items: center;
 
340
  }
341
 
342
+ .toolbar-button {
343
+ background-color: transparent;
344
+ border: none;
345
+ color: #cccccc;
346
+ padding: 5px;
347
  cursor: pointer;
348
+ border-radius: 2px;
349
+ }
350
+
351
+ .toolbar-button:hover {
352
+ background-color: #3c3c3c;
353
  }
354
 
355
+ .toolbar-separator {
356
+ width: 1px;
357
+ height: 20px;
358
+ background-color: #555;
359
+ margin: 0 5px;
360
  }
361
 
362
  /* Terminal/console styling */
 
445
  gap: 5px;
446
  }
447
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  /* Messages */
449
  .stInfo {
450
  background-color: #063b49;
 
489
  color: white;
490
  }
491
 
492
+ /* Problems panel */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
493
  .problems-panel {
494
  background-color: #252526;
495
  border: 1px solid #2d2d2d;
 
556
  </style>
557
  """, unsafe_allow_html=True)
558
 
559
+ # VS Code-style editor tabs
560
+ def render_editor_tabs(active_tab="document.tex"):
561
+ tab_html = f"""
562
+ <div class="tab-bar">
563
+ <div class="tab active">
564
+ <span class="tab-icon">📄</span> {active_tab}
565
+ </div>
566
+ </div>
567
+ """
568
+ st.markdown(tab_html, unsafe_allow_html=True)
 
 
 
 
569
 
570
  # Build a VS Code-like toolbar
571
  def render_toolbar():
572
  toolbar_html = """
573
  <div class="toolbar">
574
+ <button class="toolbar-button" title="Bold">
575
  <strong>B</strong>
576
  </button>
577
+ <button class="toolbar-button" title="Italic">
578
  <em>I</em>
579
  </button>
580
+ <button class="toolbar-button" title="Math">
581
 
582
  </button>
583
  <div class="toolbar-separator"></div>
584
+ <button class="toolbar-button" title="Section">
585
  §
586
  </button>
587
+ <button class="toolbar-button" title="Subsection">
588
  §§
589
  </button>
590
  <div class="toolbar-separator"></div>
591
+ <button class="toolbar-button" title="Itemize">
592
 
593
  </button>
594
+ <button class="toolbar-button" title="Enumerate">
595
  1.
596
  </button>
597
  <div class="toolbar-separator"></div>
598
+ <button class="toolbar-button" title="Equation">
599
  =
600
  </button>
601
+ <button class="toolbar-button" title="Figure">
602
  🖼
603
  </button>
604
+ <button class="toolbar-button" title="Table">
605
 
606
  </button>
607
  </div>
 
 
 
 
 
 
 
 
608
  """
609
  st.markdown(toolbar_html, unsafe_allow_html=True)
610
 
 
 
 
 
 
 
 
 
 
 
 
611
  # VS Code-style status bar
612
  def render_status_bar():
613
  status_html = """
 
641
  indent = "&nbsp;" * (level * 4)
642
 
643
  st.markdown(
644
+ f'<div class="outline-item">'
645
  f'<span>{type_icon}</span>'
646
  f'<span class="outline-item-text">{indent}{title}</span>'
647
  f'</div>',
 
684
 
685
  # Render document information panel
686
  def render_document_info(latex_code):
687
+ # Ensure latex_code is a string
688
+ if not isinstance(latex_code, str):
689
+ try:
690
+ latex_code = str(latex_code)
691
+ except:
692
+ latex_code = ""
693
+
694
  # Calculate basic document stats
695
  word_count = len(re.findall(r'\b\w+\b', latex_code))
696
  char_count = len(latex_code)
 
768
  # Toolbar
769
  render_toolbar()
770
 
771
+ # Simple text area with VS Code styling
772
+ latex_code = st.text_area(
773
+ "",
774
+ value=st.session_state.latex_code,
775
+ height=500,
776
+ key="latex_editor",
777
+ label_visibility="collapsed"
778
+ )
779
+ st.session_state.latex_code = latex_code
780
 
781
  # Status bar
782
  render_status_bar()
 
915
  st.info("Click 'Compile' to generate PDF output")
916
 
917
  with output_tabs[1]:
918
+ # Document structure/outline view (with type check)
919
+ if isinstance(st.session_state.latex_code, str):
920
+ structure = extract_document_structure(st.session_state.latex_code)
921
+ else:
922
+ structure = []
923
  render_document_outline(structure)
924
 
925
  with output_tabs[2]: