test #1
+3
-20
@@ -1,14 +1,12 @@
|
|||||||
# ByteDance TTS v3 API 全兼容配置示例
|
# ByteDance TTS v3 API 配置示例
|
||||||
# 将此文件复制为 .env 并填入实际配置
|
# 将此文件复制为 .env 并填入实际配置
|
||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# 必需的环境变量
|
# 必需的环境变量
|
||||||
# ==========================================
|
# ==========================================
|
||||||
|
|
||||||
# 鉴权模式(必要参数)
|
# 火山引擎新版控制台获取的 API Key
|
||||||
# - legacy: 旧版鉴权,使用 AppID + AccessKey(v1资产升级推荐)
|
BYTEDANCE_TTS_API_KEY=your_api_key_here
|
||||||
# - new: 新版鉴权,使用 ApiKey(新控制台用户推荐)
|
|
||||||
BYTEDANCE_TTS_AUTH_MODE=legacy
|
|
||||||
|
|
||||||
# 资源信息ID(决定使用1.0还是2.0模型)
|
# 资源信息ID(决定使用1.0还是2.0模型)
|
||||||
# 语音合成模型:
|
# 语音合成模型:
|
||||||
@@ -26,21 +24,6 @@ BYTEDANCE_TTS_RESOURCE_ID=seed-tts-1.0
|
|||||||
# 2.0音色只能搭配 seed-tts-2.0 Resource ID
|
# 2.0音色只能搭配 seed-tts-2.0 Resource ID
|
||||||
BYTEDANCE_TTS_SPEAKER=your_speaker_id_here
|
BYTEDANCE_TTS_SPEAKER=your_speaker_id_here
|
||||||
|
|
||||||
# ==========================================
|
|
||||||
# 鉴权参数(根据 AUTH_MODE 选择配置)
|
|
||||||
# ==========================================
|
|
||||||
|
|
||||||
# ---------- legacy 模式需要配置 ----------
|
|
||||||
# 火山引擎旧版控制台获取的 AppID
|
|
||||||
BYTEDANCE_TTS_APP_ID=your_app_id_here
|
|
||||||
|
|
||||||
# 火山引擎旧版控制台获取的 Access Key
|
|
||||||
BYTEDANCE_TTS_ACCESS_KEY=your_access_key_here
|
|
||||||
|
|
||||||
# ---------- new 模式需要配置 ----------
|
|
||||||
# 火山引擎新版控制台获取的 API Key
|
|
||||||
BYTEDANCE_TTS_API_KEY=your_api_key_here
|
|
||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# 可选的环境变量
|
# 可选的环境变量
|
||||||
# ==========================================
|
# ==========================================
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
- ✅ 完全兼容OpenAI `/v1/audio/speech` API接口
|
- ✅ 完全兼容OpenAI `/v1/audio/speech` API接口
|
||||||
- ✅ 支持火山引擎TTS v3 API(单向流式)
|
- ✅ 支持火山引擎TTS v3 API(单向流式)
|
||||||
- ✅ 支持两种鉴权模式:Legacy(AppID+AccessKey) 和 New(API Key)
|
- ✅ 支持API Key鉴权方式
|
||||||
- ✅ 支持多种发音人和模型版本
|
- ✅ 支持多种发音人和模型版本
|
||||||
- ✅ 内置速率限制和统计功能
|
- ✅ 内置速率限制和统计功能
|
||||||
- ✅ 支持配置API密钥验证
|
- ✅ 支持配置API密钥验证
|
||||||
@@ -61,19 +61,10 @@ tts_server.exe
|
|||||||
|
|
||||||
| 变量名 | 说明 | 示例 |
|
| 变量名 | 说明 | 示例 |
|
||||||
|--------|------|------|
|
|--------|------|------|
|
||||||
| `BYTEDANCE_TTS_AUTH_MODE` | 鉴权模式:`legacy` 或 `new` | `legacy` |
|
| `BYTEDANCE_TTS_API_KEY` | 火山引擎新版控制台 API Key | `your_api_key_here` |
|
||||||
| `BYTEDANCE_TTS_RESOURCE_ID` | 资源ID,决定模型版本 | `seed-tts-1.0` |
|
| `BYTEDANCE_TTS_RESOURCE_ID` | 资源ID,决定模型版本 | `seed-tts-1.0` |
|
||||||
| `BYTEDANCE_TTS_SPEAKER` | 发音人(音色)ID | `zh_female_qingxin` |
|
| `BYTEDANCE_TTS_SPEAKER` | 发音人(音色)ID | `zh_female_qingxin` |
|
||||||
|
|
||||||
### 鉴权参数(二选一)
|
|
||||||
|
|
||||||
**Legacy 模式(旧版控制台):**
|
|
||||||
- `BYTEDANCE_TTS_APP_ID` - 应用ID
|
|
||||||
- `BYTEDANCE_TTS_ACCESS_KEY` - 访问密钥
|
|
||||||
|
|
||||||
**New 模式(新版控制台):**
|
|
||||||
- `BYTEDANCE_TTS_API_KEY` - API密钥
|
|
||||||
|
|
||||||
### 可选参数
|
### 可选参数
|
||||||
|
|
||||||
| 变量名 | 说明 | 默认值 |
|
| 变量名 | 说明 | 默认值 |
|
||||||
@@ -154,10 +145,9 @@ curl http://localhost:8080/stats
|
|||||||
|
|
||||||
### 1. 如何获取鉴权信息?
|
### 1. 如何获取鉴权信息?
|
||||||
|
|
||||||
- 登录火山引擎控制台
|
- 登录火山引擎新版控制台
|
||||||
- 进入"语音合成"服务
|
- 进入"语音合成"服务
|
||||||
- 在应用管理中创建应用并获取AppID和AccessKey(Legacy模式)
|
- 创建应用并获取API Key
|
||||||
- 或在新版控制台获取API Key(New模式)
|
|
||||||
|
|
||||||
### 2. 端口被占用怎么办?
|
### 2. 端口被占用怎么办?
|
||||||
|
|
||||||
|
|||||||
+4
-45
@@ -62,9 +62,6 @@ type OpenAITTSRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ByteDanceTTSConfig struct {
|
type ByteDanceTTSConfig struct {
|
||||||
AuthMode string
|
|
||||||
AppID string
|
|
||||||
AccessKey string
|
|
||||||
ApiKey string
|
ApiKey string
|
||||||
ResourceId string
|
ResourceId string
|
||||||
Speaker string
|
Speaker string
|
||||||
@@ -149,21 +146,15 @@ func (rl *RateLimiter) Allow(key string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initTTSConfig() error {
|
func initTTSConfig() error {
|
||||||
authMode := os.Getenv("BYTEDANCE_TTS_AUTH_MODE")
|
|
||||||
appID := os.Getenv("BYTEDANCE_TTS_APP_ID")
|
|
||||||
accessKey := os.Getenv("BYTEDANCE_TTS_ACCESS_KEY")
|
|
||||||
apiKey := os.Getenv("BYTEDANCE_TTS_API_KEY")
|
apiKey := os.Getenv("BYTEDANCE_TTS_API_KEY")
|
||||||
resourceId := os.Getenv("BYTEDANCE_TTS_RESOURCE_ID")
|
resourceId := os.Getenv("BYTEDANCE_TTS_RESOURCE_ID")
|
||||||
speaker := os.Getenv("BYTEDANCE_TTS_SPEAKER")
|
speaker := os.Getenv("BYTEDANCE_TTS_SPEAKER")
|
||||||
|
|
||||||
missingVars := []string{}
|
missingVars := []string{}
|
||||||
|
|
||||||
if authMode == "" {
|
if apiKey == "" {
|
||||||
missingVars = append(missingVars, "BYTEDANCE_TTS_AUTH_MODE")
|
missingVars = append(missingVars, "BYTEDANCE_TTS_API_KEY")
|
||||||
} else if authMode != "legacy" && authMode != "new" {
|
|
||||||
return fmt.Errorf("BYTEDANCE_TTS_AUTH_MODE 无效,必须是 'legacy' (旧版 AppID+AccessKey) 或 'new' (新版 ApiKey)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if resourceId == "" {
|
if resourceId == "" {
|
||||||
missingVars = append(missingVars, "BYTEDANCE_TTS_RESOURCE_ID")
|
missingVars = append(missingVars, "BYTEDANCE_TTS_RESOURCE_ID")
|
||||||
}
|
}
|
||||||
@@ -171,19 +162,6 @@ func initTTSConfig() error {
|
|||||||
missingVars = append(missingVars, "BYTEDANCE_TTS_SPEAKER")
|
missingVars = append(missingVars, "BYTEDANCE_TTS_SPEAKER")
|
||||||
}
|
}
|
||||||
|
|
||||||
if authMode == "legacy" {
|
|
||||||
if appID == "" {
|
|
||||||
missingVars = append(missingVars, "BYTEDANCE_TTS_APP_ID")
|
|
||||||
}
|
|
||||||
if accessKey == "" {
|
|
||||||
missingVars = append(missingVars, "BYTEDANCE_TTS_ACCESS_KEY")
|
|
||||||
}
|
|
||||||
} else if authMode == "new" {
|
|
||||||
if apiKey == "" {
|
|
||||||
missingVars = append(missingVars, "BYTEDANCE_TTS_API_KEY")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(missingVars) > 0 {
|
if len(missingVars) > 0 {
|
||||||
return fmt.Errorf("缺少必需的环境变量: %v", missingVars)
|
return fmt.Errorf("缺少必需的环境变量: %v", missingVars)
|
||||||
}
|
}
|
||||||
@@ -200,9 +178,6 @@ func initTTSConfig() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ttsConfig = ByteDanceTTSConfig{
|
ttsConfig = ByteDanceTTSConfig{
|
||||||
AuthMode: authMode,
|
|
||||||
AppID: appID,
|
|
||||||
AccessKey: accessKey,
|
|
||||||
ApiKey: apiKey,
|
ApiKey: apiKey,
|
||||||
ResourceId: resourceId,
|
ResourceId: resourceId,
|
||||||
Speaker: speaker,
|
Speaker: speaker,
|
||||||
@@ -227,21 +202,12 @@ func initAPIKeys() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkEnvironmentVariables() map[string]interface{} {
|
func checkEnvironmentVariables() map[string]interface{} {
|
||||||
authMode := os.Getenv("BYTEDANCE_TTS_AUTH_MODE")
|
|
||||||
|
|
||||||
requiredVars := map[string]bool{
|
requiredVars := map[string]bool{
|
||||||
"BYTEDANCE_TTS_AUTH_MODE": authMode != "",
|
"BYTEDANCE_TTS_API_KEY": os.Getenv("BYTEDANCE_TTS_API_KEY") != "",
|
||||||
"BYTEDANCE_TTS_RESOURCE_ID": os.Getenv("BYTEDANCE_TTS_RESOURCE_ID") != "",
|
"BYTEDANCE_TTS_RESOURCE_ID": os.Getenv("BYTEDANCE_TTS_RESOURCE_ID") != "",
|
||||||
"BYTEDANCE_TTS_SPEAKER": os.Getenv("BYTEDANCE_TTS_SPEAKER") != "",
|
"BYTEDANCE_TTS_SPEAKER": os.Getenv("BYTEDANCE_TTS_SPEAKER") != "",
|
||||||
}
|
}
|
||||||
|
|
||||||
if authMode == "legacy" {
|
|
||||||
requiredVars["BYTEDANCE_TTS_APP_ID"] = os.Getenv("BYTEDANCE_TTS_APP_ID") != ""
|
|
||||||
requiredVars["BYTEDANCE_TTS_ACCESS_KEY"] = os.Getenv("BYTEDANCE_TTS_ACCESS_KEY") != ""
|
|
||||||
} else if authMode == "new" {
|
|
||||||
requiredVars["BYTEDANCE_TTS_API_KEY"] = os.Getenv("BYTEDANCE_TTS_API_KEY") != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
missingVars := []string{}
|
missingVars := []string{}
|
||||||
for varName, isSet := range requiredVars {
|
for varName, isSet := range requiredVars {
|
||||||
if !isSet {
|
if !isSet {
|
||||||
@@ -324,13 +290,7 @@ func synthesis(text string, speed float64) ([]byte, error) {
|
|||||||
"Connection": "keep-alive",
|
"Connection": "keep-alive",
|
||||||
"X-Api-Resource-Id": ttsConfig.ResourceId,
|
"X-Api-Resource-Id": ttsConfig.ResourceId,
|
||||||
"X-Api-Request-Id": reqID,
|
"X-Api-Request-Id": reqID,
|
||||||
}
|
"X-Api-Key": ttsConfig.ApiKey,
|
||||||
|
|
||||||
if ttsConfig.AuthMode == "legacy" {
|
|
||||||
headers["X-Api-App-Id"] = ttsConfig.AppID
|
|
||||||
headers["X-Api-Access-Key"] = ttsConfig.AccessKey
|
|
||||||
} else {
|
|
||||||
headers["X-Api-Key"] = ttsConfig.ApiKey
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bodyStr, err := json.Marshal(params)
|
bodyStr, err := json.Marshal(params)
|
||||||
@@ -745,7 +705,6 @@ func main() {
|
|||||||
log.Printf("OpenAI TTS endpoint: http://localhost:%s/v1/audio/speech", port)
|
log.Printf("OpenAI TTS endpoint: http://localhost:%s/v1/audio/speech", port)
|
||||||
log.Printf("Health check: http://localhost:%s/health", port)
|
log.Printf("Health check: http://localhost:%s/health", port)
|
||||||
log.Printf("Using ByteDance v3 API: %s", ttsConfig.URL)
|
log.Printf("Using ByteDance v3 API: %s", ttsConfig.URL)
|
||||||
log.Printf("Auth Mode: %s", ttsConfig.AuthMode)
|
|
||||||
log.Printf("Resource ID: %s", ttsConfig.ResourceId)
|
log.Printf("Resource ID: %s", ttsConfig.ResourceId)
|
||||||
log.Printf("Speaker: %s", ttsConfig.Speaker)
|
log.Printf("Speaker: %s", ttsConfig.Speaker)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user