← Назад// Claude API Report Generator — freelance template
// Typical Upwork project: $800-1,200
// Stack: @anthropic-ai/sdk + csv-parse + nodemailer
const Anthropic = require('@anthropic-ai/sdk')
const fs = require('fs')
const path = require('path')
// ---- Config ----
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY || 'your-key'
const REPORT_MODEL = 'claude-sonnet-4-20250514'
const client = new Anthropic({ apiKey: ANTHROPIC_API_KEY })
// ---- CSV Parser (simple, no deps) ----
function parseCSV(filePath) {
const content = fs.readFileSync(filePath, 'utf8')
const lines = content.trim().split('\n')
const headers = lines[0].split(',').map(h => h.trim())
return lines.slice(1).map(line => {
const values = line.split(',').map(v => v.trim())
const row = {}
headers.forEach((h, i) => { row[h] = values[i] || '' })
return row
})
}
// ---- Report Generation ----
async function generateReport(data, config = {}) {
const {
companyName = 'Company',
reportType = 'Weekly Sales Report',
period = 'This Week',
extraContext = '',
} = config
// Summarize data for the prompt
const dataPreview = JSON.stringify(data.slice(0, 50), null, 2)
const totalRows = data.length
const prompt = `You are a business analyst generating an executive report.
## Context
- Company: ${companyName}
- Report Type: ${reportType}
- Period: ${period}
${extraContext ? `- Additional: ${extraContext}` : ''}
## Data (${totalRows} rows, showing first 50)
\`\`\`json
${dataPreview}
\`\`\`
## Instructions
Generate a professional executive summary report with:
1. **Key Metrics** — top 3-5 numbers that matter (revenue, growth, etc.)
2. **Trends** — what's going up, what's going down, why
3. **Highlights** — notable wins or concerns
4. **Recommendations** — 2-3 actionable items for next week
5. **Risk Flags** — anything that needs immediate attention
Format as clean Markdown. Be concise, data-driven, no fluff.
Use bullet points and bold for key numbers.`
const response = await client.messages.create({
model: REPORT_MODEL,
max_tokens: 2000,
messages: [{ role: 'user', content: prompt }],
})
return response.content[0].text
}
// ---- HTML Wrapper ----
function wrapHTML(markdown, title) {
// Simple markdown → HTML (bold, headers, bullets)
let html = markdown
.replace(/^### (.+)$/gm, '<h3>$1</h3>')
.replace(/^## (.+)$/gm, '<h2>$1</h2>')
.replace(/^# (.+)$/gm, '<h1>$1</h1>')
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
.replace(/^- (.+)$/gm, '<li>$1</li>')
.replace(/(<li>.*<\/li>\n?)+/g, '<ul>$&</ul>')
.replace(/\n\n/g, '</p><p>')
.replace(/\n/g, '<br>')
return `<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: -apple-system, Arial, sans-serif; max-width: 700px; margin: 40px auto; color: #333; line-height: 1.6; }
h1 { color: #1a1a2e; border-bottom: 2px solid #4361ee; padding-bottom: 8px; }
h2 { color: #4361ee; margin-top: 24px; }
h3 { color: #555; }
strong { color: #1a1a2e; }
ul { padding-left: 20px; }
li { margin: 4px 0; }
.footer { margin-top: 40px; font-size: 12px; color: #999; border-top: 1px solid #eee; padding-top: 12px; }
</style>
</head>
<body>
<h1>${title}</h1>
<p>${html}</p>
<div class="footer">Generated automatically by AI Report Generator · ${new Date().toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}</div>
</body>
</html>`
}
// ---- Main ----
async function main() {
const inputFile = process.argv[2] || 'sample-data.csv'
if (!fs.existsSync(inputFile)) {
console.log('Creating sample data...')
createSampleData(inputFile)
}
console.log(`[Report] Reading ${inputFile}...`)
const data = parseCSV(inputFile)
console.log(`[Report] ${data.length} rows loaded`)
console.log('[Report] Generating with Claude...')
const report = await generateReport(data, {
companyName: 'Acme Corp',
reportType: 'Weekly Sales Report',
period: 'Apr 28 — May 4, 2026',
})
// Save Markdown
const mdFile = 'report.md'
fs.writeFileSync(mdFile, `# Weekly Sales Report\n\n${report}`)
console.log(`[Report] Markdown saved: ${mdFile}`)
// Save HTML
const htmlFile = 'report.html'
fs.writeFileSync(htmlFile, wrapHTML(report, 'Weekly Sales Report — Acme Corp'))
console.log(`[Report] HTML saved: ${htmlFile}`)
console.log('\n--- REPORT PREVIEW ---\n')
console.log(report)
}
// ---- Sample Data Generator ----
function createSampleData(file) {
const products = ['Widget A', 'Widget B', 'Pro Plan', 'Enterprise', 'Add-on Pack']
const regions = ['US-West', 'US-East', 'EU', 'APAC']
const lines = ['date,product,region,revenue,units,refunds']
for (let d = 0; d < 7; d++) {
const date = new Date(2026, 4, d + 28) // Apr 28 - May 4
for (const product of products) {
const region = regions[Math.floor(Math.random() * regions.length)]
const units = Math.floor(Math.random() * 50) + 5
const price = product.includes('Enterprise') ? 499 : product.includes('Pro') ? 99 : 29
const revenue = units * price
const refunds = Math.floor(Math.random() * 3)
lines.push(`${date.toISOString().split('T')[0]},${product},${region},${revenue},${units},${refunds}`)
}
}
fs.writeFileSync(file, lines.join('\n'))
console.log(`[Sample] Created ${file} with ${lines.length - 1} rows`)
}
main().catch(console.error)