mirror of
https://github.com/BoardWare-Genius/jarvis-models.git
synced 2025-12-12 16:23:26 +00:00
139 lines
5.9 KiB
Python
139 lines
5.9 KiB
Python
from typing import Union
|
||
|
||
from fastapi import FastAPI, Request, status
|
||
from fastapi.responses import JSONResponse, Response, StreamingResponse
|
||
|
||
from src.blackbox.blackbox_factory import BlackboxFactory
|
||
from src.log.loki_config import LokiLogger
|
||
import logging
|
||
|
||
from fastapi.middleware.cors import CORSMiddleware
|
||
from injector import Injector
|
||
import yaml
|
||
|
||
app = FastAPI()
|
||
|
||
app.add_middleware(
|
||
CORSMiddleware,
|
||
allow_origins=["*"],
|
||
allow_credentials=True,
|
||
allow_methods=["*"],
|
||
allow_headers=["*"],
|
||
)
|
||
|
||
injector = Injector()
|
||
blackbox_factory = injector.get(BlackboxFactory)
|
||
|
||
with open(".env.yaml", "r") as f:
|
||
config = yaml.safe_load(f)
|
||
logger = LokiLogger(
|
||
# url=config["loki"]["url"],
|
||
# username=config["loki"]["username"],
|
||
# password=config["loki"]["password"],
|
||
tags=config["loki"]["labels"],
|
||
logger_name=__name__,
|
||
level=logging.DEBUG
|
||
).get_logger()
|
||
|
||
|
||
@app.exception_handler(Exception)
|
||
async def catch_all_exceptions(request: Request, exc: Exception):
|
||
"""
|
||
捕获所有在 ASGI 应用中未被处理的异常,并记录到 Loki。
|
||
"""
|
||
logger.error(
|
||
f"Unhandled exception in ASGI application for path: {request.url.path}, method: {request.method} - {exc}",
|
||
exc_info=True, # 必须为 True,才能获取完整的堆栈信息
|
||
extra={
|
||
"path": request.url.path,
|
||
"method": request.method,
|
||
"error_type": type(exc).__name__,
|
||
"error_message": str(exc)
|
||
}
|
||
)
|
||
return JSONResponse(
|
||
status_code=500,
|
||
content={"message": "Internal Server Error", "detail": "An unexpected error occurred."}
|
||
)
|
||
|
||
@app.post("/")
|
||
@app.get("/")
|
||
async def blackbox(blackbox_name: Union[str, None] = None, request: Request = None):
|
||
if not blackbox_name:
|
||
return JSONResponse(content={"error": "blackbox_name is required"}, status_code=status.HTTP_400_BAD_REQUEST)
|
||
try:
|
||
box = blackbox_factory.get_blackbox(blackbox_name)
|
||
except ValueError as e:
|
||
logger.error(f"获取 blackbox 失败: {blackbox_name} - {e}", exc_info=True)
|
||
return JSONResponse(content={"error": "value error"}, status_code=status.HTTP_400_BAD_REQUEST)
|
||
try:
|
||
response = await box.fast_api_handler(request)
|
||
# 检查响应的状态码,如果 >= 400,则认为是错误响应并记录
|
||
if response.status_code >= 400:
|
||
try:
|
||
decoded_content = response.body.decode('utf-8', errors='ignore')
|
||
logger.error(f"Blackbox 返回错误响应: URL={request.url}, Method={request.method}, Status={response.status_code}, Content={decoded_content}")
|
||
except Exception as body_exc:
|
||
logger.error(f"Blackbox {blackbox_name} 返回错误响应: URL={request.url}, Method={request.method}, Status={response.status_code}, 无法解析响应内容: {body_exc}")
|
||
return response
|
||
except Exception as e:
|
||
logger.error(f"Blackbox 内部抛出异常: URL={request.url}, Method={request.method}, 异常报错: {type(e).__name__}: {e}", exc_info=True)
|
||
return JSONResponse(
|
||
status_code=500,
|
||
content={"message": "Internal Server Error", "detail": "An unexpected error occurred."}
|
||
)
|
||
|
||
# @app.get("/audio/{filename}")
|
||
# async def serve_audio(filename: str):
|
||
# import os
|
||
# # 确保文件存在
|
||
# if os.path.exists(filename):
|
||
# with open(filename, 'rb') as f:
|
||
# audio_data = f.read()
|
||
# if filename.endswith(".mp3"):
|
||
# # 对于 MP3 文件,设置为 inline 以在浏览器中播放
|
||
# return Response(content=audio_data, media_type="audio/mpeg", headers={"Content-Disposition": f"inline; filename={filename}"})
|
||
# elif filename.endswith(".wav"):
|
||
# # 对于 WAV 文件,设置为 inline 以在浏览器中播放
|
||
# return Response(content=audio_data, media_type="audio/wav", headers={"Content-Disposition": f"inline; filename={filename}"})
|
||
# else:
|
||
# return JSONResponse(content={"error": f"{filename} not found"}, status_code=status.HTTP_404_NOT_FOUND)
|
||
|
||
@app.get("/audio/audio_files/{filename}")
|
||
async def serve_audio(filename: str):
|
||
import os
|
||
import aiofiles
|
||
filename = os.path.join("audio_files", filename)
|
||
# 确保文件存在
|
||
if os.path.exists(filename):
|
||
try:
|
||
# 使用 aiofiles 异步读取文件
|
||
async with aiofiles.open(filename, 'rb') as f:
|
||
audio_data = await f.read()
|
||
|
||
# 根据文件类型返回正确的音频响应
|
||
if filename.endswith(".mp3"):
|
||
return Response(content=audio_data, media_type="audio/mpeg", headers={"Content-Disposition": f"inline; filename={filename}"})
|
||
elif filename.endswith(".wav"):
|
||
return Response(content=audio_data, media_type="audio/wav", headers={"Content-Disposition": f"inline; filename={filename}"})
|
||
else:
|
||
return JSONResponse(content={"error": "Unsupported audio format"}, status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE)
|
||
except asyncio.CancelledError:
|
||
# 处理任务被取消的情况
|
||
return JSONResponse(content={"error": "Request was cancelled"}, status_code=status.HTTP_400_BAD_REQUEST)
|
||
except Exception as e:
|
||
# 捕获其他异常
|
||
return JSONResponse(content={"error": str(e)}, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||
else:
|
||
return JSONResponse(content={"error": f"{filename} not found"}, status_code=status.HTTP_404_NOT_FOUND)
|
||
|
||
|
||
# @app.get("/audio/{filename}")
|
||
# async def serve_audio(filename: str):
|
||
# import os
|
||
# file_path = f"audio/{filename}"
|
||
# # 检查文件是否存在
|
||
# if os.path.exists(file_path):
|
||
# return StreamingResponse(open(file_path, "rb"), media_type="audio/mpeg" if filename.endswith(".mp3") else "audio/wav")
|
||
# else:
|
||
# return JSONResponse(content={"error": f"{filename} not found"}, status_code=404) |