teszenofficial commited on
Commit
603bef4
·
verified ·
1 Parent(s): 48f0b9a

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -161
app.py DELETED
@@ -1,161 +0,0 @@
1
- from fastapi import FastAPI, UploadFile, File, Form
2
- from fastapi.responses import FileResponse
3
- from fastapi.middleware.cors import CORSMiddleware
4
-
5
- import librosa
6
- import numpy as np
7
- from pydub import AudioSegment, effects
8
- import uuid, os, json
9
-
10
- # =====================================================
11
- # APP
12
- # =====================================================
13
-
14
- app = FastAPI(title="MONX DJ API")
15
-
16
- app.add_middleware(
17
- CORSMiddleware,
18
- allow_origins=["*"],
19
- allow_methods=["*"],
20
- allow_headers=["*"],
21
- )
22
-
23
- # =====================================================
24
- # PATHS
25
- # =====================================================
26
-
27
- STATE_PATH = "monx_dj_state.json"
28
- UPLOAD_DIR = "uploads"
29
- OUTPUT_DIR = "outputs"
30
-
31
- os.makedirs(UPLOAD_DIR, exist_ok=True)
32
- os.makedirs(OUTPUT_DIR, exist_ok=True)
33
-
34
- # =====================================================
35
- # STATE
36
- # =====================================================
37
-
38
- DEFAULT_STATE = {
39
- "weights": {
40
- "bpm": 0.35,
41
- "energy": 0.30,
42
- "smooth": 0.20,
43
- "drop_penalty": 0.15
44
- },
45
- "avg_score": 0.5,
46
- "runs": 0
47
- }
48
-
49
- def load_state():
50
- if os.path.exists(STATE_PATH):
51
- with open(STATE_PATH, "r") as f:
52
- return json.load(f)
53
- return DEFAULT_STATE.copy()
54
-
55
- def save_state(state):
56
- with open(STATE_PATH, "w") as f:
57
- json.dump(state, f, indent=2)
58
-
59
- state = load_state()
60
- weights = state["weights"]
61
-
62
- # =====================================================
63
- # AUDIO ANALYSIS
64
- # =====================================================
65
-
66
- def analyze_audio(path):
67
- y, sr = librosa.load(path, mono=True)
68
- onset_env = librosa.onset.onset_strength(y=y, sr=sr)
69
-
70
- try:
71
- tempo = float(librosa.beat.tempo(onset_envelope=onset_env, sr=sr)[0])
72
- except:
73
- tempo = 120.0
74
-
75
- rms = librosa.feature.rms(y=y)[0]
76
- rms = librosa.util.normalize(rms)
77
-
78
- drops = [
79
- i for i in range(10, len(rms) - 10)
80
- if rms[i] > np.mean(rms[i-10:i-1]) * 1.4
81
- ]
82
-
83
- return {"tempo": tempo, "energy": rms, "drops": drops}
84
-
85
- # =====================================================
86
- # CORE LOGIC
87
- # =====================================================
88
-
89
- def score_transition(a, b, t):
90
- bpm_sim = max(0, 1 - abs(a["tempo"] - b["tempo"]) / 35)
91
- energy_sim = max(0, 1 - abs(a["energy"][t] - b["energy"][0]))
92
- drop_penalty = 1 if t in a["drops"] else 0
93
-
94
- return (
95
- weights["bpm"] * bpm_sim +
96
- weights["energy"] * energy_sim +
97
- weights["smooth"] * ((bpm_sim + energy_sim) / 2) -
98
- weights["drop_penalty"] * drop_penalty
99
- )
100
-
101
- def bpm_adjust(segment, from_bpm, to_bpm):
102
- ratio = from_bpm / to_bpm if from_bpm > 0 and to_bpm > 0 else 1
103
- if abs(1 - ratio) > 0.20:
104
- return segment
105
- new_rate = int(segment.frame_rate * ratio)
106
- return segment._spawn(
107
- segment.raw_data,
108
- overrides={"frame_rate": new_rate}
109
- ).set_frame_rate(segment.frame_rate)
110
-
111
- # =====================================================
112
- # API ENDPOINT
113
- # =====================================================
114
-
115
- @app.post("/mix")
116
- async def mix(
117
- files: list[UploadFile] = File(...),
118
- durations: str = Form("90,90"),
119
- crossfade_sec: int = Form(12)
120
- ):
121
- durs = [float(x.strip()) for x in durations.split(",")]
122
- tracks, analyses = [], []
123
-
124
- for f in files:
125
- path = os.path.join(UPLOAD_DIR, f"{uuid.uuid4().hex}_{f.filename}")
126
- with open(path, "wb") as out:
127
- out.write(await f.read())
128
-
129
- audio = effects.normalize(AudioSegment.from_file(path))
130
- tracks.append(audio)
131
- analyses.append(analyze_audio(path))
132
-
133
- mix = AudioSegment.silent(0)
134
-
135
- for i in range(len(tracks)):
136
- segment = tracks[i][:int(durs[i] * 1000)]
137
- if i == 0:
138
- mix = segment
139
- continue
140
-
141
- prev, curr = analyses[i - 1], analyses[i]
142
- best_t = max(
143
- range(5, min(len(prev["energy"]) - 1, 50)),
144
- key=lambda t: score_transition(prev, curr, t)
145
- )
146
-
147
- mix = mix.append(segment, crossfade=int(crossfade_sec * 1000))
148
-
149
- out_path = os.path.join(
150
- OUTPUT_DIR, f"monx_mix_{uuid.uuid4().hex}.m4a"
151
- )
152
- mix.export(out_path, format="ipod", codec="aac", bitrate="192k")
153
-
154
- state["runs"] += 1
155
- save_state(state)
156
-
157
- return FileResponse(
158
- out_path,
159
- media_type="audio/mp4",
160
- filename="monx_mix.m4a"
161
- )