Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -839,7 +839,8 @@ class MarkdownToPDFAgent:
|
|
| 839 |
|
| 840 |
return output_files
|
| 841 |
|
| 842 |
-
|
|
|
|
| 843 |
def load_sample():
|
| 844 |
"""Load a sample markdown document."""
|
| 845 |
return """# Sample Markdown Document
|
|
@@ -870,7 +871,7 @@ def hello_world():
|
|
| 870 |
"""
|
| 871 |
|
| 872 |
def process_markdown(markdown_text, page_size, font_size, font_name,
|
| 873 |
-
margin_size, include_toc, use_ai,
|
| 874 |
"""
|
| 875 |
Process markdown text and generate a PDF.
|
| 876 |
|
|
@@ -895,12 +896,14 @@ def process_markdown(markdown_text, page_size, font_size, font_name,
|
|
| 895 |
include_toc=include_toc
|
| 896 |
)
|
| 897 |
|
|
|
|
|
|
|
|
|
|
| 898 |
# Setup AI enhancement if requested
|
| 899 |
enhance = False
|
| 900 |
if use_ai and api_key:
|
| 901 |
-
|
| 902 |
-
|
| 903 |
-
enhance = success
|
| 904 |
|
| 905 |
try:
|
| 906 |
# Create a temporary file for the markdown content
|
|
@@ -921,106 +924,393 @@ def process_markdown(markdown_text, page_size, font_size, font_name,
|
|
| 921 |
os.unlink(temp_md_path)
|
| 922 |
|
| 923 |
if output_file:
|
| 924 |
-
return output_file
|
| 925 |
else:
|
| 926 |
-
return None
|
| 927 |
except Exception as e:
|
| 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
|
| 933 |
-
|
| 934 |
-
|
| 935 |
-
|
| 936 |
-
|
| 937 |
-
|
| 938 |
-
|
| 939 |
-
|
|
|
|
| 940 |
|
| 941 |
with gr.Row():
|
|
|
|
| 942 |
with gr.Column(scale=1):
|
| 943 |
-
gr.Markdown("
|
| 944 |
|
| 945 |
markdown_input = gr.TextArea(
|
| 946 |
placeholder="Enter your markdown content here...",
|
| 947 |
label="Markdown Content",
|
| 948 |
-
lines=15
|
|
|
|
| 949 |
)
|
| 950 |
|
| 951 |
-
|
|
|
|
|
|
|
| 952 |
|
| 953 |
-
with gr.
|
| 954 |
-
|
| 955 |
-
|
| 956 |
-
|
| 957 |
-
|
| 958 |
-
|
| 959 |
-
|
| 960 |
-
|
| 961 |
-
|
| 962 |
-
|
| 963 |
-
|
| 964 |
-
|
| 965 |
-
|
| 966 |
-
|
| 967 |
-
|
| 968 |
-
|
| 969 |
-
|
| 970 |
-
|
| 971 |
-
|
| 972 |
-
|
| 973 |
-
|
| 974 |
-
|
| 975 |
-
|
| 976 |
-
|
| 977 |
-
|
| 978 |
-
|
| 979 |
-
|
| 980 |
-
|
| 981 |
-
|
| 982 |
-
|
| 983 |
-
|
| 984 |
-
|
| 985 |
-
|
| 986 |
-
|
| 987 |
-
|
| 988 |
-
|
| 989 |
-
|
| 990 |
-
|
| 991 |
-
|
| 992 |
-
|
| 993 |
-
|
| 994 |
-
|
| 995 |
-
|
| 996 |
-
|
| 997 |
-
|
| 998 |
-
|
| 999 |
-
|
| 1000 |
-
|
| 1001 |
-
|
| 1002 |
-
|
| 1003 |
-
|
| 1004 |
-
|
| 1005 |
-
|
| 1006 |
-
|
| 1007 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1008 |
|
|
|
|
|
|
|
|
|
|
| 1009 |
with gr.Column(scale=1):
|
| 1010 |
-
gr.Markdown("
|
| 1011 |
|
| 1012 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1013 |
|
| 1014 |
# Set up event handlers
|
| 1015 |
sample_btn.click(load_sample, outputs=markdown_input)
|
|
|
|
| 1016 |
|
| 1017 |
-
#
|
| 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=[
|
|
@@ -1031,22 +1321,21 @@ with gr.Blocks(title="MarkdownMuse", theme=gr.themes.Soft()) as app:
|
|
| 1031 |
margin_size,
|
| 1032 |
include_toc,
|
| 1033 |
use_ai,
|
| 1034 |
-
api_key,
|
| 1035 |
enhancement_instructions
|
| 1036 |
],
|
| 1037 |
-
outputs=
|
| 1038 |
-
|
| 1039 |
-
|
| 1040 |
-
|
| 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 |
|
| 1050 |
# Launch the app
|
| 1051 |
if __name__ == "__main__":
|
| 1052 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 839 |
|
| 840 |
return output_files
|
| 841 |
|
| 842 |
+
|
| 843 |
+
# Helper functions for the Gradio interface
|
| 844 |
def load_sample():
|
| 845 |
"""Load a sample markdown document."""
|
| 846 |
return """# Sample Markdown Document
|
|
|
|
| 871 |
"""
|
| 872 |
|
| 873 |
def process_markdown(markdown_text, page_size, font_size, font_name,
|
| 874 |
+
margin_size, include_toc, use_ai, enhancement_instructions):
|
| 875 |
"""
|
| 876 |
Process markdown text and generate a PDF.
|
| 877 |
|
|
|
|
| 896 |
include_toc=include_toc
|
| 897 |
)
|
| 898 |
|
| 899 |
+
# Get Gemini API key from environment
|
| 900 |
+
api_key = os.environ.get('GOOGLE_API_KEY')
|
| 901 |
+
|
| 902 |
# Setup AI enhancement if requested
|
| 903 |
enhance = False
|
| 904 |
if use_ai and api_key:
|
| 905 |
+
success = agent.setup_from_gemini(api_key)
|
| 906 |
+
enhance = success
|
|
|
|
| 907 |
|
| 908 |
try:
|
| 909 |
# Create a temporary file for the markdown content
|
|
|
|
| 924 |
os.unlink(temp_md_path)
|
| 925 |
|
| 926 |
if output_file:
|
| 927 |
+
return output_file, "β
PDF generated successfully!"
|
| 928 |
else:
|
| 929 |
+
return None, "β Error generating PDF. Please check your markdown syntax."
|
| 930 |
except Exception as e:
|
| 931 |
logger.error(f"Error processing markdown: {e}")
|
| 932 |
+
return None, f"β Error: {str(e)}"
|
| 933 |
+
|
| 934 |
+
|
| 935 |
+
# Check if the API key is available in the environment
|
| 936 |
+
has_api_key = bool(os.environ.get('GOOGLE_API_KEY'))
|
| 937 |
+
|
| 938 |
+
# Custom CSS for styling
|
| 939 |
+
custom_css = """
|
| 940 |
+
<style>
|
| 941 |
+
:root {
|
| 942 |
+
--primary-color: #6366F1;
|
| 943 |
+
--secondary-color: #8B5CF6;
|
| 944 |
+
--accent-color: #4f46e5;
|
| 945 |
+
--text-color: #1F2937;
|
| 946 |
+
--light-text: #F9FAFB;
|
| 947 |
+
--border-color: #E5E7EB;
|
| 948 |
+
--background-color: #F3F4F6;
|
| 949 |
+
--card-background: #FFFFFF;
|
| 950 |
+
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
| 951 |
+
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
| 952 |
+
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
| 953 |
+
--rounded-sm: 0.375rem;
|
| 954 |
+
--rounded-md: 0.5rem;
|
| 955 |
+
--rounded-lg: 0.75rem;
|
| 956 |
+
}
|
| 957 |
+
|
| 958 |
+
.header {
|
| 959 |
+
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
|
| 960 |
+
color: var(--light-text);
|
| 961 |
+
padding: 2rem;
|
| 962 |
+
border-radius: var(--rounded-lg);
|
| 963 |
+
margin-bottom: 1.5rem;
|
| 964 |
+
box-shadow: var(--shadow-lg);
|
| 965 |
+
text-align: center;
|
| 966 |
+
position: relative;
|
| 967 |
+
overflow: hidden;
|
| 968 |
+
}
|
| 969 |
+
|
| 970 |
+
.header::before {
|
| 971 |
+
content: "";
|
| 972 |
+
position: absolute;
|
| 973 |
+
top: 0;
|
| 974 |
+
left: 0;
|
| 975 |
+
right: 0;
|
| 976 |
+
bottom: 0;
|
| 977 |
+
background: repeating-linear-gradient(
|
| 978 |
+
45deg,
|
| 979 |
+
rgba(255, 255, 255, 0.05),
|
| 980 |
+
rgba(255, 255, 255, 0.05) 10px,
|
| 981 |
+
rgba(255, 255, 255, 0) 10px,
|
| 982 |
+
rgba(255, 255, 255, 0) 20px
|
| 983 |
+
);
|
| 984 |
+
}
|
| 985 |
+
|
| 986 |
+
.header h1 {
|
| 987 |
+
font-size: 2.5rem;
|
| 988 |
+
margin-bottom: 0.5rem;
|
| 989 |
+
font-weight: 700;
|
| 990 |
+
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
| 991 |
+
}
|
| 992 |
+
|
| 993 |
+
.header p {
|
| 994 |
+
font-size: 1.25rem;
|
| 995 |
+
opacity: 0.9;
|
| 996 |
+
max-width: 700px;
|
| 997 |
+
margin: 0 auto;
|
| 998 |
+
}
|
| 999 |
+
|
| 1000 |
+
.container {
|
| 1001 |
+
max-width: 1200px;
|
| 1002 |
+
margin: 0 auto;
|
| 1003 |
+
padding: 0 1rem;
|
| 1004 |
+
}
|
| 1005 |
+
|
| 1006 |
+
.card {
|
| 1007 |
+
background: var(--card-background);
|
| 1008 |
+
border-radius: var(--rounded-lg);
|
| 1009 |
+
padding: 1.5rem;
|
| 1010 |
+
box-shadow: var(--shadow-md);
|
| 1011 |
+
margin-bottom: 1.5rem;
|
| 1012 |
+
border: 1px solid var(--border-color);
|
| 1013 |
+
transition: transform 0.2s, box-shadow 0.2s;
|
| 1014 |
+
}
|
| 1015 |
+
|
| 1016 |
+
.card:hover {
|
| 1017 |
+
transform: translateY(-2px);
|
| 1018 |
+
box-shadow: var(--shadow-lg);
|
| 1019 |
+
}
|
| 1020 |
+
|
| 1021 |
+
.section-title {
|
| 1022 |
+
color: var(--primary-color);
|
| 1023 |
+
font-size: 1.5rem;
|
| 1024 |
+
font-weight: 600;
|
| 1025 |
+
margin-bottom: 1rem;
|
| 1026 |
+
padding-bottom: 0.75rem;
|
| 1027 |
+
border-bottom: 2px solid var(--border-color);
|
| 1028 |
+
}
|
| 1029 |
+
|
| 1030 |
+
.footer {
|
| 1031 |
+
text-align: center;
|
| 1032 |
+
margin-top: 2rem;
|
| 1033 |
+
padding: 1.5rem;
|
| 1034 |
+
background: var(--background-color);
|
| 1035 |
+
border-radius: var(--rounded-lg);
|
| 1036 |
+
font-size: 0.9rem;
|
| 1037 |
+
color: var(--text-color);
|
| 1038 |
+
box-shadow: var(--shadow-sm);
|
| 1039 |
+
}
|
| 1040 |
+
|
| 1041 |
+
.feature-icon {
|
| 1042 |
+
display: inline-block;
|
| 1043 |
+
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
|
| 1044 |
+
color: white;
|
| 1045 |
+
width: 2.5rem;
|
| 1046 |
+
height: 2.5rem;
|
| 1047 |
+
line-height: 2.5rem;
|
| 1048 |
+
text-align: center;
|
| 1049 |
+
border-radius: 50%;
|
| 1050 |
+
margin-right: 0.75rem;
|
| 1051 |
+
font-size: 1.25rem;
|
| 1052 |
+
box-shadow: var(--shadow-sm);
|
| 1053 |
+
}
|
| 1054 |
+
|
| 1055 |
+
.button-row {
|
| 1056 |
+
display: flex;
|
| 1057 |
+
gap: 0.75rem;
|
| 1058 |
+
margin: 1rem 0;
|
| 1059 |
+
}
|
| 1060 |
+
|
| 1061 |
+
.primary-btn {
|
| 1062 |
+
background: linear-gradient(to right, var(--primary-color), var(--secondary-color)) !important;
|
| 1063 |
+
transition: all 0.3s ease !important;
|
| 1064 |
+
transform: translateY(0);
|
| 1065 |
+
box-shadow: var(--shadow-md) !important;
|
| 1066 |
+
font-weight: 600 !important;
|
| 1067 |
+
}
|
| 1068 |
+
|
| 1069 |
+
.primary-btn:hover {
|
| 1070 |
+
transform: translateY(-2px);
|
| 1071 |
+
box-shadow: var(--shadow-lg) !important;
|
| 1072 |
+
}
|
| 1073 |
+
|
| 1074 |
+
.secondary-btn {
|
| 1075 |
+
background: var(--background-color) !important;
|
| 1076 |
+
color: var(--text-color) !important;
|
| 1077 |
+
border: 1px solid var(--border-color) !important;
|
| 1078 |
+
font-weight: 500 !important;
|
| 1079 |
+
}
|
| 1080 |
+
|
| 1081 |
+
.tip-box {
|
| 1082 |
+
background: rgba(99, 102, 241, 0.1);
|
| 1083 |
+
border-left: 4px solid var(--primary-color);
|
| 1084 |
+
padding: 1rem;
|
| 1085 |
+
margin: 1rem 0;
|
| 1086 |
+
border-radius: var(--rounded-sm);
|
| 1087 |
+
}
|
| 1088 |
+
|
| 1089 |
+
.tip-title {
|
| 1090 |
+
color: var(--primary-color);
|
| 1091 |
+
font-weight: 600;
|
| 1092 |
+
margin-bottom: 0.5rem;
|
| 1093 |
+
}
|
| 1094 |
+
|
| 1095 |
+
/* Tab styling */
|
| 1096 |
+
.tab-active {
|
| 1097 |
+
border-bottom: 3px solid var(--primary-color);
|
| 1098 |
+
color: var(--primary-color);
|
| 1099 |
+
font-weight: 600;
|
| 1100 |
+
}
|
| 1101 |
+
|
| 1102 |
+
/* Customize Gradio components */
|
| 1103 |
+
.gr-box {
|
| 1104 |
+
border-radius: var(--rounded-md) !important;
|
| 1105 |
+
border: 1px solid var(--border-color) !important;
|
| 1106 |
+
}
|
| 1107 |
+
|
| 1108 |
+
.gr-button {
|
| 1109 |
+
border-radius: var(--rounded-md) !important;
|
| 1110 |
+
}
|
| 1111 |
+
|
| 1112 |
+
.gr-form {
|
| 1113 |
+
border-radius: var(--rounded-md) !important;
|
| 1114 |
+
border: 1px solid var(--border-color) !important;
|
| 1115 |
+
box-shadow: var(--shadow-sm) !important;
|
| 1116 |
+
}
|
| 1117 |
+
|
| 1118 |
+
.gr-input {
|
| 1119 |
+
border-radius: var(--rounded-md) !important;
|
| 1120 |
+
}
|
| 1121 |
+
|
| 1122 |
+
.gr-checkbox {
|
| 1123 |
+
border-radius: var(--rounded-sm) !important;
|
| 1124 |
+
}
|
| 1125 |
+
|
| 1126 |
+
.gr-panel {
|
| 1127 |
+
border-radius: var(--rounded-md) !important;
|
| 1128 |
+
}
|
| 1129 |
+
|
| 1130 |
+
.gr-accordion {
|
| 1131 |
+
border-radius: var(--rounded-md) !important;
|
| 1132 |
+
}
|
| 1133 |
+
</style>
|
| 1134 |
+
"""
|
| 1135 |
|
| 1136 |
# Define the Gradio interface
|
| 1137 |
+
with gr.Blocks(title="MarkdownMuse", theme=gr.themes.Soft()) as demo:
|
| 1138 |
+
# Header with custom styling
|
| 1139 |
+
gr.HTML(custom_css + """
|
| 1140 |
+
<div class="header">
|
| 1141 |
+
<h1>π MarkdownMuse</h1>
|
| 1142 |
+
<p>Transform your Markdown files into beautifully formatted PDFs with a single click.
|
| 1143 |
+
Professional-looking documents made simple.</p>
|
| 1144 |
+
</div>
|
| 1145 |
+
""")
|
| 1146 |
|
| 1147 |
with gr.Row():
|
| 1148 |
+
# Input Section
|
| 1149 |
with gr.Column(scale=1):
|
| 1150 |
+
gr.Markdown("## π Input", elem_id="section-title")
|
| 1151 |
|
| 1152 |
markdown_input = gr.TextArea(
|
| 1153 |
placeholder="Enter your markdown content here...",
|
| 1154 |
label="Markdown Content",
|
| 1155 |
+
lines=15,
|
| 1156 |
+
elem_id="markdown-input"
|
| 1157 |
)
|
| 1158 |
|
| 1159 |
+
with gr.Row(elem_id="button-row"):
|
| 1160 |
+
sample_btn = gr.Button("π Load Sample", size="sm", elem_classes="secondary-btn")
|
| 1161 |
+
clear_btn = gr.Button("ποΈ Clear", size="sm", elem_classes="secondary-btn")
|
| 1162 |
|
| 1163 |
+
with gr.Tabs():
|
| 1164 |
+
with gr.TabItem("π PDF Settings", elem_classes="tab-item"):
|
| 1165 |
+
with gr.Row():
|
| 1166 |
+
with gr.Column(scale=1):
|
| 1167 |
+
page_size = gr.Radio(
|
| 1168 |
+
["A4", "Letter"],
|
| 1169 |
+
label="Page Size",
|
| 1170 |
+
value="A4",
|
| 1171 |
+
elem_id="page-size"
|
| 1172 |
+
)
|
| 1173 |
+
include_toc = gr.Checkbox(
|
| 1174 |
+
value=True,
|
| 1175 |
+
label="Include Table of Contents",
|
| 1176 |
+
elem_id="include-toc"
|
| 1177 |
+
)
|
| 1178 |
+
|
| 1179 |
+
with gr.Column(scale=1):
|
| 1180 |
+
font_name = gr.Dropdown(
|
| 1181 |
+
["Helvetica", "Times-Roman", "Courier"],
|
| 1182 |
+
label="Font Family",
|
| 1183 |
+
value="Helvetica",
|
| 1184 |
+
elem_id="font-name"
|
| 1185 |
+
)
|
| 1186 |
+
font_size = gr.Slider(
|
| 1187 |
+
minimum=8,
|
| 1188 |
+
maximum=14,
|
| 1189 |
+
value=10,
|
| 1190 |
+
step=1,
|
| 1191 |
+
label="Base Font Size (pt)",
|
| 1192 |
+
elem_id="font-size"
|
| 1193 |
+
)
|
| 1194 |
+
|
| 1195 |
+
margin_size = gr.Slider(
|
| 1196 |
+
minimum=0.5,
|
| 1197 |
+
maximum=2.0,
|
| 1198 |
+
value=0.75,
|
| 1199 |
+
step=0.25,
|
| 1200 |
+
label="Margins (inches)",
|
| 1201 |
+
elem_id="margin-size"
|
| 1202 |
+
)
|
| 1203 |
+
|
| 1204 |
+
with gr.TabItem("π§ AI Enhancement", elem_classes="tab-item"):
|
| 1205 |
+
use_ai = gr.Checkbox(
|
| 1206 |
+
value=has_api_key,
|
| 1207 |
+
label="Enable AI Enhancement",
|
| 1208 |
+
elem_id="use-ai"
|
| 1209 |
+
)
|
| 1210 |
+
|
| 1211 |
+
# Only show API key message if no key is in environment
|
| 1212 |
+
if not has_api_key:
|
| 1213 |
+
gr.Markdown("""
|
| 1214 |
+
> **Note:** To use AI enhancement, add your Google Gemini API key to the Hugging Face Space secrets as `GOOGLE_API_KEY`.
|
| 1215 |
+
""", elem_id="api-key-note")
|
| 1216 |
+
else:
|
| 1217 |
+
gr.Markdown("""
|
| 1218 |
+
> **API Key Detected!** AI enhancement is available.
|
| 1219 |
+
""", elem_id="api-key-success")
|
| 1220 |
+
|
| 1221 |
+
enhancement_instructions = gr.TextArea(
|
| 1222 |
+
placeholder="Provide specific instructions for how the AI should enhance your markdown... (Optional)",
|
| 1223 |
+
label="Enhancement Instructions",
|
| 1224 |
+
lines=3,
|
| 1225 |
+
elem_id="enhancement-instructions"
|
| 1226 |
+
)
|
| 1227 |
|
| 1228 |
+
convert_btn = gr.Button("π Convert to PDF", variant="primary", elem_classes="primary-btn")
|
| 1229 |
+
|
| 1230 |
+
# Output Section
|
| 1231 |
with gr.Column(scale=1):
|
| 1232 |
+
gr.Markdown("## π Output", elem_id="section-title")
|
| 1233 |
|
| 1234 |
+
status = gr.Markdown("β¨ Ready to convert your markdown to PDF.", elem_id="status")
|
| 1235 |
+
output_pdf = gr.File(label="Generated PDF", elem_id="output-pdf")
|
| 1236 |
+
|
| 1237 |
+
with gr.Accordion("π‘ Markdown Tips", open=False, elem_id="markdown-tips"):
|
| 1238 |
+
gr.HTML("""
|
| 1239 |
+
<div class="tip-box">
|
| 1240 |
+
<div class="tip-title">β¨ Basic Syntax</div>
|
| 1241 |
+
<ul>
|
| 1242 |
+
<li><strong>Headings</strong>: Use <code>#</code> for h1, <code>##</code> for h2, etc.</li>
|
| 1243 |
+
<li><strong>Bold</strong>: Surround text with <code>**double asterisks**</code></li>
|
| 1244 |
+
<li><strong>Italic</strong>: Surround text with <code>*single asterisks*</code></li>
|
| 1245 |
+
<li><strong>Lists</strong>: Start lines with <code>-</code> or <code>*</code> for bullets, <code>1.</code> for numbered</li>
|
| 1246 |
+
<li><strong>Links</strong>: <code>[link text](http://example.com)</code></li>
|
| 1247 |
+
<li><strong>Images</strong>: <code></code></li>
|
| 1248 |
+
</ul>
|
| 1249 |
+
</div>
|
| 1250 |
+
|
| 1251 |
+
<div class="tip-box">
|
| 1252 |
+
<div class="tip-title">π Advanced Features</div>
|
| 1253 |
+
<ul>
|
| 1254 |
+
<li><strong>Tables</strong>: Use <code>|</code> to separate columns and <code>-</code> for header rows</li>
|
| 1255 |
+
<li><strong>Code Blocks</strong>: Wrap with triple backticks (<code>```</code> code <code>```</code>)</li>
|
| 1256 |
+
<li><strong>Blockquotes</strong>: Start lines with <code>></code></li>
|
| 1257 |
+
<li><strong>Horizontal Rule</strong>: Three dashes <code>---</code></li>
|
| 1258 |
+
</ul>
|
| 1259 |
+
</div>
|
| 1260 |
+
|
| 1261 |
+
<p><a href="https://www.markdownguide.org/basic-syntax/" target="_blank">Learn more about Markdown syntax β</a></p>
|
| 1262 |
+
""")
|
| 1263 |
+
|
| 1264 |
+
with gr.Accordion("π Features", open=False, elem_id="features"):
|
| 1265 |
+
gr.HTML("""
|
| 1266 |
+
<div style="display: flex; flex-wrap: wrap; gap: 1rem; margin-top: 0.5rem;">
|
| 1267 |
+
<div style="flex: 1; min-width: 200px;">
|
| 1268 |
+
<div style="display: flex; align-items: center; margin-bottom: 0.5rem;">
|
| 1269 |
+
<span class="feature-icon">π</span>
|
| 1270 |
+
<strong>PDF Conversion</strong>
|
| 1271 |
+
</div>
|
| 1272 |
+
<p>Transform any markdown document into a professionally formatted PDF with proper styling.</p>
|
| 1273 |
+
</div>
|
| 1274 |
+
|
| 1275 |
+
<div style="flex: 1; min-width: 200px;">
|
| 1276 |
+
<div style="display: flex; align-items: center; margin-bottom: 0.5rem;">
|
| 1277 |
+
<span class="feature-icon">π§ </span>
|
| 1278 |
+
<strong>AI Enhancement</strong>
|
| 1279 |
+
</div>
|
| 1280 |
+
<p>Use AI to improve content formatting, fix grammar, and enhance readability.</p>
|
| 1281 |
+
</div>
|
| 1282 |
+
|
| 1283 |
+
<div style="flex: 1; min-width: 200px;">
|
| 1284 |
+
<div style="display: flex; align-items: center; margin-bottom: 0.5rem;">
|
| 1285 |
+
<span class="feature-icon">π¨</span>
|
| 1286 |
+
<strong>Custom Styling</strong>
|
| 1287 |
+
</div>
|
| 1288 |
+
<p>Control fonts, sizes, margins, and other style elements to match your needs.</p>
|
| 1289 |
+
</div>
|
| 1290 |
+
|
| 1291 |
+
<div style="flex: 1; min-width: 200px;">
|
| 1292 |
+
<div style="display: flex; align-items: center; margin-bottom: 0.5rem;">
|
| 1293 |
+
<span class="feature-icon">π</span>
|
| 1294 |
+
<strong>Table of Contents</strong>
|
| 1295 |
+
</div>
|
| 1296 |
+
<p>Automatically generate a structured table of contents from document headings.</p>
|
| 1297 |
+
</div>
|
| 1298 |
+
</div>
|
| 1299 |
+
""")
|
| 1300 |
+
|
| 1301 |
+
# Footer
|
| 1302 |
+
gr.HTML("""
|
| 1303 |
+
<div class="footer">
|
| 1304 |
+
<p><strong>MarkdownMuse</strong> | A powerful Markdown to PDF converter with AI enhancement capabilities</p>
|
| 1305 |
+
<p>Made with β€οΈ using Python, ReportLab, and Gradio | <a href="https://github.com/your-username/markdownmuse" target="_blank">GitHub</a></p>
|
| 1306 |
+
</div>
|
| 1307 |
+
""")
|
| 1308 |
|
| 1309 |
# Set up event handlers
|
| 1310 |
sample_btn.click(load_sample, outputs=markdown_input)
|
| 1311 |
+
clear_btn.click(lambda: "", outputs=markdown_input)
|
| 1312 |
|
| 1313 |
+
# Process markdown and generate PDF
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1314 |
convert_btn.click(
|
| 1315 |
process_markdown,
|
| 1316 |
inputs=[
|
|
|
|
| 1321 |
margin_size,
|
| 1322 |
include_toc,
|
| 1323 |
use_ai,
|
|
|
|
| 1324 |
enhancement_instructions
|
| 1325 |
],
|
| 1326 |
+
outputs=[
|
| 1327 |
+
output_pdf,
|
| 1328 |
+
status
|
| 1329 |
+
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1330 |
)
|
| 1331 |
|
| 1332 |
# Launch the app
|
| 1333 |
if __name__ == "__main__":
|
| 1334 |
+
try:
|
| 1335 |
+
print("Starting MarkdownMuse application...")
|
| 1336 |
+
demo.launch(server_name="0.0.0.0", server_port=7860)
|
| 1337 |
+
print("MarkdownMuse application launched successfully!")
|
| 1338 |
+
except Exception as e:
|
| 1339 |
+
print(f"ERROR LAUNCHING APP: {str(e)}")
|
| 1340 |
+
import traceback
|
| 1341 |
+
traceback.print_exc()
|