Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save UltiRequiem/b605b2f670d9cb913d52d2cc4df44340 to your computer and use it in GitHub Desktop.
Save UltiRequiem/b605b2f670d9cb913d52d2cc4df44340 to your computer and use it in GitHub Desktop.
import pLimit from "p-limit";
export interface GitHubAnalyzerResponse {
success: boolean;
evaluation: Evaluation;
}
export interface Evaluation {
id: number;
username: string;
role: string;
overallScore: number;
seniorityLevel: string;
repositories: Repository[];
summary: string;
strengths: string[];
areasForImprovement: string[];
additionalInsights?: string[];
technologies: string[];
categoryPromedies?: {
contributionPromedy: number;
relevancePromedy: number;
qualityPromedy: number;
starsPromedy: number;
forksPromedy: number;
lastActivityMonths: number;
maintainabilityPromedy?: number;
securityPromedy?: number;
testCoveragePromedy?: number;
documentationPromedy?: number;
performancePromedy?: number;
codeComplexityScore?: number;
};
jobMatch: JobMatch;
}
export interface JobMatch {
explanation: string;
score: number;
}
export interface Repository {
name: string;
description: string;
stars: number;
forks: number;
language: string;
createdAt: string;
updatedAt: string;
score: number;
contributionScore: number;
relevanceScore: number;
qualityScore: number;
codeQualityMetrics: CodeQualityMetrics;
fullAnalysis: FullAnalysis;
}
export interface CodeQualityMetrics {
recencyScore: number;
popularityScore: number;
codeQualityScore: number;
categories: Category[];
categoryInsights: CategoryInsight[];
strengths: string[];
weaknesses: string[];
filesAnalyzed: number;
summary: string;
repoAge: string;
clusterScores: ClusterScores;
practiceRecommendations: string[];
complexityIndicators: ComplexityIndicators;
}
export interface Category {
id: string;
name: string;
percentage: number;
weight: number;
explanation: string;
}
export interface CategoryInsight {
name: string;
score: number;
insight: string;
recommendation: string;
}
export interface ClusterScores {
maintainability: number;
security: number;
quality: number;
performance: number;
}
export interface ComplexityIndicators {
avgCategoryScore: number;
codeToTestRatio: number;
topCategory: TopCategory;
}
export interface TopCategory {
id: string;
name: string;
percentage: number;
weight: number;
explanation: string;
}
export interface FullAnalysis {
repository: string;
categories: Category2[];
promedy: number;
summary: string;
filesAnalyzed: number;
fileSelectionData: FileSelectionData;
}
export interface Category2 {
id: string;
name: string;
percentage: number;
weight: number;
explanation: string;
}
export interface FileSelectionData {
totalFilesInRepo: number;
totalFilesSelected: number;
selectedFilePaths: SelectedFilePath[];
}
export interface SelectedFilePath {
path: string;
importance: number;
reason: string;
}
export type AnalysisMode = "quick" | "exhaustive";
/**
export const profileEvaluationSchema = z.object({
username: GitHubUsername,
jobName: z.string().min(1, "Job name is required"),
jobDescription: z.string().optional(),
projectId: ProjectId.optional(),
backofficeUser: z.string().optional(),
});
*/
export interface GitHubAnalyzerRequest {
username: string;
jobName: string;
expectedSeniority?: string;
jobDescription: string;
projectId?: number;
backofficeUser?: string;
}
export interface GenericGithubAnalyzerRequest {
username: string;
}
export class GitHubAnalyzerClient {
private readonly timeout: number;
constructor(
private baseUrl: string,
private authToken: string,
timeout = 60_000,
) {
this.baseUrl = baseUrl;
this.authToken = authToken;
this.timeout = timeout;
}
private async fetchWithTimeout(
url: string,
options: RequestInit,
): Promise<Response> {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
try {
const response = await fetch(url, {
...options,
signal: controller.signal,
});
return response;
} finally {
clearTimeout(timeoutId);
}
}
async getProfileById(id: number): Promise<GitHubAnalyzerResponse> {
const url = `${this.baseUrl}/analyze-profile/${id}`;
try {
const response = await this.fetchWithTimeout(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
"analyzer-token": this.authToken,
},
});
if (!response.ok) {
throw new Error(
`GitHub Analyzer API error: ${response.status} ${response.statusText}`,
);
}
const data = await response.json();
if (!data.success) {
throw new Error(data.code);
}
return data as GitHubAnalyzerResponse;
} catch (error) {
if (error instanceof Error && error.name === "AbortError") {
throw new Error("Request timeout: The analysis is taking too long");
}
throw error;
}
}
async analyzeProfile(
analysisConfig: GitHubAnalyzerRequest,
): Promise<GitHubAnalyzerResponse> {
const url = `${this.baseUrl}/analyze-profile`;
try {
const response = await this.fetchWithTimeout(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"analyzer-token": this.authToken,
},
body: JSON.stringify(analysisConfig),
});
if (!response.ok) {
throw new Error(
`GitHub Analyzer API error: ${response.status} ${response.statusText}`,
);
}
const data = await response.json();
if (!data.success) {
throw new Error(data.code);
}
return data as GitHubAnalyzerResponse;
} catch (error) {
if (error instanceof Error && error.name === "AbortError") {
throw new Error("Request timeout: The analysis is taking too long");
}
throw error;
}
}
async analyzeBatch(
profiles: GitHubAnalyzerRequest[],
): Promise<GitHubAnalyzerResponse[]> {
const results = await Promise.all(
profiles.map((analyzerConfig) => this.analyzeProfile(analyzerConfig)),
);
return results;
}
async genericAnalysis(request: GenericGithubAnalyzerRequest) {
const url = `${this.baseUrl}/api/analyze-profile-generic`;
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"analyzer-token": this.authToken,
},
body: JSON.stringify(request),
});
if (!response.ok) {
console.log(response);
throw new Error("Failed to fetch generic analysis");
}
const data = await response.json();
return data;
}
async analyzeGenericBatch(profiles: string[]) {
const input: GenericGithubAnalyzerRequest[] = profiles.map((username) => ({
username,
}));
const limit = pLimit(35);
const promises = input.map((request) =>
limit(() => this.genericAnalysis(request)),
);
const resultsData = await Promise.all(promises);
return resultsData;
}
}
const client = new GitHubAnalyzerClient(
"https://code-quality-ms-production.up.railway.app",
"clnDUQDXoH6DnhsOYw2uy4_SOEj1GcZfynjiT-BjtSA",
);
const results = await client.analyzeGenericBatch([
"https://github.com/GEnma29?tab=repositories",
"http://www.github.com/SantiagoRatto",
"https://github.com/phantom0109",
"https://github.com/jonathan-messina",
]);
console.log(results);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment