chore(cleanup): remove obsolete scripts and update paths for production deployment
- Remove dev/scripts/check-file-organization.sh (obsolete organization checker) - Remove dev/scripts/community_onboarding.py (unused 559-line automation script) - Update gpu_miner_host.py log path from /home/oib/windsurf/aitbc to /opt/aitbc - Add service status and standardization badges to README.md
This commit is contained in:
559
dev/scripts/development/community_onboarding.py
Normal file
559
dev/scripts/development/community_onboarding.py
Normal file
@@ -0,0 +1,559 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
AITBC Community Onboarding Automation
|
||||
|
||||
This script automates the onboarding process for new community members,
|
||||
including welcome messages, resource links, and initial guidance.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List, Optional
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
|
||||
class CommunityOnboarding:
|
||||
"""Automated community onboarding system."""
|
||||
|
||||
def __init__(self, config_path: str = "config/community_config.json"):
|
||||
self.config = self._load_config(config_path)
|
||||
self.logger = self._setup_logging()
|
||||
self.onboarding_data = self._load_onboarding_data()
|
||||
|
||||
def _load_config(self, config_path: str) -> Dict:
|
||||
"""Load community configuration."""
|
||||
default_config = {
|
||||
"discord": {
|
||||
"bot_token": os.getenv("DISCORD_BOT_TOKEN"),
|
||||
"welcome_channel": "welcome",
|
||||
"general_channel": "general",
|
||||
"help_channel": "help"
|
||||
},
|
||||
"github": {
|
||||
"token": os.getenv("GITHUB_TOKEN"),
|
||||
"org": "aitbc",
|
||||
"repo": "aitbc",
|
||||
"team_slugs": ["core-team", "maintainers", "contributors"]
|
||||
},
|
||||
"email": {
|
||||
"smtp_server": os.getenv("SMTP_SERVER"),
|
||||
"smtp_port": 587,
|
||||
"username": os.getenv("SMTP_USERNAME"),
|
||||
"password": os.getenv("SMTP_PASSWORD"),
|
||||
"from_address": "community@aitbc.dev"
|
||||
},
|
||||
"onboarding": {
|
||||
"welcome_delay_hours": 1,
|
||||
"follow_up_days": [3, 7, 14],
|
||||
"resource_links": {
|
||||
"documentation": "https://docs.aitbc.dev",
|
||||
"api_reference": "https://api.aitbc.dev/docs",
|
||||
"plugin_development": "https://docs.aitbc.dev/plugins",
|
||||
"community_forum": "https://community.aitbc.dev",
|
||||
"discord_invite": "https://discord.gg/aitbc"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config_file = Path(config_path)
|
||||
if config_file.exists():
|
||||
with open(config_file, 'r') as f:
|
||||
user_config = json.load(f)
|
||||
default_config.update(user_config)
|
||||
|
||||
return default_config
|
||||
|
||||
def _setup_logging(self) -> logging.Logger:
|
||||
"""Setup logging for the onboarding system."""
|
||||
logger = logging.getLogger("community_onboarding")
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
if not logger.handlers:
|
||||
handler = logging.StreamHandler()
|
||||
formatter = logging.Formatter(
|
||||
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
|
||||
return logger
|
||||
|
||||
def _load_onboarding_data(self) -> Dict:
|
||||
"""Load onboarding data from file."""
|
||||
data_file = Path("data/onboarding_data.json")
|
||||
if data_file.exists():
|
||||
with open(data_file, 'r') as f:
|
||||
return json.load(f)
|
||||
return {"members": {}, "messages": {}, "follow_ups": {}}
|
||||
|
||||
def _save_onboarding_data(self) -> None:
|
||||
"""Save onboarding data to file."""
|
||||
data_file = Path("data/onboarding_data.json")
|
||||
data_file.parent.mkdir(exist_ok=True)
|
||||
with open(data_file, 'w') as f:
|
||||
json.dump(self.onboarding_data, f, indent=2)
|
||||
|
||||
async def welcome_new_member(self, member_id: str, member_name: str,
|
||||
platform: str = "discord") -> bool:
|
||||
"""Welcome a new community member."""
|
||||
try:
|
||||
self.logger.info(f"Welcoming new member: {member_name} on {platform}")
|
||||
|
||||
# Create onboarding record
|
||||
self.onboarding_data["members"][member_id] = {
|
||||
"name": member_name,
|
||||
"platform": platform,
|
||||
"joined_at": datetime.now().isoformat(),
|
||||
"welcome_sent": False,
|
||||
"follow_ups_sent": [],
|
||||
"resources_viewed": [],
|
||||
"contributions": [],
|
||||
"status": "new"
|
||||
}
|
||||
|
||||
# Schedule welcome message
|
||||
await self._schedule_welcome_message(member_id)
|
||||
|
||||
# Track member in analytics
|
||||
await self._track_member_analytics(member_id, "joined")
|
||||
|
||||
self._save_onboarding_data()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error welcoming member {member_name}: {e}")
|
||||
return False
|
||||
|
||||
async def _schedule_welcome_message(self, member_id: str) -> None:
|
||||
"""Schedule welcome message for new member."""
|
||||
delay_hours = self.config["onboarding"]["welcome_delay_hours"]
|
||||
|
||||
# In production, this would use a proper task queue
|
||||
# For now, we'll send immediately
|
||||
await asyncio.sleep(delay_hours * 3600)
|
||||
await self.send_welcome_message(member_id)
|
||||
|
||||
async def send_welcome_message(self, member_id: str) -> bool:
|
||||
"""Send welcome message to member."""
|
||||
try:
|
||||
member_data = self.onboarding_data["members"][member_id]
|
||||
platform = member_data["platform"]
|
||||
|
||||
if platform == "discord":
|
||||
success = await self._send_discord_welcome(member_id)
|
||||
elif platform == "github":
|
||||
success = await self._send_github_welcome(member_id)
|
||||
else:
|
||||
self.logger.warning(f"Unsupported platform: {platform}")
|
||||
return False
|
||||
|
||||
if success:
|
||||
member_data["welcome_sent"] = True
|
||||
member_data["welcome_sent_at"] = datetime.now().isoformat()
|
||||
self._save_onboarding_data()
|
||||
await self._track_member_analytics(member_id, "welcome_sent")
|
||||
|
||||
return success
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error sending welcome message to {member_id}: {e}")
|
||||
return False
|
||||
|
||||
async def _send_discord_welcome(self, member_id: str) -> bool:
|
||||
"""Send welcome message via Discord."""
|
||||
try:
|
||||
# Discord bot implementation would go here
|
||||
# For now, we'll log the message
|
||||
|
||||
member_data = self.onboarding_data["members"][member_id]
|
||||
welcome_message = self._generate_welcome_message(member_data["name"])
|
||||
|
||||
self.logger.info(f"Discord welcome message for {member_id}: {welcome_message}")
|
||||
|
||||
# In production:
|
||||
# await discord_bot.send_message(
|
||||
# channel_id=self.config["discord"]["welcome_channel"],
|
||||
# content=welcome_message
|
||||
# )
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error sending Discord welcome: {e}")
|
||||
return False
|
||||
|
||||
async def _send_github_welcome(self, member_id: str) -> bool:
|
||||
"""Send welcome message via GitHub."""
|
||||
try:
|
||||
# GitHub API implementation would go here
|
||||
member_data = self.onboarding_data["members"][member_id]
|
||||
welcome_message = self._generate_welcome_message(member_data["name"])
|
||||
|
||||
self.logger.info(f"GitHub welcome message for {member_id}: {welcome_message}")
|
||||
|
||||
# In production:
|
||||
# await github_api.create_issue_comment(
|
||||
# repo=self.config["github"]["repo"],
|
||||
# issue_number=welcome_issue_number,
|
||||
# body=welcome_message
|
||||
# )
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error sending GitHub welcome: {e}")
|
||||
return False
|
||||
|
||||
def _generate_welcome_message(self, member_name: str) -> str:
|
||||
"""Generate personalized welcome message."""
|
||||
resources = self.config["onboarding"]["resource_links"]
|
||||
|
||||
message = f"""🎉 Welcome to AITBC, {member_name}!
|
||||
|
||||
We're excited to have you join our community of developers, researchers, and innovators building the future of AI-powered blockchain technology.
|
||||
|
||||
🚀 **Quick Start Guide:**
|
||||
1. **Documentation**: {resources["documentation"]}
|
||||
2. **API Reference**: {resources["api_reference"]}
|
||||
3. **Plugin Development**: {resources["plugin_development"]}
|
||||
4. **Community Forum**: {resources["community_forum"]}
|
||||
5. **Discord Chat**: {resources["discord_invite"]}
|
||||
|
||||
📋 **Next Steps:**
|
||||
- ⭐ Star our repository on GitHub
|
||||
- 📖 Read our contribution guidelines
|
||||
- 💬 Introduce yourself in the #introductions channel
|
||||
- 🔍 Check out our "good first issues" for newcomers
|
||||
|
||||
🛠️ **Ways to Contribute:**
|
||||
- Code contributions (bug fixes, features)
|
||||
- Documentation improvements
|
||||
- Plugin development
|
||||
- Community support and mentoring
|
||||
- Testing and feedback
|
||||
|
||||
❓ **Need Help?**
|
||||
- Ask questions in #help channel
|
||||
- Check our FAQ at {resources["documentation"]}/faq
|
||||
- Join our weekly office hours (Tuesdays 2PM UTC)
|
||||
|
||||
We're here to help you succeed! Don't hesitate to reach out.
|
||||
|
||||
Welcome aboard! 🚀
|
||||
|
||||
#AITBCCommunity #Welcome #OpenSource"""
|
||||
|
||||
return message
|
||||
|
||||
async def send_follow_up_message(self, member_id: str, day: int) -> bool:
|
||||
"""Send follow-up message to member."""
|
||||
try:
|
||||
member_data = self.onboarding_data["members"][member_id]
|
||||
|
||||
if day in member_data["follow_ups_sent"]:
|
||||
return True # Already sent
|
||||
|
||||
follow_up_message = self._generate_follow_up_message(member_data["name"], day)
|
||||
|
||||
if member_data["platform"] == "discord":
|
||||
success = await self._send_discord_follow_up(member_id, follow_up_message)
|
||||
else:
|
||||
success = await self._send_email_follow_up(member_id, follow_up_message)
|
||||
|
||||
if success:
|
||||
member_data["follow_ups_sent"].append(day)
|
||||
member_data[f"follow_up_{day}_sent_at"] = datetime.now().isoformat()
|
||||
self._save_onboarding_data()
|
||||
await self._track_member_analytics(member_id, f"follow_up_{day}")
|
||||
|
||||
return success
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error sending follow-up to {member_id}: {e}")
|
||||
return False
|
||||
|
||||
def _generate_follow_up_message(self, member_name: str, day: int) -> str:
|
||||
"""Generate follow-up message based on day."""
|
||||
resources = self.config["onboarding"]["resource_links"]
|
||||
|
||||
if day == 3:
|
||||
return f"""Hi {member_name}! 👋
|
||||
|
||||
Hope you're settling in well! Here are some resources to help you get started:
|
||||
|
||||
🔧 **Development Setup:**
|
||||
- Clone the repository: `git clone https://github.com/aitbc/aitbc`
|
||||
- Install dependencies: `poetry install`
|
||||
- Run tests: `pytest`
|
||||
|
||||
📚 **Learning Resources:**
|
||||
- Architecture overview: {resources["documentation"]}/architecture
|
||||
- Plugin tutorial: {resources["plugin_development"]}/tutorial
|
||||
- API examples: {resources["api_reference"]}/examples
|
||||
|
||||
💬 **Community Engagement:**
|
||||
- Join our weekly community call (Thursdays 3PM UTC)
|
||||
- Share your progress in #show-and-tell
|
||||
- Ask for help in #help
|
||||
|
||||
How's your experience been so far? Any questions or challenges we can help with?
|
||||
|
||||
#AITBCCommunity #Onboarding #GetStarted"""
|
||||
|
||||
elif day == 7:
|
||||
return f"""Hi {member_name}! 🎯
|
||||
|
||||
You've been with us for a week! We'd love to hear about your experience:
|
||||
|
||||
📊 **Quick Check-in:**
|
||||
- Have you been able to set up your development environment?
|
||||
- Have you explored the codebase or documentation?
|
||||
- Are there any areas where you'd like more guidance?
|
||||
|
||||
🚀 **Contribution Opportunities:**
|
||||
- Good first issues: https://github.com/aitbc/aitbc/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22
|
||||
- Documentation improvements: {resources["documentation"]}/contribute
|
||||
- Plugin ideas: {resources["plugin_development"]}/ideas
|
||||
|
||||
🎉 **Community Events:**
|
||||
- Monthly hackathon (first Saturday)
|
||||
- Plugin showcase (third Thursday)
|
||||
- Office hours (every Tuesday 2PM UTC)
|
||||
|
||||
Your feedback helps us improve the onboarding experience. What would make your journey more successful?
|
||||
|
||||
#AITBCCommunity #Feedback #Community"""
|
||||
|
||||
elif day == 14:
|
||||
return f"""Hi {member_name}! 🌟
|
||||
|
||||
Two weeks in - you're becoming part of the AITBC ecosystem!
|
||||
|
||||
🎯 **Next Level Engagement:**
|
||||
- Consider joining a specialized team (security, plugins, docs, etc.)
|
||||
- Start a plugin project: {resources["plugin_development"]}/starter
|
||||
- Review a pull request to learn the codebase
|
||||
- Share your ideas in #feature-requests
|
||||
|
||||
🏆 **Recognition Program:**
|
||||
- Contributor of the month nominations
|
||||
- Plugin contest participation
|
||||
- Community spotlight features
|
||||
- Speaking opportunities at community events
|
||||
|
||||
📈 **Your Impact:**
|
||||
- Every contribution, no matter how small, helps
|
||||
- Your questions help us improve documentation
|
||||
- Your feedback shapes the project direction
|
||||
- Your presence strengthens the community
|
||||
|
||||
What would you like to focus on next? We're here to support your journey!
|
||||
|
||||
#AITBCCommunity #Growth #Impact"""
|
||||
|
||||
else:
|
||||
return f"Hi {member_name}! Just checking in. How's your AITBC journey going?"
|
||||
|
||||
async def _send_discord_follow_up(self, member_id: str, message: str) -> bool:
|
||||
"""Send follow-up via Discord DM."""
|
||||
try:
|
||||
self.logger.info(f"Discord follow-up for {member_id}: {message[:100]}...")
|
||||
# Discord DM implementation
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error sending Discord follow-up: {e}")
|
||||
return False
|
||||
|
||||
async def _send_email_follow_up(self, member_id: str, message: str) -> bool:
|
||||
"""Send follow-up via email."""
|
||||
try:
|
||||
self.logger.info(f"Email follow-up for {member_id}: {message[:100]}...")
|
||||
# Email implementation
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error sending email follow-up: {e}")
|
||||
return False
|
||||
|
||||
async def track_member_activity(self, member_id: str, activity_type: str,
|
||||
details: Dict = None) -> None:
|
||||
"""Track member activity for analytics."""
|
||||
try:
|
||||
if member_id not in self.onboarding_data["members"]:
|
||||
return
|
||||
|
||||
member_data = self.onboarding_data["members"][member_id]
|
||||
|
||||
if "activities" not in member_data:
|
||||
member_data["activities"] = []
|
||||
|
||||
activity = {
|
||||
"type": activity_type,
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"details": details or {}
|
||||
}
|
||||
|
||||
member_data["activities"].append(activity)
|
||||
|
||||
# Update member status based on activity
|
||||
if activity_type == "first_contribution":
|
||||
member_data["status"] = "contributor"
|
||||
elif activity_type == "first_plugin":
|
||||
member_data["status"] = "plugin_developer"
|
||||
|
||||
self._save_onboarding_data()
|
||||
await self._track_member_analytics(member_id, activity_type)
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error tracking activity for {member_id}: {e}")
|
||||
|
||||
async def _track_member_analytics(self, member_id: str, event: str) -> None:
|
||||
"""Track analytics for member events."""
|
||||
try:
|
||||
# Analytics implementation would go here
|
||||
self.logger.info(f"Analytics event: {member_id} - {event}")
|
||||
|
||||
# In production, send to analytics service
|
||||
# await analytics_service.track_event({
|
||||
# "member_id": member_id,
|
||||
# "event": event,
|
||||
# "timestamp": datetime.now().isoformat(),
|
||||
# "properties": {}
|
||||
# })
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error tracking analytics: {e}")
|
||||
|
||||
async def process_follow_ups(self) -> None:
|
||||
"""Process scheduled follow-ups for all members."""
|
||||
try:
|
||||
current_date = datetime.now()
|
||||
|
||||
for member_id, member_data in self.onboarding_data["members"].items():
|
||||
joined_date = datetime.fromisoformat(member_data["joined_at"])
|
||||
|
||||
for day in self.config["onboarding"]["follow_up_days"]:
|
||||
follow_up_date = joined_date + timedelta(days=day)
|
||||
|
||||
if (current_date >= follow_up_date and
|
||||
day not in member_data["follow_ups_sent"]):
|
||||
await self.send_follow_up_message(member_id, day)
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error processing follow-ups: {e}")
|
||||
|
||||
async def generate_onboarding_report(self) -> Dict:
|
||||
"""Generate onboarding analytics report."""
|
||||
try:
|
||||
total_members = len(self.onboarding_data["members"])
|
||||
welcome_sent = sum(1 for m in self.onboarding_data["members"].values() if m.get("welcome_sent"))
|
||||
|
||||
status_counts = {}
|
||||
for member in self.onboarding_data["members"].values():
|
||||
status = member.get("status", "new")
|
||||
status_counts[status] = status_counts.get(status, 0) + 1
|
||||
|
||||
platform_counts = {}
|
||||
for member in self.onboarding_data["members"].values():
|
||||
platform = member.get("platform", "unknown")
|
||||
platform_counts[platform] = platform_counts.get(platform, 0) + 1
|
||||
|
||||
return {
|
||||
"total_members": total_members,
|
||||
"welcome_sent": welcome_sent,
|
||||
"welcome_rate": welcome_sent / total_members if total_members > 0 else 0,
|
||||
"status_distribution": status_counts,
|
||||
"platform_distribution": platform_counts,
|
||||
"generated_at": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error generating report: {e}")
|
||||
return {}
|
||||
|
||||
async def run_daily_tasks(self) -> None:
|
||||
"""Run daily onboarding tasks."""
|
||||
try:
|
||||
self.logger.info("Running daily onboarding tasks")
|
||||
|
||||
# Process follow-ups
|
||||
await self.process_follow_ups()
|
||||
|
||||
# Generate daily report
|
||||
report = await self.generate_onboarding_report()
|
||||
self.logger.info(f"Daily onboarding report: {report}")
|
||||
|
||||
# Cleanup old data
|
||||
await self._cleanup_old_data()
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error running daily tasks: {e}")
|
||||
|
||||
async def _cleanup_old_data(self) -> None:
|
||||
"""Clean up old onboarding data."""
|
||||
try:
|
||||
cutoff_date = datetime.now() - timedelta(days=365)
|
||||
|
||||
# Remove members older than 1 year with no activity
|
||||
to_remove = []
|
||||
for member_id, member_data in self.onboarding_data["members"].items():
|
||||
joined_date = datetime.fromisoformat(member_data["joined_at"])
|
||||
|
||||
if (joined_date < cutoff_date and
|
||||
not member_data.get("activities") and
|
||||
member_data.get("status") == "new"):
|
||||
to_remove.append(member_id)
|
||||
|
||||
for member_id in to_remove:
|
||||
del self.onboarding_data["members"][member_id]
|
||||
self.logger.info(f"Removed inactive member: {member_id}")
|
||||
|
||||
if to_remove:
|
||||
self._save_onboarding_data()
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error cleaning up data: {e}")
|
||||
|
||||
|
||||
# CLI interface for the onboarding system
|
||||
async def main():
|
||||
"""Main CLI interface."""
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="AITBC Community Onboarding")
|
||||
parser.add_argument("--welcome", help="Welcome new member (member_id,name,platform)")
|
||||
parser.add_argument("--followup", help="Send follow-up (member_id,day)")
|
||||
parser.add_argument("--report", action="store_true", help="Generate onboarding report")
|
||||
parser.add_argument("--daily", action="store_true", help="Run daily tasks")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
onboarding = CommunityOnboarding()
|
||||
|
||||
if args.welcome:
|
||||
member_id, name, platform = args.welcome.split(",")
|
||||
await onboarding.welcome_new_member(member_id, name, platform)
|
||||
print(f"Welcome message scheduled for {name}")
|
||||
|
||||
elif args.followup:
|
||||
member_id, day = args.followup.split(",")
|
||||
success = await onboarding.send_follow_up_message(member_id, int(day))
|
||||
print(f"Follow-up sent: {success}")
|
||||
|
||||
elif args.report:
|
||||
report = await onboarding.generate_onboarding_report()
|
||||
print(json.dumps(report, indent=2))
|
||||
|
||||
elif args.daily:
|
||||
await onboarding.run_daily_tasks()
|
||||
print("Daily tasks completed")
|
||||
|
||||
else:
|
||||
print("Use --help to see available options")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user