
Research Company
- 46 installs
- 61 repo stars
- Updated March 16, 2026
- kirkluokun/awesome-a-stock-openclawskills
Helps with ai & agent building tasks.
About
research-company is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- research-company
- AI & Agent Building
- AI-coding skill
Research Company by the numbers
- 46 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #7,568 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/kirkluokun/awesome-a-stock-openclawskills --skill research-companyAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 46 |
|---|---|
| repo stars | ★ 61 |
| Last updated | March 16, 2026 |
| Repository | kirkluokun/awesome-a-stock-openclawskills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Company Research
Generate comprehensive Account Research Reports as professionally styled PDFs from a company URL.
Workflow
1. Research the company (web fetch + searches) 2. Build JSON data structure 3. Generate PDF via scripts/generate_report.py 4. Deliver PDF to user
Phase 1: Research (Parallel)
Execute these searches concurrently to minimize context usage:
WebFetch: [company URL]
WebSearch: "[company name] funding news 2024"
WebSearch: "[company name] competitors market"
WebSearch: "[company name] CEO founder leadership"Extract from website: company name, industry, HQ, founded, leadership, products/services, pricing model, target customers, case studies, testimonials, recent news.
Phase 2: Build Data Structure
Create JSON matching this schema (see references/data-schema.md for full spec):
{
"company_name": "...",
"source_url": "...",
"report_date": "January 20, 2026",
"executive_summary": "3-5 sentences...",
"profile": { "name": "...", "industry": "...", ... },
"products": { "offerings": [...], "differentiators": [...] },
"target_market": { "segments": "...", "verticals": [...] },
"use_cases": [{ "title": "...", "description": "..." }],
"competitors": [{ "name": "...", "strengths": "...", "differentiation": "..." }],
"industry": { "trends": [...], "opportunities": [...], "challenges": [...] },
"developments": [{ "date": "...", "title": "...", "description": "..." }],
"lead_gen": { "keywords": {...}, "outreach_angles": [...] },
"info_gaps": ["..."]
}Phase 3: Generate PDF
# Install if needed
pip install reportlab
# Save JSON to temp file
cat > /tmp/research_data.json << 'EOF'
{...your JSON data...}
EOF
# Generate PDF
python3 scripts/generate_report.py /tmp/research_data.json /path/to/output/report.pdfPhase 4: Deliver
Save PDF to workspace folder and provide download link:
[Download Company Research Report](computer:///sessions/.../report.pdf)Quality Standards
- Accuracy: Base claims on observable evidence; cite sources
- Specificity: Include product names, metrics, customer examples
- Completeness: Note gaps as "Not publicly available"
- No fabrication: Never invent information
Resources
scripts/generate_report.py- PDF generator (uses reportlab)references/data-schema.md- Full JSON schema with examples
{
"owner": "tomstools11",
"slug": "research-company",
"displayName": "Research Company",
"latest": {
"version": "1.0.0",
"publishedAt": 1769361755518,
"commit": "https://github.com/clawdbot/skills/commit/96360ab73785e7f893202475fa5d6facb79bf7c9"
},
"history": [
{
"version": "0.1.0",
"publishedAt": 1769360269379,
"commit": "https://github.com/clawdbot/skills/commit/95a6a373447cedfb53b99c91947d8bc1441f82b3"
}
]
}
{
"company_name": "阿里巴巴集团 (Alibaba Group)",
"source_url": "https://www.alibaba.com",
"report_date": "March 9, 2026",
"executive_summary": "阿里巴巴集团是中国领先的电商与科技集团,旗下 Alibaba.com 为全球最大 B2B 跨境电商平台之一,连接制造商、供应商与全球买家。集团业务涵盖淘天(国内电商)、阿里云、国际数字商业(速卖通、Lazada、Trendyol 等)、菜鸟、本地生活与数字娱乐。2024 财年收入约 9,412 亿元、同比增 8%;国际电商收入同比增 45%。CEO 吴泳铭,董事长蔡崇信;面临京东、拼多多、亚马逊及 Temu/Shein 等竞争。",
"profile": {
"name": "阿里巴巴集团 (Alibaba Group)",
"industry": "电商 / 云计算 / 数字商业",
"headquarters": "中国杭州",
"founded": "1999",
"ceo": "吴泳铭 (Eddie Wu),CEO 兼淘天集团、云智能集团董事长(2023年9月上任)",
"size": "约 20 万+ 员工(集团层面);Alibaba.com 年活买家约 1.3 亿",
"website": "https://www.alibaba.com",
"funding": "2024年11月双币种债券融资 50 亿美元;2024年5月 50 亿美元可转债;2024年领投 Moonshot AI、MiniMax 等 AI 融资"
},
"products": {
"offerings": [
{
"name": "Alibaba.com B2B 平台",
"description": "全球 B2B 在线批发市场,覆盖 34K+ 定制工厂,品类含消费电子、服装、家居、工业机械、汽配、新能源等;支持小额批发、定制加工、图片搜货、本地仓与 Alibaba Guaranteed 保障"
},
{
"name": "淘天(淘宝/天猫)",
"description": "国内零售电商与品牌旗舰店,88VIP 会员超 3,500 万,客户管理收入与 GMV 双位数增长"
},
{
"name": "阿里云(云智能集团)",
"description": "公共云与 AI 服务,通义千问大模型;核心云产品与 AI 相关收入双位数/三位数同比增长"
},
{
"name": "国际数字商业(AIDC)",
"description": "速卖通 Choice、Lazada、Trendyol 等;跨境 5 日/10 日妥投率同比翻倍,Trendyol 在海湾地区为下载量领先电商应用之一"
},
{
"name": "菜鸟",
"description": "智慧物流与跨境物流网络,支撑集团电商履约"
}
],
"differentiators": [
"全球最大 B2B 跨境电商平台之一,供应商与品类覆盖广",
"一站式从寻源、定制到履约的 B2B 能力",
"阿里云与通义大模型支撑集团 AI 与数字化",
"国际电商多区域布局(东南亚、中东、欧洲等)与强劲增速"
],
"tech_stack": {
"Core": "电商中台、推荐与搜索",
"Cloud": "阿里云、多可用区",
"AI/ML": "通义千问、AI 驱动选品与运营"
}
},
"target_market": {
"segments": "B2B 买家(批发商、零售商、制造商、品牌方)、跨境电商卖家;国内消费者(淘天);企业客户(阿里云);海外消费者(速卖通、Lazada、Trendyol)",
"verticals": ["消费电子", "服装与配饰", "家居与园艺", "工业机械", "汽配", "新能源", "农业食品", "美妆", "包装印刷", "医疗器械"],
"personas": [
{
"title": "跨境采购 / 采购经理",
"description": "需要稳定供应商、小单起订、定制加工与合规保障,关注 Alibaba Guaranteed 与物流时效"
},
{
"title": "品牌与零售商",
"description": "寻源新品、ODM/OEM、本地仓与快速补货,关注数据选品与趋势排行"
},
{
"title": "企业 IT / 技术决策者",
"description": "需要云与 AI 能力,关注通义与云产品合规与成本"
}
],
"business_model": "B2B 平台:会员费、营销与增值服务、交易佣金;国内电商:客户管理收入、佣金;云:订阅与按量计费;国际电商:平台佣金与广告"
},
"use_cases": [
{
"title": "跨境批发与定制",
"description": "买家通过 Alibaba.com 对接工厂,完成小单定制、Logo/图案打样与批量采购,配合 Alibaba Guaranteed 与物流保障降低风险"
},
{
"title": "多区域零售电商",
"description": "速卖通 Choice、Lazada、Trendyol 为当地消费者提供跨境与本地商品,5/10 日达与高妥投率支撑体验"
},
{
"title": "企业上云与 AI",
"description": "企业采用阿里云与通义千问进行基础设施与智能化升级,云与 AI 收入快速增长"
}
],
"competitors": [
{
"name": "京东 (JD.com)",
"strengths": "自建物流、正品与时效在国内领先",
"differentiation": "阿里以平台生态与多业务协同见长;京东偏重自营与物流"
},
{
"name": "拼多多 / Temu",
"strengths": "社交与低价、农业与下沉市场;Temu 全球下载领先",
"differentiation": "阿里覆盖 B2B、国内零售与多区域国际电商,拼多多/Temu 更偏 C 端与极致低价"
},
{
"name": "亚马逊 (Amazon)",
"strengths": "全球电商与云龙头,北美/欧洲/日本份额高",
"differentiation": "阿里在中国与亚洲及 B2B 市场深耕,亚马逊在欧美 C 端与 3P 卖家生态更强"
},
{
"name": "Shein",
"strengths": "快时尚与算法供应链、年轻用户",
"differentiation": "阿里为综合电商与 B2B;Shein 聚焦服装与 DTC"
}
],
"competitive_positioning": "在中国与亚洲具备电商、云与国际化综合优势;B2B 端 Alibaba.com 为全球主要采购平台;国内面临拼多多与京东分流,国际面临 Temu/Shein 与亚马逊竞争;通过组织重组(如电商业务整合、蒋凡统管电商)与 AI 投入强化增长与效率。",
"industry": {
"trends": [
"跨境电商与全托管/半托管模式普及",
"AI 驱动选品、运营与客服",
"供应链近岸与多区域布局",
"监管与平台责任加强"
],
"opportunities": [
"国际电商高增速与新兴市场(如海湾)拓展",
"云与 AI 产品商业化与政企市场",
"B2B 与跨境物流体验持续提升"
],
"challenges": [
"国内消费与竞争压力;市值较峰值回落",
"反垄断与合规要求",
"Temu/Shein 等对份额与利润的挤压"
]
},
"developments": [
{
"date": "2024年11月",
"title": "50 亿美元双币种债券",
"description": "亚洲太平洋地区当年最大企业债券之一,用于一般企业用途、偿债与股份回购"
},
{
"date": "2024年11月",
"title": "蒋凡出任电商业务集团负责人",
"description": "统管淘天、国际数字商业等电商业务,直接向 CEO 吴泳铭汇报,强化电商协同"
},
{
"date": "2024年5月",
"title": "50 亿美元可转债发行",
"description": "0.50% 可转换优先票据 2031 年到期,补充资本"
},
{
"date": "2024年2–3月",
"title": "领投 AI 公司",
"description": "领投 Moonshot AI(约 10 亿美元,估值约 25 亿美元)、MiniMax 约 6 亿美元融资,加码生成式 AI"
},
{
"date": "2024财年 Q4",
"title": "淘天 GMV 与国际电商双位数/45% 增长",
"description": "淘天 GMV 与订单双位数增长;AIDC 收入同比增 45%,速卖通 Choice 占单量约 70%"
}
],
"lead_gen": {
"keywords": {
"primary": ["B2B 采购", "跨境电商", "批发平台", "供应商", "Alibaba.com"],
"vertical": ["消费电子批发", "服装 OEM", "工业机械", "新能源供应链"],
"technology": ["通义千问", "阿里云", "电商中台", "跨境物流"],
"pain_point": ["寻源效率", "小单定制", "跨境合规", "供应链稳定"]
},
"outreach_angles": [
{
"title": "B2B 一站式寻源与履约",
"description": "强调 Alibaba.com 工厂覆盖、定制能力与 Alibaba Guaranteed、菜鸟跨境时效"
},
{
"title": "多区域电商与云+AI",
"description": "国际电商高增长与多区域布局;云与通义在企业数字化与 AI 场景的应用"
}
],
"partnership_targets": [
{
"name": "跨境物流与支付伙伴",
"rationale": "提升妥投率与本地化支付,增强买家体验"
},
{
"name": "品牌与制造商",
"rationale": "扩大优质供给与品牌旗舰,提升平台 GMV 与客单价"
}
]
},
"info_gaps": [
"Alibaba.com 单独营收与利润未公开",
"各国家/地区买家占比未披露",
"部分业务线具体 MAU/DAU 未在公开财报细分"
]
}
Report Data Schema
Complete JSON schema for the PDF generator. Only read this file if you need schema details.
Full Schema
{
"company_name": "string (required)",
"source_url": "string (required)",
"report_date": "string, e.g., 'January 20, 2026'",
"executive_summary": "string, 3-5 sentences covering what the company does, who they serve, market position",
"profile": {
"name": "string",
"industry": "string, e.g., 'AI/ML Platform', 'FinTech'",
"headquarters": "string, e.g., 'San Francisco, CA'",
"founded": "string, e.g., '2019'",
"ceo": "string, name and title",
"size": "string, e.g., '50-200 employees'",
"website": "string, URL",
"funding": "string, e.g., '$50M Series B (2024)'"
},
"products": {
"offerings": [
{
"name": "string, product name",
"description": "string, what it does and value"
}
],
"differentiators": ["string array of unique selling points"],
"tech_stack": {
"Core": "string",
"Cloud": "string",
"AI/ML": "string"
}
},
"target_market": {
"segments": "string, description of primary customer segments",
"verticals": ["string array of industries served"],
"personas": [
{
"title": "string, e.g., 'VP of Engineering'",
"description": "string, their needs and why they buy"
}
],
"business_model": "string, how they make money"
},
"use_cases": [
{
"title": "string, use case name",
"description": "string, problem solved and outcomes"
}
],
"competitors": [
{
"name": "string",
"strengths": "string",
"differentiation": "string, how target company is different"
}
],
"competitive_positioning": "string, summary of market position",
"industry": {
"trends": ["string array of market trends"],
"opportunities": ["string array of growth opportunities"],
"challenges": ["string array of industry challenges"]
},
"developments": [
{
"date": "string, e.g., 'Dec 2024'",
"title": "string, headline",
"description": "string, details and significance"
}
],
"lead_gen": {
"keywords": {
"primary": ["string array, service keywords"],
"vertical": ["string array, industry keywords"],
"technology": ["string array, tech keywords"],
"pain_point": ["string array, problem keywords"]
},
"outreach_angles": [
{
"title": "string, angle name",
"description": "string, talking points"
}
],
"partnership_targets": [
{
"name": "string, partner type or name",
"rationale": "string, why this partnership"
}
]
},
"info_gaps": ["string array of unavailable information"]
}Example
{
"company_name": "Acme AI",
"source_url": "https://acme.ai",
"report_date": "January 20, 2026",
"executive_summary": "Acme AI provides enterprise MLOps solutions that simplify model deployment and monitoring. They serve mid-market and enterprise companies in financial services and healthcare, with a strong focus on compliance and security. Founded in 2020, they've raised $75M and compete primarily with DataRobot and MLflow.",
"profile": {
"name": "Acme AI",
"industry": "AI/ML Platform",
"headquarters": "San Francisco, CA",
"founded": "2020",
"ceo": "Jane Smith, CEO & Co-founder",
"size": "100-250 employees",
"website": "https://acme.ai",
"funding": "$75M Series B (Oct 2024)"
},
"products": {
"offerings": [
{
"name": "Acme Deploy",
"description": "One-click model deployment with automatic scaling and A/B testing"
},
{
"name": "Acme Monitor",
"description": "Real-time model performance tracking with drift detection"
}
],
"differentiators": [
"HIPAA and SOC2 compliant out of the box",
"50% faster deployment than competitors",
"No-code interface for business users"
],
"tech_stack": {
"Core": "Python, Kubernetes",
"Cloud": "AWS, GCP, Azure",
"AI/ML": "PyTorch, TensorFlow, scikit-learn"
}
},
"target_market": {
"segments": "Mid-market and enterprise companies with existing data science teams looking to operationalize ML models",
"verticals": ["Financial Services", "Healthcare", "Insurance", "Retail"],
"personas": [
{
"title": "VP of Data Science",
"description": "Needs to scale ML operations and demonstrate ROI to leadership"
},
{
"title": "ML Engineer",
"description": "Wants to reduce deployment friction and focus on model development"
}
],
"business_model": "SaaS subscription based on model deployments and API calls. Enterprise contracts start at $100K/year."
},
"use_cases": [
{
"title": "Fraud Detection at Scale",
"description": "Financial services companies use Acme to deploy real-time fraud models, reducing false positives by 40% while maintaining sub-100ms latency."
},
{
"title": "Healthcare Risk Stratification",
"description": "Health insurers deploy patient risk models with full HIPAA compliance, enabling proactive care management."
}
],
"competitors": [
{
"name": "DataRobot",
"strengths": "End-to-end AutoML, large customer base",
"differentiation": "Acme is 50% cheaper and more flexible for custom models"
},
{
"name": "MLflow",
"strengths": "Open source, developer-friendly",
"differentiation": "Acme provides enterprise support and compliance features"
}
],
"competitive_positioning": "Positioned as the enterprise-ready alternative to open source MLOps, with a focus on regulated industries.",
"industry": {
"trends": [
"Increasing ML model complexity requires better tooling",
"Regulatory pressure driving demand for model explainability"
],
"opportunities": [
"Expansion into European market with GDPR compliance",
"Generative AI deployment tools"
],
"challenges": [
"Competition from cloud provider native tools",
"Economic uncertainty affecting enterprise budgets"
]
},
"developments": [
{
"date": "Oct 2024",
"title": "$75M Series B Funding",
"description": "Led by Sequoia Capital to accelerate product development and international expansion"
},
{
"date": "Aug 2024",
"title": "Partnership with AWS",
"description": "Available on AWS Marketplace, enabling faster enterprise procurement"
}
],
"lead_gen": {
"keywords": {
"primary": ["MLOps platform", "model deployment", "ML monitoring"],
"vertical": ["healthcare AI compliance", "financial services ML"],
"technology": ["Kubernetes ML", "PyTorch deployment"],
"pain_point": ["ML model deployment challenges", "AI governance"]
},
"outreach_angles": [
{
"title": "Compliance-First Approach",
"description": "Lead with HIPAA/SOC2 compliance for regulated industries"
},
{
"title": "Cost Reduction",
"description": "Highlight 50% cost savings vs DataRobot with comparable features"
}
],
"partnership_targets": [
{
"name": "Consulting Firms",
"rationale": "Deloitte, Accenture have large AI practices needing deployment tools"
}
]
},
"info_gaps": [
"Exact customer count",
"Revenue figures",
"Employee breakdown by department"
]
}#!/usr/bin/env python3
"""
Company Research Report PDF Generator
Generates professionally styled PDF reports from research data.
Uses reportlab for high-quality PDF output with proper typography and layout.
Usage:
python generate_report.py input.json output.pdf
Input JSON structure: See references/data-schema.md
"""
import json
import sys
from datetime import datetime
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
KeepTogether, HRFlowable, CondPageBreak
)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# macOS 中文字体:优先 Arial Unicode,其次 STHeiti(黑体-简),避免中文显示为方块
def _register_cjk_font():
"""注册支持中文的字体,返回 (normal_name, bold_name)。"""
import os
import platform
candidates = []
if platform.system() == 'Darwin':
candidates = [
('HeitiSC', '/System/Library/Fonts/STHeiti Medium.ttc', 0),
('ArialUnicodeMS', '/System/Library/Fonts/Supplemental/Arial Unicode.ttf', None),
('SongtiSC', '/System/Library/Fonts/Supplemental/Songti.ttc', 0),
('PingFang', '/System/Library/Fonts/PingFang.ttc', 0),
]
# 用户目录下的中文字体作为备选
user_font = os.path.expanduser('~/Library/Fonts/FZLTHJW.TTF')
if os.path.isfile(user_font):
candidates.append(('FZLanTingHei', user_font, None))
for name, path, sub in candidates:
try:
if os.path.isfile(path):
if sub is not None:
f = TTFont(name, path, subfontIndex=sub)
else:
f = TTFont(name, path)
pdfmetrics.registerFont(f)
return (name, name)
except Exception:
continue
return ('Helvetica', 'Helvetica-Bold')
_CJK_FONT, _CJK_FONT_BOLD = _register_cjk_font()
def _escape_for_paragraph(s):
"""Paragraph 内需转义 & < >,避免被当作标签解析。"""
if s is None:
return ''
s = str(s)
return s.replace('&', '&').replace('<', '<').replace('>', '>')
# Color palette (professional slate-based)
COLORS = {
'primary': colors.HexColor('#1e293b'), # Dark slate
'secondary': colors.HexColor('#334155'), # Medium slate
'muted': colors.HexColor('#64748b'), # Light slate
'accent_blue': colors.HexColor('#3b82f6'),
'accent_emerald': colors.HexColor('#10b981'),
'accent_violet': colors.HexColor('#8b5cf6'),
'accent_amber': colors.HexColor('#f59e0b'),
'accent_teal': colors.HexColor('#14b8a6'),
'accent_indigo': colors.HexColor('#6366f1'),
'accent_rose': colors.HexColor('#f43f5e'),
'bg_light': colors.HexColor('#f8fafc'),
'border': colors.HexColor('#e2e8f0'),
'white': colors.white,
}
def create_styles():
"""Create custom paragraph styles for the report."""
styles = getSampleStyleSheet()
styles['Normal'].fontName = _CJK_FONT
# Title style (for header)
styles.add(ParagraphStyle(
'ReportTitle',
parent=styles['Heading1'],
fontSize=24,
textColor=COLORS['white'],
spaceAfter=6,
fontName=_CJK_FONT_BOLD
))
# Section heading
styles.add(ParagraphStyle(
'SectionHeading',
parent=styles['Heading2'],
fontSize=14,
textColor=COLORS['primary'],
spaceBefore=16,
spaceAfter=8,
borderPadding=(0, 0, 4, 0),
fontName=_CJK_FONT_BOLD
))
# Subsection heading
styles.add(ParagraphStyle(
'SubHeading',
parent=styles['Heading3'],
fontSize=11,
textColor=COLORS['secondary'],
spaceBefore=12,
spaceAfter=6,
fontName=_CJK_FONT_BOLD
))
# Body text (custom)
styles.add(ParagraphStyle(
'ReportBody',
parent=styles['Normal'],
fontSize=10,
textColor=COLORS['secondary'],
spaceAfter=8,
leading=14,
alignment=TA_JUSTIFY
))
# Muted text (for metadata, footer)
styles.add(ParagraphStyle(
'MutedText',
parent=styles['Normal'],
fontSize=9,
textColor=COLORS['muted'],
spaceAfter=4
))
# Tag/pill style text
styles.add(ParagraphStyle(
'TagText',
parent=styles['Normal'],
fontSize=9,
textColor=COLORS['secondary'],
))
# Item title (for bordered items)
styles.add(ParagraphStyle(
'ItemTitle',
parent=styles['Normal'],
fontSize=10,
textColor=COLORS['primary'],
fontName=_CJK_FONT_BOLD,
spaceAfter=2
))
# Item description
styles.add(ParagraphStyle(
'ItemDesc',
parent=styles['Normal'],
fontSize=9,
textColor=COLORS['secondary'],
leading=12
))
return styles
def create_header_table(data, styles):
"""Create the dark header section."""
company = data.get('company_name', 'Unknown Company')
date = data.get('report_date', datetime.now().strftime('%B %d, %Y'))
url = data.get('source_url', '')
header_content = [
[Paragraph('<font color="white" size="9">ACCOUNT RESEARCH REPORT</font>', styles['Normal'])],
[Paragraph(f'<font color="white" size="20"><b>{company}</b></font>', styles['Normal'])],
[Spacer(1, 8)],
[Paragraph(f'<font color="#94a3b8" size="9"><b>Date:</b> {date} | <b>Source:</b> {url} | <b>Analyst:</b> openclaw</font>', styles['Normal'])]
]
header_table = Table(header_content, colWidths=[7*inch])
header_table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, -1), COLORS['primary']),
('LEFTPADDING', (0, 0), (-1, -1), 24),
('RIGHTPADDING', (0, 0), (-1, -1), 24),
('TOPPADDING', (0, 0), (0, 0), 20),
('BOTTOMPADDING', (0, -1), (-1, -1), 20),
]))
return header_table
def create_section_heading(title, styles):
"""Create a section heading with bottom border."""
elements = []
elements.append(Paragraph(title, styles['SectionHeading']))
elements.append(HRFlowable(width="100%", thickness=2, color=COLORS['border'], spaceAfter=8))
return elements
def create_profile_table(profile_data, styles):
"""Create the company profile table;单元格用 Paragraph 渲染以正确显示中文。"""
label_style = ParagraphStyle(
'ProfileLabel',
parent=styles['Normal'],
fontSize=9,
textColor=COLORS['secondary'],
fontName=_CJK_FONT_BOLD,
)
value_style = ParagraphStyle(
'ProfileValue',
parent=styles['Normal'],
fontSize=9,
textColor=COLORS['secondary'],
fontName=_CJK_FONT,
leading=12,
)
rows = []
fields = [
('Company Name', 'name'),
('Industry', 'industry'),
('Headquarters', 'headquarters'),
('Founded', 'founded'),
('CEO/Founder', 'ceo'),
('Company Size', 'size'),
('Website', 'website'),
('Recent Funding', 'funding'),
]
for label, key in fields:
value = profile_data.get(key, '')
if value:
rows.append([
Paragraph(_escape_for_paragraph(label), label_style),
Paragraph(_escape_for_paragraph(value), value_style),
])
if not rows:
return None
table = Table(rows, colWidths=[1.8*inch, 5.2*inch])
table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (0, -1), COLORS['bg_light']),
('TEXTCOLOR', (0, 0), (0, -1), COLORS['secondary']),
('TEXTCOLOR', (1, 0), (1, -1), COLORS['secondary']),
('FONTSIZE', (0, 0), (-1, -1), 9),
('PADDING', (0, 0), (-1, -1), 8),
('GRID', (0, 0), (-1, -1), 0.5, COLORS['border']),
('VALIGN', (0, 0), (-1, -1), 'TOP'),
('ROWBACKGROUNDS', (0, 0), (-1, -1), [COLORS['bg_light'], COLORS['white']]),
]))
return table
def create_bordered_item(title, description, accent_color, styles):
"""Create a left-bordered item block."""
content = []
if title:
content.append([Paragraph(f'<b>{title}</b>', styles['ItemTitle'])])
if description:
content.append([Paragraph(description, styles['ItemDesc'])])
if not content:
return None
inner_table = Table(content, colWidths=[6.6*inch])
inner_table.setStyle(TableStyle([
('LEFTPADDING', (0, 0), (-1, -1), 8),
('RIGHTPADDING', (0, 0), (-1, -1), 4),
('TOPPADDING', (0, 0), (-1, -1), 4),
('BOTTOMPADDING', (0, 0), (-1, -1), 4),
]))
outer_table = Table([[inner_table]], colWidths=[7*inch])
outer_table.setStyle(TableStyle([
('LINEAFTER', (0, 0), (0, -1), 0, COLORS['white']),
('LINEBEFORE', (0, 0), (0, -1), 4, accent_color),
('BACKGROUND', (0, 0), (-1, -1), colors.HexColor('#fafafa')),
('TOPPADDING', (0, 0), (-1, -1), 0),
('BOTTOMPADDING', (0, 0), (-1, -1), 0),
('LEFTPADDING', (0, 0), (-1, -1), 0),
]))
return outer_table
def create_competitor_table(competitors, styles):
"""Create the competitor comparison table with proper text wrapping."""
if not competitors:
return None
# Create cell style for wrapping text
cell_style = ParagraphStyle(
'TableCell',
parent=styles['Normal'],
fontSize=9,
textColor=COLORS['secondary'],
leading=12,
fontName=_CJK_FONT
)
cell_style_bold = ParagraphStyle(
'TableCellBold',
parent=cell_style,
fontName=_CJK_FONT_BOLD
)
header_style = ParagraphStyle(
'TableHeader',
parent=cell_style,
fontName=_CJK_FONT_BOLD,
textColor=COLORS['secondary']
)
# Create header row with Paragraphs
header = [
Paragraph('Competitor', header_style),
Paragraph('Key Strengths', header_style),
Paragraph('Differentiation', header_style)
]
rows = [header]
# Create data rows with Paragraphs for text wrapping
for comp in competitors:
rows.append([
Paragraph(comp.get('name', ''), cell_style_bold),
Paragraph(comp.get('strengths', ''), cell_style),
Paragraph(comp.get('differentiation', ''), cell_style)
])
table = Table(rows, colWidths=[1.6*inch, 2.7*inch, 2.7*inch])
table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), COLORS['bg_light']),
('PADDING', (0, 0), (-1, -1), 8),
('GRID', (0, 0), (-1, -1), 0.5, COLORS['border']),
('VALIGN', (0, 0), (-1, -1), 'TOP'),
]))
return table
def create_tags(keywords, color_map, styles):
"""Create keyword tags as a wrapped paragraph."""
if not keywords:
return None
tags_text = ' '.join([f'<font color="{color_map.get(kw, "#334155")}" size="9">[{kw}]</font>' for kw in keywords])
return Paragraph(tags_text, styles['TagText'])
def create_bullet_list(items, bullet_color, styles):
"""Create a simple bullet list."""
if not items:
return None
elements = []
for item in items:
bullet_html = f'<font color="{bullet_color}">•</font> {item}'
elements.append(Paragraph(bullet_html, styles['ReportBody']))
return elements
def generate_pdf(data, output_path):
"""Generate the complete PDF report."""
styles = create_styles()
doc = SimpleDocTemplate(
output_path,
pagesize=letter,
rightMargin=0.5*inch,
leftMargin=0.5*inch,
topMargin=0.5*inch,
bottomMargin=0.5*inch
)
story = []
# Header
story.append(create_header_table(data, styles))
story.append(Spacer(1, 16))
# Executive Summary
if data.get('executive_summary'):
story.extend(create_section_heading('Executive Summary', styles))
story.append(Paragraph(data['executive_summary'], styles['ReportBody']))
story.append(Spacer(1, 8))
# Company Profile
if data.get('profile'):
story.extend(create_section_heading('Company Profile', styles))
profile_table = create_profile_table(data['profile'], styles)
if profile_table:
story.append(KeepTogether([profile_table]))
story.append(Spacer(1, 8))
# Products & Services
if data.get('products'):
story.extend(create_section_heading('Products & Services', styles))
if data['products'].get('offerings'):
story.append(Paragraph('<b>Core Offerings</b>', styles['SubHeading']))
for item in data['products']['offerings']:
block = create_bordered_item(item.get('name'), item.get('description'), COLORS['accent_blue'], styles)
if block:
story.append(KeepTogether([block, Spacer(1, 6)]))
if data['products'].get('differentiators'):
story.append(Paragraph('<b>Key Differentiators</b>', styles['SubHeading']))
for diff in data['products']['differentiators']:
block = create_bordered_item(diff, None, COLORS['accent_emerald'], styles)
if block:
story.append(block)
story.append(Spacer(1, 4))
if data['products'].get('tech_stack'):
story.append(Paragraph('<b>Technology Stack</b>', styles['SubHeading']))
tech_text = ' | '.join([f'<b>{k}:</b> {v}' for k, v in data['products']['tech_stack'].items()])
story.append(Paragraph(tech_text, styles['MutedText']))
story.append(Spacer(1, 8))
# Target Market
if data.get('target_market'):
story.extend(create_section_heading('Target Market', styles))
if data['target_market'].get('segments'):
story.append(Paragraph(data['target_market']['segments'], styles['ReportBody']))
if data['target_market'].get('verticals'):
story.append(Paragraph('<b>Industry Verticals</b>', styles['SubHeading']))
verticals_text = ' '.join([f'[{v}]' for v in data['target_market']['verticals']])
story.append(Paragraph(verticals_text, styles['MutedText']))
if data['target_market'].get('personas'):
story.append(Paragraph('<b>Buyer Personas</b>', styles['SubHeading']))
for persona in data['target_market']['personas']:
block = create_bordered_item(persona.get('title'), persona.get('description'), COLORS['accent_violet'], styles)
if block:
story.append(block)
story.append(Spacer(1, 4))
if data['target_market'].get('business_model'):
story.append(Paragraph('<b>Business Model</b>', styles['SubHeading']))
story.append(Paragraph(data['target_market']['business_model'], styles['ReportBody']))
story.append(Spacer(1, 8))
# Use Cases & Pain Points (conditional page break only if needed)
if data.get('use_cases'):
# Use CondPageBreak to only break if less than 2 inches remain
story.append(CondPageBreak(2*inch))
story.extend(create_section_heading('Use Cases & Pain Points', styles))
for uc in data['use_cases']:
block = create_bordered_item(uc.get('title'), uc.get('description'), COLORS['accent_amber'], styles)
if block:
story.append(KeepTogether([block, Spacer(1, 6)]))
story.append(Spacer(1, 8))
# Competitive Landscape
if data.get('competitors'):
story.extend(create_section_heading('Competitive Landscape', styles))
comp_table = create_competitor_table(data['competitors'], styles)
if comp_table:
story.append(KeepTogether([comp_table]))
if data.get('competitive_positioning'):
story.append(Spacer(1, 8))
story.append(Paragraph('<b>Competitive Positioning</b>', styles['SubHeading']))
story.append(Paragraph(data['competitive_positioning'], styles['ReportBody']))
story.append(Spacer(1, 8))
# Industry Dynamics
if data.get('industry'):
story.extend(create_section_heading('Industry Dynamics', styles))
if data['industry'].get('trends'):
story.append(Paragraph('<b>Market Trends</b>', styles['SubHeading']))
for trend in data['industry']['trends']:
story.append(Paragraph(f'<font color="#3b82f6">•</font> {trend}', styles['ReportBody']))
if data['industry'].get('opportunities'):
story.append(Paragraph('<b>Growth Opportunities</b>', styles['SubHeading']))
for opp in data['industry']['opportunities']:
story.append(Paragraph(f'<font color="#10b981">•</font> {opp}', styles['ReportBody']))
if data['industry'].get('challenges'):
story.append(Paragraph('<b>Challenges</b>', styles['SubHeading']))
for ch in data['industry']['challenges']:
story.append(Paragraph(f'<font color="#f59e0b">•</font> {ch}', styles['ReportBody']))
story.append(Spacer(1, 8))
# Recent Developments
if data.get('developments'):
story.extend(create_section_heading('Recent Developments', styles))
for dev in data['developments']:
date_str = dev.get('date', '')
title = dev.get('title', '')
desc = dev.get('description', '')
block = create_bordered_item(f'<font color="#14b8a6">{date_str}</font> — {title}', desc, COLORS['accent_teal'], styles)
if block:
story.append(KeepTogether([block, Spacer(1, 6)]))
story.append(Spacer(1, 8))
# Lead Generation Intelligence (conditional page break only if needed)
if data.get('lead_gen'):
# Use CondPageBreak to only break if less than 2 inches remain
story.append(CondPageBreak(2*inch))
story.extend(create_section_heading('Lead Generation Intelligence', styles))
kw = data['lead_gen'].get('keywords', {})
if kw.get('primary'):
story.append(Paragraph('<b>Primary Service Keywords</b>', styles['SubHeading']))
story.append(Paragraph(' '.join([f'<font color="#3b82f6">[{k}]</font>' for k in kw['primary']]), styles['TagText']))
if kw.get('vertical'):
story.append(Paragraph('<b>Vertical Keywords</b>', styles['SubHeading']))
story.append(Paragraph(' '.join([f'<font color="#10b981">[{k}]</font>' for k in kw['vertical']]), styles['TagText']))
if kw.get('technology'):
story.append(Paragraph('<b>Technology Keywords</b>', styles['SubHeading']))
story.append(Paragraph(' '.join([f'<font color="#8b5cf6">[{k}]</font>' for k in kw['technology']]), styles['TagText']))
if kw.get('pain_point'):
story.append(Paragraph('<b>Pain Point Keywords</b>', styles['SubHeading']))
story.append(Paragraph(' '.join([f'<font color="#f59e0b">[{k}]</font>' for k in kw['pain_point']]), styles['TagText']))
if data['lead_gen'].get('outreach_angles'):
story.append(Spacer(1, 8))
story.append(Paragraph('<b>Outreach Angles</b>', styles['SubHeading']))
for angle in data['lead_gen']['outreach_angles']:
block = create_bordered_item(angle.get('title'), angle.get('description'), COLORS['accent_indigo'], styles)
if block:
story.append(block)
story.append(Spacer(1, 4))
if data['lead_gen'].get('partnership_targets'):
story.append(Spacer(1, 8))
story.append(Paragraph('<b>Partnership Targets</b>', styles['SubHeading']))
for partner in data['lead_gen']['partnership_targets']:
block = create_bordered_item(partner.get('name'), partner.get('rationale'), COLORS['accent_rose'], styles)
if block:
story.append(block)
story.append(Spacer(1, 4))
story.append(Spacer(1, 8))
# Information Gaps
if data.get('info_gaps'):
story.extend(create_section_heading('Information Gaps', styles))
story.append(Paragraph('The following information was not publicly available:', styles['MutedText']))
for gap in data['info_gaps']:
story.append(Paragraph(f'<font color="#94a3b8">•</font> {gap}', styles['MutedText']))
story.append(Spacer(1, 8))
# Footer
story.append(Spacer(1, 16))
story.append(HRFlowable(width="100%", thickness=1, color=COLORS['border']))
report_date = data.get('report_date', datetime.now().strftime('%B %d, %Y'))
footer_text = f'This report was prepared for business development and sales intelligence purposes. All information is based on publicly available sources and is current as of {report_date}. Verify critical details before making business decisions.'
story.append(Paragraph(footer_text, styles['MutedText']))
# Build PDF
doc.build(story)
return output_path
if __name__ == '__main__':
if len(sys.argv) < 3:
print("Usage: python generate_report.py input.json output.pdf")
sys.exit(1)
input_file = sys.argv[1]
output_file = sys.argv[2]
with open(input_file, 'r') as f:
data = json.load(f)
generate_pdf(data, output_file)
print(f"Report generated: {output_file}")