← Back to Portfolio

Build Log · ThePokeAlgorithm

How I Built
PokeAlgorithm
Lab V3

A full-stack analytics command center, AI voice engine, and content automation system — built to run my Pokémon TCG YouTube channel like a data lab.

Flask · Python ElevenLabs TTS Chart.js CapCut Integration WSL · Ubuntu
SCROLL

Introduction

Why I Built This

Running a data-driven Pokémon TCG YouTube channel means tracking a lot — card prices, view velocity, profit per episode, CTR, audience retention. I was bouncing between YouTube Studio, spreadsheets, TCGPlayer tabs, and my notes app just to plan one video. That was unsustainable.

So I built PokeAlgorithm Lab v3 — a custom Flask web application that lives locally on my machine and acts as a single command center for everything: analytics, content planning, SEO research, profit tracking, script building, and even AI voiceover generation.

This isn't a template or a no-code tool. Every feature was written specifically for how I make content. Data > luck. — The PokeAlgorithm Build Philosophy

Table of Contents

  1. Tech Stack Overview
  2. Project Setup & Structure
  3. Analytics Dashboard
  4. Smart Content Calendar
  5. Script Builder + CapCut
  6. Description Generator
  7. Competitor Title Analyzer
  8. Watchlist & Price Alerts
  9. Weekly Report Export
  10. Keyboard Shortcuts
  11. TTS Voice Engine
  12. Local Deployment on WSL

01 — Foundation

Tech Stack Overview

I chose tools I already knew and that were fast to iterate with. The entire stack is Python-first on the backend with vanilla JS and Chart.js on the frontend — no React, no build pipeline, no bloat.

Python 3.11 Flask Chart.js ElevenLabs API CapCut YouTube Studio CSVs pandas WSL Ubuntu argparse requests
🧪

Flask

Lightweight Python web framework. Perfect for a local-only tool — no auth, no deployment overhead, just routes and templates.

📊

Chart.js

All channel analytics charts — view velocity, CTR heatmaps, content type breakdowns — rendered client-side using real CSV data.

🎙️

ElevenLabs API

Powers the TTS voice engine. Custom voice settings tuned to my energetic NYC delivery style, outputting numbered MP3s per segment.

📁

YouTube Studio CSVs

The ground truth for all analytics. Real exports from YouTube Studio — views, CTR, watch time, impressions — fed directly into the dashboard.

02 — Project Setup

Folder Structure & Environment

The first step was laying out a clean folder structure and getting Flask running inside a Python virtual environment. Because I'm on WSL (Windows Subsystem for Linux), I had to work around PEP 668's restriction on installing packages system-wide.

bash
# Create and activate the virtual environment
python3 -m venv venv
source venv/bin/activate

# Install all dependencies
pip install flask pandas requests elevenlabs

The project folder was organized like this:

tree
pokealgorithm-lab/
├── app.py                 # Flask routes & logic
├── tts_engine.py          # ElevenLabs voice engine CLI
├── requirements.txt
├── data/
│   ├── Table_data.csv     # Per-video performance
│   ├── Chart_data.csv     # Daily view history (140 rows)
│   ├── Totals.csv         # 28-day view totals
│   └── profit_tracker.csv # Ad revenue + affiliate per episode
└── templates/
    ├── base.html
    ├── dashboard.html
    ├── calendar.html
    ├── script_builder.html
    └── ...
WSL Note: The zip file was extracted from the Windows Downloads folder at /mnt/c/Users/[username]/Downloads/ — a common trip-up when running WSL on Windows.

03 — Core Feature

Analytics Dashboard

The dashboard was the most important piece — it needed to show me, at a glance, how the channel was performing so I could make fast decisions. I loaded real YouTube Studio CSV exports and built every chart around actual numbers.

Key Components Built

1

View Velocity Chart

A line chart built from Chart_data.csv (140 rows of daily view data) showing how views ramp up and decay after each upload. This exposed a sharp Day 1 spike with rapid falloff — meaning the algorithm wasn't picking videos up for long-tail distribution.

2

Per-Video Performance Cards with Letter Grades

Each video from Table_data.csv got a card showing Views, Watch Time, CTR, and a calculated letter grade (A–F) based on a weighted score of those metrics. Story-driven titles scored consistently higher — which confirmed the "Profit or Cooked" framing strategy.

3

CTR Heatmap

Mapped Click-Through Rate against day of the week and hour of upload using data from the impressions column. Immediately showed which upload windows were underperforming.

4

Content Type Breakdown & Growth Goals Tracker

A donut chart breaking down content types (pack openings, market analysis, Shorts) by view share, plus a goal tracker showing progress toward monthly subscriber and view milestones.

python · flask route
@app.route('/dashboard')
def dashboard():
    df = pd.read_csv('data/Table_data.csv')
    chart_df = pd.read_csv('data/Chart_data.csv')

    # Calculate letter grade per video
    def grade(row):
        score = (row['Views'] * 0.4
               + row['Watch time (hours)'] * 0.3
               + row['Impressions click-through rate (%)'] * 0.3)
        if score >= 80: return 'A'
        elif score >= 65: return 'B'
        elif score >= 50: return 'C'
        else: return 'D'

    df['grade'] = df.apply(grade, axis=1)
    return render_template('dashboard.html',
                           videos=df.to_dict('records'),
                           chart_data=chart_df.to_json())

04 — Content Planning

Smart Content Calendar

The content calendar was built to reduce the guesswork of "what should I upload next?" It pulls in past video data, identifies gaps in the schedule, and shows urgency banners based on how long it's been since the last upload.

Key Features

A days-since-upload urgency banner turns yellow after 5 days and red after 10, nudging me to stay on a consistent cadence. Each slot on the calendar is color-coded by content type — pack openings (red), market analysis (neon green), Shorts (yellow) — so I can see the content mix at a glance.

Insight from the data: The calendar revealed I was uploading market analysis videos 3x more than pack openings, even though pack openings drove 60%+ of total views. Seeing the color distribution made this imbalance obvious immediately.

05 — Production Workflow

Script Builder + CapCut Timeline

This feature turned a plain script into a full CapCut production timeline — one of my favorite parts of the whole build. The idea: I write the episode script in the text area, hit Generate, and get back a timestamped editing plan I can follow inside CapCut.

1

Price Pop-Up Markers Every 30 Seconds

The builder automatically inserts "INSERT PRICE POP-UP" cue markers at 30-second intervals throughout the timeline, matching the CapCut checklist rule of showing real TCGPlayer/eBay data every 30 seconds.

2

Retention Hook Text Overlays Every 35 Seconds

Pattern-matched against the script to detect natural tension points and insert "RETENTION HOOK OVERLAY" cues every ~35 seconds, keeping watch time up.

3

FOMO Giveaway Tease at 80% Mark

Calculates the 80% timestamp from total video duration and auto-inserts a "FOMO GIVEAWAY TEASE" cue — the exact strategy used to spike audience retention near the end.

4

Exportable CSV Timeline

The full production timeline exports as a downloadable CSV with columns for Timestamp, Cue Type, Script Line, and Notes — ready to follow in CapCut or share with an editor.

python · timeline generator
def generate_capcut_timeline(script, duration_seconds):
    timeline = []
    words = script.split()
    words_per_second = len(words) / duration_seconds

    for t in range(0, duration_seconds, 30):
        timeline.append({
            'timestamp': fmt_time(t),
            'cue': 'PRICE POP-UP',
            'note': 'Insert TCGPlayer / eBay live price'
        })

    fomo_t = int(duration_seconds * 0.80)
    timeline.append({
        'timestamp': fmt_time(fomo_t),
        'cue': 'FOMO GIVEAWAY TEASE',
        'note': 'Drop the community hint'
    })

    return sorted(timeline, key=lambda x: x['timestamp'])

06 — SEO Workflow

Description Generator with Auto-Chapters

Writing YouTube descriptions was tedious and often skipped under time pressure. The Description Generator takes the episode title, main topics, and affiliate links, then outputs a fully formatted description with SEO keywords baked in — including auto-generated chapter timestamps.

The auto-chapters feature reads the CapCut timeline output and converts production cue timestamps into YouTube chapter markers. So if my price pop-up at 1:30 lines up with a major card pull, that becomes a chapter called 🔥 Big Pull — 1:30 automatically.

Why this matters: YouTube chapters improve watch time by letting viewers re-scrub to the best moments. Longer watch time = better algorithmic distribution. Automating chapters removed a step I was consistently skipping.

07 — Competitive Research

Competitor Title Analyzer

I built a title analysis tool directly into the SEO page so I could reverse-engineer what was working in the Pokémon TCG space without leaving the app.

How It Works

You paste in a list of competitor video titles. The tool runs four analysis passes:

📈

Keyword Frequency

Counts and ranks every meaningful word across all titles. Surfaces which terms dominate top-performing content in the niche.

🔗

Bigram Detection

Finds two-word phrases ("price spike", "pack opening", "profit or") that appear repeatedly — these are your high-signal title patterns.

🧩

Pattern Analysis

Identifies structural patterns: question-style titles, number-led titles, versus-framing, dollar-amount framing, etc.

🕳️

Content Gap ID

Cross-references competitor keywords against my own video titles to surface topics I haven't covered that competitors are using successfully.

08 — Market Tracking

Watchlist with Price History Sparklines

As a Pokémon TCG channel, card price movements are content. I need to know when a card spikes before everyone else does. The Watchlist page lets me track specific cards and sets, and stores price history over time.

Each card on the watchlist shows a mini sparkline chart of its price history, a percentage movement badge (green for up, red for down), and a customizable price alert threshold. If a card crosses the threshold, it surfaces with a highlighted alert badge on the dashboard.

javascript · sparkline
const spark = new Chart(ctx, {
  type: 'line',
  data: {
    labels: priceHistory.map(p => p.date),
    datasets: [{
      data: priceHistory.map(p => p.price),
      borderColor: priceDelta > 0
        ? '#00f5c4'
        : '#e63946',
      borderWidth: 1.5,
      pointRadius: 0,
      tension: 0.4,
      fill: true,
      backgroundColor: 'rgba(0,245,196,0.06)'
    }]
  },
  options: { plugins: { legend: { display: false } },
             scales: { x: { display: false },
                       y: { display: false } } }
});

09 — Reporting

Weekly Report Export

Every Sunday I want a clean summary of the week: top performing video, total views, average CTR, biggest price movement on the watchlist, and action items for next week. The Weekly Report feature generates all of this as a downloadable Markdown file.

The action items are auto-generated based on rules: if CTR dropped week-over-week, it adds "A/B test new thumbnail style." If no upload happened for 8+ days, it adds "Urgency: upload queue is empty." This made the weekly review actually useful rather than just a vanity metrics dump.

markdown output (example)
# PokeAlgorithm Weekly Report — Week of Apr 3, 2026

## Channel Stats
- Total Views This Week: 4,218
- Average CTR: 6.4%
- New Subscribers: +31
- Top Video: "Paradox Rift Box — Profit or Cooked?"

## Watchlist Alerts
- 🔴 Charizard ex (SV1): +22% — CONSIDER CONTENT

## Action Items
- Upload cadence: 9 days since last post. Post this week.
- CTR declined 1.2% — A/B test thumbnail this cycle.

10 — UX Polish

Global Keyboard Shortcuts

Once the app had 7+ pages, navigation was getting slow. I added a global keyboard shortcut system so I could jump anywhere without touching the mouse. Press ? to open the shortcuts modal.

⌨️

g + letter

g d → Dashboard, g c → Calendar, g s → Script Builder, g w → Watchlist

🔍

/ — Global Search

Focuses the SEO keyword search bar from anywhere in the app instantly.

📅

Alt+T — New Task

Opens the content calendar task creator modal without navigating away from the current page.

? — Shortcuts Modal

Displays all available shortcuts in a full-screen overlay. Press Esc to dismiss from any state.

11 — Voice Automation

TTS Voice Engine (tts_engine.py)

Beyond the web app, I built a standalone command-line TTS engine that converts my episode scripts into AI voiceover audio files using the ElevenLabs API. This was designed to match my exact delivery style: energetic, NYC-paced, with specific hype phrases baked into the voice settings.

Voice Settings Tuned to the Brand

ElevenLabs exposes stability, similarity boost, and style parameters for each generation call. After testing, I landed on:

python · elevenlabs config
VOICE_SETTINGS = {
    "stability": 0.35,        # Lower = more energetic variation
    "similarity_boost": 0.85,  # Stay close to voice clone
    "style": 0.60,             # Expressive, not robotic
    "use_speaker_boost": True
}

BRAND_OPENERS = [
    "Welcome back to the Lab.",
    "What's good Lab fam.",
    "Lock in, welcome to the Lab."
]

How the CLI Works

The script accepts a plain text file with tagged segments and outputs numbered MP3 files plus a JSON manifest for CapCut import.

bash · usage
# Basic usage — generate voiceover from script
python tts_engine.py --input episode_07.txt --output ./audio/

# Dry-run: validate script parsing without calling API
python tts_engine.py --input episode_07.txt --dry-run

# Batch mode from CSV (per-segment voice control)
python tts_engine.py --csv segments.csv --output ./audio/

Output Structure

output files
audio/
├── 01_intro.mp3
├── 02_price_check.mp3
├── 03_pull_reaction.mp3
├── 04_outro.mp3
└── manifest.json        # Segment metadata for CapCut

The manifest.json stores each segment's filename, duration, and script text — structured so it can be dropped into a CapCut import script or referenced while editing.

Dry-run pattern: The --dry-run flag was critical during development. It validates all script parsing and file I/O logic without burning ElevenLabs API credits on every test run. This is a pattern I now use in any CLI tool that hits a paid API.

12 — Running It Locally

Deployment on WSL / Ubuntu

Everything runs locally on my Windows machine via WSL (Windows Subsystem for Linux) with Ubuntu. No cloud hosting, no always-on server — just a Python venv and a browser tab on localhost:8080.

1

Extract the Project

Unzip the project files from the Windows Downloads folder, accessible in WSL at /mnt/c/Users/[username]/Downloads/.

2

Create the Virtual Environment

WSL Ubuntu blocks system-wide pip installs (PEP 668). Solution: python3 -m venv venv && source venv/bin/activate.

3

Install Dependencies

With the venv active, pip install -r requirements.txt works cleanly. Includes Flask, pandas, requests, and elevenlabs.

4

Launch on Port 8080

Port 5000 conflicts with macOS AirPlay (and other services). The app runs on flask run --port 8080 — accessible at http://localhost:8080.

bash · full launch sequence
cd /mnt/c/Users/smanbari/Downloads/pokealgorithm-lab
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
flask run --port 8080

Takeaways

What I Learned Building This

The biggest lesson: build for your actual workflow, not a hypothetical one. Every feature in Lab v3 came from a real pain point — a tab I kept forgetting, a calculation I kept redoing, a decision I kept making without data.

Technically, the modular file approach (separate CSVs, separate route files, standalone CLI tools) made iteration much faster than a monolithic script would have. The dry-run pattern saved API credits and made testing feel safe. And Flask — boring as it sounds — was exactly the right call. No framework overhead, just Python logic and a browser.

The channel improved too. Seeing view decay data made me rethink how I was titling videos. The CTR heatmap changed when I upload. The script builder made me more consistent with retention hooks. Building the tool made me better at the job the tool was supposed to help.

Data > luck. Always. — ThePokeAlgorithm