Spaces:
Running
Running
Commit
·
feb8411
1
Parent(s):
9473dce
新增 api
Browse files- .env.example +2 -0
- README.md +85 -5
- api.py +283 -0
- app.py +7 -0
- requirements.txt +4 -1
.env.example
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
# OpenAI API Key for TTS
|
2 |
+
OPENAI_API_KEY=your_openai_api_key_here
|
README.md
CHANGED
@@ -21,6 +21,9 @@ short_description: 原tbdavid2019/PDF2podcast拆出的語音生成(2)
|
|
21 |
- 🎚️ **模型選擇**:支援標準(tts-1)和高清(tts-1-hd)音頻模型
|
22 |
- 🌐 **友好界面**:基於Gradio的簡潔網頁界面,易於使用
|
23 |
- 💾 **自動文件管理**:自動保存生成的音頻並清理過期文件
|
|
|
|
|
|
|
24 |
|
25 |
## 安裝說明
|
26 |
|
@@ -28,6 +31,7 @@ short_description: 原tbdavid2019/PDF2podcast拆出的語音生成(2)
|
|
28 |
|
29 |
- Python 3.7+
|
30 |
- OpenAI API金鑰(需要啟用TTS功能)
|
|
|
31 |
|
32 |
### 安裝步驟
|
33 |
|
@@ -40,7 +44,22 @@ pip install -r requirements.txt
|
|
40 |
|
41 |
## 使用方法
|
42 |
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
|
45 |
```bash
|
46 |
python app.py
|
@@ -48,10 +67,62 @@ python app.py
|
|
48 |
|
49 |
2. 在瀏覽器中打開顯示的URL(通常是 http://127.0.0.1:7860)
|
50 |
3. 在文本框中輸入您的腳本
|
51 |
-
4. 輸入您的OpenAI API
|
52 |
5. 選擇所需的音頻模型和說話者聲音
|
53 |
-
6.
|
54 |
-
7.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
|
56 |
## 腳本格式
|
57 |
|
@@ -73,6 +144,7 @@ speaker-1: 繼續對話...
|
|
73 |
| 音頻模型 | 選擇TTS模型:標準(tts-1)或高清(tts-1-hd) |
|
74 |
| 說話者1聲音 | 第一位說話者使用的聲音 |
|
75 |
| 說話者2聲音 | 第二位說話者使用的聲音 |
|
|
|
76 |
| OpenAI API Key | 您的OpenAI API金鑰 |
|
77 |
|
78 |
## 聲音選項
|
@@ -89,14 +161,20 @@ speaker-1: 繼續對話...
|
|
89 |
## 技術細節
|
90 |
|
91 |
- 使用OpenAI的TTS API進行語音合成
|
92 |
-
- 使用Gradio
|
|
|
93 |
- 自動管理臨時音頻文件(24小時後自動清理)
|
94 |
- 支援流式處理大型音頻文件
|
|
|
95 |
|
96 |
## 依賴項
|
97 |
|
98 |
- gradio: 網頁界面
|
99 |
- openai: OpenAI API客戶端
|
|
|
|
|
|
|
|
|
100 |
- pathlib: 文件路徑處理
|
101 |
- io: 二進制數據處理
|
102 |
|
@@ -105,6 +183,8 @@ speaker-1: 繼續對話...
|
|
105 |
- 使用此應用程式需要有效的OpenAI API金鑰
|
106 |
- API使用會產生費用,請參考OpenAI的[價格頁面](https://openai.com/pricing)
|
107 |
- 生成的臨時音頻文件會在24小時後自動刪除
|
|
|
|
|
108 |
|
109 |
## 授權信息
|
110 |
|
|
|
21 |
- 🎚️ **模型選擇**:支援標準(tts-1)和高清(tts-1-hd)音頻模型
|
22 |
- 🌐 **友好界面**:基於Gradio的簡潔網頁界面,易於使用
|
23 |
- 💾 **自動文件管理**:自動保存生成的音頻並清理過期文件
|
24 |
+
- 🔊 **音量調整**:內建音量增益功能,可調整輸出音頻音量
|
25 |
+
- 🌍 **API支援**:提供獨立的API服務,支援外部應用程式呼叫
|
26 |
+
- 🔑 **環境變量**:支援通過.env文件配置API金鑰
|
27 |
|
28 |
## 安裝說明
|
29 |
|
|
|
31 |
|
32 |
- Python 3.7+
|
33 |
- OpenAI API金鑰(需要啟用TTS功能)
|
34 |
+
- 可選:創建`.env`文件存儲API金鑰(從`.env.example`複製並修改)
|
35 |
|
36 |
### 安裝步驟
|
37 |
|
|
|
44 |
|
45 |
## 使用方法
|
46 |
|
47 |
+
### 環境設置
|
48 |
+
|
49 |
+
```bash
|
50 |
+
# 複製環境變量範本
|
51 |
+
cp .env.example .env
|
52 |
+
|
53 |
+
# 編輯 .env 文件,添加您的 OpenAI API Key
|
54 |
+
nano .env # 或使用其他編輯器
|
55 |
+
|
56 |
+
# 安裝依賴項
|
57 |
+
pip install -r requirements.txt
|
58 |
+
```
|
59 |
+
|
60 |
+
### 通過網頁界面使用 (app.py)
|
61 |
+
|
62 |
+
1. 運行Gradio應用程式:
|
63 |
|
64 |
```bash
|
65 |
python app.py
|
|
|
67 |
|
68 |
2. 在瀏覽器中打開顯示的URL(通常是 http://127.0.0.1:7860)
|
69 |
3. 在文本框中輸入您的腳本
|
70 |
+
4. 輸入您的OpenAI API金鑰(或預先在`.env`文件中配置)
|
71 |
5. 選擇所需的音頻模型和說話者聲音
|
72 |
+
6. 調整音量增益(建議值:6-10 dB)
|
73 |
+
7. 點擊「生成音頻」按鈕
|
74 |
+
8. 等待處理完成後,您可以播放或下載生成的音頻
|
75 |
+
|
76 |
+
### 通過API使用 (api.py)
|
77 |
+
|
78 |
+
如果您需要從外部應用程式呼叫TTS功能,可以使用API:
|
79 |
+
|
80 |
+
1. 運行API服務:
|
81 |
+
|
82 |
+
```bash
|
83 |
+
python api.py
|
84 |
+
```
|
85 |
+
|
86 |
+
2. API服務將在 http://localhost:8000 啟動
|
87 |
+
|
88 |
+
#### API端點
|
89 |
+
|
90 |
+
##### 生成音頻
|
91 |
+
|
92 |
+
```
|
93 |
+
POST /generate-audio
|
94 |
+
```
|
95 |
+
|
96 |
+
請求體示例:
|
97 |
+
```json
|
98 |
+
{
|
99 |
+
"script": "speaker-1: 你好,歡迎來到播客!\nspeaker-2: 謝謝邀請,很高興來到這裡。",
|
100 |
+
"api_key": "your_openai_api_key",
|
101 |
+
"model": "tts-1",
|
102 |
+
"speaker1_voice": "onyx",
|
103 |
+
"speaker2_voice": "nova",
|
104 |
+
"volume_boost": 6.0,
|
105 |
+
"return_url": false
|
106 |
+
}
|
107 |
+
```
|
108 |
+
|
109 |
+
- 如果`return_url`為`false`,將直接返回音頻文件
|
110 |
+
- 如果`return_url`為`true`,將返回音頻文件的URL
|
111 |
+
|
112 |
+
##### 獲取可用選項
|
113 |
+
|
114 |
+
```
|
115 |
+
GET /options
|
116 |
+
```
|
117 |
+
|
118 |
+
返回可用的音頻模型和聲音選項。
|
119 |
+
|
120 |
+
##### API文檔
|
121 |
+
|
122 |
+
啟動API服務後,可以訪問自動生成的API文檔:
|
123 |
+
|
124 |
+
- Swagger UI: http://localhost:8000/docs
|
125 |
+
- ReDoc: http://localhost:8000/redoc
|
126 |
|
127 |
## 腳本格式
|
128 |
|
|
|
144 |
| 音頻模型 | 選擇TTS模型:標準(tts-1)或高清(tts-1-hd) |
|
145 |
| 說話者1聲音 | 第一位說話者使用的聲音 |
|
146 |
| 說話者2聲音 | 第二位說話者使用的聲音 |
|
147 |
+
| 音量增益 | 增加音頻音量的分貝值(dB),建議值:6-10 dB |
|
148 |
| OpenAI API Key | 您的OpenAI API金鑰 |
|
149 |
|
150 |
## 聲音選項
|
|
|
161 |
## 技術細節
|
162 |
|
163 |
- 使用OpenAI的TTS API進行語音合成
|
164 |
+
- 使用Gradio建立網頁界面(app.py)
|
165 |
+
- 使用FastAPI提供RESTful API(api.py)
|
166 |
- 自動管理臨時音頻文件(24小時後自動清理)
|
167 |
- 支援流式處理大型音頻文件
|
168 |
+
- 使用pydub處理音頻音量調整
|
169 |
|
170 |
## 依賴項
|
171 |
|
172 |
- gradio: 網頁界面
|
173 |
- openai: OpenAI API客戶端
|
174 |
+
- fastapi: API框架
|
175 |
+
- uvicorn: ASGI服務器
|
176 |
+
- pydub: 音頻處理
|
177 |
+
- python-dotenv: 環境變量管理
|
178 |
- pathlib: 文件路徑處理
|
179 |
- io: 二進制數據處理
|
180 |
|
|
|
183 |
- 使用此應用程式需要有效的OpenAI API金鑰
|
184 |
- API使用會產生費用,請參考OpenAI的[價格頁面](https://openai.com/pricing)
|
185 |
- 生成的臨時音頻文件會在24小時後自動刪除
|
186 |
+
- 在Hugging Face Space上運行時,app.py會自動啟動,提供Gradio界面
|
187 |
+
- 如需API功能,需要單獨運行api.py
|
188 |
|
189 |
## 授權信息
|
190 |
|
api.py
ADDED
@@ -0,0 +1,283 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import io
|
3 |
+
from pathlib import Path
|
4 |
+
from tempfile import NamedTemporaryFile
|
5 |
+
import time
|
6 |
+
from typing import Optional
|
7 |
+
import uvicorn
|
8 |
+
from fastapi import FastAPI, HTTPException, Body
|
9 |
+
from fastapi.middleware.cors import CORSMiddleware
|
10 |
+
from fastapi.responses import FileResponse, JSONResponse
|
11 |
+
from pydantic import BaseModel
|
12 |
+
from dotenv import load_dotenv
|
13 |
+
from openai import OpenAI
|
14 |
+
from pydub import AudioSegment
|
15 |
+
|
16 |
+
# 加載環境變量
|
17 |
+
load_dotenv()
|
18 |
+
|
19 |
+
# 獲取 OpenAI API Key
|
20 |
+
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
21 |
+
|
22 |
+
# 標準音頻模型和聲音選項
|
23 |
+
STANDARD_AUDIO_MODELS = [
|
24 |
+
"tts-1",
|
25 |
+
"tts-1-hd",
|
26 |
+
]
|
27 |
+
STANDARD_VOICES = [
|
28 |
+
"alloy",
|
29 |
+
"echo",
|
30 |
+
"fable",
|
31 |
+
"onyx",
|
32 |
+
"nova",
|
33 |
+
"shimmer",
|
34 |
+
]
|
35 |
+
|
36 |
+
# 創建 FastAPI 應用
|
37 |
+
app = FastAPI(
|
38 |
+
title="TTS API",
|
39 |
+
description="API for generating audio from text using OpenAI TTS",
|
40 |
+
version="1.0.0"
|
41 |
+
)
|
42 |
+
|
43 |
+
# 添加 CORS 中間件
|
44 |
+
app.add_middleware(
|
45 |
+
CORSMiddleware,
|
46 |
+
allow_origins=["*"], # 允許所有來源,可以根據需要限制
|
47 |
+
allow_credentials=True,
|
48 |
+
allow_methods=["*"], # 允許所有方法
|
49 |
+
allow_headers=["*"], # 允許所有頭部
|
50 |
+
)
|
51 |
+
|
52 |
+
# 優化腳本處理 - 合併相同說話者連續文本
|
53 |
+
def optimize_script(script):
|
54 |
+
lines = [line.strip() for line in script.splitlines() if line.strip()]
|
55 |
+
optimized = []
|
56 |
+
current_speaker = None
|
57 |
+
current_text = ""
|
58 |
+
|
59 |
+
for line in lines:
|
60 |
+
if line.lower().startswith("speaker-1:"):
|
61 |
+
speaker = "speaker-1"
|
62 |
+
text = line.split(":", 1)[1].strip()
|
63 |
+
elif line.lower().startswith("speaker-2:"):
|
64 |
+
speaker = "speaker-2"
|
65 |
+
text = line.split(":", 1)[1].strip()
|
66 |
+
else:
|
67 |
+
speaker = "speaker-1" # 默認使用說話者1
|
68 |
+
text = line
|
69 |
+
|
70 |
+
# 如果說話者變了,保存之前的文本並開始新的
|
71 |
+
if speaker != current_speaker and current_text:
|
72 |
+
optimized.append((current_speaker, current_text))
|
73 |
+
current_text = text
|
74 |
+
current_speaker = speaker
|
75 |
+
else:
|
76 |
+
# 相同說話者,合併文本(加空格)
|
77 |
+
if current_text:
|
78 |
+
current_text += " " + text
|
79 |
+
else:
|
80 |
+
current_text = text
|
81 |
+
current_speaker = speaker
|
82 |
+
|
83 |
+
# 添加最後一個說話者的文本
|
84 |
+
if current_text:
|
85 |
+
optimized.append((current_speaker, current_text))
|
86 |
+
|
87 |
+
return optimized
|
88 |
+
|
89 |
+
def get_mp3(text: str, voice: str, audio_model: str, api_key: str) -> bytes:
|
90 |
+
"""使用 OpenAI TTS API 生成音頻"""
|
91 |
+
client = OpenAI(api_key=api_key)
|
92 |
+
try:
|
93 |
+
with client.audio.speech.with_streaming_response.create(
|
94 |
+
model=audio_model,
|
95 |
+
voice=voice,
|
96 |
+
input=text,
|
97 |
+
) as response:
|
98 |
+
with io.BytesIO() as file:
|
99 |
+
for chunk in response.iter_bytes():
|
100 |
+
file.write(chunk)
|
101 |
+
return file.getvalue()
|
102 |
+
except Exception as e:
|
103 |
+
print(f"Error generating audio: {e}")
|
104 |
+
raise
|
105 |
+
|
106 |
+
def generate_audio_from_script(
|
107 |
+
script: str,
|
108 |
+
audio_api_key: str,
|
109 |
+
audio_model: str = "tts-1",
|
110 |
+
speaker1_voice: str = "onyx",
|
111 |
+
speaker2_voice: str = "nova",
|
112 |
+
volume_boost: float = 0,
|
113 |
+
) -> tuple[bytes, list]:
|
114 |
+
"""從腳本生成音頻,支持兩個說話者,並優化 API 調用"""
|
115 |
+
combined_audio = b""
|
116 |
+
status_log = []
|
117 |
+
|
118 |
+
# 優化腳本處理
|
119 |
+
optimized_script = optimize_script(script)
|
120 |
+
|
121 |
+
# 處理每一段
|
122 |
+
for speaker, text in optimized_script:
|
123 |
+
voice_to_use = speaker1_voice if speaker == "speaker-1" else speaker2_voice
|
124 |
+
status_log.append(f"[{speaker}] {text}")
|
125 |
+
|
126 |
+
try:
|
127 |
+
# 生成這一段的音頻
|
128 |
+
audio_chunk = get_mp3(
|
129 |
+
text,
|
130 |
+
voice_to_use,
|
131 |
+
audio_model,
|
132 |
+
audio_api_key
|
133 |
+
)
|
134 |
+
combined_audio += audio_chunk
|
135 |
+
except Exception as e:
|
136 |
+
status_log.append(f"[錯誤] 無法生成音頻: {str(e)}")
|
137 |
+
raise HTTPException(status_code=500, detail=f"無法生成音頻: {str(e)}")
|
138 |
+
|
139 |
+
# 如果需要調整音量
|
140 |
+
if volume_boost > 0:
|
141 |
+
try:
|
142 |
+
# 將二進制數據轉換為 AudioSegment
|
143 |
+
with NamedTemporaryFile(suffix=".mp3", delete=False) as temp_file:
|
144 |
+
temp_file.write(combined_audio)
|
145 |
+
temp_file_path = temp_file.name
|
146 |
+
|
147 |
+
# 讀取音頻並調整音量
|
148 |
+
audio = AudioSegment.from_mp3(temp_file_path)
|
149 |
+
audio = audio + volume_boost # 增加音量 (dB)
|
150 |
+
|
151 |
+
# 將調整後的音頻轉換回二進制數據
|
152 |
+
output = io.BytesIO()
|
153 |
+
audio.export(output, format="mp3")
|
154 |
+
combined_audio = output.getvalue()
|
155 |
+
|
156 |
+
# 刪除臨時文件
|
157 |
+
os.unlink(temp_file_path)
|
158 |
+
|
159 |
+
status_log.append(f"[音量] 已增加 {volume_boost} dB")
|
160 |
+
except Exception as e:
|
161 |
+
status_log.append(f"[警告] 音量調整失敗: {str(e)}")
|
162 |
+
|
163 |
+
return combined_audio, status_log
|
164 |
+
|
165 |
+
def save_audio_file(audio_data: bytes) -> str:
|
166 |
+
"""將音頻數據保存為臨時文件"""
|
167 |
+
temp_dir = Path("./temp_audio")
|
168 |
+
temp_dir.mkdir(exist_ok=True)
|
169 |
+
# 清理舊文件
|
170 |
+
for old_file in temp_dir.glob("*.mp3"):
|
171 |
+
if old_file.stat().st_mtime < (time.time() - 24*60*60): # 24小時前的文件
|
172 |
+
old_file.unlink()
|
173 |
+
# 創建新的臨時文件
|
174 |
+
temp_file = NamedTemporaryFile(
|
175 |
+
dir=temp_dir,
|
176 |
+
delete=False,
|
177 |
+
suffix=".mp3"
|
178 |
+
)
|
179 |
+
temp_file.write(audio_data)
|
180 |
+
temp_file.close()
|
181 |
+
return temp_file.name
|
182 |
+
|
183 |
+
# 定義請求模型
|
184 |
+
class TTSRequest(BaseModel):
|
185 |
+
script: str
|
186 |
+
api_key: Optional[str] = None
|
187 |
+
model: Optional[str] = "tts-1"
|
188 |
+
speaker1_voice: Optional[str] = "onyx"
|
189 |
+
speaker2_voice: Optional[str] = "nova"
|
190 |
+
volume_boost: Optional[float] = 6.0
|
191 |
+
return_url: Optional[bool] = False
|
192 |
+
|
193 |
+
# API 端點
|
194 |
+
@app.post("/generate-audio")
|
195 |
+
async def generate_audio(request: TTSRequest):
|
196 |
+
"""
|
197 |
+
生成音頻 API 端點
|
198 |
+
|
199 |
+
- **script**: 腳本內容,格式為 "speaker-1: 文本" 或 "speaker-2: 文本"
|
200 |
+
- **api_key**: OpenAI API Key (可選,如果未提供則使用環境變量)
|
201 |
+
- **model**: 音頻模型 (可選,默認為 "tts-1")
|
202 |
+
- **speaker1_voice**: 說話者1的聲音 (可選,默認為 "onyx")
|
203 |
+
- **speaker2_voice**: 說話者2的聲音 (可選,默認為 "nova")
|
204 |
+
- **volume_boost**: 音量增益 dB (可選,默認為 6.0)
|
205 |
+
- **return_url**: 是否返回音頻文件的 URL (可選,默認為 False)
|
206 |
+
"""
|
207 |
+
# 使用提供的 API Key 或環境變量中的 API Key
|
208 |
+
api_key = request.api_key or OPENAI_API_KEY
|
209 |
+
|
210 |
+
if not api_key:
|
211 |
+
raise HTTPException(status_code=400, detail="未提供 OpenAI API Key")
|
212 |
+
|
213 |
+
try:
|
214 |
+
# 生成音頻
|
215 |
+
audio_data, status_log = generate_audio_from_script(
|
216 |
+
request.script,
|
217 |
+
api_key,
|
218 |
+
request.model,
|
219 |
+
request.speaker1_voice,
|
220 |
+
request.speaker2_voice,
|
221 |
+
request.volume_boost
|
222 |
+
)
|
223 |
+
|
224 |
+
# 保存音頻文件
|
225 |
+
audio_path = save_audio_file(audio_data)
|
226 |
+
|
227 |
+
# 根據請求返回不同的響應
|
228 |
+
if request.return_url:
|
229 |
+
# 構建文件 URL (相對路徑)
|
230 |
+
file_name = os.path.basename(audio_path)
|
231 |
+
file_url = f"/audio/{file_name}"
|
232 |
+
|
233 |
+
return {
|
234 |
+
"status": "success",
|
235 |
+
"message": "音頻生成成功",
|
236 |
+
"audio_url": file_url,
|
237 |
+
"logs": status_log
|
238 |
+
}
|
239 |
+
else:
|
240 |
+
# 直接返回文件
|
241 |
+
return FileResponse(
|
242 |
+
audio_path,
|
243 |
+
media_type="audio/mpeg",
|
244 |
+
filename="generated_audio.mp3"
|
245 |
+
)
|
246 |
+
|
247 |
+
except Exception as e:
|
248 |
+
raise HTTPException(status_code=500, detail=f"生成音頻時發生錯誤: {str(e)}")
|
249 |
+
|
250 |
+
# 獲取音頻文件的端點
|
251 |
+
@app.get("/audio/{file_name}")
|
252 |
+
async def get_audio(file_name: str):
|
253 |
+
"""獲取生成的音頻文件"""
|
254 |
+
file_path = Path(f"./temp_audio/{file_name}")
|
255 |
+
|
256 |
+
if not file_path.exists():
|
257 |
+
raise HTTPException(status_code=404, detail="音頻文件不存在")
|
258 |
+
|
259 |
+
return FileResponse(
|
260 |
+
file_path,
|
261 |
+
media_type="audio/mpeg",
|
262 |
+
filename="generated_audio.mp3"
|
263 |
+
)
|
264 |
+
|
265 |
+
# 獲取可用的音頻模型和聲音選項
|
266 |
+
@app.get("/options")
|
267 |
+
async def get_options():
|
268 |
+
"""獲取可用的音頻模型和聲音選項"""
|
269 |
+
return {
|
270 |
+
"models": STANDARD_AUDIO_MODELS,
|
271 |
+
"voices": STANDARD_VOICES
|
272 |
+
}
|
273 |
+
|
274 |
+
# 健康檢查端點
|
275 |
+
@app.get("/health")
|
276 |
+
async def health_check():
|
277 |
+
"""API 健康檢查"""
|
278 |
+
return {"status": "healthy", "api_version": "1.0.0"}
|
279 |
+
|
280 |
+
# 主程序
|
281 |
+
if __name__ == "__main__":
|
282 |
+
# 啟動 API 服務器
|
283 |
+
uvicorn.run("api:app", host="0.0.0.0", port=8000, reload=True)
|
app.py
CHANGED
@@ -6,6 +6,13 @@ import time
|
|
6 |
import gradio as gr
|
7 |
from openai import OpenAI
|
8 |
from pydub import AudioSegment
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
# 标准音频模型和声音选项
|
11 |
STANDARD_AUDIO_MODELS = [
|
|
|
6 |
import gradio as gr
|
7 |
from openai import OpenAI
|
8 |
from pydub import AudioSegment
|
9 |
+
from dotenv import load_dotenv
|
10 |
+
|
11 |
+
# 加載環境變量
|
12 |
+
load_dotenv()
|
13 |
+
|
14 |
+
# 獲取 OpenAI API Key (如果在環境變量中設置了)
|
15 |
+
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
|
16 |
|
17 |
# 标准音频模型和声音选项
|
18 |
STANDARD_AUDIO_MODELS = [
|
requirements.txt
CHANGED
@@ -5,4 +5,7 @@ loguru
|
|
5 |
promptic
|
6 |
tenacity
|
7 |
bs4
|
8 |
-
pydub
|
|
|
|
|
|
|
|
5 |
promptic
|
6 |
tenacity
|
7 |
bs4
|
8 |
+
pydub
|
9 |
+
fastapi
|
10 |
+
uvicorn
|
11 |
+
python-dotenv
|