feat(backend): 添加 Groq供应商支持并优化笔记生成流程- 在 builtin_providers.json 中添加 Groq 供应商信息

- 实现 GroqTranscriber 类以支持 Groq 语音转录服务
- 新增异常处理中间件以提高系统稳定性
- 优化笔记生成流程,增加错误处理和日志记录
- 添加思维导图功能和相关组件
-重构 Markdown 查看器以支持切换视图模式
This commit is contained in:
黄建武
2025-05-12 14:59:06 +08:00
parent b2034c0865
commit 6ff8b4d90f
16 changed files with 743 additions and 352 deletions

View File

@@ -0,0 +1,52 @@
from abc import ABC
import os
from app.decorators.timeit import timeit
from app.models.transcriber_model import TranscriptResult, TranscriptSegment
from app.services.provider import ProviderService
from app.transcriber.base import Transcriber
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
class GroqTranscriber(Transcriber, ABC):
@timeit
def transcript(self, file_path: str) -> TranscriptResult:
provider = ProviderService.get_provider_by_id('groq')
if not provider:
raise Exception("Groq 供应商未配置,请配置以后使用。")
client = OpenAI(
api_key=provider.get('api_key'),
base_url=provider.get('base_url')
)
filename = file_path
with open(filename, "rb") as file:
transcription = client.audio.transcriptions.create(
file=(filename, file.read()),
model=os.getenv('GROQ_TRANSCRIBER_MODEL'),
response_format="verbose_json",
)
print(transcription.text)
print(transcription)
segments = []
full_text = ""
for seg in transcription.segments:
text = seg.text.strip()
full_text += text + " "
segments.append(TranscriptSegment(
start=seg.start,
end=seg.end,
text=text
))
result = TranscriptResult(
language=transcription.language,
full_text=full_text.strip(),
segments=segments,
raw=transcription.to_dict()
)
return result

View File

@@ -1,113 +1,115 @@
import os
import platform
from enum import Enum
from app.transcriber.groq import GroqTranscriber
from app.transcriber.whisper import WhisperTranscriber
from app.transcriber.bcut import BcutTranscriber
from app.transcriber.kuaishou import KuaishouTranscriber
from app.utils.logger import get_logger
logger = get_logger(__name__)
# 只在Apple平台且设置了环境变量时才导入MLX Whisper
class TranscriberType(str, Enum):
FAST_WHISPER = "fast-whisper"
MLX_WHISPER = "mlx-whisper"
BCUT = "bcut"
KUAISHOU = "kuaishou"
GROQ = "groq"
# 仅在 Apple 平台启用 MLX Whisper
MLX_WHISPER_AVAILABLE = False
if platform.system() == "Darwin" and os.environ.get("TRANSCRIBER_TYPE") == "mlx-whisper":
try:
from app.transcriber.mlx_whisper_transcriber import MLXWhisperTranscriber
MLX_WHISPER_AVAILABLE = True
logger.info("MLX Whisper 可用,已导入")
except ImportError:
MLX_WHISPER_AVAILABLE = False
logger.warning("MLX Whisper 导入失败,可能未安装或平台不支持")
else:
MLX_WHISPER_AVAILABLE = False
logger.info('初始化转录服务提供器')
# 维护各种转录器单例实例
# 转录器单例缓存
_transcribers = {
'bcut': None,
'kuaishou': None,
'mlx-whisper': None,
'fast-whisper':None
TranscriberType.FAST_WHISPER: None,
TranscriberType.MLX_WHISPER: None,
TranscriberType.BCUT: None,
TranscriberType.KUAISHOU: None,
TranscriberType.GROQ: None,
}
def get_whisper_transcriber(model_size="base", device="cuda"):
"""获取 Whisper 转录器实例"""
if _transcribers['fast-whisper'] is None:
logger.info(f'创建 Whisper 转录器实例,参数:{model_size}, {device}')
# 公共实例初始化函数
def _init_transcriber(key: TranscriberType, cls, *args, **kwargs):
if _transcribers[key] is None:
logger.info(f'创建 {cls.__name__} 实例: {key}')
try:
_transcribers['whisper'] = WhisperTranscriber(model_size=model_size, device=device)
logger.info('Whisper 转录器创建成功')
_transcribers[key] = cls(*args, **kwargs)
logger.info(f'{cls.__name__} 创建成功')
except Exception as e:
logger.error(f"Whisper 转录器创建失败: {e}")
logger.error(f"{cls.__name__} 创建失败: {e}")
raise
return _transcribers['whisper']
return _transcribers[key]
# 各类型获取方法
def get_groq_transcriber():
return _init_transcriber(TranscriberType.GROQ, GroqTranscriber)
def get_whisper_transcriber(model_size="base", device="cuda"):
return _init_transcriber(TranscriberType.FAST_WHISPER, WhisperTranscriber, model_size=model_size, device=device)
def get_bcut_transcriber():
"""获取 Bcut 转录器实例"""
if _transcribers['bcut'] is None:
logger.info('创建 Bcut 转录器实例')
try:
_transcribers['bcut'] = BcutTranscriber()
logger.info('Bcut 转录器创建成功')
except Exception as e:
logger.error(f"Bcut 转录器创建失败: {e}")
raise
return _transcribers['bcut']
return _init_transcriber(TranscriberType.BCUT, BcutTranscriber)
def get_kuaishou_transcriber():
"""获取快手转录器实例"""
if _transcribers['kuaishou'] is None:
logger.info('创建快手转录器实例')
try:
_transcribers['kuaishou'] = KuaishouTranscriber()
logger.info('快手转录器创建成功')
except Exception as e:
logger.error(f"快手转录器创建失败: {e}")
raise
return _transcribers['kuaishou']
return _init_transcriber(TranscriberType.KUAISHOU, KuaishouTranscriber)
def get_mlx_whisper_transcriber(model_size="base"):
"""获取 MLX Whisper 转录器实例"""
if not MLX_WHISPER_AVAILABLE:
logger.warning("MLX Whisper 不可用请确保在Apple平台且已安装mlx_whisper")
raise ImportError("MLX Whisper 不可用请确保在Apple平台且已安装mlx_whisper")
if _transcribers['mlx-whisper'] is None:
logger.info(f'创建 MLX Whisper 转录器实例,参数:{model_size}')
try:
_transcribers['mlx-whisper'] = MLXWhisperTranscriber(model_size=model_size)
logger.info('MLX Whisper 转录器创建成功')
except Exception as e:
logger.error(f"MLX Whisper 转录器创建失败: {e}")
raise
return _transcribers['mlx-whisper']
logger.warning("MLX Whisper 不可用,请确保在 Apple 平台且已安装 mlx_whisper")
raise ImportError("MLX Whisper 不可用")
return _init_transcriber(TranscriberType.MLX_WHISPER, MLXWhisperTranscriber, model_size=model_size)
# 通用入口
def get_transcriber(transcriber_type="fast-whisper", model_size="base", device="cuda"):
"""
获取指定类型的转录器实例
参数:
transcriber_type: 转录器类型,支持 "fast-whisper", "bcut", "kuaishou", "mlx-whisper"(仅Apple平台)
model_size: 模型大小,whisper 和 mlx-whisper 特有参数
device: 设备类型whisper 特有参数
transcriber_type: 支持 "fast-whisper", "mlx-whisper", "bcut", "kuaishou", "groq"
model_size: 模型大小,适用于 whisper
device: 设备类型(如 cuda / cpuwhisper 使用
返回:
对应类型的转录器实例
"""
logger.info(f'获取转录器类型: {transcriber_type}')
if transcriber_type == "fast-whisper":
whisper_model_size = os.environ.get("WHISPER_MODEL_SIZE",model_size)
logger.info(f'请求转录器类型: {transcriber_type}')
try:
transcriber_enum = TranscriberType(transcriber_type)
except ValueError:
logger.warning(f'未知转录器类型 "{transcriber_type}",默认使用 fast-whisper')
transcriber_enum = TranscriberType.FAST_WHISPER
whisper_model_size = os.environ.get("WHISPER_MODEL_SIZE", model_size)
if transcriber_enum == TranscriberType.FAST_WHISPER:
return get_whisper_transcriber(whisper_model_size, device=device)
elif transcriber_type == "mlx-whisper":
whisper_model_size = os.environ.get("WHISPER_MODEL_SIZE",model_size)
elif transcriber_enum == TranscriberType.MLX_WHISPER:
if not MLX_WHISPER_AVAILABLE:
logger.warning("MLX Whisper 不可用,回退到 fast-whisper")
return get_whisper_transcriber(whisper_model_size, device=device)
return get_mlx_whisper_transcriber(whisper_model_size)
elif transcriber_type == "bcut":
elif transcriber_enum == TranscriberType.BCUT:
return get_bcut_transcriber()
elif transcriber_type == "kuaishou":
elif transcriber_enum == TranscriberType.KUAISHOU:
return get_kuaishou_transcriber()
else:
logger.warning(f'未知转录器类型 "{transcriber_type}",使用默认 whisper')
whisper_model_size = os.environ.get("WHISPER_MODEL_SIZE",model_size)
return get_whisper_transcriber(whisper_model_size, device)
elif transcriber_enum == TranscriberType.GROQ:
return get_groq_transcriber()
# fallback
logger.warning(f'未识别转录器类型 "{transcriber_type}",使用 fast-whisper 作为默认')
return get_whisper_transcriber(whisper_model_size, device=device)