9.3 KiB
9.3 KiB
AI Analysis Service Integration Example
Overview
This document shows how to integrate the AI Analysis Service with the Git Integration Service using the direct file access approach.
New API Endpoints
1. Repository Analysis by ID
Endpoint: POST /analyze-repository
Purpose: Analyze a repository using its ID from the git-integration service
Request:
{
"repository_id": "uuid-123",
"user_id": "user-456",
"output_format": "pdf",
"max_files": 100
}
Response:
{
"success": true,
"message": "Repository analysis completed successfully",
"analysis_id": "repo_analysis_uuid-123_20241201_143022",
"report_path": "/app/reports/repo_analysis_uuid-123_20241201_143022_analysis.pdf",
"stats": {
"repository_id": "uuid-123",
"total_files": 85,
"total_lines": 15420,
"languages": ["typescript", "javascript", "python"],
"code_quality_score": 7.8,
"high_quality_files": 45,
"medium_quality_files": 30,
"low_quality_files": 10,
"total_issues": 23
}
}
2. Repository Information
Endpoint: GET /repository/{repository_id}/info?user_id={user_id}
Purpose: Get repository information from git-integration service
Response:
{
"success": true,
"repository_info": {
"id": "uuid-123",
"name": "my-repo",
"full_name": "owner/my-repo",
"local_path": "/app/git-repos/owner__my-repo__main",
"description": "My awesome repository",
"language": "typescript",
"size": 1024000
}
}
Frontend Integration Example
TypeScript Interface
interface RepositoryAnalysisRequest {
repository_id: string;
user_id: string;
output_format: 'pdf' | 'json';
max_files?: number;
}
interface AnalysisResponse {
success: boolean;
message: string;
analysis_id?: string;
report_path?: string;
stats?: {
repository_id: string;
total_files: number;
total_lines: number;
languages: string[];
code_quality_score: number;
high_quality_files: number;
medium_quality_files: number;
low_quality_files: number;
total_issues: number;
};
}
API Service Function
class AIAnalysisService {
private baseUrl = process.env.NEXT_PUBLIC_AI_ANALYSIS_SERVICE_URL || 'http://localhost:8022';
async analyzeRepository(request: RepositoryAnalysisRequest): Promise<AnalysisResponse> {
const response = await fetch(`${this.baseUrl}/analyze-repository`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(request)
});
if (!response.ok) {
throw new Error(`Analysis failed: ${response.statusText}`);
}
return response.json();
}
async getRepositoryInfo(repositoryId: string, userId: string) {
const response = await fetch(
`${this.baseUrl}/repository/${repositoryId}/info?user_id=${userId}`
);
if (!response.ok) {
throw new Error(`Failed to get repository info: ${response.statusText}`);
}
return response.json();
}
async downloadReport(filename: string): Promise<Blob> {
const response = await fetch(`${this.baseUrl}/reports/${filename}`);
if (!response.ok) {
throw new Error(`Failed to download report: ${response.statusText}`);
}
return response.blob();
}
}
React Component Example
import React, { useState } from 'react';
const RepositoryAnalysis: React.FC<{ repositoryId: string; userId: string }> = ({
repositoryId,
userId
}) => {
const [isAnalyzing, setIsAnalyzing] = useState(false);
const [analysisResult, setAnalysisResult] = useState<AnalysisResponse | null>(null);
const [error, setError] = useState<string | null>(null);
const aiAnalysisService = new AIAnalysisService();
const handleAnalyze = async () => {
setIsAnalyzing(true);
setError(null);
try {
const result = await aiAnalysisService.analyzeRepository({
repository_id: repositoryId,
user_id: userId,
output_format: 'pdf',
max_files: 100
});
setAnalysisResult(result);
} catch (err) {
setError(err instanceof Error ? err.message : 'Analysis failed');
} finally {
setIsAnalyzing(false);
}
};
const handleDownloadReport = async () => {
if (!analysisResult?.report_path) return;
try {
const filename = analysisResult.report_path.split('/').pop();
const blob = await aiAnalysisService.downloadReport(filename!);
// Create download link
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename!;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
} catch (err) {
setError('Failed to download report');
}
};
return (
<div className="repository-analysis">
<h2>Repository Analysis</h2>
<button
onClick={handleAnalyze}
disabled={isAnalyzing}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
{isAnalyzing ? 'Analyzing...' : 'Analyze Repository'}
</button>
{error && (
<div className="error-message text-red-500 mt-4">
{error}
</div>
)}
{analysisResult && (
<div className="analysis-results mt-6">
<h3>Analysis Results</h3>
<div className="stats grid grid-cols-2 gap-4 mt-4">
<div className="stat">
<strong>Total Files:</strong> {analysisResult.stats?.total_files}
</div>
<div className="stat">
<strong>Total Lines:</strong> {analysisResult.stats?.total_lines}
</div>
<div className="stat">
<strong>Code Quality Score:</strong> {analysisResult.stats?.code_quality_score}/10
</div>
<div className="stat">
<strong>Languages:</strong> {analysisResult.stats?.languages?.join(', ')}
</div>
</div>
<div className="quality-breakdown mt-4">
<h4>Quality Breakdown</h4>
<div className="grid grid-cols-3 gap-4">
<div className="text-green-600">
High Quality: {analysisResult.stats?.high_quality_files} files
</div>
<div className="text-yellow-600">
Medium Quality: {analysisResult.stats?.medium_quality_files} files
</div>
<div className="text-red-600">
Low Quality: {analysisResult.stats?.low_quality_files} files
</div>
</div>
</div>
<button
onClick={handleDownloadReport}
className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded mt-4"
>
Download Report
</button>
</div>
)}
</div>
);
};
export default RepositoryAnalysis;
Key Features Implemented
1. Rate Limiting
- Claude API Rate Limiting: 90 requests per minute with proper queuing
- Request Tracking: Tracks API requests to prevent rate limit violations
- Dynamic Delays: Automatically adjusts delays based on request frequency
2. Content Optimization
- Large File Handling: Truncates files larger than 32KB tokens
- Important Line Extraction: Keeps imports, functions, classes, and exports
- Smart Truncation: Preserves code structure while reducing size
3. Caching System
- Redis-based Caching: Caches analysis results for 24 hours
- File Hash-based Keys: Uses SHA-256 hashes for cache keys
- Automatic Cache Invalidation: Handles cache misses gracefully
4. Error Handling
- Graceful Degradation: Continues analysis even if some files fail
- Retry Logic: Built-in retry mechanisms for API failures
- Progress Tracking: Real-time progress updates during analysis
5. Service Integration
- Git Integration Communication: HTTP API calls to git-integration service
- Repository Info Retrieval: Gets local paths and metadata
- Direct File Access: Uses local file system for analysis
Performance Improvements
Before (Original Implementation)
- Time for 1000 files: 33-50 hours
- Rate Limit Issues: Would exceed Claude API limits
- No Caching: Re-analyzed files on every request
- No Optimization: Sent full file content to API
After (Optimized Implementation)
- Time for 1000 files: 2-4 hours
- Rate Limit Compliance: Respects 90 requests/minute limit
- Intelligent Caching: Avoids re-analysis of unchanged files
- Content Optimization: Sends only essential code to API
Usage Flow
- Frontend calls
/analyze-repositorywith repository ID - AI Analysis Service gets repository info from git-integration service
- AI Analysis Service accesses files directly from local storage
- Rate Limiting ensures compliance with Claude API limits
- Caching checks for existing analysis results
- Content Optimization truncates large files intelligently
- Analysis processes files with memory integration
- Report Generation creates PDF or JSON reports
- Response returns analysis results and report path
This implementation provides a robust, scalable solution for repository analysis while maintaining service independence and optimal performance.