|
1 | 1 | from base64 import b64encode
|
2 | 2 | import tempfile
|
| 3 | +from os import getenv |
3 | 4 |
|
4 | 5 | import streamlit as st
|
5 | 6 | from audio_recorder_streamlit import audio_recorder
|
6 | 7 | from gtts import gTTS
|
7 | 8 | from langchain_community.callbacks.streamlit import (
|
8 | 9 | StreamlitCallbackHandler,
|
9 | 10 | )
|
| 11 | +from langchain_community.document_loaders.parsers.audio import AzureOpenAIWhisperParser |
| 12 | +from langchain_core.documents.base import Blob |
10 | 13 |
|
11 | 14 | from template_langgraph.agents.chat_with_tools_agent.agent import (
|
12 | 15 | AgentState,
|
@@ -38,6 +41,33 @@ def image_to_base64(image_bytes: bytes) -> str:
|
38 | 41 | )
|
39 | 42 | st.session_state["input_output_mode"] = input_output_mode
|
40 | 43 |
|
| 44 | + # 音声モードの場合、Azure OpenAI設定を表示 |
| 45 | + if input_output_mode == "音声": |
| 46 | + st.subheader("音声認識設定 (オプション)") |
| 47 | + with st.expander("Azure OpenAI Whisper設定", expanded=False): |
| 48 | + azure_openai_endpoint = st.text_input( |
| 49 | + "AZURE_OPENAI_ENDPOINT", |
| 50 | + value=getenv("AZURE_OPENAI_ENDPOINT", ""), |
| 51 | + help="Azure OpenAI リソースのエンドポイント" |
| 52 | + ) |
| 53 | + azure_openai_api_key = st.text_input( |
| 54 | + "AZURE_OPENAI_API_KEY", |
| 55 | + value=getenv("AZURE_OPENAI_API_KEY", ""), |
| 56 | + type="password", |
| 57 | + help="Azure OpenAI リソースのAPIキー" |
| 58 | + ) |
| 59 | + azure_openai_api_version = st.text_input( |
| 60 | + "AZURE_OPENAI_API_VERSION", |
| 61 | + value=getenv("AZURE_OPENAI_API_VERSION", "2024-02-01"), |
| 62 | + help="Azure OpenAI APIバージョン" |
| 63 | + ) |
| 64 | + azure_openai_model_stt = st.text_input( |
| 65 | + "AZURE_OPENAI_MODEL_STT", |
| 66 | + value=getenv("AZURE_OPENAI_MODEL_STT", "whisper"), |
| 67 | + help="音声認識用のデプロイ名" |
| 68 | + ) |
| 69 | + st.caption("※設定しない場合は、音声入力時にプレースホルダーテキストが使用されます") |
| 70 | + |
41 | 71 | st.divider()
|
42 | 72 | st.subheader("使用するツール")
|
43 | 73 |
|
@@ -99,19 +129,51 @@ def image_to_base64(image_bytes: bytes) -> str:
|
99 | 129 |
|
100 | 130 | if audio_bytes:
|
101 | 131 | st.audio(audio_bytes, format="audio/wav")
|
| 132 | + |
102 | 133 | # 音声データを一時ファイルに保存
|
103 | 134 | with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_audio_file:
|
104 | 135 | temp_audio_file.write(audio_bytes)
|
105 | 136 | temp_audio_file_path = temp_audio_file.name
|
106 | 137 |
|
107 |
| - # TODO: 音声からテキストへの変換実装 |
108 |
| - # 現在は音声入力をプレースホルダーテキストに変換 |
109 |
| - prompt_text = "音声入力を受信しました(音声認識は後で実装予定)" |
110 |
| - prompt = prompt_text |
111 |
| - |
112 |
| - # 一時ファイルを削除 |
113 |
| - import os |
114 |
| - os.unlink(temp_audio_file_path) |
| 138 | + # Azure OpenAI Whisperが設定されている場合は音声認識を実施 |
| 139 | + try: |
| 140 | + if (input_output_mode == "音声" and |
| 141 | + azure_openai_endpoint and azure_openai_api_key and |
| 142 | + azure_openai_model_stt): |
| 143 | + |
| 144 | + with st.spinner("音声を認識中..."): |
| 145 | + audio_blob = Blob(path=temp_audio_file_path) |
| 146 | + parser = AzureOpenAIWhisperParser( |
| 147 | + api_key=azure_openai_api_key, |
| 148 | + azure_endpoint=azure_openai_endpoint, |
| 149 | + api_version=azure_openai_api_version, |
| 150 | + deployment_name=azure_openai_model_stt, |
| 151 | + ) |
| 152 | + documents = parser.lazy_parse(blob=audio_blob) |
| 153 | + results = [doc.page_content for doc in documents] |
| 154 | + prompt_text = "\n".join(results).strip() |
| 155 | + |
| 156 | + if prompt_text: |
| 157 | + st.success(f"音声認識完了: {prompt_text}") |
| 158 | + prompt = prompt_text |
| 159 | + else: |
| 160 | + st.warning("音声が認識できませんでした") |
| 161 | + prompt = None |
| 162 | + else: |
| 163 | + # Azure OpenAI設定がない場合はプレースホルダー |
| 164 | + prompt_text = "音声入力を受信しました(音声認識設定が必要です)" |
| 165 | + prompt = prompt_text |
| 166 | + st.info("音声認識を使用するには、サイドバーでAzure OpenAI設定を入力してください") |
| 167 | + |
| 168 | + except Exception as e: |
| 169 | + st.error(f"音声認識でエラーが発生しました: {e}") |
| 170 | + prompt_text = "音声入力でエラーが発生しました" |
| 171 | + prompt = prompt_text |
| 172 | + finally: |
| 173 | + # 一時ファイルを削除 |
| 174 | + import os |
| 175 | + if os.path.exists(temp_audio_file_path): |
| 176 | + os.unlink(temp_audio_file_path) |
115 | 177 |
|
116 | 178 | else:
|
117 | 179 | # 既存のテキスト入力モード
|
|
0 commit comments