Merge branch 'develop'
This commit is contained in:
25
README.md
25
README.md
@@ -24,11 +24,17 @@ pip install -r requirements.txt
|
||||
|
||||
```bash
|
||||
git clone https://github.com/misyaguziya/translators.git
|
||||
python ./translators/setup.py install
|
||||
cd translators
|
||||
python ./setup.py install
|
||||
cd ../
|
||||
git clone https://github.com/misyaguziya/deepl-translate.git
|
||||
python ./deepl_translate/setup.py install
|
||||
cd deepl-translate
|
||||
python ./setup.py install
|
||||
cd ../
|
||||
git clone https://github.com/misyaguziya/custom_speech_recognition.git
|
||||
python ./custom_speech_recognition/setup.py install
|
||||
cd custom_speech_recognition
|
||||
python ./setup.py install
|
||||
cd ../
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -44,7 +50,7 @@ ptyhon VRCT.py
|
||||
(任意)
|
||||
1. DeepLのAPIを使用するためにアカウント登録し、認証キーを取得する
|
||||
2. ギアアイコンのボタンでconfigウィンドウを開く
|
||||
3. ParameterタブのDeepL Auth Keyに認証キーを記載し、フロッピーアイコンのボタンを押す
|
||||
3. ParameterタブのDeepL Auth Keyに認証キーを記載
|
||||
4. configウィンドウを閉じる
|
||||
|
||||
### Normal use
|
||||
@@ -69,22 +75,29 @@ ptyhon VRCT.py
|
||||
- Appearance Theme: ウィンドウテーマを選択
|
||||
- UI Scaling: UIサイズを調整
|
||||
- Font Family: 表示フォントを選択
|
||||
- **(New!) UI Language: UIの表示言語を選択**
|
||||
- Translation tab
|
||||
- Select Translator: 翻訳エンジンの変更
|
||||
- Send Language: 送信するメッセージに対して翻訳する言語[source, target]を選択
|
||||
- Receive Language: 受信したメッセージに対して翻訳する言語[source, target]を選択
|
||||
- Transcription tab
|
||||
- **(New!) Input Mic Host: マイクのホストAPIを選択**
|
||||
- Input Mic Device: マイクを選択
|
||||
- Input Mic Voice Language: 入力する音声の言語
|
||||
- Input Mic Energy Threshold: 音声取得のしきい値
|
||||
- **(New!) Check threshold point: Input Mic Energy Thresholdのしきい値を視覚化**
|
||||
- Input Mic Dynamic Energy Threshold: 音声取得のしきい値の自動調整
|
||||
- Input Mic Phase Timeout: 文字起こしする音声時間の上限
|
||||
- Input Mic Record Timeout: 音声の区切りの無音時間
|
||||
- Input Mic Max Phrases: 保留する単語の上限
|
||||
- **(New!) Input Mic Word Filter: MICの文字起こし時にWord Filterで設定した文字が入っていた場合にChatboxに表示しない (ex AAA,BBB,CCC)**
|
||||
- Input Speaker Device: スピーカーを選択
|
||||
- Input Speaker Voice Language: 受信する音声の言語
|
||||
- Input Speaker Energy Threshold: 音声取得のしきい値
|
||||
- **(New!) Check threshold point: (New!)Input Speaker Energy Thresholdのしきい値を視覚化**
|
||||
- Input Speaker Dynamic Energy Threshold: 音声取得のしきい値の自動調整
|
||||
- Input Speaker Record Timeout: 音声の区切りの無音時間
|
||||
- Input Speaker Phase Timeout: 文字起こしする音声時間の上限
|
||||
- Input Speaker Max Phrases: 保留する単語の上限
|
||||
- Parameter tab
|
||||
- OSC IP address: 変更不要
|
||||
@@ -94,8 +107,12 @@ ptyhon VRCT.py
|
||||
- [message]がメッセージボックスに記入したメッセージに置換される
|
||||
- [translation]が翻訳されたメッセージに置換される
|
||||
- 初期フォーマット:`[message]([translation])`
|
||||
- Others tab
|
||||
- **(New!) Auto clear chat box: メッセージ送信後に書き込んだメッセージを空にする**
|
||||
|
||||
## Author
|
||||
みしゃ(misyaguzi)
|
||||
twitter: https://twitter.com/misya_ai
|
||||
booth: https://misyaguziya.booth.pm/items/4814313
|
||||
|
||||
Shiina_12siy
|
||||
136
README.txt
136
README.txt
@@ -1,77 +1,90 @@
|
||||
ご購入ありがとうございます。
|
||||
フィードバックお待ちしております。
|
||||
|
||||
概要
|
||||
# 概要
|
||||
VRChatで使用されるChatBoxをOSC経由でメッセージを送信するツールになります。
|
||||
翻訳エンジンを使用してメッセージとその翻訳部分を同時に送信することができます。
|
||||
(翻訳エンジンはDeepL,Google,Bingに対応)
|
||||
|
||||
使用方法
|
||||
初期設定時
|
||||
0. VRChatのOSCを有効にする(重要)
|
||||
# 使用方法
|
||||
初期設定時
|
||||
0. VRChatのOSCを有効にする(重要)
|
||||
|
||||
(任意)
|
||||
1. DeepLのAPIを使用するためにアカウント登録し、認証キーを取得する
|
||||
2. ギアアイコンのボタンでconfigウィンドウを開く
|
||||
3. ParameterタブのDeepL Auth Keyに認証キーを記載し、フロッピーアイコンのボタンを押す
|
||||
4. configウィンドウを閉じる
|
||||
(任意)
|
||||
1. DeepLのAPIを使用するためにアカウント登録し、認証キーを取得する
|
||||
2. ギアアイコンのボタンでconfigウィンドウを開く
|
||||
3. ParameterタブのDeepL Auth Keyに認証キーを記載
|
||||
4. configウィンドウを閉じる
|
||||
|
||||
通常使用時
|
||||
1. メッセージボックスにメッセージを記入
|
||||
2. Enterキーを押し、メッセージを送信する
|
||||
通常使用時
|
||||
1. メッセージボックスにメッセージを記入
|
||||
2. Enterキーを押し、メッセージを送信する
|
||||
|
||||
その他の設定
|
||||
- translation チェックボックス: 翻訳の有効無効
|
||||
- voice2chatbox チェックボックス : マイクの音声を文字起こししてチャットボックスに送信する
|
||||
- speaker2log チェックボックス : スピーカーの音声から文字起こししてログに表示する
|
||||
- foreground チェックボックス: 最前面表示の有効無効
|
||||
# その他の設定
|
||||
translation チェックボックス: 翻訳の有効無効
|
||||
voice2chatbox チェックボックス : マイクの音声を文字起こししてチャットボックスに送信する
|
||||
speaker2log チェックボックス : スピーカーの音声から文字起こししてログに表示する
|
||||
foreground チェックボックス: 最前面表示の有効無効
|
||||
|
||||
- テキストボックス
|
||||
- logタブ: すべてのログを表示
|
||||
- sendタブ: 送信したメッセージを表示
|
||||
- receiveタブ: 受信したメッセージを表示
|
||||
- systemタブ: 機能についてのメッセージを表示
|
||||
テキストボックス
|
||||
logタブ
|
||||
すべてのログを表示
|
||||
sendタブ
|
||||
送信したメッセージを表示
|
||||
receiveタブ
|
||||
受信したメッセージを表示
|
||||
systemタブ
|
||||
機能についてのメッセージを表示
|
||||
|
||||
- Configウィンドウ
|
||||
- UIタブ
|
||||
- Transparency: ウィンドウの透過度の調整
|
||||
- Appearance Theme: ウィンドウテーマを選択
|
||||
- UI Scaling: UIサイズを調整
|
||||
- Font Family: 表示フォントを選択
|
||||
- Translationタブ
|
||||
- Select Translator: 翻訳エンジンの変更
|
||||
- Send Language: 送信するメッセージに対して翻訳する言語[source, target]を選択
|
||||
- Receive Language: 受信したメッセージに対して翻訳する言語[source, target]を選択
|
||||
- Transcriptionタブ
|
||||
- Input Mic Device: マイクを選択
|
||||
- Input Mic Voice Language: 入力する音声の言語
|
||||
- Input Mic Energy Threshold: 音声取得のしきい値
|
||||
- Input Mic Dynamic Energy Threshold: 音声取得のしきい値の自動調整
|
||||
- Input Mic Record Timeout: 音声の区切りの無音時間
|
||||
- Input Mic Max Phrases: 保留する単語の上限
|
||||
- Input Speaker Device: スピーカーを選択
|
||||
- Input Speaker Voice Language: 受信する音声の言語
|
||||
- Input Speaker Energy Threshold: 音声取得のしきい値
|
||||
- Input Speaker Dynamic Energy Threshold: 音声取得のしきい値の自動調整
|
||||
- Input Speaker Record Timeout: 音声の区切りの無音時間
|
||||
- Input Speaker Max Phrases: 保留する単語の上限
|
||||
- Parameterタブ
|
||||
- OSC IP address: 変更不要
|
||||
- OSC port: 変更不要
|
||||
- DeepL Auth key: DeepLの認証キーの設定
|
||||
- Message Format: 送信するメッセージのデコレーションの設定
|
||||
- [message]がメッセージボックスに記入したメッセージに置換される
|
||||
- [translation]が翻訳されたメッセージに置換される
|
||||
- 初期フォーマット:"[message]([translation])"
|
||||
configウィンドウ
|
||||
UIタブ
|
||||
Transparency: ウィンドウの透過度の調整
|
||||
Appearance Theme: ウィンドウテーマを選択
|
||||
UI Scaling: UIサイズを調整
|
||||
Font Family: 表示フォントを選択
|
||||
(New!) UI Language: UIの表示言語を選択
|
||||
Translationタブ
|
||||
Select Translator: 翻訳エンジンの変更
|
||||
Send Language: 送信するメッセージに対して翻訳する言語[source, target]を選択
|
||||
Receive Language: 受信したメッセージに対して翻訳する言語[source, target]を選択
|
||||
Transcriptionタブ
|
||||
(New!) Input Mic Host: マイクのホストAPIを選択
|
||||
Input Mic Device: マイクを選択
|
||||
Input Mic Voice Language: 入力する音声の言語
|
||||
Input Mic Energy Threshold: 音声取得のしきい値
|
||||
(New!) Check threshold point: Input Mic Energy Thresholdのしきい値を視覚化
|
||||
Input Mic Dynamic Energy Threshold: 音声取得のしきい値の自動調整
|
||||
Input Mic Record Timeout: 音声の区切りの無音時間
|
||||
Input Mic Phase Timeout: 文字起こしする音声時間の上限
|
||||
Input Mic Max Phrases: 保留する単語の上限
|
||||
(New!) Input Mic Word Filter: MICの文字起こし時にWord Filterで設定した文字が入っていた場合にChatboxに表示しない (ex AAA,BBB,CCC)
|
||||
Input Speaker Device: スピーカーを選択
|
||||
Input Speaker Voice Language: 受信する音声の言語
|
||||
Input Speaker Energy Threshold: 音声取得のしきい値
|
||||
(New!) Check threshold point: (New!)Input Speaker Energy Thresholdのしきい値を視覚化
|
||||
Input Speaker Dynamic Energy Threshold: 音声取得のしきい値の自動調整
|
||||
Input Speaker Record Timeout: 音声の区切りの無音時間
|
||||
Input Speaker Phase Timeout: 文字起こしする音声時間の上限
|
||||
Input Speaker Max Phrases: 保留する単語の上限
|
||||
Parameterタブ
|
||||
OSC IP address: 変更不要
|
||||
OSC port: 変更不要
|
||||
DeepL Auth key: DeepLの認証キーの設定
|
||||
Message Format: 送信するメッセージのデコレーションの設定
|
||||
[message]がメッセージボックスに記入したメッセージに置換される
|
||||
[translation]が翻訳されたメッセージに置換される
|
||||
初期フォーマット:"[message]([translation])"
|
||||
Othersタブ
|
||||
(New!) Auto clear chat box: メッセージ送信後に書き込んだメッセージを空にする
|
||||
|
||||
設定の初期化
|
||||
- config.jsonを削除
|
||||
設定の初期化
|
||||
config.jsonを削除
|
||||
|
||||
お問い合わせ
|
||||
# お問い合わせ
|
||||
要望などはTwitterまで
|
||||
https://twitter.com/misya_ai
|
||||
|
||||
アップデート履歴
|
||||
# アップデート履歴
|
||||
[2023-05-29: v0.1b] v0.1b リリース
|
||||
[2023-05-30: v0.2b]
|
||||
- configボタンをギアアイコンに変更
|
||||
@@ -97,6 +110,15 @@ https://twitter.com/misya_ai
|
||||
- 文字起こしの処理の軽量化
|
||||
[2023-07-05: v1.2]
|
||||
- 文字起こし精度の向上
|
||||
[2023-07-21: v1.3]
|
||||
- UIの表示言語を日本語/英語を選択できる機能を追加
|
||||
- Energy Thresholdの視覚化機能を追加
|
||||
- 文字起こしの誤認識対策のため、Word Filterを追加
|
||||
- WASAPI以外のHostAPIでもマイクとして使用できるようにHostAPIを選択できる機能を追加
|
||||
- メッセージ送信後に書き込んだメッセージを空にするか選択できる機能を追加
|
||||
- バグ対策のため、translation/voice2chatbox/speaker2log/foregroundは起動時はOFFになるように変更
|
||||
- バグ対策のため、スピーカーについて既定デバイス以外を選択した時にERRORが出るように変更
|
||||
- 半角入力時に一部の文字が書き込めないバグを修正
|
||||
|
||||
# 注意事項
|
||||
再配布とかはやめてね
|
||||
562
VRCT.py
562
VRCT.py
@@ -1,29 +1,35 @@
|
||||
import os
|
||||
import json
|
||||
import queue
|
||||
from os import path as os_path
|
||||
from json import load as json_load
|
||||
from json import dump as json_dump
|
||||
from queue import Queue
|
||||
import tkinter as tk
|
||||
import customtkinter
|
||||
from PIL import Image
|
||||
from customtkinter import CTk, CTkFrame, CTkCheckBox, CTkFont, CTkButton, CTkImage, CTkTabview, CTkTextbox, CTkEntry
|
||||
from PIL.Image import open as Image_open
|
||||
from flashtext import KeywordProcessor
|
||||
|
||||
import utils
|
||||
import osc_tools
|
||||
import window_config
|
||||
import window_information
|
||||
import languages
|
||||
import audio_utils
|
||||
import audio_recorder
|
||||
import audio_transcriber
|
||||
import translation
|
||||
from threading import Thread
|
||||
from utils import save_json, print_textbox, thread_fnc, get_localized_text, widget_main_window_label_setter
|
||||
from osc_tools import send_typing, send_message
|
||||
from window_config import ToplevelWindowConfig
|
||||
from window_information import ToplevelWindowInformation
|
||||
from languages import transcription_lang, translators, translation_lang, selectable_languages
|
||||
from audio_utils import get_input_device_list, get_output_device_list, get_default_input_device, get_default_output_device
|
||||
from audio_recorder import SelectedMicRecorder, SelectedSpeakerRecorder
|
||||
from audio_transcriber import AudioTranscriber
|
||||
from translation import Translator
|
||||
|
||||
class App(customtkinter.CTk):
|
||||
class App(CTk):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# init instance
|
||||
self.translator = translation.Translator()
|
||||
self.translator = Translator()
|
||||
self.keyword_processor = KeywordProcessor()
|
||||
|
||||
# init config
|
||||
self.PATH_CONFIG = "./config.json"
|
||||
|
||||
## main window
|
||||
self.ENABLE_TRANSLATION = False
|
||||
self.ENABLE_TRANSCRIPTION_SEND = False
|
||||
@@ -34,23 +40,26 @@ class App(customtkinter.CTk):
|
||||
self.APPEARANCE_THEME = "System"
|
||||
self.UI_SCALING = "100%"
|
||||
self.FONT_FAMILY = "Yu Gothic UI"
|
||||
self.UI_LANGUAGE = "en"
|
||||
## Translation
|
||||
self.CHOICE_TRANSLATOR = languages.translators[0]
|
||||
self.INPUT_SOURCE_LANG = list(languages.translation_lang[self.CHOICE_TRANSLATOR].keys())[0]
|
||||
self.INPUT_TARGET_LANG = list(languages.translation_lang[self.CHOICE_TRANSLATOR].keys())[1]
|
||||
self.OUTPUT_SOURCE_LANG = list(languages.translation_lang[self.CHOICE_TRANSLATOR].keys())[1]
|
||||
self.OUTPUT_TARGET_LANG = list(languages.translation_lang[self.CHOICE_TRANSLATOR].keys())[0]
|
||||
self.CHOICE_TRANSLATOR = translators[0]
|
||||
self.INPUT_SOURCE_LANG = list(translation_lang[self.CHOICE_TRANSLATOR].keys())[0]
|
||||
self.INPUT_TARGET_LANG = list(translation_lang[self.CHOICE_TRANSLATOR].keys())[1]
|
||||
self.OUTPUT_SOURCE_LANG = list(translation_lang[self.CHOICE_TRANSLATOR].keys())[1]
|
||||
self.OUTPUT_TARGET_LANG = list(translation_lang[self.CHOICE_TRANSLATOR].keys())[0]
|
||||
## Transcription Send
|
||||
self.CHOICE_MIC_DEVICE = audio_utils.get_default_input_device()["name"]
|
||||
self.INPUT_MIC_VOICE_LANGUAGE = list(languages.transcription_lang.keys())[0]
|
||||
self.CHOICE_MIC_HOST = get_default_input_device()["host"]["name"]
|
||||
self.CHOICE_MIC_DEVICE = get_default_input_device()["device"]["name"]
|
||||
self.INPUT_MIC_VOICE_LANGUAGE = list(transcription_lang.keys())[0]
|
||||
self.INPUT_MIC_ENERGY_THRESHOLD = 300
|
||||
self.INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD = True
|
||||
self.INPUT_MIC_RECORD_TIMEOUT = 3
|
||||
self.INPUT_MIC_PHRASE_TIMEOUT = 3
|
||||
self.INPUT_MIC_MAX_PHRASES = 10
|
||||
self.INPUT_MIC_WORD_FILTER = []
|
||||
## Transcription Receive
|
||||
self.CHOICE_SPEAKER_DEVICE = audio_utils.get_default_output_device()["name"]
|
||||
self.INPUT_SPEAKER_VOICE_LANGUAGE = list(languages.transcription_lang.keys())[1]
|
||||
self.CHOICE_SPEAKER_DEVICE = get_default_output_device()["name"]
|
||||
self.INPUT_SPEAKER_VOICE_LANGUAGE = list(transcription_lang.keys())[1]
|
||||
self.INPUT_SPEAKER_ENERGY_THRESHOLD = 300
|
||||
self.INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD = True
|
||||
self.INPUT_SPEAKER_RECORD_TIMEOUT = 3
|
||||
@@ -66,24 +75,30 @@ class App(customtkinter.CTk):
|
||||
"Google(web)": None,
|
||||
}
|
||||
self.MESSAGE_FORMAT = "[message]([translation])"
|
||||
# Others
|
||||
self.ENABLE_AUTO_CLEAR_CHATBOX = False
|
||||
|
||||
# load config
|
||||
if os.path.isfile(self.PATH_CONFIG) is not False:
|
||||
if os_path.isfile(self.PATH_CONFIG) is not False:
|
||||
with open(self.PATH_CONFIG, 'r') as fp:
|
||||
config = json.load(fp)
|
||||
config = json_load(fp)
|
||||
# main window
|
||||
if "ENABLE_TRANSLATION" in config.keys():
|
||||
if type(config["ENABLE_TRANSLATION"]) is bool:
|
||||
self.ENABLE_TRANSLATION = config["ENABLE_TRANSLATION"]
|
||||
if "ENABLE_TRANSCRIPTION_SEND" in config.keys():
|
||||
if type(config["ENABLE_TRANSCRIPTION_SEND"]) is bool:
|
||||
self.ENABLE_TRANSCRIPTION_SEND = config["ENABLE_TRANSCRIPTION_SEND"]
|
||||
if "ENABLE_TRANSCRIPTION_RECEIVE" in config.keys():
|
||||
if type(config["ENABLE_TRANSCRIPTION_RECEIVE"]) is bool:
|
||||
self.ENABLE_TRANSCRIPTION_RECEIVE = config["ENABLE_TRANSCRIPTION_RECEIVE"]
|
||||
if "ENABLE_FOREGROUND" in config.keys():
|
||||
if type(config["ENABLE_FOREGROUND"]) is bool:
|
||||
self.ENABLE_FOREGROUND = config["ENABLE_FOREGROUND"]
|
||||
# main windowは初期はすべてOFFにする
|
||||
# if "ENABLE_TRANSLATION" in config.keys():
|
||||
# if type(config["ENABLE_TRANSLATION"]) is bool:
|
||||
# self.ENABLE_TRANSLATION = config["ENABLE_TRANSLATION"]
|
||||
|
||||
# 環境に依ってマイクとスピーカーを同時起動するとエラーが発生するため、起動時は強制的にOFFにする
|
||||
# if "ENABLE_TRANSCRIPTION_SEND" in config.keys():
|
||||
# if type(config["ENABLE_TRANSCRIPTION_SEND"]) is bool:
|
||||
# self.ENABLE_TRANSCRIPTION_SEND = config["ENABLE_TRANSCRIPTION_SEND"]
|
||||
# if "ENABLE_TRANSCRIPTION_RECEIVE" in config.keys():
|
||||
# if type(config["ENABLE_TRANSCRIPTION_RECEIVE"]) is bool:
|
||||
# self.ENABLE_TRANSCRIPTION_RECEIVE = config["ENABLE_TRANSCRIPTION_RECEIVE"]
|
||||
|
||||
# if "ENABLE_FOREGROUND" in config.keys():
|
||||
# if type(config["ENABLE_FOREGROUND"]) is bool:
|
||||
# self.ENABLE_FOREGROUND = config["ENABLE_FOREGROUND"]
|
||||
|
||||
# tab ui
|
||||
if "TRANSPARENCY" in config.keys():
|
||||
@@ -99,30 +114,36 @@ class App(customtkinter.CTk):
|
||||
if "FONT_FAMILY" in config.keys():
|
||||
if config["FONT_FAMILY"] in list(tk.font.families()):
|
||||
self.FONT_FAMILY = config["FONT_FAMILY"]
|
||||
if "UI_LANGUAGE" in config.keys():
|
||||
if config["UI_LANGUAGE"] in list(selectable_languages.keys()):
|
||||
self.UI_LANGUAGE = config["UI_LANGUAGE"]
|
||||
|
||||
# translation
|
||||
if "CHOICE_TRANSLATOR" in config.keys():
|
||||
if config["CHOICE_TRANSLATOR"] in list(self.translator.translator_status.keys()):
|
||||
self.CHOICE_TRANSLATOR = config["CHOICE_TRANSLATOR"]
|
||||
if "INPUT_SOURCE_LANG" in config.keys():
|
||||
if config["INPUT_SOURCE_LANG"] in list(languages.translation_lang[self.CHOICE_TRANSLATOR].keys()):
|
||||
if config["INPUT_SOURCE_LANG"] in list(translation_lang[self.CHOICE_TRANSLATOR].keys()):
|
||||
self.INPUT_SOURCE_LANG = config["INPUT_SOURCE_LANG"]
|
||||
if "INPUT_TARGET_LANG" in config.keys():
|
||||
if config["INPUT_SOURCE_LANG"] in list(languages.translation_lang[self.CHOICE_TRANSLATOR].keys()):
|
||||
if config["INPUT_SOURCE_LANG"] in list(translation_lang[self.CHOICE_TRANSLATOR].keys()):
|
||||
self.INPUT_TARGET_LANG = config["INPUT_TARGET_LANG"]
|
||||
if "OUTPUT_SOURCE_LANG" in config.keys():
|
||||
if config["INPUT_SOURCE_LANG"] in list(languages.translation_lang[self.CHOICE_TRANSLATOR].keys()):
|
||||
if config["INPUT_SOURCE_LANG"] in list(translation_lang[self.CHOICE_TRANSLATOR].keys()):
|
||||
self.OUTPUT_SOURCE_LANG = config["OUTPUT_SOURCE_LANG"]
|
||||
if "OUTPUT_TARGET_LANG" in config.keys():
|
||||
if config["INPUT_SOURCE_LANG"] in list(languages.translation_lang[self.CHOICE_TRANSLATOR].keys()):
|
||||
if config["INPUT_SOURCE_LANG"] in list(translation_lang[self.CHOICE_TRANSLATOR].keys()):
|
||||
self.OUTPUT_TARGET_LANG = config["OUTPUT_TARGET_LANG"]
|
||||
|
||||
# Transcription
|
||||
if "CHOICE_MIC_HOST" in config.keys():
|
||||
if config["CHOICE_MIC_HOST"] in [host for host in get_input_device_list().keys()]:
|
||||
self.CHOICE_MIC_HOST = config["CHOICE_MIC_HOST"]
|
||||
if "CHOICE_MIC_DEVICE" in config.keys():
|
||||
if config["CHOICE_MIC_DEVICE"] in [device["name"] for device in audio_utils.get_input_device_list()]:
|
||||
if config["CHOICE_MIC_DEVICE"] in [device["name"] for device in get_input_device_list()[self.CHOICE_MIC_HOST]]:
|
||||
self.CHOICE_MIC_DEVICE = config["CHOICE_MIC_DEVICE"]
|
||||
if "INPUT_MIC_VOICE_LANGUAGE" in config.keys():
|
||||
if config["INPUT_MIC_VOICE_LANGUAGE"] in list(languages.transcription_lang.keys()):
|
||||
if config["INPUT_MIC_VOICE_LANGUAGE"] in list(transcription_lang.keys()):
|
||||
self.INPUT_MIC_VOICE_LANGUAGE = config["INPUT_MIC_VOICE_LANGUAGE"]
|
||||
if "INPUT_MIC_ENERGY_THRESHOLD" in config.keys():
|
||||
if type(config["INPUT_MIC_ENERGY_THRESHOLD"]) is int:
|
||||
@@ -139,12 +160,17 @@ class App(customtkinter.CTk):
|
||||
if "INPUT_MIC_MAX_PHRASES" in config.keys():
|
||||
if type(config["INPUT_MIC_MAX_PHRASES"]) is int:
|
||||
self.INPUT_MIC_MAX_PHRASES = config["INPUT_MIC_MAX_PHRASES"]
|
||||
if "INPUT_MIC_WORD_FILTER" in config.keys():
|
||||
if type(config["INPUT_MIC_WORD_FILTER"]) is list:
|
||||
self.INPUT_MIC_WORD_FILTER = config["INPUT_MIC_WORD_FILTER"]
|
||||
|
||||
if "CHOICE_SPEAKER_DEVICE" in config.keys():
|
||||
if config["CHOICE_SPEAKER_DEVICE"] in [device["name"] for device in audio_utils.get_output_device_list()]:
|
||||
if config["CHOICE_SPEAKER_DEVICE"] in [device["name"] for device in get_output_device_list()]:
|
||||
speaker_device = [device for device in get_output_device_list() if device["name"] == config["CHOICE_SPEAKER_DEVICE"]][0]
|
||||
if get_default_output_device()["index"] == speaker_device["index"]:
|
||||
self.CHOICE_SPEAKER_DEVICE = config["CHOICE_SPEAKER_DEVICE"]
|
||||
if "INPUT_SPEAKER_VOICE_LANGUAGE" in config.keys():
|
||||
if config["INPUT_SPEAKER_VOICE_LANGUAGE"] in list(languages.transcription_lang.keys()):
|
||||
if config["INPUT_SPEAKER_VOICE_LANGUAGE"] in list(transcription_lang.keys()):
|
||||
self.INPUT_SPEAKER_VOICE_LANGUAGE = config["INPUT_SPEAKER_VOICE_LANGUAGE"]
|
||||
if "INPUT_SPEAKER_ENERGY_THRESHOLD" in config.keys():
|
||||
if type(config["INPUT_SPEAKER_ENERGY_THRESHOLD"]) is int:
|
||||
@@ -179,21 +205,28 @@ class App(customtkinter.CTk):
|
||||
if type(config["MESSAGE_FORMAT"]) is str:
|
||||
self.MESSAGE_FORMAT = config["MESSAGE_FORMAT"]
|
||||
|
||||
# Others
|
||||
if "ENABLE_AUTO_CLEAR_CHATBOX" in config.keys():
|
||||
if type(config["ENABLE_AUTO_CLEAR_CHATBOX"]) is bool:
|
||||
self.ENABLE_AUTO_CLEAR_CHATBOX = config["ENABLE_AUTO_CLEAR_CHATBOX"]
|
||||
|
||||
with open(self.PATH_CONFIG, 'w') as fp:
|
||||
config = {
|
||||
"ENABLE_TRANSLATION": self.ENABLE_TRANSLATION,
|
||||
"ENABLE_TRANSCRIPTION_SEND": self.ENABLE_TRANSCRIPTION_SEND,
|
||||
"ENABLE_TRANSCRIPTION_RECEIVE": self.ENABLE_TRANSCRIPTION_RECEIVE,
|
||||
"ENABLE_FOREGROUND": self.ENABLE_FOREGROUND,
|
||||
# "ENABLE_TRANSLATION": self.ENABLE_TRANSLATION,
|
||||
# "ENABLE_TRANSCRIPTION_SEND": self.ENABLE_TRANSCRIPTION_SEND,
|
||||
# "ENABLE_TRANSCRIPTION_RECEIVE": self.ENABLE_TRANSCRIPTION_RECEIVE,
|
||||
# "ENABLE_FOREGROUND": self.ENABLE_FOREGROUND,
|
||||
"TRANSPARENCY": self.TRANSPARENCY,
|
||||
"APPEARANCE_THEME": self.APPEARANCE_THEME,
|
||||
"UI_SCALING": self.UI_SCALING,
|
||||
"UI_LANGUAGE": self.UI_LANGUAGE,
|
||||
"FONT_FAMILY": self.FONT_FAMILY,
|
||||
"CHOICE_TRANSLATOR": self.CHOICE_TRANSLATOR,
|
||||
"INPUT_SOURCE_LANG": self.INPUT_SOURCE_LANG,
|
||||
"INPUT_TARGET_LANG": self.INPUT_TARGET_LANG,
|
||||
"OUTPUT_SOURCE_LANG": self.OUTPUT_SOURCE_LANG,
|
||||
"OUTPUT_TARGET_LANG": self.OUTPUT_TARGET_LANG,
|
||||
"CHOICE_MIC_HOST": self.CHOICE_MIC_HOST,
|
||||
"CHOICE_MIC_DEVICE": self.CHOICE_MIC_DEVICE,
|
||||
"INPUT_MIC_VOICE_LANGUAGE": self.INPUT_MIC_VOICE_LANGUAGE,
|
||||
"INPUT_MIC_ENERGY_THRESHOLD": self.INPUT_MIC_ENERGY_THRESHOLD,
|
||||
@@ -201,6 +234,7 @@ class App(customtkinter.CTk):
|
||||
"INPUT_MIC_RECORD_TIMEOUT": self.INPUT_MIC_RECORD_TIMEOUT,
|
||||
"INPUT_MIC_PHRASE_TIMEOUT": self.INPUT_MIC_PHRASE_TIMEOUT,
|
||||
"INPUT_MIC_MAX_PHRASES": self.INPUT_MIC_MAX_PHRASES,
|
||||
"INPUT_MIC_WORD_FILTER": self.INPUT_MIC_WORD_FILTER,
|
||||
"CHOICE_SPEAKER_DEVICE": self.CHOICE_SPEAKER_DEVICE,
|
||||
"INPUT_SPEAKER_VOICE_LANGUAGE": self.INPUT_SPEAKER_VOICE_LANGUAGE,
|
||||
"INPUT_SPEAKER_ENERGY_THRESHOLD": self.INPUT_SPEAKER_ENERGY_THRESHOLD,
|
||||
@@ -212,15 +246,16 @@ class App(customtkinter.CTk):
|
||||
"OSC_PORT": self.OSC_PORT,
|
||||
"AUTH_KEYS": self.AUTH_KEYS,
|
||||
"MESSAGE_FORMAT": self.MESSAGE_FORMAT,
|
||||
"ENABLE_AUTO_CLEAR_CHATBOX": self.ENABLE_AUTO_CLEAR_CHATBOX,
|
||||
}
|
||||
json.dump(config, fp, indent=4)
|
||||
json_dump(config, fp, indent=4)
|
||||
|
||||
## set UI theme
|
||||
customtkinter.set_appearance_mode(self.APPEARANCE_THEME)
|
||||
customtkinter.set_default_color_theme("blue")
|
||||
|
||||
# init main window
|
||||
self.iconbitmap(os.path.join(os.path.dirname(__file__), "img", "app.ico"))
|
||||
self.iconbitmap(os_path.join(os_path.dirname(__file__), "img", "app.ico"))
|
||||
self.title("VRCT")
|
||||
self.geometry(f"{400}x{175}")
|
||||
self.minsize(400, 175)
|
||||
@@ -228,132 +263,87 @@ class App(customtkinter.CTk):
|
||||
self.grid_rowconfigure(0, weight=1)
|
||||
|
||||
# add sidebar left
|
||||
self.sidebar_frame = customtkinter.CTkFrame(self, corner_radius=0)
|
||||
self.sidebar_frame = CTkFrame(self, corner_radius=0)
|
||||
self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsw")
|
||||
self.sidebar_frame.grid_rowconfigure(5, weight=1)
|
||||
|
||||
init_lang_text = "Loading..."
|
||||
|
||||
# add checkbox translation
|
||||
self.checkbox_translation = customtkinter.CTkCheckBox(
|
||||
self.checkbox_translation = CTkCheckBox(
|
||||
self.sidebar_frame,
|
||||
text="translation",
|
||||
text=init_lang_text,
|
||||
onvalue=True,
|
||||
offvalue=False,
|
||||
command=self.checkbox_translation_callback,
|
||||
font=customtkinter.CTkFont(family=self.FONT_FAMILY)
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.checkbox_translation.grid(row=0, column=0, columnspan=2 ,padx=10, pady=(5, 5), sticky="we")
|
||||
self.checkbox_translation.grid(row=0, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we")
|
||||
|
||||
# add checkbox transcription send
|
||||
self.checkbox_transcription_send = customtkinter.CTkCheckBox(
|
||||
self.checkbox_transcription_send = CTkCheckBox(
|
||||
self.sidebar_frame,
|
||||
text="voice2chatbox",
|
||||
text=init_lang_text,
|
||||
onvalue=True,
|
||||
offvalue=False,
|
||||
command=self.checkbox_transcription_send_callback,
|
||||
font=customtkinter.CTkFont(family=self.FONT_FAMILY)
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.checkbox_transcription_send.grid(row=1, column=0, columnspan=2 ,padx=10, pady=(5, 5), sticky="we")
|
||||
self.checkbox_transcription_send.grid(row=1, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we")
|
||||
|
||||
# add checkbox transcription receive
|
||||
self.checkbox_transcription_receive = customtkinter.CTkCheckBox(
|
||||
self.checkbox_transcription_receive = CTkCheckBox(
|
||||
self.sidebar_frame,
|
||||
text="speaker2log",
|
||||
text=init_lang_text,
|
||||
onvalue=True,
|
||||
offvalue=False,
|
||||
command=self.checkbox_transcription_receive_callback,
|
||||
font=customtkinter.CTkFont(family=self.FONT_FAMILY)
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.checkbox_transcription_receive.grid(row=2, column=0, columnspan=2 ,padx=10, pady=(5, 5), sticky="we")
|
||||
self.checkbox_transcription_receive.grid(row=2, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we")
|
||||
|
||||
# add checkbox foreground
|
||||
self.checkbox_foreground = customtkinter.CTkCheckBox(
|
||||
self.checkbox_foreground = CTkCheckBox(
|
||||
self.sidebar_frame,
|
||||
text="foreground",
|
||||
text=init_lang_text,
|
||||
onvalue=True,
|
||||
offvalue=False,
|
||||
command=self.checkbox_foreground_callback,
|
||||
font=customtkinter.CTkFont(family=self.FONT_FAMILY)
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.checkbox_foreground.grid(row=3, column=0, columnspan=2 ,padx=10, pady=(5, 5), sticky="we")
|
||||
self.checkbox_foreground.grid(row=3, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we")
|
||||
|
||||
# add button information
|
||||
self.button_information = customtkinter.CTkButton(
|
||||
self.button_information = CTkButton(
|
||||
self.sidebar_frame,
|
||||
text="",
|
||||
width=25,
|
||||
command=self.button_information_callback,
|
||||
image=customtkinter.CTkImage(Image.open(os.path.join(os.path.dirname(__file__), "img", "info-icon-white.png")))
|
||||
image=CTkImage(Image_open(os_path.join(os_path.dirname(__file__), "img", "info-icon-white.png")))
|
||||
)
|
||||
self.button_information.grid(row=5, column=0, padx=(10, 5), pady=(5, 5), sticky="wse")
|
||||
self.information_window = None
|
||||
|
||||
# add button config
|
||||
self.button_config = customtkinter.CTkButton(
|
||||
self.button_config = CTkButton(
|
||||
self.sidebar_frame,
|
||||
text="",
|
||||
width=25,
|
||||
command=self.button_config_callback,
|
||||
image=customtkinter.CTkImage(Image.open(os.path.join(os.path.dirname(__file__), "img", "config-icon-white.png")))
|
||||
image=CTkImage(Image_open(os_path.join(os_path.dirname(__file__), "img", "config-icon-white.png")))
|
||||
)
|
||||
self.button_config.grid(row=5, column=1, padx=(5, 10), pady=(5, 5), sticky="wse")
|
||||
self.config_window = None
|
||||
|
||||
# load ui language data
|
||||
language_yaml_data = get_localized_text(f"{self.UI_LANGUAGE}")
|
||||
# add tabview textbox
|
||||
self.tabview_logs = customtkinter.CTkTabview(master=self)
|
||||
self.tabview_logs.add("log")
|
||||
self.tabview_logs.add("send")
|
||||
self.tabview_logs.add("receive")
|
||||
self.tabview_logs.add("system")
|
||||
self.tabview_logs.grid(row=0, column=1, padx=0, pady=0, sticky="nsew")
|
||||
self.tabview_logs._segmented_button.configure(font=customtkinter.CTkFont(family=self.FONT_FAMILY))
|
||||
self.tabview_logs._segmented_button.grid(sticky="W")
|
||||
self.tabview_logs.tab("log").grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("log").grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("send").grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("send").grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("receive").grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("receive").grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("system").grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("system").grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.configure(fg_color="transparent")
|
||||
|
||||
# add textbox message log
|
||||
self.textbox_message_log = customtkinter.CTkTextbox(
|
||||
self.tabview_logs.tab("log"),
|
||||
font=customtkinter.CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_log.configure(state='disabled')
|
||||
|
||||
# add textbox message send log
|
||||
self.textbox_message_send_log = customtkinter.CTkTextbox(
|
||||
self.tabview_logs.tab("send"),
|
||||
font=customtkinter.CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_send_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_send_log.configure(state='disabled')
|
||||
|
||||
# add textbox message receive log
|
||||
self.textbox_message_receive_log = customtkinter.CTkTextbox(
|
||||
self.tabview_logs.tab("receive"),
|
||||
font=customtkinter.CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_receive_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_receive_log.configure(state='disabled')
|
||||
|
||||
# add textbox message system log
|
||||
self.textbox_message_system_log = customtkinter.CTkTextbox(
|
||||
self.tabview_logs.tab("system"),
|
||||
font=customtkinter.CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_system_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_system_log.configure(state='disabled')
|
||||
self.add_tabview_logs(language_yaml_data)
|
||||
|
||||
# add entry message box
|
||||
self.entry_message_box = customtkinter.CTkEntry(
|
||||
self.entry_message_box = CTkEntry(
|
||||
self,
|
||||
placeholder_text="message",
|
||||
font=customtkinter.CTkFont(family=self.FONT_FAMILY)
|
||||
font=CTkFont(family=self.FONT_FAMILY),
|
||||
)
|
||||
self.entry_message_box.grid(row=1, column=1, columnspan=2, padx=5, pady=(5, 10), sticky="nsew")
|
||||
|
||||
@@ -361,36 +351,40 @@ class App(customtkinter.CTk):
|
||||
## set translator
|
||||
if self.translator.authentication(self.CHOICE_TRANSLATOR, self.AUTH_KEYS[self.CHOICE_TRANSLATOR]) is False:
|
||||
# error update Auth key
|
||||
utils.print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
utils.print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
|
||||
## set checkbox enable translation
|
||||
if self.ENABLE_TRANSLATION:
|
||||
self.checkbox_translation.select()
|
||||
self.checkbox_translation_callback()
|
||||
else:
|
||||
self.checkbox_translation.deselect()
|
||||
# ## set checkbox enable translation
|
||||
# if self.ENABLE_TRANSLATION:
|
||||
# self.checkbox_translation.select()
|
||||
# self.checkbox_translation_callback()
|
||||
# else:
|
||||
# self.checkbox_translation.deselect()
|
||||
|
||||
## set checkbox enable transcription send
|
||||
if self.ENABLE_TRANSCRIPTION_SEND:
|
||||
self.checkbox_transcription_send.select()
|
||||
self.checkbox_transcription_send_callback()
|
||||
else:
|
||||
self.checkbox_transcription_send.deselect()
|
||||
# ## set checkbox enable transcription send
|
||||
# if self.ENABLE_TRANSCRIPTION_SEND:
|
||||
# self.checkbox_transcription_send.select()
|
||||
# self.checkbox_transcription_send_callback()
|
||||
# else:
|
||||
# self.checkbox_transcription_send.deselect()
|
||||
|
||||
## set checkbox enable transcription receive
|
||||
if self.ENABLE_TRANSCRIPTION_RECEIVE:
|
||||
self.checkbox_transcription_receive.select()
|
||||
self.checkbox_transcription_receive_callback()
|
||||
else:
|
||||
self.checkbox_transcription_receive.deselect()
|
||||
# ## set checkbox enable transcription receive
|
||||
# if self.ENABLE_TRANSCRIPTION_RECEIVE:
|
||||
# self.checkbox_transcription_receive.select()
|
||||
# self.checkbox_transcription_receive_callback()
|
||||
# else:
|
||||
# self.checkbox_transcription_receive.deselect()
|
||||
|
||||
## set set checkbox enable foreground
|
||||
if self.ENABLE_FOREGROUND:
|
||||
self.checkbox_foreground.select()
|
||||
self.checkbox_foreground_callback()
|
||||
else:
|
||||
self.checkbox_foreground.deselect()
|
||||
# ## set set checkbox enable foreground
|
||||
# if self.ENABLE_FOREGROUND:
|
||||
# self.checkbox_foreground.select()
|
||||
# self.checkbox_foreground_callback()
|
||||
# else:
|
||||
# self.checkbox_foreground.deselect()
|
||||
|
||||
## set word filter
|
||||
for f in self.INPUT_MIC_WORD_FILTER:
|
||||
self.keyword_processor.add_keyword(f)
|
||||
|
||||
## set bind entry message box
|
||||
self.entry_message_box.bind("<Return>", self.entry_message_box_press_key_enter)
|
||||
@@ -407,51 +401,52 @@ class App(customtkinter.CTk):
|
||||
# delete window
|
||||
self.protocol("WM_DELETE_WINDOW", self.delete_window)
|
||||
|
||||
self.config_window = ToplevelWindowConfig(self)
|
||||
|
||||
def button_config_callback(self):
|
||||
if self.config_window is None or not self.config_window.winfo_exists():
|
||||
self.config_window = window_config.ToplevelWindowConfig(self)
|
||||
self.checkbox_translation.configure(state="disabled")
|
||||
self.checkbox_transcription_send.configure(state="disabled")
|
||||
self.checkbox_transcription_receive.configure(state="disabled")
|
||||
self.button_config.configure(state="disabled", fg_color=["gray92", "gray14"])
|
||||
|
||||
self.config_window.deiconify()
|
||||
self.config_window.focus_set()
|
||||
self.config_window.focus()
|
||||
|
||||
def button_information_callback(self):
|
||||
if self.information_window is None or not self.information_window.winfo_exists():
|
||||
self.information_window = window_information.ToplevelWindowInformation(self)
|
||||
self.information_window = ToplevelWindowInformation(self)
|
||||
self.information_window.focus()
|
||||
|
||||
def checkbox_translation_callback(self):
|
||||
self.ENABLE_TRANSLATION = self.checkbox_translation.get()
|
||||
if self.ENABLE_TRANSLATION:
|
||||
self.button_config.configure(state="disabled", fg_color=["gray92", "gray14"])
|
||||
utils.print_textbox(self.textbox_message_log, "Start translation", "INFO")
|
||||
utils.print_textbox(self.textbox_message_system_log, "Start translation", "INFO")
|
||||
print_textbox(self.textbox_message_log, "Start translation", "INFO")
|
||||
print_textbox(self.textbox_message_system_log, "Start translation", "INFO")
|
||||
else:
|
||||
if ((self.checkbox_translation.get() is False) and
|
||||
(self.checkbox_transcription_send.get() is False) and
|
||||
(self.checkbox_transcription_receive.get() is False)):
|
||||
self.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"])
|
||||
utils.print_textbox(self.textbox_message_log, "Stop translation", "INFO")
|
||||
utils.print_textbox(self.textbox_message_system_log, "Stop translation", "INFO")
|
||||
utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSLATION", self.ENABLE_TRANSLATION)
|
||||
print_textbox(self.textbox_message_log, "Stop translation", "INFO")
|
||||
print_textbox(self.textbox_message_system_log, "Stop translation", "INFO")
|
||||
save_json(self.PATH_CONFIG, "ENABLE_TRANSLATION", self.ENABLE_TRANSLATION)
|
||||
|
||||
def checkbox_transcription_send_callback(self):
|
||||
self.ENABLE_TRANSCRIPTION_SEND = self.checkbox_transcription_send.get()
|
||||
if self.ENABLE_TRANSCRIPTION_SEND is True:
|
||||
self.button_config.configure(state="disabled", fg_color=["gray92", "gray14"])
|
||||
self.mic_audio_queue = queue.Queue()
|
||||
mic_device = [device for device in audio_utils.get_input_device_list() if device["name"] == self.CHOICE_MIC_DEVICE][0]
|
||||
self.mic_audio_recorder = audio_recorder.SelectedMicRecorder(
|
||||
def transcription_send_start(self):
|
||||
self.mic_audio_queue = Queue()
|
||||
mic_device = [device for device in get_input_device_list()[self.CHOICE_MIC_HOST] if device["name"] == self.CHOICE_MIC_DEVICE][0]
|
||||
self.mic_audio_recorder = SelectedMicRecorder(
|
||||
mic_device,
|
||||
self.INPUT_MIC_ENERGY_THRESHOLD,
|
||||
self.INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD,
|
||||
self.INPUT_MIC_RECORD_TIMEOUT,
|
||||
)
|
||||
self.mic_audio_recorder.record_into_queue(self.mic_audio_queue)
|
||||
self.mic_transcriber = audio_transcriber.AudioTranscriber(
|
||||
self.mic_transcriber = AudioTranscriber(
|
||||
speaker=False,
|
||||
source=self.mic_audio_recorder.source,
|
||||
language=languages.transcription_lang[self.INPUT_MIC_VOICE_LANGUAGE],
|
||||
language=transcription_lang[self.INPUT_MIC_VOICE_LANGUAGE],
|
||||
phrase_timeout=self.INPUT_MIC_PHRASE_TIMEOUT,
|
||||
max_phrases=self.INPUT_MIC_MAX_PHRASES,
|
||||
)
|
||||
@@ -459,12 +454,18 @@ class App(customtkinter.CTk):
|
||||
self.mic_transcriber.transcribe_audio_queue(self.mic_audio_queue)
|
||||
message = self.mic_transcriber.get_transcript()
|
||||
if len(message) > 0:
|
||||
# word filter
|
||||
if len(self.keyword_processor.extract_keywords(message)) != 0:
|
||||
print_textbox(self.textbox_message_log, f"Detect WordFilter :{message}", "INFO")
|
||||
print_textbox(self.textbox_message_system_log, f"Detect WordFilter :{message}", "INFO")
|
||||
return
|
||||
|
||||
# translate
|
||||
if self.checkbox_translation.get() is False:
|
||||
voice_message = f"{message}"
|
||||
elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False:
|
||||
utils.print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
utils.print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
voice_message = f"{message}"
|
||||
else:
|
||||
result = self.translator.translate(
|
||||
@@ -477,49 +478,65 @@ class App(customtkinter.CTk):
|
||||
|
||||
if self.checkbox_transcription_send.get() is True:
|
||||
# send OSC message
|
||||
osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT)
|
||||
send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT)
|
||||
# update textbox message log
|
||||
utils.print_textbox(self.textbox_message_log, f"{voice_message}", "SEND")
|
||||
utils.print_textbox(self.textbox_message_send_log, f"{voice_message}", "SEND")
|
||||
print_textbox(self.textbox_message_log, f"{voice_message}", "SEND")
|
||||
print_textbox(self.textbox_message_send_log, f"{voice_message}", "SEND")
|
||||
|
||||
self.mic_print_transcript = utils.thread_fnc(mic_transcript_to_chatbox)
|
||||
self.mic_print_transcript = thread_fnc(mic_transcript_to_chatbox)
|
||||
self.mic_print_transcript.daemon = True
|
||||
self.mic_print_transcript.start()
|
||||
print_textbox(self.textbox_message_log, "Start voice2chatbox", "INFO")
|
||||
print_textbox(self.textbox_message_system_log, "Start voice2chatbox", "INFO")
|
||||
self.checkbox_transcription_send.configure(state="normal")
|
||||
self.checkbox_transcription_receive.configure(state="normal")
|
||||
|
||||
utils.print_textbox(self.textbox_message_log, "Start voice2chatbox", "INFO")
|
||||
utils.print_textbox(self.textbox_message_system_log, "Start voice2chatbox", "INFO")
|
||||
else:
|
||||
if ((self.checkbox_translation.get() is False) and
|
||||
(self.checkbox_transcription_send.get() is False) and
|
||||
(self.checkbox_transcription_receive.get() is False)):
|
||||
self.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"])
|
||||
if isinstance(self.mic_print_transcript, utils.thread_fnc):
|
||||
def transcription_send_stop(self):
|
||||
if isinstance(self.mic_print_transcript, thread_fnc):
|
||||
self.mic_print_transcript.stop()
|
||||
if self.mic_audio_recorder.stop != None:
|
||||
self.mic_audio_recorder.stop()
|
||||
self.mic_audio_recorder.stop = None
|
||||
|
||||
utils.print_textbox(self.textbox_message_log, "Stop voice2chatbox", "INFO")
|
||||
utils.print_textbox(self.textbox_message_system_log, "Stop voice2chatbox", "INFO")
|
||||
utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSCRIPTION_SEND", self.ENABLE_TRANSCRIPTION_SEND)
|
||||
print_textbox(self.textbox_message_log, "Stop voice2chatbox", "INFO")
|
||||
print_textbox(self.textbox_message_system_log, "Stop voice2chatbox", "INFO")
|
||||
if ((self.checkbox_translation.get() is False) and
|
||||
(self.checkbox_transcription_send.get() is False) and
|
||||
(self.checkbox_transcription_receive.get() is False)):
|
||||
self.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"])
|
||||
self.checkbox_transcription_send.configure(state="normal")
|
||||
self.checkbox_transcription_receive.configure(state="normal")
|
||||
|
||||
def checkbox_transcription_receive_callback(self):
|
||||
self.ENABLE_TRANSCRIPTION_RECEIVE = self.checkbox_transcription_receive.get()
|
||||
if self.ENABLE_TRANSCRIPTION_RECEIVE is True:
|
||||
def checkbox_transcription_send_callback(self):
|
||||
self.checkbox_transcription_send.configure(state="disabled")
|
||||
self.checkbox_transcription_receive.configure(state="disabled")
|
||||
self.button_config.configure(state="disabled", fg_color=["gray92", "gray14"])
|
||||
self.spk_audio_queue = queue.Queue()
|
||||
spk_device = [device for device in audio_utils.get_output_device_list() if device["name"] == self.CHOICE_SPEAKER_DEVICE][0]
|
||||
self.spk_audio_recorder = audio_recorder.SelectedSpeakerRecorder(
|
||||
self.update()
|
||||
self.ENABLE_TRANSCRIPTION_SEND = self.checkbox_transcription_send.get()
|
||||
if self.ENABLE_TRANSCRIPTION_SEND is True:
|
||||
th_transcription_send_start = Thread(target=self.transcription_send_start)
|
||||
th_transcription_send_start.daemon = True
|
||||
th_transcription_send_start.start()
|
||||
else:
|
||||
th_transcription_send_stop = Thread(target=self.transcription_send_stop)
|
||||
th_transcription_send_stop.daemon = True
|
||||
th_transcription_send_stop.start()
|
||||
save_json(self.PATH_CONFIG, "ENABLE_TRANSCRIPTION_SEND", self.ENABLE_TRANSCRIPTION_SEND)
|
||||
|
||||
def transcription_receive_start(self):
|
||||
self.spk_audio_queue = Queue()
|
||||
spk_device = [device for device in get_output_device_list() if device["name"] == self.CHOICE_SPEAKER_DEVICE][0]
|
||||
self.spk_audio_recorder = SelectedSpeakerRecorder(
|
||||
spk_device,
|
||||
self.INPUT_SPEAKER_ENERGY_THRESHOLD,
|
||||
self.INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD,
|
||||
self.INPUT_SPEAKER_RECORD_TIMEOUT,
|
||||
)
|
||||
self.spk_audio_recorder.record_into_queue(self.spk_audio_queue)
|
||||
self.spk_transcriber = audio_transcriber.AudioTranscriber(
|
||||
self.spk_transcriber = AudioTranscriber(
|
||||
speaker=True,
|
||||
source=self.spk_audio_recorder.source,
|
||||
language=languages.transcription_lang[self.INPUT_SPEAKER_VOICE_LANGUAGE],
|
||||
language=transcription_lang[self.INPUT_SPEAKER_VOICE_LANGUAGE],
|
||||
phrase_timeout=self.INPUT_SPEAKER_PHRASE_TIMEOUT,
|
||||
max_phrases=self.INPUT_SPEAKER_MAX_PHRASES,
|
||||
)
|
||||
@@ -532,8 +549,8 @@ class App(customtkinter.CTk):
|
||||
if self.checkbox_translation.get() is False:
|
||||
voice_message = f"{message}"
|
||||
elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False:
|
||||
utils.print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
utils.print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
voice_message = f"{message}"
|
||||
else:
|
||||
result = self.translator.translate(
|
||||
@@ -544,47 +561,69 @@ class App(customtkinter.CTk):
|
||||
)
|
||||
voice_message = self.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result)
|
||||
# send OSC message
|
||||
# osc_tools.send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT)
|
||||
# send_message(voice_message, self.OSC_IP_ADDRESS, self.OSC_PORT)
|
||||
|
||||
if self.checkbox_transcription_receive.get() is True:
|
||||
# update textbox message receive log
|
||||
utils.print_textbox(self.textbox_message_log, f"{voice_message}", "RECEIVE")
|
||||
utils.print_textbox(self.textbox_message_receive_log, f"{voice_message}", "RECEIVE")
|
||||
print_textbox(self.textbox_message_log, f"{voice_message}", "RECEIVE")
|
||||
print_textbox(self.textbox_message_receive_log, f"{voice_message}", "RECEIVE")
|
||||
|
||||
self.spk_print_transcript = utils.thread_fnc(spk_transcript_to_textbox)
|
||||
self.spk_print_transcript = thread_fnc(spk_transcript_to_textbox)
|
||||
self.spk_print_transcript.daemon = True
|
||||
self.spk_print_transcript.start()
|
||||
utils.print_textbox(self.textbox_message_log, "Start speaker2log", "INFO")
|
||||
utils.print_textbox(self.textbox_message_system_log, "Start speaker2log", "INFO")
|
||||
else:
|
||||
if ((self.checkbox_translation.get() is False) and
|
||||
(self.checkbox_transcription_send.get() is False) and
|
||||
(self.checkbox_transcription_receive.get() is False)):
|
||||
self.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"])
|
||||
if isinstance(self.spk_print_transcript, utils.thread_fnc):
|
||||
print_textbox(self.textbox_message_log, "Start speaker2log", "INFO")
|
||||
print_textbox(self.textbox_message_system_log, "Start speaker2log", "INFO")
|
||||
self.checkbox_transcription_send.configure(state="normal")
|
||||
self.checkbox_transcription_receive.configure(state="normal")
|
||||
|
||||
def transcription_receive_stop(self):
|
||||
if isinstance(self.spk_print_transcript, thread_fnc):
|
||||
self.spk_print_transcript.stop()
|
||||
if self.spk_audio_recorder.stop != None:
|
||||
self.spk_audio_recorder.stop()
|
||||
self.spk_audio_recorder.stop = None
|
||||
utils.print_textbox(self.textbox_message_log, "Stop speaker2log", "INFO")
|
||||
utils.print_textbox(self.textbox_message_system_log, "Stop speaker2log", "INFO")
|
||||
utils.save_json(self.PATH_CONFIG, "ENABLE_TRANSCRIPTION_RECEIVE", self.ENABLE_TRANSCRIPTION_RECEIVE)
|
||||
|
||||
print_textbox(self.textbox_message_log, "Stop speaker2log", "INFO")
|
||||
print_textbox(self.textbox_message_system_log, "Stop speaker2log", "INFO")
|
||||
if ((self.checkbox_translation.get() is False) and
|
||||
(self.checkbox_transcription_send.get() is False) and
|
||||
(self.checkbox_transcription_receive.get() is False)):
|
||||
self.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"])
|
||||
self.checkbox_transcription_send.configure(state="normal")
|
||||
self.checkbox_transcription_receive.configure(state="normal")
|
||||
|
||||
def checkbox_transcription_receive_callback(self):
|
||||
self.checkbox_transcription_send.configure(state="disabled")
|
||||
self.checkbox_transcription_receive.configure(state="disabled")
|
||||
self.button_config.configure(state="disabled", fg_color=["gray92", "gray14"])
|
||||
self.update()
|
||||
self.ENABLE_TRANSCRIPTION_RECEIVE = self.checkbox_transcription_receive.get()
|
||||
if self.ENABLE_TRANSCRIPTION_RECEIVE is True:
|
||||
th_transcription_receive_start = Thread(target=self.transcription_receive_start)
|
||||
th_transcription_receive_start.daemon = True
|
||||
th_transcription_receive_start.start()
|
||||
else:
|
||||
th_transcription_receive_stop = Thread(target=self.transcription_receive_stop)
|
||||
th_transcription_receive_stop.daemon = True
|
||||
th_transcription_receive_stop.start()
|
||||
|
||||
save_json(self.PATH_CONFIG, "ENABLE_TRANSCRIPTION_RECEIVE", self.ENABLE_TRANSCRIPTION_RECEIVE)
|
||||
|
||||
def checkbox_foreground_callback(self):
|
||||
self.ENABLE_FOREGROUND = self.checkbox_foreground.get()
|
||||
if self.ENABLE_FOREGROUND:
|
||||
self.attributes("-topmost", True)
|
||||
utils.print_textbox(self.textbox_message_log, "Start foreground", "INFO")
|
||||
utils.print_textbox(self.textbox_message_system_log, "Start foreground", "INFO")
|
||||
print_textbox(self.textbox_message_log, "Start foreground", "INFO")
|
||||
print_textbox(self.textbox_message_system_log, "Start foreground", "INFO")
|
||||
else:
|
||||
self.attributes("-topmost", False)
|
||||
utils.print_textbox(self.textbox_message_log, "Stop foreground", "INFO")
|
||||
utils.print_textbox(self.textbox_message_system_log, "Stop foreground", "INFO")
|
||||
utils.save_json(self.PATH_CONFIG, "ENABLE_FOREGROUND", self.ENABLE_FOREGROUND)
|
||||
print_textbox(self.textbox_message_log, "Stop foreground", "INFO")
|
||||
print_textbox(self.textbox_message_system_log, "Stop foreground", "INFO")
|
||||
save_json(self.PATH_CONFIG, "ENABLE_FOREGROUND", self.ENABLE_FOREGROUND)
|
||||
|
||||
def entry_message_box_press_key_enter(self, event):
|
||||
# send OSC typing
|
||||
osc_tools.send_typing(False, self.OSC_IP_ADDRESS, self.OSC_PORT)
|
||||
send_typing(False, self.OSC_IP_ADDRESS, self.OSC_PORT)
|
||||
|
||||
if self.ENABLE_FOREGROUND:
|
||||
self.attributes("-topmost", True)
|
||||
@@ -595,8 +634,8 @@ class App(customtkinter.CTk):
|
||||
if self.checkbox_translation.get() is False:
|
||||
chat_message = f"{message}"
|
||||
elif self.translator.translator_status[self.CHOICE_TRANSLATOR] is False:
|
||||
utils.print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
utils.print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR")
|
||||
chat_message = f"{message}"
|
||||
else:
|
||||
result = self.translator.translate(
|
||||
@@ -608,24 +647,34 @@ class App(customtkinter.CTk):
|
||||
chat_message = self.MESSAGE_FORMAT.replace("[message]", message).replace("[translation]", result)
|
||||
|
||||
# send OSC message
|
||||
osc_tools.send_message(chat_message, self.OSC_IP_ADDRESS, self.OSC_PORT)
|
||||
send_message(chat_message, self.OSC_IP_ADDRESS, self.OSC_PORT)
|
||||
|
||||
# update textbox message log
|
||||
utils.print_textbox(self.textbox_message_log, f"{chat_message}", "SEND")
|
||||
utils.print_textbox(self.textbox_message_send_log, f"{chat_message}", "SEND")
|
||||
print_textbox(self.textbox_message_log, f"{chat_message}", "SEND")
|
||||
print_textbox(self.textbox_message_send_log, f"{chat_message}", "SEND")
|
||||
|
||||
# delete message in entry message box
|
||||
# self.entry_message_box.delete(0, customtkinter.END)
|
||||
if self.ENABLE_AUTO_CLEAR_CHATBOX == True:
|
||||
self.entry_message_box.delete(0, customtkinter.END)
|
||||
|
||||
BREAK_KEYSYM_LIST = [
|
||||
"Delete", "Select", "Up", "Down", "Next", "End", "Print",
|
||||
"Prior","Insert","Home", "Left", "Clear", "Right", "Linefeed"
|
||||
]
|
||||
def entry_message_box_press_key_any(self, event):
|
||||
# send OSC typing
|
||||
osc_tools.send_typing(True, self.OSC_IP_ADDRESS, self.OSC_PORT)
|
||||
send_typing(True, self.OSC_IP_ADDRESS, self.OSC_PORT)
|
||||
if self.ENABLE_FOREGROUND:
|
||||
self.attributes("-topmost", False)
|
||||
|
||||
if event.keysym != "??":
|
||||
if len(event.char) != 0 and event.keysym in self.BREAK_KEYSYM_LIST:
|
||||
self.entry_message_box.insert("end", event.char)
|
||||
return "break"
|
||||
|
||||
def entry_message_box_leave(self, event):
|
||||
# send OSC typing
|
||||
osc_tools.send_typing(False, self.OSC_IP_ADDRESS, self.OSC_PORT)
|
||||
send_typing(False, self.OSC_IP_ADDRESS, self.OSC_PORT)
|
||||
if self.ENABLE_FOREGROUND:
|
||||
self.attributes("-topmost", True)
|
||||
|
||||
@@ -633,6 +682,71 @@ class App(customtkinter.CTk):
|
||||
self.quit()
|
||||
self.destroy()
|
||||
|
||||
def delete_tabview_logs(self, pre_language_yaml_data):
|
||||
self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_log"])
|
||||
self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_send"])
|
||||
self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_receive"])
|
||||
self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_system"])
|
||||
|
||||
def add_tabview_logs(self, language_yaml_data):
|
||||
main_tab_title_log = language_yaml_data["main_tab_title_log"]
|
||||
main_tab_title_send = language_yaml_data["main_tab_title_send"]
|
||||
main_tab_title_receive = language_yaml_data["main_tab_title_receive"]
|
||||
main_tab_title_system = language_yaml_data["main_tab_title_system"]
|
||||
|
||||
# add tabview textbox
|
||||
self.tabview_logs = CTkTabview(master=self)
|
||||
self.tabview_logs.add(main_tab_title_log)
|
||||
self.tabview_logs.add(main_tab_title_send)
|
||||
self.tabview_logs.add(main_tab_title_receive)
|
||||
self.tabview_logs.add(main_tab_title_system)
|
||||
self.tabview_logs.grid(row=0, column=1, padx=0, pady=0, sticky="nsew")
|
||||
self.tabview_logs._segmented_button.configure(font=CTkFont(family=self.FONT_FAMILY))
|
||||
self.tabview_logs._segmented_button.grid(sticky="W")
|
||||
self.tabview_logs.tab(main_tab_title_log).grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_log).grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_send).grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_send).grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_receive).grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_receive).grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_system).grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_system).grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.configure(fg_color="transparent")
|
||||
|
||||
# add textbox message log
|
||||
self.textbox_message_log = CTkTextbox(
|
||||
self.tabview_logs.tab(main_tab_title_log),
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_log.configure(state='disabled')
|
||||
|
||||
# add textbox message send log
|
||||
self.textbox_message_send_log = CTkTextbox(
|
||||
self.tabview_logs.tab(main_tab_title_send),
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_send_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_send_log.configure(state='disabled')
|
||||
|
||||
# add textbox message receive log
|
||||
self.textbox_message_receive_log = CTkTextbox(
|
||||
self.tabview_logs.tab(main_tab_title_receive),
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_receive_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_receive_log.configure(state='disabled')
|
||||
|
||||
# add textbox message system log
|
||||
self.textbox_message_system_log = CTkTextbox(
|
||||
self.tabview_logs.tab(main_tab_title_system),
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_system_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_system_log.configure(state='disabled')
|
||||
|
||||
widget_main_window_label_setter(self, language_yaml_data)
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
app = App()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import speech_recognition as sr
|
||||
import pyaudiowpatch as pyaudio
|
||||
from speech_recognition import Recognizer, Microphone
|
||||
from pyaudiowpatch import get_sample_size, paInt16
|
||||
from datetime import datetime
|
||||
|
||||
class BaseRecorder:
|
||||
def __init__(self, source, energy_threshold, dynamic_energy_threshold, record_timeout):
|
||||
self.recorder = sr.Recognizer()
|
||||
self.recorder = Recognizer()
|
||||
self.recorder.energy_threshold = energy_threshold
|
||||
self.recorder.dynamic_energy_threshold = dynamic_energy_threshold
|
||||
self.record_timeout = record_timeout
|
||||
@@ -20,14 +20,14 @@ class BaseRecorder:
|
||||
self.recorder.adjust_for_ambient_noise(self.source)
|
||||
|
||||
def record_into_queue(self, audio_queue):
|
||||
def record_callback(_, audio:sr.AudioData) -> None:
|
||||
def record_callback(_, audio):
|
||||
audio_queue.put((audio.get_raw_data(), datetime.now()))
|
||||
|
||||
self.stop = self.recorder.listen_in_background(self.source, record_callback, phrase_time_limit=self.record_timeout)
|
||||
|
||||
class SelectedMicRecorder(BaseRecorder):
|
||||
def __init__(self, device, energy_threshold, dynamic_energy_threshold, record_timeout):
|
||||
source=sr.Microphone(
|
||||
source=Microphone(
|
||||
device_index=device['index'],
|
||||
sample_rate=int(device["defaultSampleRate"]),
|
||||
)
|
||||
@@ -37,11 +37,55 @@ class SelectedMicRecorder(BaseRecorder):
|
||||
class SelectedSpeakerRecorder(BaseRecorder):
|
||||
def __init__(self, device, energy_threshold, dynamic_energy_threshold, record_timeout):
|
||||
|
||||
source = sr.Microphone(speaker=True,
|
||||
source = Microphone(speaker=True,
|
||||
device_index= device["index"],
|
||||
sample_rate=int(device["defaultSampleRate"]),
|
||||
chunk_size=pyaudio.get_sample_size(pyaudio.paInt16),
|
||||
chunk_size=get_sample_size(paInt16),
|
||||
channels=device["maxInputChannels"]
|
||||
)
|
||||
super().__init__(source=source, energy_threshold=energy_threshold, dynamic_energy_threshold=dynamic_energy_threshold, record_timeout=record_timeout)
|
||||
self.adjust_for_noise()
|
||||
|
||||
class BaseEnergyRecorder:
|
||||
def __init__(self, source):
|
||||
self.recorder = Recognizer()
|
||||
self.recorder.energy_threshold = 0
|
||||
self.recorder.dynamic_energy_threshold = False
|
||||
self.record_timeout = 0
|
||||
self.stop = None
|
||||
|
||||
if source is None:
|
||||
raise ValueError("audio source can't be None")
|
||||
|
||||
self.source = source
|
||||
|
||||
def adjust_for_noise(self):
|
||||
with self.source:
|
||||
self.recorder.adjust_for_ambient_noise(self.source)
|
||||
|
||||
def record_into_queue(self, energy_queue):
|
||||
def record_callback(_, energy):
|
||||
energy_queue.put(energy)
|
||||
|
||||
self.stop = self.recorder.listen_energy_in_background(self.source, record_callback)
|
||||
|
||||
class SelectedMicEnergyRecorder(BaseEnergyRecorder):
|
||||
def __init__(self, device):
|
||||
source=Microphone(
|
||||
device_index=device['index'],
|
||||
sample_rate=int(device["defaultSampleRate"]),
|
||||
)
|
||||
super().__init__(source=source)
|
||||
self.adjust_for_noise()
|
||||
|
||||
class SelectedSpeakeEnergyRecorder(BaseEnergyRecorder):
|
||||
def __init__(self, device):
|
||||
|
||||
source = Microphone(speaker=True,
|
||||
device_index= device["index"],
|
||||
sample_rate=int(device["defaultSampleRate"]),
|
||||
chunk_size=get_sample_size(paInt16),
|
||||
channels=device["maxInputChannels"]
|
||||
)
|
||||
super().__init__(source=source)
|
||||
self.adjust_for_noise()
|
||||
@@ -1,9 +1,9 @@
|
||||
import io
|
||||
import threading
|
||||
from io import BytesIO
|
||||
from threading import Event
|
||||
import wave
|
||||
import speech_recognition as sr
|
||||
from speech_recognition import Recognizer, AudioData, AudioFile
|
||||
from datetime import timedelta
|
||||
import pyaudiowpatch as pyaudio
|
||||
from pyaudiowpatch import get_sample_size, paInt16
|
||||
|
||||
PHRASE_TIMEOUT = 3
|
||||
MAX_PHRASES = 10
|
||||
@@ -15,8 +15,8 @@ class AudioTranscriber:
|
||||
self.phrase_timeout = phrase_timeout
|
||||
self.max_phrases = max_phrases
|
||||
self.transcript_data = []
|
||||
self.transcript_changed_event = threading.Event()
|
||||
self.audio_recognizer = sr.Recognizer()
|
||||
self.transcript_changed_event = Event()
|
||||
self.audio_recognizer = Recognizer()
|
||||
self.audio_sources = {
|
||||
"sample_rate": source.SAMPLE_RATE,
|
||||
"sample_width": source.SAMPLE_WIDTH,
|
||||
@@ -59,19 +59,18 @@ class AudioTranscriber:
|
||||
source_info["last_spoken"] = time_spoken
|
||||
|
||||
def process_mic_data(self):
|
||||
audio_data = sr.AudioData(self.audio_sources["last_sample"], self.audio_sources["sample_rate"], self.audio_sources["sample_width"])
|
||||
audio_data = AudioData(self.audio_sources["last_sample"], self.audio_sources["sample_rate"], self.audio_sources["sample_width"])
|
||||
return audio_data
|
||||
|
||||
def process_speaker_data(self):
|
||||
temp_file = io.BytesIO()
|
||||
temp_file = BytesIO()
|
||||
with wave.open(temp_file, 'wb') as wf:
|
||||
wf.setnchannels(self.audio_sources["channels"])
|
||||
p = pyaudio.PyAudio()
|
||||
wf.setsampwidth(p.get_sample_size(pyaudio.paInt16))
|
||||
wf.setsampwidth(get_sample_size(paInt16))
|
||||
wf.setframerate(self.audio_sources["sample_rate"])
|
||||
wf.writeframes(self.audio_sources["last_sample"])
|
||||
temp_file.seek(0)
|
||||
with sr.AudioFile(temp_file) as source:
|
||||
with AudioFile(temp_file) as source:
|
||||
audio = self.audio_recognizer.record(source)
|
||||
return audio
|
||||
|
||||
|
||||
@@ -1,40 +1,43 @@
|
||||
import pyaudiowpatch as pyaudio
|
||||
from pyaudiowpatch import PyAudio, paWASAPI
|
||||
|
||||
def get_input_device_list():
|
||||
devices = []
|
||||
with pyaudio.PyAudio() as p:
|
||||
wasapi_info = p.get_host_api_info_by_type(pyaudio.paWASAPI)
|
||||
devices = {}
|
||||
with PyAudio() as p:
|
||||
for host_index in range(0, p.get_host_api_count()):
|
||||
for device_index in range(0, p. get_host_api_info_by_index(host_index)['deviceCount']):
|
||||
host = p.get_host_api_info_by_index(host_index)
|
||||
for device_index in range(0, p.get_host_api_info_by_index(host_index)['deviceCount']):
|
||||
device = p.get_device_info_by_host_api_device_index(host_index, device_index)
|
||||
if device["hostApi"] == wasapi_info["index"] and device["maxInputChannels"] > 0 and device["isLoopbackDevice"] is False:
|
||||
devices.append(device)
|
||||
if device["maxInputChannels"] > 0 and device["isLoopbackDevice"] is False:
|
||||
if host["name"] in devices.keys():
|
||||
devices[host["name"]].append(device)
|
||||
else:
|
||||
devices[host["name"]] = [device]
|
||||
return devices
|
||||
|
||||
def get_output_device_list():
|
||||
devices =[]
|
||||
with pyaudio.PyAudio() as p:
|
||||
wasapi_info = p.get_host_api_info_by_type(pyaudio.paWASAPI)
|
||||
with PyAudio() as p:
|
||||
wasapi_info = p.get_host_api_info_by_type(paWASAPI)
|
||||
for device in p.get_loopback_device_info_generator():
|
||||
if device["hostApi"] == wasapi_info["index"] and device["isLoopbackDevice"] is True:
|
||||
devices.append(device)
|
||||
return devices
|
||||
|
||||
def get_default_input_device():
|
||||
with pyaudio.PyAudio() as p:
|
||||
wasapi_info = p.get_host_api_info_by_type(pyaudio.paWASAPI)
|
||||
defaultInputDevice = wasapi_info["defaultInputDevice"]
|
||||
with PyAudio() as p:
|
||||
api_info = p.get_default_host_api_info()
|
||||
defaultInputDevice = api_info["defaultInputDevice"]
|
||||
|
||||
for host_index in range(0, p.get_host_api_count()):
|
||||
host = p.get_host_api_info_by_index(host_index)
|
||||
for device_index in range(0, p. get_host_api_info_by_index(host_index)['deviceCount']):
|
||||
device = p.get_device_info_by_host_api_device_index(host_index, device_index)
|
||||
if device["index"] == defaultInputDevice:
|
||||
default_device = device
|
||||
return default_device
|
||||
return {"host":host, "device": device}
|
||||
|
||||
def get_default_output_device():
|
||||
with pyaudio.PyAudio() as p:
|
||||
wasapi_info = p.get_host_api_info_by_type(pyaudio.paWASAPI)
|
||||
with PyAudio() as p:
|
||||
wasapi_info = p.get_host_api_info_by_type(paWASAPI)
|
||||
defaultOutputDevice = wasapi_info["defaultOutputDevice"]
|
||||
|
||||
for host_index in range(0, p.get_host_api_count()):
|
||||
|
||||
325
ctk_scrollable_dropdown.py
Normal file
325
ctk_scrollable_dropdown.py
Normal file
@@ -0,0 +1,325 @@
|
||||
"""
|
||||
CustomTkinter Scrollable Dropdown Menu
|
||||
Author: Akash Bora
|
||||
License: MIT
|
||||
This is a custom dropdown menu for customtkinter.
|
||||
Homepage: https://github.com/Akascape/CTkScrollableDropdown
|
||||
|
||||
Advanced Scrollable Dropdown class for customtkinter widgets
|
||||
Author: Akash Bora
|
||||
"""
|
||||
import customtkinter
|
||||
import sys
|
||||
import time
|
||||
|
||||
class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
||||
|
||||
def __init__(self, attach, x=None, y=None, button_color=None, height: int = 200, width: int = None,
|
||||
fg_color=None, button_height: int = 20, justify="center", scrollbar_button_color=None,
|
||||
scrollbar=True, scrollbar_button_hover_color=None, frame_border_width=2, values=[],
|
||||
command=None, image_values=[], alpha: float = 0.97, frame_corner_radius=20, double_click=False,
|
||||
resize=True, frame_border_color=None, text_color=None, autocomplete=False, **button_kwargs):
|
||||
|
||||
super().__init__(takefocus=1)
|
||||
self.transient(self.master)
|
||||
self.alpha = alpha
|
||||
self.attach = attach
|
||||
self.corner = frame_corner_radius
|
||||
self.padding = 0
|
||||
self.focus_something = False
|
||||
self.disable = True
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
self.after(100, lambda: self.overrideredirect(True))
|
||||
self.transparent_color = self._apply_appearance_mode(self._fg_color)
|
||||
self.attributes("-transparentcolor", self.transparent_color)
|
||||
elif sys.platform.startswith("darwin"):
|
||||
self.overrideredirect(True)
|
||||
self.transparent_color = 'systemTransparent'
|
||||
self.attributes("-transparent", True)
|
||||
self.focus_something = True
|
||||
else:
|
||||
self.overrideredirect(True)
|
||||
self.transparent_color = '#000001'
|
||||
self.corner = 0
|
||||
self.padding = 18
|
||||
self.withdraw()
|
||||
|
||||
self.hide = True
|
||||
self.attach.bind('<Configure>', lambda e: self._withdraw() if not self.disable else None, add="+")
|
||||
self.attach.winfo_toplevel().bind('<Configure>', lambda e: self._withdraw() if not self.disable else None, add="+")
|
||||
self.attach.winfo_toplevel().bind("<Triple-Button-1>", lambda e: self._withdraw() if not self.disable else None, add="+")
|
||||
self.attach.winfo_toplevel().bind("<Button-3>", lambda e: self._withdraw() if not self.disable else None, add="+")
|
||||
self.attach.winfo_toplevel().bind("<Button-2>", lambda e: self._withdraw() if not self.disable else None, add="+")
|
||||
|
||||
self.attributes('-alpha', 0)
|
||||
self.disable = False
|
||||
self.fg_color = customtkinter.ThemeManager.theme["CTkFrame"]["fg_color"] if fg_color is None else fg_color
|
||||
self.scroll_button_color = customtkinter.ThemeManager.theme["CTkScrollbar"]["button_color"] if scrollbar_button_color is None else scrollbar_button_color
|
||||
self.scroll_hover_color = customtkinter.ThemeManager.theme["CTkScrollbar"]["button_hover_color"] if scrollbar_button_hover_color is None else scrollbar_button_hover_color
|
||||
self.frame_border_color = customtkinter.ThemeManager.theme["CTkFrame"]["border_color"] if frame_border_color is None else frame_border_color
|
||||
self.button_color = customtkinter.ThemeManager.theme["CTkFrame"]["top_fg_color"] if button_color is None else button_color
|
||||
self.text_color = customtkinter.ThemeManager.theme["CTkLabel"]["text_color"] if text_color is None else text_color
|
||||
|
||||
if scrollbar is False:
|
||||
self.scroll_button_color = self.fg_color
|
||||
self.scroll_hover_color = self.fg_color
|
||||
|
||||
self.frame = customtkinter.CTkScrollableFrame(self, bg_color=self.transparent_color, fg_color=self.fg_color,
|
||||
scrollbar_button_hover_color=self.scroll_hover_color,
|
||||
corner_radius=self.corner, border_width=frame_border_width,
|
||||
scrollbar_button_color=self.scroll_button_color,
|
||||
border_color=self.frame_border_color)
|
||||
self.frame._scrollbar.grid_configure(padx=3)
|
||||
self.frame.pack(expand=True, fill="both")
|
||||
|
||||
self.dummy_entry = customtkinter.CTkEntry(self.frame, fg_color="transparent", border_width=0, height=1, width=1)
|
||||
self.no_match = customtkinter.CTkLabel(self.frame, text="No Match")
|
||||
self.height = height
|
||||
self.height_new = height
|
||||
self.width = width
|
||||
self.command = command
|
||||
self.fade = False
|
||||
self.resize = resize
|
||||
self.autocomplete = autocomplete
|
||||
self.var_update = customtkinter.StringVar()
|
||||
self.appear = False
|
||||
|
||||
if justify.lower()=="left":
|
||||
self.justify = "w"
|
||||
elif justify.lower()=="right":
|
||||
self.justify = "e"
|
||||
else:
|
||||
self.justify = "c"
|
||||
|
||||
self.button_height = button_height
|
||||
self.values = values
|
||||
self.button_num = len(self.values)
|
||||
self.image_values = None if len(image_values)!=len(self.values) else image_values
|
||||
|
||||
self.resizable(width=False, height=False)
|
||||
self._init_buttons(**button_kwargs)
|
||||
|
||||
# Add binding for different ctk widgets
|
||||
if double_click or self.attach.winfo_name().startswith("!ctkentry") or self.attach.winfo_name().startswith("!ctkcombobox"):
|
||||
self.attach.bind('<Double-Button-1>', lambda e: self._iconify(), add="+")
|
||||
else:
|
||||
self.attach.bind('<Button-1>', lambda e: self._iconify(), add="+")
|
||||
|
||||
if self.attach.winfo_name().startswith("!ctkcombobox"):
|
||||
self.attach._canvas.tag_bind("right_parts", "<Button-1>", lambda e: self._iconify())
|
||||
self.attach._canvas.tag_bind("dropdown_arrow", "<Button-1>", lambda e: self._iconify())
|
||||
if self.command is None:
|
||||
self.command = self.attach.set
|
||||
|
||||
if self.attach.winfo_name().startswith("!ctkoptionmenu"):
|
||||
self.attach._canvas.bind("<Button-1>", lambda e: self._iconify())
|
||||
self.attach._text_label.bind("<Button-1>", lambda e: self._iconify())
|
||||
if self.command is None:
|
||||
self.command = self.attach.set
|
||||
|
||||
self.update_idletasks()
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
if self.autocomplete:
|
||||
self.bind_autocomplete()
|
||||
|
||||
# self.deiconify()
|
||||
self.withdraw()
|
||||
|
||||
self.attributes("-alpha", self.alpha)
|
||||
|
||||
def _withdraw(self):
|
||||
if self.hide is False: self.withdraw()
|
||||
self.hide = True
|
||||
|
||||
def _update(self, a, b, c):
|
||||
self.live_update(self.attach._entry.get())
|
||||
|
||||
def bind_autocomplete(self, ):
|
||||
def appear(x):
|
||||
self.appear = True
|
||||
|
||||
if self.attach.winfo_name().startswith("!ctkcombobox"):
|
||||
self.attach._entry.configure(textvariable=self.var_update)
|
||||
self.attach._entry.bind("<Key>", appear)
|
||||
self.attach.set(self.values[0])
|
||||
self.var_update.trace_add('write', self._update)
|
||||
|
||||
if self.attach.winfo_name().startswith("!ctkentry"):
|
||||
self.attach.configure(textvariable=self.var_update)
|
||||
self.attach.bind("<Key>", appear)
|
||||
self.var_update.trace_add('write', self._update)
|
||||
|
||||
def fade_out(self):
|
||||
for i in range(100,0,-10):
|
||||
if not self.winfo_exists():
|
||||
break
|
||||
self.attributes("-alpha", i/100)
|
||||
self.update()
|
||||
time.sleep(1/100)
|
||||
|
||||
def fade_in(self):
|
||||
for i in range(0,100,10):
|
||||
if not self.winfo_exists():
|
||||
break
|
||||
self.attributes("-alpha", i/100)
|
||||
self.update()
|
||||
time.sleep(1/100)
|
||||
|
||||
def _init_buttons(self, **button_kwargs):
|
||||
self.i = 0
|
||||
self.widgets = {}
|
||||
for row in self.values:
|
||||
self.widgets[self.i] = customtkinter.CTkButton(self.frame,
|
||||
text=row,
|
||||
height=self.button_height,
|
||||
fg_color=self.button_color,
|
||||
text_color=self.text_color,
|
||||
image=self.image_values[i] if self.image_values is not None else None,
|
||||
anchor=self.justify,
|
||||
command=lambda k=row: self._attach_key_press(k), **button_kwargs)
|
||||
self.widgets[self.i].pack(fill="x", pady=2, padx=(self.padding, 0))
|
||||
self.i+=1
|
||||
|
||||
self.hide = False
|
||||
|
||||
def destroy_popup(self):
|
||||
self.destroy()
|
||||
self.disable = True
|
||||
|
||||
def place_dropdown(self):
|
||||
self.x_pos = self.attach.winfo_rootx() if self.x is None else self.x + self.attach.winfo_rootx()
|
||||
self.y_pos = self.attach.winfo_rooty() + self.attach.winfo_reqheight() + 5 if self.y is None else self.y + self.attach.winfo_rooty()
|
||||
self.width_new = self.attach.winfo_width() if self.width is None else self.width
|
||||
|
||||
if self.resize:
|
||||
if self.button_num==1:
|
||||
self.height_new = self.button_height * self.button_num + 45
|
||||
else:
|
||||
self.height_new = self.button_height * self.button_num + 35
|
||||
if self.height_new>self.height:
|
||||
self.height_new = self.height
|
||||
|
||||
self.geometry('{}x{}+{}+{}'.format(self.width_new, self.height_new,
|
||||
self.x_pos, self.y_pos))
|
||||
self.fade_in()
|
||||
self.attributes('-alpha', self.alpha)
|
||||
|
||||
def _iconify(self):
|
||||
if self.disable: return
|
||||
if self.hide:
|
||||
self._deiconify()
|
||||
self.place_dropdown()
|
||||
if self.focus_something:
|
||||
self.dummy_entry.pack()
|
||||
self.dummy_entry.focus_set()
|
||||
self.after(100, self.dummy_entry.pack_forget)
|
||||
self.hide = False
|
||||
self.focus_set()
|
||||
self.focus()
|
||||
else:
|
||||
self.withdraw()
|
||||
self.hide = True
|
||||
|
||||
def _attach_key_press(self, k):
|
||||
self.fade = True
|
||||
if self.command:
|
||||
self.command(k)
|
||||
self.fade = False
|
||||
self.fade_out()
|
||||
self.withdraw()
|
||||
self.hide = True
|
||||
|
||||
def live_update(self, string=None):
|
||||
if not self.appear: return
|
||||
if self.disable: return
|
||||
if self.fade: return
|
||||
if string:
|
||||
self._deiconify()
|
||||
i=1
|
||||
for key in self.widgets.keys():
|
||||
s = self.widgets[key].cget("text")
|
||||
if not s.startswith(string):
|
||||
self.widgets[key].pack_forget()
|
||||
else:
|
||||
self.widgets[key].pack(fill="x", pady=2, padx=(self.padding, 0))
|
||||
i+=1
|
||||
|
||||
if i==1:
|
||||
self.no_match.pack(fill="x", pady=2, padx=(self.padding, 0))
|
||||
else:
|
||||
self.no_match.pack_forget()
|
||||
self.button_num = i
|
||||
self.place_dropdown()
|
||||
|
||||
else:
|
||||
self.no_match.pack_forget()
|
||||
self.button_num = len(self.values)
|
||||
for key in self.widgets.keys():
|
||||
self.widgets[key].destroy()
|
||||
self._init_buttons()
|
||||
self.place_dropdown()
|
||||
|
||||
self.frame._parent_canvas.yview_moveto(0.0)
|
||||
self.appear = False
|
||||
|
||||
def insert(self, value, **kwargs):
|
||||
self.widgets[self.i] = customtkinter.CTkButton(self.frame,
|
||||
text=value,
|
||||
height=self.button_height,
|
||||
fg_color=self.button_color,
|
||||
text_color=self.text_color,
|
||||
anchor=self.justify,
|
||||
command=lambda k=value: self._attach_key_press(k), **kwargs)
|
||||
self.widgets[self.i].pack(fill="x", pady=2, padx=(self.padding, 0))
|
||||
self.i+=1
|
||||
self.values.append(value)
|
||||
|
||||
def _deiconify(self):
|
||||
if len(self.values)>0:
|
||||
self.deiconify()
|
||||
|
||||
def popup(self, x=None, y=None):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.hide = True
|
||||
self._iconify()
|
||||
|
||||
def configure(self, **kwargs):
|
||||
if "height" in kwargs:
|
||||
self.height = kwargs.pop("height")
|
||||
self.height_new = self.height
|
||||
|
||||
if "alpha" in kwargs:
|
||||
self.alpha = kwargs.pop("alpha")
|
||||
|
||||
if "width" in kwargs:
|
||||
self.width = kwargs.pop("width")
|
||||
|
||||
if "fg_color" in kwargs:
|
||||
self.frame.configure(fg_color=kwargs.pop("fg_color"))
|
||||
|
||||
if "values" in kwargs:
|
||||
self.values = kwargs.pop("values")
|
||||
self.image_values = None
|
||||
for key in self.widgets.keys():
|
||||
self.widgets[key].destroy()
|
||||
self._init_buttons()
|
||||
|
||||
if "image_values" in kwargs:
|
||||
self.image_values = kwargs.pop("image_values")
|
||||
self.image_values = None if len(self.image_values)!=len(self.values) else self.image_values
|
||||
if self.image_values is not None:
|
||||
i=0
|
||||
for key in self.widgets.keys():
|
||||
self.widgets[key].configure(image=self.image_values[i])
|
||||
i+=1
|
||||
|
||||
if "button_color" in kwargs:
|
||||
for key in self.widgets.keys():
|
||||
self.widgets[key].configure(fg_color=kwargs.pop("button_color"))
|
||||
|
||||
for key in self.widgets.keys():
|
||||
self.widgets[key].configure(**kwargs)
|
||||
250
languages.py
250
languages.py
@@ -154,128 +154,134 @@ translation_lang["DeepL(auth)"] = {
|
||||
"Chinese":"zh"
|
||||
}
|
||||
translation_lang["Google(web)"] = {
|
||||
"japanese":"ja",
|
||||
"english":"en",
|
||||
"chinese":"zh",
|
||||
"arabic":"ar",
|
||||
"russian":"ru",
|
||||
"french":"fr",
|
||||
"german":"de",
|
||||
"spanish":"es",
|
||||
"portuguese":"pt",
|
||||
"italian":"it",
|
||||
"korean":"ko",
|
||||
"greek":"el",
|
||||
"dutch":"nl",
|
||||
"hindi":"hi",
|
||||
"turkish":"tr",
|
||||
"malay":"ms",
|
||||
"thai":"th",
|
||||
"vietnamese":"vi",
|
||||
"indonesian":"id",
|
||||
"hebrew":"he",
|
||||
"polish":"pl",
|
||||
"mongolian":"mn",
|
||||
"czech":"cs",
|
||||
"hungarian":"hu",
|
||||
"estonian":"et",
|
||||
"bulgarian":"bg",
|
||||
"danish":"da",
|
||||
"finnish":"fi",
|
||||
"romanian":"ro",
|
||||
"swedish":"sv",
|
||||
"slovenian":"sl",
|
||||
"persian/farsi":"fa",
|
||||
"bosnian":"bs",
|
||||
"serbian":"sr",
|
||||
"filipino":"tl",
|
||||
"haitiancreole":"ht",
|
||||
"catalan":"ca",
|
||||
"croatian":"hr",
|
||||
"latvian":"lv",
|
||||
"lithuanian":"lt",
|
||||
"urdu":"ur",
|
||||
"ukrainian":"uk",
|
||||
"welsh":"cy",
|
||||
"swahili":"sw",
|
||||
"samoan":"sm",
|
||||
"slovak":"sk",
|
||||
"afrikaans":"af",
|
||||
"norwegian":"no",
|
||||
"bengali":"bn",
|
||||
"malagasy":"mg",
|
||||
"maltese":"mt",
|
||||
"gujarati":"gu",
|
||||
"tamil":"ta",
|
||||
"telugu":"te",
|
||||
"punjabi":"pa",
|
||||
"amharic":"am",
|
||||
"azerbaijani":"az",
|
||||
"belarusian":"be",
|
||||
"cebuano":"ceb",
|
||||
"esperanto":"eo",
|
||||
"basque":"eu",
|
||||
"irish":"ga"
|
||||
"Japanese":"ja",
|
||||
"English":"en",
|
||||
"Chinese":"zh",
|
||||
"Arabic":"ar",
|
||||
"Russian":"ru",
|
||||
"French":"fr",
|
||||
"German":"de",
|
||||
"Spanish":"es",
|
||||
"Portuguese":"pt",
|
||||
"Italian":"it",
|
||||
"Korean":"ko",
|
||||
"Greek":"el",
|
||||
"Dutch":"nl",
|
||||
"Hindi":"hi",
|
||||
"Turkish":"tr",
|
||||
"Malay":"ms",
|
||||
"Thai":"th",
|
||||
"Vietnamese":"vi",
|
||||
"Indonesian":"id",
|
||||
"Hebrew":"he",
|
||||
"Polish":"pl",
|
||||
"Mongolian":"mn",
|
||||
"Czech":"cs",
|
||||
"Hungarian":"hu",
|
||||
"Estonian":"et",
|
||||
"Bulgarian":"bg",
|
||||
"Danish":"da",
|
||||
"Finnish":"fi",
|
||||
"Romanian":"ro",
|
||||
"Swedish":"sv",
|
||||
"Slovenian":"sl",
|
||||
"Persian/Farsi":"fa",
|
||||
"Bosnian":"bs",
|
||||
"Serbian":"sr",
|
||||
"Filipino":"tl",
|
||||
"Haitiancreole":"ht",
|
||||
"Catalan":"ca",
|
||||
"Croatian":"hr",
|
||||
"Latvian":"lv",
|
||||
"Lithuanian":"lt",
|
||||
"Urdu":"ur",
|
||||
"Ukrainian":"uk",
|
||||
"Welsh":"cy",
|
||||
"Swahili":"sw",
|
||||
"Samoan":"sm",
|
||||
"Slovak":"sk",
|
||||
"Afrikaans":"af",
|
||||
"Norwegian":"no",
|
||||
"Bengali":"bn",
|
||||
"Malagasy":"mg",
|
||||
"Maltese":"mt",
|
||||
"Gujarati":"gu",
|
||||
"Tamil":"ta",
|
||||
"Telugu":"te",
|
||||
"Punjabi":"pa",
|
||||
"Amharic":"am",
|
||||
"Azerbaijani":"az",
|
||||
"Belarusian":"be",
|
||||
"Cebuano":"ceb",
|
||||
"Esperanto":"eo",
|
||||
"Basque":"eu",
|
||||
"Irish":"ga"
|
||||
}
|
||||
translation_lang["Bing(web)"] = {
|
||||
"japanese":"ja",
|
||||
"english":"en",
|
||||
"chinese":"zh",
|
||||
"arabic":"ar",
|
||||
"russian":"ru",
|
||||
"french":"fr",
|
||||
"german":"de",
|
||||
"spanish":"es",
|
||||
"portuguese":"pt",
|
||||
"italian":"it",
|
||||
"korean":"ko",
|
||||
"greek":"el",
|
||||
"dutch":"nl",
|
||||
"hindi":"hi",
|
||||
"turkish":"tr",
|
||||
"malay":"ms",
|
||||
"thai":"th",
|
||||
"vietnamese":"vi",
|
||||
"indonesian":"id",
|
||||
"hebrew":"he",
|
||||
"polish":"pl",
|
||||
"czech":"cs",
|
||||
"hungarian":"hu",
|
||||
"estonian":"et",
|
||||
"bulgarian":"bg",
|
||||
"danish":"da",
|
||||
"finnish":"fi",
|
||||
"romanian":"ro",
|
||||
"swedish":"sv",
|
||||
"slovenian":"sl",
|
||||
"persian/farsi":"fa",
|
||||
"bosnian":"bs",
|
||||
"serbian":"sr",
|
||||
"fijian":"fj",
|
||||
"filipino":"tl",
|
||||
"haitiancreole":"ht",
|
||||
"catalan":"ca",
|
||||
"croatian":"hr",
|
||||
"latvian":"lv",
|
||||
"lithuanian":"lt",
|
||||
"urdu":"ur",
|
||||
"ukrainian":"uk",
|
||||
"welsh":"cy",
|
||||
"tahiti":"ty",
|
||||
"tongan":"to",
|
||||
"swahili":"sw",
|
||||
"samoan":"sm",
|
||||
"slovak":"sk",
|
||||
"afrikaans":"af",
|
||||
"norwegian":"no",
|
||||
"bengali":"bn",
|
||||
"malagasy":"mg",
|
||||
"maltese":"mt",
|
||||
"queretaro otomi":"otq",
|
||||
"klingon/tlhingan hol":"tlh",
|
||||
"gujarati":"gu",
|
||||
"tamil":"ta",
|
||||
"telugu":"te",
|
||||
"punjabi":"pa",
|
||||
"irish":"ga"
|
||||
"Japanese":"ja",
|
||||
"English":"en",
|
||||
"Chinese":"zh",
|
||||
"Arabic":"ar",
|
||||
"Russian":"ru",
|
||||
"French":"fr",
|
||||
"German":"de",
|
||||
"Spanish":"es",
|
||||
"Portuguese":"pt",
|
||||
"Italian":"it",
|
||||
"Korean":"ko",
|
||||
"Greek":"el",
|
||||
"Dutch":"nl",
|
||||
"Hindi":"hi",
|
||||
"Turkish":"tr",
|
||||
"Malay":"ms",
|
||||
"Thai":"th",
|
||||
"Vietnamese":"vi",
|
||||
"Indonesian":"id",
|
||||
"Hebrew":"he",
|
||||
"Polish":"pl",
|
||||
"Czech":"cs",
|
||||
"Hungarian":"hu",
|
||||
"Estonian":"et",
|
||||
"Bulgarian":"bg",
|
||||
"Danish":"da",
|
||||
"Finnish":"fi",
|
||||
"Romanian":"ro",
|
||||
"Swedish":"sv",
|
||||
"Slovenian":"sl",
|
||||
"Persian/Farsi":"fa",
|
||||
"Bosnian":"bs",
|
||||
"Serbian":"sr",
|
||||
"Fijian":"fj",
|
||||
"Filipino":"tl",
|
||||
"Haitiancreole":"ht",
|
||||
"Catalan":"ca",
|
||||
"Croatian":"hr",
|
||||
"Latvian":"lv",
|
||||
"Lithuanian":"lt",
|
||||
"Urdu":"ur",
|
||||
"Ukrainian":"uk",
|
||||
"Welsh":"cy",
|
||||
"Tahiti":"ty",
|
||||
"Tongan":"to",
|
||||
"Swahili":"sw",
|
||||
"Samoan":"sm",
|
||||
"Slovak":"sk",
|
||||
"Afrikaans":"af",
|
||||
"Norwegian":"no",
|
||||
"Bengali":"bn",
|
||||
"Malagasy":"mg",
|
||||
"Maltese":"mt",
|
||||
"Queretaro otomi":"otq",
|
||||
"Klingon/tlhingan Hol":"tlh",
|
||||
"Gujarati":"gu",
|
||||
"Tamil":"ta",
|
||||
"Telugu":"te",
|
||||
"Punjabi":"pa",
|
||||
"Irish":"ga"
|
||||
}
|
||||
|
||||
selectable_languages = {
|
||||
"en": "English",
|
||||
"ja": "日本語",
|
||||
# 新しい言語とキーを追加する場合はここに追記してください
|
||||
}
|
||||
128
locales.yml
Normal file
128
locales.yml
Normal file
@@ -0,0 +1,128 @@
|
||||
en:
|
||||
# main window
|
||||
checkbox_translation: "Translation"
|
||||
checkbox_transcription_send: "Voice2chatbox"
|
||||
checkbox_transcription_receive: "Speaker2log"
|
||||
checkbox_foreground: "Foreground"
|
||||
|
||||
# main tabview
|
||||
main_tab_title_log: "Log"
|
||||
main_tab_title_send: "Send"
|
||||
main_tab_title_receive: "Receive"
|
||||
main_tab_title_system: "System"
|
||||
|
||||
|
||||
# configure window
|
||||
# config tabview
|
||||
config_tab_title_ui: "UI"
|
||||
config_tab_title_translation: "Translation"
|
||||
config_tab_title_transcription: "Transcription"
|
||||
config_tab_title_parameter: "Parameter"
|
||||
config_tab_title_others: "Others"
|
||||
# tab UI
|
||||
label_transparency: "Transparency"
|
||||
label_appearance_theme: "Appearance Theme"
|
||||
label_ui_scaling: "UI Scaling"
|
||||
label_font_family: "Font Family"
|
||||
label_ui_language: "UI Language"
|
||||
|
||||
# tab Translation
|
||||
label_translation_translator: "Select Translator"
|
||||
label_translation_input_language: "Send Language"
|
||||
label_translation_output_language: "Receive Language"
|
||||
|
||||
# tab Transcription
|
||||
label_input_mic_host: "Input Mic Host"
|
||||
label_input_mic_device: "Input Mic Device"
|
||||
label_input_mic_voice_language: "Input Mic Voice Language"
|
||||
label_input_mic_energy_threshold: "Input Mic Energy Threshold"
|
||||
checkbox_input_mic_threshold_check: "Check threshold point"
|
||||
label_input_mic_dynamic_energy_threshold: "Input Mic Dynamic Energy Threshold"
|
||||
label_input_mic_record_timeout: "Input Mic Record Timeout"
|
||||
label_input_mic_phrase_timeout: "Input Mic Phrase Timeout"
|
||||
label_input_mic_max_phrases: "Input Mic Max Phrases"
|
||||
label_input_mic_word_filter: "Input Mic Word Filter"
|
||||
|
||||
label_input_speaker_device: "Input Speaker Device"
|
||||
label_input_speaker_voice_language: "Input Speaker Voice Language"
|
||||
label_input_speaker_energy_threshold: "Input Speaker Energy Threshold"
|
||||
checkbox_input_speaker_threshold_check: "Check threshold point"
|
||||
label_input_speaker_dynamic_energy_threshold: "Input Speaker Dynamic Energy Threshold"
|
||||
label_input_speaker_record_timeout: "Input Speaker Record Timeout"
|
||||
label_input_speaker_phrase_timeout: "Input Speaker Phrase Timeout"
|
||||
label_input_speaker_max_phrases: "Input Speaker Max Phrases"
|
||||
|
||||
# tab Parameter
|
||||
label_ip_address: "OSC IP address"
|
||||
label_port: "OSC Port"
|
||||
label_authkey: "DeepL Auth Key"
|
||||
label_message_format: "Message Format"
|
||||
|
||||
# tab Others
|
||||
label_checkbox_auto_clear_chatbox: "Auto clear chat box"
|
||||
|
||||
|
||||
ja:
|
||||
# main window
|
||||
checkbox_translation: "翻訳"
|
||||
checkbox_transcription_send: "マイク->チャットボックス"
|
||||
checkbox_transcription_receive: "スピーカー->ログ"
|
||||
checkbox_foreground: "最前面表示"
|
||||
|
||||
# main tabview
|
||||
main_tab_title_log: "ログ"
|
||||
main_tab_title_send: "送信"
|
||||
main_tab_title_receive: "受信"
|
||||
main_tab_title_system: "システム"
|
||||
|
||||
|
||||
# configure window
|
||||
# config tabview
|
||||
config_tab_title_ui: "UI"
|
||||
config_tab_title_translation: "翻訳方法"
|
||||
config_tab_title_transcription: "音声認識"
|
||||
config_tab_title_parameter: "パラメーター"
|
||||
config_tab_title_others: "その他"
|
||||
|
||||
# tab UI
|
||||
label_transparency: "透過度"
|
||||
label_appearance_theme: "外観テーマを選択"
|
||||
label_ui_scaling: "UIの拡大縮小"
|
||||
label_font_family: "使用フォントの変更"
|
||||
label_ui_language: "UI 言語"
|
||||
|
||||
# tab Translation
|
||||
label_translation_translator: "翻訳エンジンの選択"
|
||||
label_translation_input_language: "送信言語-->翻訳言語"
|
||||
label_translation_output_language: "受信言語-->翻訳言語"
|
||||
|
||||
# tab Transcription
|
||||
label_input_mic_host: "マイク入力ホスト"
|
||||
label_input_mic_device: "マイク入力デバイス"
|
||||
label_input_mic_voice_language: "マイクで話す言語"
|
||||
label_input_mic_energy_threshold: "音声取得のしきい値"
|
||||
checkbox_input_mic_threshold_check: "音声取得のしきい値の視覚化"
|
||||
label_input_mic_dynamic_energy_threshold: "音声取得のしきい値の自動調整"
|
||||
label_input_mic_record_timeout: "マイク音声の区切りの無音時間"
|
||||
label_input_mic_phrase_timeout: "文字起こしする音声時間の上限"
|
||||
label_input_mic_max_phrases: "保留する単語の上限(マイク)"
|
||||
label_input_mic_word_filter: "ワードフィルタ"
|
||||
|
||||
label_input_speaker_device: "スピーカー(聞き取りたいデバイス)"
|
||||
label_input_speaker_voice_language: "聞き取る音声の言語"
|
||||
label_input_speaker_energy_threshold: "音声取得のしきい値"
|
||||
checkbox_input_speaker_threshold_check: "音声取得のしきい値の視覚化"
|
||||
label_input_speaker_dynamic_energy_threshold: "音声取得のしきい値の自動調整"
|
||||
label_input_speaker_record_timeout: "スピーカー音声の区切りの無音時間"
|
||||
label_input_speaker_phrase_timeout: "文字起こしする音声時間の上限"
|
||||
label_input_speaker_max_phrases: "保留する単語の上限(スピーカー)"
|
||||
|
||||
# tab Parameter
|
||||
# label_ip_address: ""
|
||||
# label_port: ""
|
||||
# label_authkey: ""
|
||||
label_message_format: "送信するメッセージのフォーマット"
|
||||
|
||||
# tab Others
|
||||
label_checkbox_auto_clear_chatbox: "送信後はチャットボックスを空にする"
|
||||
|
||||
@@ -3,3 +3,5 @@ PyAudioWPatch
|
||||
python-osc
|
||||
customtkinter
|
||||
deepl
|
||||
flashtext
|
||||
pyyaml
|
||||
@@ -1,13 +1,13 @@
|
||||
import deepl
|
||||
import deepl_translate
|
||||
import translators as ts
|
||||
import languages
|
||||
from deepl import Translator as deepl_Translator
|
||||
from deepl_translate import translate as deepl_web_Translator
|
||||
from translators import translate_text as other_web_Translator
|
||||
from languages import translators, translation_lang
|
||||
|
||||
# Translator
|
||||
class Translator():
|
||||
def __init__(self):
|
||||
self.translator_status = {}
|
||||
for translator in languages.translators:
|
||||
for translator in translators:
|
||||
self.translator_status[translator] = False
|
||||
self.deepl_client = None
|
||||
|
||||
@@ -18,7 +18,7 @@ class Translator():
|
||||
self.translator_status["DeepL(web)"] = True
|
||||
result = True
|
||||
elif translator_name == "DeepL(auth)":
|
||||
self.deepl_client = deepl.Translator(authkey)
|
||||
self.deepl_client = deepl_Translator(authkey)
|
||||
self.deepl_client.translate_text(" ", target_lang="EN-US")
|
||||
self.translator_status["DeepL(auth)"] = True
|
||||
result = True
|
||||
@@ -35,10 +35,10 @@ class Translator():
|
||||
def translate(self, translator_name, source_language, target_language, message):
|
||||
result = ""
|
||||
try:
|
||||
source_language=languages.translation_lang[translator_name][source_language]
|
||||
target_language=languages.translation_lang[translator_name][target_language]
|
||||
source_language=translation_lang[translator_name][source_language]
|
||||
target_language=translation_lang[translator_name][target_language]
|
||||
if translator_name == "DeepL(web)":
|
||||
result = deepl_translate.translate(
|
||||
result = deepl_web_Translator(
|
||||
source_language=source_language,
|
||||
target_language=target_language,
|
||||
text=message
|
||||
@@ -50,14 +50,14 @@ class Translator():
|
||||
target_lang=target_language,
|
||||
).text
|
||||
elif translator_name == "Google(web)":
|
||||
result = ts.translate_text(
|
||||
result = other_web_Translator(
|
||||
query_text=message,
|
||||
translator="google",
|
||||
from_language=source_language,
|
||||
to_language=target_language,
|
||||
)
|
||||
elif translator_name == "Bing(web)":
|
||||
result = ts.translate_text(
|
||||
result = other_web_Translator(
|
||||
query_text=message,
|
||||
translator="bing",
|
||||
from_language=source_language,
|
||||
|
||||
105
utils.py
105
utils.py
@@ -1,16 +1,18 @@
|
||||
import json
|
||||
import datetime
|
||||
import threading
|
||||
from json import load, dump
|
||||
from os import path as os_path
|
||||
import yaml
|
||||
from datetime import datetime
|
||||
from threading import Thread, Event
|
||||
|
||||
def save_json(path, key, value):
|
||||
with open(path, "r") as fp:
|
||||
json_data = json.load(fp)
|
||||
json_data = load(fp)
|
||||
json_data[key] = value
|
||||
with open(path, "w") as fp:
|
||||
json.dump(json_data, fp, indent=4)
|
||||
dump(json_data, fp, indent=4)
|
||||
|
||||
def print_textbox(textbox, message, tags=None):
|
||||
now = datetime.datetime.now()
|
||||
now = datetime.now()
|
||||
now = now.strftime('%H:%M:%S')
|
||||
|
||||
textbox.tag_config("ERROR", foreground="#FF0000")
|
||||
@@ -25,11 +27,11 @@ def print_textbox(textbox, message, tags=None):
|
||||
textbox.configure(state='disabled')
|
||||
textbox.see("end")
|
||||
|
||||
class thread_fnc(threading.Thread):
|
||||
class thread_fnc(Thread):
|
||||
def __init__(self, fnc, daemon=True, *args, **kwargs):
|
||||
super(thread_fnc, self).__init__(daemon=daemon, *args, **kwargs)
|
||||
self.fnc = fnc
|
||||
self._stop = threading.Event()
|
||||
self._stop = Event()
|
||||
def stop(self):
|
||||
self._stop.set()
|
||||
def stopped(self):
|
||||
@@ -39,3 +41,90 @@ class thread_fnc(threading.Thread):
|
||||
if self.stopped():
|
||||
return
|
||||
self.fnc(*self._args, **self._kwargs)
|
||||
|
||||
def get_localized_text(language):
|
||||
file_path = os_path.join(os_path.dirname(__file__), "locales.yml")
|
||||
|
||||
with open(file_path, encoding="utf-8") as file:
|
||||
languages_yaml_data = yaml.safe_load(file)
|
||||
default_language = "en"
|
||||
if language in languages_yaml_data:
|
||||
localized_text = languages_yaml_data[language]
|
||||
if default_language in languages_yaml_data:
|
||||
default_text = languages_yaml_data[default_language]
|
||||
merged_text = {**default_text, **localized_text}
|
||||
return merged_text
|
||||
else:
|
||||
return localized_text
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_key_by_value(dictionary, value):
|
||||
for key, val in dictionary.items():
|
||||
if val == value:
|
||||
return key
|
||||
return None
|
||||
|
||||
def widget_config_window_label_setter(self, language_yaml_data):
|
||||
widget_names = [
|
||||
# tab UI
|
||||
"label_transparency",
|
||||
"label_appearance_theme",
|
||||
"label_ui_scaling",
|
||||
"label_font_family",
|
||||
"label_ui_language",
|
||||
|
||||
# tab Translation
|
||||
"label_translation_translator",
|
||||
"label_translation_input_language",
|
||||
"label_translation_output_language",
|
||||
|
||||
# tab Transcription
|
||||
"label_input_mic_host",
|
||||
"label_input_mic_device",
|
||||
"label_input_mic_voice_language",
|
||||
"label_input_mic_energy_threshold",
|
||||
"checkbox_input_mic_threshold_check",
|
||||
"label_input_mic_dynamic_energy_threshold",
|
||||
"label_input_mic_record_timeout",
|
||||
"label_input_mic_phrase_timeout",
|
||||
"label_input_mic_max_phrases",
|
||||
"label_input_mic_word_filter",
|
||||
|
||||
"label_input_speaker_device",
|
||||
"label_input_speaker_voice_language",
|
||||
"label_input_speaker_energy_threshold",
|
||||
"checkbox_input_speaker_threshold_check",
|
||||
"label_input_speaker_dynamic_energy_threshold",
|
||||
"label_input_speaker_record_timeout",
|
||||
"label_input_speaker_phrase_timeout",
|
||||
"label_input_speaker_max_phrases",
|
||||
|
||||
|
||||
# tab Parameter
|
||||
"label_ip_address",
|
||||
"label_port",
|
||||
"label_authkey",
|
||||
"label_message_format",
|
||||
|
||||
# tab Others
|
||||
"label_checkbox_auto_clear_chatbox"
|
||||
]
|
||||
for name in widget_names:
|
||||
widget = getattr(self, name)
|
||||
text_value = language_yaml_data.get(name)
|
||||
if widget is not None and text_value is not None:
|
||||
widget.configure(text=text_value + ":")
|
||||
|
||||
def widget_main_window_label_setter(self, language_yaml_data):
|
||||
widget_names = [
|
||||
"checkbox_translation",
|
||||
"checkbox_transcription_send",
|
||||
"checkbox_transcription_receive",
|
||||
"checkbox_foreground",
|
||||
]
|
||||
for name in widget_names:
|
||||
widget = getattr(self, name)
|
||||
text_value = language_yaml_data.get(name)
|
||||
if widget is not None and text_value is not None:
|
||||
widget.configure(text=text_value)
|
||||
1639
window_config.py
1639
window_config.py
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
import customtkinter
|
||||
from customtkinter import CTkToplevel, CTkTextbox, CTkFont
|
||||
|
||||
class ToplevelWindowInformation(customtkinter.CTkToplevel):
|
||||
class ToplevelWindowInformation(CTkToplevel):
|
||||
def __init__(self, parent, *args, **kwargs):
|
||||
super().__init__(parent, *args, **kwargs)
|
||||
self.parent = parent
|
||||
@@ -13,12 +13,12 @@ class ToplevelWindowInformation(customtkinter.CTkToplevel):
|
||||
self.after(200, lambda: self.iconbitmap(os.path.join(os.path.dirname(__file__), "img", "app.ico")))
|
||||
self.title("Information")
|
||||
# create textbox information
|
||||
self.textbox_information = customtkinter.CTkTextbox(
|
||||
self.textbox_information = CTkTextbox(
|
||||
self,
|
||||
font=customtkinter.CTkFont(family=self.parent.FONT_FAMILY)
|
||||
font=CTkFont(family=self.parent.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_information.grid(row=0, column=0, padx=(10, 10), pady=(10, 10), sticky="nsew")
|
||||
textbox_information_message = """VRCT(v1.2)
|
||||
textbox_information_message = """VRCT(v1.3)
|
||||
|
||||
# 概要
|
||||
VRChatで使用されるChatBoxをOSC経由でメッセージを送信するツールになります。
|
||||
@@ -32,7 +32,7 @@ VRChatで使用されるChatBoxをOSC経由でメッセージを送信するツ
|
||||
(任意)
|
||||
1. DeepLのAPIを使用するためにアカウント登録し、認証キーを取得する
|
||||
2. ギアアイコンのボタンでconfigウィンドウを開く
|
||||
3. ParameterタブのDeepL Auth Keyに認証キーを記載し、フロッピーアイコンのボタンを押す
|
||||
3. ParameterタブのDeepL Auth Keyに認証キーを記載
|
||||
4. configウィンドウを閉じる
|
||||
|
||||
通常使用時
|
||||
@@ -61,22 +61,29 @@ VRChatで使用されるChatBoxをOSC経由でメッセージを送信するツ
|
||||
Appearance Theme: ウィンドウテーマを選択
|
||||
UI Scaling: UIサイズを調整
|
||||
Font Family: 表示フォントを選択
|
||||
(New!) UI Language: UIの表示言語を選択
|
||||
Translationタブ
|
||||
Select Translator: 翻訳エンジンの変更
|
||||
Send Language: 送信するメッセージに対して翻訳する言語[source, target]を選択
|
||||
Receive Language: 受信したメッセージに対して翻訳する言語[source, target]を選択
|
||||
Transcriptionタブ
|
||||
(New!) Input Mic Host: マイクのホストAPIを選択
|
||||
Input Mic Device: マイクを選択
|
||||
Input Mic Voice Language: 入力する音声の言語
|
||||
Input Mic Energy Threshold: 音声取得のしきい値
|
||||
(New!) Check threshold point: Input Mic Energy Thresholdのしきい値を視覚化
|
||||
Input Mic Dynamic Energy Threshold: 音声取得のしきい値の自動調整
|
||||
Input Mic Record Timeout: 音声の区切りの無音時間
|
||||
Input Mic Phase Timeout: 文字起こしする音声時間の上限
|
||||
Input Mic Max Phrases: 保留する単語の上限
|
||||
(New!) Input Mic Word Filter: MICの文字起こし時にWord Filterで設定した文字が入っていた場合にChatboxに表示しない (ex AAA,BBB,CCC)
|
||||
Input Speaker Device: スピーカーを選択
|
||||
Input Speaker Voice Language: 受信する音声の言語
|
||||
Input Speaker Energy Threshold: 音声取得のしきい値
|
||||
(New!) Check threshold point: (New!)Input Speaker Energy Thresholdのしきい値を視覚化
|
||||
Input Speaker Dynamic Energy Threshold: 音声取得のしきい値の自動調整
|
||||
Input Speaker Record Timeout: 音声の区切りの無音時間
|
||||
Input Speaker Phase Timeout: 文字起こしする音声時間の上限
|
||||
Input Speaker Max Phrases: 保留する単語の上限
|
||||
Parameterタブ
|
||||
OSC IP address: 変更不要
|
||||
@@ -86,6 +93,8 @@ VRChatで使用されるChatBoxをOSC経由でメッセージを送信するツ
|
||||
[message]がメッセージボックスに記入したメッセージに置換される
|
||||
[translation]が翻訳されたメッセージに置換される
|
||||
初期フォーマット:"[message]([translation])"
|
||||
Othersタブ
|
||||
(New!) Auto clear chat box: メッセージ送信後に書き込んだメッセージを空にする
|
||||
|
||||
設定の初期化
|
||||
config.jsonを削除
|
||||
@@ -118,6 +127,17 @@ https://twitter.com/misya_ai
|
||||
- いくつかのバクを修正
|
||||
- 翻訳/文字起こし言語の表記を略称からわかりやすい文字に変更
|
||||
- 文字起こしの処理の軽量化
|
||||
[2023-07-05: v1.2]
|
||||
- 文字起こし精度の向上
|
||||
[2023-07-21: v1.3]
|
||||
- UIの表示言語を日本語/英語を選択できる機能を追加
|
||||
- Energy Thresholdの視覚化機能を追加
|
||||
- 文字起こしの誤認識対策のため、Word Filterを追加
|
||||
- WASAPI以外のHostAPIでもマイクとして使用できるようにHostAPIを選択できる機能を追加
|
||||
- メッセージ送信後に書き込んだメッセージを空にするか選択できる機能を追加
|
||||
- バグ対策のため、translation/voice2chatbox/speaker2log/foregroundは起動時はOFFになるように変更
|
||||
- バグ対策のため、スピーカーについて既定デバイス以外を選択した時にERRORが出るように変更
|
||||
- 半角入力時に一部の文字が書き込めないバグを修正
|
||||
|
||||
# 注意事項
|
||||
再配布とかはやめてね
|
||||
|
||||
Reference in New Issue
Block a user