Skip to main content

report-generation

Creating structured PDF reports from data, templates, and AI-generated content using professional toolchains

来源信息

仓库
cosmicstack-labs/mercury-agent-skills
最近来源活动
2026年5月12日 09:02
检测到的 SKILL.md 语言
英语
星标
476
分支
63

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
report-generation
description
Creating structured PDF reports from data, templates, and AI-generated content using professional toolchains
metadata
{"author":"cosmicstack-labs","version":"1.0.0","category":"pdf-generation","tags":["report-generation","pdf-report","data-to-pdf","templating","business-reports"]}
# Report Generation Create structured, data-driven PDF reports that communicate insights effectively. This skill covers the full pipeline — from data sources and templates to polished PDF output with charts, tables, and professional formatting. --- ## Report Structure Fundamentals A well-structured report follows a consistent pattern that guides the reader from context to conclusions. ### Standard Report Anatomy ```text ┌────────────────────────────────────────┐ │ Cover Page │ │ Title, subtitle, author, date, │ │ organization branding │ ├────────────────────────────────────────┤ │ Table of Contents │ │ Auto-generated from headings │ ├────────────────────────────────────────┤ │ Executive Summary │ │ Key findings in 1-2 paragraphs │ ├────────────────────────────────────────┤ │ Introduction / Background │ │ Context, objectives, scope │ ├────────────────────────────────────────┤ │ Methodology │ │ How data was collected/analyzed │ ├────────────────────────────────────────┤ │ Findings / Results │ │ Data presentation with charts/tables │ ├────────────────────────────────────────┤ │ Discussion │ │ Interpretation of results │ ├────────────────────────────────────────┤ │ Conclusions │ │ Summary of key takeaways │ ├────────────────────────────────────────┤ │ Recommendations │ │ Actionable next steps │ ├────────────────────────────────────────┤ │ Appendices │ │ Raw data, methodology details, refs │ └────────────────────────────────────────┘ ``` ### Report Metadata Standards ```python """Report metadata schema for consistent document properties.""" from dataclasses import dataclass, field from datetime import datetime from typing import Optional @dataclass class ReportMetadata: """Standard metadata for all generated reports.""" title: str subtitle: Optional[str] = None author: str = "Automated Report System" organization: str = "Cosmic Stack Labs" department: Optional[str] = None version: str = "1.0" report_date: str = field(default_factory=lambda: datetime.now().strftime("%Y-%m-%d")) period_start: Optional[str] = None period_end: Optional[str] = None classification: str = "Internal" document_id: Optional[str] = None keywords: list[str] = field(default_factory=list) def to_dict(self) -> dict: """Convert to dictionary for template rendering.""" return { 'title': self.title, 'subtitle': self.subtitle, 'author': self.author, 'organization': self.organization, 'department': self.department, 'version': self.version, 'report_date': self.report_date, 'period_start': self.period_start, 'period_end': self.period_end, 'classification': self.classification, 'document_id': self.document_id or f"RPT-{self.report_date}-{hash(self.title) % 10000:04d}", 'keywords': ', '.join(self.keywords) if self.keywords else '', } # Usage metadata = ReportMetadata( title="Q4 2024 Performance Analysis", subtitle="Infrastructure & Operations Review", author="Data Engineering Team", department="Engineering", version="2.1", period_start="2024-10-01", period_end="2024-12-31", classification="Confidential", keywords=["performance", "infrastructure", "q4-2024", "analytics"], ) ``` --- ## 2. Template Engines ### Jinja2 + WeasyPrint Pipeline This is the most flexible approach for branded, data-rich reports. #### Report Template (HTML) ```html <!-- templates/report.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>{{ metadata.title }}</title> <style> @page { size: A4; margin: 2.5cm 2cm 2.5cm 2cm; @top-center { content: "{{ metadata.organization }}"; font-size: 8pt; color: #666; font-family: 'Helvetica', sans-serif; } @bottom-center { content: "Page " counter(page) " of " counter(pages); font-size: 8pt; color: #666; font-family: 'Helvetica', sans-serif; } @bottom-left { content: "{{ metadata.classification }}"; font-size: 7pt; color: #999; font-style: italic; } } @page:first { @top-center { content: none; } @bottom-left { content: none; } } body { font-family: 'Helvetica', 'Arial', sans-serif; font-size: 10pt; line-height: 1.6; color: #333; } /* Cover page */ .cover-page { page-break-after: always; text-align: center; padding-top: 8cm; } .cover-page .org-name { font-size: 11pt; color: #666; letter-spacing: 2px; text-transform: uppercase; margin-bottom: 2cm; } .cover-page h1 { font-size: 28pt; color: #1a1a2e; margin-bottom: 0.5cm; border: none; } .cover-page .subtitle { font-size: 16pt; color: #555; margin-bottom: 1.5cm; } .cover-page .meta-info { font-size: 10pt; color: #777; line-height: 2; } /* Section headings */ h1 { font-size: 20pt; color: #1a1a2e; border-bottom: 2px solid #1a1a2e; padding-bottom: 6px; page-break-before: always; page-break-after: avoid; } h1:first-of-type { page-break-before: avoid; } h2 { font-size: 14pt; color: #2c3e50; margin-top: 1cm; page-break-after: avoid; } h3 { font-size: 12pt; color: #555; margin-top: 0.7cm; page-break-after: avoid; } /* Tables */ table { width: 100%; border-collapse: collapse; margin: 0.8em 0; font-size: 9pt; } thead { display: table-header-group; } tr { page-break-inside: avoid; } th { background: {{ accent_color }}; color: white; padding: 8px 10px; text-align: left; font-weight: bold; } td { padding: 6px 10px; border-bottom: 1px solid #e0e0e0; } tr:nth-child(even) td { background: #f8f9fa; } tr:hover td { background: #e8f4f8; } /* Executive summary box */ .executive-summary { background: #f0f4f8; border-left: 4px solid {{ accent_color }}; padding: 16px 20px; margin: 1em 0; font-size: 11pt; line-height: 1.7; } .executive-summary h2 { margin-top: 0; color: {{ accent_color }}; } /* Charts and images */ .chart-container { text-align: center; margin: 1em 0; page-break-inside: avoid; } .chart-container img { max-width: 100%; max-height: 12cm; } .chart-caption { font-size: 9pt; color: #666; font-style: italic; margin-top: 4px; } /* Callout boxes */ .callout { padding: 12px 16px; margin: 0.8em 0; border-radius: 4px; page-break-inside: avoid; } .callout-info { background: #e3f2fd; border-left: 4px solid #1565c0; } .callout-warning { background: #fff3e0; border-left: 4px solid #ef6c00; } .callout-success { background: #e8f5e9; border-left: 4px solid #2e7d32; } /* Page breaks */ .page-break { page-break-before: always; } </style> </head> <body> <div class="cover-page"> <div class="org-name">{{ metadata.organization }}</div> <h1>{{ metadata.title }}</h1> {% if metadata.subtitle %} <div class="subtitle">{{ metadata.subtitle }}</div> {% endif %} <div class="meta-info"> {% if metadata.department %}<p>{{ metadata.department }}</p>{% endif %} <p>Author: {{ metadata.author }}</p> <p>Date: {{ metadata.report_date }}</p> {% if metadata.period_start and metadata.period_end %} <p>Period: {{ metadata.period_start }} — {{ metadata.period_end }}</p> {% endif %} <p>Version: {{ metadata.version }}</p> <p>Document ID: {{ metadata.document_id }}</p> </div> </div> <!-- Auto-generated TOC placeholder --> <div class="toc"> <h1>Table of Contents</h1> <ul> {% for section in sections %} <li class="toc-{{ section.level }}"> <a href="#{{ section.anchor }}">{{ section.number }} {{ section.title }}</a> </li> {% endfor %} </ul> </div> {% for section in sections %} <div class="section"> <h{{ section.level }} id="{{ section.anchor }}"> {{ section.number }} {{ section.title }} </h{{ section.level }}> {% for paragraph in section.content %} {% if paragraph.type == 'text' %} <p>{{ paragraph.text }}</p> {% elif paragraph.type == 'table' %} <table> <thead> <tr> {% for header in paragraph.headers %} <th>{{ header }}</th> {% endfor %} </tr> </thead> <tbody> {% for row in paragraph.rows %} <tr> {% for cell in row %} <td>{{ cell }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> {% if paragraph.caption %} <div class="chart-caption">Table: {{ paragraph.caption }}</div> {% endif %} {% elif paragraph.type == 'chart' %} <div class="chart-container"> <img src="{{ paragraph.image_path }}" alt="{{ paragraph.caption }}"> {% if paragraph.caption %} <div class="chart-caption">Figure: {{ paragraph.caption }}</div> {% endif %} </div> {% elif paragraph.type == 'callout' %} <div class="callout callout-{{ paragraph.callout_type }}"> <strong>{{ paragraph.title }}</strong><br> {{ paragraph.text }} </div> {% elif paragraph.type == 'list' %} <ul> {% for item in paragraph.items %} <li>{{ item }}</li> {% endfor %} </ul> {% endif %} {% endfor %} </div> {% endfor %} </body> </html> ``` #### Python Report Generator ```python """Complete report generation system using Jinja2 and WeasyPrint.""" import json import os from pathlib import Path from datetime import datetime from typing import Optional import jinja2 import matplotlib.pyplot as plt import pandas as pd from weasyprint import HTML class ReportGenerator: """Generate professional PDF reports from data and templates.""" def __init__(self, template_dir: str = "templates", output_dir: str = "output"): self.template_dir = Path(template_dir) self.output_dir = Path(output_dir) self.output_dir.mkdir(parents=True, exist_ok=True) # Set up Jinja2 environment self.env = jinja2.Environment( loader=jinja2.FileSystemLoader(str(self.template_dir)), autoescape=False, ) def generate_chart(self, data: pd.DataFrame, chart_type: str, title: str, output_path: str) -> str: """Generate a matplotlib chart and save to file.""" fig, ax = plt.subplots(figsize=(8, 4.5)) if chart_type == 'bar':
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看