#!/usr/bin/env python3 """ Script to recalculate project statistics from imported sessions and conversations. Run this after importing data to fix zero statistics on the projects page. """ import asyncio from sqlalchemy import select, func from sqlalchemy.ext.asyncio import AsyncSession from app.database.connection import engine, async_session_maker from app.models.project import Project from app.models.session import Session from app.models.conversation import Conversation from app.models.activity import Activity from app.models.tool_call import ToolCall async def recalculate_project_stats(): """Recalculate statistics for all projects based on imported data.""" async with async_session_maker() as db: try: # Get all projects result = await db.execute(select(Project)) projects = result.scalars().all() print(f"Found {len(projects)} projects to recalculate") for project in projects: print(f"\nRecalculating stats for project: {project.name}") # Get all sessions for this project session_result = await db.execute( select(Session).where(Session.project_id == project.id) ) sessions = session_result.scalars().all() session_ids = [s.id for s in sessions] if sessions else [] # Calculate session-based statistics total_sessions = len(sessions) total_time_minutes = sum( s.calculated_duration_minutes or 0 for s in sessions ) # Find last session time last_session_time = None if sessions: last_session_time = max(s.start_time for s in sessions) # Calculate activity-based statistics files_modified_count = 0 lines_changed_count = 0 tool_calls_count = 0 if session_ids: activity_result = await db.execute( select(Activity).where(Activity.session_id.in_(session_ids)) ) activities = activity_result.scalars().all() # Count unique files modified unique_files = set() total_lines_changed = 0 for activity in activities: if activity.file_path: unique_files.add(activity.file_path) if activity.total_lines_changed: total_lines_changed += activity.total_lines_changed files_modified_count = len(unique_files) lines_changed_count = total_lines_changed # Count tool calls session_ids_str = [str(sid) for sid in session_ids] tool_calls_result = await db.execute( select(ToolCall).where(ToolCall.session_id.in_(session_ids_str)) ) tool_calls = tool_calls_result.scalars().all() tool_calls_count = len(tool_calls) # Update project statistics project.total_sessions = total_sessions project.total_time_minutes = total_time_minutes project.files_modified_count = files_modified_count project.lines_changed_count = lines_changed_count project.tool_calls_count = tool_calls_count if last_session_time: project.last_session = last_session_time print(f" Sessions: {total_sessions}") print(f" Time: {total_time_minutes} minutes") print(f" Files: {files_modified_count}") print(f" Lines: {lines_changed_count}") print(f" Tool calls: {tool_calls_count}") print(f" Last session: {last_session_time}") # Commit all changes await db.commit() print(f"\nSuccessfully recalculated statistics for {len(projects)} projects") except Exception as e: await db.rollback() print(f"Error recalculating project stats: {e}") raise finally: await engine.dispose() if __name__ == "__main__": asyncio.run(recalculate_project_stats())