Cleanup: Add migration scripts to gitignore and remove from tracking

- Add debug_usage.py, fix_database.py, migrate_usage_summaries.py,
  simple_migrate.py, validate_implementation.py to .gitignore
- Add CAMERA_SELFIE_IMPLEMENTATION.md to .gitignore
- Remove these files from git tracking (keep locally)
This commit is contained in:
ajaysi
2026-03-22 12:47:00 +05:30
parent 51bc76345f
commit 1fd9720dac
7 changed files with 10 additions and 622 deletions

10
.gitignore vendored
View File

@@ -261,3 +261,13 @@ docs/__pycache__/
backend/.onboarding_progress*.json
backend/researchtools_text/projects/Draft__AI_advanc_c2f90698.json
backend/researchtools_text/projects/Draft__AI_adv_388d4491.json
# Migration and debug scripts
debug_usage.py
fix_database.py
migrate_usage_summaries.py
simple_migrate.py
validate_implementation.py
# Camera selfie implementation (not needed)
CAMERA_SELFIE_IMPLEMENTATION.md

View File

@@ -1,137 +0,0 @@
# Camera Selfie Feature - Implementation Complete
## ✅ **Feature Successfully Implemented**
The camera selfie feature has been successfully added to the Podcast Maker's avatar upload section.
## 🚀 **What Was Built**
### 1. **CameraSelfie Component** (`CameraSelfie.tsx`)
- **Full camera functionality** using MediaDevices API
- **Live video preview** with mirror effect for natural selfie experience
- **Camera controls**: Capture, flip camera, close
- **Face positioning guide** overlay for better framing
- **Comprehensive error handling** for permissions and device limitations
- **Mobile support** with front/back camera switching
- **Responsive design** for desktop and mobile
### 2. **AvatarSelector Integration**
- **New "Take Selfie" tab** added before "Upload Your Photo"
- **Seamless integration** with existing avatar flow
- **Consistent UI/UX** matching current design patterns
- **Updated help text** to include camera option
### 3. **CreateModal Integration**
- **Camera state management** with React hooks
- **Image processing**: DataURL → File conversion
- **Upload integration**: Reuses existing upload logic
- **Error handling** for camera capture failures
## 🎯 **Key Features**
### **Camera Experience**
- **One-click camera access** from avatar selector
- **Live preview** with natural mirror effect
- **Face guide overlay** to help users position themselves
- **Camera flip** for mobile devices (front/back)
- **Instant capture** with visual feedback
### **Technical Features**
- **MediaDevices API** for camera access
- **Canvas-based image capture** with proper formatting
- **File conversion** to maintain compatibility with existing upload flow
- **Permission handling** with user-friendly error messages
- **Resource cleanup** to prevent camera leaks
### **User Experience**
- **Intuitive tab placement** before file upload
- **Clear visual indicators** and instructions
- **Graceful fallback** to file upload if camera unavailable
- **Consistent styling** with existing UI components
## 📱 **Browser Compatibility**
### **Supported**
- ✅ Modern browsers with MediaDevices API support
- ✅ Chrome 60+, Firefox 55+, Safari 11+, Edge 79+
- ✅ Mobile browsers with camera access
### **Fallback Handling**
- ❌ Camera not available → Shows message with file upload suggestion
- ❌ Permission denied → Clear instructions to enable camera
- ❌ Camera in use → User-friendly error message
## 🔧 **How It Works**
### **User Flow**
1. User clicks "Take Selfie" tab in avatar selector
2. Camera dialog opens with live preview
3. User positions face using guide overlay
4. User clicks capture button (or uses controls)
5. Image is processed and uploaded automatically
6. User can use "Make Presentable" feature like uploaded photos
### **Technical Flow**
1. `setCameraSelfieOpen(true)` opens camera dialog
2. `CameraSelfie` component requests camera access
3. Live video stream displayed with mirror effect
4. User captures photo → canvas conversion
5. DataURL passed to `handleCameraSelfie`
6. DataURL → File conversion and upload
7. Integration with existing avatar preview system
## 🎨 **UI Components**
### **Camera Dialog**
- **Modal dialog** with full-screen camera view
- **Control overlay** at bottom with capture, flip, close buttons
- **Face guide** overlay in center
- **Loading states** and error messages
### **Tab Integration**
- **New tab** with camera icon
- **Consistent styling** with existing tabs
- **Hover effects** and visual feedback
- **Help text** updates
## 🔍 **Files Modified/Created**
### **New Files**
- `frontend/src/components/PodcastMaker/CameraSelfie.tsx` - Full camera component
### **Modified Files**
- `frontend/src/components/PodcastMaker/CreateStep/AvatarSelector.tsx` - Added camera tab and integration
- `frontend/src/components/PodcastMaker/CreateModal.tsx` - Added camera state and handlers
## 🧪 **Testing Instructions**
### **Manual Testing**
1. Start frontend development server
2. Navigate to Podcast Maker
3. Click "Create New Podcast"
4. Select "Take Selfie" tab in avatar section
5. Grant camera permissions when prompted
6. Test camera preview and capture functionality
7. Verify "Make Presentable" works with captured photo
8. Test error scenarios (deny permission, no camera)
### **Test Scenarios**
- ✅ Camera permission granted
- ✅ Camera permission denied
- ✅ No camera available
- ✅ Camera already in use
- ✅ Mobile camera switching
- ✅ Image capture and upload
- ✅ Integration with "Make Presentable"
- ✅ Avatar removal and re-capture
## 🎉 **Ready for Production**
The camera selfie feature is now fully implemented and ready for user testing. It provides a modern, intuitive way for users to capture their podcast presenter photos directly from their device camera, with full integration into the existing avatar upload and enhancement workflow.
**Key Benefits:**
- 📸 **Faster than file upload** - No need to find and select photos
- 🎯 **Better framing** - Face guide helps users position themselves correctly
- 📱 **Mobile optimized** - Native camera experience on phones
- 🔄 **Seamless integration** - Works with existing "Make Presentable" feature
- 🛡️ **Robust error handling** - Graceful fallbacks and clear instructions

View File

@@ -1,64 +0,0 @@
import sys
import os
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
# Add backend to path
sys.path.append(os.path.join(os.getcwd(), 'backend'))
from services.database import Base
from models.subscription_models import APIUsageLog, UserSubscription
from services.subscription import UsageTrackingService, PricingService
# Setup DB connection
# dynamic path resolution as per codebase
DB_PATH = os.path.join(os.getcwd(), 'backend', 'data', 'alwrity.db')
# Note: The codebase might use user-specific DBs now.
# Let's check how get_db works or if we need to look at a specific user db.
# user_memories says: Database path updated to `workspace/workspace_{user_id}/db/alwrity.db` to support user isolation.
USER_ID = "user_33Gz1FPI86VDXhRY8QN4ragRFGN"
WORKSPACE_DB_PATH = os.path.join(os.getcwd(), 'workspace', f'workspace_{USER_ID}', 'db', 'alwrity.db')
print(f"Checking specific user DB at: {WORKSPACE_DB_PATH}")
if os.path.exists(WORKSPACE_DB_PATH):
db_url = f"sqlite:///{WORKSPACE_DB_PATH}"
else:
print(f"User DB not found at {WORKSPACE_DB_PATH}, falling back to main DB for check (legacy/shared mode)")
db_url = f"sqlite:///backend/data/alwrity.db"
engine = create_engine(db_url)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
db = SessionLocal()
try:
print(f"\n--- Checking Usage for User: {USER_ID} ---")
# Check API Usage Logs
logs_count = db.query(APIUsageLog).filter(APIUsageLog.user_id == USER_ID).count()
print(f"Total API Usage Logs: {logs_count}")
if logs_count > 0:
last_log = db.query(APIUsageLog).filter(APIUsageLog.user_id == USER_ID).order_by(APIUsageLog.created_at.desc()).first()
print(f"Last Activity: {last_log.created_at} - {last_log.endpoint} ({last_log.provider})")
# Check Subscription
sub = db.query(UserSubscription).filter(UserSubscription.user_id == USER_ID).first()
if sub:
print(f"Subscription: {sub.plan_type} (Status: {sub.status})")
else:
print("No subscription record found.")
# Run Service Logic
print("\n--- Running UsageTrackingService.get_user_usage_stats ---")
usage_service = UsageTrackingService(db)
stats = usage_service.get_user_usage_stats(USER_ID)
print("Stats returned:")
print(stats)
except Exception as e:
print(f"Error: {e}")
finally:
db.close()

View File

@@ -1,74 +0,0 @@
"""
Quick fix for missing wavespeed columns in usage_summaries table
Run this script to fix the database schema issue
"""
import sqlite3
import os
def fix_database():
# Find database file
db_path = None
for path in ["backend/database.db", "database.db"]:
if os.path.exists(path):
db_path = path
break
if not db_path:
print("❌ Database not found!")
print("Please make sure you're running this from the project root directory")
return
print(f"📁 Using database: {db_path}")
try:
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Check if table exists
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='usage_summaries'")
if not cursor.fetchone():
print("❌ Table 'usage_summaries' not found!")
return
# Get current columns
cursor.execute("PRAGMA table_info(usage_summaries)")
columns = [row[1] for row in cursor.fetchall()]
# Columns that need to be added
missing_columns = []
required_columns = [
'wavespeed_calls', 'tavily_calls', 'serper_calls', 'metaphor_calls',
'firecrawl_calls', 'stability_calls', 'exa_calls', 'video_calls',
'image_edit_calls', 'audio_calls', 'wavespeed_tokens', 'wavespeed_cost',
'tavily_cost', 'serper_cost', 'metaphor_cost', 'firecrawl_cost',
'stability_cost', 'exa_cost', 'video_cost', 'image_edit_cost', 'audio_cost'
]
for col in required_columns:
if col not in columns:
missing_columns.append(col)
if missing_columns:
print(f" Adding {len(missing_columns)} missing columns...")
for col in missing_columns:
if col.endswith('_calls') or col.endswith('_tokens'):
cursor.execute(f"ALTER TABLE usage_summaries ADD COLUMN {col} INTEGER DEFAULT 0")
else: # cost columns
cursor.execute(f"ALTER TABLE usage_summaries ADD COLUMN {col} FLOAT DEFAULT 0.0")
print(f" ✅ Added {col}")
conn.commit()
print("🎉 Database schema updated successfully!")
else:
print("✅ All columns already exist!")
conn.close()
except Exception as e:
print(f"❌ Error: {e}")
if __name__ == "__main__":
print("🔧 Fixing database schema for usage_summaries...")
fix_database()
print("✅ Done!")

View File

@@ -1,131 +0,0 @@
#!/usr/bin/env python3
"""
Migration script to add missing wavespeed columns to usage_summaries table
"""
import sqlite3
import sys
import os
from pathlib import Path
def get_db_path():
"""Find the database file"""
# Look for common database locations
possible_paths = [
"backend/database.db",
"backend/data/database.db",
"database.db",
"data/database.db"
]
for path in possible_paths:
if os.path.exists(path):
return path
# If not found, check if there's a .db file in backend directory
backend_dir = Path("backend")
if backend_dir.exists():
for db_file in backend_dir.glob("*.db"):
return str(db_file)
return None
def migrate_usage_summaries():
"""Add missing wavespeed columns to usage_summaries table"""
db_path = get_db_path()
if not db_path:
print("❌ Database file not found!")
print("Looked in:")
for path in ["backend/database.db", "backend/data/database.db", "database.db", "data/database.db"]:
print(f" - {path}")
return False
print(f"📁 Using database: {db_path}")
try:
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Check if table exists
cursor.execute("""
SELECT name FROM sqlite_master
WHERE type='table' AND name='usage_summaries'
""")
if not cursor.fetchone():
print("❌ Table 'usage_summaries' does not exist!")
return False
# Get current columns
cursor.execute("PRAGMA table_info(usage_summaries)")
columns = [row[1] for row in cursor.fetchall()]
print(f"📋 Current columns: {columns}")
# Columns to add
columns_to_add = [
("wavespeed_calls", "INTEGER DEFAULT 0"),
("tavily_calls", "INTEGER DEFAULT 0"),
("serper_calls", "INTEGER DEFAULT 0"),
("metaphor_calls", "INTEGER DEFAULT 0"),
("firecrawl_calls", "INTEGER DEFAULT 0"),
("stability_calls", "INTEGER DEFAULT 0"),
("exa_calls", "INTEGER DEFAULT 0"),
("video_calls", "INTEGER DEFAULT 0"),
("image_edit_calls", "INTEGER DEFAULT 0"),
("audio_calls", "INTEGER DEFAULT 0"),
("wavespeed_tokens", "INTEGER DEFAULT 0"),
("wavespeed_cost", "FLOAT DEFAULT 0.0"),
("tavily_cost", "FLOAT DEFAULT 0.0"),
("serper_cost", "FLOAT DEFAULT 0.0"),
("metaphor_cost", "FLOAT DEFAULT 0.0"),
("firecrawl_cost", "FLOAT DEFAULT 0.0"),
("stability_cost", "FLOAT DEFAULT 0.0"),
("exa_cost", "FLOAT DEFAULT 0.0"),
("video_cost", "FLOAT DEFAULT 0.0"),
("image_edit_cost", "FLOAT DEFAULT 0.0"),
("audio_cost", "FLOAT DEFAULT 0.0")
]
# Add missing columns
added_columns = []
for column_name, column_def in columns_to_add:
if column_name not in columns:
print(f" Adding column: {column_name}")
cursor.execute(f"ALTER TABLE usage_summaries ADD COLUMN {column_name} {column_def}")
added_columns.append(column_name)
else:
print(f"✅ Column already exists: {column_name}")
if added_columns:
conn.commit()
print(f"🎉 Successfully added {len(added_columns)} columns:")
for col in added_columns:
print(f" - {col}")
else:
print("✅ All columns already exist!")
# Verify the changes
cursor.execute("PRAGMA table_info(usage_summaries)")
new_columns = [row[1] for row in cursor.fetchall()]
print(f"📋 Updated columns: {new_columns}")
conn.close()
return True
except sqlite3.Error as e:
print(f"❌ Database error: {e}")
return False
except Exception as e:
print(f"❌ Unexpected error: {e}")
return False
if __name__ == "__main__":
print("🚀 Starting usage_summaries migration...")
if migrate_usage_summaries():
print("✅ Migration completed successfully!")
sys.exit(0)
else:
print("❌ Migration failed!")
sys.exit(1)

View File

@@ -1,50 +0,0 @@
import sqlite3
import os
# Find database
db_paths = ["backend/database.db", "backend/data/database.db", "database.db", "data/database.db"]
db_path = None
for path in db_paths:
if os.path.exists(path):
db_path = path
break
if not db_path:
print("Database not found!")
exit(1)
print(f"Using database: {db_path}")
try:
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Check table
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='usage_summaries'")
if not cursor.fetchone():
print("Table usage_summaries not found!")
exit(1)
# Get columns
cursor.execute("PRAGMA table_info(usage_summaries)")
columns = [row[1] for row in cursor.fetchall()]
print(f"Columns: {columns}")
# Check for wavespeed_calls
if "wavespeed_calls" in columns:
print("✅ wavespeed_calls column exists")
else:
print("❌ wavespeed_calls column missing")
# Add the column
print("Adding wavespeed_calls column...")
cursor.execute("ALTER TABLE usage_summaries ADD COLUMN wavespeed_calls INTEGER DEFAULT 0")
conn.commit()
print("✅ wavespeed_calls column added")
conn.close()
print("Migration completed!")
except Exception as e:
print(f"Error: {e}")

View File

@@ -1,166 +0,0 @@
#!/usr/bin/env python3
"""
Validation script for the enhanced topic feature implementation.
Checks that all files and components are properly implemented.
"""
import os
import sys
import json
def check_file_exists(filepath, description):
"""Check if a file exists."""
if os.path.exists(filepath):
print(f"{description}: {filepath}")
return True
else:
print(f"{description}: {filepath} (NOT FOUND)")
return False
def check_file_content(filepath, search_strings, description):
"""Check if file contains required content."""
if not os.path.exists(filepath):
print(f"{description}: File not found")
return False
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
missing = []
for search in search_strings:
if search not in content:
missing.append(search)
if missing:
print(f"{description}: Missing content: {missing}")
return False
else:
print(f"{description}: All required content found")
return True
except Exception as e:
print(f"{description}: Error reading file: {e}")
return False
def main():
"""Validate the complete implementation."""
print("🔍 Validating Enhanced Topic Feature Implementation")
print("=" * 60)
backend_root = "c:\\Users\\diksha rawat\\Desktop\\ALwrity_github\\windsurf\\ALwrity\\backend"
frontend_root = "c:\\Users\\diksha rawat\\Desktop\\ALwrity_github\\windsurf\\ALwrity\\frontend\\src\\components\\PodcastMaker"
checks_passed = 0
total_checks = 0
# Backend Checks
print("\n📋 BACKEND VALIDATION")
print("-" * 30)
# Check models.py
total_checks += 1
if check_file_content(
f"{backend_root}\\api\\podcast\\models.py",
["enhanced_ideas: List[str]", "rationales: List[str]"],
"Backend Response Model"
):
checks_passed += 1
# Check analysis.py handler
total_checks += 1
if check_file_content(
f"{backend_root}\\api\\podcast\\handlers\\analysis.py",
["Professional & Expert-led angle", "Storytelling & Human interest angle", "Trendy & Contemporary angle"],
"Backend Enhancement Prompt"
):
checks_passed += 1
# Check response handling
total_checks += 1
if check_file_content(
f"{backend_root}\\api\\podcast\\handlers\\analysis.py",
["enhanced_ideas[:3]", "rationales[:3]"],
"Backend Response Handling"
):
checks_passed += 1
# Frontend Checks
print("\n📋 FRONTEND VALIDATION")
print("-" * 30)
# Check modal component
total_checks += 1
if check_file_exists(
f"{frontend_root}\\EnhancedTopicChoicesModal.tsx",
"Enhanced Topic Choices Modal Component"
):
checks_passed += 1
# Check modal content
total_checks += 1
if check_file_content(
f"{frontend_root}\\EnhancedTopicChoicesModal.tsx",
["CHOICE_LABELS", "handleChoiceEdit", "handleSelectChoice"],
"Modal Component Logic"
):
checks_passed += 1
# Check CreateModal state
total_checks += 1
if check_file_content(
f"{frontend_root}\\CreateModal.tsx",
["enhancedChoices", "enhancedRationales", "choicesModalOpen", "editedChoices"],
"CreateModal State Management"
):
checks_passed += 1
# Check CreateModal handlers
total_checks += 1
if check_file_content(
f"{frontend_root}\\CreateModal.tsx",
["handleChoiceSelection", "result.enhanced_ideas", "setChoicesModalOpen(true)"],
"CreateModal Event Handlers"
):
checks_passed += 1
# Check API service update
total_checks += 1
if check_file_content(
f"{frontend_root}\\..\\..\\services\\podcastApi.ts",
["enhanced_ideas: string[]", "rationales: string[]"],
"Frontend API Service Update"
):
checks_passed += 1
# Check modal import and usage
total_checks += 1
if check_file_content(
f"{frontend_root}\\CreateModal.tsx",
["import { EnhancedTopicChoicesModal }", "<EnhancedTopicChoicesModal"],
"Modal Integration"
):
checks_passed += 1
# Summary
print("\n📊 VALIDATION SUMMARY")
print("=" * 30)
print(f"Checks Passed: {checks_passed}/{total_checks}")
print(f"Success Rate: {(checks_passed/total_checks)*100:.1f}%")
if checks_passed == total_checks:
print("\n🎉 ALL CHECKS PASSED! Implementation is complete.")
print("\n📝 FEATURE SUMMARY:")
print("✅ Backend returns 3 enhanced ideas with rationales")
print("✅ Frontend displays choices in editable modal")
print("✅ Users can select and edit choices")
print("✅ AI gradient styling applied consistently")
print("✅ Error handling and fallbacks implemented")
print("\n🚀 Ready for testing!")
else:
print(f"\n⚠️ {total_checks - checks_passed} checks failed. Please review implementation.")
return checks_passed == total_checks
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)