This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
所以有一阵子以来 我用简单NMT翻译 .md
不同语言的文件 在这里.. 我想"露面"这个 这样你们也能一起玩一玩
见本系列的第二部分。 在这里.
你们眼中的鹰会注意到 我给记分编辑加了点滴
这是一份我翻译的语言列表( EasyNMT 有点像资源型猪, 所以我限制我可以翻译的语言数量) 。
[技选委
当您从下载中选择语言时, 并按下按钮, 您会发送“ 翻译” 任务到此 API :
[ApiController]
[Route("api/[controller]")]
public class TranslateController(
BackgroundTranslateService backgroundTranslateService,
TranslateCacheService translateCacheService) : ControllerBase
{
[HttpPost("start-translation")]
public async Task<IActionResult> StartTranslation([FromBody] MarkdownTranslationModel model)
{
// Create a unique identifier for this translation task
var taskId = Guid.NewGuid().ToString("N");
var userId = Request.GetUserId(Response);
// Trigger translation and store the associated task
var translationTask = await backgroundTranslateService.Translate(model);
var translateTask = new TranslateTask(taskId, model.Language, translationTask);
translateCacheService.AddTask(userId, translateTask);
// Return the task ID to the client
return Ok(new { TaskId = taskId });
}
}
THS做一些事情:
Cookie 服务是 Httprequest 对象的简单扩展名 。 它检查一个饼干是否存在, 如果它没有它创造一个新的。 这是用来识别您和您的翻译任务 。
public static class UserIdHtlper
{
public static string GetUserId(this HttpRequest request, HttpResponse response)
{
var userId = request.Cookies["UserIdentifier"];
if (userId == null)
{
userId = Guid.NewGuid().ToString();
var cookieOptions = new CookieOptions
{
Expires = DateTimeOffset.UtcNow.AddMinutes(60),
HttpOnly = true,
Secure = true,
SameSite = SameSiteMode.Strict
};
response.Cookies.Append("UserIdentifier", userId, cookieOptions);
}
return userId;
}
}
缓存服务使用简单的记忆缓存来为单个用户( 您! ) 保存所有翻译任务 。 你等着瞧吧 我已经安排了一个小时后 缓存过期了 这是因为我不想 坚持这些任务太久。
public class TranslateCacheService(IMemoryCache memoryCache)
{
public List<TranslateTask> GetTasks(string userId)
{
if (memoryCache.TryGetValue(userId, out List<TranslateTask>? task)) return task;
return new List<TranslateTask>();
}
public void AddTask(string userId, TranslateTask task)
{
if (memoryCache.TryGetValue(userId, out List<TranslateTask>? tasks))
{
tasks ??= new List<TranslateTask>();
tasks.Add(task);
memoryCache.Set(userId, tasks, new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
});
}
else
{
memoryCache.Set(userId, new List<TranslateTask> { task }, new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
});
}
}
}
public record TranslateTask(string TaskId, string language, Task<TaskCompletion>? Task);
我会在下一部分报道的,它有点像野兽。
然而, Translate
方法使用任务完成源来让我们跟踪翻译任务的状况 。
public async Task<Task<TaskCompletion>> Translate(MarkdownTranslationModel message)
{
// Create a TaskCompletionSource that will eventually hold the result of the translation
var translateMessage = new PageTranslationModel
{
Language = message.Language,
OriginalFileName = "",
OriginalMarkdown = message.OriginalMarkdown,
Persist = false
};
return await Translate(translateMessage);
}
private async Task<Task<TaskCompletion>> Translate(PageTranslationModel message)
{
// Create a TaskCompletionSource that will eventually hold the result of the translation
var tcs = new TaskCompletionSource<TaskCompletion>();
// Send the translation request along with the TaskCompletionSource to be processed
await _translations.SendAsync((message, tcs));
return tcs.Task;
}
正如你可以看到的,所有这一切 真正做的就是发送翻译到一个 BufferBlock
(我将来会看电视频道,这或许是更好的办法! )) )
它还使用一种 TaskCompletionSource
来跟踪翻译任务的状况。
在处理服务内部(我们稍后再讨论),我们设定了结果 TaskCompletionSource
翻译工作的结果。
var translatedMarkdown =
await markdownTranslatorService.TranslateMarkdown(translateModel.OriginalMarkdown,
translateModel.Language, cancellationToken);
tcs.SetResult(new TaskCompletion(translatedMarkdown, translateModel.Language, true, DateTime.Now));
}
通过这样做,我们可以“发送”我们储存在缓存中的翻译任务状态,并给用户反馈翻译状况。 这可能需要几分钟时间,视交通量和标记文件长度而定。
你已经看到我们为你设置了一个浏览器饼干了 这是用来识别您和您的翻译任务 。 在您提交译文后, 我们将使用 HTMX 民调来点击此动作, 只需返回您的译文 。
[HttpGet]
[Route("get-translations")]
public IActionResult GetTranslations()
{
var userId = Request.GetUserId(Response);
var tasks = translateCacheService.GetTasks(userId);
var translations = tasks;
return PartialView("_GetTranslations", translations);
}
一旦有翻译及其状态列表, 您可以使用此列表来选择翻译, 并在 Markdown 编辑器中出现 。 使用此 API 端点来获得任务 ;
[HttpGet]
[Route("get-translation/{taskId}")]
public Results<JsonHttpResult<TaskCompletion>, BadRequest<string>> GetTranslation(string taskId)
{
var userId = Request.GetUserId(Response);
var tasks = translateCacheService.GetTasks(userId);
var translationTask = tasks.FirstOrDefault(t => t.TaskId == taskId);
if(translationTask?.Task?.Status != System.Threading.Tasks.TaskStatus.RanToCompletion)
{
return TypedResults.BadRequest<string>("Task not completed");
}
return TypedResults.Json(translationTask.Task.Result);
}
早些时我还在建这个房子 但我很兴奋看到它能到哪里去 我将在下一期详细报道背景服务。