GitRecap / server /routes.py
github-actions[bot]
Deploy app/api to HF Space
0491d76
from fastapi import APIRouter, HTTPException, Request, Query
from pydantic import BaseModel
from models.schemas import ChatRequest
from services.llm_service import initialize_llm_session, set_llm, get_llm, trim_messages
from services.fetcher_service import store_fetcher, get_fetcher
from git_recap.utils import parse_entries_to_txt
from aicore.llm.config import LlmConfig
from datetime import datetime, timezone
from typing import Optional, List
import requests
import os
router = APIRouter()
class CloneRequest(BaseModel):
"""Request model for repository cloning endpoint."""
url: str
GITHUB_ACCESS_TOKEN_URL = 'https://github.com/login/oauth/access_token'
@router.post("/clone-repo")
async def clone_repository(request: CloneRequest):
"""
Endpoint for cloning a repository from a URL.
Args:
request: CloneRequest containing the repository URL
Returns:
dict: Contains session_id for subsequent operations
Raises:
HTTPException: 400 for invalid URL, 500 for cloning failure
"""
try:
response = await create_llm_session()
session_id = response.get("session_id")
store_fetcher(session_id, request.url, "URL")
return {"session_id": session_id}
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to clone repository: {str(e)}")
@router.get("/external-signup")
async def external_signup(app: str, accessToken: str, provider: str):
if provider.lower() != "github":
raise HTTPException(status_code=400, detail="Unsupported provider")
# Build the URL to exchange the code for a token
params = {
"client_id": os.getenv("VITE_GITHUB_CLIENT_ID"),
"client_secret": os.getenv("VITE_GITHUB_CLIENT_SECRET"),
"code": accessToken
}
headers = {
"Accept": "application/json",
"Accept-Encoding": "application/json"
}
response = requests.get(GITHUB_ACCESS_TOKEN_URL, params=params, headers=headers)
if response.status_code != 200:
raise HTTPException(status_code=response.status_code, detail="Error fetching token from GitHub")
githubUserData = response.json()
token = githubUserData.get("access_token")
if not token:
raise HTTPException(status_code=400, detail="Failed to retrieve access token")
response = await create_llm_session()
response["token"] = token
response["provider"] = provider
final_response = await store_fetcher_endpoint(response)
session_id = final_response.get("session_id")
return {"session_id": session_id}
@router.post("/pat")
async def store_fetcher_endpoint(request: Request):
"""
Endpoint to store the PAT associated with a session.
Args:
request: Contains JSON payload with 'session_id' and 'pat'
Returns:
dict: Contains session_id
Raises:
HTTPException: 400 if PAT is missing
"""
if isinstance(request, Request):
payload = await request.json()
else:
payload = request
provider = payload.get("provider", "GitHub")
token = payload.get("pat") or payload.get("token")
if not token:
raise HTTPException(status_code=400, detail="Missing required field: pat")
response = await create_llm_session()
session_id = response.get("session_id")
store_fetcher(session_id, token, provider)
return {"session_id": session_id}
async def create_llm_session(
request: Optional[LlmConfig] = None
):
"""
Create a new LLM session with custom configuration
Args:
request: Optional LLM configuration
Returns:
dict: Contains session_id and success message
Raises:
HTTPException: 500 if session creation fails
"""
try:
session_id = await set_llm(request)
return {
"session_id": session_id,
"message": "LLM session created successfully"
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/repos")
async def get_repos(session_id: str):
"""
Return a list of repositories for the given session_id.
Args:
session_id: The session identifier
Returns:
dict: Contains list of repository names
Raises:
HTTPException: 404 if session not found
"""
fetcher = get_fetcher(session_id)
return {"repos": fetcher.repos_names}
@router.get("/actions")
async def get_actions(
session_id: str,
start_date: Optional[str] = Query(None),
end_date: Optional[str] = Query(None),
repo_filter: Optional[List[str]] = Query(None),
authors: Optional[List[str]] = Query(None)
):
"""
Get actions for the specified session with optional filters.
Args:
session_id: The session identifier
start_date: Optional start date filter
end_date: Optional end date filter
repo_filter: Optional list of repositories to filter
authors: Optional list of authors to filter
Returns:
dict: Contains formatted action entries
Raises:
HTTPException: 404 if session not found
"""
if repo_filter is not None:
repo_filter = sum([repo.split(",") for repo in repo_filter], [])
if authors is not None:
authors = sum([author.split(",") for author in authors], [])
fetcher = get_fetcher(session_id)
# Convert date strings to datetime objects
start_dt = datetime.fromisoformat(start_date).replace(tzinfo=timezone.utc) if start_date else None
end_dt = datetime.fromisoformat(end_date).replace(tzinfo=timezone.utc) if end_date else None
if start_dt:
fetcher.start_date = start_dt
if end_dt:
fetcher.end_dt = end_dt
if repo_filter is not None:
fetcher.repo_filter = repo_filter
if authors is not None:
fetcher.authors = authors
llm = get_llm(session_id)
actions = fetcher.get_authored_messages()
actions = trim_messages(actions, llm.tokenizer)
print(f"\n\n\n{actions=}\n\n\n")
return {"actions": parse_entries_to_txt(actions)}
# @router.post("/chat")
# async def chat(
# chat_request: ChatRequest
# ):
# try:
# llm = await initialize_llm_session(chat_request.session_id)
# response = await llm.acomplete(chat_request.message)
# return {"response": response}
# except Exception as e:
# raise HTTPException(status_code=500, detail=str(e))