219 lines
7.9 KiB
C#
219 lines
7.9 KiB
C#
using PerfReviewSummarizer.Api.Models;
|
||
using PerfReviewSummarizer.Api.Services;
|
||
|
||
var builder = WebApplication.CreateBuilder(args);
|
||
|
||
// Добавляем сервисы
|
||
builder.Services.AddScoped<IGitService, GitService>();
|
||
builder.Services.AddHttpClient<GeminiService>();
|
||
builder.Services.AddHttpClient<OpenAiService>();
|
||
builder.Services.AddSingleton<IAiServiceFactory, AiServiceFactory>();
|
||
builder.Services.AddScoped<IAiService>(sp => sp.GetRequiredService<IAiServiceFactory>().CreateAiService());
|
||
builder.Services.AddEndpointsApiExplorer();
|
||
builder.Services.AddOpenApi();
|
||
builder.Services.AddSwaggerGen();
|
||
builder.Services.AddCors(options =>
|
||
{
|
||
options.AddDefaultPolicy(policy =>
|
||
{
|
||
policy.AllowAnyOrigin()
|
||
.AllowAnyMethod()
|
||
.AllowAnyHeader();
|
||
});
|
||
});
|
||
|
||
var app = builder.Build();
|
||
|
||
// Настройка статических файлов
|
||
app.UseStaticFiles();
|
||
|
||
// Настройка Swagger
|
||
app.UseSwagger();
|
||
app.UseSwaggerUI(c =>
|
||
{
|
||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "PerfReviewSummarizer API v1");
|
||
c.RoutePrefix = "swagger"; // Swagger UI на /swagger
|
||
});
|
||
|
||
app.UseCors();
|
||
|
||
// Эндпоинт для получения summary
|
||
app.MapPost("/api/summary", async (SummaryRequest request, IGitService gitService, IConfiguration configuration) =>
|
||
{
|
||
try
|
||
{
|
||
var repositoryPath = request.RepositoryPath ?? configuration["GitRepository:DefaultPath"] ?? ".";
|
||
|
||
DateTime? startDate = request.StartDate;
|
||
DateTime? endDate = request.EndDate;
|
||
|
||
// Если указан период, вычисляем даты
|
||
if (!string.IsNullOrEmpty(request.Period) && !startDate.HasValue && !endDate.HasValue)
|
||
{
|
||
var now = DateTime.Now;
|
||
if (request.Period.ToLower() == "quarter")
|
||
{
|
||
// Текущий квартал
|
||
var quarter = (now.Month - 1) / 3;
|
||
startDate = new DateTime(now.Year, quarter * 3 + 1, 1);
|
||
endDate = startDate.Value.AddMonths(3).AddDays(-1);
|
||
}
|
||
else if (request.Period.ToLower() == "halfyear")
|
||
{
|
||
// Текущее полугодие
|
||
var half = (now.Month - 1) / 6;
|
||
startDate = new DateTime(now.Year, half * 6 + 1, 1);
|
||
endDate = startDate.Value.AddMonths(6).AddDays(-1);
|
||
}
|
||
}
|
||
|
||
var summary = await gitService.GenerateSummaryAsync(repositoryPath, startDate, endDate);
|
||
return Results.Ok(summary);
|
||
}
|
||
catch (DirectoryNotFoundException ex)
|
||
{
|
||
return Results.BadRequest(new { error = ex.Message });
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return Results.Problem($"Ошибка при обработке запроса: {ex.Message}");
|
||
}
|
||
})
|
||
.WithName("GetSummary")
|
||
.Produces<SummaryResponse>(StatusCodes.Status200OK)
|
||
.Produces(StatusCodes.Status400BadRequest)
|
||
.Produces(StatusCodes.Status500InternalServerError);
|
||
|
||
// Эндпоинт для получения списка коммитов
|
||
app.MapGet("/api/commits", async (string? repositoryPath, DateTime? startDate, DateTime? endDate, IGitService gitService, IConfiguration configuration) =>
|
||
{
|
||
try
|
||
{
|
||
var repoPath = repositoryPath ?? configuration["GitRepository:DefaultPath"] ?? ".";
|
||
var commits = await gitService.GetCommitsAsync(repoPath, startDate, endDate);
|
||
return Results.Ok(commits);
|
||
}
|
||
catch (DirectoryNotFoundException ex)
|
||
{
|
||
return Results.BadRequest(new { error = ex.Message });
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return Results.Problem($"Ошибка при обработке запроса: {ex.Message}");
|
||
}
|
||
})
|
||
.WithName("GetCommits")
|
||
.Produces<List<CommitInfo>>(StatusCodes.Status200OK)
|
||
.Produces(StatusCodes.Status400BadRequest)
|
||
.Produces(StatusCodes.Status500InternalServerError);
|
||
|
||
// Эндпоинт для получения AI summary (OpenAI или Gemini в зависимости от конфигурации)
|
||
app.MapPost("/api/summary/ai", async (OpenAiSummaryRequest request, IGitService gitService, IAiService aiService, IConfiguration configuration) =>
|
||
{
|
||
try
|
||
{
|
||
var repositoryPath = request.RepositoryPath ?? configuration["GitRepository:DefaultPath"] ?? ".";
|
||
|
||
DateTime? startDate = request.StartDate;
|
||
DateTime? endDate = request.EndDate;
|
||
|
||
// Если указан период, вычисляем даты
|
||
if (!string.IsNullOrEmpty(request.Period) && !startDate.HasValue && !endDate.HasValue)
|
||
{
|
||
var now = DateTime.Now;
|
||
if (request.Period.ToLower() == "quarter")
|
||
{
|
||
var quarter = (now.Month - 1) / 3;
|
||
startDate = new DateTime(now.Year, quarter * 3 + 1, 1);
|
||
endDate = startDate.Value.AddMonths(3).AddDays(-1);
|
||
}
|
||
else if (request.Period.ToLower() == "halfyear")
|
||
{
|
||
var half = (now.Month - 1) / 6;
|
||
startDate = new DateTime(now.Year, half * 6 + 1, 1);
|
||
endDate = startDate.Value.AddMonths(6).AddDays(-1);
|
||
}
|
||
}
|
||
|
||
// Получаем коммиты
|
||
var commits = await gitService.GetCommitsAsync(repositoryPath, startDate, endDate);
|
||
|
||
if (!commits.Any())
|
||
{
|
||
return Results.Ok(new OpenAiSummaryResponse
|
||
{
|
||
Summary = "Нет коммитов за указанный период для анализа",
|
||
CommitsCount = 0,
|
||
PeriodInfo = new PeriodInfo
|
||
{
|
||
StartDate = startDate ?? DateTime.MinValue,
|
||
EndDate = endDate ?? DateTime.MaxValue,
|
||
Description = "Период без коммитов"
|
||
}
|
||
});
|
||
}
|
||
|
||
var commitMessages = commits.Select(c => c.Message).ToList();
|
||
var aiSummary = await aiService.GenerateSummaryFromCommitMessagesAsync(commitMessages);
|
||
|
||
return Results.Ok(new OpenAiSummaryResponse
|
||
{
|
||
Summary = aiSummary,
|
||
CommitsCount = commits.Count,
|
||
CommitMessages = commitMessages,
|
||
PeriodInfo = new PeriodInfo
|
||
{
|
||
StartDate = startDate ?? commits.Min(c => c.When.DateTime),
|
||
EndDate = endDate ?? commits.Max(c => c.When.DateTime),
|
||
Description = $"С {startDate?.ToString("yyyy-MM-dd") ?? "начала"} по {endDate?.ToString("yyyy-MM-dd") ?? "конца"}"
|
||
}
|
||
});
|
||
}
|
||
catch (DirectoryNotFoundException ex)
|
||
{
|
||
return Results.BadRequest(new { error = ex.Message });
|
||
}
|
||
catch (InvalidOperationException ex)
|
||
{
|
||
return Results.BadRequest(new { error = ex.Message });
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return Results.Problem($"Ошибка при обработке запроса: {ex.Message}");
|
||
}
|
||
})
|
||
.WithName("GetAiSummary")
|
||
.Produces<OpenAiSummaryResponse>(StatusCodes.Status200OK)
|
||
.Produces(StatusCodes.Status400BadRequest)
|
||
.Produces(StatusCodes.Status500InternalServerError);
|
||
|
||
// Health check
|
||
app.MapGet("/health", () => Results.Ok(new { status = "healthy", timestamp = DateTime.UtcNow }))
|
||
.WithName("HealthCheck")
|
||
.Produces(StatusCodes.Status200OK);
|
||
|
||
// Корневой эндпоинт - отдаем HTML страницу
|
||
app.MapGet("/", () =>
|
||
{
|
||
var htmlPath = Path.Combine(app.Environment.WebRootPath ?? "", "index.html");
|
||
if (File.Exists(htmlPath))
|
||
{
|
||
return Results.File(htmlPath, "text/html");
|
||
}
|
||
return Results.Ok(new
|
||
{
|
||
message = "PerfReviewSummarizer API",
|
||
version = "1.0.0",
|
||
endpoints = new[]
|
||
{
|
||
"POST /api/summary - Получить summary за период",
|
||
"GET /api/commits?repositoryPath=&startDate=&endDate= - Получить список коммитов",
|
||
"GET /health - Health check",
|
||
"GET /swagger - Swagger UI"
|
||
}
|
||
});
|
||
})
|
||
.WithName("Root");
|
||
|
||
app.Run();
|