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
+26
View File
@@ -1,11 +1,15 @@
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import List, Optional
import logging
from database import get_db
from models.brand import Brand
from schemas import BrandCreate, BrandUpdate, BrandResponse
from response import ApiResponse, PageData
# Configure logging
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/brands", tags=["brands"])
@@ -18,6 +22,7 @@ def get_brands(
):
"""获取所有品牌列表(支持按名称模糊查询)"""
try:
logger.info(f"Getting brands: skip={skip}, limit={limit}, name={name}")
query = db.query(Brand)
if name:
query = query.filter(Brand.name.like(f"%{name}%"))
@@ -25,7 +30,10 @@ def get_brands(
total = query.count()
brands = query.offset(skip).limit(limit).all()
logger.info(f"Found {len(brands)} brands, total={total}")
if not brands:
logger.warning("No brands found")
return ApiResponse(code=2, msg="empty", data=None)
# 转换为字典列表
@@ -33,6 +41,7 @@ def get_brands(
return ApiResponse(code=1, msg="success", data={"items": brands_data, "total": total, "skip": skip, "limit": limit})
except Exception as e:
logger.error(f"Error getting brands: {str(e)}", exc_info=True)
return ApiResponse(code=0, msg="error", data=None)
@@ -40,11 +49,15 @@ def get_brands(
def get_brand(brand_id: int, db: Session = Depends(get_db)):
"""获取单个品牌"""
try:
logger.info(f"Getting brand: id={brand_id}")
brand = db.query(Brand).filter(Brand.id == brand_id).first()
if not brand:
logger.warning(f"Brand not found: id={brand_id}")
return ApiResponse(code=2, msg="empty", data=None)
logger.info(f"Brand found: {brand.to_dict()}")
return ApiResponse(code=1, msg="success", data=brand.to_dict())
except Exception as e:
logger.error(f"Error getting brand {brand_id}: {str(e)}", exc_info=True)
return ApiResponse(code=0, msg="error", data=None)
@@ -52,17 +65,21 @@ def get_brand(brand_id: int, db: Session = Depends(get_db)):
def create_brand(brand: BrandCreate, db: Session = Depends(get_db)):
"""创建新品牌"""
try:
logger.info(f"Creating brand: name={brand.name}")
# 检查是否已存在
existing = db.query(Brand).filter(Brand.name == brand.name).first()
if existing:
logger.warning(f"Brand already exists: name={brand.name}")
return ApiResponse.error(msg="品牌名称已存在", code=0)
db_brand = Brand(name=brand.name)
db.add(db_brand)
db.commit()
db.refresh(db_brand)
logger.info(f"Brand created successfully: id={db_brand.id}, name={db_brand.name}")
return ApiResponse.success(data=db_brand.to_dict(), msg="品牌创建成功")
except Exception as e:
logger.error(f"Error creating brand: {str(e)}", exc_info=True)
db.rollback()
return ApiResponse.error(msg=f"创建失败:{str(e)}", code=0)
@@ -71,21 +88,26 @@ def create_brand(brand: BrandCreate, db: Session = Depends(get_db)):
def update_brand(brand_id: int, brand: BrandUpdate, db: Session = Depends(get_db)):
"""更新品牌"""
try:
logger.info(f"Updating brand: id={brand_id}, data={brand.dict()}")
db_brand = db.query(Brand).filter(Brand.id == brand_id).first()
if not db_brand:
logger.warning(f"Brand not found: id={brand_id}")
return ApiResponse.no_data(msg="品牌不存在")
# 如果更新名称,检查是否冲突
if brand.name and brand.name != db_brand.name:
existing = db.query(Brand).filter(Brand.name == brand.name).first()
if existing:
logger.warning(f"Brand name already exists: name={brand.name}")
return ApiResponse.error(msg="品牌名称已存在", code=0)
db_brand.name = brand.name
db.commit()
db.refresh(db_brand)
logger.info(f"Brand updated successfully: id={db_brand.id}")
return ApiResponse.success(data=db_brand.to_dict(), msg="品牌更新成功")
except Exception as e:
logger.error(f"Error updating brand {brand_id}: {str(e)}", exc_info=True)
db.rollback()
return ApiResponse.error(msg=f"更新失败:{str(e)}", code=0)
@@ -94,13 +116,17 @@ def update_brand(brand_id: int, brand: BrandUpdate, db: Session = Depends(get_db
def delete_brand(brand_id: int, db: Session = Depends(get_db)):
"""删除品牌"""
try:
logger.info(f"Deleting brand: id={brand_id}")
db_brand = db.query(Brand).filter(Brand.id == brand_id).first()
if not db_brand:
logger.warning(f"Brand not found: id={brand_id}")
return ApiResponse.no_data(msg="品牌不存在")
db.delete(db_brand)
db.commit()
logger.info(f"Brand deleted successfully: id={brand_id}")
return ApiResponse.success(msg="删除成功")
except Exception as e:
logger.error(f"Error deleting brand {brand_id}: {str(e)}", exc_info=True)
db.rollback()
return ApiResponse.error(msg=f"删除失败:{str(e)}", code=0)
+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)