Files
ZakirovT 057e1f526b init
2026-01-22 00:45:41 +03:00

129 lines
4.9 KiB
C#

using PerfReviewSummarizer.Api.Models;
namespace PerfReviewSummarizer.Api.Services;
public class GeminiService : IAiService
{
private readonly IConfiguration _configuration;
private readonly HttpClient _httpClient;
private readonly ILogger<GeminiService> _logger;
public GeminiService(IConfiguration configuration, HttpClient httpClient, ILogger<GeminiService> logger)
{
_logger = logger;
_logger.LogInformation("GeminiService constructor called");
_configuration = configuration;
_httpClient = httpClient;
}
private void EnsureInitialized()
{
var apiKey = _configuration["Gemini:ApiKey"];
if (string.IsNullOrEmpty(apiKey))
{
throw new InvalidOperationException("Gemini API ключ не найден в конфигурации. Добавьте 'Gemini:ApiKey' в appsettings.json");
}
}
public async Task<string> GenerateSummaryFromCommitsAsync(List<CommitInfo> commits)
{
var commitMessages = commits.Select(c => c.Message).ToList();
return await GenerateSummaryFromCommitMessagesAsync(commitMessages);
}
public async Task<string> GenerateSummaryFromCommitMessagesAsync(List<string> commitMessages)
{
EnsureInitialized();
if (!commitMessages.Any())
{
return "Нет коммитов для анализа";
}
var commitListText = string.Join("\n", commitMessages.Select((msg, idx) => $"{idx + 1}. {msg}"));
var prompt = $@"Проанализируй следующие сообщения коммитов из Git репозитория и создай краткое, информативное резюме (summary).
Сообщения коммитов:
{commitListText}
Требования:
1. Резюме должно быть на русском языке
2. Будь лаконичен, но информативен (2-4 абзаца)
3. Выделите основные темы изменений (новые функции, исправления, рефакторинг и т.д.)
4. Укажите общую направленность разработки
5. Отметьте любые важные или критичные изменения
Формат ответа - просто текст резюме без дополнительных комментариев.";
try
{
var apiKey = _configuration["Gemini:ApiKey"];
var model = _configuration["Gemini:Model"] ?? "gemini-2.5-flash";
var request = new GeminiRequest
{
Contents = new List<GeminiContent>
{
new GeminiContent
{
Parts = new List<GeminiPart>
{
new GeminiPart { Text = prompt }
}
}
}
};
var json = System.Text.Json.JsonSerializer.Serialize(request);
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
var url = $"https://generativelanguage.googleapis.com/v1/models/{model}:generateContent?key={apiKey}";
var response = await _httpClient.PostAsync(url, content);
if (!response.IsSuccessStatusCode)
{
var errorContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Gemini Error ({response.StatusCode}): {errorContent}");
throw new InvalidOperationException($"Ошибка Gemini API: {response.StatusCode} - {errorContent}");
}
var responseContent = await response.Content.ReadAsStringAsync();
var result = System.Text.Json.JsonDocument.Parse(responseContent);
var text = result.RootElement
.GetProperty("candidates")[0]
.GetProperty("content")
.GetProperty("parts")[0]
.GetProperty("text")
.GetString();
return text ?? "Ошибка при генерировании резюме";
}
catch (Exception ex)
{
throw new InvalidOperationException($"Ошибка при обращении к Gemini API: {ex.Message}", ex);
}
}
}
// Вспомогательные классы для сериализации Gemini API
public class GeminiRequest
{
[System.Text.Json.Serialization.JsonPropertyName("contents")]
public List<GeminiContent> Contents { get; set; } = new();
}
public class GeminiContent
{
[System.Text.Json.Serialization.JsonPropertyName("parts")]
public List<GeminiPart> Parts { get; set; } = new();
}
public class GeminiPart
{
[System.Text.Json.Serialization.JsonPropertyName("text")]
public string Text { get; set; } = string.Empty;
}