Files
2025-11-29 18:16:25 +08:00

308 lines
11 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
User Preference Learning
Learns from user's choices to provide better recommendations over time
"""
import json
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Optional
from collections import defaultdict
class UserPreferences:
"""Learns and stores user preferences for automation"""
def __init__(self, storage_path: str = ".claude/meta-automation/user_preferences.json"):
self.storage_path = Path(storage_path)
self.storage_path.parent.mkdir(parents=True, exist_ok=True)
self.preferences = self._load()
def _load(self) -> Dict:
"""Load existing preferences or create new"""
if self.storage_path.exists():
try:
with open(self.storage_path, 'r') as f:
return json.load(f)
except:
return self._create_new()
return self._create_new()
def _create_new(self) -> Dict:
"""Create new preferences structure"""
return {
'version': '1.0',
'created_at': datetime.now().isoformat(),
'projects_analyzed': 0,
'automation_mode_preferences': {
'quick': 0,
'focused': 0,
'comprehensive': 0
},
'agent_usage': {},
'skill_usage': {},
'project_type_history': {},
'time_saved_total': 0,
'cost_spent_total': 0,
'satisfaction_ratings': [],
'most_valuable_automations': [],
'rarely_used': [],
'integration_preferences': {
'focus_on_gaps': 0,
'enhance_existing': 0,
'independent': 0
},
'sessions': []
}
def _save(self):
"""Save preferences to disk"""
with open(self.storage_path, 'w') as f:
json.dump(self.preferences, f, indent=2)
def record_session(self, session_data: Dict):
"""
Record a new automation session
Args:
session_data: {
'session_id': str,
'project_type': str,
'mode': 'quick|focused|comprehensive',
'agents_used': List[str],
'skills_generated': List[str],
'time_spent_minutes': int,
'cost': float,
'time_saved_estimate': int, # hours
'user_satisfaction': int, # 1-5
'integration_choice': str, # gaps|enhance|independent
}
"""
# Update counts
self.preferences['projects_analyzed'] += 1
# Record mode preference
mode = session_data.get('mode', 'quick')
self.preferences['automation_mode_preferences'][mode] += 1
# Record agent usage
for agent in session_data.get('agents_used', []):
if agent not in self.preferences['agent_usage']:
self.preferences['agent_usage'][agent] = 0
self.preferences['agent_usage'][agent] += 1
# Record skill usage
for skill in session_data.get('skills_generated', []):
if skill not in self.preferences['skill_usage']:
self.preferences['skill_usage'][skill] = 0
self.preferences['skill_usage'][skill] += 1
# Record project type
project_type = session_data.get('project_type', 'unknown')
if project_type not in self.preferences['project_type_history']:
self.preferences['project_type_history'][project_type] = 0
self.preferences['project_type_history'][project_type] += 1
# Track totals
self.preferences['time_saved_total'] += session_data.get('time_saved_estimate', 0)
self.preferences['cost_spent_total'] += session_data.get('cost', 0)
# Track satisfaction
satisfaction = session_data.get('user_satisfaction')
if satisfaction:
self.preferences['satisfaction_ratings'].append({
'session_id': session_data.get('session_id'),
'rating': satisfaction,
'date': datetime.now().isoformat()
})
# Track integration preference
integration = session_data.get('integration_choice')
if integration in self.preferences['integration_preferences']:
self.preferences['integration_preferences'][integration] += 1
# Store full session
self.preferences['sessions'].append({
**session_data,
'recorded_at': datetime.now().isoformat()
})
self._save()
def get_recommended_mode(self) -> str:
"""Get recommended automation mode based on history"""
prefs = self.preferences['automation_mode_preferences']
if self.preferences['projects_analyzed'] == 0:
return 'quick' # Default for first-time users
# Return mode user uses most
return max(prefs.items(), key=lambda x: x[1])[0]
def get_recommended_agents(self, project_type: str, count: int = 5) -> List[str]:
"""Get recommended agents based on past usage and project type"""
# Get agents user has used
agent_usage = self.preferences['agent_usage']
if not agent_usage:
# Default recommendations for new users
defaults = {
'programming': ['project-analyzer', 'security-analyzer', 'test-coverage-analyzer'],
'academic_writing': ['project-analyzer', 'latex-structure-analyzer', 'citation-analyzer'],
'educational': ['project-analyzer', 'learning-path-analyzer', 'assessment-analyzer'],
}
return defaults.get(project_type, ['project-analyzer'])
# Sort by usage count
sorted_agents = sorted(agent_usage.items(), key=lambda x: x[1], reverse=True)
return [agent for agent, _ in sorted_agents[:count]]
def get_rarely_used(self) -> List[str]:
"""Get agents/skills that user never finds valuable"""
rarely_used = []
# Check for agents used only once or twice
for agent, count in self.preferences['agent_usage'].items():
if count <= 2 and self.preferences['projects_analyzed'] > 5:
rarely_used.append(agent)
return rarely_used
def should_skip_agent(self, agent_name: str) -> bool:
"""Check if this agent is rarely useful for this user"""
rarely_used = self.get_rarely_used()
return agent_name in rarely_used
def get_integration_preference(self) -> str:
"""Get preferred integration approach"""
prefs = self.preferences['integration_preferences']
if sum(prefs.values()) == 0:
return 'focus_on_gaps' # Default
return max(prefs.items(), key=lambda x: x[1])[0]
def get_statistics(self) -> Dict:
"""Get usage statistics"""
total_sessions = self.preferences['projects_analyzed']
if total_sessions == 0:
return {
'total_sessions': 0,
'message': 'No automation sessions yet'
}
avg_satisfaction = 0
if self.preferences['satisfaction_ratings']:
avg_satisfaction = sum(r['rating'] for r in self.preferences['satisfaction_ratings']) / len(self.preferences['satisfaction_ratings'])
return {
'total_sessions': total_sessions,
'time_saved_total_hours': self.preferences['time_saved_total'],
'cost_spent_total': round(self.preferences['cost_spent_total'], 2),
'average_satisfaction': round(avg_satisfaction, 1),
'preferred_mode': self.get_recommended_mode(),
'most_used_agents': sorted(
self.preferences['agent_usage'].items(),
key=lambda x: x[1],
reverse=True
)[:5],
'project_types': self.preferences['project_type_history'],
'roi': round(self.preferences['time_saved_total'] / max(1, self.preferences['cost_spent_total'] * 60), 1)
}
def get_recommendations_for_user(self, project_type: str) -> Dict:
"""Get personalized recommendations"""
stats = self.get_statistics()
if stats['total_sessions'] == 0:
return {
'recommended_mode': 'quick',
'reason': 'First time - start with quick analysis to see how it works',
'recommended_agents': ['project-analyzer'],
'skip_agents': []
}
return {
'recommended_mode': self.get_recommended_mode(),
'reason': f"You've used {self.get_recommended_mode()} mode {self.preferences['automation_mode_preferences'][self.get_recommended_mode()]} times",
'recommended_agents': self.get_recommended_agents(project_type),
'skip_agents': self.get_rarely_used(),
'integration_preference': self.get_integration_preference(),
'stats': {
'total_time_saved': f"{stats['time_saved_total_hours']} hours",
'average_satisfaction': stats.get('average_satisfaction', 0),
'roi': f"{stats.get('roi', 0)}x return on investment"
}
}
def export_report(self) -> str:
"""Export usage report"""
stats = self.get_statistics()
report = f"""
# Meta-Automation Usage Report
## Overview
- **Total Sessions:** {stats['total_sessions']}
- **Time Saved:** {stats.get('time_saved_total_hours', 0)} hours
- **Cost Spent:** ${stats.get('cost_spent_total', 0):.2f}
- **ROI:** {stats.get('roi', 0)}x (hours saved per dollar spent × 60)
- **Avg Satisfaction:** {stats.get('average_satisfaction', 0)}/5
## Your Preferences
- **Preferred Mode:** {stats.get('preferred_mode', 'quick')}
- **Integration Style:** {self.get_integration_preference()}
## Most Used Agents
"""
for agent, count in stats.get('most_used_agents', []):
report += f"- {agent}: {count} times\n"
report += "\n## Project Types\n"
for ptype, count in self.preferences['project_type_history'].items():
report += f"- {ptype}: {count} projects\n"
return report
# Example usage
if __name__ == '__main__':
prefs = UserPreferences()
# Simulate some sessions
print("Simulating usage...\n")
prefs.record_session({
'session_id': 'session-1',
'project_type': 'programming',
'mode': 'quick',
'agents_used': ['project-analyzer'],
'skills_generated': [],
'time_spent_minutes': 5,
'cost': 0.03,
'time_saved_estimate': 10,
'user_satisfaction': 4,
'integration_choice': 'focus_on_gaps'
})
prefs.record_session({
'session_id': 'session-2',
'project_type': 'programming',
'mode': 'focused',
'agents_used': ['project-analyzer', 'security-analyzer', 'test-coverage-analyzer'],
'skills_generated': ['security-scanner', 'test-generator'],
'time_spent_minutes': 8,
'cost': 0.09,
'time_saved_estimate': 50,
'user_satisfaction': 5,
'integration_choice': 'focus_on_gaps'
})
print(prefs.export_report())
print("\nRecommendations for next programming project:")
recs = prefs.get_recommendations_for_user('programming')
print(json.dumps(recs, indent=2))