WIP: AI Podcast Maker and YouTube Creator Studio integration

This commit is contained in:
ajaysi
2025-12-10 09:37:55 +05:30
parent 31f078c763
commit 81590cf4db
75 changed files with 11879 additions and 1380 deletions

View File

@@ -0,0 +1,149 @@
"""
Database Migration Script for Podcast Maker
Creates the podcast_projects table for cross-device project persistence.
"""
import sys
import os
from pathlib import Path
# Add the backend directory to Python path
backend_dir = Path(__file__).parent.parent
sys.path.insert(0, str(backend_dir))
from sqlalchemy import create_engine, text
from loguru import logger
import traceback
# Import models - PodcastProject uses SubscriptionBase
from models.subscription_models import Base as SubscriptionBase
from models.podcast_models import PodcastProject
from services.database import DATABASE_URL
def create_podcast_tables():
"""Create podcast-related tables."""
try:
# Create engine
engine = create_engine(DATABASE_URL, echo=False)
# Create all tables (PodcastProject uses SubscriptionBase, so it will be created)
logger.info("Creating podcast maker tables...")
SubscriptionBase.metadata.create_all(bind=engine)
logger.info("✅ Podcast tables created successfully")
# Verify table was created
display_setup_summary(engine)
except Exception as e:
logger.error(f"❌ Error creating podcast tables: {e}")
logger.error(traceback.format_exc())
raise
def display_setup_summary(engine):
"""Display a summary of the created tables."""
try:
with engine.connect() as conn:
logger.info("\n" + "="*60)
logger.info("PODCAST MAKER SETUP SUMMARY")
logger.info("="*60)
# Check if table exists
check_query = text("""
SELECT name FROM sqlite_master
WHERE type='table' AND name='podcast_projects'
""")
result = conn.execute(check_query)
table_exists = result.fetchone()
if table_exists:
logger.info("✅ Table 'podcast_projects' created successfully")
# Get table schema
schema_query = text("""
SELECT sql FROM sqlite_master
WHERE type='table' AND name='podcast_projects'
""")
result = conn.execute(schema_query)
schema = result.fetchone()
if schema:
logger.info("\n📋 Table Schema:")
logger.info(schema[0])
# Check indexes
indexes_query = text("""
SELECT name FROM sqlite_master
WHERE type='index' AND tbl_name='podcast_projects'
""")
result = conn.execute(indexes_query)
indexes = result.fetchall()
if indexes:
logger.info(f"\n📊 Indexes ({len(indexes)}):")
for idx in indexes:
logger.info(f"{idx[0]}")
else:
logger.warning("⚠️ Table 'podcast_projects' not found after creation")
logger.info("\n" + "="*60)
logger.info("NEXT STEPS:")
logger.info("="*60)
logger.info("1. The podcast_projects table is ready for use")
logger.info("2. Projects will automatically sync to database after major steps")
logger.info("3. Users can resume projects from any device")
logger.info("4. Use the 'My Projects' button in the Podcast Dashboard to view saved projects")
logger.info("="*60)
except Exception as e:
logger.error(f"Error displaying summary: {e}")
def check_existing_table(engine):
"""Check if podcast_projects table already exists."""
try:
with engine.connect() as conn:
check_query = text("""
SELECT name FROM sqlite_master
WHERE type='table' AND name='podcast_projects'
""")
result = conn.execute(check_query)
table_exists = result.fetchone()
if table_exists:
logger.info(" Table 'podcast_projects' already exists")
logger.info(" Running migration will ensure schema is up to date...")
return True
return False
except Exception as e:
logger.error(f"Error checking existing table: {e}")
return False
if __name__ == "__main__":
logger.info("🚀 Starting podcast maker database migration...")
try:
# Create engine to check existing table
engine = create_engine(DATABASE_URL, echo=False)
# Check existing table
table_exists = check_existing_table(engine)
# Create tables (idempotent - won't recreate if exists)
create_podcast_tables()
logger.info("✅ Migration completed successfully!")
except KeyboardInterrupt:
logger.info("Migration cancelled by user")
sys.exit(0)
except Exception as e:
logger.error(f"❌ Migration failed: {e}")
traceback.print_exc()
sys.exit(1)

View File

@@ -0,0 +1,141 @@
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from loguru import logger
from sqlalchemy import text
from services.database import SessionLocal, engine
# Import models to ensure they are registered and we can recreate them
from models.content_planning import (
ContentStrategy, ContentGapAnalysis, ContentRecommendation, AIAnalysisResult,
Base as ContentPlanningBase
)
from models.enhanced_calendar_models import (
ContentCalendarTemplate, AICalendarRecommendation, ContentPerformanceTracking,
ContentTrendAnalysis, ContentOptimization, CalendarGenerationSession,
Base as EnhancedCalendarBase
)
def migrate_table(db, table_name, base_metadata):
"""Migrate user_id column for a specific table from INTEGER to VARCHAR(255)."""
try:
logger.info(f"Checking table: {table_name}")
# Check if table exists
check_table_query = f"SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}';"
result = db.execute(text(check_table_query))
if not result.scalar():
logger.warning(f"Table '{table_name}' does not exist. Skipping check, but will try to create it.")
# If it doesn't exist, we can just create it with the new schema
try:
base_metadata.create_all(bind=engine, tables=[base_metadata.tables[table_name]], checkfirst=True)
logger.success(f"✅ Created {table_name} with new schema")
except Exception as e:
logger.error(f"Failed to create {table_name}: {e}")
return True
# Check current column type
check_column_query = f"SELECT type FROM pragma_table_info('{table_name}') WHERE name = 'user_id';"
result = db.execute(text(check_column_query))
current_type = result.scalar()
if not current_type:
logger.info(f"Table {table_name} does not have user_id column. Skipping.")
return True
if 'varchar' in current_type.lower() or 'text' in current_type.lower():
logger.info(f"{table_name}.user_id is already {current_type}. No migration needed.")
return True
logger.info(f"Migrating {table_name}.user_id from {current_type} to VARCHAR...")
# Backup data
backup_table = f"{table_name}_backup"
db.execute(text(f"DROP TABLE IF EXISTS {backup_table}")) # Ensure clean state
db.execute(text(f"CREATE TABLE {backup_table} AS SELECT * FROM {table_name}"))
# Drop old table
db.execute(text(f"DROP TABLE {table_name}"))
# Recreate table
# We need to find the Table object in metadata
table_obj = base_metadata.tables.get(table_name)
if table_obj is not None:
base_metadata.create_all(bind=engine, tables=[table_obj], checkfirst=False)
else:
logger.error(f"Could not find Table object for {table_name} in metadata")
# Restore backup and abort
db.execute(text(f"ALTER TABLE {backup_table} RENAME TO {table_name}"))
return False
# Restore data
# We need to list columns to construct INSERT statement, excluding those that might be auto-generated if needed,
# but usually for restore we want all.
# However, we need to cast user_id to TEXT.
# Get columns from backup
columns_result = db.execute(text(f"PRAGMA table_info({backup_table})"))
columns = [row[1] for row in columns_result]
cols_str = ", ".join(columns)
# Construct select list with cast
select_parts = []
for col in columns:
if col == 'user_id':
select_parts.append("CAST(user_id AS TEXT)")
else:
select_parts.append(col)
select_str = ", ".join(select_parts)
restore_query = f"INSERT INTO {table_name} ({cols_str}) SELECT {select_str} FROM {backup_table}"
db.execute(text(restore_query))
# Drop backup
db.execute(text(f"DROP TABLE {backup_table}"))
db.commit()
logger.success(f"✅ Migrated {table_name} successfully")
return True
except Exception as e:
logger.error(f"❌ Failed to migrate {table_name}: {e}")
db.rollback()
return False
def migrate_all():
db = SessionLocal()
try:
# Content Planning Tables
cp_tables = [
"content_strategies",
"content_gap_analyses",
"content_recommendations",
"ai_analysis_results"
]
for table in cp_tables:
migrate_table(db, table, ContentPlanningBase.metadata)
# Enhanced Calendar Tables
ec_tables = [
"content_calendar_templates",
"ai_calendar_recommendations",
"content_performance_tracking",
"content_trend_analysis",
"content_optimizations",
"calendar_generation_sessions"
]
for table in ec_tables:
migrate_table(db, table, EnhancedCalendarBase.metadata)
finally:
db.close()
if __name__ == "__main__":
logger.info("Starting comprehensive user_id migration...")
migrate_all()
logger.info("Migration finished.")

View File

@@ -0,0 +1,42 @@
#!/usr/bin/env python3
"""
Verify that the podcast_projects table exists and has the correct structure.
"""
import sys
from pathlib import Path
backend_dir = Path(__file__).parent.parent
sys.path.insert(0, str(backend_dir))
from sqlalchemy import inspect
from services.database import engine
def verify_table():
"""Verify the podcast_projects table exists."""
inspector = inspect(engine)
tables = inspector.get_table_names()
if 'podcast_projects' in tables:
print("✅ Table 'podcast_projects' exists")
columns = inspector.get_columns('podcast_projects')
print(f"\n📊 Columns ({len(columns)}):")
for col in columns:
print(f"{col['name']}: {col['type']}")
indexes = inspector.get_indexes('podcast_projects')
print(f"\n📈 Indexes ({len(indexes)}):")
for idx in indexes:
print(f"{idx['name']}: {idx['column_names']}")
return True
else:
print("❌ Table 'podcast_projects' not found")
print(f"Available tables: {', '.join(tables)}")
return False
if __name__ == "__main__":
success = verify_table()
sys.exit(0 if success else 1)