Sfoglia il codice sorgente

unified class update with use narrative flag

Yuce Dincer 3 mesi fa
parent
commit
8b99e94c04

+ 33 - 16
end-to-end-use-cases/powerpoint-to-voiceover-transcript/README.md

@@ -9,9 +9,10 @@ This system extracts speaker notes and visual content from PowerPoint files, the
 ### Key Features
 
 - **AI-Powered Analysis**: Uses Llama 4 Maverick to understand slide content and context
-- **Narrative Continuity**: Advanced workflow maintains context across slides for smooth transitions
+- **Unified Processing**: Single processor handles both standard and narrative-aware modes
+- **Narrative Continuity**: Optional context-aware processing maintains smooth transitions
 - **Speech Optimization**: Converts numbers, decimals, and technical terms to spoken form
-- **Flexible Processing**: Supports both individual slides and batch processing
+- **Flexible Configuration**: Toggle between processing modes with simple flags
 - **Cross-Platform**: Works on Windows, macOS, and Linux
 - **Production Ready**: Comprehensive error handling, progress tracking, and retry logic
 
@@ -98,13 +99,13 @@ This workflow uses previous slide transcripts as context to maintain narrative c
 Or use the Python API:
 ```python
 from src.core.pptx_processor import pptx_to_images_and_notes
-from src.processors.transcript_generator import TranscriptProcessor
+from src.processors.unified_transcript_generator import UnifiedTranscriptProcessor
 
 # Convert PPTX and extract notes
 result = pptx_to_images_and_notes("presentation.pptx", "output/")
 
 # Generate transcripts
-processor = TranscriptProcessor()
+processor = UnifiedTranscriptProcessor()
 transcripts = processor.process_slides_dataframe(result['notes_df'], "output/")
 
 # Save results
@@ -119,7 +120,7 @@ powerpoint-to-voiceover-transcript/
 ├── config.yaml                        # Main configuration
 ├── pyproject.toml                     # Dependencies and project metadata
 ├── uv.lock                            # uv dependency lock file
-├── narrative_continuity_workflow.ipynb # Enhanced narrative-aware workflow
+├── narrative_continuity_workflow.ipynb # Narrative-aware workflow
 ├── .env.example                       # Environment template
 ├── input/                             # Place your PPTX files here
 └── src/
@@ -131,8 +132,7 @@ powerpoint-to-voiceover-transcript/
     │   ├── llama_client.py            # Llama API integration
     │   └── pptx_processor.py          # PPTX extraction and conversion
     └── processors/
-        ├── transcript_generator.py    # Standard AI transcript generation
-        └── narrative_transcript_generator.py # Narrative-aware processing
+        └── unified_transcript_generator.py # Unified processor (standard + narrative)
 ```
 
 ## Configuration
@@ -167,19 +167,36 @@ Converts PowerPoint to images and extracts speaker notes.
 
 **Returns:** Dictionary with `image_files`, `notes_df`, and `output_dir`
 
-#### `TranscriptProcessor()`
-Main class for generating AI transcripts.
+#### `UnifiedTranscriptProcessor(use_narrative=True, context_window_size=5)`
+Main class for generating AI transcripts with configurable processing modes.
+
+**Parameters:**
+- `use_narrative` (bool): Enable narrative continuity mode (default: True)
+- `context_window_size` (int): Number of previous slides to use as context (default: 5)
 
 **Methods:**
-- `process_slides_dataframe(df, output_dir)` - Process all slides
-- `process_single_slide(image_path, speaker_notes)` - Process one slide
+- `process_slides_dataframe(df, output_dir, save_context=True)` - Process all slides
+- `process_single_slide(image_path, speaker_notes, slide_number, slide_title)` - Process one slide
 
-#### `NarrativeTranscriptProcessor(context_window_size=5)`
-Enhanced class for narrative-aware transcript generation.
+### Processing Modes
 
-**Methods:**
-- `process_slides_dataframe_with_narrative(df, output_dir)` - Process with context
-- `process_single_slide_with_context(image_path, speaker_notes, context)` - Process with previous slides
+#### Standard Mode (`use_narrative=False`)
+- **Best for**: Simple presentations, quick processing, independent slides
+- **Features**: Fast execution, no context dependencies
+- **Use cases**: Training materials, product demos, standalone slides
+
+#### Narrative Mode (`use_narrative=True`)
+- **Best for**: Story-driven presentations, complex topics, educational content
+- **Features**: Context awareness, smooth transitions, terminology consistency
+- **Use cases**: Conference talks, educational courses, marketing presentations
+
+### Legacy Functions (Backward Compatibility)
+
+#### `process_slides(df, output_dir, use_narrative=False)`
+Convenience function for standard processing.
+
+#### `process_slides_with_narrative(df, output_dir, context_window_size=5)`
+Convenience function for narrative processing.
 
 ### Speech Optimization
 

+ 360 - 47
end-to-end-use-cases/powerpoint-to-voiceover-transcript/narrative_continuity_workflow.ipynb

@@ -7,19 +7,26 @@
    "source": [
     "# PowerPoint to Narrative-Aware Voiceover Transcript Generator\n",
     "\n",
-    "This notebook demonstrates the complete workflow for converting PowerPoint presentations into AI-generated voiceover transcripts with narrative continuity using Llama 4 Maverick through the Llama API.\n",
+    "This notebook demonstrates the complete workflow for converting PowerPoint presentations into AI-generated voiceover transcripts using the unified transcript processor with Llama 4 Maverick through the Llama API.\n",
     "\n",
     "## Overview\n",
     "\n",
-    "This enhanced workflow performs the following operations:\n",
+    "This unified workflow performs the following operations:\n",
     "\n",
     "1. **Content Extraction**: Pulls speaker notes and visual elements from PowerPoint slides\n",
     "2. **Image Conversion**: Transforms slides into high-quality images for AI analysis\n",
-    "3. **Narrative-Aware Processing**: Uses previous slide transcripts as context for continuity\n",
-    "4. **Transcript Generation**: Creates natural-sounding voiceover content with smooth transitions\n",
+    "3. **Flexible Processing**: Choose between standard or narrative-aware processing modes\n",
+    "4. **Transcript Generation**: Creates natural-sounding voiceover content with optional narrative continuity\n",
     "5. **Speech Optimization**: Converts numbers, technical terms, and abbreviations to spoken form\n",
     "6. **Results Export**: Saves transcripts and context information in multiple formats\n",
     "\n",
+    "## Key Features\n",
+    "\n",
+    "- **Unified Processor**: Single class handles both standard and narrative-aware processing\n",
+    "- **Configurable Context**: Adjustable context window for narrative continuity\n",
+    "- **Mode Selection**: Toggle between standard and narrative processing with a simple flag\n",
+    "- **Backward Compatibility**: Maintains compatibility with existing workflows\n",
+    "\n",
     "## Prerequisites\n",
     "\n",
     "Before running this notebook, ensure you have:\n",
@@ -40,10 +47,19 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 19,
    "id": "21a962b2",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "SUCCESS: Environment loaded successfully!\n",
+      "SUCCESS: Llama API key found\n"
+     ]
+    }
+   ],
    "source": [
     "# Import required libraries\n",
     "import pandas as pd\n",
@@ -67,23 +83,35 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 20,
    "id": "71c1c8bd",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "SUCCESS: All modules imported successfully!\n",
+      "- PPTX processor ready\n",
+      "- Unified transcript generator ready\n",
+      "- Configuration manager ready\n"
+     ]
+    }
+   ],
    "source": [
     "# Import custom modules\n",
     "try:\n",
     "    from src.core.pptx_processor import extract_pptx_notes, pptx_to_images_and_notes\n",
-    "    from src.processors.narrative_transcript_generator import (\n",
-    "        NarrativeTranscriptProcessor,\n",
+    "    from src.processors.unified_transcript_generator import (\n",
+    "        UnifiedTranscriptProcessor,\n",
+    "        process_slides,\n",
     "        process_slides_with_narrative\n",
     "    )\n",
     "    from src.config.settings import load_config, get_config\n",
     "\n",
     "    print(\"SUCCESS: All modules imported successfully!\")\n",
     "    print(\"- PPTX processor ready\")\n",
-    "    print(\"- Narrative transcript generator ready\")\n",
+    "    print(\"- Unified transcript generator ready\")\n",
     "    print(\"- Configuration manager ready\")\n",
     "\n",
     "except ImportError as e:\n",
@@ -93,10 +121,24 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 21,
    "id": "53781172",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "SUCCESS: Configuration loaded successfully!\n",
+      "\n",
+      "Current Settings:\n",
+      "- Llama Model: Llama-4-Maverick-17B-128E-Instruct-FP8\n",
+      "- Image DPI: 200\n",
+      "- Image Format: png\n",
+      "- Context Window: 5 previous slides (default)\n"
+     ]
+    }
+   ],
    "source": [
     "# Load and display configuration\n",
     "config = load_config()\n",
@@ -110,10 +152,22 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 22,
    "id": "9386e035",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "File Configuration:\n",
+      "- Input File: input/Part 1 Llama Certification V2 PPT Outline.pptx\n",
+      "- Output Directory: output/\n",
+      "- SUCCESS: Input file found (80.4 MB)\n",
+      "- SUCCESS: Output directory ready\n"
+     ]
+    }
+   ],
    "source": [
     "# Configure file paths from config.yaml\n",
     "pptx_file = config['current_project']['pptx_file'] + config['current_project']['extension']\n",
@@ -138,6 +192,53 @@
   },
   {
    "cell_type": "markdown",
+   "id": "35a9e13a-4f85-488e-880b-62c7512d1248",
+   "metadata": {},
+   "source": [
+    "## Processing Mode Configuration\n",
+    "\n",
+    "Choose your processing mode and configure the unified processor."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "id": "6fbfcb28-2f09-4497-8098-35cf3d62ebf3",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Processing Mode Configuration:\n",
+      "- Mode: NARRATIVE CONTINUITY\n",
+      "- Context Window: 5 previous slides\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Configure processing mode\n",
+    "\n",
+    "USE_NARRATIVE = True  # Set to False for standard processing, True for narrative continuity\n",
+    "CONTEXT_WINDOW_SIZE = 5  # Number of previous slides to use as context (only used when USE_NARRATIVE=True)\n",
+    "\n",
+    "print(\"Processing Mode Configuration:\")\n",
+    "if USE_NARRATIVE:\n",
+    "    print(f\"- Mode: NARRATIVE CONTINUITY\")\n",
+    "    print(f\"- Context Window: {CONTEXT_WINDOW_SIZE} previous slides\")\n",
+    "else:\n",
+    "    print(f\"- Mode: STANDARD PROCESSING\")\n",
+    "    print(f\"- Features: Independent slide processing, faster execution\")\n",
+    "\n",
+    "# Initialize the unified processor\n",
+    "processor = UnifiedTranscriptProcessor(\n",
+    "    use_narrative=USE_NARRATIVE,\n",
+    "    context_window_size=CONTEXT_WINDOW_SIZE\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
    "id": "ea4851e6",
    "metadata": {},
    "source": [
@@ -159,10 +260,131 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 26,
    "id": "644ee94c",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "PROCESSING: Converting PPTX to images and extracting notes...\n",
+      "Processing: Part 1 Llama Certification V2 PPT Outline.pptx\n",
+      "Extracting speaker notes...\n",
+      "Found notes on 41 of 102 slides\n",
+      "Notes df saved to: /Users/yucedincer/Desktop/Projects/llama-cookbook/end-to-end-use-cases/powerpoint-to-voiceover-transcript/output/Part 1 Llama Certification V2 PPT Outline_notes.csv\n",
+      "Converting to PDF...\n",
+      "Converting to PNG images at 200 DPI...\n",
+      "\n",
+      "Successfully processed 102 slides\n",
+      "Images saved to: /Users/yucedincer/Desktop/Projects/llama-cookbook/end-to-end-use-cases/powerpoint-to-voiceover-transcript/output\n",
+      "\n",
+      "SUCCESS: Processing completed successfully!\n",
+      "- Processed 102 slides\n",
+      "- Images saved to: /Users/yucedincer/Desktop/Projects/llama-cookbook/end-to-end-use-cases/powerpoint-to-voiceover-transcript/output\n",
+      "- Found notes on 41 slides\n",
+      "- DataFrame shape: (102, 8)\n",
+      "\n",
+      "Sample Data (First 5 slides):\n"
+     ]
+    },
+    {
+     "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    .dataframe tbody tr th:only-of-type {\n",
+       "        vertical-align: middle;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe tbody tr th {\n",
+       "        vertical-align: top;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe thead th {\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "</style>\n",
+       "<table border=\"1\" class=\"dataframe\">\n",
+       "  <thead>\n",
+       "    <tr style=\"text-align: right;\">\n",
+       "      <th></th>\n",
+       "      <th>slide_number</th>\n",
+       "      <th>slide_title</th>\n",
+       "      <th>has_notes</th>\n",
+       "      <th>notes_word_count</th>\n",
+       "      <th>slide_text_word_count</th>\n",
+       "    </tr>\n",
+       "  </thead>\n",
+       "  <tbody>\n",
+       "    <tr>\n",
+       "      <th>0</th>\n",
+       "      <td>1</td>\n",
+       "      <td>APRIL 2025</td>\n",
+       "      <td>False</td>\n",
+       "      <td>0</td>\n",
+       "      <td>6</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>1</th>\n",
+       "      <td>2</td>\n",
+       "      <td>Module 1: \u000b",
+       "Introduction to Llama</td>\n",
+       "      <td>False</td>\n",
+       "      <td>0</td>\n",
+       "      <td>41</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>2</th>\n",
+       "      <td>3</td>\n",
+       "      <td>Video 1: Overview of Llama</td>\n",
+       "      <td>False</td>\n",
+       "      <td>0</td>\n",
+       "      <td>15</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>3</th>\n",
+       "      <td>4</td>\n",
+       "      <td>Artificial intelligence (AI)</td>\n",
+       "      <td>True</td>\n",
+       "      <td>243</td>\n",
+       "      <td>34</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>4</th>\n",
+       "      <td>5</td>\n",
+       "      <td>Leverage Llama for unparalleled \u000b",
+       "control, cust...</td>\n",
+       "      <td>True</td>\n",
+       "      <td>244</td>\n",
+       "      <td>147</td>\n",
+       "    </tr>\n",
+       "  </tbody>\n",
+       "</table>\n",
+       "</div>"
+      ],
+      "text/plain": [
+       "   slide_number                                        slide_title  has_notes  \\\n",
+       "0             1                                         APRIL 2025      False   \n",
+       "1             2                   Module 1: \n",
+       "Introduction to Llama      False   \n",
+       "2             3                         Video 1: Overview of Llama      False   \n",
+       "3             4                       Artificial intelligence (AI)       True   \n",
+       "4             5  Leverage Llama for unparalleled \n",
+       "control, cust...       True   \n",
+       "\n",
+       "   notes_word_count  slide_text_word_count  \n",
+       "0                 0                      6  \n",
+       "1                 0                     41  \n",
+       "2                 0                     15  \n",
+       "3               243                     34  \n",
+       "4               244                    147  "
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
    "source": [
     "print(\"PROCESSING: Converting PPTX to images and extracting notes...\")\n",
     "\n",
@@ -206,31 +428,79 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 27,
    "id": "fe564b99",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "PROCESSING: Starting AI transcript generation with unified processor...\n",
+      "- Processing 102 slides\n",
+      "- Using model: Llama-4-Maverick-17B-128E-Instruct-FP8\n",
+      "- Mode: Narrative Continuity\n",
+      "- Context window: 5 previous slides\n",
+      "- Using previous transcripts as context for narrative continuity\n",
+      "- This may take several minutes...\n",
+      "Processing 102 slides with narrative continuity...\n",
+      "Using context window of 5 previous slides\n"
+     ]
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "Processing slides: 100%|██████████████████████| 102/102 [06:03<00:00,  3.56s/it]"
+     ]
+    },
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Context information saved to: output/narrative_context\n",
+      "\n",
+      "SUCCESS: Transcript generation completed!\n",
+      "- Generated 102 transcripts\n",
+      "- Average length: 1137 characters\n",
+      "- Total words: 16,950\n",
+      "- Context information saved to: output/narrative_context/\n",
+      "- Average context slides used: 4.9\n"
+     ]
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "\n"
+     ]
+    }
+   ],
    "source": [
-    "print(\"PROCESSING: Starting narrative-aware AI transcript generation...\")\n",
+    "print(\"PROCESSING: Starting AI transcript generation with unified processor...\")\n",
     "print(f\"- Processing {len(notes_df)} slides\")\n",
     "print(f\"- Using model: {config['api']['llama_model']}\")\n",
-    "print(f\"- Context window: 5 previous slides\")\n",
-    "print(f\"- Using previous transcripts as context for narrative continuity\")\n",
+    "print(f\"- Mode: {'Narrative Continuity' if USE_NARRATIVE else 'Standard Processing'}\")\n",
+    "if USE_NARRATIVE:\n",
+    "    print(f\"- Context window: {CONTEXT_WINDOW_SIZE} previous slides\")\n",
+    "    print(f\"- Using previous transcripts as context for narrative continuity\")\n",
     "print(\"- This may take several minutes...\")\n",
     "\n",
-    "# Initialize processor and generate transcripts with narrative continuity\n",
-    "processor = NarrativeTranscriptProcessor(context_window_size=5)\n",
-    "processed_df = processor.process_slides_dataframe_with_narrative(\n",
+    "# Generate transcripts using the unified processor\n",
+    "processed_df = processor.process_slides_dataframe(\n",
     "    df=notes_df,\n",
     "    output_dir=output_dir,\n",
-    "    save_context=True\n",
+    "    save_context=True  # Only saves context if USE_NARRATIVE=True\n",
     ")\n",
     "\n",
-    "print(f\"\\nSUCCESS: Narrative-aware transcript generation completed!\")\n",
+    "print(f\"\\nSUCCESS: Transcript generation completed!\")\n",
     "print(f\"- Generated {len(processed_df)} transcripts\")\n",
     "print(f\"- Average length: {processed_df['ai_transcript'].str.len().mean():.0f} characters\")\n",
     "print(f\"- Total words: {processed_df['ai_transcript'].str.split().str.len().sum():,}\")\n",
-    "print(f\"- Context information saved to: {output_dir}narrative_context/\")"
+    "\n",
+    "if USE_NARRATIVE:\n",
+    "    print(f\"- Context information saved to: {output_dir}narrative_context/\")\n",
+    "    print(f\"- Average context slides used: {processed_df['context_slides_used'].mean():.1f}\")"
    ]
   },
   {
@@ -245,29 +515,56 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 28,
    "id": "8463ac3a",
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "PROCESSING: Saving results in multiple formats...\n",
+      "- SUCCESS: Complete results saved to output/narrative_transcripts.csv\n",
+      "- SUCCESS: Clean transcripts saved to output/narrative_transcripts_clean.csv\n",
+      "- SUCCESS: JSON format saved to output/narrative_transcripts.json\n",
+      "\n",
+      "Export Summary:\n",
+      "- Processing mode: Narrative Continuity\n",
+      "- Total slides processed: 102\n",
+      "- Slides with speaker notes: 41\n",
+      "- Total transcript words: 16,950\n",
+      "- Average transcript length: 1137 characters\n",
+      "- Estimated reading time: 113.0 minutes\n",
+      "- Average context slides per slide: 4.9\n"
+     ]
+    }
+   ],
    "source": [
     "print(\"PROCESSING: Saving results in multiple formats...\")\n",
     "\n",
     "# Create output directory\n",
     "os.makedirs(output_dir, exist_ok=True)\n",
     "\n",
+    "# Determine file prefix based on processing mode\n",
+    "file_prefix = \"narrative\" if USE_NARRATIVE else \"standard\"\n",
+    "\n",
     "# Save complete results with all metadata\n",
-    "output_file = f\"{output_dir}narrative_transcripts.csv\"\n",
+    "output_file = f\"{output_dir}{file_prefix}_transcripts.csv\"\n",
     "processed_df.to_csv(output_file, index=False)\n",
     "print(f\"- SUCCESS: Complete results saved to {output_file}\")\n",
     "\n",
     "# Save transcript-only version for voiceover work\n",
-    "transcript_only = processed_df[['slide_number', 'slide_title', 'ai_transcript', 'context_slides_used']]\n",
-    "transcript_file = f\"{output_dir}narrative_transcripts_clean.csv\"\n",
+    "if USE_NARRATIVE:\n",
+    "    transcript_only = processed_df[['slide_number', 'slide_title', 'ai_transcript', 'context_slides_used']]\n",
+    "else:\n",
+    "    transcript_only = processed_df[['slide_number', 'slide_title', 'ai_transcript']]\n",
+    "\n",
+    "transcript_file = f\"{output_dir}{file_prefix}_transcripts_clean.csv\"\n",
     "transcript_only.to_csv(transcript_file, index=False)\n",
     "print(f\"- SUCCESS: Clean transcripts saved to {transcript_file}\")\n",
     "\n",
     "# Save as JSON for API integration\n",
-    "json_file = f\"{output_dir}narrative_transcripts.json\"\n",
+    "json_file = f\"{output_dir}{file_prefix}_transcripts.json\"\n",
     "processed_df.to_json(json_file, orient='records', indent=2)\n",
     "print(f\"- SUCCESS: JSON format saved to {json_file}\")\n",
     "\n",
@@ -276,12 +573,15 @@
     "reading_time = total_words / 150  # Assuming 150 words per minute\n",
     "\n",
     "print(f\"\\nExport Summary:\")\n",
+    "print(f\"- Processing mode: {'Narrative Continuity' if USE_NARRATIVE else 'Standard Processing'}\")\n",
     "print(f\"- Total slides processed: {len(processed_df)}\")\n",
     "print(f\"- Slides with speaker notes: {processed_df['has_notes'].sum()}\")\n",
     "print(f\"- Total transcript words: {total_words:,}\")\n",
     "print(f\"- Average transcript length: {processed_df['ai_transcript'].str.len().mean():.0f} characters\")\n",
     "print(f\"- Estimated reading time: {reading_time:.1f} minutes\")\n",
-    "print(f\"- Average context slides per slide: {processed_df['context_slides_used'].mean():.1f}\")"
+    "\n",
+    "if USE_NARRATIVE and 'context_slides_used' in processed_df.columns:\n",
+    "    print(f\"- Average context slides per slide: {processed_df['context_slides_used'].mean():.1f}\")"
    ]
   },
   {
@@ -293,31 +593,44 @@
     "# Completion Summary\n",
     "\n",
     "## Successfully Generated:\n",
-    "- **Narrative-Aware Transcripts**: Context-aware voiceover content with smooth transitions\n",
-    "- **Consistent Terminology**: Maintained terminology consistency throughout presentation\n",
+    "- **Unified Processing**: Single processor handles both standard and narrative modes\n",
+    "- **Flexible Configuration**: Easy switching between processing modes\n",
+    "- **Speech-Optimized Transcripts**: Natural-sounding voiceover content\n",
     "- **Multiple Formats**: CSV, JSON exports for different use cases\n",
-    "- **Context Analysis**: Detailed information about narrative flow and relationships\n",
+    "- **Context Analysis**: Detailed information about narrative flow (when enabled)\n",
     "\n",
     "## Output Files:\n",
-    "- `narrative_transcripts.csv` - Complete dataset with context information\n",
-    "- `narrative_transcripts_clean.csv` - Clean transcripts for voiceover work\n",
-    "- `narrative_transcripts.json` - JSON format for API integration\n",
-    "- `narrative_context/slide_contexts.json` - Individual slide context data\n",
-    "- `narrative_context/narrative_summary.json` - Overall narrative analysis\n",
+    "- `[mode]_transcripts.csv` - Complete dataset with metadata\n",
+    "- `[mode]_transcripts_clean.csv` - Clean transcripts for voiceover work\n",
+    "- `[mode]_transcripts.json` - JSON format for API integration\n",
+    "- `narrative_context/` - Context analysis files (narrative mode only)\n",
     "- Individual slide images in PNG/JPEG format\n",
     "\n",
+    "## Processing Modes:\n",
+    "\n",
+    "### Standard Mode (`USE_NARRATIVE = False`)\n",
+    "- **Best for**: Simple presentations, quick processing, independent slides\n",
+    "- **Features**: Fast execution, no context dependencies\n",
+    "- **Use cases**: Training materials, product demos, standalone slides\n",
+    "\n",
+    "### Narrative Mode (`USE_NARRATIVE = True`)\n",
+    "- **Best for**: Story-driven presentations, complex topics, educational content\n",
+    "- **Features**: Context awareness, smooth transitions, terminology consistency\n",
+    "- **Use cases**: Conference talks, educational courses, marketing presentations\n",
+    "\n",
     "## Next Steps:\n",
-    "1. **Review** generated transcripts for narrative flow and accuracy\n",
+    "1. **Review** generated transcripts for accuracy and flow\n",
     "2. **Edit** any content that needs refinement\n",
     "3. **Create** voiceover recordings or use TTS systems\n",
     "4. **Integrate** JSON data into your video production workflow\n",
+    "5. **Experiment** with different processing modes for optimal results\n",
     "\n",
     "## Tips for Better Results:\n",
-    "- **Rich Speaker Notes**: Slides with detailed notes generate better contextual transcripts\n",
+    "- **Rich Speaker Notes**: Detailed notes improve transcript quality in both modes\n",
     "- **Clear Visuals**: High-contrast slides with readable text work best\n",
-    "- **Consistent Style**: Maintain consistent formatting across your presentation\n",
+    "- **Mode Selection**: Use narrative mode for complex presentations, standard for simple ones\n",
     "- **Context Window**: Adjust context window size (3-7 slides) based on presentation complexity\n",
-    "- **Review Context**: Check the narrative_context files to understand how continuity was maintained\n",
+    "- **Consistent Style**: Maintain consistent formatting across your presentation\n",
     "\n",
     "---"
    ]

+ 0 - 115
end-to-end-use-cases/powerpoint-to-voiceover-transcript/src/processors/transcript_generator.py

@@ -1,115 +0,0 @@
-"""Transcript generation processor for PPTX slides."""
-
-from pathlib import Path
-from typing import Optional, Union
-
-import pandas as pd
-from tqdm import tqdm
-
-from ..config.settings import get_processing_config
-
-from ..core.llama_client import LlamaClient
-
-
-class TranscriptProcessor:
-    """Processor for generating transcripts from slide images and notes."""
-
-    def __init__(self, api_key: Optional[str] = None):
-        """
-        Initialize transcript processor.
-
-        Args:
-            api_key: Llama API key. If None, will be loaded from config/environment.
-        """
-        self.client = LlamaClient(api_key=api_key)
-        self.processing_config = get_processing_config()
-
-    def process_single_slide(
-        self,
-        image_path: Union[str, Path],
-        speaker_notes: str = "",
-        system_prompt: Optional[str] = None,
-    ) -> str:
-        """
-        Process a single slide to generate transcript.
-
-        Args:
-            image_path: Path to the slide image
-            speaker_notes: Speaker notes for the slide
-            system_prompt: Custom system prompt. If None, uses default from config.
-
-        Returns:
-            Generated transcript text
-        """
-        return self.client.generate_transcript(
-            image_path=str(image_path),
-            speaker_notes=speaker_notes,
-            system_prompt=system_prompt,
-            stream=False,
-        )
-
-    def process_slides_dataframe(
-        self,
-        df: pd.DataFrame,
-        output_dir: Union[str, Path],
-        system_prompt: Optional[str] = None,
-    ) -> pd.DataFrame:
-        """
-        Process slides from a DataFrame containing slide information.
-
-        Args:
-            df: DataFrame with slide information (from extract_pptx_notes)
-            output_dir: Directory containing slide images
-            system_prompt: Custom system prompt. If None, uses default from config.
-
-        Returns:
-            DataFrame with added 'ai_transcript' column
-        """
-        output_dir = Path(output_dir)
-        df_copy = df.copy()
-
-        for i in tqdm(range(len(df_copy)), desc="Processing slides"):
-            # Get data for current slide
-            slide_filename = df_copy.iloc[i]["image_filename"]
-            speaker_notes = (
-                df_copy.iloc[i]["speaker_notes"]
-                if pd.notna(df_copy.iloc[i]["speaker_notes"])
-                else ""
-            )
-
-            image_path = output_dir / slide_filename
-
-            # Generate transcript
-            transcript = self.process_single_slide(
-                image_path=image_path,
-                speaker_notes=speaker_notes,
-                system_prompt=system_prompt,
-            )
-
-            # Add to dataframe
-            df_copy.loc[i, "ai_transcript"] = transcript
-
-        return df_copy
-
-
-def process_slides(
-    df: pd.DataFrame,
-    output_dir: Union[str, Path] = "slide_images",
-    api_key: Optional[str] = None,
-    system_prompt: Optional[str] = None,
-) -> pd.DataFrame:
-    """
-    Legacy function for backward compatibility with notebook code.
-    Process slides from a DataFrame to generate transcripts.
-
-    Args:
-        df: DataFrame with slide information (from extract_pptx_notes)
-        output_dir: Directory containing slide images
-        api_key: Llama API key. If None, will be loaded from config/environment.
-        system_prompt: Custom system prompt. If None, uses default from config.
-
-    Returns:
-        DataFrame with added 'ai_transcript' column
-    """
-    processor = TranscriptProcessor(api_key=api_key)
-    return processor.process_slides_dataframe(df, output_dir, system_prompt)

+ 121 - 61
end-to-end-use-cases/powerpoint-to-voiceover-transcript/src/processors/narrative_transcript_generator.py

@@ -1,4 +1,4 @@
-"""Simplified transcript generation processor with narrative continuity using previous slide transcripts."""
+"""Unified transcript generation processor with optional narrative continuity."""
 
 import json
 from pathlib import Path
@@ -7,7 +7,7 @@ from typing import Any, Dict, List, Optional, Union
 import pandas as pd
 from tqdm import tqdm
 
-from ..config.settings import get_system_prompt
+from ..config.settings import get_processing_config, get_system_prompt
 from ..core.llama_client import LlamaClient
 
 
@@ -27,18 +27,26 @@ class SlideContext:
         }
 
 
-class NarrativeTranscriptProcessor:
-    """Simplified processor for generating transcripts with narrative continuity using previous slide transcripts."""
+class UnifiedTranscriptProcessor:
+    """Unified processor for generating transcripts with optional narrative continuity."""
 
-    def __init__(self, api_key: Optional[str] = None, context_window_size: int = 5):
+    def __init__(
+        self,
+        api_key: Optional[str] = None,
+        use_narrative: bool = True,
+        context_window_size: int = 5,
+    ):
         """
-        Initialize narrative transcript processor.
+        Initialize unified transcript processor.
 
         Args:
             api_key: Llama API key. If None, will be loaded from config/environment.
-            context_window_size: Number of previous slides to include in context (default: 5)
+            use_narrative: Whether to use narrative continuity (default: True)
+            context_window_size: Number of previous slides to include in context when use_narrative=True (default: 5)
         """
         self.client = LlamaClient(api_key=api_key)
+        self.processing_config = get_processing_config()
+        self.use_narrative = use_narrative
         self.context_window_size = context_window_size
         self.slide_contexts: List[SlideContext] = []
 
@@ -47,6 +55,7 @@ class NarrativeTranscriptProcessor:
     ) -> str:
         """
         Build enhanced system prompt with previous slide transcripts as context.
+        Only used when use_narrative=True.
 
         Args:
             current_slide_number: Number of the current slide being processed
@@ -57,7 +66,7 @@ class NarrativeTranscriptProcessor:
         """
         base_prompt = get_system_prompt()
 
-        if not slide_contexts:
+        if not slide_contexts or not self.use_narrative:
             return base_prompt
 
         # Build context section
@@ -96,71 +105,88 @@ When generating the transcript for this slide, ensure:
 
         return base_prompt + context_section + continuity_instructions
 
-    def process_single_slide_with_context(
+    def process_single_slide(
         self,
-        slide_number: int,
-        slide_title: str,
         image_path: Union[str, Path],
         speaker_notes: str = "",
+        system_prompt: Optional[str] = None,
+        slide_number: Optional[int] = None,
+        slide_title: str = "",
     ) -> str:
         """
-        Process a single slide with context from previous slides.
+        Process a single slide to generate transcript.
 
         Args:
-            slide_number: Number of the current slide
-            slide_title: Title of the current slide
             image_path: Path to the slide image
             speaker_notes: Speaker notes for the slide
+            system_prompt: Custom system prompt. If None, uses default from config.
+            slide_number: Number of the current slide (used for narrative continuity)
+            slide_title: Title of the current slide (used for narrative continuity)
 
         Returns:
-            Generated transcript text with narrative continuity
+            Generated transcript text
         """
-        # Build context-aware system prompt
-        enhanced_prompt = self._build_context_prompt(slide_number, self.slide_contexts)
-
-        # Generate transcript with context
-        transcript = self.client.generate_transcript(
-            image_path=str(image_path),
-            speaker_notes=speaker_notes,
-            system_prompt=enhanced_prompt,
-            stream=False,
-        )
+        if self.use_narrative and slide_number is not None:
+            # Use narrative-aware processing
+            enhanced_prompt = self._build_context_prompt(
+                slide_number, self.slide_contexts
+            )
 
-        # Create and store slide context for future slides
-        slide_context = SlideContext(
-            slide_number=slide_number,
-            title=slide_title,
-            transcript=transcript,
-        )
+            # Generate transcript with context
+            transcript = self.client.generate_transcript(
+                image_path=str(image_path),
+                speaker_notes=speaker_notes,
+                system_prompt=enhanced_prompt,
+                stream=False,
+            )
 
-        self.slide_contexts.append(slide_context)
+            # Create and store slide context for future slides
+            slide_context = SlideContext(
+                slide_number=slide_number,
+                title=slide_title,
+                transcript=transcript,
+            )
+            self.slide_contexts.append(slide_context)
 
-        return transcript
+            return transcript
+        else:
+            # Use standard processing
+            return self.client.generate_transcript(
+                image_path=str(image_path),
+                speaker_notes=speaker_notes,
+                system_prompt=system_prompt,
+                stream=False,
+            )
 
-    def process_slides_dataframe_with_narrative(
+    def process_slides_dataframe(
         self,
         df: pd.DataFrame,
         output_dir: Union[str, Path],
+        system_prompt: Optional[str] = None,
         save_context: bool = True,
     ) -> pd.DataFrame:
         """
-        Process slides from a DataFrame with narrative continuity.
+        Process slides from a DataFrame containing slide information.
 
         Args:
             df: DataFrame with slide information (from extract_pptx_notes)
             output_dir: Directory containing slide images
-            save_context: Whether to save context information to file
+            system_prompt: Custom system prompt. If None, uses default from config.
+            save_context: Whether to save context information to file (only used when use_narrative=True)
 
         Returns:
-            DataFrame with added 'ai_transcript' and context columns
+            DataFrame with added 'ai_transcript' column and context columns if using narrative mode
         """
         output_dir = Path(output_dir)
         df_copy = df.copy()
 
-        print(f"Processing {len(df_copy)} slides with narrative continuity...")
-        print(f"Using context window of {self.context_window_size} previous slides")
+        if self.use_narrative:
+            print(f"Processing {len(df_copy)} slides with narrative continuity...")
+            print(f"Using context window of {self.context_window_size} previous slides")
+        else:
+            print(f"Processing {len(df_copy)} slides in standard mode...")
 
-        for i in tqdm(range(len(df_copy)), desc="Processing slides with context"):
+        for i in tqdm(range(len(df_copy)), desc="Processing slides"):
             # Get data for current slide
             slide_row = df_copy.iloc[i]
             slide_number = slide_row["slide_number"]
@@ -174,28 +200,40 @@ When generating the transcript for this slide, ensure:
 
             image_path = output_dir / slide_filename
 
-            # Generate transcript with narrative context
-            transcript = self.process_single_slide_with_context(
-                slide_number=slide_number,
-                slide_title=slide_title,
-                image_path=image_path,
-                speaker_notes=speaker_notes,
-            )
-
-            # Add to dataframe
+            # Generate transcript
+            if self.use_narrative:
+                transcript = self.process_single_slide(
+                    image_path=image_path,
+                    speaker_notes=speaker_notes,
+                    system_prompt=system_prompt,
+                    slide_number=slide_number,
+                    slide_title=slide_title,
+                )
+                # Add context information to dataframe
+                df_copy.loc[i, "context_slides_used"] = min(
+                    len(self.slide_contexts) - 1, self.context_window_size
+                )
+            else:
+                transcript = self.process_single_slide(
+                    image_path=image_path,
+                    speaker_notes=speaker_notes,
+                    system_prompt=system_prompt,
+                )
+
+            # Add transcript to dataframe
             df_copy.loc[i, "ai_transcript"] = transcript
-            df_copy.loc[i, "context_slides_used"] = min(
-                len(self.slide_contexts) - 1, self.context_window_size
-            )
 
-        # Save context information if requested
-        if save_context:
+        # Save context information if requested and using narrative mode
+        if save_context and self.use_narrative:
             self._save_context_information(output_dir)
 
         return df_copy
 
     def _save_context_information(self, output_dir: Path):
-        """Save context information to files."""
+        """Save context information to files. Only used when use_narrative=True."""
+        if not self.use_narrative:
+            return
+
         context_dir = output_dir / "narrative_context"
         context_dir.mkdir(exist_ok=True)
 
@@ -225,7 +263,31 @@ When generating the transcript for this slide, ensure:
         print(f"Context information saved to: {context_dir}")
 
 
-# Convenience function for backward compatibility
+# Convenience functions for backward compatibility
+def process_slides(
+    df: pd.DataFrame,
+    output_dir: Union[str, Path] = "slide_images",
+    api_key: Optional[str] = None,
+    system_prompt: Optional[str] = None,
+    use_narrative: bool = False,
+) -> pd.DataFrame:
+    """
+    Process slides from a DataFrame to generate transcripts.
+
+    Args:
+        df: DataFrame with slide information (from extract_pptx_notes)
+        output_dir: Directory containing slide images
+        api_key: Llama API key. If None, will be loaded from config/environment.
+        system_prompt: Custom system prompt. If None, uses default from config.
+        use_narrative: Whether to use narrative continuity (default: False for backward compatibility)
+
+    Returns:
+        DataFrame with added 'ai_transcript' column
+    """
+    processor = UnifiedTranscriptProcessor(api_key=api_key, use_narrative=use_narrative)
+    return processor.process_slides_dataframe(df, output_dir, system_prompt)
+
+
 def process_slides_with_narrative(
     df: pd.DataFrame,
     output_dir: Union[str, Path] = "slide_images",
@@ -246,9 +308,7 @@ def process_slides_with_narrative(
     Returns:
         DataFrame with added transcript and context columns
     """
-    processor = NarrativeTranscriptProcessor(
-        api_key=api_key, context_window_size=context_window_size
-    )
-    return processor.process_slides_dataframe_with_narrative(
-        df, output_dir, save_context
+    processor = UnifiedTranscriptProcessor(
+        api_key=api_key, use_narrative=True, context_window_size=context_window_size
     )
+    return processor.process_slides_dataframe(df, output_dir, save_context=save_context)