Hal Swift commited on
Commit
a6e7a4b
·
1 Parent(s): de5bdb8

Deploy v1.37

Browse files
Files changed (3) hide show
  1. Dockerfile +5 -6
  2. app.py +37 -88
  3. requirements.txt +6 -6
Dockerfile CHANGED
@@ -1,6 +1,6 @@
1
- # [Forge Log #75] Build v1.36 - Isolated Crepe Installation
2
- # Isolating 'crepe' to bypass network timeouts during requirement sweeps.
3
- ARG CACHE_BUSTER=20251219082000
4
 
5
  FROM python:3.8-slim-bullseye
6
 
@@ -13,15 +13,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends libsndfile-
13
 
14
  RUN mkdir -p /tmp/.crepe
15
 
16
- RUN mkdir /models /models_tmp && echo "--- [1/6] Downloading Model ---" && wget -O /models/model.zip https://storage.googleapis.com/ddsp-inv/ckpts/synthetic_pretrained_ckpt.zip && echo "--- [2/6] Unzipping Model ---" && unzip /models/model.zip -d /models_tmp && echo "--- [3/6] Moving model files to root directory ---" && mv /models_tmp/usr/local/google/home/jesseengel/Desktop/pretrained_ckpt/* /models/ && echo "--- [4/6] Cleaning up temporary files ---" && rm -rf /models_tmp && rm /models/model.zip && echo "--- [5/6] Verifying Final Model Files ---" && ls -lR /models && echo "--- [6/6] Model setup complete. ---"
17
 
18
- RUN pip install --no-cache-dir --upgrade pip setuptools wheel && pip install --no-cache-dir crepe==0.0.16 resampy==0.2.2
19
 
20
  COPY requirements.txt requirements.txt
21
  RUN pip install --no-cache-dir -r requirements.txt
22
 
23
  COPY app.py /code/app.py
24
- RUN echo "--- Verifying App Code ---" && ls -l /code
25
 
26
  EXPOSE 7860
27
 
 
1
+ # [Forge Log #76] Build v1.37 - Purged Crepe Recursion
2
+ # Refreshed cache and synchronized numpy version in the isolated layer.
3
+ ARG CACHE_BUSTER=20251219114500
4
 
5
  FROM python:3.8-slim-bullseye
6
 
 
13
 
14
  RUN mkdir -p /tmp/.crepe
15
 
16
+ RUN mkdir /models /models_tmp && wget -O /models/model.zip https://storage.googleapis.com/ddsp-inv/ckpts/synthetic_pretrained_ckpt.zip && unzip /models/model.zip -d /models_tmp && mv /models_tmp/usr/local/google/home/jesseengel/Desktop/pretrained_ckpt/* /models/ && rm -rf /models_tmp && rm /models/model.zip
17
 
18
+ RUN pip install --no-cache-dir --upgrade pip setuptools wheel && pip install --no-cache-dir numpy<1.24 crepe==0.0.16 resampy==0.2.2
19
 
20
  COPY requirements.txt requirements.txt
21
  RUN pip install --no-cache-dir -r requirements.txt
22
 
23
  COPY app.py /code/app.py
 
24
 
25
  EXPOSE 7860
26
 
app.py CHANGED
@@ -1,13 +1,11 @@
1
- # [Forge Log #75] The Canary Banner v1.36
2
- # 'Vanguard Iota' Protocol - Deep-Path Synthesis Targeting.
3
- # Specifically hunts for .ae.decoder and .ae.processor_group sub-objects.
4
- print("--- [CANARY] DecentSampler DDSP Server v1.36 ---")
5
  print("--- [CANARY] Executing Verified Production App ---")
6
 
7
  import os
8
- # CRITICAL: This must be run BEFORE any other imports that might use numba.
9
  os.environ['NUMBA_DISABLE_JIT_CACHE'] = '1'
10
- print("--- [CANARY] Numba JIT Cache programmatically disabled. ---")
11
 
12
  import logging
13
  import importlib
@@ -16,13 +14,10 @@ import importlib_metadata
16
  import types
17
  import sys
18
 
19
- # [Forge Log #47] Monkey-patch missing attribute in Python 3.8
20
  if not hasattr(importlib.metadata, 'packages_distributions'):
21
  try:
22
  importlib.metadata.packages_distributions = importlib_metadata.packages_distributions
23
- print("--- [CANARY] importlib.metadata monkey-patched for Python 3.8 compatibility. ---")
24
- except Exception as e:
25
- print(f"--- [CANARY] Metadata patch failed: {e} ---")
26
 
27
  from fastapi import FastAPI, HTTPException
28
  from fastapi.responses import Response
@@ -35,47 +30,31 @@ import ddsp.training
35
  from scipy.io.wavfile import write as write_wav
36
  import io
37
 
38
- # --- Version Diagnostics ---
39
- try:
40
- print(f"DDSP Version: {ddsp.__version__}")
41
- print(f"TensorFlow Version: {tf.__version__}")
42
- except Exception as e:
43
- print(f"Error during version printing: {e}")
44
-
45
- # --- TAE Identification Ladder ---
46
- TAE_CLASS = None
47
-
48
  def find_tae():
49
  try:
50
  import ddsp.training.models.midi_autoencoder as ma
51
- if hasattr(ma, 'MidiAutoencoder'):
52
- print("--- [CANARY] TAE Ladder 1: Found MidiAutoencoder")
53
- return ma.MidiAutoencoder
54
  except: pass
55
  try:
56
  import ddsp.training.models as m
57
- if hasattr(m, 'TranscribingAutoencoder'):
58
- print("--- [CANARY] TAE Ladder 2: Found in ddsp.training.models")
59
- return m.TranscribingAutoencoder
60
  except: pass
61
  return None
62
 
63
  TAE_CLASS = find_tae()
64
 
65
- # --- Note Synth 'Vanguard' Ladder [Forge Log #75] ---
66
- NOTE_SYNTH_FN = None
67
-
68
  def find_note_synth():
69
  target = 'note_expression_synthesis'
70
  try:
71
  import ddsp.training.models.midi_autoencoder as ma
72
  if hasattr(ma, target):
73
- print(f"--- [CANARY] Synth Ladder 1: Found functional '{target}'")
74
  return lambda model, pitches, note_lengths, **kwargs: getattr(ma, target)(model, pitches, note_lengths, **kwargs)
75
  except: pass
76
 
77
- def vanguard_synth_wrapper(model, pitches, note_lengths, **kwargs):
78
- """Iota Protocol: Deep-path targeting for 1.6.5 Gin proxies."""
79
  p_tensor = tf.convert_to_tensor(pitches, dtype=tf.float32)
80
  l_tensor = tf.convert_to_tensor(note_lengths, dtype=tf.float32)
81
  midi_dicts = [
@@ -83,20 +62,13 @@ def find_note_synth():
83
  {'midi': {'pitch': p_tensor, 'duration': l_tensor}},
84
  {'inputs': {'pitch': p_tensor, 'duration': l_tensor}}
85
  ]
86
- methods_to_try = ['midi_to_audio', 'decode', 'synthesize_audio', 'synthesize', 'call', '__call__']
87
- objects_to_probe = []
88
- if model:
89
- objects_to_probe.append(model)
90
- for layer1 in ['ae', 'decoder', 'processor_group', 'nn']:
91
- if hasattr(model, layer1):
92
- obj1 = getattr(model, layer1)
93
- objects_to_probe.append(obj1)
94
- for layer2 in ['decoder', 'processor_group', 'ae']:
95
- if hasattr(obj1, layer2):
96
- obj2 = getattr(obj1, layer2)
97
- objects_to_probe.append(obj2)
98
-
99
- for obj in objects_to_probe:
100
  for name in methods_to_try:
101
  method = getattr(obj, name, None)
102
  if method and callable(method):
@@ -109,18 +81,17 @@ def find_note_synth():
109
  except:
110
  try: return method(p_tensor, l_tensor)
111
  except: pass
112
- if callable(model):
113
- for m_dict in midi_dicts:
114
- try: return model(m_dict, training=False)
115
- except: pass
116
- print(f"--- [CANARY] CRITICAL: Discovery failed. Type: {type(model)}")
117
- print(f"Model Attributes: {dir(model)}")
118
- raise AttributeError(f"Vanguard Iota failure: No synthesis path found.")
119
-
120
- print("--- [CANARY] Vanguard: Discovery initialized via Vanguard V11 (Iota).")
121
- return vanguard_synth_wrapper
122
-
123
- print("--- [CANARY] Initiating Vanguard discovery... ---")
124
  NOTE_SYNTH_FN = find_note_synth()
125
 
126
  # --- Global Setup ---
@@ -128,60 +99,44 @@ logging.basicConfig(level=logging.INFO)
128
  logger = logging.getLogger(__name__)
129
  app = FastAPI()
130
 
131
- # --- Model Loading ---
132
  MODEL_DIR = '/models'
133
  LATEST_CHECKPOINT = tf.train.latest_checkpoint(MODEL_DIR)
134
 
135
- if not LATEST_CHECKPOINT:
136
- raise RuntimeError(f"Could not find model checkpoint in {MODEL_DIR}")
137
-
138
  try:
139
- logger.info(f"Loading DDSP model from: {LATEST_CHECKPOINT}...")
140
  try:
141
  gin.register(TAE_CLASS, 'TranscribingAutoencoder', namespace='models')
142
- except TypeError:
143
  gin.register(TAE_CLASS, 'models.TranscribingAutoencoder')
144
  gin_file = os.path.join(MODEL_DIR, 'operative_config-0.gin')
145
  gin.parse_config_file(gin_file, skip_unknown=True)
146
  model = TAE_CLASS()
147
  model.restore(LATEST_CHECKPOINT)
148
- logger.info(f"DDSP model restored. Class: {model.__class__.__name__}")
149
  except Exception as e:
150
- logger.error(f"!!! CRITICAL: Model Load Failure: {e}", exc_info=True)
151
  raise
152
 
153
- # --- API Data Models ---
154
  class NoteRequest(BaseModel):
155
  instrument: str = "DDSP_Synth"
156
  note: str
157
  duration: float = 2.0
158
  seed: int = -1
159
 
160
- # --- Helper Functions ---
161
  def note_to_midi(note_name: str) -> float:
162
  note_names = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
163
  try:
164
  note = note_name[:-1].upper()
165
  octave = int(note_name[-1])
166
- if '#' in note:
167
- base_note = note.replace('#', '')
168
- semitone = note_names.index(base_note) + 1
169
- else:
170
- semitone = note_names.index(note)
171
- midi_pitch = semitone + (octave + 1) * 12
172
  return float(midi_pitch)
173
- except Exception:
174
- raise ValueError(f"Invalid note format: '{note_name}'")
175
 
176
- # --- API Endpoints ---
177
  @app.get("/")
178
  def read_root():
179
- return {"message": "DDSP Server Online", "canary": "v1.36"}
180
 
181
  @app.post("/generate-note")
182
  async def generate_note(request: NoteRequest):
183
  try:
184
- logger.info(f"Generating note: {request.note}")
185
  pitch = note_to_midi(request.note)
186
  audio = NOTE_SYNTH_FN(
187
  model=model,
@@ -194,18 +149,12 @@ async def generate_note(request: NoteRequest):
194
  if key in audio:
195
  audio = audio[key]
196
  break
197
- if hasattr(audio, 'numpy'):
198
- audio = audio.numpy()
199
  audio_squeeze = audio.squeeze()
200
  audio_int16 = np.int16(audio_squeeze * 32767)
201
  wav_io = io.BytesIO()
202
  write_wav(wav_io, 16000, audio_int16)
203
  wav_io.seek(0)
204
- return Response(
205
- content=wav_io.getvalue(),
206
- media_type="audio/wav",
207
- headers={"Content-Disposition": f'attachment; filename="{request.instrument}_{request.note}.wav"'}
208
- )
209
  except Exception as e:
210
- logger.error(f"Synthesis error: {e}", exc_info=True)
211
- raise HTTPException(status_code=500, detail=f"[Vanguard V1.36] {str(e)}")
 
1
+ # [Forge Log #76] The Canary Banner v1.37
2
+ # 'Vanguard Kappa' Protocol - Atomic Synthesis Discovery.
3
+ # Final brute-force probe to locate synthesis paths in MidiAutoencoder.
4
+ print("--- [CANARY] DecentSampler DDSP Server v1.37 ---")
5
  print("--- [CANARY] Executing Verified Production App ---")
6
 
7
  import os
 
8
  os.environ['NUMBA_DISABLE_JIT_CACHE'] = '1'
 
9
 
10
  import logging
11
  import importlib
 
14
  import types
15
  import sys
16
 
 
17
  if not hasattr(importlib.metadata, 'packages_distributions'):
18
  try:
19
  importlib.metadata.packages_distributions = importlib_metadata.packages_distributions
20
+ except: pass
 
 
21
 
22
  from fastapi import FastAPI, HTTPException
23
  from fastapi.responses import Response
 
30
  from scipy.io.wavfile import write as write_wav
31
  import io
32
 
33
+ # --- TAE Identification ---
 
 
 
 
 
 
 
 
 
34
  def find_tae():
35
  try:
36
  import ddsp.training.models.midi_autoencoder as ma
37
+ return ma.MidiAutoencoder
 
 
38
  except: pass
39
  try:
40
  import ddsp.training.models as m
41
+ return m.TranscribingAutoencoder
 
 
42
  except: pass
43
  return None
44
 
45
  TAE_CLASS = find_tae()
46
 
47
+ # --- Atomic Synth 'Vanguard' Ladder [Forge Log #76] ---
 
 
48
  def find_note_synth():
49
  target = 'note_expression_synthesis'
50
  try:
51
  import ddsp.training.models.midi_autoencoder as ma
52
  if hasattr(ma, target):
 
53
  return lambda model, pitches, note_lengths, **kwargs: getattr(ma, target)(model, pitches, note_lengths, **kwargs)
54
  except: pass
55
 
56
+ def atomic_synth_wrapper(model, pitches, note_lengths, **kwargs):
57
+ """Kappa Protocol: Multi-tier brute force probe."""
58
  p_tensor = tf.convert_to_tensor(pitches, dtype=tf.float32)
59
  l_tensor = tf.convert_to_tensor(note_lengths, dtype=tf.float32)
60
  midi_dicts = [
 
62
  {'midi': {'pitch': p_tensor, 'duration': l_tensor}},
63
  {'inputs': {'pitch': p_tensor, 'duration': l_tensor}}
64
  ]
65
+ methods_to_try = ['midi_to_audio', 'decode', 'synthesize', 'synthesize_audio', 'call', '__call__', 'predict']
66
+ objs = [model]
67
+ for sub in ['ae', 'decoder', 'processor_group', 'nn']:
68
+ if hasattr(model, sub):
69
+ objs.append(getattr(model, sub))
70
+
71
+ for obj in objs:
 
 
 
 
 
 
 
72
  for name in methods_to_try:
73
  method = getattr(obj, name, None)
74
  if method and callable(method):
 
81
  except:
82
  try: return method(p_tensor, l_tensor)
83
  except: pass
84
+ for obj in objs:
85
+ for attr_name in dir(obj):
86
+ attr = getattr(obj, attr_name)
87
+ if callable(attr) and not attr_name.startswith('_'):
88
+ for m_dict in midi_dicts:
89
+ try: return attr(m_dict)
90
+ except: pass
91
+ raise AttributeError(f"Vanguard Kappa Failure: No synthesis entry point in {type(model)}")
92
+
93
+ return atomic_synth_wrapper
94
+
 
95
  NOTE_SYNTH_FN = find_note_synth()
96
 
97
  # --- Global Setup ---
 
99
  logger = logging.getLogger(__name__)
100
  app = FastAPI()
101
 
 
102
  MODEL_DIR = '/models'
103
  LATEST_CHECKPOINT = tf.train.latest_checkpoint(MODEL_DIR)
104
 
 
 
 
105
  try:
 
106
  try:
107
  gin.register(TAE_CLASS, 'TranscribingAutoencoder', namespace='models')
108
+ except:
109
  gin.register(TAE_CLASS, 'models.TranscribingAutoencoder')
110
  gin_file = os.path.join(MODEL_DIR, 'operative_config-0.gin')
111
  gin.parse_config_file(gin_file, skip_unknown=True)
112
  model = TAE_CLASS()
113
  model.restore(LATEST_CHECKPOINT)
 
114
  except Exception as e:
115
+ logger.error(f"Model Load Failure: {e}", exc_info=True)
116
  raise
117
 
 
118
  class NoteRequest(BaseModel):
119
  instrument: str = "DDSP_Synth"
120
  note: str
121
  duration: float = 2.0
122
  seed: int = -1
123
 
 
124
  def note_to_midi(note_name: str) -> float:
125
  note_names = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
126
  try:
127
  note = note_name[:-1].upper()
128
  octave = int(note_name[-1])
129
+ midi_pitch = note_names.index(note) + (octave + 1) * 12
 
 
 
 
 
130
  return float(midi_pitch)
131
+ except: raise ValueError(f"Invalid note: '{note_name}'")
 
132
 
 
133
  @app.get("/")
134
  def read_root():
135
+ return {"message": "DDSP Server Online", "canary": "v1.37"}
136
 
137
  @app.post("/generate-note")
138
  async def generate_note(request: NoteRequest):
139
  try:
 
140
  pitch = note_to_midi(request.note)
141
  audio = NOTE_SYNTH_FN(
142
  model=model,
 
149
  if key in audio:
150
  audio = audio[key]
151
  break
152
+ if hasattr(audio, 'numpy'): audio = audio.numpy()
 
153
  audio_squeeze = audio.squeeze()
154
  audio_int16 = np.int16(audio_squeeze * 32767)
155
  wav_io = io.BytesIO()
156
  write_wav(wav_io, 16000, audio_int16)
157
  wav_io.seek(0)
158
+ return Response(content=wav_io.getvalue(), media_type="audio/wav")
 
 
 
 
159
  except Exception as e:
160
+ raise HTTPException(status_code=500, detail=f"[Vanguard V1.37] {str(e)}")
 
requirements.txt CHANGED
@@ -1,19 +1,19 @@
1
- # [Forge Log #46] Golden Set Requirements v1.3
2
- # Added importlib-metadata to resolve Python 3.8 compatibility warning.
 
3
 
4
  fastapi
5
  uvicorn[standard]
6
 
7
- # The "golden set" that resolves the installation issues.
8
  ddsp==1.6.5
9
  hmmlearn==0.2.7
10
- crepe
11
 
12
- # Other critical dependencies identified during server debugging.
13
  numpy<1.24
14
  librosa==0.8.0
15
  numba==0.49.1
16
  tensorflow-cpu==2.12.0
17
  tensorflow-probability==0.19.0
18
  scipy
19
- importlib-metadata # [Forge Log #46] Fix metadata attribute error
 
1
+ # [Forge Log #76] Requirements v1.4
2
+ # CRITICAL: 'crepe' REMOVED to prevent backtracking build errors.
3
+ # 'crepe' is now handled exclusively in the isolated Docker layer.
4
 
5
  fastapi
6
  uvicorn[standard]
7
 
8
+ # The "golden set" for DDSP 1.6.5
9
  ddsp==1.6.5
10
  hmmlearn==0.2.7
 
11
 
12
+ # Core dependencies
13
  numpy<1.24
14
  librosa==0.8.0
15
  numba==0.49.1
16
  tensorflow-cpu==2.12.0
17
  tensorflow-probability==0.19.0
18
  scipy
19
+ importlib-metadata