crowncode-backend / app /schemas.py
Rthur2003's picture
feat: remix ve Multitrack API uç noktaları ile rate limiting ve Pydantic schema doğrulama eklendi
26c0314
Raw History Blame Contribute Delete
6.69 kB
"""
Pydantic schemas for YouTube analysis endpoints.
"""
from __future__ import annotations
from typing import Dict, List, Literal, Optional
from pydantic import BaseModel, Field
class YouTubeAnalyzeRequest(BaseModel):
url: str = Field(..., description="YouTube video URL")
include_raw: bool = Field(
default=False,
description="Include raw service responses in output",
)
class YouTubeSource(BaseModel):
url: str
normalized_url: str
video_id: str
start_time_sec: Optional[int] = None
title: Optional[str] = None
duration_sec: Optional[float] = None
audio_format: Optional[str] = None
class AnalysisSummary(BaseModel):
"""Summary of AI detection result."""
is_ai_generated: bool
confidence: float = Field(..., ge=0.0, le=1.0)
decision_source: str
model_version: str
indicators: List[str]
class ServiceResult(BaseModel):
available: bool
response: Optional[Dict[str, object]] = None
error: Optional[str] = None
class YouTubeAnalyzeResponse(BaseModel):
request_id: str
status: Literal["ok", "partial"]
source: YouTubeSource
summary: AnalysisSummary
music_ai: ServiceResult
ses_analizi: ServiceResult
warnings: List[str]
errors: List[str]
timings: Dict[str, float]
class AudioAugmentationOptions(BaseModel):
model_config = {"populate_by_name": True}
pitch_shift: bool = Field(default=False, alias="pitchShift", description="Apply random pitch shifting")
speed_change: bool = Field(default=False, alias="speedChange", description="Apply random speed change")
bass_boost: bool = Field(default=False, alias="bassBoost", description="Apply bass boost equalization")
trim_silence: bool = Field(default=False, alias="trimSilence", description="Trim leading and trailing silence")
mix_audio: bool = Field(default=False, alias="mixAudio", description="Mix with a second uploaded audio track")
add_noise: bool = Field(default=False, alias="addNoise", description="Add Gaussian noise")
AudioTargetFormat = Literal["wav", "mp3", "flac", "ogg"]
class AudioConvertOptions(BaseModel):
model_config = {"populate_by_name": True}
target_format: AudioTargetFormat = Field(
default="wav", alias="targetFormat", description="Output container/codec to convert to"
)
bitrate_kbps: int = Field(
default=192, alias="bitrateKbps", ge=64, le=320,
description="Target bitrate for lossy formats (mp3/ogg); ignored for wav/flac"
)
class DatasetEntryMetadata(BaseModel):
model_config = {"populate_by_name": True}
duration_sec: float = Field(alias="durationSec")
tempo_bpm: float = Field(alias="tempoBpm")
key: str
loudness_db: float = Field(alias="loudnessDb")
tags: List[str]
class DreamAnalysisRequest(BaseModel):
dream_text: str = Field(..., alias="dreamText", min_length=1, max_length=4000)
language: str = Field(default="English", description="Output language for the interpretation")
model_config = {"populate_by_name": True}
class DreamAnalysisResponse(BaseModel):
model_config = {"populate_by_name": True}
emotions: List[str]
themes: List[str]
symbols: List[str]
interpretation: str
lucidity_indicator: bool = Field(alias="lucidityIndicator")
RemixCrossfadeCurve = Literal["equal_power", "linear"]
class RemixOptions(BaseModel):
"""Options for the Creator Studio AI Remix engine — auto tempo/key
matching plus a crossfade blend between two uploaded tracks."""
model_config = {"populate_by_name": True}
match_tempo: bool = Field(
default=True, alias="matchTempo",
description="Time-stretch the second track to the first track's detected BPM"
)
match_key: bool = Field(
default=False, alias="matchKey",
description="Pitch-shift the second track to the first track's detected key"
)
crossfade_seconds: float = Field(
default=4.0, alias="crossfadeSeconds", ge=0.5, le=30.0,
description="Length of the crossfade transition between the two tracks"
)
crossfade_curve: RemixCrossfadeCurve = Field(
default="equal_power", alias="crossfadeCurve",
description="Crossfade power curve — equal_power avoids a volume dip at the midpoint"
)
class RemixAnalysis(BaseModel):
"""Reports what the remix engine actually detected/did to each track,
so the UI can show real numbers instead of a black box."""
model_config = {"populate_by_name": True}
track_a_bpm: float = Field(alias="trackABpm")
track_b_bpm: float = Field(alias="trackBBpm")
track_a_key: str = Field(alias="trackAKey")
track_b_key: str = Field(alias="trackBKey")
applied_stretch_rate: float = Field(alias="appliedStretchRate")
applied_pitch_shift_semitones: float = Field(alias="appliedPitchShiftSemitones")
output_duration_sec: float = Field(alias="outputDurationSec")
class MultitrackChannelSettings(BaseModel):
"""Per-track mix settings for the Creator Studio Multitrack mixer.
Index-matched to the uploaded files (channel 0 -> first file, etc.)."""
model_config = {"populate_by_name": True}
gain_db: float = Field(
default=0.0, alias="gainDb", ge=-60.0, le=12.0,
description="Gain applied to this track before mixing, in dB"
)
pan: float = Field(
default=0.0, ge=-1.0, le=1.0,
description="Stereo position: -1.0 full left, 0.0 center, 1.0 full right"
)
muted: bool = Field(default=False, description="Exclude this track from the mix entirely")
class MultitrackOptions(BaseModel):
model_config = {"populate_by_name": True}
channels: List[MultitrackChannelSettings] = Field(
default_factory=list,
description="Per-track settings, index-matched to the uploaded files"
)
normalize_output: bool = Field(
default=True, alias="normalizeOutput",
description="Peak-normalize the final mix to prevent clipping"
)
class MultitrackChannelReport(BaseModel):
"""What actually happened to one channel during mixdown."""
model_config = {"populate_by_name": True}
index: int
duration_sec: float = Field(alias="durationSec")
applied_gain_db: float = Field(alias="appliedGainDb")
pan: float
muted: bool
peak_level: float = Field(alias="peakLevel")
class MultitrackAnalysis(BaseModel):
model_config = {"populate_by_name": True}
channels: List[MultitrackChannelReport]
output_duration_sec: float = Field(alias="outputDurationSec")
output_peak_level: float = Field(alias="outputPeakLevel")
clipping_prevented: bool = Field(alias="clippingPrevented")