Add initial files for Audio Dashboard Management System

- Created .env.example for environment variable configuration.
- Added docker-compose.yml for service orchestration.
- Implemented frequency response extraction in extract_frequency_response.py and convert_to_frequency_db.py.
- Generated output files: frequency_response_detailed.json, frequency_response_points.json, frequency_response.csv, and frequency_response_curve.png.
- Included sample measurement data for FiiO FA19 in CSV format.
This commit is contained in:
yangy
2026-03-17 14:20:08 +08:00
parent 75b1d16453
commit 90aec37461
25 changed files with 7570 additions and 47 deletions
+74 -11
View File
@@ -1,12 +1,18 @@
from fastapi import APIRouter, Depends, HTTPException, Query, Body
from fastapi import APIRouter, Depends, HTTPException, Query, Body, UploadFile, File, Form
from sqlalchemy.orm import Session
from typing import List, Optional
import logging
from database import get_db
from models.model import Model
from schemas import ModelCreate, ModelUpdate, ModelResponse
from response import ApiResponse, PageData
import requests
import os
import shutil
from pathlib import Path
# Configure logging
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/models", tags=["models"])
@@ -15,6 +21,10 @@ MEILISEARCH_URL = os.getenv("MEILISEARCH_URL", "http://localhost:7700")
MEILISEARCH_API_KEY = os.getenv("MEILISEARCH_API_KEY", "")
MEILISEARCH_INDEX = os.getenv("MEILISEARCH_INDEX", "models")
# 文件上传配置
UPLOAD_FOLDER = Path(__file__).parent.parent.parent / "autoeq" / "measurements"
ALLOWED_EXTENSIONS = {'.csv', '.txt', '.json'}
@router.get("/", response_model=ApiResponse)
def get_models(
@@ -26,6 +36,7 @@ def get_models(
):
"""获取所有型号列表(支持按品牌名称和型号名称模糊查询)"""
try:
logger.info(f"Getting models: skip={skip}, limit={limit}, brand_name={brand_name}, name={name}")
query = db.query(Model)
if brand_name:
query = query.filter(Model.brand_name.like(f"%{brand_name}%"))
@@ -35,7 +46,10 @@ def get_models(
total = query.count()
models = query.offset(skip).limit(limit).all()
logger.info(f"Found {len(models)} models, total={total}")
if not models:
logger.warning("No models found")
return ApiResponse(code=2, msg="empty", data=None)
# 转换为字典列表
@@ -43,6 +57,7 @@ def get_models(
return ApiResponse(code=1, msg="success", data={"items": models_data, "total": total, "skip": skip, "limit": limit})
except Exception as e:
logger.error(f"Error getting models: {str(e)}", exc_info=True)
return ApiResponse(code=0, msg="error", data=None)
@@ -50,39 +65,78 @@ def get_models(
def get_model(model_id: int, db: Session = Depends(get_db)):
"""获取单个型号"""
try:
logger.info(f"Getting model: id={model_id}")
model = db.query(Model).filter(Model.id == model_id).first()
if not model:
logger.warning(f"Model not found: id={model_id}")
return ApiResponse(code=2, msg="empty", data=None)
logger.info(f"Model found: {model.to_dict()}")
return ApiResponse(code=1, msg="success", data=model.to_dict())
except Exception as e:
logger.error(f"Error getting model {model_id}: {str(e)}", exc_info=True)
return ApiResponse(code=0, msg="error", data=None)
@router.post("/", response_model=ApiResponse)
def create_model(model: ModelCreate, db: Session = Depends(get_db)):
"""创建新型号"""
def create_model(
brand_name: str = Form(...),
name: str = Form(...),
form: str = Form(None),
rig: str = Form(None),
source: str = Form(None),
eq_key: str = Form(None),
measurement_file: UploadFile = File(None),
db: Session = Depends(get_db)
):
"""创建新型号(支持文件上传)"""
try:
logger.info(f"Creating model: brand_name={brand_name}, name={name}, form={form}, source={source}")
# 检查是否已存在
existing = db.query(Model).filter(
Model.brand_name == model.brand_name,
Model.name == model.name
Model.brand_name == brand_name,
Model.name == name
).first()
if existing:
logger.warning(f"Model already exists: brand_name={brand_name}, name={name}")
return ApiResponse(code=0, msg="该品牌下型号名称已存在", data=None)
# 处理文件上传
measurement_filename = None
if measurement_file and measurement_file.filename:
logger.info(f"Uploading measurement file: {measurement_file.filename}")
# 验证文件扩展名
file_ext = os.path.splitext(measurement_file.filename)[1].lower()
if file_ext not in ALLOWED_EXTENSIONS:
logger.error(f"Unsupported file format: {file_ext}")
return ApiResponse(code=0, msg=f"不支持的文件格式:{file_ext}", data=None)
# 创建保存路径:autoeq/measurements/{source}/data/{form}/{filename}
save_dir = UPLOAD_FOLDER / source / "data" / form
save_dir.mkdir(parents=True, exist_ok=True)
# 保存文件(保留原文件名)
file_path = save_dir / measurement_file.filename
with open(file_path, "wb") as buffer:
shutil.copyfileobj(measurement_file.file, buffer)
measurement_filename = measurement_file.filename
logger.info(f"File saved: {file_path}")
db_model = Model(
brand_name=model.brand_name,
name=model.name,
form=model.form,
rig=model.rig,
source=model.source,
eq_key=model.eq_key
brand_name=brand_name,
name=name,
form=form,
rig=rig,
source=source,
eq_key=eq_key
)
db.add(db_model)
db.commit()
db.refresh(db_model)
logger.info(f"Model created successfully: id={db_model.id}")
return ApiResponse(code=1, msg="success", data=db_model.to_dict())
except Exception as e:
logger.error(f"Error creating model: {str(e)}", exc_info=True)
db.rollback()
return ApiResponse(code=0, msg="error", data=None)
@@ -91,8 +145,10 @@ def create_model(model: ModelCreate, db: Session = Depends(get_db)):
def update_model(model_id: int, model: ModelUpdate, db: Session = Depends(get_db)):
"""更新型号"""
try:
logger.info(f"Updating model: id={model_id}, data={model.dict()}")
db_model = db.query(Model).filter(Model.id == model_id).first()
if not db_model:
logger.warning(f"Model not found: id={model_id}")
return ApiResponse(code=2, msg="empty", data=None)
# 如果更新品牌或型号名称,检查是否冲突
@@ -106,6 +162,7 @@ def update_model(model_id: int, model: ModelUpdate, db: Session = Depends(get_db
Model.name == new_name
).first()
if existing:
logger.warning(f"Model already exists: brand_name={new_brand_name}, name={new_name}")
return ApiResponse(code=0, msg="该品牌下型号名称已存在", data=None)
# 更新字段
@@ -124,8 +181,10 @@ def update_model(model_id: int, model: ModelUpdate, db: Session = Depends(get_db
db.commit()
db.refresh(db_model)
logger.info(f"Model updated successfully: id={db_model.id}")
return ApiResponse(code=1, msg="success", data=db_model.to_dict())
except Exception as e:
logger.error(f"Error updating model {model_id}: {str(e)}", exc_info=True)
db.rollback()
return ApiResponse(code=0, msg="error", data=None)
@@ -134,14 +193,18 @@ def update_model(model_id: int, model: ModelUpdate, db: Session = Depends(get_db
def delete_model(model_id: int, db: Session = Depends(get_db)):
"""删除型号"""
try:
logger.info(f"Deleting model: id={model_id}")
db_model = db.query(Model).filter(Model.id == model_id).first()
if not db_model:
logger.warning(f"Model not found: id={model_id}")
return ApiResponse(code=2, msg="empty", data=None)
db.delete(db_model)
db.commit()
logger.info(f"Model deleted successfully: id={model_id}")
return ApiResponse(code=1, msg="success", data=None)
except Exception as e:
logger.error(f"Error deleting model {model_id}: {str(e)}", exc_info=True)
db.rollback()
return ApiResponse(code=0, msg="error", data=None)