Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Voice2json #11

Merged
merged 6 commits into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions DragonbornSpeaksNaturally.SAMPLE-zhCN.ini
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
Engine=Microsoft
;Engine=Voice2Json

;;; 通过取消注释(删除开头的分号)为Voice2Json使用bash(wsl)设置而不是docker(默认)
;bVoice2JsonUseDocker=0

;;; 语音识别使用的语言,通常不需要设置,使用系统默认语言
;;; 如果要手动设置语言,请移除“Locale”前面的分号(;)。
;;;
Expand All @@ -45,7 +48,7 @@ Engine=Microsoft
;;; zh-cn, zh-tw, zh-hk, zh-sg
;;;
;;; Engine=Voice2Json 可用的语言:
;;; ca-es, cs-cz, de, el-gr, en, en-in, en-us, es, es-mexican,
;;; ca-es, cs-cz, de, el-gr, en, en-in, en-us, es, es-mexican,
;;; fr, hi, it, ko-kr, kz, nl, pl, pt-br, ru, sv, vi, zh, zh-cn
;;; 参考文档:http://voice2json.org/#supported-languages
;;;
Expand Down Expand Up @@ -123,7 +126,7 @@ omitHandSuffix=0
;;; 该选项允许你按类别装备收藏夹内物品。
;;; 类别是物品名称的一部分 (比如 "铁匕首" 和 "钢匕首" 都属于 "匕首")。
;;; 如果有多个物品属于同一类别,第一个物品会被装备。
;;;
;;;
;;; 提示:
;;; 1. 把等号后面的内容删空就可以禁用该功能。
;;; 2. 如果遇到随机装备物品的问题,可以考虑禁用该功能。
Expand Down Expand Up @@ -192,7 +195,7 @@ SubsetMatchingMode=None
;;; [自定义命令]
;;; 请不要修改、删除或者移动下面那行,它是ini配置节名称,删除后下面的选项就不起作用了!
[ConsoleCommands]

;;;
;;; 可以添加老滚5支持的控制台命令,格式如下:
;;;
Expand Down Expand Up @@ -224,12 +227,12 @@ SubsetMatchingMode=None
;我需要治疗=player.equipspell 12fcc left; player.equipspell 12fcc right; player.cast 12fcc player left; player.cast 12fcc player right
;我需要快速治疗=player.equipspell 0002f3b8 left; player.equipspell 0002f3b8 right; player.cast 0002f3b8 player left; player.cast 0002f3b8 player right

;;;
;;;
;;; 以下命令用于直接施放龙吼
;;;
;;;
;;; 你可以从以下页面的子页面找到命令所需的龙吼法术ID:
;;; https://en.uesp.net/wiki/Skyrim:Dragon_Shouts
;;;
;;;
;;; 注意,龙吼名称下方的ID不是其法术ID,而是龙吼本身的id,只能与 equipitem 命令一起使用,不能用于 cast 命令。
;;; 必须单击龙吼名称进入子页面,然后复制右侧表格里 Spell ID 下面的值。一个龙吼通常对应三个法术ID,对应1到3个力量之语。
;;;
Expand Down
19 changes: 11 additions & 8 deletions DragonbornSpeaksNaturally.SAMPLE.ini
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,17 @@
;Engine=Microsoft
Engine=Voice2Json

;;; Uncomment (remove leading semicolon) to use bash (wsl) setup for Voice2Json instead of docker (default)
;bVoice2JsonUseDocker=0

;;; Set this to override your system's default locale
;;;
;;; Available Locales for Engine=Microsoft:
;;; en-us, en-uk, en-ca, en-in, en-au, fr, de, ja,
;;; zh-cn, zh-tw, zh-hk, zh-sg
;;;
;;; Available Locales for Engine=Voice2Json:
;;; ca-es, cs-cz, de, el-gr, en, en-in, en-us, es, es-mexican,
;;; ca-es, cs-cz, de, el-gr, en, en-in, en-us, es, es-mexican,
;;; fr, hi, it, ko-kr, kz, nl, pl, pt-br, ru, sv, vi, zh, zh-cn
;;; References: http://voice2json.org/#supported-languages
;;;
Expand Down Expand Up @@ -109,23 +112,23 @@ enabled=0

;;; Set this to your preferred prefix for equipping items.
;;; Separate multiple words with semicolons.
;;;
;;;
;;; Tips:
;;; If you are struggling with uncontrolled random items equipping in your game,
;;; try set a more complicated prefix.
;;; try set a more complicated prefix.
equipPhrasePrefix=equip;wear;use

;;; Set to 1 to allow omission of equipPhrasePrefix,
;;; which allows you to directly name the equipment to equip the item.
;;;
;;;
;;; Note: Enabling this option can greatly increase the probability of false matches.
;;; DSN may equip items randomly due to noise.
omitHandSuffix=0

;;; This setting allows you to equip an item with it's type.
;;; Type is a part of the item name (such as "Dagger" for "Iron Dagger" and "Steel Dagger").
;;; If multiple items have the same type, the first will be equipped.
;;;
;;;
;;; Tips:
;;; 1. Remove all items below to disable this feature.
;;; 2. If you are struggling with uncontrolled random items equipping in your game, try to disable it.
Expand Down Expand Up @@ -223,12 +226,12 @@ SubsetMatchingMode=None
;I need treatment=player.equipspell 12fcc left; player.equipspell 12fcc right; player.cast 12fcc player left; player.cast 12fcc player right
;I need quick treatment!=player.equipspell 0002f3b8 left; player.equipspell 0002f3b8 right; player.cast 0002f3b8 player left; player.cast 0002f3b8 player right

;;;
;;;
;;; For a shout's command phrase, use a similar English spelling to improve the recognition rate.
;;;
;;;
;;; You can find more shouts' spell ID from the subpage of the page:
;;; https://en.uesp.net/wiki/Skyrim:Dragon_Shouts
;;;
;;;
;;; Note that the ID below the shout name is not its spell ID and
;;; can only be used with the equipitem command and not for the cast command.
;;; You must click the shout name to go to the subpage and copy the value under the "Spell ID" title.
Expand Down
93 changes: 77 additions & 16 deletions dsn_service/dsn_service/Voice2JsonCli.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
Expand All @@ -12,6 +13,8 @@
namespace DSN
{
class Voice2JsonCli {
private const int TRAIN_TIMEOUT = 120000; // 2min timout for voice2json training

public delegate void SpeechRecognizedHandler(string resultJson);
public event SpeechRecognizedHandler SpeechRecognized;

Expand Down Expand Up @@ -69,15 +72,16 @@ private int runCommand(string command, string args = "", int waitMs = 0, bool el
process.StartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8;
}

Trace.TraceInformation("Executing:\n> {0} {1}", command, args);
bool ok = false;
try {
ok = process.Start();
} catch {
// ignore
} catch(Exception e) {
Trace.TraceError(e.Message); // log exception and continue
}
if (!ok) {
endSession();
throw new Exception("Run docker command failed, make sure you have Docker Desktop installed:\n" + command + " " + args);
throw new Exception(String.Format(GetExecutionException(), command, args));
}

if (!elevating) {
Expand All @@ -101,6 +105,35 @@ private int runCommand(string command, string args = "", int waitMs = 0, bool el
}

private void init() {
if (UseDocke()) {
initDocker();
} else {
initBash();
}
}

/**
* Init voice2json via local bash (wsl)
*/
private void initBash()
{
Trace.TraceInformation("Automatically downloading speech recognition model files");
runCommand("bash",
"-c \"voice2json -p " + config.GetLocale() + " train-profile\"",
TRAIN_TIMEOUT);
Trace.TraceInformation("Deploying sentences.ini");
runCommand("bash", "-c \""
+ "find ~/.local/share/voice2json/ -maxdepth 1 -type d | while read d; do"
+ " ln -sf ~/.dsn_sentences.ini \\${d}/sentences.ini; "
+ "done"
+ "\"",
30000); // sec timeout
}

/**
* Init voice2json via docker
*/
private void initDocker() {
int exitCode;
if (runCommand("docker", "ps -a") != 0) {
string dockerDesktopPath = @"C:\Program Files\Docker\Docker";
Expand Down Expand Up @@ -143,16 +176,25 @@ private void init() {
}

Trace.TraceInformation("Automatically download speech recognition model files");
runCommand("docker", "exec dsn_voice2json sh -c \"" +
runCommand("docker", "exec dsn_voice2json sh -c \"" +
"/usr/lib/voice2json/bin/voice2json -p " + config.GetLocale() + " train-profile; " +
"ls /root/.local/share/voice2json | while read d; " +
"do " +
"ln -sf /root/sentences.ini /root/.local/share/voice2json/$d/sentences.ini; " +
"ln -sf /root/sentences.ini /root/.local/share/voice2json/$d/sentences.ini; " +
"done" +
"\"");
}

public void LoadJSGF(string jsgf) {
Trace.TraceInformation("Generating sentences.ini file and running training");
string command = UseDocke() ? "docker" : "bash";
string args = UseDocke()
? "exec -i dsn_voice2json sh -c \"base64 -id > /root/sentences.ini; " +
"/usr/lib/voice2json/bin/voice2json -p " + config.GetLocale() + " train-profile\""
: "-c \"" +
"base64 -id > ~/.dsn_sentences.ini; " +
"voice2json -p " + config.GetLocale() + " train-profile" +
"\"";
lock (ioLock) {
process = new Process();
process.StartInfo.RedirectStandardInput = true;
Expand All @@ -161,13 +203,14 @@ public void LoadJSGF(string jsgf) {
process.StartInfo.UseShellExecute = false;
process.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8;
process.StartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8;
process.StartInfo.FileName = "docker";
process.StartInfo.Arguments = "exec -i dsn_voice2json sh -c \"base64 -id > /root/sentences.ini; " +
"/usr/lib/voice2json/bin/voice2json -p " + config.GetLocale() + " train-profile\"";
process.StartInfo.FileName = command;
process.StartInfo.Arguments = args;

Trace.TraceInformation("Executing: {0} {1}", command, args);

if (!process.Start()) {
endSession();
throw new Exception("Run docker command failed, make sure you have Docker Desktop installed.");
String.Format(String.Format(GetExecutionException() + ":\n> {0} {1}", command, args));
}

readStdOut = new Thread(ReadStdOut);
Expand All @@ -179,12 +222,12 @@ public void LoadJSGF(string jsgf) {
process.StandardInput.Flush();
process.StandardInput.Close();

process.WaitForExit();
process.WaitForExit(TRAIN_TIMEOUT);
var exitCode = process.ExitCode;
endSession();

if (exitCode != 0) {
throw new Exception("Unable to access docker container 'dsn_voice2json', please make sure your Docker Desktop is running.");
String.Format(String.Format(GetExecutionException() + ":\n> {0} {1}", command, args));
}
}
}
Expand Down Expand Up @@ -236,6 +279,15 @@ private void ReadRecognizeResult() {
}

public void RecognizeAsync() {
string command = UseDocke() ? "docker" : "bash";
// TODO consolidate
string args = UseDocke()
? "exec -i dsn_voice2json sh -c \"base64 -id | /usr/lib/voice2json/bin/voice2json -p " +
config.GetLocale() + " transcribe-stream --audio-source -" +
" | /usr/lib/voice2json/bin/voice2json -p " + config.GetLocale() + " recognize-intent\""
: "-c \"base64 -id | voice2json -p " +
config.GetLocale() + " transcribe-stream --audio-source -" +
" | voice2json -p " + config.GetLocale() + " recognize-intent\"";
lock (ioLock) {
process = new Process();
process.StartInfo.RedirectStandardInput = true;
Expand All @@ -244,14 +296,13 @@ public void RecognizeAsync() {
process.StartInfo.UseShellExecute = false;
process.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8;
process.StartInfo.StandardErrorEncoding = System.Text.Encoding.UTF8;
process.StartInfo.FileName = "docker";
process.StartInfo.Arguments = "exec -i dsn_voice2json sh -c \"base64 -id | /usr/lib/voice2json/bin/voice2json -p "
+ config.GetLocale() + " transcribe-stream --audio-source -"
+ " | /usr/lib/voice2json/bin/voice2json -p " + config.GetLocale() + " recognize-intent\"";
process.StartInfo.FileName = command;
process.StartInfo.Arguments = args;
Trace.TraceInformation("Executing: {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);

if (!process.Start()) {
endSession();
throw new Exception("Run docker command failed, make sure you have Docker Desktop installed.");
throw new Exception(String.Format(GetExecutionException() + ":\n> {0} {1}", command, args));
}

stdIn = process.StandardInput;
Expand All @@ -261,6 +312,7 @@ public void RecognizeAsync() {
readStdErr.Start();
}
}

private void WaveSourceDataAvailable(object sender, WaveInEventArgs e) {
//Trace.TraceInformation("WaveSourceDataAvailable: {0}, {1}", sessionId, e.BytesRecorded);
lock (ioLock) {
Expand All @@ -273,5 +325,14 @@ private void WaveSourceDataAvailable(object sender, WaveInEventArgs e) {
private string Base64Encode(byte[] buffer) {
return System.Convert.ToBase64String(buffer);
}

private string GetExecutionException() {
return UseDocke() ? "Run docker commnad failed, make sure you have Docker Desktop installed"
: "Voice2Json execution failed, please make sure that bash (wsl) is available and voice2json is installed correctly";
}

private bool UseDocke() {
return config.Get("SpeechRecognition", "bVoice2JsonUseDocker", "1") == "1";
}
}
}
2 changes: 1 addition & 1 deletion dsn_service/dsn_service/Voice2JsonSpeechRecognition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ private void DSN_SpeechRecognized(string resultJson) {
}
string text = result.text;
string intent = result.intent.name;
float confidence = result.intent.confidence * 100;
float confidence = result.intent.confidence;

if (logAudioSignalIssues) {
Trace.TraceInformation("Recognition log: '{0}' (Confidence: {1})", text, confidence);
Expand Down