aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-06-21 22:45:28 +0800
committer魏曹先生 <1992414357@qq.com>2026-06-21 22:45:28 +0800
commitc6885ae2312a1be589e945129bdd9d268f14c370 (patch)
tree919e0fe49331b533de312a39548f17b133ef4975 /src
parent291c01fd98d44e42bb0a65468e3b6cee3dc25044 (diff)
feat: replace `--pinyin` flag with generic `--post="+pinyin"` option
Diffstat (limited to 'src')
-rw-r--r--src/args.rs50
-rw-r--r--src/main.rs6
-rw-r--r--src/post_proc.rs25
-rw-r--r--src/post_proc/pinyin.rs31
-rw-r--r--src/post_proc/trait.rs12
5 files changed, 112 insertions, 12 deletions
diff --git a/src/args.rs b/src/args.rs
index 11a1f11..7b472c4 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -118,9 +118,9 @@ pub struct DMVOPArguments {
)]
pub subnet_mask: String,
- // Convert text output to pinyin (Chinese romanization)
- #[arg(long = "pinyin")]
- pub use_pinyin: bool,
+ // Post-processing pipeline, e.g. --post="+pinyin()" or --post="+reverse"
+ #[arg(long = "post", require_equals = true)]
+ pub post: Option<String>,
}
#[derive(Clone, Debug)]
@@ -182,13 +182,43 @@ pub fn format_output(pattern: &str, word: &str, confidence: f32, volume: f32) ->
result
}
-/// Convert transcribed text to pinyin if the `use_pinyin` flag is set.
-/// Otherwise returns the original text as a String.
-pub fn maybe_to_pinyin(text: &str, use_pinyin: bool) -> String {
- if use_pinyin {
- pinyin::to_pinyin_vec(text, pinyin::Pinyin::plain).join(" ")
- } else {
- text.to_string()
+/// Parse a post-processor spec in the form `+function_name(arg1, arg2, ...)`.
+/// Returns `(name, args)`.
+pub fn parse_post_spec(spec: &str) -> (&str, Vec<&str>) {
+ let spec = spec.trim();
+ if !spec.starts_with('+') {
+ return (spec, vec![]);
+ }
+ let inner = &spec[1..];
+ if let Some(paren) = inner.find('(') {
+ if inner.ends_with(')') {
+ let name = inner[..paren].trim();
+ let args_str = inner[paren + 1..inner.len() - 1].trim();
+ let args: Vec<&str> = if args_str.is_empty() {
+ vec![]
+ } else {
+ // Simple comma split (no nested parens, no escape handling for now)
+ args_str.split(',').map(|a| a.trim()).collect()
+ };
+ return (name, args);
+ }
+ }
+ // No parens → no args
+ (inner.trim(), vec![])
+}
+
+/// Run the post-processing pipeline on the given text.
+pub fn run_post_process(text: &str, spec: Option<&str>) -> String {
+ let Some(spec) = spec else {
+ return text.to_string();
+ };
+ let (name, args) = parse_post_spec(spec);
+ match crate::post_proc::run(text, name, &args) {
+ Some(result) => result,
+ None => {
+ eprintln!("[dmvop] Unknown post-processor: '{}'", name);
+ text.to_string()
+ }
}
}
diff --git a/src/main.rs b/src/main.rs
index e3a5b84..73b4e06 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,5 @@
+pub mod post_proc;
+
mod args;
pub use args::*;
@@ -252,7 +254,7 @@ async fn main() {
match rx.recv().await {
Ok(event) => match event {
vtx_engine::EngineEvent::TranscriptionComplete(result) => {
- let raw = maybe_to_pinyin(&result.text, args.use_pinyin);
+ let raw = run_post_process(&result.text, args.post.as_deref());
let formatted = format_output(&pattern, &raw, 0.0, last_volume_db);
for ch in &channels {
@@ -260,7 +262,7 @@ async fn main() {
}
}
vtx_engine::EngineEvent::TranscriptionSegment(segment) => {
- let raw = maybe_to_pinyin(&segment.text, args.use_pinyin);
+ let raw = run_post_process(&segment.text, args.post.as_deref());
let formatted = format_output(&pattern, &raw, 0.0, last_volume_db);
for ch in &channels {
diff --git a/src/post_proc.rs b/src/post_proc.rs
new file mode 100644
index 0000000..d8dfa74
--- /dev/null
+++ b/src/post_proc.rs
@@ -0,0 +1,25 @@
+mod r#trait;
+pub use r#trait::*;
+
+pub mod pinyin;
+
+/// Look up a processor by name and run it.
+pub fn run(text: &str, name: &str, args: &[&str]) -> Option<String> {
+ macro_rules! match_processor {
+ ($($processor:ty),+ $(,)?) => {
+ match name {
+ $(
+ n if n == <$processor as TextPostProcesser>::processer_name() => {
+ Some(<$processor as TextPostProcesser>::process(args, text))
+ }
+ )+
+ _ => None,
+ }
+ };
+ }
+
+ match_processor!(
+ // +pinyin
+ crate::post_proc::pinyin::PinyinPostProcesser,
+ )
+}
diff --git a/src/post_proc/pinyin.rs b/src/post_proc/pinyin.rs
new file mode 100644
index 0000000..c06b040
--- /dev/null
+++ b/src/post_proc/pinyin.rs
@@ -0,0 +1,31 @@
+use crate::post_proc::TextPostProcesser;
+
+/// Converts Chinese characters to pinyin (romanized phonetic representation).
+///
+/// # Styles
+/// - `plain` — ni hao (default)
+/// - `tone` — nǐ hǎo (with tone marks, requires `with_tone` feature)
+/// - `tone-num` — ni3 hao3 (tone number at end)
+/// - `first-letter` — n h (first letter only)
+pub struct PinyinPostProcesser;
+
+impl TextPostProcesser for PinyinPostProcesser {
+ fn processer_name() -> &'static str {
+ "pinyin"
+ }
+
+ fn process(param: &[&str], text: &str) -> String {
+ let style = param.first().copied().unwrap_or("plain");
+ let result: Vec<&'static str> = match style {
+ "tone" => pinyin::to_pinyin_vec(text, pinyin::Pinyin::with_tone),
+ "tone-num" | "tone_num" => {
+ pinyin::to_pinyin_vec(text, pinyin::Pinyin::with_tone_num_end)
+ }
+ "first-letter" | "first_letter" => {
+ pinyin::to_pinyin_vec(text, pinyin::Pinyin::first_letter)
+ }
+ _ => pinyin::to_pinyin_vec(text, pinyin::Pinyin::plain),
+ };
+ result.join(" ")
+ }
+}
diff --git a/src/post_proc/trait.rs b/src/post_proc/trait.rs
new file mode 100644
index 0000000..7fced5b
--- /dev/null
+++ b/src/post_proc/trait.rs
@@ -0,0 +1,12 @@
+/// A text post-processor that transforms transcribed text.
+pub trait TextPostProcesser {
+ /// Name used in `--post="+name(args)"`.
+ fn processer_name() -> &'static str;
+
+ /// Execute the post-processing.
+ ///
+ /// # Arguments
+ /// * `param` — arguments parsed from `--post="+name(arg1, arg2)"`
+ /// * `text` — the transcribed text to process
+ fn process(param: &[&str], text: &str) -> String;
+}