mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-09-18 12:45:17 +08:00
feat(glossary): 实现 Rust Glossary V1
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use super::report_output::print_json_value;
|
||||
use super::*;
|
||||
use bat_core::domain::TranslationMemoryContext;
|
||||
use bat_core::domain::{GlossaryOverride, TranslationMemoryContext};
|
||||
use bat_core::repositories::TranslationMemoryRepository;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
@@ -9,6 +9,8 @@ struct TranslationTaskResultUpdateParam {
|
||||
unit_id: String,
|
||||
source_text: String,
|
||||
translated_text: String,
|
||||
#[serde(default)]
|
||||
glossary_override: Option<GlossaryOverride>,
|
||||
}
|
||||
|
||||
pub(super) fn build_translation_tasks_report(
|
||||
@@ -170,6 +172,7 @@ pub(super) fn build_translation_handoff_report(
|
||||
pub(super) fn update_translation_task_status_report(
|
||||
state_dir: &Path,
|
||||
params: Option<&serde_json::Value>,
|
||||
configured_glossary_path: Option<&Path>,
|
||||
) -> anyhow::Result<serde_json::Value> {
|
||||
let task_id = rpc_string_param(params, "task_id")
|
||||
.ok_or_else(|| anyhow::anyhow!("translation.task.update 缺少 task_id"))?;
|
||||
@@ -229,6 +232,22 @@ pub(super) fn update_translation_task_status_report(
|
||||
.find(task_id)
|
||||
.await
|
||||
.map_err(|error| anyhow::anyhow!("{error}"))?;
|
||||
let glossary_path = configured_glossary_path
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|| {
|
||||
bat_infrastructure::SqliteGlossaryRepository::repository_path(
|
||||
¤t.resource_root,
|
||||
)
|
||||
});
|
||||
let glossary = if std::fs::symlink_metadata(&glossary_path).is_ok() {
|
||||
Some(
|
||||
bat_infrastructure::SqliteGlossaryRepository::open(&glossary_path)
|
||||
.await
|
||||
.map_err(|error| anyhow::anyhow!("打开 Glossary 数据库失败:{error}"))?,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let results = build_manual_translation_results(
|
||||
¤t_task,
|
||||
index,
|
||||
@@ -236,7 +255,9 @@ pub(super) fn update_translation_task_status_report(
|
||||
&result_provider,
|
||||
&result_provider_run_id,
|
||||
result_timestamp,
|
||||
)?;
|
||||
glossary.as_ref(),
|
||||
)
|
||||
.await?;
|
||||
repository
|
||||
.update_status_with_results(
|
||||
task_id,
|
||||
@@ -291,13 +312,14 @@ fn translation_task_result_params(
|
||||
.map_err(|error| anyhow::anyhow!("translation_results 必须是结果数组:{error}"))
|
||||
}
|
||||
|
||||
fn build_manual_translation_results(
|
||||
async fn build_manual_translation_results(
|
||||
task: &bat_infrastructure::PersistedTranslationTask,
|
||||
index: &bat_infrastructure::OfficialTextUnitIndex,
|
||||
params: &[TranslationTaskResultUpdateParam],
|
||||
provider: &str,
|
||||
provider_run_id: &str,
|
||||
translated_unix_seconds: u64,
|
||||
glossary: Option<&bat_infrastructure::SqliteGlossaryRepository>,
|
||||
) -> anyhow::Result<Vec<bat_infrastructure::TranslationTaskUnitResult>> {
|
||||
let index_by_id = index
|
||||
.units
|
||||
@@ -332,6 +354,53 @@ fn build_manual_translation_results(
|
||||
"TextUnit {unit_id} 的 source_text 与当前索引不一致"
|
||||
));
|
||||
}
|
||||
let glossary_qa = if let Some(glossary) = glossary {
|
||||
let context = bat_infrastructure::translation_memory_context(
|
||||
&unit.destination,
|
||||
unit.archive_entry.as_deref(),
|
||||
unit.serialized_file.as_deref(),
|
||||
unit.path_id,
|
||||
unit.class_id,
|
||||
unit.field_path.as_deref(),
|
||||
unit.format.as_deref(),
|
||||
unit.asset_name.as_deref(),
|
||||
unit.text_source_kind.as_deref(),
|
||||
&unit.context,
|
||||
);
|
||||
Some(
|
||||
glossary
|
||||
.diagnose(&unit.source_text, &context)
|
||||
.await
|
||||
.map_err(|error| anyhow::anyhow!("Glossary QA 失败:{error}"))?
|
||||
.check_translation(¶m.translated_text),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(qa) = glossary_qa.as_ref().filter(|qa| qa.status.is_blocked()) {
|
||||
let Some(override_record) = param.glossary_override.as_ref() else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"TextUnit {} 的 Glossary QA blocked;必须提供 glossary_override",
|
||||
unit_id
|
||||
));
|
||||
};
|
||||
if override_record.reviewer.trim().is_empty()
|
||||
|| override_record.reason.trim().is_empty()
|
||||
|| override_record.provenance.trim().is_empty()
|
||||
|| override_record.confirmed_unix_seconds == 0
|
||||
{
|
||||
return Err(anyhow::anyhow!(
|
||||
"TextUnit {} 的 glossary_override 不完整或 confirmed_unix_seconds 无效",
|
||||
unit_id
|
||||
));
|
||||
}
|
||||
let _ = qa;
|
||||
} else if param.glossary_override.is_some() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"TextUnit {} 不能为非 blocking Glossary QA 指定 override",
|
||||
unit_id
|
||||
));
|
||||
}
|
||||
results.push(bat_infrastructure::TranslationTaskUnitResult {
|
||||
unit_id: unit_id.to_string(),
|
||||
source_text: param.source_text.clone(),
|
||||
@@ -341,6 +410,8 @@ fn build_manual_translation_results(
|
||||
provider: provider.to_string(),
|
||||
provider_run_id: provider_run_id.to_string(),
|
||||
translated_unix_seconds,
|
||||
glossary_qa,
|
||||
glossary_override: param.glossary_override.clone(),
|
||||
});
|
||||
}
|
||||
Ok(results)
|
||||
|
||||
Reference in New Issue
Block a user