1
+ import logging
1
2
import os
2
3
import re
3
4
from enum import Enum
@@ -13,43 +14,85 @@ class ArtifactType(Enum):
13
14
HTML = "html"
14
15
15
16
16
- HTML_FILE_TEMPLATE = """
17
+ COMMON_STYLES = """
18
+ body {
19
+ font-family: Arial, sans-serif;
20
+ line-height: 1.3;
21
+ color: #333;
22
+ }
23
+ h1, h2, h3, h4, h5, h6 {
24
+ margin-top: 1em;
25
+ margin-bottom: 0.5em;
26
+ }
27
+ p {
28
+ margin-bottom: 0.7em;
29
+ }
30
+ code {
31
+ background-color: #f4f4f4;
32
+ padding: 2px 4px;
33
+ border-radius: 4px;
34
+ }
35
+ pre {
36
+ background-color: #f4f4f4;
37
+ padding: 10px;
38
+ border-radius: 4px;
39
+ overflow-x: auto;
40
+ }
41
+ table {
42
+ border-collapse: collapse;
43
+ width: 100%;
44
+ margin-bottom: 1em;
45
+ }
46
+ th, td {
47
+ border: 1px solid #ddd;
48
+ padding: 8px;
49
+ text-align: left;
50
+ }
51
+ th {
52
+ background-color: #f2f2f2;
53
+ font-weight: bold;
54
+ }
55
+ """
56
+
57
+ HTML_SPECIFIC_STYLES = """
58
+ body {
59
+ max-width: 800px;
60
+ margin: 0 auto;
61
+ padding: 20px;
62
+ }
63
+ """
64
+
65
+ PDF_SPECIFIC_STYLES = """
66
+ @page {
67
+ size: letter;
68
+ margin: 2cm;
69
+ }
70
+ body {
71
+ font-size: 11pt;
72
+ }
73
+ h1 { font-size: 18pt; }
74
+ h2 { font-size: 16pt; }
75
+ h3 { font-size: 14pt; }
76
+ h4, h5, h6 { font-size: 12pt; }
77
+ pre, code {
78
+ font-family: Courier, monospace;
79
+ font-size: 0.9em;
80
+ }
81
+ """
82
+
83
+ HTML_TEMPLATE = """
17
84
<!DOCTYPE html>
18
85
<html lang="en">
19
86
<head>
20
87
<meta charset="UTF-8">
21
88
<meta name="viewport" content="width=device-width, initial-scale=1.0">
22
89
<style>
23
- body {{
24
- font-family: Arial, sans-serif;
25
- line-height: 1.3;
26
- color: #333;
27
- max-width: 800px;
28
- margin: 0 auto;
29
- padding: 20px;
30
- }}
31
- h1, h2, h3, h4, h5, h6 {{
32
- margin-top: 1.5em;
33
- margin-bottom: 0.5em;
34
- }}
35
- p {{
36
- margin-bottom: 1em;
37
- }}
38
- code {{
39
- background-color: #f4f4f4;
40
- padding: 2px 4px;
41
- border-radius: 4px;
42
- }}
43
- pre {{
44
- background-color: #f4f4f4;
45
- padding: 10px;
46
- border-radius: 4px;
47
- overflow-x: auto;
48
- }}
90
+ {common_styles}
91
+ {specific_styles}
49
92
</style>
50
93
</head>
51
94
<body>
52
- {html_content }
95
+ {content }
53
96
</body>
54
97
</html>
55
98
"""
@@ -68,8 +111,10 @@ def _generate_html_content(cls, original_content: str) -> str:
68
111
"Failed to import required modules. Please install markdown."
69
112
)
70
113
71
- # Convert markdown to HTML
72
- html_content = markdown .markdown (original_content )
114
+ # Convert markdown to HTML with fenced code and table extensions
115
+ html_content = markdown .markdown (
116
+ original_content , extensions = ["fenced_code" , "tables" ]
117
+ )
73
118
return html_content
74
119
75
120
@classmethod
@@ -84,25 +129,21 @@ def _generate_pdf(cls, html_content: str) -> BytesIO:
84
129
"Failed to import required modules. Please install xhtml2pdf."
85
130
)
86
131
132
+ pdf_html = HTML_TEMPLATE .format (
133
+ common_styles = COMMON_STYLES ,
134
+ specific_styles = PDF_SPECIFIC_STYLES ,
135
+ content = html_content ,
136
+ )
137
+
87
138
buffer = BytesIO ()
88
139
pdf = pisa .pisaDocument (
89
- BytesIO (html_content .encode ("UTF-8" )),
90
- buffer ,
91
- encoding = "UTF-8" ,
92
- path = "." ,
93
- link_callback = None ,
94
- debug = 0 ,
95
- default_css = None ,
96
- xhtml = False ,
97
- xml_output = None ,
98
- ident = 0 ,
99
- show_error_as_pdf = False ,
100
- quiet = True ,
101
- capacity = 100 * 1024 * 1024 ,
102
- raise_exception = True ,
140
+ BytesIO (pdf_html .encode ("UTF-8" )), buffer , encoding = "UTF-8"
103
141
)
142
+
104
143
if pdf .err :
144
+ logging .error (f"PDF generation failed: { pdf .err } " )
105
145
raise ValueError ("PDF generation failed" )
146
+
106
147
buffer .seek (0 )
107
148
return buffer
108
149
@@ -111,7 +152,11 @@ def _generate_html(cls, html_content: str) -> str:
111
152
"""
112
153
Generate a complete HTML document with the given HTML content.
113
154
"""
114
- return HTML_FILE_TEMPLATE .format (html_content = html_content )
155
+ return HTML_TEMPLATE .format (
156
+ common_styles = COMMON_STYLES ,
157
+ specific_styles = HTML_SPECIFIC_STYLES ,
158
+ content = html_content ,
159
+ )
115
160
116
161
@classmethod
117
162
def generate_artifact (
@@ -137,7 +182,7 @@ def generate_artifact(
137
182
138
183
# Based on the type of artifact, generate the corresponding file
139
184
if artifact_type == ArtifactType .PDF :
140
- content = cls ._generate_pdf (cls . _generate_html ( html_content ) )
185
+ content = cls ._generate_pdf (html_content )
141
186
file_extension = "pdf"
142
187
elif artifact_type == ArtifactType .HTML :
143
188
content = BytesIO (cls ._generate_html (html_content ).encode ("utf-8" ))
0 commit comments