"""Organization settings endpoints.""" from typing import Dict, Any, Optional from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from pydantic import BaseModel import httpx from app.core.database import get_db from app.models.organization import Organization, OrganizationMember from app.api.deps import get_current_user, require_role router = APIRouter() class AIConfig(BaseModel): provider: str = "openrouter" apiKey: str = "" model: str = "meta-llama/llama-3.3-70b-instruct" autoAnalyze: bool = True autoCreatePR: bool = True confidenceThreshold: int = 70 class SettingsUpdate(BaseModel): ai_config: Optional[AIConfig] = None class TestLLMRequest(BaseModel): provider: str api_key: str model: str # In-memory storage for now (should be moved to database) ORG_SETTINGS: Dict[int, Dict[str, Any]] = {} @router.get("/{org_id}/settings") async def get_settings( org_id: int, member: OrganizationMember = Depends(require_role("viewer")), db: AsyncSession = Depends(get_db) ): """Get organization settings.""" settings = ORG_SETTINGS.get(org_id, {}) # Mask API key for security if settings.get("ai_config", {}).get("apiKey"): settings["ai_config"]["apiKey"] = "***configured***" return settings @router.put("/{org_id}/settings") async def update_settings( org_id: int, settings: SettingsUpdate, member: OrganizationMember = Depends(require_role("admin")), db: AsyncSession = Depends(get_db) ): """Update organization settings.""" if org_id not in ORG_SETTINGS: ORG_SETTINGS[org_id] = {} if settings.ai_config: ORG_SETTINGS[org_id]["ai_config"] = settings.ai_config.dict() return {"message": "Settings updated", "settings": ORG_SETTINGS[org_id]} @router.post("/{org_id}/test-llm") async def test_llm_connection( org_id: int, request: TestLLMRequest, member: OrganizationMember = Depends(require_role("admin")), db: AsyncSession = Depends(get_db) ): """Test LLM API connection.""" # Build request based on provider if request.provider == "openrouter": url = "https://openrouter.ai/api/v1/chat/completions" headers = { "Authorization": f"Bearer {request.api_key}", "Content-Type": "application/json", "HTTP-Referer": "https://jira-fixer.startdata.com.br", "X-Title": "JIRA AI Fixer" } payload = { "model": request.model, "messages": [{"role": "user", "content": "Say 'OK' if you can read this."}], "max_tokens": 10 } elif request.provider == "anthropic": url = "https://api.anthropic.com/v1/messages" headers = { "x-api-key": request.api_key, "Content-Type": "application/json", "anthropic-version": "2023-06-01" } payload = { "model": request.model, "max_tokens": 10, "messages": [{"role": "user", "content": "Say 'OK' if you can read this."}] } elif request.provider == "openai": url = "https://api.openai.com/v1/chat/completions" headers = { "Authorization": f"Bearer {request.api_key}", "Content-Type": "application/json" } payload = { "model": request.model, "messages": [{"role": "user", "content": "Say 'OK' if you can read this."}], "max_tokens": 10 } elif request.provider == "groq": url = "https://api.groq.com/openai/v1/chat/completions" headers = { "Authorization": f"Bearer {request.api_key}", "Content-Type": "application/json" } payload = { "model": request.model, "messages": [{"role": "user", "content": "Say 'OK' if you can read this."}], "max_tokens": 10 } elif request.provider == "google": url = f"https://generativelanguage.googleapis.com/v1beta/models/{request.model}:generateContent?key={request.api_key}" headers = {"Content-Type": "application/json"} payload = { "contents": [{"parts": [{"text": "Say 'OK' if you can read this."}]}], "generationConfig": {"maxOutputTokens": 10} } else: raise HTTPException(status_code=400, detail=f"Unsupported provider: {request.provider}") try: async with httpx.AsyncClient() as client: response = await client.post(url, headers=headers, json=payload, timeout=15.0) if response.status_code == 200: return {"success": True, "message": "Connection successful"} elif response.status_code == 401: raise HTTPException(status_code=400, detail="Invalid API key") elif response.status_code == 403: raise HTTPException(status_code=400, detail="API key lacks permissions") else: error_detail = response.json().get("error", {}).get("message", response.text) raise HTTPException(status_code=400, detail=f"API error: {error_detail}") except httpx.TimeoutException: raise HTTPException(status_code=400, detail="Connection timeout") except httpx.ConnectError: raise HTTPException(status_code=400, detail="Could not connect to API")