import gradio as gr from github_client import GitHubClient from models import SearchRequest, SearchResponse import os from typing import Optional, Dict, Any, List def search_pr_opportunities( keyword: Optional[str] = None, topic: Optional[str] = None, per_page: int = 5, page: int = 1, token: Optional[str] = None ) -> Dict[str, Any]: """Search GitHub for PR opportunities. Args: keyword: Keyword to search in repositories (optional) topic: Topic to filter repositories (optional) per_page: Number of results per page (default: 5) page: Page number (default: 1) token: GitHub token for authentication Returns: A dictionary containing opportunities and total count """ if not token: token = os.getenv("GITHUB_TOKEN") if not token: raise gr.Error("GitHub token required in Authorization header or .env") try: client: GitHubClient = GitHubClient(token) opportunities, total_count = client.find_pr_opportunities( keyword=keyword, topic=topic, per_page=per_page, page=page ) # The return structure matches a dictionary format, so we type it as Dict[str, Any] response: Dict[str, Any] = { "opportunities": [ { "repo_name": opp.repo_name, "repo_url": opp.repo_url, "issue_title": opp.issue_title, "issue_url": opp.issue_url, "issue_labels": opp.issue_labels, "issue_body": opp.issue_body } for opp in opportunities ], "total_count": total_count } return response except Exception as e: raise gr.Error(str(e)) # Create the Gradio interface demo: gr.Interface = gr.Interface( fn=search_pr_opportunities, inputs=[ gr.Textbox(label="Keyword", placeholder="e.g., fastapi"), gr.Textbox(label="Topic", placeholder="e.g., python"), gr.Slider(minimum=1, maximum=20, value=5, step=1, label="Results per page"), gr.Slider(minimum=1, maximum=10, value=1, step=1, label="Page number") ], outputs=gr.JSON(label="Search Results"), title="GitHub PR Opportunity Finder", description="Search GitHub repositories for PR opportunities (issues labeled 'good first issue' or 'help wanted')", examples=[ ["fastapi", "python", 5, 1, ""], ["react", "javascript", 3, 1, ""], ["machine-learning", None, 2, 1, ""], [None, "web-development", 4, 1, ""] ] ) # Launch with MCP server enabled if __name__ == "__main__": demo.launch(mcp_server=True)