Spaces:
Running
Running
""" | |
GitHub Technology Trends Search Tool | |
""" | |
from .base_tool import BaseTool | |
import requests | |
import json | |
from typing import Dict, List, Optional | |
from datetime import datetime, timedelta | |
class GitHubSearchTool(BaseTool): | |
"""Search GitHub for technology trends and adoption patterns""" | |
def __init__(self): | |
super().__init__("GitHub", "Search GitHub for technology adoption and development trends") | |
self.base_url = "https://api.github.com" | |
self.rate_limit_delay = 2.0 # GitHub has rate limits | |
def search(self, technology: str, max_results: int = 5, **kwargs) -> str: | |
"""Search GitHub for technology trends and adoption""" | |
self.rate_limit() | |
try: | |
# Search repositories | |
repos_data = self._search_repositories(technology, max_results) | |
if not repos_data or not repos_data.get('items'): | |
return f"**GitHub Technology Research for: {technology}**\n\nNo relevant repositories found." | |
result = f"**GitHub Technology Trends for: {technology}**\n\n" | |
# Repository analysis | |
result += self._format_repository_data(repos_data['items'], technology) | |
# Trend analysis | |
result += self._analyze_technology_trends(repos_data, technology) | |
# Recent activity analysis | |
result += self._analyze_recent_activity(repos_data['items'], technology) | |
return result | |
except requests.RequestException as e: | |
return self.format_error_response(technology, f"Network error accessing GitHub: {str(e)}") | |
except Exception as e: | |
return self.format_error_response(technology, str(e)) | |
def _search_repositories(self, technology: str, max_results: int) -> Optional[Dict]: | |
"""Search GitHub repositories for the technology""" | |
repos_url = f"{self.base_url}/search/repositories" | |
# Create comprehensive search query | |
search_query = f'{technology} language:python OR language:javascript OR language:typescript OR language:go OR language:rust' | |
params = { | |
'q': search_query, | |
'sort': 'stars', | |
'order': 'desc', | |
'per_page': max_results | |
} | |
response = requests.get(repos_url, params=params, timeout=15) | |
response.raise_for_status() | |
return response.json() | |
def _format_repository_data(self, repositories: List[Dict], technology: str) -> str: | |
"""Format repository information""" | |
result = f"**Top {len(repositories)} Repositories:**\n" | |
for i, repo in enumerate(repositories, 1): | |
stars = repo.get('stargazers_count', 0) | |
forks = repo.get('forks_count', 0) | |
language = repo.get('language', 'Unknown') | |
updated = repo.get('updated_at', '')[:10] # YYYY-MM-DD | |
result += f"**{i}. {repo['name']}** ({stars:,} ⭐, {forks:,} 🍴)\n" | |
result += f" Language: {language} | Updated: {updated}\n" | |
description = repo.get('description', 'No description') | |
if description and len(description) > 100: | |
description = description[:100] + "..." | |
result += f" Description: {description}\n" | |
result += f" URL: {repo.get('html_url', 'N/A')}\n\n" | |
return result | |
def _analyze_technology_trends(self, repos_data: Dict, technology: str) -> str: | |
"""Analyze technology adoption trends""" | |
total_count = repos_data.get('total_count', 0) | |
items = repos_data.get('items', []) | |
if not items: | |
return "" | |
# Calculate adoption metrics | |
total_stars = sum(repo.get('stargazers_count', 0) for repo in items) | |
total_forks = sum(repo.get('forks_count', 0) for repo in items) | |
avg_stars = total_stars / len(items) if items else 0 | |
# Determine adoption level | |
if total_count > 50000: | |
adoption_level = "Very High" | |
elif total_count > 10000: | |
adoption_level = "High" | |
elif total_count > 1000: | |
adoption_level = "Moderate" | |
elif total_count > 100: | |
adoption_level = "Emerging" | |
else: | |
adoption_level = "Niche" | |
# Language analysis | |
languages = {} | |
for repo in items: | |
lang = repo.get('language') | |
if lang: | |
languages[lang] = languages.get(lang, 0) + 1 | |
result = f"**Technology Adoption Analysis:**\n" | |
result += f"• Total repositories: {total_count:,}\n" | |
result += f"• Adoption level: {adoption_level}\n" | |
result += f"• Average stars (top repos): {avg_stars:,.0f}\n" | |
result += f"• Total community engagement: {total_stars:,} stars, {total_forks:,} forks\n" | |
if languages: | |
top_languages = sorted(languages.items(), key=lambda x: x[1], reverse=True)[:3] | |
result += f"• Popular languages: {', '.join(f'{lang} ({count})' for lang, count in top_languages)}\n" | |
result += "\n" | |
return result | |
def _analyze_recent_activity(self, repositories: List[Dict], technology: str) -> str: | |
"""Analyze recent development activity""" | |
if not repositories: | |
return "" | |
# Check update recency | |
current_date = datetime.now() | |
recent_updates = 0 | |
very_recent_updates = 0 | |
for repo in repositories: | |
updated_str = repo.get('updated_at', '') | |
if updated_str: | |
try: | |
updated_date = datetime.fromisoformat(updated_str.replace('Z', '+00:00')) | |
days_ago = (current_date - updated_date.replace(tzinfo=None)).days | |
if days_ago <= 30: | |
very_recent_updates += 1 | |
if days_ago <= 90: | |
recent_updates += 1 | |
except: | |
pass | |
result = f"**Development Activity:**\n" | |
result += f"• Recently updated (30 days): {very_recent_updates}/{len(repositories)} repositories\n" | |
result += f"• Active projects (90 days): {recent_updates}/{len(repositories)} repositories\n" | |
# Activity assessment | |
if very_recent_updates / len(repositories) > 0.7: | |
activity_level = "Very Active" | |
elif recent_updates / len(repositories) > 0.5: | |
activity_level = "Active" | |
elif recent_updates / len(repositories) > 0.3: | |
activity_level = "Moderate" | |
else: | |
activity_level = "Low" | |
result += f"• Overall activity level: {activity_level}\n" | |
result += f"• Community health: {'Strong' if activity_level in ['Very Active', 'Active'] else 'Moderate'} developer engagement\n\n" | |
return result | |
def should_use_for_query(self, query: str) -> bool: | |
"""GitHub is good for technology, framework, and development-related queries""" | |
tech_indicators = [ | |
'technology', 'framework', 'library', 'software', 'programming', | |
'development', 'developer', 'code', 'github', 'open source', | |
'javascript', 'python', 'react', 'nodejs', 'django', 'flask', | |
'vue', 'angular', 'typescript', 'rust', 'go', 'kotlin', | |
'adoption', 'popular', 'trending', 'tools', 'stack' | |
] | |
query_lower = query.lower() | |
return any(indicator in query_lower for indicator in tech_indicators) | |
def extract_key_info(self, text: str) -> dict: | |
"""Extract key information from GitHub results""" | |
base_info = super().extract_key_info(text) | |
if text: | |
# Look for GitHub-specific patterns | |
base_info.update({ | |
'repo_count': text.count('repositories'), | |
'has_stars': '⭐' in text, | |
'has_forks': '🍴' in text, | |
'has_recent_activity': any(year in text for year in ['2024', '2025']), | |
'adoption_mentioned': any(term in text.lower() for term in ['adoption', 'popular', 'trending']), | |
'languages_analyzed': 'Popular languages:' in text | |
}) | |
return base_info |