feat: complete implementation using gemini as analyzer
This commit is contained in:
@@ -12,61 +12,68 @@ namespace StreamShorts.Library.Analysis.Gemini;
|
||||
/// <inheritdoc/>
|
||||
public sealed class GeminiAnalyzer(
|
||||
IHttpClientFactory httpClientFactory,
|
||||
string apiKey
|
||||
) : ITranscriptAnalyzer
|
||||
string apiKey,
|
||||
string? model = null
|
||||
) : ITranscriptAnalyzer
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
|
||||
private readonly IHttpClientFactory _httpClientFactory =
|
||||
httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
|
||||
|
||||
private readonly string _apiKey = apiKey ?? throw new ArgumentNullException(nameof(apiKey));
|
||||
private readonly string _model = model ?? "gemini-2.5-flash-lite";
|
||||
private readonly IAnalysisPrompt _prompt = new DefaultAnalysisPrompt();
|
||||
|
||||
public GeminiAnalyzer(
|
||||
IHttpClientFactory httpClientFactory,
|
||||
string apiKey,
|
||||
IAnalysisPrompt prompt
|
||||
) : this(httpClientFactory, apiKey)
|
||||
IAnalysisPrompt prompt,
|
||||
string? model = null
|
||||
) : this(httpClientFactory, apiKey, model)
|
||||
{
|
||||
_prompt = prompt ?? throw new ArgumentNullException(nameof(prompt));
|
||||
}
|
||||
|
||||
public async Task<TranscriptAnalysis> AnalyzeAsync(IEnumerable<TranscriptionSegment> segments)
|
||||
{
|
||||
using var client = _httpClientFactory.CreateClient();
|
||||
client.Timeout = TimeSpan.FromMinutes(5);
|
||||
|
||||
var requestUrl = $"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-lite:generateContent?key={_apiKey}";
|
||||
var generateContentRequest = new GenerateContentRequest(
|
||||
[
|
||||
new Content(
|
||||
Role: "user",
|
||||
Parts:[ new Part(Text: _prompt.GetPrompt(segments)) ]
|
||||
)
|
||||
],
|
||||
new GenerationConfig(ResponseMimeType: "application/json")
|
||||
);
|
||||
using var requestContent = new StringContent(
|
||||
JsonSerializer.Serialize(generateContentRequest),
|
||||
Encoding.UTF8,
|
||||
"application/json"
|
||||
);
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, requestUrl)
|
||||
try
|
||||
{
|
||||
Content = requestContent
|
||||
};
|
||||
using var client = _httpClientFactory.CreateClient();
|
||||
client.Timeout = TimeSpan.FromMinutes(5);
|
||||
|
||||
var response = await client.SendAsync(request).ConfigureAwait(false);
|
||||
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var responseJson = JsonSerializer.Deserialize<GenerateContentResponse>(responseContent);
|
||||
var candidatesText = responseJson?
|
||||
.Candidates?
|
||||
.FirstOrDefault()?
|
||||
.Content
|
||||
.Parts?.FirstOrDefault()?
|
||||
.Text;
|
||||
var requestUrl =
|
||||
$"https://generativelanguage.googleapis.com/v1beta/models/{_model}:generateContent?key={_apiKey}";
|
||||
var generateContentRequest = new GenerateContentRequest(
|
||||
[
|
||||
new Content(
|
||||
Role: "user",
|
||||
Parts: [new Part(Text: _prompt.GetPrompt(segments))]
|
||||
)
|
||||
],
|
||||
new GenerationConfig(ResponseMimeType: "application/json")
|
||||
);
|
||||
using var requestContent = new StringContent(
|
||||
JsonSerializer.Serialize(generateContentRequest),
|
||||
Encoding.UTF8,
|
||||
"application/json"
|
||||
);
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, requestUrl) { Content = requestContent };
|
||||
|
||||
var clips = JsonSerializer.Deserialize<List<ShortCandidate>>(candidatesText ?? string.Empty);
|
||||
return new TranscriptAnalysis(clips ?? []);
|
||||
var response = await client.SendAsync(request).ConfigureAwait(false);
|
||||
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
var responseJson = JsonSerializer.Deserialize<GenerateContentResponse>(responseContent);
|
||||
var candidatesText = responseJson?
|
||||
.Candidates?
|
||||
.FirstOrDefault()?
|
||||
.Content
|
||||
.Parts?.FirstOrDefault()?
|
||||
.Text;
|
||||
|
||||
var clips = JsonSerializer.Deserialize<List<ShortCandidate>>(candidatesText ?? string.Empty);
|
||||
return new TranscriptAnalysis(clips ?? []);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new FailedTranscriptAnalysisException("Failed to analyze transcript segments using Gemini.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -11,6 +11,7 @@ public interface ITranscriptAnalyzer
|
||||
/// Analyzes the provided transcript segments and generates a transcript analysis result.
|
||||
/// </summary>
|
||||
/// <param name="segments">The transcript segments to analyze.</param>
|
||||
/// <returns>A task that represents the asynchronous operation. The task result contains the <see cref="TranscriptAnalysis"/> containing the short clips derived from the transcript.</returns>
|
||||
/// <returns>A task that represents the asynchronous operation. The task result contains the <see cref="TranscriptAnalysis"/> containing the short clips derived from the transcript.</returns>
|
||||
/// <exception cref="FailedTranscriptAnalysisException">Thrown when the analysis fails due to an error.</exception>
|
||||
Task<TranscriptAnalysis> AnalyzeAsync(IEnumerable<TranscriptionSegment> segments);
|
||||
}
|
||||
@@ -42,8 +42,9 @@ internal sealed class DefaultAnalysisPrompt : IAnalysisPrompt
|
||||
{0}
|
||||
");
|
||||
|
||||
public string GetPrompt(IEnumerable<TranscriptionSegment> transcript)
|
||||
public string GetPrompt(IEnumerable<TranscriptionSegment> segments)
|
||||
{
|
||||
var transcript = string.Join(Environment.NewLine, segments);
|
||||
return string.Format(CultureInfo.InvariantCulture, Prompt, transcript);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user