314 lines
9.3 KiB
Markdown
314 lines
9.3 KiB
Markdown
# 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:**
|
|
```json
|
|
{
|
|
"repository_id": "uuid-123",
|
|
"user_id": "user-456",
|
|
"output_format": "pdf",
|
|
"max_files": 100
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"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:**
|
|
```json
|
|
{
|
|
"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
|
|
```typescript
|
|
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
|
|
```typescript
|
|
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
|
|
```typescript
|
|
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
|
|
|
|
1. **Frontend** calls `/analyze-repository` with repository ID
|
|
2. **AI Analysis Service** gets repository info from git-integration service
|
|
3. **AI Analysis Service** accesses files directly from local storage
|
|
4. **Rate Limiting** ensures compliance with Claude API limits
|
|
5. **Caching** checks for existing analysis results
|
|
6. **Content Optimization** truncates large files intelligently
|
|
7. **Analysis** processes files with memory integration
|
|
8. **Report Generation** creates PDF or JSON reports
|
|
9. **Response** returns analysis results and report path
|
|
|
|
This implementation provides a robust, scalable solution for repository analysis while maintaining service independence and optimal performance.
|