Spaces:
Sleeping
Sleeping
| import sys | |
| import subprocess | |
| from pathlib import Path | |
| from os import getenv | |
| from importlib.metadata import version | |
| from PIL import Image | |
| from minijinja import Environment | |
| import gradio as gr | |
| # Config | |
| document_name = "document-template.typ" | |
| do_share = getenv("DO_SHARE") | |
| concurrency_limit = getenv("CONCURRENCY_LIMIT", 1) | |
| typst_bin_path = getenv("TYPST_BIN", "/home/user/app/typst") | |
| # App description | |
| title = "Typst-based PDF generation" | |
| examples = [ | |
| """ | |
| I begin this story with a neutral statement. | |
| Basically this is a very silly test. | |
| """, | |
| ] | |
| description_head = f""" | |
| # {title} | |
| ## Overview | |
| We use https://typst.app to generate a PDF file with some parameters from this Gradio app. | |
| """.strip() | |
| tech_env = f""" | |
| #### Environment | |
| - Python: {sys.version} | |
| """.strip() | |
| def app_version(bin_path): | |
| return subprocess.run([bin_path, "--version"], capture_output=True, text=True) | |
| def typst_compile(typst_bin_path, filename, export_template): | |
| args = [typst_bin_path, "compile", filename, export_template] | |
| print("Running:", args) | |
| return subprocess.run( | |
| args, | |
| capture_output=False, | |
| ) | |
| def convert_document(bin_paths, text): | |
| print("Converting...") | |
| env = Environment( | |
| templates={ | |
| "document": Path("document-template.typ").read_text(), | |
| } | |
| ) | |
| formatted_document = env.render_template("document", text=text) | |
| # Write the rendered document to a temporary file | |
| document_file = Path("document.typ") | |
| document_file.write_text(formatted_document) | |
| # Compile the .typ file to a .pdf file | |
| c = typst_compile(bin_paths["typst"], "document.typ", "document.pdf") | |
| if c.returncode != 0: | |
| raise gr.Error("Typst compilation failed.") | |
| print("Result:", c) | |
| # Extract the first page of the PDF file | |
| c = typst_compile(bin_paths["typst"], "document.typ", "file-{n}.png") | |
| if c.returncode != 0: | |
| raise gr.Error("Typst exporting to PNGs failed.") | |
| print("Result:", c) | |
| first_page = Path("file-1.png") | |
| if not first_page.exists(): | |
| raise gr.Error("The first page has not been exported.") | |
| # Move the image to an object | |
| image = Image.open(first_page.absolute()) | |
| # Remove the temporary files | |
| first_page.unlink(missing_ok=True) | |
| document_file.unlink(missing_ok=True) | |
| return image | |
| typst_version_info = app_version(typst_bin_path) | |
| if typst_version_info.returncode != 0: | |
| print("Error: Typst version command failed.") | |
| exit(1) | |
| r_tech_env = f""" | |
| #### Typst Environment | |
| ``` | |
| {typst_version_info.stdout.strip()} | |
| ``` | |
| """.strip() | |
| tech_libraries = f""" | |
| #### Libraries | |
| - gradio: {version("gradio")} | |
| """.strip() | |
| def generate_pdf(text, progress=gr.Progress()): | |
| if not text: | |
| raise gr.Error("Please paste your text.") | |
| # Remove the previous PDF file and Typst file | |
| Path("document.pdf").unlink(missing_ok=True) | |
| Path("document.typ").unlink(missing_ok=True) | |
| gr.Info("Generating the PDF document", duration=1) | |
| bin_paths = { | |
| "typst": typst_bin_path, | |
| } | |
| image = convert_document(bin_paths, text) | |
| gr.Success("Finished!", duration=2) | |
| pdf_file = gr.DownloadButton( | |
| label="Download document.pdf", | |
| value="./document.pdf", | |
| visible=True, | |
| ) | |
| return [image, pdf_file] | |
| demo = gr.Blocks( | |
| title=title, | |
| analytics_enabled=False, | |
| theme=gr.themes.Base(), | |
| ) | |
| with demo: | |
| gr.Markdown(description_head) | |
| gr.Markdown("## Usage") | |
| with gr.Row(): | |
| text = gr.Textbox(label="Text", autofocus=True, max_lines=50) | |
| with gr.Column(): | |
| pdf_file = gr.DownloadButton(label="Download PDF", visible=False) | |
| preview_image = gr.Image( | |
| label="Preview image", | |
| ) | |
| gr.Button("Generate").click( | |
| generate_pdf, | |
| concurrency_limit=concurrency_limit, | |
| inputs=text, | |
| outputs=[preview_image, pdf_file], | |
| ) | |
| with gr.Row(): | |
| gr.Examples(label="Choose an example", inputs=text, examples=examples) | |
| gr.Markdown("### Gradio app uses:") | |
| gr.Markdown(tech_env) | |
| gr.Markdown(r_tech_env) | |
| gr.Markdown(tech_libraries) | |
| if __name__ == "__main__": | |
| demo.queue() | |
| if do_share: | |
| demo.launch(share=True) | |
| else: | |
| demo.launch() | |