Skip to content

Commit 910b5e7

Browse files
committed
feat: Add AI-powered governance with Gemini 2.0 Flash + policy management
Major Update - AI Governance Enhancement: 🤖 AI Features (Gemini Integration): - Backend AI service using Gemini 2.0 Flash (configurable via env) - Automated risk assessment with EU AI Act guidelines - Policy compliance checking - Documentation quality suggestions - All AI features are optional and gracefully degrade Backend Changes: - Created ai_governance.py service module - Async/await for non-blocking operations - Response caching (1 hour TTL) - Comprehensive error handling - Input sanitization - New AI API routes (/ai/assess-risk, /ai/check-compliance, /ai/improve-description) - Added google-generativeai==0.8.3 dependency Frontend Changes: - Enhanced ModelForm with AI risk suggestion feature - 'Get AI Suggestion' button - Display reasoning, EU criteria, recommendations - Loading states and error handling - Color-coded risk badges - Added policy edit/delete functionality - Toggle active/inactive status - Delete policies with confirmation - Actions column in policy table Security & Configuration: ✅ No hardcoded API keys (environment variables only) ✅ Graceful degradation (app works without AI) ✅ Feature flag: ENABLE_AI_FEATURES ✅ Configurable model: GEMINI_MODEL=gemini-2.0-flash-exp (default) ✅ Input validation on all AI endpoints ✅ Rate limiting support ✅ Created .env.example with all config options Documentation: - Added docs/AI_FEATURES.md with setup guide - Environment variable documentation - Security best practices Build Status: - Frontend build successful (CSS: 28.99KB) - No breaking changes - All existing features intact Backwards Compatibility: - All AI features are optional enhancements - Application functions normally without AI configuration - No required environment variables - Existing workflows unchanged
1 parent c8f0b8f commit 910b5e7

File tree

7 files changed

+822
-10
lines changed

7 files changed

+822
-10
lines changed

AIGovHub/backend/.env.example

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Environment Variables for AI Governance Hub
2+
3+
## Backend Configuration
4+
5+
# Database
6+
DATABASE_URL=postgresql://user:pass@localhost/aigovhub
7+
8+
# API Configuration
9+
API_HOST=0.0.0.0
10+
API_PORT=8000
11+
12+
# AI Features (Optional - Gemini Integration)
13+
ENABLE_AI_FEATURES=false
14+
GEMINI_API_KEY=your_gemini_api_key_here
15+
GEMINI_MODEL=gemini-2.0-flash-exp
16+
AI_CACHE_TTL_SECONDS=3600
17+
18+
# Security
19+
SECRET_KEY=your_secret_key_here
20+
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
"""
2+
AI-powered governance API routes
3+
4+
Provides endpoints for Gemini-based governance assistance.
5+
All endpoints are optional and gracefully degrade if AI is disabled.
6+
"""
7+
8+
from fastapi import APIRouter, HTTPException, Depends
9+
from pydantic import BaseModel, Field
10+
from typing import Optional, List, Dict, Any
11+
from app.services.ai_governance import (
12+
assess_model_risk,
13+
check_policy_compliance,
14+
suggest_description_improvements,
15+
is_ai_enabled,
16+
get_ai_config
17+
)
18+
from app.core.database import get_session
19+
from sqlmodel import Session, select
20+
from app.models import Policy
21+
import logging
22+
23+
logger = logging.getLogger(__name__)
24+
25+
router = APIRouter(tags=["AI Governance"])
26+
27+
28+
# Request/Response Models
29+
class RiskAssessmentRequest(BaseModel):
30+
model_name: str = Field(..., min_length=1, max_length=200)
31+
description: str = Field(..., min_length=10, max_length=2000)
32+
owner: str = Field(..., min_length=1, max_length=200)
33+
34+
35+
class RiskAssessmentResponse(BaseModel):
36+
suggested_risk: str
37+
reasoning: str
38+
eu_criteria: List[str]
39+
recommendations: List[str]
40+
ai_generated: bool = True
41+
42+
43+
class ComplianceCheckRequest(BaseModel):
44+
model_name: str
45+
description: Optional[str] = ""
46+
risk_level: str = "unclassified"
47+
compliance_status: str = "draft"
48+
49+
50+
class ComplianceCheckResponse(BaseModel):
51+
compliant: bool
52+
concerns: List[str]
53+
required_actions: List[str]
54+
recommendations: List[str]
55+
ai_generated: bool = True
56+
57+
58+
class DescriptionImprovementRequest(BaseModel):
59+
description: str = Field(..., min_length=1, max_length=2000)
60+
61+
62+
class DescriptionImprovementResponse(BaseModel):
63+
quality_score: int
64+
strengths: List[str]
65+
weaknesses: List[str]
66+
suggestions: List[str]
67+
compliance_gaps: List[str]
68+
ai_generated: bool = True
69+
70+
71+
class AIConfigResponse(BaseModel):
72+
enabled: bool
73+
model: Optional[str]
74+
cache_ttl: int
75+
cache_size: int
76+
77+
78+
# Endpoints
79+
80+
@router.get("/ai/config", response_model=AIConfigResponse)
81+
async def get_config():
82+
"""Get current AI configuration (diagnostics)"""
83+
config = get_ai_config()
84+
return AIConfigResponse(**config)
85+
86+
87+
@router.post("/ai/assess-risk", response_model=RiskAssessmentResponse)
88+
async def assess_risk(request: RiskAssessmentRequest):
89+
"""
90+
AI-powered risk assessment for model registration.
91+
92+
Analyzes model details and suggests EU AI Act risk classification.
93+
Returns 503 if AI features are disabled.
94+
"""
95+
if not is_ai_enabled():
96+
raise HTTPException(
97+
status_code=503,
98+
detail="AI features are not enabled. Set ENABLE_AI_FEATURES=true and provide GEMINI_API_KEY."
99+
)
100+
101+
try:
102+
result = await assess_model_risk(
103+
model_name=request.model_name,
104+
description=request.description,
105+
owner=request.owner
106+
)
107+
108+
if result is None:
109+
raise HTTPException(
110+
status_code=500,
111+
detail="AI risk assessment failed. Please try again or set risk manually."
112+
)
113+
114+
return RiskAssessmentResponse(**result)
115+
116+
except Exception as e:
117+
logger.error(f"Risk assessment error: {e}")
118+
raise HTTPException(
119+
status_code=500,
120+
detail=f"AI assessment failed: {str(e)}"
121+
)
122+
123+
124+
@router.post("/ai/check-compliance", response_model=ComplianceCheckResponse)
125+
async def check_compliance(
126+
request: ComplianceCheckRequest,
127+
session: Session = Depends(get_session)
128+
):
129+
"""
130+
AI-powered policy compliance check.
131+
132+
Reviews model against active policies and identifies concerns.
133+
Returns 503 if AI features are disabled.
134+
"""
135+
if not is_ai_enabled():
136+
raise HTTPException(
137+
status_code=503,
138+
detail="AI features are not enabled."
139+
)
140+
141+
try:
142+
# Fetch active policies
143+
statement = select(Policy).where(Policy.is_active == True)
144+
policies = session.exec(statement).all()
145+
146+
if not policies:
147+
return ComplianceCheckResponse(
148+
compliant=True,
149+
concerns=[],
150+
required_actions=[],
151+
recommendations=["No active policies to check against"],
152+
ai_generated=False
153+
)
154+
155+
# Convert policies to dict
156+
policies_dict = [
157+
{
158+
"name": p.name,
159+
"description": p.description,
160+
"scope": p.scope,
161+
"is_active": p.is_active
162+
}
163+
for p in policies
164+
]
165+
166+
model_data = {
167+
"name": request.model_name,
168+
"description": request.description,
169+
"risk_level": request.risk_level,
170+
"compliance_status": request.compliance_status
171+
}
172+
173+
result = await check_policy_compliance(model_data, policies_dict)
174+
175+
if result is None:
176+
raise HTTPException(
177+
status_code=500,
178+
detail="AI compliance check failed. Please review policies manually."
179+
)
180+
181+
return ComplianceCheckResponse(**result)
182+
183+
except HTTPException:
184+
raise
185+
except Exception as e:
186+
logger.error(f"Compliance check error: {e}")
187+
raise HTTPException(
188+
status_code=500,
189+
detail=f"Compliance check failed: {str(e)}"
190+
)
191+
192+
193+
@router.post("/ai/improve-description", response_model=DescriptionImprovementResponse)
194+
async def improve_description(request: DescriptionImprovementRequest):
195+
"""
196+
AI-powered description quality analysis.
197+
198+
Suggests improvements for governance documentation quality.
199+
Returns 503 if AI features are disabled.
200+
"""
201+
if not is_ai_enabled():
202+
raise HTTPException(
203+
status_code=503,
204+
detail="AI features are not enabled."
205+
)
206+
207+
try:
208+
result = await suggest_description_improvements(request.description)
209+
210+
if result is None:
211+
raise HTTPException(
212+
status_code=500,
213+
detail="AI description analysis failed."
214+
)
215+
216+
return DescriptionImprovementResponse(**result)
217+
218+
except HTTPException:
219+
raise
220+
except Exception as e:
221+
logger.error(f"Description improvement error: {e}")
222+
raise HTTPException(
223+
status_code=500,
224+
detail=f"Description analysis failed: {str(e)}"
225+
)

AIGovHub/backend/app/main.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from .api import organization_routes
1010
from .api import metrics_routes
1111
from .api import lineage_routes
12+
from .api import ai_routes
1213

1314
@asynccontextmanager
1415
async def lifespan(app: FastAPI):
@@ -53,6 +54,9 @@ async def lifespan(app: FastAPI):
5354
# Lineage routes (datasets & dependencies)
5455
app.include_router(lineage_routes.router, prefix="/api/v1")
5556

57+
# AI Governance routes (optional feature)
58+
app.include_router(ai_routes.router, prefix="/api/v1")
59+
5660
@app.get("/")
5761
def read_root():
5862
return {"message": "Welcome to AI Governance Hub API v0.4"}

0 commit comments

Comments
 (0)