A Flask web application designed to help automate social media promotion for your content. This tool automatically syncs with podcast, blog, and YouTube RSS feeds, providing an interface for company employees to easily share new content on social media.
- Automatic content syncing from RSS feeds (podcasts, blogs, and YouTube videos)
- Clean, modern web interface for viewing content
- Items displayed with title, description, and publication date
- Direct links to original content
- Integration with Okta for single sign-on, or normal email/password authentication
- Automatically generates social media posts, taking each person's specific context into account
- Has a fully "autonomous" mode that allows for 100% automated social media promotion
This application follows the Model-View-Template (MVT) architecture pattern:
- Models: Defined in the
models
package, each in its own file, representing the data structure - Views: Located in the
views/
package, containing:main.py
: Main page routesapi.py
: API endpoints for promotionauth.py
: Standard authentication routesokta_auth.py
: Okta SSO authentication routes
- Templates: Stored in the
templates/
directory
The application is structured as follows:
app.py
: Application factory and configurationextensions.py
: Flask extensions initializationmodels/
: Database models organized by entity__init__.py
: Imports and exports all modelsuser.py
: User modelepisode.py
: Podcast episode modelpost.py
: Blog post modelvideo.py
: YouTube video model
cli/
: Command-line interface commandshelpers/
: Utility functions and modulesmigrations/
: Database migration filesviews/
: View functions organized by feature
- Python 3.12 or newer
- pip (Python package installer)
- Virtual environment tool (venv)
- Clone the repository:
git clone <repository-url>
cd <repository-directory>
- Create a virtual environment:
# On macOS/Linux
python -m venv venv
source venv/bin/activate
# On Windows
python -m venv venv
venv\Scripts\activate
- Install dependencies:
pip install -r requirements.txt
- Initialize the database:
# First, set the Flask application
export FLASK_APP=app.py # On Windows: set FLASK_APP=app.py
# Then create the database tables
flask init-db
Before running the application, you need to set up the following environment variables:
# Flask secret key (for session security)
export SECRET_KEY="your-secure-random-key" # On Windows: set SECRET_KEY="your-secure-random-key"
# OpenAI API key (required for generating social media content)
export OPENAI_API_KEY="your-openai-api-key" # On Windows: set OPENAI_API_KEY="your-openai-api-key"
# Arcade API key (required for social media posting)
export ARCADE_API_KEY="your-arcade-api-key" # On Windows: set ARCADE_API_KEY="your-arcade-api-key"
You can generate a secure random key for SECRET_KEY using:
# On macOS/Linux
openssl rand -hex 32
# On Windows (in PowerShell)
-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 32 | ForEach-Object {[char]$_})
# Database configuration (defaults to SQLite)
export DATABASE_URL="sqlite:///ai-promoter.db" # Change if using PostgreSQL or other database
# Enable/disable Okta SSO (defaults to false)
export OKTA_ENABLED="false" # Set to "true" to enable Okta SSO
If you want to use Okta SSO for authentication, you'll need to set these additional variables:
# Okta application credentials
export OKTA_CLIENT_ID="your-okta-client-id"
export OKTA_CLIENT_SECRET="your-okta-client-secret"
# Okta domain with authorization server path
export OKTA_ISSUER="https://your-okta-domain.okta.com/oauth2/default"
# Redirect URI (must match what you set in Okta)
export OKTA_REDIRECT_URI="http://localhost:5000/auth/okta/callback"
See the Okta SSO section for details on setting up an Okta application.
- Start the Flask development server:
python app.py
- Open your browser and visit: http://localhost:5000
The application includes CLI commands to sync content from RSS feeds. You can run these manually or set them up as scheduled tasks.
To sync podcast episodes manually:
# First, ensure you're in your virtual environment
source venv/bin/activate # On Windows: venv\Scripts\activate
# Set the Flask application
export FLASK_APP=app.py # On Windows: set FLASK_APP=app.py
# Run the sync command with your podcast's RSS feed URL
flask sync-podcast "YOUR_PODCAST_RSS_URL"
# For example, for The Secure Developer podcast:
flask sync-podcast "https://feeds.simplecast.com/47yfLpm0"
To sync blog posts manually:
# First, ensure you're in your virtual environment
source venv/bin/activate # On Windows: venv\Scripts\activate
# Set the Flask application
export FLASK_APP=app.py # On Windows: set FLASK_APP=app.py
# Run the sync command with your blog's RSS feed URL
flask sync-blog "YOUR_BLOG_RSS_URL"
# For example, for the Snyk blog:
flask sync-blog "https://snyk.io/blog/feed/"
To sync YouTube videos manually:
# First, ensure you're in your virtual environment
source venv/bin/activate # On Windows: venv\Scripts\activate
# Set the Flask application
export FLASK_APP=app.py # On Windows: set FLASK_APP=app.py
# Run the sync command with your YouTube channel's RSS feed URL
flask sync-youtube "YOUR_YOUTUBE_CHANNEL_RSS_URL"
# For example:
flask sync-youtube "https://www.youtube.com/feeds/videos.xml?channel_id=UCh4dJzctb0NhSibjU-e2P6w"
To automatically sync new episodes, you can set up a cron job (on Unix-based systems) or a scheduled task (on Windows).
- Create a shell script named
sync_episodes.sh
:
#!/bin/bash
cd /path/to/your/ai-promoter
source venv/bin/activate
export FLASK_APP=app.py
flask sync-podcast "YOUR_PODCAST_RSS_URL"
- Make it executable:
chmod +x sync_episodes.sh
- Add to crontab (runs every hour):
0 * * * * /path/to/your/sync_episodes.sh
- Create a batch file named
sync_episodes.bat
:
cd C:\path\to\your\ai-promoter
call venv\Scripts\activate
set FLASK_APP=app.py
flask sync-podcast "YOUR_PODCAST_RSS_URL"
- Use Windows Task Scheduler to run this batch file on your desired schedule.
The application supports both SQLite (default for development) and PostgreSQL (recommended for production) databases.
By default, SQLite is used in development mode with the database file stored at ai-promoter.db
.
You can customize the database configuration using the DATABASE_URL
environment variable:
# PostgreSQL configuration (recommended for production)
export DATABASE_URL="postgresql://username:password@localhost:5432/ai_promoter"
# Custom SQLite database path
export DATABASE_URL="sqlite:///path/to/your/custom.db"
To initialize the database for the first time:
# Set the Flask application
export FLASK_APP=app.py # On Windows: set FLASK_APP=app.py
# Create the database tables
flask init-db
For PostgreSQL, make sure the database exists before running init-db
.
When you make changes to database models, you'll need to create and apply migrations:
# Create a migration after changing models
flask db migrate -m "Description of your changes"
# Apply pending migrations
flask db upgrade
Other useful migration commands:
# Show current migration status
flask db current
# Roll back the last migration
flask db downgrade
# Show migration history
flask db history
This section provides instructions for deploying the application to Heroku, a popular cloud platform.
The easiest way to deploy AI Promoter is with the Heroku Deploy button below. This will create your own instance of the application with all the necessary configuration:
What this does:
- Creates a new Heroku application with the required buildpacks
- Sets up a PostgreSQL database automatically
- Installs the Heroku Scheduler add-on
- Prompts you to enter your API keys and configuration
- Deploys the code and runs initial database setup
After deployment:
- Configure scheduled jobs for content syncing:
- Open the Scheduler:
heroku addons:open scheduler -a your-app-name
- Add jobs for podcasts, blogs, and YouTube as described in the Scheduler section
- Open the Scheduler:
- Set up autonomous social posting if desired (see Autonomous Posting section)
- Visit your new application:
heroku open -a your-app-name
If you prefer to deploy manually or need more control over the deployment process, follow these steps:
- Heroku CLI installed
- Git installed
- Heroku account
-
Login to Heroku
heroku login
-
Create a new Heroku application
heroku create your-app-name
-
Add Heroku PostgreSQL add-on
heroku addons:create heroku-postgresql:essential-0
This will provision a PostgreSQL database and set the
DATABASE_URL
environment variable automatically. -
Specify Python version
Create a file named
runtime.txt
in the root directory with the following content:python-3.11.9
This ensures Heroku uses Python 3.11.9 instead of the latest version (3.13+), which may have compatibility issues with SQLAlchemy and Flask-Migrate.
Note: If you encounter typing-related errors like
AssertionError: Class directly inherits TypingOnly but has additional attributes
, it's a sign of Python version incompatibility. Make sure you're using theruntime.txt
file to specify a compatible Python version. -
Set required environment variables
# Set a secure random secret key heroku config:set SECRET_KEY=$(openssl rand -hex 32) # Set OpenAI API key heroku config:set OPENAI_API_KEY=your-openai-api-key # Set Arcade API key if using social media posting heroku config:set ARCADE_API_KEY=your-arcade-api-key
-
Create a Procfile
Create a file named
Procfile
(no extension) in the root directory with the following content:web: gunicorn "app:create_app()" release: FLASK_APP=app.py flask db upgrade
This tells Heroku how to run your application:
web
: Specifies the command to start your web server (using Gunicorn)release
: Specifies commands that run automatically when a new version is deployed (running database migrations)
-
Add Gunicorn to requirements.txt
Ensure
gunicorn
is in your requirements.txt file:gunicorn>=21.2.0
-
Deploy to Heroku
git add . git commit -m "Prepare for Heroku deployment" git push heroku main
-
Bootstrap the database on Heroku
After the first deployment, you need to set up and initialize the database:
# Run migrations to create all database tables heroku run "FLASK_APP=app.py flask db upgrade" # Initialize the database with required tables and initial data heroku run "FLASK_APP=app.py flask init-db"
Troubleshooting SQLAlchemy/typing errors:
If you encounter errors like this when running database commands:
AssertionError: Class directly inherits TypingOnly but has additional attributes {'__firstlineno__', '__static_attributes__'}
This is typically caused by Python version incompatibility. To fix it:
-
Create or update the
runtime.txt
file with a compatible Python version:python-3.11.9
-
Deploy the changes:
git add runtime.txt git commit -m "Specify Python 3.11.9 for compatibility" git push heroku main
-
After deployment completes, try the database commands again.
Other database troubleshooting commands:
# Check database connection info heroku pg:info # View database credentials heroku pg:credentials:url # Connect to the database directly for troubleshooting heroku pg:psql
For a fresh start, you can reset the database (
⚠️ caution - this deletes all data):# Reset the database (removes all data) heroku pg:reset DATABASE --confirm your-app-name # Then run migrations and initialization again heroku run "FLASK_APP=app.py flask db upgrade" heroku run "FLASK_APP=app.py flask init-db"
-
-
Ensure web dyno is running
After deploying, make sure your web dyno is running to serve the application:
# Check current dynos heroku ps # If no web dyno is running, start one heroku ps:scale web=1 # To stop the web dyno (e.g., to avoid charges when not in use) heroku ps:scale web=0
You can also manage dynos through the Heroku Dashboard by:
- Going to your app's "Resources" tab
- Under "Dynos", clicking the edit (pencil) icon
- Moving the slider to enable/disable the web dyno
- Confirming the change
-
Set up scheduled content syncing
To automate content syncing and social media posting, you'll use the Heroku Scheduler add-on:
# Install the Heroku Scheduler add-on heroku addons:create scheduler:standard
Then open the scheduler dashboard to configure your scheduled tasks:
heroku addons:open scheduler
In the Heroku Scheduler dashboard:
- Click on Create Job
- Set the frequency (recommended: Every hour for content syncing)
- Enter the command to run (see examples below)
- Click Save Job
Repeat this process for each type of content you want to sync.
Sync podcast episodes hourly:
FLASK_APP=app.py flask sync-podcast "https://feeds.simplecast.com/47yfLpm0"
Sync blog posts hourly:
FLASK_APP=app.py flask sync-blog "https://snyk.io/blog/feed/"
Sync YouTube videos hourly:
FLASK_APP=app.py flask sync-youtube "https://www.youtube.com/feeds/videos.xml?channel_id=UCh4dJzctb0NhSibjU-e2P6w"
To enable autonomous social media posting for newly discovered content, add this scheduled job:
- In the Scheduler dashboard, click Create Job
- Set frequency to Every hour (runs 30 minutes after content syncing)
- Enter this command:
The
FLASK_APP=app.py flask auto-post --limit=3
--limit
parameter controls the maximum number of posts to create per run
- Stagger your jobs: Schedule content syncing to run at the top of the hour and auto-posting to run 30 minutes later
- Monitor usage: Check your application logs to ensure tasks are completing successfully
- Adjust frequency: For high-volume feeds, consider more frequent syncing (every 10 minutes)
- Check logs: If a job fails, view logs with
heroku logs --ps scheduler
To check if your scheduled jobs are running properly:
# View recent scheduler logs heroku logs --ps scheduler # View all application logs heroku logs --tail
-
Open your application
heroku open
-
Sign in to your Okta Developer Console
Go to https://developer.okta.com/ and sign in to your account.
-
Create a new application
- Click on "Applications" in the top menu
- Click "Create App Integration"
- Select "OIDC - OpenID Connect" as the sign-in method
- Select "Web Application" as the application type
- Click "Next"
-
Configure the application
- Name: Enter a name for your application (e.g., "AI Promoter")
- Logo (optional): Upload your application logo
- Sign-in redirect URIs:
https://your-app-name.herokuapp.com/auth/okta/callback
- Sign-out redirect URIs:
https://your-app-name.herokuapp.com
- Assignments:
- Select "Allow everyone in your organization to access" for all employees, or
- Select "Limit access to selected groups" to restrict access
-
Save the application
After saving, Okta will provide you with:
- Client ID
- Client Secret
- Okta Domain
Save these for the next step.
-
Set Okta environment variables
# Enable Okta SSO heroku config:set OKTA_ENABLED=true # Okta application credentials heroku config:set OKTA_CLIENT_ID=your-client-id heroku config:set OKTA_CLIENT_SECRET=your-client-secret # Okta domain with authorization server path # Format: https://your-okta-domain.okta.com/oauth2/default heroku config:set OKTA_ISSUER=https://your-okta-domain.okta.com/oauth2/default # Redirect URI (must match what you set in Okta) heroku config:set OKTA_REDIRECT_URI=https://your-app-name.herokuapp.com/auth/okta/callback
-
Deploy the changes
git push heroku main
-
Test Okta SSO
Visit your application and click on the "Sign in with Company SSO" button to test the Okta integration.
If you encounter issues with Okta SSO:
-
Check environment variables
Ensure all Okta environment variables are set correctly:
heroku config:get OKTA_CLIENT_ID heroku config:get OKTA_ISSUER heroku config:get OKTA_REDIRECT_URI
-
Check Okta application settings
- Verify that the redirect URIs match exactly
- Ensure the application is assigned to the appropriate users or groups
- Check if the authorization server in the issuer URL is correct
-
Check Heroku logs
heroku logs --tail
-
Update callback URL in Okta
If your Heroku app URL changes, remember to update the callback URL in your Okta application settings.
- The main application logic is in
app.py
- Database models are defined in the
models
package, with each model in its own file - CLI commands are in
cli.py
- HTML templates are in the
templates
directory
- Fork the repository
- Create a feature branch
- Commit your changes
- Push to the branch
- Create a Pull Request