Skip to main content

Overview

The Reports API generates comprehensive AI-powered reports with real-time streaming using Server-Sent Events (SSE). Base Path: /api/reports

Endpoints

Generate Report (Streaming)

Generate a report with real-time streaming.
POST /api/reports/generate
Request Body:
{
  "company_id": "550e8400-e29b-41d4-a716-446655440000",
  "report_type": "due_diligence",
  "sections": [
    "company_overview",
    "financial_analysis",
    "market_analysis",
    "risk_assessment",
    "recommendations"
  ],
  "include_comparisons": true,
  "time_period": "2024"
}
Report Types:
  • due_diligence - Complete DD report
  • financial_analysis - Financial deep dive
  • market_analysis - Market and competitive analysis
  • executive_summary - High-level overview
  • investment_memo - Investment committee memo
Example Request:
curl -X POST \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{
    "company_id": "550e8400-e29b-41d4-a716-446655440000",
    "report_type": "due_diligence"
  }' \
  "http://localhost:8000/api/reports/generate"
Response (Server-Sent Events):
data: {"type": "start", "report_id": "aa0e8400-e29b-41d4-a716-446655440555", "timestamp": "2024-01-22T10:30:00Z"}

data: {"type": "section_start", "section": "company_overview"}

data: {"type": "chunk", "content": "# Company Overview\n\nAcme Corp is a leading technology"}

data: {"type": "chunk", "content": " company specializing in enterprise SaaS solutions."}

data: {"type": "section_complete", "section": "company_overview"}

data: {"type": "section_start", "section": "financial_analysis"}

data: {"type": "chunk", "content": "# Financial Analysis\n\nRevenue for 2024: $15M"}

data: {"type": "chunk", "content": "\nEBITDA: $4.5M (30% margin)"}

data: {"type": "section_complete", "section": "financial_analysis"}

data: {"type": "complete", "report_id": "aa0e8400-e29b-41d4-a716-446655440555", "total_time": 12.5}

Get Report

Retrieve a previously generated report.
GET /api/reports/{report_id}
Example Request:
curl -H "Authorization: Bearer TOKEN" \
  "http://localhost:8000/api/reports/aa0e8400-e29b-41d4-a716-446655440555"
Response:
{
  "id": "aa0e8400-e29b-41d4-a716-446655440555",
  "company_id": "550e8400-e29b-41d4-a716-446655440000",
  "company_name": "Acme Corp",
  "report_type": "due_diligence",
  "status": "completed",
  "content": "# Due Diligence Report\n\n## Company Overview\n\nAcme Corp...",
  "sections": {
    "company_overview": "...",
    "financial_analysis": "...",
    "market_analysis": "...",
    "risk_assessment": "...",
    "recommendations": "..."
  },
  "metadata": {
    "pages": 45,
    "word_count": 12500,
    "generated_at": "2024-01-22T10:30:00Z",
    "generation_time": 12.5
  },
  "created_at": "2024-01-22T10:30:00Z"
}

List Reports

Get a list of all generated reports.
GET /api/reports
Query Parameters:
ParameterTypeDescription
pageintegerPage number
page_sizeintegerItems per page
company_idUUIDFilter by company
report_typestringFilter by report type
statusstringFilter by status
Response:
{
  "data": [
    {
      "id": "aa0e8400-e29b-41d4-a716-446655440555",
      "company_name": "Acme Corp",
      "report_type": "due_diligence",
      "status": "completed",
      "created_at": "2024-01-22T10:30:00Z"
    }
  ],
  "total": 15,
  "page": 1,
  "page_size": 20
}

Export Report

Export report in various formats.
GET /api/reports/{report_id}/export?format={format}
Formats:
  • pdf - PDF document
  • docx - Word document
  • html - HTML page
  • json - Structured JSON
Example Request:
curl -H "Authorization: Bearer TOKEN" \
  "http://localhost:8000/api/reports/aa0e8400-e29b-41d4-a716-446655440555/export?format=pdf" \
  -O report.pdf

Streaming Integration

Frontend (TypeScript)

async function streamReport(companyId: string) {
  const response = await fetch('http://localhost:8000/api/reports/generate', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json',
      'Accept': 'text/event-stream'
    },
    body: JSON.stringify({
      company_id: companyId,
      report_type: 'due_diligence'
    })
  })

  const reader = response.body!.getReader()
  const decoder = new TextDecoder()

  while (true) {
    const { done, value } = await reader.read()
    if (done) break

    const chunk = decoder.decode(value)
    const lines = chunk.split('\n')

    for (const line of lines) {
      if (line.startsWith('data: ')) {
        const data = JSON.parse(line.slice(6))

        if (data.type === 'chunk') {
          // Append content to UI
          setReportContent(prev => prev + data.content)
        } else if (data.type === 'complete') {
          // Report generation complete
          console.log(`Report completed in ${data.total_time}s`)
        }
      }
    }
  }
}

React Hook

import { useState, useEffect } from 'react'

export function useReportStream(companyId: string, reportType: string) {
  const [content, setContent] = useState('')
  const [isStreaming, setIsStreaming] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const startStream = async () => {
    setIsStreaming(true)
    setContent('')
    setError(null)

    try {
      const response = await fetch('/api/reports/generate', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json',
          'Accept': 'text/event-stream'
        },
        body: JSON.stringify({
          company_id: companyId,
          report_type: reportType
        })
      })

      const reader = response.body!.getReader()
      const decoder = new TextDecoder()

      while (true) {
        const { done, value } = await reader.read()
        if (done) break

        const chunk = decoder.decode(value)
        const lines = chunk.split('\n')

        for (const line of lines) {
          if (line.startsWith('data: ')) {
            const data = JSON.parse(line.slice(6))

            if (data.type === 'chunk') {
              setContent(prev => prev + data.content)
            } else if (data.type === 'complete') {
              setIsStreaming(false)
            } else if (data.type === 'error') {
              setError(data.message)
              setIsStreaming(false)
            }
          }
        }
      }
    } catch (err) {
      setError('Failed to generate report')
      setIsStreaming(false)
    }
  }

  return { content, isStreaming, error, startStream }
}

Event Types

Event TypeDescriptionData
startReport generation started{type, report_id, timestamp}
section_startSection generation started{type, section}
chunkContent chunk{type, content}
section_completeSection finished{type, section}
completeReport finished{type, report_id, total_time}
errorError occurred{type, message, error_code}

Examples

Python

import requests
import json

def stream_report(company_id: str, token: str):
    response = requests.post(
        'http://localhost:8000/api/reports/generate',
        headers={
            'Authorization': f'Bearer {token}',
            'Content-Type': 'application/json',
            'Accept': 'text/event-stream'
        },
        json={
            'company_id': company_id,
            'report_type': 'due_diligence'
        },
        stream=True
    )

    for line in response.iter_lines():
        if line:
            line = line.decode('utf-8')
            if line.startswith('data: '):
                data = json.loads(line[6:])

                if data['type'] == 'chunk':
                    print(data['content'], end='', flush=True)
                elif data['type'] == 'complete':
                    print(f"\n\nReport completed in {data['total_time']}s")

Next Steps