# Export Format Rules

## Core Principles
1. **Default Formats**: JSON + TXT for every transcript
2. **Preserve Structure**: Maintain segments, timestamps, metadata
3. **Human Readable**: TXT files must be clean and readable
4. **Machine Parseable**: JSON must be valid and complete

## Default Export Rules

### Automatic Exports
```python
# REQUIRED: Every transcript generates these
async def export_transcript(transcript: dict, output_dir: Path):
    """Export to default formats automatically"""
    base_name = output_dir / transcript['id']
    
    # JSON - Complete data
    json_path = f"{base_name}.json"
    with open(json_path, 'w') as f:
        json.dump(transcript, f, indent=2, ensure_ascii=False)
    
    # TXT - Human readable
    txt_path = f"{base_name}.txt"
    with open(txt_path, 'w') as f:
        f.write(format_as_text(transcript))
    
    # Log exports
    logger.info(f"Exported: {json_path}, {txt_path}")
    
    return {
        "json": json_path,
        "txt": txt_path
    }
```

## JSON Export Rules

### Structure Requirements
```python
# REQUIRED: JSON structure
{
    "id": "uuid-string",
    "version": "1.0",
    "media_file": {
        "path": "path/to/file.mp4",
        "hash": "sha256-hash",
        "duration": 300.5,
        "size": 10485760
    },
    "transcript": {
        "text": "Full transcript text...",
        "language": "en",
        "segments": [
            {
                "id": 0,
                "start": 0.0,
                "end": 5.2,
                "text": "Segment text",
                "confidence": 0.95,
                "speaker": "SPEAKER_00"  # Optional
            }
        ],
        "words": [  # Optional
            {
                "word": "Hello",
                "start": 0.0,
                "end": 0.5,
                "confidence": 0.99
            }
        ]
    },
    "metadata": {
        "model": "whisper-distil-large-v3",
        "processing_date": "2024-01-01T12:00:00Z",
        "processing_time": 23.5,
        "version": "v2",  # Pipeline version
        "enhanced": true,
        "parameters": {
            "temperature": 0.0,
            "beam_size": 2
        }
    },
    "enhancements": {  # Optional
        "applied": ["punctuation", "capitalization", "formatting"],
        "model": "deepseek-chat",
        "confidence_delta": 0.04
    },
    "speakers": {  # Optional, v4 only
        "count": 2,
        "profiles": [
            {
                "id": "SPEAKER_00",
                "segments": 45,
                "total_time": 150.3,
                "average_confidence": 0.92
            }
        ]
    }
}
```

### JSON Validation
```python
# REQUIRED: Validate before export
import jsonschema

TRANSCRIPT_SCHEMA = {
    "type": "object",
    "required": ["id", "version", "media_file", "transcript", "metadata"],
    "properties": {
        "id": {"type": "string", "format": "uuid"},
        "version": {"type": "string"},
        "transcript": {
            "type": "object",
            "required": ["text", "language", "segments"],
            "properties": {
                "segments": {
                    "type": "array",
                    "items": {
                        "required": ["id", "start", "end", "text"],
                        "properties": {
                            "start": {"type": "number", "minimum": 0},
                            "end": {"type": "number", "minimum": 0}
                        }
                    }
                }
            }
        }
    }
}

def validate_json_export(data: dict):
    """Validate JSON structure before export"""
    try:
        jsonschema.validate(data, TRANSCRIPT_SCHEMA)
        return True
    except jsonschema.ValidationError as e:
        logger.error(f"Invalid JSON structure: {e}")
        return False
```

## TXT Export Rules

### Formatting Requirements
```python
def format_as_text(transcript: dict) -> str:
    """REQUIRED: Human-readable text format"""
    lines = []
    
    # Header
    lines.append("=" * 80)
    lines.append(f"Transcript: {transcript['media_file']['path']}")
    lines.append(f"Duration: {format_duration(transcript['media_file']['duration'])}")
    lines.append(f"Language: {transcript['transcript']['language']}")
    lines.append(f"Processed: {transcript['metadata']['processing_date']}")
    lines.append("=" * 80)
    lines.append("")
    
    # Content with timestamps (optional)
    if include_timestamps:
        for segment in transcript['transcript']['segments']:
            timestamp = format_timestamp(segment['start'])
            speaker = f"[{segment.get('speaker', 'SPEAKER')}]" if 'speaker' in segment else ""
            lines.append(f"{timestamp} {speaker} {segment['text']}")
            lines.append("")
    else:
        # Plain text paragraphs
        lines.append(transcript['transcript']['text'])
    
    # Footer
    lines.append("")
    lines.append("-" * 80)
    lines.append(f"Model: {transcript['metadata']['model']}")
    lines.append(f"Confidence: {calculate_average_confidence(transcript):.2%}")
    if transcript.get('enhancements'):
        lines.append(f"Enhanced: Yes ({', '.join(transcript['enhancements']['applied'])})")
    
    return "\n".join(lines)
```

### Timestamp Formatting
```python
def format_timestamp(seconds: float) -> str:
    """Format seconds as [HH:MM:SS.mmm]"""
    hours = int(seconds // 3600)
    minutes = int((seconds % 3600) // 60)
    secs = seconds % 60
    
    if hours > 0:
        return f"[{hours:02d}:{minutes:02d}:{secs:06.3f}]"
    else:
        return f"[{minutes:02d}:{secs:06.3f}]"
```

## Additional Export Formats

### SRT (Subtitles)
```python
def export_srt(transcript: dict, output_path: Path):
    """Export as SRT subtitle file"""
    with open(output_path, 'w', encoding='utf-8') as f:
        for i, segment in enumerate(transcript['transcript']['segments'], 1):
            # Subtitle number
            f.write(f"{i}\n")
            
            # Timestamps
            start = format_srt_time(segment['start'])
            end = format_srt_time(segment['end'])
            f.write(f"{start} --> {end}\n")
            
            # Text (max 2 lines)
            text = segment['text']
            if len(text) > 80:
                # Split at word boundary
                mid = len(text) // 2
                split_point = text.rfind(' ', 0, mid)
                if split_point > 0:
                    line1 = text[:split_point]
                    line2 = text[split_point + 1:]
                    f.write(f"{line1}\n{line2}\n")
                else:
                    f.write(f"{text}\n")
            else:
                f.write(f"{text}\n")
            
            # Blank line between subtitles
            f.write("\n")

def format_srt_time(seconds: float) -> str:
    """Format as HH:MM:SS,mmm"""
    hours = int(seconds // 3600)
    minutes = int((seconds % 3600) // 60)
    secs = int(seconds % 60)
    millis = int((seconds % 1) * 1000)
    return f"{hours:02d}:{minutes:02d}:{secs:02d},{millis:03d}"
```

### Markdown Export
```python
def export_markdown(transcript: dict, output_path: Path):
    """Export as Markdown with metadata"""
    with open(output_path, 'w', encoding='utf-8') as f:
        # Frontmatter
        f.write("---\n")
        f.write(f"title: {transcript['media_file']['path']}\n")
        f.write(f"date: {transcript['metadata']['processing_date']}\n")
        f.write(f"language: {transcript['transcript']['language']}\n")
        f.write(f"duration: {transcript['media_file']['duration']}\n")
        f.write("---\n\n")
        
        # Title
        f.write(f"# Transcript: {Path(transcript['media_file']['path']).name}\n\n")
        
        # Metadata section
        f.write("## Metadata\n\n")
        f.write(f"- **Duration**: {format_duration(transcript['media_file']['duration'])}\n")
        f.write(f"- **Language**: {transcript['transcript']['language']}\n")
        f.write(f"- **Model**: {transcript['metadata']['model']}\n")
        f.write(f"- **Processed**: {transcript['metadata']['processing_date']}\n\n")
        
        # Content
        f.write("## Transcript\n\n")
        
        if 'speakers' in transcript:
            # With speakers
            current_speaker = None
            for segment in transcript['transcript']['segments']:
                speaker = segment.get('speaker', 'UNKNOWN')
                if speaker != current_speaker:
                    f.write(f"\n**{speaker}**:\n")
                    current_speaker = speaker
                f.write(f"{segment['text']} ")
        else:
            # Plain paragraphs
            f.write(transcript['transcript']['text'])
```

### CSV Export
```python
def export_csv(transcript: dict, output_path: Path):
    """Export segments as CSV"""
    import csv
    
    with open(output_path, 'w', newline='', encoding='utf-8') as f:
        writer = csv.DictWriter(f, fieldnames=[
            'id', 'start', 'end', 'duration', 'text', 
            'confidence', 'speaker', 'word_count'
        ])
        
        writer.writeheader()
        
        for segment in transcript['transcript']['segments']:
            writer.writerow({
                'id': segment['id'],
                'start': segment['start'],
                'end': segment['end'],
                'duration': segment['end'] - segment['start'],
                'text': segment['text'],
                'confidence': segment.get('confidence', ''),
                'speaker': segment.get('speaker', ''),
                'word_count': len(segment['text'].split())
            })
```

## Batch Export Rules

### Batch Organization
```python
def organize_batch_exports(transcripts: List[dict], output_dir: Path):
    """REQUIRED: Organized directory structure"""
    # Create structure
    (output_dir / "json").mkdir(exist_ok=True)
    (output_dir / "txt").mkdir(exist_ok=True)
    (output_dir / "srt").mkdir(exist_ok=True)
    
    # Manifest file
    manifest = {
        "export_date": datetime.now().isoformat(),
        "total_files": len(transcripts),
        "formats": ["json", "txt", "srt"],
        "files": []
    }
    
    for transcript in transcripts:
        base_name = sanitize_filename(
            Path(transcript['media_file']['path']).stem
        )
        
        # Export each format
        exports = {
            "json": output_dir / "json" / f"{base_name}.json",
            "txt": output_dir / "txt" / f"{base_name}.txt",
            "srt": output_dir / "srt" / f"{base_name}.srt"
        }
        
        export_json(transcript, exports["json"])
        export_txt(transcript, exports["txt"])
        export_srt(transcript, exports["srt"])
        
        manifest["files"].append({
            "id": transcript["id"],
            "source": transcript["media_file"]["path"],
            "exports": {k: str(v) for k, v in exports.items()}
        })
    
    # Save manifest
    with open(output_dir / "manifest.json", 'w') as f:
        json.dump(manifest, f, indent=2)
```

## Filename Rules

### Safe Filenames
```python
def sanitize_filename(name: str) -> str:
    """REQUIRED: Safe filenames for all platforms"""
    # Remove/replace invalid characters
    invalid_chars = '<>:"/\\|?*'
    for char in invalid_chars:
        name = name.replace(char, '_')
    
    # Limit length
    if len(name) > 200:
        name = name[:200]
    
    # Remove leading/trailing dots and spaces
    name = name.strip('. ')
    
    # Ensure not empty
    if not name:
        name = "unnamed"
    
    return name
```

### Naming Convention
```python
def generate_export_filename(transcript: dict, format: str) -> str:
    """Consistent naming convention"""
    # Components
    source = Path(transcript['media_file']['path']).stem
    date = transcript['metadata']['processing_date'][:10]
    version = transcript['metadata']['version']
    
    # Build filename
    name = f"{source}_{date}_{version}.{format}"
    
    # Sanitize
    return sanitize_filename(name)
```

## Compression Rules

### Large Exports
```python
def compress_exports(export_dir: Path, output_file: Path):
    """Compress large export sets"""
    import zipfile
    
    with zipfile.ZipFile(output_file, 'w', zipfile.ZIP_DEFLATED) as zf:
        for file in export_dir.rglob('*'):
            if file.is_file():
                arcname = file.relative_to(export_dir)
                zf.write(file, arcname)
    
    # Calculate compression ratio
    original_size = sum(f.stat().st_size for f in export_dir.rglob('*'))
    compressed_size = output_file.stat().st_size
    ratio = (1 - compressed_size / original_size) * 100
    
    logger.info(f"Compressed {original_size:,} bytes to {compressed_size:,} bytes ({ratio:.1f}% reduction)")
```

## Testing Rules

### Export Validation Tests
```python
def test_json_export_valid():
    """Test JSON export is valid"""
    transcript = create_test_transcript()
    output = export_json(transcript)
    
    # Valid JSON
    parsed = json.loads(output)
    assert parsed['id'] == transcript['id']
    
    # Schema valid
    assert validate_json_export(parsed)
    
    # All segments present
    assert len(parsed['transcript']['segments']) == len(transcript['transcript']['segments'])

def test_txt_export_readable():
    """Test TXT export is human-readable"""
    transcript = create_test_transcript()
    output = export_txt(transcript)
    
    # Contains key information
    assert transcript['media_file']['path'] in output
    assert transcript['transcript']['text'] in output
    
    # Properly formatted
    assert "=" * 80 in output  # Header separator
    assert "-" * 80 in output  # Footer separator
```

## Monitoring Rules

### Export Metrics
```python
export_metrics = {
    "formats_used": {"json": 1000, "txt": 1000, "srt": 450},
    "export_times": {"json": 0.1, "txt": 0.05, "srt": 0.15},
    "file_sizes": {"json": 45.2, "txt": 12.3, "srt": 8.7},  # KB average
    "compression_ratio": 0.72,
    "errors": {"validation": 2, "disk_full": 1}
}
```

---

*These rules ensure consistent, reliable export functionality across all formats.*