zlwu hai 11 meses
pai
achega
e5295b07e1
Modificáronse 6 ficheiros con 96 adicións e 166 borrados
  1. 45 150
      backend/.env.template
  2. 18 0
      backend/ENV_CONFIG.md
  3. 7 2
      backend/ai_service.py
  4. 18 11
      backend/config.py
  5. 7 2
      backend/database.py
  6. 1 1
      backend/stt_service.py

+ 45 - 150
backend/.env.template

@@ -1,160 +1,55 @@
-# ============================================
-# Tolan 后端环境变量配置模板
-# ============================================
-# 使用说明:
-# 1. 复制此文件为 .env: cp .env.template .env
-# 2. 填写必需的配置项(特别是 API 密钥)
-# 3. 根据需要调整可选配置
-# ============================================
+# DashScope API配置
+DASHSCOPE_API_KEY=sk-59d99526b02f405db8f3cd2c81a5009c #sk-92f2fec23dc94de49a31c9945d04e5f7
 
-# ====================================
-# 🔑 必需配置 - 请务必填写
-# ====================================
-
-# 阿里云 DashScope API 密钥(必需)
-# 获取地址: https://dashscope.console.aliyun.com/
-DASHSCOPE_API_KEY=sk-your-api-key-here
-
-# 阿里云 DashScope 国际版 API 密钥(可选)
-# 如果需要使用国际版API,请填写此项并设置 USE_DASHSCOPE_INTL=true
-# DASHSCOPE_API_KEY_INTL=sk-your-intl-api-key-here
-
-# 豆包 API 密钥(可选 - 如果使用豆包STT)
-# DOUBAO_API_KEY=your-doubao-api-key
-# DOUBAO_APP_ID=your-doubao-app-id
-
-# ====================================
-# 🌐 服务器配置
-# ====================================
-
-# 服务器监听地址(默认: 0.0.0.0,监听所有网卡)
+# 服务器配置
 HOST=0.0.0.0
+PORT=8766
 
-# 服务器监听端口(默认: 8000)
-PORT=8000
-
-# ====================================
-# 🚀 API 选择配置
-# ====================================
-
-# 是否使用 DashScope 国际版(默认: false)
-# 设置为 true 时需要配置 DASHSCOPE_API_KEY_INTL
-USE_DASHSCOPE_INTL=false
-
-# ====================================
-# 🤖 AI 模型配置
-# ====================================
+# LLM模型配置
+LLM_MODEL=qwen-flash
 
-# LLM 模型选择(默认: qwen-turbo)
-# 可选值: qwen-turbo, qwen-plus, qwen-max
-# qwen-turbo: 速度快,成本低
-# qwen-plus: 平衡性能
-# qwen-max: 最强性能
-LLM_MODEL=qwen-turbo
-
-# TTS 语音合成模型(默认: qwen3-tts-flash)
-# 可选值: qwen3-tts-flash, qwen3-tts-standard
-# flash: 低延迟,适合实时对话
-# standard: 音质更好,延迟稍高
+# TTS模型配置
 TTS_MODEL=qwen3-tts-flash
-
-# TTS 语音选择(默认: Cherry)
-# 可选值: Cherry(女声), Stella(女声)
-TTS_VOICE=Cherry
-
-# TTS 语速(默认: 1.1,即10%加速)
-# 范围: 0.8-1.3
-# 1.0 = 正常语速
-# 1.1 = 加速10%(推荐,减少延迟)
-# 0.9 = 减速10%
+TTS_VOICE=Jada # 上海阿珍
 TTS_SPEECH_RATE=1.1
 
-# ====================================
-# 🔧 TTS 优化配置(速率限制处理)
-# ====================================
-
-# TTS API 最大重试次数(默认: 3)
-TTS_MAX_RETRIES=3
-
-# TTS 初始重试延迟,单位:秒(默认: 5.0)
-TTS_RETRY_DELAY=5.0
-
-# TTS 重试指数退避系数(默认: 2.0)
-# 每次重试延迟时间 = 上次延迟 × 退避系数
-TTS_RETRY_BACKOFF=2.0
-
-# TTS 两次调用的最小间隔,单位:秒(默认: 0.8)
-# 用于预防性控制,避免触发 API 速率限制
-TTS_MIN_INTERVAL=0.8
-
-# ====================================
-# 🎓 AI 助手配置
-# ====================================
-
-# 学习者英语水平(默认: A1-A2)
-# 可选值: A1, A1-A2, B1-B2, C1-C2
-LEARNER_PROFICIENCY=A1-A2
-
-# 年龄标签(默认: Adult)
-# 可选值: Child(儿童), Teen(青少年), Adult(成人)
-AGE_TAG=Adult
-
-# 对话主题(默认: Daily Conversation)
-# 可选值: Daily Conversation(日常对话), Business(商务), Travel(旅行)等
-TOPIC_TAG=Daily Conversation
-
-# 实验标签(默认: control)
-# control: 不启用纠错
-# experiment: 启用纠错功能
-EXPERIMENT_TAG=control
-
-# 是否使用简化提示词(默认: false)
-# 设置为 true 可减少延迟,但可能影响对话质量
-USE_SIMPLIFIED_PROMPT=false
-
-# ====================================
-# 🔊 豆包 API 配置(如果使用豆包STT)
-# ====================================
-
-# 豆包 API WebSocket 地址
-DOUBAO_API_URL=wss://openspeech.bytedance.com/api/v3/realtime/dialogue
-
-# 豆包输出音频格式(默认: ogg_opus)
-# 可选值: ogg_opus, pcm
-DOUBAO_OUTPUT_FORMAT=ogg_opus
-
-# ====================================
-# 🌍 CORS 跨域配置
-# ====================================
-
-# 是否允许所有来源访问(默认: true)
-# 开发环境: true(方便调试)
-# 生产环境: false(安全考虑)
-CORS_ALLOW_ALL=true
-
-# ====================================
-# 🔒 SSL 证书配置(可选)
-# ====================================
-
-# SSL 私钥文件路径(留空则使用 HTTP)
-# 示例: /path/to/ssl/key.pem
+# SSL证书配置(本地开发)
+# 留空则自动使用 ../ssl/ 目录下的证书
 SSL_KEYFILE=
-
-# SSL 证书文件路径(留空则使用 HTTP)
-# 示例: /path/to/ssl/cert.pem
 SSL_CERTFILE=
 
-# ====================================
-# 📝 配置说明
-# ====================================
-# 1. 所有以 # 开头的行都是注释
-# 2. 必需配置必须填写,否则服务无法正常运行
-# 3. 可选配置如果不填写,将使用默认值
-# 4. 修改配置后需要重启服务才能生效
-# 5. 生产环境部署时请特别注意安全配置(CORS、SSL等)
-#
-# 快速开始:
-# 1. 复制此文件: cp .env.template .env
-# 2. 编辑 .env 文件: vim .env 或 nano .env
-# 3. 填写 DASHSCOPE_API_KEY(必需)
-# 4. 启动服务: python main.py
+# CORS配置
+CORS_ALLOW_ALL=true
+
+# MySQL配置
+MYSQL_HOST=101.201.60.170
+MYSQL_PORT=13306
+MYSQL_USER=root
+MYSQL_PASSWORD=Lyrria@Root@123456
+MYSQL_DATABASE=Lyrria
+
+# Redis配置
+REDIS_HOST=101.201.60.170
+REDIS_PORT=16379
+REDIS_DB=1
+REDIS_PASSWORD=Lyrria@redis@123456
+REDIS_SSL=false
+REDIS_SESSION_TTL=86400
+
+# MySQL健康检查配置
+MYSQL_HEALTHCHECK_INTERVAL=600
+
+# Redis健康检查配置
+REDIS_HEALTHCHECK_INTERVAL=300
+
+# HTTP客户端配置(用于DashScope API)
+HTTPX_MAX_KEEPALIVE_CONNECTIONS=20
+HTTPX_MAX_CONNECTIONS=50
+HTTPX_KEEPALIVE_EXPIRY=60.0
+
+# LLM连接健康检查配置
+LLM_HEALTHCHECK_INTERVAL=300
+
+# 日志级别
+LOG_LEVEL=DEBUG
+DEBUG=true

+ 18 - 0
backend/ENV_CONFIG.md

@@ -12,4 +12,22 @@
 | `TTS_HEALTHCHECK_INTERVAL` | `300` | TTS 连接健康检查间隔(秒),长时间未使用时自动检查连接状态,失效时重建。确保长时间不交互后首次TTS调用也能快速响应。 |
 | `ENERGY_STONE_TTL_SECONDS` | `20` | 能量石在前端展示的生存时间(秒),超时后自动触发消失事件。 |
 | `CONVERSATION_STONE_INTERVAL_SECONDS` | `30` | 对话能量石触发间隔(秒),基于用户累计说话时长达到该阈值时生成。 |
+| `STT_MODEL` | `qwen3-asr-flash-realtime` | STT 模型名称,对应 DashScope `qwen3-asr-flash-realtime` 流式识别。 |
+| `STT_WS_URL` | *(空)* | STT WebSocket 自定义调用地址,留空时根据 `USE_DASHSCOPE_INTL` 自动拼接 DashScope 默认地址。 |
+| `STT_LANGUAGE` | `zh` | STT 目标语种(`zh`/`en`/`ja`/`ko`/`auto`),用于 DashScope 识别参数。 |
+| `LLM_MODEL` | `qwen-flash` | LLM 模型名称,传递给 DashScope 兼容模式 Chat Completions API。 |
+| `LLM_BASE_URL` | *(空)* | LLM HTTP 调用地址,留空则自动根据 `USE_DASHSCOPE_INTL` 选择 `compatible-mode/v1` 域名。 |
+| `TTS_MODEL` | `qwen3-tts-flash` | TTS 模型名称,传递给 DashScope `MultiModalConversation`。 |
+| `TTS_API_URL` | *(空)* | 自定义 TTS HTTP 调用地址,留空则使用 `https://dashscope(或 dashscope-intl).aliyuncs.com/api/v1`。 |
+| `TTS_VOICE` | `Cherry` | TTS 音色(如 `Cherry`/`Stella`),用于生成目标发音。 |
+| `TTS_SPEECH_RATE` | `1.1` | TTS 语速,1.0 为标准,>1 加速,<1 减速。 |
+| `TTS_MIN_INTERVAL` | `0.8` | 两次 TTS 调用之间的最小时长(秒),避免触发限流。 |
+| `TTS_MAX_RETRIES` | `3` | 单次 TTS 调用的最大重试次数。 |
+| `TTS_RETRY_DELAY` | `5.0` | TTS 初次重试等待时间(秒)。 |
+| `TTS_RETRY_BACKOFF` | `2.0` | TTS 重试指数退避倍数。 |
+| `LEARNER_PROFICIENCY` | `A1-A2` | LLM 提示词中对学习者水平的设定。 |
+| `AGE_TAG` | `Adult` | LLM 提示词使用的年龄段标签。 |
+| `TOPIC_TAG` | `Daily Conversation` | LLM 提示词使用的主题标签。 |
+| `EXPERIMENT_TAG` | `control` | 提示词实验分组标记(`control` 或 `experiment`)。 |
+| `USE_SIMPLIFIED_PROMPT` | `false` | 是否启用简化提示词逻辑,降低 LLM 延迟。 |
 

+ 7 - 2
backend/ai_service.py

@@ -11,7 +11,12 @@ import traceback
 from typing import AsyncGenerator, Optional
 import dashscope
 from openai import OpenAI
-from config import settings, get_dashscope_http_base_url, get_dashscope_domain
+from config import (
+    settings,
+    get_dashscope_http_base_url,
+    get_dashscope_domain,
+    get_dashscope_tts_api_url,
+)
 from models import EmotionType
 from http_pool import http_pool  # 🔥 使用连接池管理器
 
@@ -24,10 +29,10 @@ USE_NEW_TTS_API = False  # 保持使用 MultiModalConversation
 
 # 设置API Key和endpoint(根据国际版/国内版自动选择)
 dashscope.api_key = settings.active_dashscope_api_key
+dashscope.base_http_api_url = get_dashscope_tts_api_url()
 # 配置国际版endpoint(如果需要)
 if settings.use_dashscope_intl:
     dashscope_domain = get_dashscope_domain()
-    dashscope.base_http_api_url = f"https://{dashscope_domain}/api/v1"
     dashscope.base_websocket_api_url = f"wss://{dashscope_domain}/api-ws/v1"
 
 

+ 18 - 11
backend/config.py

@@ -46,6 +46,7 @@ class Settings(BaseSettings):
     
     # LLM配置
     llm_model: str = os.getenv("LLM_MODEL", "qwen-flash")
+    LLM_BASE_URL: str = os.getenv("LLM_BASE_URL", "")
     
     # STT配置
     # ⚠️ 重要:language参数必须设置!
@@ -56,10 +57,13 @@ class Settings(BaseSettings):
     #   - 'ko' (韩文)
     #   - 'auto' (自动检测 - 实验性,需要测试)
     # 项目正式使用时应设为'en',测试阶段用'zh'或'auto'
+    STT_MODEL: str = os.getenv("STT_MODEL", "qwen3-asr-flash-realtime")
+    STT_WS_URL: str = os.getenv("STT_WS_URL", "")
     STT_LANGUAGE: str = os.getenv("STT_LANGUAGE", "zh")
     
     # TTS配置
     tts_model: str = os.getenv("TTS_MODEL", "qwen3-tts-flash")
+    TTS_API_URL: str = os.getenv("TTS_API_URL", "")
     tts_voice: str = os.getenv("TTS_VOICE", "Cherry")  # 女声(支持:Cherry, Stella)
     tts_speech_rate: float = float(os.getenv("TTS_SPEECH_RATE", "1.1"))  # 语速:1.1 = 10%加速(优化延迟)
     
@@ -71,17 +75,6 @@ class Settings(BaseSettings):
     # TTS速率控制(预防性措施,避免触发API限制)
     TTS_MIN_INTERVAL: float = float(os.getenv("TTS_MIN_INTERVAL", "0.8"))  # 两次TTS调用的最小间隔(秒)
     
-    # 豆包API超时配置
-    DOUBAO_RECV_TIMEOUT: int = 15  # 接收消息超时(秒)
-    DOUBAO_CONNECT_TIMEOUT: int = 10  # 连接超时(秒)
-    DOUBAO_RESPONSE_TIMEOUT: int = 20  # 响应超时(秒)
-    
-    # 豆包API配置
-    DOUBAO_API_KEY: str = os.getenv("DOUBAO_API_KEY", "")
-    DOUBAO_APP_ID: str = os.getenv("DOUBAO_APP_ID", "")
-    DOUBAO_API_URL: str = os.getenv("DOUBAO_API_URL", "wss://openspeech.bytedance.com/api/v3/realtime/dialogue")
-    DOUBAO_OUTPUT_FORMAT: str = os.getenv("DOUBAO_OUTPUT_FORMAT", "ogg_opus")  # ogg_opus 或 pcm
-    
     # AI助手提示词配置
     LEARNER_PROFICIENCY: str = os.getenv("LEARNER_PROFICIENCY", "A1-A2")
     AGE_TAG: str = os.getenv("AGE_TAG", "Adult")
@@ -179,13 +172,27 @@ def get_dashscope_domain() -> str:
     """获取 DashScope API 域名"""
     return "dashscope-intl.aliyuncs.com" if settings.use_dashscope_intl else "dashscope.aliyuncs.com"
 
+
 def get_dashscope_ws_url() -> str:
     """获取 DashScope WebSocket URL(用于STT)"""
+    if settings.STT_WS_URL:
+        return settings.STT_WS_URL
     domain = get_dashscope_domain()
     return f"wss://{domain}/api-ws/v1/realtime"
 
+
 def get_dashscope_http_base_url() -> str:
     """获取 DashScope HTTP base URL(用于LLM)"""
+    if settings.LLM_BASE_URL:
+        return settings.LLM_BASE_URL.rstrip("/")
     domain = get_dashscope_domain()
     return f"https://{domain}/compatible-mode/v1"
 
+
+def get_dashscope_tts_api_url() -> str:
+    """获取 DashScope HTTP API URL(用于TTS)"""
+    if settings.TTS_API_URL:
+        return settings.TTS_API_URL.rstrip("/")
+    domain = get_dashscope_domain()
+    return f"https://{domain}/api/v1"
+

+ 7 - 2
backend/database.py

@@ -4,8 +4,10 @@
 import asyncio
 import time
 import traceback
-import redis.asyncio as aioredis
 from typing import Optional
+from urllib.parse import quote_plus
+
+import redis.asyncio as aioredis
 from sqlalchemy.ext.asyncio import (
     create_async_engine,
     AsyncSession,
@@ -13,6 +15,7 @@ from sqlalchemy.ext.asyncio import (
     AsyncEngine
 )
 from sqlalchemy.orm import declarative_base
+
 from config import settings
 import logging
 
@@ -45,8 +48,10 @@ class DatabaseManager:
     async def _create_mysql_engine(self):
         """创建 SQLAlchemy 异步引擎"""
         # 构建 MySQL 连接 URL
+        encoded_user = quote_plus(settings.MYSQL_USER)
+        encoded_password = quote_plus(settings.MYSQL_PASSWORD)
         mysql_url = (
-            f"mysql+aiomysql://{settings.MYSQL_USER}:{settings.MYSQL_PASSWORD}"
+            f"mysql+aiomysql://{encoded_user}:{encoded_password}"
             f"@{settings.MYSQL_HOST}:{settings.MYSQL_PORT}/{settings.MYSQL_DATABASE}"
             f"?charset=utf8mb4"
         )

+ 1 - 1
backend/stt_service.py

@@ -379,7 +379,7 @@ class STTSession:
                     )
                     
                     conversation = OmniRealtimeConversation(
-                        model='qwen3-asr-flash-realtime',
+                        model=settings.STT_MODEL,
                         url=ws_url,
                         callback=self.callback
                     )