GENERATE PDF
The GENERATE PDF keyword creates PDF documents from HTML templates or Markdown content, enabling bots to produce professional reports, invoices, certificates, and other documents.
Note: This keyword uses spaces, not underscores. Write
GENERATE PDFnotGENERATE_PDF.
Syntax
result = GENERATE PDF template, data, "output.pdf"
Parameters
| Parameter | Type | Description |
|---|---|---|
template | String | Path to HTML template or Markdown file |
data | Object | Template variables to substitute |
output | String | Output path for the generated PDF |
Description
GENERATE PDF renders an HTML or Markdown template into a PDF document, substituting placeholders with provided values. The generated PDF is stored in the bot’s drive storage and can be downloaded, emailed, or processed further.
Use cases include:
- Generating invoices and receipts
- Creating reports and summaries
- Producing certificates and credentials
- Building contracts and agreements
- Creating personalized documents
Examples
Basic PDF Generation
' Generate PDF from template with data
data = #{
"title": "Invoice",
"date": FORMAT(NOW(), "MMMM DD, YYYY")
}
result = GENERATE PDF "templates/invoice.html", data, "invoices/inv-001.pdf"
TALK "Invoice generated!"
With Template Variables
' Generate PDF with data substitution
data = #{
"customer_name": customer.name,
"customer_email": customer.email,
"invoice_number": invoice_id,
"date": FORMAT(NOW(), "MMMM DD, YYYY"),
"items": order_items,
"subtotal": order_subtotal,
"tax": order_tax,
"total": order_total
}
result = GENERATE PDF "templates/invoice.html", data, "invoices/inv-" + invoice_id + ".pdf"
TALK "Invoice #" + invoice_id + " generated!"
Generate and Download
' Create PDF and send to user
data = #{
"title": "Monthly Report",
"period": FORMAT(NOW(), "MMMM YYYY"),
"data": report_data
}
result = GENERATE PDF "templates/report.html", data, "temp/report.pdf"
DOWNLOAD result.url AS "Monthly Report.pdf"
TALK "Here's your report!"
Generate and Email
' Create PDF and email it
data = #{
"party_a": company_name,
"party_b": customer_name,
"effective_date": FORMAT(NOW(), "MMMM DD, YYYY"),
"terms": contract_terms
}
result = GENERATE PDF "templates/contract.html", data, "contracts/" + contract_id + ".pdf"
SEND MAIL customer_email, "Your Contract",
"Please find attached your contract for review.",
[result.localName]
TALK "Contract sent to " + customer_email
Template Format
HTML Template
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
.header { text-align: center; margin-bottom: 20px; }
.invoice-number { color: #666; }
table { width: 100%; border-collapse: collapse; }
th, td { border: 1px solid #ddd; padding: 8px; }
.total { font-weight: bold; font-size: 1.2em; }
</style>
</head>
<body>
<div class="header">
<h1>INVOICE</h1>
<p class="invoice-number">{{invoice_number}}</p>
</div>
<p><strong>Date:</strong> {{date}}</p>
<p><strong>Customer:</strong> {{customer_name}}</p>
<table>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
</tr>
{{#each items}}
<tr>
<td>{{this.name}}</td>
<td>{{this.quantity}}</td>
<td>${{this.price}}</td>
</tr>
{{/each}}
</table>
<p class="total">Total: ${{total}}</p>
</body>
</html>
Markdown Template
# {{title}}
**Date:** {{date}}
**Prepared for:** {{customer_name}}
## Summary
{{summary}}
## Details
{{#each items}}
- **{{this.name}}:** {{this.description}}
{{/each}}
---
Generated by General Bots
Template Placeholders
| Syntax | Description |
|---|---|
{{variable}} | Simple variable substitution |
{{#each items}}...{{/each}} | Loop over array |
{{#if condition}}...{{/if}} | Conditional rendering |
{{#unless condition}}...{{/unless}} | Negative conditional |
{{this.property}} | Access property in loop |
Common Use Cases
Invoice Generation
' Generate a complete invoice
items = FIND "order_items" WHERE order_id = order.id
data = #{
"invoice_number": "INV-" + FORMAT(order.id, "00000"),
"date": FORMAT(NOW(), "MMMM DD, YYYY"),
"due_date": FORMAT(DATEADD(NOW(), 30, "day"), "MMMM DD, YYYY"),
"customer_name": customer.name,
"customer_address": customer.address,
"items": items,
"subtotal": FORMAT(order.subtotal, "#,##0.00"),
"tax": FORMAT(order.tax, "#,##0.00"),
"total": FORMAT(order.total, "#,##0.00")
}
result = GENERATE PDF "templates/invoice.html", data, "invoices/" + order.id + ".pdf"
TALK "Invoice generated: " + result.localName
Certificate Generation
' Generate completion certificate
data = #{
"recipient_name": user.name,
"course_name": course.title,
"completion_date": FORMAT(NOW(), "MMMM DD, YYYY"),
"certificate_id": GUID(),
"instructor_name": course.instructor
}
result = GENERATE PDF "templates/certificate.html", data, "certificates/" + user.id + "-" + course.id + ".pdf"
DOWNLOAD result.url AS "Certificate - " + course.title + ".pdf"
TALK "Congratulations! Here's your certificate!"
Report Generation
' Generate monthly sales report
sales_data = FIND "sales" WHERE
date >= DATEADD(NOW(), -30, "day")
summary = AGGREGATE sales_data SUM amount
count = AGGREGATE sales_data COUNT
data = #{
"title": "Monthly Sales Report",
"period": FORMAT(NOW(), "MMMM YYYY"),
"total_sales": FORMAT(summary, "$#,##0.00"),
"transaction_count": count,
"sales_data": sales_data,
"generated_at": FORMAT(NOW(), "YYYY-MM-DD HH:mm")
}
result = GENERATE PDF "templates/sales-report.html", data, "reports/sales-" + FORMAT(NOW(), "YYYYMM") + ".pdf"
TALK "Sales report generated!"
Contract Generation
' Generate service agreement
data = #{
"contract_number": contract_id,
"client_name": client.name,
"client_company": client.company,
"service_description": selected_service.description,
"monthly_fee": FORMAT(selected_service.price, "$#,##0.00"),
"start_date": FORMAT(start_date, "MMMM DD, YYYY"),
"term_months": contract_term,
"end_date": FORMAT(DATEADD(start_date, contract_term, "month"), "MMMM DD, YYYY")
}
result = GENERATE PDF "templates/service-agreement.html", data, "contracts/sa-" + contract_id + ".pdf"
TALK "Service agreement ready for signature!"
Return Value
Returns an object with generation details:
| Property | Description |
|---|---|
result.url | Full URL to the generated PDF (S3/MinIO path) |
result.localName | Local filename of the generated PDF |
Error Handling
ON ERROR RESUME NEXT
data = #{
"customer_name": customer_name,
"total": order_total
}
result = GENERATE PDF "templates/invoice.html", data, "invoices/test.pdf"
IF ERROR THEN
TALK "PDF generation failed: " + ERROR MESSAGE
IF INSTR(ERROR MESSAGE, "template") > 0 THEN
TALK "Template file not found."
ELSE IF INSTR(ERROR MESSAGE, "storage") > 0 THEN
TALK "Not enough storage space."
ELSE
TALK "Sorry, I couldn't generate the document. Please try again."
END IF
ELSE
TALK "PDF generated successfully!"
END IF
ON ERROR GOTO 0
Common Errors
| Error | Cause | Solution |
|---|---|---|
TEMPLATE_NOT_FOUND | Template file doesn’t exist | Verify template path |
INVALID_TEMPLATE | Template has syntax errors | Check template format |
MISSING_VARIABLE | Required placeholder not provided | Include all variables |
STORAGE_FULL | Insufficient space | Clean up storage |
RENDER_ERROR | HTML/CSS rendering issue | Simplify template |
Styling Tips
Supported CSS
- Basic typography (fonts, sizes, colors)
- Box model (margins, padding, borders)
- Tables and layouts
- Page breaks (
page-break-before,page-break-after) - Print media queries (
@media print)
Page Setup
<style>
@page {
size: A4;
margin: 2cm;
}
.page-break {
page-break-after: always;
}
@media print {
.no-print { display: none; }
}
</style>
Configuration
No specific configuration required. Uses bot’s standard drive settings from config.csv:
name,value
drive-provider,seaweedfs
drive-url,http://localhost:8333
drive-bucket,my-bot
Implementation Notes
- Implemented in Rust under
src/file/pdf.rs - Uses headless browser rendering for HTML
- Supports embedded images (base64 or relative paths)
- Handles Unicode and special characters
- Maximum PDF size: 50 MB
- Template caching for performance
Related Keywords
- MERGE PDF — Combine multiple PDFs
- FILL — Fill templates with data (alternative approach)
- READ — Read template content
- DOWNLOAD — Send PDF to user
- SEND MAIL — Email PDF as attachment
- WRITE — Create template dynamically
Summary
GENERATE PDF creates professional PDF documents from HTML or Markdown templates with variable substitution. Use it for invoices, reports, certificates, contracts, and any document that needs a polished format. Templates support loops, conditionals, and styling for flexible document generation. Combine with DOWNLOAD to deliver PDFs to users or SEND MAIL to email them as attachments.
Syntax reminder: Always use
GENERATE PDF(with space), notGENERATE_PDF.