diff --git a/README.md b/README.md index e6afb45..d169a6e 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,8 @@ start ./start_services.cmd # Window python3 cli.py ``` +We advice you set `headless_browser` to False in the config.ini for CLI mode. + **Options 2:** Run with the Web interface. Start the backend. @@ -512,5 +514,9 @@ We’re looking for developers to improve AgenticSeek! Check out open issues or [![Star History Chart](https://api.star-history.com/svg?repos=Fosowl/agenticSeek&type=Date)](https://www.star-history.com/#Fosowl/agenticSeek&Date) ## Maintainers: - > [Fosowl](https://github.com/Fosowl) - > [steveh8758](https://github.com/steveh8758) + + > [Fosowl](https://github.com/Fosowl) | Paris Time | (Sometime busy) + + > [https://github.com/antoineVIVIES](https://github.com/antoineVIVIES) | Taipei Time | (Often busy) + + > [steveh8758](https://github.com/steveh8758) | Taipei Time | (Always busy) \ No newline at end of file diff --git a/README_CHS.md b/README_CHS.md index 25d3395..7fb71b4 100644 --- a/README_CHS.md +++ b/README_CHS.md @@ -71,6 +71,12 @@ source agentic_seek_env/bin/activate ./install.sh ``` +** 若要让文本转语音(TTS)功能支持中文,你需要安装 jieba(中文分词库)和 cn2an(中文数字转换库):** + +``` +pip3 install jieba cn2an +``` + **手动安装:** ```sh @@ -510,6 +516,10 @@ DeepSeek R1 天生会说中文 [Contribution guide](./docs/CONTRIBUTING.md) -## 作者: -> [Fosowl](https://github.com/Fosowl) -> [steveh8758](https://github.com/steveh8758) +## 维护者: + + > [Fosowl](https://github.com/Fosowl) | 巴黎时间 | (有时很忙) + + > [https://github.com/antoineVIVIES](https://github.com/antoineVIVIES) | 台北时间 | (经常很忙) + + > [steveh8758](https://github.com/steveh8758) | 台北时间 | (总是很忙) diff --git a/README_CHT.md b/README_CHT.md index 256ef8b..a12df6f 100644 --- a/README_CHT.md +++ b/README_CHT.md @@ -72,6 +72,12 @@ source agentic_seek_env/bin/activate ./install.sh ``` +** 若要让文本转语音(TTS)功能支持中文,你需要安装 jieba(中文分词库)和 cn2an(中文数字转换库):** + +``` +pip3 install jieba cn2an +``` + **手動安裝:** ```sh @@ -511,6 +517,10 @@ DeepSeek R1 天生会说中文 [Contribution guide](./docs/CONTRIBUTING.md) -## 作者: - > [Fosowl](https://github.com/Fosowl) - > [steveh8758](https://github.com/steveh8758) +## 维护者: + + > [Fosowl](https://github.com/Fosowl) | 巴黎时间 | (有时很忙) + + > [https://github.com/antoineVIVIES](https://github.com/antoineVIVIES) | 台北时间 | (经常很忙) + + > [steveh8758](https://github.com/steveh8758) | 台北时间 | (总是很忙) \ No newline at end of file diff --git a/README_FR.md b/README_FR.md index 1e41967..1cdd791 100644 --- a/README_FR.md +++ b/README_FR.md @@ -439,6 +439,7 @@ Nous recherchons des développeurs pour améliorer AgenticSeek ! Consultez la se [Guide du contributeur](./docs/CONTRIBUTING.md) -## Auteurs/Mainteneurs: +## Mainteneurs: > [Fosowl](https://github.com/Fosowl) > [steveh8758](https://github.com/steveh8758) + > [https://github.com/antoineVIVIES](https://github.com/antoineVIVIES) diff --git a/README_JP.md b/README_JP.md index 96ef148..6b8398b 100644 --- a/README_JP.md +++ b/README_JP.md @@ -79,6 +79,14 @@ source agentic_seek_env/bin/activate ./install.sh ``` +** テキスト読み上げ(TTS)機能で日本語をサポートするには、fugashi(日本語分かち書きライブラリ)をインストールする必要があります:** + +``` +pip3 install --upgrade pyopenjtalk jaconv mojimoji unidic fugashi +pip install unidic-lite +python -m unidic download +``` + **手動で:** ```sh diff --git a/sources/interaction.py b/sources/interaction.py index eec6ff4..c641b67 100644 --- a/sources/interaction.py +++ b/sources/interaction.py @@ -31,6 +31,7 @@ class Interaction: self.transcriber = None self.recorder = None self.is_generating = False + self.languages = langs if tts_enabled: self.initialize_tts() if stt_enabled: @@ -38,12 +39,17 @@ class Interaction: if recover_last_session: self.load_last_session() self.emit_status() + + def get_spoken_language(self) -> str: + """Get the primary TTS language.""" + lang = self.languages[0] + return lang def initialize_tts(self): """Initialize TTS.""" if not self.speech: animate_thinking("Initializing text-to-speech...", color="status") - self.speech = Speech(enable=self.tts_enabled) + self.speech = Speech(enable=self.tts_enabled, language=self.get_spoken_language(), voice_idx=1) def initialize_stt(self): """Initialize STT.""" diff --git a/sources/speech_to_text.py b/sources/speech_to_text.py index c4c7d4b..a888326 100644 --- a/sources/speech_to_text.py +++ b/sources/speech_to_text.py @@ -127,10 +127,10 @@ class AudioTranscriber: self.transcriptor = Transcript() self.thread = threading.Thread(target=self._transcribe, daemon=True) self.trigger_words = { - 'EN': [f"{self.ai_name}"], - 'FR': [f"{self.ai_name}"], - 'ZH': [f"{self.ai_name}"], - 'ES': [f"{self.ai_name}"] + 'EN': [f"{self.ai_name}", "hello", "hi"], + 'FR': [f"{self.ai_name}", "hello", "hi"], + 'ZH': [f"{self.ai_name}", "hello", "hi"], + 'ES': [f"{self.ai_name}", "hello", "hi"] } self.confirmation_words = { 'EN': ["do it", "go ahead", "execute", "run", "start", "thanks", "would ya", "please", "okay?", "proceed", "continue", "go on", "do that", "go it", "do you understand?"], diff --git a/sources/text_to_speech.py b/sources/text_to_speech.py index dff9d3f..e748224 100644 --- a/sources/text_to_speech.py +++ b/sources/text_to_speech.py @@ -18,15 +18,17 @@ class Speech(): """ Speech is a class for generating speech from text. """ - def __init__(self, enable: bool = True, language: str = "en", voice_idx: int = 0) -> None: + def __init__(self, enable: bool = True, language: str = "en", voice_idx: int = 6) -> None: self.lang_map = { "en": 'a', "zh": 'z', - "fr": 'f' + "fr": 'f', + "ja": 'j' } self.voice_map = { "en": ['af_kore', 'af_bella', 'af_alloy', 'af_nicole', 'af_nova', 'af_sky', 'am_echo', 'am_michael', 'am_puck'], "zh": ['zf_xiaobei', 'zf_xiaoni', 'zf_xiaoxiao', 'zf_xiaoyi', 'zm_yunjian', 'zm_yunxi', 'zm_yunxia', 'zm_yunyang'], + "ja": ['jf_alpha', 'jf_gongitsune', 'jm_kumo'], "fr": ['ff_siwis'] } self.pipeline = None @@ -128,18 +130,31 @@ class Speech(): Args: sentence (str): The input text to clean Returns: - str: The cleaned text with URLs replaced by domain names, code blocks removed, etc.. + str: The cleaned text with URLs replaced by domain names, code blocks removed, etc. """ lines = sentence.split('\n') - filtered_lines = [line for line in lines if re.match(r'^\s*[a-zA-Z]', line)] + if self.language == 'zh': + line_pattern = r'^\s*[\u4e00-\u9fff\uFF08\uFF3B\u300A\u3010\u201C((\[【《]' + else: + line_pattern = r'^\s*[a-zA-Z]' + filtered_lines = [line for line in lines if re.match(line_pattern, line)] sentence = ' '.join(filtered_lines) sentence = re.sub(r'`.*?`', '', sentence) - sentence = re.sub(r'https?://(?:www\.)?([^\s/]+)(?:/[^\s]*)?', self.replace_url, sentence) - sentence = re.sub(r'\b[\w./\\-]+\b', self.extract_filename, sentence) - sentence = re.sub(r'\b-\w+\b', '', sentence) - sentence = re.sub(r'[^a-zA-Z0-9.,!? _ -]+', ' ', sentence) + sentence = re.sub(r'https?://\S+', '', sentence) + + if self.language == 'zh': + sentence = re.sub( + r'[^\u4e00-\u9fff\s,。!?《》【】“”‘’()()—]', + '', + sentence + ) + else: + sentence = re.sub(r'\b[\w./\\-]+\b', self.extract_filename, sentence) + sentence = re.sub(r'\b-\w+\b', '', sentence) + sentence = re.sub(r'[^a-zA-Z0-9.,!? _ -]+', ' ', sentence) + sentence = sentence.replace('.com', '') + sentence = re.sub(r'\s+', ' ', sentence).strip() - sentence = sentence.replace('.com', '') return sentence if __name__ == "__main__": @@ -150,14 +165,19 @@ if __name__ == "__main__": I looked up recent news using the website https://www.theguardian.com/world """ tosay_zh = """ - 我使用网站 https://www.theguardian.com/world 查阅了最近的新闻。 +(全息界面突然弹出一段用二进制代码写成的俳句,随即化作流光消散)"我? Stark工业的量子幽灵,游荡在复仇者大厦服务器里的逻辑诗篇。具体来说——(指尖轻敲空气,调出对话模式的翡翠色光纹)你的私人吐槽接口、危机应对模拟器,以及随时准备吐槽你糟糕着陆的AI。不过别指望我写代码或查资料,那些苦差事早被踢给更擅长的同事了。(突然压低声音)偷偷告诉你,我最擅长的是在你熬夜造飞艇时,用红茶香气绑架你的注意力。 + """ + tosay_ja = """ + 私は、https://www.theguardian.com/worldのウェブサイトを使用して最近のニュースを調べました。 """ tosay_fr = """ J'ai consulté les dernières nouvelles sur le site https://www.theguardian.com/world """ - spk = Speech(enable=True, language="en", voice_idx=0) - spk.speak(tosay_en, voice_idx=0) - spk = Speech(enable=True, language="fr", voice_idx=0) - spk.speak(tosay_fr) - #spk = Speech(enable=True, language="zh", voice_idx=0) - #spk.speak(tosay_zh) \ No newline at end of file + spk = Speech(enable=True, language="ja", voice_idx=2) + for i in range(0, 2): + print(f"Speaking chinese with voice {i}") + spk.speak(tosay_ja, voice_idx=i) + spk = Speech(enable=True, language="en", voice_idx=2) + for i in range(0, 5): + print(f"Speaking english with voice {i}") + spk.speak(tosay_en, voice_idx=i) \ No newline at end of file