Skip to content

Commit 7501085

Browse files
committed
ログ機能の追加とダウンロード処理のリファクタリング
コード全体にログ記録機能を導入し、進捗状況の可視化を実現しました。また、ダウンロード処理をリファクタリングし、再利用可能な拡張メソッドを追加しました。これにより、デバッグや運用時の利便性が向上しました。
1 parent 752df66 commit 7501085

4 files changed

Lines changed: 89 additions & 10 deletions

File tree

Plugins/WindowTranslator.Plugin.BergamotTranslatorPlugin/BergamotTranslator.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Globalization;
44
using System.IO.Compression;
55
using BergamotTranslatorSharp;
6+
using Microsoft.Extensions.Logging;
67
using Microsoft.Extensions.Options;
78
using Octokit;
89
using WindowTranslator.ComponentModel;
@@ -58,11 +59,12 @@ private string[] Translate(TextInfo[] srcTexts)
5859
}
5960
}
6061

61-
public class BergamotValidator(IGitHubClient client) : ITargetSettingsValidator
62+
public class BergamotValidator(IGitHubClient client, ILogger<BergamotValidator> logger) : ITargetSettingsValidator
6263
{
6364
private const string RepoOwner = "mozilla";
6465
private const string RepoName = "firefox-translations-models";
6566
private readonly IGitHubClient client = client;
67+
private readonly ILogger<BergamotValidator> logger = logger;
6668

6769
public async ValueTask<ValidateResult> Validate(TargetSettings settings)
6870
{
@@ -162,7 +164,9 @@ private async ValueTask<List<string>> DownloadAndExtractFiles(IReadOnlyList<Repo
162164
foreach (var content in contents)
163165
{
164166
var tmpPath = Path.Combine(tmpDir, content.Name);
167+
this.logger.LogInformation("Downloading {FileName}...", content.Name);
165168
await this.client.DownloadFileAsync(RepoOwner, RepoName, content, tmpPath).ConfigureAwait(false);
169+
this.logger.LogInformation("Downloaded {FileName}", content.Name);
166170

167171
var fileName = await ExtractFileIfNeeded(tmpPath, modelDir);
168172
files.Add(fileName);

Plugins/WindowTranslator.Plugin.PLaMoPlugin/PLaMoOptions.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System.ComponentModel.DataAnnotations;
2+
using Microsoft.Extensions.Logging;
23
using PropertyTools.DataAnnotations;
34
using WindowTranslator.ComponentModel;
5+
using WindowTranslator.Extensions;
46
using WindowTranslator.Modules;
57
using WindowTranslator.Plugin.PLaMoPlugin.Properties;
68

@@ -23,8 +25,9 @@ public class PLaMoOptions : IPluginParam
2325
public int VRAM { get; set; } = -1;
2426
}
2527

26-
public class PLaMoValidator : ITargetSettingsValidator
28+
public class PLaMoValidator(ILogger<PLaMoValidator> logger) : ITargetSettingsValidator
2729
{
30+
private readonly ILogger<PLaMoValidator> logger = logger;
2831

2932
public async ValueTask<ValidateResult> Validate(TargetSettings settings)
3033
{
@@ -45,7 +48,7 @@ public async ValueTask<ValidateResult> Validate(TargetSettings settings)
4548
}
4649
}
4750

48-
private static async ValueTask DownloadModelIfNotExists()
51+
private async ValueTask DownloadModelIfNotExists()
4952
{
5053
var modelPath = PLaMoOptions.ModelPath;
5154
// すでにモデルファイルが存在する場合は処理をスキップ
@@ -57,11 +60,7 @@ private static async ValueTask DownloadModelIfNotExists()
5760

5861
// モデルファイルをダウンロード
5962
using var httpClient = new HttpClient();
60-
using var response = await httpClient.GetAsync(PLaMoOptions.ModelUrl, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
61-
response.EnsureSuccessStatusCode();
62-
63-
await using var contentStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
64-
await using var fileStream = new FileStream(modelPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 8192, useAsync: true);
65-
await contentStream.CopyToAsync(fileStream).ConfigureAwait(false);
63+
this.logger.LogInformation("Downloading PLaMo model...");
64+
await httpClient.DownloadFile(PLaMoOptions.ModelUrl, modelPath, p => this.logger.LogInformation($"Downloading PLaMo model: {p:P2}")).ConfigureAwait(false);
6665
}
6766
}

Plugins/WindowTranslator.Plugin.TesseractOCRPlugin/TesseractOcrValidator.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Diagnostics;
2+
using Microsoft.Extensions.Logging;
23
using Microsoft.Win32;
34
using Octokit;
45
using TesseractOCR.Enums;
@@ -10,11 +11,12 @@
1011

1112
namespace WindowTranslator.Plugin.TesseractOCRPlugin;
1213

13-
public class TesseractOcrValidator(IGitHubClient client, IContentDialogService dialogService) : ITargetSettingsValidator
14+
public class TesseractOcrValidator(IGitHubClient client, IContentDialogService dialogService, ILogger<TesseractOcrValidator> logger) : ITargetSettingsValidator
1415
{
1516
private static readonly ValidateResult Invalid = ValidateResult.Invalid("TesseractOcr", Resources.NotInstalledVcRedist);
1617
private readonly IGitHubClient client = client;
1718
private readonly IContentDialogService dialogService = dialogService;
19+
private readonly ILogger<TesseractOcrValidator> logger = logger;
1820

1921
public async ValueTask<ValidateResult> Validate(TargetSettings settings)
2022
{
@@ -92,9 +94,11 @@ await this.dialogService.ShowSimpleDialogAsync(new()
9294
}
9395

9496
// IGitHubClient を利用して `tesseract-ocr/tessdata_best` リポジトリからeng.traineddataをダウンロードする
97+
this.logger.LogInformation("Downloading {LangData} from tessdata_best repository", langData);
9598
var contents = await client.Repository.Content.GetRawContent("tesseract-ocr", "tessdata_best", langData);
9699
await using var fs = File.Create(langDataPath);
97100
await fs.WriteAsync(contents).ConfigureAwait(false);
101+
this.logger.LogInformation("Downloaded {LangData} to {Path}", langData, langDataPath);
98102
return ValidateResult.Valid;
99103
}
100104

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using System.Buffers;
2+
using System.Diagnostics.CodeAnalysis;
3+
4+
namespace WindowTranslator.Extensions;
5+
6+
/// <summary>
7+
/// <see cref="HttpClient"/> の拡張メソッドを提供します。
8+
/// </summary>
9+
public static class HttpClientExtensions
10+
{
11+
/// <summary>
12+
/// 指定したURIからファイルを非同期でダウンロードし、ダウンロードの進捗状況を1秒ごとに報告します。
13+
/// </summary>
14+
/// <param name="httpClient">HTTPクライアント。</param>
15+
/// <param name="uri">ダウンロード元のURI。</param>
16+
/// <param name="path">ダウンロード先のファイルパス。</param>
17+
/// <param name="progress">ダウンロードの進捗状況を受け取るコールバック。進捗率は0.0~1.0の範囲で報告されます。</param>
18+
/// <param name="token">キャンセルトークン</param>
19+
/// <returns>非同期操作を表すタスク。</returns>
20+
/// <exception cref="HttpRequestException">HTTPリクエストが失敗した場合にスローされます。</exception>
21+
/// <remarks>
22+
/// このメソッドは以下の動作を行います:
23+
/// <list type="bullet">
24+
/// <item><description>Content-Lengthヘッダーが存在する場合、1秒ごとに進捗率を計算して報告します。</description></item>
25+
/// <item><description>Content-Lengthヘッダーが存在しない場合、ダウンロード完了時にのみ100%を報告します。</description></item>
26+
/// <item><description>80KBのバッファサイズでストリーミングダウンロードを実行します。</description></item>
27+
/// <item><description>ダウンロード完了時には必ず100%(1.0f)の進捗を報告します。</description></item>
28+
/// </list>
29+
/// </remarks>
30+
public static async ValueTask DownloadFile(this HttpClient httpClient, [StringSyntax("Uri")] string uri, string path, Action<float> progress, CancellationToken token = default)
31+
{
32+
using var response = await httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead, token).ConfigureAwait(false);
33+
response.EnsureSuccessStatusCode();
34+
35+
var contentLength = response.Content.Headers.ContentLength;
36+
if (!contentLength.HasValue)
37+
{
38+
// Content-Lengthがない場合は通常のダウンロード
39+
await using var stream = File.Create(path);
40+
await response.Content.CopyToAsync(stream, token).ConfigureAwait(false);
41+
progress(1.0f);
42+
return;
43+
}
44+
45+
var totalBytes = contentLength.Value;
46+
using var buffer = MemoryPool<byte>.Shared.Rent(81920); // 80KB バッファ
47+
var totalBytesRead = 0L;
48+
var lastProgressReport = DateTime.UtcNow;
49+
var progressReportInterval = TimeSpan.FromSeconds(1);
50+
51+
await using var contentStream = await response.Content.ReadAsStreamAsync(token).ConfigureAwait(false);
52+
await using var fileStream = File.Create(path);
53+
54+
int bytesRead;
55+
while ((bytesRead = await contentStream.ReadAsync(buffer.Memory, token).ConfigureAwait(false)) > 0)
56+
{
57+
await fileStream.WriteAsync(buffer.Memory[..bytesRead], token).ConfigureAwait(false);
58+
totalBytesRead += bytesRead;
59+
60+
var now = DateTime.UtcNow;
61+
if (now - lastProgressReport >= progressReportInterval)
62+
{
63+
var currentProgress = (float)totalBytesRead / totalBytes;
64+
progress(currentProgress);
65+
lastProgressReport = now;
66+
}
67+
}
68+
69+
// 最終的な進捗を報告
70+
progress(1.0f);
71+
}
72+
}

0 commit comments

Comments
 (0)