Skip to content
PeterYousefiPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Lumina — AI Marketing Platform

Portfolio demonstration project. Runs entirely locally with Flask. IBM watsonx.ai (Granite) acts as the marketing reasoning engine, orchestrating a complete campaign across copy, imagery, and distribution in a single cinematic, five-step workflow.


Problem Statement

Small business owners are their own marketers — but consistent local marketing demands time, budget, and expertise most don't have. Identifying relevant nearby events, writing platform-specific copy for Instagram, Facebook, and email, generating professional imagery, and coordinating publishing across channels currently takes hours of manual work per campaign. Most small businesses either skip it entirely or produce inconsistent, low-impact content.


Solution Description

Lumina is an end-to-end AI marketing platform purpose-built for small businesses. A business owner describes their business once; Lumina's 5-step guided workflow takes them from that description to a fully drafted, editable, ready-to-publish campaign — marketing strategy, Instagram caption, Facebook post, HTML email, campaign image, and direct one-click publishing — in minutes, not hours. Every generated field is editable and individually regeneratable before anything leaves the app.


Challenge Theme

Challenge Theme: Reimagine Creative Industries with AI (July Challenge)


How IBM Bob Was Used

Lumina was built end-to-end using IBM Bob as the primary development partner throughout the entire project.

Bob was used to:

  • Plan the architecture — designing the 5-step wizard flow, the Flask app factory structure, the service layer separation, and the session/storage strategy
  • Generate and iterate on the Flask backend — all route handlers in app/routes/api.py, the storage layer in storage.py, and the app factory in app/__init__.py were written and refined through Bob
  • Build the multi-provider image fallback logic — the waterfall chain in app/services/image_gen.py (OpenAI → Google Gemini → Hugging Face → mock) was designed and implemented with Bob
  • Debug across integration modules — fixing the Instagram async container-readiness polling bug, the Granite JSON repair pipeline, the session cookie overflow caused by storing base64 image data, and the BeautifulSoup email HTML sanitisation were all diagnosed and resolved with Bob
  • Refactor throughout development — dead code removal, consolidating duplicate route files, moving large session payloads to campaign_history.json, and tightening the prompt template were all driven by Bob

Important distinction: IBM Bob is the development tool used to build Lumina. IBM Granite (ibm/granite-3-8b-instruct via watsonx.ai) is the runtime AI model running inside the finished app — it generates the marketing strategy, captions, email copy, and image prompts for each campaign. Bob built the platform; Granite powers it.


Architecture

Business Owner
       │
       ▼
 Describe Business          ← Step 1  (index.html · Step 1 form)
       │
       ▼
 Discover Nearby Events     ← Step 2  (app/services/events.py)
   • PredictHQ API          real festivals, concerts, sports, markets
   • Nager.Date API         public holidays (free, no key required)
   • Universal Observances  worldwide awareness days, seasons, shopping events
       │
       ▼
 IBM Granite Analyses       ← Step 3  (app/services/granite.py → watsonx.ai)
   • business context
   • current promotions
   • target audience
   • selected nearby events
       │
       ▼
 Granite Generates
   • Marketing strategy
   • Instagram caption
   • Facebook post
   • HTML email body
   • Campaign slogan
   • Detailed image prompt
       │
       ▼
 Owner Reviews & Edits      ← Step 3  (every field is editable; regenerate any piece)
       │
       ▼
 Generate Campaign Image    ← Step 4  (app/services/image_gen.py)
   Multi-Provider Waterfall:
     1. OpenAI DALL-E 3 / DALL-E 2
     2. Google Gemini image generation
     3. Hugging Face Inference API (SDXL or configured model)
     4. Mock PNG — built-in, zero keys required
       │
       ▼
 Owner Previews & Publishes ← Step 5
   • Post to Instagram  (Meta Graph API)
   • Post to Facebook   (Meta Graph API)
   • Send email         (SendGrid → predetermined EMAIL_TO recipient)

Project Structure

lumina/
│
├── app/
│   ├── __init__.py               # Flask app factory
│   ├── routes/
│   │   ├── main.py               # Page routes
│   │   └── api.py                # JSON API consumed by the frontend
│   ├── services/
│   │   ├── events.py             # PredictHQ + Nager.Date + observances
│   │   ├── granite.py            # IBM watsonx.ai Granite integration
│   │   ├── image_gen.py          # Multi-provider image waterfall
│   │   └── social.py             # Instagram · Facebook · SendGrid
│   ├── static/
│   │   ├── css/lumina.css        # Full cinematic design system + motion
│   │   └── js/lumina.js          # Frontend orchestration (vanilla JS)
│   └── templates/
│       ├── index.html            # 5-step workflow UI
│       ├── history.html          # Campaign history list
│       ├── campaign_detail.html  # Single campaign view
│       ├── 404.html
│       └── 500.html
│
├── config.py                     # Centralised config loaded from .env
├── demo_mode.py                  # Realistic mock data when API keys are absent
├── utils.py                      # Logging setup, ID generation, helpers
├── storage.py                    # campaign_history.json read/write (no database)
│
├── campaign_history.json         # All campaigns stored here as JSON
├── generated/                    # Generated campaign images saved here
│
├── requirements.txt
├── .env.example
├── .gitignore
└── README.md

Quick Start

1. Clone and create a virtual environment

git clone <repo-url>
cd lumina
python3 -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate

2. Install dependencies

pip install -r requirements.txt

3. Configure environment

cp .env.example .env
# Edit .env — fill in any keys you have. The app runs without all of them.

4. Run

python run.py

Open http://127.0.0.1:5000


API Keys

Service Environment Variable(s) Where to get it Required?
IBM watsonx.ai (Granite) WATSONX_API_KEY, WATSONX_PROJECT_ID cloud.ibm.com Recommended — falls back to rich mock data
PredictHQ (events, concerts, festivals, sports) PREDICTHQ_API_KEY control.predicthq.com Optional — free public holidays always load
API Ninjas (public holidays) API_NINJAS_KEY api-ninjas.com Optional
OpenAI Images (DALL-E 3 / DALL-E 2) OPENAI_API_KEY platform.openai.com/api-keys Optional — waterfall falls through to next provider
Google Gemini image generation GOOGLE_API_KEY aistudio.google.com/apikey Optional
Hugging Face Inference API HUGGINGFACE_API_KEY huggingface.co/settings/tokens Optional
Instagram Graph API INSTAGRAM_ACCESS_TOKEN, INSTAGRAM_ACCOUNT_ID Meta for Developers Optional
Facebook Graph API FACEBOOK_ACCESS_TOKEN, FACEBOOK_PAGE_ID Meta for Developers Optional
SendGrid Email SENDGRID_API_KEY, EMAIL_FROM, EMAIL_TO sendgrid.com Optional — email sends to the predetermined EMAIL_TO address

Zero-key mode: the app runs end-to-end without a single API key configured. Granite falls back to realistic mock campaigns; images fall back to a built-in mock PNG; events load from free public APIs (Nager.Date + universal observances). Missing credentials surface as clear UI messages rather than crashes.


Image Generation — Multi-Provider Waterfall

Lumina tries image providers in priority order and uses the first one that succeeds:

  1. OpenAI DALL-E 3 / DALL-E 2 — highest quality; requires OPENAI_API_KEY
  2. Google Gemini (gemini-2.0-flash-preview-image-generation) — requires GOOGLE_API_KEY
  3. Hugging Face Inference API (default model: stabilityai/stable-diffusion-xl-base-1.0) — requires HUGGINGFACE_API_KEY
  4. Mock PNG — a valid 64×64 gold PNG generated entirely in Python; always works with zero keys

Configure which model each provider uses via the corresponding env variables in .env:

OPENAI_IMAGE_MODEL=dall-e-3
OPENAI_IMAGE_SIZE=1024x1024
GOOGLE_IMAGE_MODEL=gemini-2.0-flash-preview-image-generation
HUGGINGFACE_MODEL=stabilityai/stable-diffusion-xl-base-1.0

DRY_RUN Mode

Set DRY_RUN=true in your .env to test the full publishing workflow without sending any real requests to Meta or SendGrid.

DRY_RUN=true

When DRY_RUN is enabled:

  • The /api/publish endpoint logs the full API payload to the console instead of making live calls.
  • The UI receives a simulated success response so you can verify the end-to-end flow.
  • No posts are published to Instagram or Facebook.
  • No emails are sent via SendGrid.

This is the recommended setting when demoing the app, running CI checks, or testing with incomplete credentials.


Event Discovery

Events are fetched from three sources simultaneously, then scored, deduplicated, and ranked:

Source Notes
PredictHQ Real nearby events (festivals, concerts, sports, expos, community) within a configurable radius. Requires PREDICTHQ_API_KEY.
Nager.Date Worldwide public holidays — free, no key required.
Universal Observances 25+ curated global awareness days and shopping events (Valentine's Day, Earth Day, Black Friday, etc.) that always apply regardless of location.

Scoring weights recency, proximity, and event rank to surface the most impactful opportunities.


Campaign History

Every campaign generated is automatically appended to campaign_history.json. No database required. The history page at /history lists all past campaigns; individual campaigns can be viewed at /history/<campaign_id> and deleted.


Design Principles

  • Cinematic and minimal — #0a0908 dark background, warm gold accents, Playfair Display wordmark
  • IBM Granite as creative partner — AI writes, the owner approves and edits
  • No dashboards — pure linear workflow, step by step
  • Owner always in control — every generated field is editable and individually regeneratable before anything is published
  • Motion with restraint — ambient light, animated step connector, shimmer loading states; all wrapped in @media (prefers-reduced-motion: no-preference)

Logging

Logs are written to both the console and lumina.log (rotating, 5 MB × 3 backups). Set LOG_LEVEL=DEBUG in .env for verbose output including full Granite prompts and responses.


Built as a portfolio demonstration of IBM watsonx.ai Granite capabilities in a real-world, production-grade marketing workflow.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages