Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion auto-analyst-backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,11 @@ COPY --chown=user ./requirements.txt requirements.txt
RUN pip install --no-cache-dir --upgrade -r requirements.txt

COPY --chown=user . /app
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]

# Make entrypoint script executable
USER root
RUN chmod +x /app/entrypoint.sh
USER user

# Use the entrypoint script instead of directly running uvicorn
CMD ["/app/entrypoint.sh"]
Binary file removed auto-analyst-backend/Housing.xlsx
Binary file not shown.
4 changes: 2 additions & 2 deletions auto-analyst-backend/chat_database.db
Git LFS file not shown
3 changes: 0 additions & 3 deletions auto-analyst-backend/cleaned_property_data.csv

This file was deleted.

89 changes: 89 additions & 0 deletions auto-analyst-backend/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/bin/bash

# Entrypoint script for Auto-Analyst backend
# This script safely initializes the database and starts the application
# SAFE for PostgreSQL/RDS - only modifies SQLite databases

set -e # Exit on any error

echo "🚀 Starting Auto-Analyst Backend..."

# Function to run safe database initialization
init_production_database() {
echo "🔧 Running SAFE database initialization..."

# Run the safe initialization script
python scripts/init_production_db.py

# Don't fail if database initialization has issues - let app try to start
if [ $? -eq 0 ]; then
echo "✅ Database initialization completed successfully"
else
echo "⚠️ Database initialization had issues, but continuing..."
echo "📋 App will start but some features may not work properly"
fi
}

# Function to verify basic app imports work
verify_app_imports() {
echo "🔍 Verifying application imports..."
python -c "
try:
from app import app
print('✅ Main application imports successful')
except Exception as e:
print(f'❌ Application import failed: {e}')
exit(1)
" || {
echo "❌ Critical application import failure - cannot start"
exit 1
}
}

# Function to verify database connectivity (non-failing)
verify_database_connectivity() {
echo "🔗 Testing database connectivity..."
python -c "
try:
from src.db.init_db import get_session, is_postgres_db
from src.db.schemas.models import AgentTemplate

db_type = 'PostgreSQL/RDS' if is_postgres_db() else 'SQLite'
print(f'🗄️ Database type: {db_type}')

session = get_session()

# Try to query templates if table exists
try:
template_count = session.query(AgentTemplate).count()
print(f'✅ Database connected. Found {template_count} templates.')
except Exception as table_error:
print(f'⚠️ Database connected but template table issue: {table_error}')
print('📋 Template functionality may not work')
finally:
session.close()

except Exception as e:
print(f'⚠️ Database connectivity issue: {e}')
print('📋 App will start but database features may not work')
"
# Don't exit on database connectivity issues - let app try to start
}

# Main startup sequence
echo "🔧 Initializing production environment..."

# Verify critical imports first
verify_app_imports

# Initialize database safely (won't modify RDS)
init_production_database

# Test database connectivity (non-failing)
verify_database_connectivity

echo "🎯 Starting FastAPI application..."
echo "🌐 Application will be available on port 7860"

# Start the FastAPI application
exec uvicorn app:app --host 0.0.0.0 --port 7860
3 changes: 0 additions & 3 deletions auto-analyst-backend/property_price_vs_area.png

This file was deleted.

191 changes: 191 additions & 0 deletions auto-analyst-backend/scripts/init_production_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
#!/usr/bin/env python3
"""
Production database initialization script.
This ensures templates are populated properly and verifies database health.
SAFE for PostgreSQL/RDS - only creates tables on SQLite databases.
"""

import sys
import os
import logging
from datetime import datetime, UTC

# Add the project root to the Python path
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from src.db.init_db import init_db, session_factory, engine, is_postgres_db
from src.db.schemas.models import Base, AgentTemplate, UserTemplatePreference
from scripts.populate_agent_templates import populate_templates
from sqlalchemy import inspect, text
from src.utils.logger import Logger

logger = Logger("init_production_db", see_time=True, console_log=True)

def get_database_type():
"""Get the database type (sqlite or postgresql)."""
try:
if is_postgres_db():
return "postgresql"
else:
return "sqlite"
except Exception as e:
logger.log_message(f"Error determining database type: {e}", logging.ERROR)
return "unknown"

def check_table_exists(table_name: str) -> bool:
"""Check if a table exists in the database."""
try:
inspector = inspect(engine)
tables = inspector.get_table_names()
return table_name in tables
except Exception as e:
logger.log_message(f"Error checking table existence: {e}", logging.ERROR)
return False

def verify_database_schema():
"""Verify that all required tables exist. Only create tables on SQLite."""
db_type = get_database_type()
logger.log_message(f"🔍 Verifying database schema for {db_type.upper()} database...", logging.INFO)

required_tables = [
'users', 'chats', 'messages', 'model_usage', 'code_executions',
'message_feedback', 'deep_analysis_reports', 'agent_templates',
'user_template_preferences'
]

missing_tables = []
existing_tables = []

for table in required_tables:
if not check_table_exists(table):
missing_tables.append(table)
logger.log_message(f"❌ Missing table: {table}", logging.WARNING)
else:
existing_tables.append(table)
logger.log_message(f"✅ Table exists: {table}", logging.INFO)

if missing_tables:
if db_type == "sqlite":
logger.log_message(f"🔧 Creating missing tables on SQLite: {missing_tables}", logging.INFO)
try:
# Safe to create tables on SQLite
Base.metadata.create_all(engine)
logger.log_message("✅ All tables created successfully on SQLite", logging.INFO)
except Exception as e:
logger.log_message(f"❌ Failed to create tables: {e}", logging.ERROR)
raise
else:
# PostgreSQL/RDS - DO NOT create tables automatically
logger.log_message(f"⚠️ WARNING: Missing tables detected in {db_type.upper()} database: {missing_tables}", logging.WARNING)
logger.log_message("🛡️ SAFETY: Not creating tables automatically on PostgreSQL/RDS", logging.INFO)
logger.log_message("📋 Please ensure these tables exist in your RDS database:", logging.INFO)
for table in missing_tables:
logger.log_message(f" - {table}", logging.INFO)

# Continue without failing - the app might still work with existing tables
if 'agent_templates' in missing_tables or 'user_template_preferences' in missing_tables:
logger.log_message("⚠️ Template functionality may not work without agent_templates and user_template_preferences tables", logging.WARNING)
else:
logger.log_message(f"✅ All required tables exist in {db_type.upper()} database", logging.INFO)

def verify_template_data():
"""Verify that agent templates are populated. Safe for all database types."""
logger.log_message("📋 Verifying template data...", logging.INFO)

session = session_factory()
try:
# Check if agent_templates table exists before querying
if not check_table_exists('agent_templates'):
logger.log_message("⚠️ agent_templates table does not exist, skipping template verification", logging.WARNING)
return

template_count = session.query(AgentTemplate).filter(AgentTemplate.is_active == True).count()
logger.log_message(f"📊 Found {template_count} active templates", logging.INFO)

if template_count == 0:
logger.log_message("🔧 No templates found, populating...", logging.INFO)
try:
populate_templates()

# Verify population worked
new_count = session.query(AgentTemplate).filter(AgentTemplate.is_active == True).count()
logger.log_message(f"✅ Templates populated. Total active templates: {new_count}", logging.INFO)
except Exception as e:
logger.log_message(f"❌ Template population failed: {e}", logging.ERROR)
logger.log_message("⚠️ App will continue but template functionality may not work", logging.WARNING)
else:
logger.log_message("✅ Templates already populated", logging.INFO)

except Exception as e:
logger.log_message(f"❌ Error verifying templates: {e}", logging.ERROR)
logger.log_message("⚠️ Template verification failed, but app will continue", logging.WARNING)
finally:
session.close()

def test_template_api_functionality():
"""Test that template-related database operations work. Safe for all database types."""
logger.log_message("🧪 Testing template API functionality...", logging.INFO)

session = session_factory()
try:
# Check if agent_templates table exists before testing
if not check_table_exists('agent_templates'):
logger.log_message("⚠️ agent_templates table does not exist, skipping API test", logging.WARNING)
return

# Test basic template query
templates = session.query(AgentTemplate).filter(AgentTemplate.is_active == True).limit(5).all()
logger.log_message(f"✅ Successfully queried {len(templates)} templates", logging.INFO)

if templates:
sample_template = templates[0]
logger.log_message(f"📄 Sample template: {sample_template.template_name} - {sample_template.display_name}", logging.INFO)
else:
logger.log_message("📭 No templates found in database", logging.INFO)

except Exception as e:
logger.log_message(f"❌ Template API test failed: {e}", logging.ERROR)
logger.log_message("⚠️ Template API may not work properly", logging.WARNING)
finally:
session.close()

def run_safe_initialization():
"""Run safe database initialization that respects production databases."""
db_type = get_database_type()
logger.log_message(f"🚀 Starting SAFE database initialization for {db_type.upper()}...", logging.INFO)

if db_type == "postgresql":
logger.log_message("🛡️ PostgreSQL/RDS detected - running in SAFE mode", logging.INFO)
logger.log_message("📋 Will only verify schema and populate templates", logging.INFO)
elif db_type == "sqlite":
logger.log_message("💽 SQLite detected - full initialization mode", logging.INFO)

try:
# Step 1: Initialize database (safe for all types)
logger.log_message("Step 1: Basic database initialization", logging.INFO)
if db_type == "sqlite":
init_db() # Only run full init on SQLite
else:
logger.log_message("Skipping init_db() for PostgreSQL (safety)", logging.INFO)

# Step 2: Verify schema (safe - only creates tables on SQLite)
logger.log_message("Step 2: Schema verification", logging.INFO)
verify_database_schema()

# Step 3: Verify template data (safe for all types)
logger.log_message("Step 3: Template data verification", logging.INFO)
verify_template_data()

# Step 4: Test functionality (safe for all types)
logger.log_message("Step 4: Functionality testing", logging.INFO)
test_template_api_functionality()

logger.log_message(f"🎉 Safe database initialization completed for {db_type.upper()}!", logging.INFO)

except Exception as e:
logger.log_message(f"💥 Database initialization failed: {e}", logging.ERROR)
logger.log_message("⚠️ App may still start but some features might not work", logging.WARNING)
# Don't raise - let the app try to start anyway

if __name__ == "__main__":
run_safe_initialization()
24 changes: 14 additions & 10 deletions auto-analyst-frontend/components/custom-templates/TemplateCard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react'
import { motion } from 'framer-motion'
import { Sparkles, Lock, TrendingUp } from 'lucide-react'
import { Switch } from '../ui/switch'
import { Sparkles, Lock, TrendingUp, Check } from 'lucide-react'
import { Badge } from '../ui/badge'
import { TemplateAgent, TemplatePreference } from './types'

Expand All @@ -24,9 +23,9 @@ export default function TemplateCard({
// Premium-only templates are only toggleable by premium users (hasAccess = true for premium)
const canToggle = hasAccess

const handleToggle = (checked: boolean) => {
const handleClick = () => {
if (canToggle) {
onToggleChange(template.template_id, checked)
onToggleChange(template.template_id, !isEnabled)
}
}

Expand Down Expand Up @@ -106,15 +105,20 @@ export default function TemplateCard({
</div>
</div>

{/* Toggle switch */}
{/* Checkmark selector */}
<div className="flex items-center gap-3">
<div className="flex flex-col items-end gap-1">
<Switch
checked={isEnabled}
onCheckedChange={handleToggle}
<button
onClick={handleClick}
disabled={!canToggle}
className={`data-[state=checked]:bg-[#FF7F7F] ${!canToggle ? 'opacity-50 cursor-not-allowed' : ''}`}
/>
className={`w-6 h-6 rounded-md border-2 flex items-center justify-center transition-all duration-200 ${
isEnabled
? 'bg-[#FF7F7F] border-[#FF7F7F] text-white'
: 'border-gray-300 hover:border-[#FF7F7F] bg-white'
} ${!canToggle ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer hover:scale-105'}`}
>
{isEnabled && <Check className="w-4 h-4" />}
</button>
<span className={`text-xs ${
!canToggle
? 'text-gray-400'
Expand Down
Loading