import gradio as gr
import os
import aiohttp
import asyncio
from git import Repo, GitCommandError
from pathlib import Path
from datetime import datetime
import shutil
import json
import logging
import re
from typing import Dict, List, Optional, Tuple
import subprocess
import plotly.express as px
import plotly.graph_objects as go
from transformers import pipeline, AutoModelForCausalLM, AutoTokenizer
import threading
from http.server import HTTPServer, BaseHTTPRequestHandler
import speech_recognition as sr
from code_editor import code_editor
from functools import lru_cache
import hashlib
import markdown2
from concurrent.futures import ThreadPoolExecutor
from hdb_scan import HDBSCAN
import websockets
from websockets.exceptions import ConnectionClosed
from code_editor import code_editor, generate_code_snippet
# ========== Configuration ==========
WORKSPACE = Path("/tmp/issue_workspace")
WORKSPACE.mkdir(exist_ok=True)
GITHUB_API = "https://api.github.com/repos"
HF_INFERENCE_API = "https://api-inference.huggingface.co/models"
WEBHOOK_PORT = 8000
WS_PORT = 8001
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
executor = ThreadPoolExecutor(max_workers=4)
HF_MODELS = {
"Mistral-8x7B": "mistralai/Mixtral-8x7B-Instruct-v0.1",
"Llama-3-8B": "meta-llama/Meta-Llama-3-8B",
"CodeLlama-34B": "codellama/CodeLlama-34b-Instruct-hf",
"StarCoder2": "bigcode/starcoder2-15b"
}
DEFAULT_MODEL = "mistralai/Mixtral-8x7B-Instruct-v0.1"
# ========== Modern Theme ==========
theme = gr.themes.Soft(
primary_hue="violet",
secondary_hue="emerald",
radius_size="xl",
font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui"]
).set(
button_primary_background_fill="linear-gradient(90deg, #8B5CF6 0%, #EC4899 100%)",
button_primary_text_color="white",
button_primary_border_radius="12px",
block_label_text_size="lg",
block_label_text_weight="600",
block_title_text_size="xl",
block_title_text_weight="800",
panel_background_fill="white",
panel_border_radius="16px",
block_shadow="*shadow_drop_lg",
)
# ========== Enhanced Webhook Handler ==========
class WebhookHandler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers['Content-Length'])
payload = json.loads(self.rfile.read(content_length).decode())
event = self.headers.get('X-GitHub-Event')
if event == 'issues':
action = payload.get('action')
if action in ['opened', 'reopened', 'closed', 'assigned']:
asyncio.run_coroutine_threadsafe(
manager.handle_webhook_event(event, action, payload),
asyncio.get_event_loop()
)
self.send_response(200)
self.end_headers()
# ========== AI-Powered Issue Manager ==========
class IssueManager:
def __init__(self):
self.issues: Dict[int, dict] = {}
self.repo_url: Optional[str] = None
self.repo: Optional[Repo] = None
self.current_issue: Optional[int] = None
self.github_token: Optional[str] = None
self.hf_token: Optional[str] = None
self.collaborators: Dict[str, dict] = {}
self.points: int = 0
self.severity_rules: Dict[str, List[str]] = {
"Critical": ["critical", "urgent", "security", "crash"],
"High": ["high", "important", "error", "regression"],
"Medium": ["medium", "bug", "performance"],
"Low": ["low", "documentation", "enhancement"]
}
self.issue_clusters: Dict[int, List[int]] = {} # Store clusters
self._init_local_models()
self.ws_clients: List[websockets.WebSocketClientProtocol] = []
self.code_editors: Dict[int, OTCodeEditor] = {} # Store code editors for each issue
def _init_local_models(self):
self.code_model = pipeline(
"text-generation",
model="codellama/CodeLlama-7b-Instruct-hf",
device_map="auto",
torch_dtype="auto"
)
self.summarizer = pipeline(
"summarization",
model="philschmid/bart-large-cnn-samsum",
device_map="auto"
)
@lru_cache(maxsize=100)
async def cached_suggestion(self, issue_hash: str, model: str):
return await self.suggest_resolution(issue_hash, model)
async def handle_webhook_event(self, event: str, action: str, payload: dict):
logger.info(f"Processing {event} {action} event")
if action == 'closed':
self.issues.pop(payload['issue']['number'], None)
else:
await self.crawl_issues(self.repo_url, self.github_token, self.hf_token)
async def crawl_issues(self, repo_url: str, github_token: str, hf_token: str) -> Tuple[bool, str]:
try:
self.repo_url = repo_url
self.github_token = github_token
self.hf_token = hf_token
self.repo = Repo.clone_from(repo_url, WORKSPACE / "repo")
headers = {"Authorization": f"token {github_token}"}
async with aiohttp.ClientSession(headers=headers) as session:
async with session.get(f"{GITHUB_API}/{repo_url}/issues") as response:
issues = await response.json()
for issue in issues:
self.issues[issue['number']] = issue
await self._cluster_similar_issues()
return True, f"Found {len(self.issues)} issues (clustered into {len(self.issue_clusters)} groups)"
except Exception as e:
logger.error(f"Crawl error: {e}")
return False, str(e)
async def _cluster_similar_issues(self):
embeddings = await self._generate_embeddings()
# Use HDBSCAN for clustering
clusterer = HDBSCAN(min_cluster_size=2, metric='cosine')
clusters = clusterer.fit_predict(embeddings)
self.issue_clusters = {}
for i, cluster_id in enumerate(clusters):
if cluster_id not in self.issue_clusters:
self.issue_clusters[cluster_id] = []
self.issue_clusters[cluster_id].append(i)
async def _generate_embeddings(self):
async with aiohttp.ClientSession() as session:
texts = [f"{i['title']} {i['body']}" for i in self.issues.values()]
response = await session.post(
f"{HF_INFERENCE_API}/sentence-transformers/all-mpnet-base-v2",
headers={"Authorization": f"Bearer {self.hf_token}"},
json={"inputs": texts}
)
return await response.json()
async def generate_code_patch(self, issue_number: int) -> dict:
issue = self.issues[issue_number]
context = await self._get_code_context(issue_number)
prompt = f"""