Skip to content

Commit

Permalink
Issue #14 (#36) 《Command》に /set <set-name> コマンドを追加することで「入力セット」機能を追加します
Browse files Browse the repository at this point in the history
* fix #14
《Command》に /set <set-name> コマンドを追加することで「入力セット」機能を追加します

* 設定サンプルファイルにコメント追加
  • Loading branch information
usagi authored Oct 14, 2023
1 parent b166e27 commit 5b1ad48
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 6 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ alkana-rs = "0.1.0"
whatlang = "0.16.3"
isolang = { version = "2.3.0", features = ["list_languages"] }
os_info = "3.7.0"
async-recursion = "1.0.5"

# Windows Only
[target.'cfg(windows)'.dependencies]
Expand Down
83 changes: 83 additions & 0 deletions conf.example-command.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# 音声から「かっこよくそれっぽいコマンド」を演出します。(必須ではありませんが心躍る方は参考にして下さい。)
[[processors]]
feature = "modify"
channel_from = "user"
channel_to = "system"
regex_files = ["regex.pre-command.txt"]

# コマンドプロセッサーの使用例です。
[[processors]]
feature = "command"
channel_from = "system"
# コマンド実行に対する応答を表示したり音声合成させたい場合は送信先チャンネルを設定します。
channel_to = "ai"
# 応答メッセージをカスタマイズしたい場合は設定します。設定しない場合はデフォルトの応答メッセージが使用されます。
response_mod = [
[
"disable",
"システムコマンドにより{A}モジュールは無効化された。",
],
[
"enable",
"システムコマンドにより{A}モジュールは有効化された。",
],
[
"reload",
"システムコマンドにより{A}モジュールは再読み込みされた。",
],
[
"set",
"了解した。セット{A}の実行を試みる。",
],
[
"set:error",
"セット{A}の実行中にエラーが発生している。エラーログを確認するといい。",
],
[
"_",
"コマンドまたは何かが違うようだ。",
],
]

# セットコマンド( /set <セット名> )を使用したい場合に設定します。
[[processors.set]]
# /set <name> で呼び出す <name> の部分を設定します。お好みのセット名を設定できます。
name = "init"
# この init セットが実行される際、直前に追加で実行したいセット群があれば設定します。
pre = []
# この init セットが実行される際、直後に追加で実行したいセット群があれば設定します。
post = ["clear", "preparing"]

# /set init コマンドで送出したいチャンネルとコンテントを設定します。こちらは1つめです。
[[processors.set.channel_contents]]
channel = "title"
content = "Dr.USAGIとKal'tsit Pseudo先生ののんびりゲームお楽しみ配信"
# 1つのコマンドで複数のチャンネルとコンテントへ送出できます。こちらは2つめです。
[[processors.set.channel_contents]]
channel = "description"
content = "配信支援アプリ Virtual Avatar Connect 一般公開中です👀 https://usagi.github.io/virtual-avatar-connect/"

# /set clear コマンド
[[processors.set]]
name = "clear"
[[processors.set.channel_contents]]
channel = "user"
content = ""
[[processors.set.channel_contents]]
channel = "ai"
content = ""

# /set preparing コマンド
[[processors.set]]
name = "preparing"
[[processors.set.channel_contents]]
channel = "brb"
content = "只今、配信準備中です。 now preparing for streaming."
[[processors.set.channel_contents]]
channel = "scene"
content = "overlay brb"

# OS-TTS で ai チャンネルに出力されたコンテントを音声合成して読み上げます。
[[processors]]
feature = "OS-TTS"
channel_from = "ai"
12 changes: 7 additions & 5 deletions regex.pre-command.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/quit ^\s*システムコマンド\s*シャットダウン
/reload ^\s*システムコマンド\s*リロード
/disable ^\s*システムコマンド\s*ディゼ[イー]ブル
/enable ^\s*システムコマンド\s*イネ[イー]ブル
/? ^\s*システムコマンド
/quit ^\s*システムコマンド\s*シャットダウン.*
/reload ^\s*システムコマンド\s*リロード.*
/disable ^\s*システムコマンド\s*ディゼ[イー]ブル.*
/enable ^\s*システムコマンド\s*イネ[イー]ブル.*
/set init ^\s*システムコマンド\s*セット\s*(イニット|イニシャライズ).*
/set clear ^\s*システムコマンド\s*セット\s*クリア.*
/? ^\s*システムコマンド.*
19 changes: 19 additions & 0 deletions src/conf/processor_conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@ use serde::{Deserialize, Serialize};

pub type SharedProcessorConf = Arc<RwLock<ProcessorConf>>;

#[derive(Debug, Deserialize, Serialize, Clone, Default)]
pub struct ContentWithChannel {
pub channel: String,
pub content: String,
}

#[derive(Debug, Deserialize, Serialize, Clone, Default)]
pub struct CommandSet {
pub name: String,
#[serde(default)]
pub pre: Vec<String>,
#[serde(default)]
pub post: Vec<String>,
#[serde(default)]
pub channel_contents: Vec<ContentWithChannel>,
}

#[derive(Debug, Deserialize, Serialize, Clone, Default)]
pub struct ProcessorConf {
// Common
Expand All @@ -22,6 +39,8 @@ pub struct ProcessorConf {
pub through_if_not_command: Option<bool>,
#[serde(default)]
pub response_mod: Vec<Vec<String>>,
#[serde(default)]
pub set: Vec<CommandSet>,

// screenshot
pub title: Option<String>,
Expand Down
48 changes: 47 additions & 1 deletion src/processor/command.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{CompletedAnd, Processor};
use crate::conf::CommandSet;
use crate::{ChannelDatum, ProcessorConf, ProcessorKind, SharedChannelData, SharedProcessorConf, SharedState};
use anyhow::{bail, Result};
use async_trait::async_trait;
Expand Down Expand Up @@ -82,8 +83,23 @@ impl Processor for Command {
)
.await;
},
"set" if args.len() >= 1 => {
log::info!("set がコマンドされセット名 {:?} の実行が試行されます。", args[0]);
response1(conf.clone(), self.state.clone(), "set", "セット {A} の実行を試みます。", args[0].clone()).await;
if let Err(e) = activate_command_set(args[0], &conf.set, self.state.clone()).await {
log::error!("セットの実行中にエラーが発生しました: {:?}", e);
response1(
conf,
self.state.clone(),
"set:error",
"セット {A} の実行中にエラーが発生しました。",
args[0].clone(),
)
.await;
}
},
_ => {
log::info!("コマンドまたは何かが違うようです。");
log::warn!("コマンドまたは何かが違うようです: command = {:?} args = {:?}", command, args);
response0(conf, self.state.clone(), "_", "コマンドまたは何かが違うようです。").await;
},
}
Expand Down Expand Up @@ -173,3 +189,33 @@ async fn response1(conf: ProcessorConf, state: SharedState, command: &str, defau
let state = state.read().await;
state.push_channel_datum(cd).await;
}

#[async_recursion::async_recursion]
async fn activate_command_set(set_name: &str, command_sets: &Vec<CommandSet>, state: SharedState) -> Result<()> {
// find
let command = command_sets
.iter()
.find(|&c| c.name == set_name)
.ok_or_else(|| anyhow::anyhow!("セット名 {:?} が見つかりませんでした。", set_name))?;

for pre in &command.pre {
if let Err(e) = activate_command_set(&pre, command_sets, state.clone()).await {
log::error!("pre 処理でエラーが発生しました: {:?}", e);
}
}

for cc in &command.channel_contents {
// log::warn!("channel = {:?} に content = {:?} を送信します。", cc.channel, cc.content)
let cd = ChannelDatum::new(cc.channel.clone(), cc.content.clone()).with_flag(ChannelDatum::FLAG_IS_FINAL);
let state = state.read().await;
state.push_channel_datum(cd).await;
}

for post in &command.post {
if let Err(e) = activate_command_set(&post, command_sets, state.clone()).await {
log::error!("post 処理でエラーが発生しました: {:?}", e);
}
}

Ok(())
}

0 comments on commit 5b1ad48

Please sign in to comment.