File size: 17,478 Bytes
6b46d68 7aaa922 6b46d68 7aaa922 6756b6d 7aaa922 45d6cf1 7aaa922 6756b6d 7aaa922 6756b6d 7aaa922 6756b6d 45d6cf1 7aaa922 6756b6d 7aaa922 45d6cf1 7aaa922 6756b6d 7aaa922 6756b6d 7aaa922 6756b6d 7aaa922 6756b6d 7aaa922 6756b6d 7aaa922 45d6cf1 7aaa922 6756b6d 7aaa922 45d6cf1 6756b6d 7aaa922 45d6cf1 7aaa922 6b46d68 7aaa922 6b46d68 7aaa922 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | #!/usr/bin/env python3
"""AFIP v3 - Acoustic Flatulence Intelligence Platform"""
import os, time, json, hashlib, struct, sqlite3, tempfile, wave
from pathlib import Path
from datetime import datetime, timezone
from typing import List, Tuple
import numpy as np
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.staticfiles import StaticFiles
from fastapi.responses import JSONResponse, FileResponse
from fastapi.middleware.cors import CORSMiddleware
DB = Path(os.getenv("DATABASE_PATH", "./afip.db"))
OUTPUT = Path("./output"); OUTPUT.mkdir(exist_ok=True)
B58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
def b58(v: bytes) -> str:
n = int.from_bytes(v, "big")
if n == 0: return B58[0]
s = ""
while n: n, r = divmod(n, 58); s = B58[r] + s
return s
# ββ SMF MIDI Writer ββ
class SMF:
def __init__(self, tpq=480):
self.tpq = tpq; self.tracks: List[List[Tuple[int, bytes]]] = []
def add(self) -> int: self.tracks.append([]); return len(self.tracks)-1
def _vlq(self, v: int) -> bytes:
buf = [v & 0x7F]; v >>= 7
while v: buf.append((v & 0x7F) | 0x80); v >>= 7
return bytes(reversed(buf))
def meta(self, t: int, d: bytes = b"") -> bytes: return bytes([0xFF, t, len(d)]) + d
def tempo(self, trk: int, tus: int = 500000): self.tracks[trk].append((0, self.meta(0x51, struct.pack(">I", tus)[1:])))
def prog(self, trk: int, ch: int, p: int): self.tracks[trk].append((0, bytes([0xC0 | (ch & 0x0F), p & 0x7F])))
def on(self, trk: int, ch: int, n: int, v: int, dt: int = 0): self.tracks[trk].append((dt, bytes([0x90 | (ch & 0x0F), n & 0x7F, v & 0x7F])))
def off(self, trk: int, ch: int, n: int, v: int = 0, dt: int = 0): self.tracks[trk].append((dt, bytes([0x80 | (ch & 0x0F), n & 0x7F, v & 0x7F])))
def eot(self, trk: int, dt: int = 0): self.tracks[trk].append((dt, self.meta(0x2F)))
def save(self, path):
with open(path, "wb") as f:
f.write(b"MThd"); f.write(struct.pack(">I", 6)); f.write(struct.pack(">H", 1))
f.write(struct.pack(">H", len(self.tracks))); f.write(struct.pack(">H", self.tpq))
for evts in self.tracks:
data = b"".join(self._vlq(dt) + msg for dt, msg in evts)
f.write(b"MTrk"); f.write(struct.pack(">I", len(data))); f.write(data)
# ββ YIN Pitch Detector ββ
class YIN:
def __init__(self, sr=16000, frame_ms=46):
self.sr = sr; self.fs = int(sr * frame_ms / 1000)
self.hs = max(1, self.fs // 4); self.th = 0.15
def _diff(self, x):
n, mt = len(x), len(x)//2; d = np.zeros(mt)
for tau in range(1, mt): d[tau] = np.sum((x[:n-tau] - x[tau:n]) ** 2)
return d
def _cmdf(self, df):
cm = np.ones(len(df)); rs = 0.0
for tau in range(1, len(df)): rs += df[tau]; cm[tau] = df[tau]/(rs/tau) if rs else 1.0
return cm
def pitch(self, frame):
frame = (frame[:self.fs] if len(frame) >= self.fs else np.pad(frame, (0, self.fs - len(frame)))) * np.hanning(self.fs)
df = self._diff(frame); cm = self._cmdf(df); est = None
for tau in range(2, len(cm)):
if cm[tau] < self.th:
while tau+1 < len(cm) and cm[tau+1] < cm[tau]: tau += 1
est = tau; break
if est is None: est = int(np.argmin(cm[2:])) + 2
if 1 <= est < len(cm)-1:
p = 0.5 * (cm[est-1] - cm[est+1]) / (cm[est-1] - 2*cm[est] + cm[est+1])
est += p
return self.sr / est if est > 0 else None
def detect(self, y):
return [(i / self.sr, self.pitch(y[i:i + self.fs])) for i in range(0, len(y) - self.fs, self.hs)]
# ββ WAV I/O ββ
def wav_read(path):
with wave.open(str(path), "rb") as w:
ch, sw, sr, nf = w.getnchannels(), w.getsampwidth(), w.getframerate(), w.getnframes()
raw = np.frombuffer(w.readframes(nf), dtype=np.int16)
if ch == 2: raw = ((raw[0::2] + raw[1::2]) / 2).astype(np.int16)
return raw.astype(np.float32) / 32768.0, sr
def wav_write(path, y, sr):
y = np.clip(y * 32767, -32767, 32767).astype(np.int16)
with wave.open(str(path), "wb") as w:
w.setnchannels(1); w.setsampwidth(2); w.setframerate(sr); w.writeframes(y.tobytes())
# ββ 36-Model Registry ββ
REGISTRY = {
"ml": [
{"id": "MIT/ast-finetuned-audioset-10-10-0.4593", "task": "audio-classification", "role": "Primary Acoustic Classifier"},
{"id": "facebook/wav2vec2-base-960h", "task": "asr", "role": "Spectral Transcription"},
{"id": "microsoft/wavlm-base", "task": "feature-extraction", "role": "Embedding Extractor"},
{"id": "facebook/hubert-base-ls960", "task": "feature-extraction", "role": "Hidden-Unit BERT"},
{"id": "google/yamnet", "task": "audio-classification", "role": "Mobile Audio Tagger"},
{"id": "espnet/owsm_ctc", "task": "asr", "role": "Open Whisper CTC"},
{"id": "patrickvonplaten/whisper-large-v2", "task": "asr", "role": "Multilingual Whisper"},
{"id": "openai/whisper-base", "task": "asr", "role": "Baseline Whisper"},
{"id": "spotify/basic-pitch", "task": "audio-to-audio", "role": "Fundamental Freq Tracker"},
{"id": "facebook/encodec_24khz", "task": "audio-to-audio", "role": "Neural Codec"},
{"id": "speechbrain/sepformer-wsj02mix", "task": "audio-to-audio", "role": "Source Separation"},
{"id": "m3hrdadfi/wav2vec2-base-100k-gtzan-music-genre", "task": "audio-classification", "role": "Genre Classifier"},
{"id": "ehcalabres/wav2vec2-lg-xlsr-en-speech-emotion-recognition", "task": "audio-classification", "role": "Emotion Detector"},
{"id": "superb/wav2vec2-base-superb-er", "task": "audio-classification", "role": "SUPERB Emotion"},
{"id": "alefiury/wav2vec2-base-960h-gender-recognition-libri", "task": "audio-classification", "role": "Gender Profile"},
{"id": "facebook/wav2vec2-xlsr-53", "task": "feature-extraction", "role": "XLS-R Encoder"},
{"id": "jonatasgrosman/wav2vec2-large-xlsr-53-english", "task": "asr", "role": "English ASR"},
{"id": "facebook/s2t-small-librispeech-asr", "task": "asr", "role": "Speech-to-Text S2T"},
{"id": "speechbrain/emotion-recognition-wav2vec2-IEMOCAP", "task": "audio-classification", "role": "IEMOCAP Baseline"},
{"id": "sentence-transformers/all-MiniLM-L6-v2", "task": "feature-extraction", "role": "Semantic Embedding"},
{"id": "sentence-transformers/all-mpnet-base-v2", "task": "feature-extraction", "role": "MPNet Encoder"},
{"id": "facebook/bart-base", "task": "feature-extraction", "role": "BART Feature"},
{"id": "facebook/roberta-base", "task": "feature-extraction", "role": "RoBERTa Context"},
{"id": "cardiffnlp/twitter-roberta-base-emotion", "task": "text-classification", "role": "Twitter Emotion"},
{"id": "distilbert-base-uncased-finetuned-sst-2-english", "task": "text-classification", "role": "SST-2 Sentiment"},
{"id": "dslim/bert-base-NER", "task": "token-classification", "role": "NER Tagger"},
{"id": "huggingface-course/audio-transformers", "task": "audio-classification", "role": "Course Ref"},
{"id": "sanchit-gandhi/whisper-medium-finetuned-common-voice-13", "task": "asr", "role": "CV-13 Whisper"},
{"id": "jonatasgrosman/wavlm-large-xtreme-s", "task": "audio-classification", "role": "XTreme Emotion"},
{"id": "ehcalabres/wav2vec2-lg-xlsr-en-speech-emotion-recognition", "task": "audio-classification", "role": "Emotion Re-Classifier"},
],
"llm": [
{"id": "mistralai/Mistral-7B-Instruct-v0.1", "task": "text-generation", "role": "Poetry Engine"},
{"id": "meta-llama/Llama-2-7b-chat-hf", "task": "text-generation", "role": "Scientific Abstract"},
{"id": "google/gemma-7b-it", "task": "text-generation", "role": "Naming Conventions"},
{"id": "HuggingFaceH4/zephyr-7b-beta", "task": "text-generation", "role": "Roast & Critique"},
{"id": "microsoft/Phi-3-mini-4k-instruct", "task": "text-generation", "role": "Shakespearean Xlator"},
{"id": "tiiuae/falcon-7b-instruct", "task": "text-generation", "role": "Tokenomics Architect"},
],
}
ALL_MODELS = REGISTRY["ml"] + REGISTRY["llm"]
def stub_infer(m: dict, seed: int) -> dict:
rng = np.random.default_rng(seed)
t = m["task"]
if t == "audio-classification":
return {"label": str(rng.choice(["toot","brap","poot","squeak","rumble","whistle","plop","thunder"])), "score": round(float(rng.random()*0.4+0.5),4)}
if t == "asr":
return {"text": str(rng.choice(["brrrraaaaap","pfffffttt","prrrrrrrt","squeeeeeak","thunderclap"]))}
if t == "feature-extraction":
return {"dims": 768, "preview": [round(float(x),6) for x in rng.random(4)]}
if t == "audio-to-audio":
return {"output": "synthetic_reconstruction.wav", "quality": round(float(rng.random()),4)}
if t == "text-classification":
return {"label": str(rng.choice(["POSITIVE","NEGATIVE","NEUTRAL"])), "score": round(float(rng.random()),4)}
if t == "token-classification":
return {"entities": [{"word": "fart", "label": "B-FART", "score": 0.99}]}
if t == "text-generation":
return {"generated_text": f"[stub] {m['role']} says: beep boop"}
return {"stub": True}
# ββ DB ββ
def init_db():
with sqlite3.connect(DB, check_same_thread=False) as c:
c.execute("PRAGMA journal_mode=WAL")
c.execute("CREATE TABLE IF NOT EXISTS farts (id TEXT PRIMARY KEY, ts TEXT, audio_hash TEXT, fingerprint TEXT, fartscore INTEGER, midi_path TEXT, note_count INTEGER, duration REAL, report JSON, prev_hash TEXT, receipt_hash TEXT)")
c.execute("CREATE TABLE IF NOT EXISTS analyses (id INTEGER PRIMARY KEY, fart_id TEXT, model_id TEXT, task TEXT, role TEXT, result JSON, latency_ms REAL, ts TEXT)")
c.execute("CREATE INDEX IF NOT EXISTS idx_farts_ts ON farts(ts)")
c.execute("CREATE INDEX IF NOT EXISTS idx_analyses_fart ON analyses(fart_id)")
def db_conn():
c = sqlite3.connect(DB, check_same_thread=False)
c.row_factory = sqlite3.Row
return c
def latest_receipt() -> str:
with db_conn() as c:
r = c.execute("SELECT receipt_hash FROM farts ORDER BY ts DESC LIMIT 1").fetchone()
return r["receipt_hash"] if r else ""
def insert_fart(fid, ah, fp, fscore, midi, notes, dur, report, prev, receipt):
with db_conn() as c:
c.execute("INSERT INTO farts VALUES (?,?,?,?,?,?,?,?,?,?,?)", (fid, datetime.now(timezone.utc).isoformat(), ah, fp, fscore, midi, notes, dur, json.dumps(report), prev, receipt))
c.commit()
def insert_analysis(fid, m, res, lat):
with db_conn() as c:
c.execute("INSERT INTO analyses (fart_id, model_id, task, role, result, latency_ms, ts) VALUES (?,?,?,?,?,?,?)", (fid, m["id"], m["task"], m["role"], json.dumps(res), lat, datetime.now(timezone.utc).isoformat()))
c.commit()
def list_farts(limit=50):
with db_conn() as c:
return [dict(r) for r in c.execute("SELECT * FROM farts ORDER BY ts DESC LIMIT ?", (limit,)).fetchall()]
def get_fart(fid):
with db_conn() as c:
r = c.execute("SELECT * FROM farts WHERE id=?", (fid,)).fetchone()
return dict(r) if r else None
def leaderboard():
with db_conn() as c:
return [dict(r) for r in c.execute("SELECT fingerprint, fartscore, ts, note_count FROM farts ORDER BY fartscore DESC LIMIT 20").fetchall()]
# ββ Ledger ββ
def fingerprint(audio_bytes: bytes) -> tuple:
h = hashlib.sha256(audio_bytes).digest()
score = int(hashlib.sha256(h).hexdigest(), 16) % 101
return "Fart" + b58(h)[:38], score
def receipt(fid: str, ah: str, fp: str, fscore: int, prev: str) -> str:
return hashlib.sha256(f"{fid}:{ah}:{fp}:{fscore}:{prev}".encode()).hexdigest()
# ββ Note Segmentation ββ
def segment_notes(pitches):
notes = []; active = False; nstart = 0.0; cur = None
for t, p in pitches:
if p and 40 <= p <= 2000:
mn = max(0, min(127, int(69 + 12 * np.log2(p / 440))))
vel = min(127, max(30, int(70 + np.random.randn() * 20)))
if not active: active, nstart, cur = True, t, mn
elif abs(mn - cur) > 2:
if t - nstart >= 0.05: notes.append((nstart, t - nstart, cur, vel))
nstart, cur = t, mn
else:
if active and t - nstart >= 0.05: notes.append((nstart, t - nstart, cur, vel))
active = False
if active and pitches and pitches[-1][0] - nstart >= 0.05:
notes.append((nstart, pitches[-1][0] - nstart, cur, vel))
return notes
def build_midi(notes, path):
if not notes: return None
w = SMF(); t = w.add(); w.tempo(t); w.prog(t, 0, 58)
notes = sorted(notes, key=lambda x: x[0])
tps = 480 * (120 / 60.0); last = 0
for s, d, n, v in notes:
on, dur = int(s * tps), max(1, int(d * tps))
w.on(t, 0, n, v, on - last); w.off(t, 0, n, 0, dur); last = on + dur
w.eot(t, 0); w.save(path); return path
# ββ Full Pipeline ββ
def run_pipeline(wav_path: Path):
y, sr = wav_read(wav_path)
dur = len(y) / sr
audio_bytes = open(wav_path, "rb").read()
ah = hashlib.sha256(audio_bytes).hexdigest()
fp, fscore = fingerprint(audio_bytes)
prev = latest_receipt() or ""
pitches = YIN(sr=sr).detect(y)
notes = segment_notes(pitches)
midi_file = OUTPUT / f"{fp[:12]}_{int(time.time())}.mid"
build_midi(notes, midi_file)
seed = int(hashlib.md5(audio_bytes[:4096]).hexdigest(), 16) % (2**31)
ml_out, llm_out = [], []
for m in REGISTRY["ml"]:
t0 = time.time()
res = stub_infer(m, seed)
lat = (time.time() - t0) * 1000
ml_out.append({"model": m["id"], "role": m["role"], "task": m["task"], "result": res, "latency_ms": round(lat, 2)})
insert_analysis(fp[:16], m, res, lat)
prompts = [
"Write a haiku about this fart.",
"Name this fart like a startup.",
"Write a fake Nature abstract about this acoustic emission.",
"Roast this fart mercilessly.",
"Translate this fart into Shakespearean English.",
"Write Solana memecoin tokenomics for this fart.",
]
for m, pr in zip(REGISTRY["llm"], prompts):
t0 = time.time()
res = stub_infer(m, int(hashlib.md5((audio_bytes[:4096] + pr.encode())).hexdigest(), 16) % (2**31))
lat = (time.time() - t0) * 1000
llm_out.append({"model": m["id"], "role": m["role"], "prompt": pr, "result": res, "latency_ms": round(lat, 2)})
insert_analysis(fp[:16], m, res, lat)
rec = receipt(fp[:16], ah, fp, fscore, prev)
report = {"fingerprint": fp, "fartscore": fscore, "duration": dur, "note_count": len(notes), "models": ml_out + llm_out}
insert_fart(fp[:16], ah, fp, fscore, str(midi_file), len(notes), dur, report, prev, rec)
return {
"fart_id": fp[:16], "fingerprint": fp, "fartscore": fscore,
"duration_sec": dur, "note_count": len(notes),
"midi_url": f"/output/{midi_file.name}" if midi_file.exists() else None,
"receipt": rec, "prev_receipt": prev,
"model_outputs": ml_out, "llm_outputs": llm_out,
"notes": [{"start": s, "duration": d, "midi": n, "velocity": v} for s, d, n, v in notes],
}
# ββ FastAPI ββ
app = FastAPI(title="AFIP", version="3.0.0")
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
init_db()
app.mount("/output", StaticFiles(directory="output"), name="output")
if Path("static").exists():
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/")
def root():
if Path("static/index.html").exists():
return FileResponse("static/index.html")
return {"name": "AFIP", "version": "3.0.0", "models": len(ALL_MODELS)}
@app.get("/health")
def health(): return {"status": "ok", "models_loaded": len(ALL_MODELS), "db": str(DB)}
@app.get("/registry")
def registry(): return {"ml_models": REGISTRY["ml"], "llm_models": REGISTRY["llm"], "total": len(ALL_MODELS)}
@app.get("/history")
def history(limit: int = 50): return list_farts(limit=limit)
@app.get("/leaderboard")
def lb(): return leaderboard()
@app.get("/fart/{fart_id}")
def get_fart_api(fart_id: str):
r = get_fart(fart_id)
if not r: raise HTTPException(status_code=404, detail="Fart not found")
return r
@app.post("/analyze")
async def analyze(file: UploadFile = File(...)):
tmp = Path(tempfile.gettempdir()) / f"afip_{int(time.time()*1000)}.wav"
try:
open(tmp, "wb").write(await file.read())
return run_pipeline(tmp)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
finally:
if tmp.exists(): tmp.unlink()
@app.get("/mock")
def mock():
t = np.linspace(0, 1.5, int(16000 * 1.5))
y = np.sin(2 * np.pi * 120 * t) * np.exp(-t * 2) + np.sin(2 * np.pi * 85 * t) * 0.5
y += np.random.randn(len(y)) * 0.02
tmp = OUTPUT / f"mock_{int(time.time())}.wav"
wav_write(tmp, y, 16000)
return run_pipeline(tmp)
@app.get("/download/{fname}")
def download(fname: str):
p = OUTPUT / fname
if not p.exists(): raise HTTPException(status_code=404)
return FileResponse(p, media_type="audio/midi", filename=fname)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=int(os.getenv("PORT", "8080")))
|