Hezu06 commited on
Commit
bbe8f42
·
verified ·
1 Parent(s): 2372d15

Delete main.py

Browse files
Files changed (1) hide show
  1. main.py +0 -164
main.py DELETED
@@ -1,164 +0,0 @@
1
- from fastapi import FastAPI, Request
2
- from fastapi.staticfiles import StaticFiles
3
- from fastapi.responses import FileResponse
4
- from pydantic import BaseModel
5
- import torch
6
- import torch.nn as nn
7
- import pickle
8
- import numpy as np
9
- from music21 import note, chord, stream, instrument
10
- import os
11
- os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'
12
- import random
13
- import subprocess
14
-
15
- app = FastAPI(title="Bio-Vibe AI Inference")
16
- os.makedirs("music", exist_ok=True)
17
- app.mount("/music", StaticFiles(directory="music"), name="music")
18
-
19
- @app.get("/")
20
- async def serve_frontend():
21
- return FileResponse("index.html")
22
-
23
- class HeartRateData(BaseModel):
24
- bpm: int
25
-
26
- # ==========================================
27
- # 1. KHÔI PHỤC "BỘ NÃO" (PYTORCH MODEL)
28
- # ==========================================
29
- # Cấu trúc class phải y hệt lúc train
30
- class BioVibeAI(nn.Module):
31
- def __init__(self, vocab_size, embed_size=256, hidden_size=512, num_layers=2):
32
- super(BioVibeAI, self).__init__()
33
- self.embedding = nn.Embedding(vocab_size, embed_size)
34
- self.lstm = nn.LSTM(embed_size, hidden_size, num_layers, batch_first=True)
35
- self.fc = nn.Linear(hidden_size, vocab_size)
36
-
37
- def forward(self, x):
38
- embedded = self.embedding(x)
39
- out, _ = self.lstm(embedded)
40
- out = self.fc(out[:, -1, :])
41
- return out
42
-
43
- # Nạp từ điển
44
- with open('mapping_dict.pkl', 'rb') as f:
45
- int_to_note = pickle.load(f)
46
- note_to_int = {note: number for number, note in int_to_note.items()}
47
- vocab_size = len(int_to_note)
48
-
49
- # Load trọng số mô hình
50
- device = torch.device("cpu") # Server chạy CPU cho nhẹ
51
- model = BioVibeAI(vocab_size=vocab_size)
52
- model.load_state_dict(torch.load("biovibe_brain.pth", map_location=device))
53
- model.eval() # Chuyển sang chế độ suy luận
54
-
55
- # Nạp kho dữ liệu cũ để lấy Seed (đoạn nhạc mồi)
56
- with open('notes_corpus.pkl', 'rb') as f:
57
- corpus = pickle.load(f)
58
-
59
- # ==========================================
60
- # 2. HÀM SÁNG TÁC BẰNG NHIỆT ĐỘ (TEMPERATURE)
61
- # ==========================================
62
- def generate_ai_midi(bpm: int, output_file: str, num_notes: int = 60):
63
- # Logic phản hồi sinh học
64
- if bpm > 80:
65
- temperature = 0.7 # An toàn, ổn định
66
- base_offset = 1.0 # Nốt đánh chậm
67
- else:
68
- temperature = 1.0 # Bay bổng, ngẫu hứng
69
- base_offset = 0.5 # Nốt đánh nhanh hơn một chút
70
-
71
- # Chọn bừa 100 nốt từ kho dữ liệu để làm "mồi" cho AI
72
- start_idx = random.randint(0, len(corpus) - 100)
73
- seed_sequence = corpus[start_idx:start_idx + 100]
74
- pattern = [note_to_int[char] for char in seed_sequence]
75
-
76
- generated_notes = []
77
-
78
- print(f"Đang sáng tác với Temp={temperature}...")
79
-
80
- # AI bắt đầu dự đoán
81
- for i in range(num_notes):
82
- sequence_tensor = torch.tensor([pattern], dtype=torch.long).to(device)
83
-
84
- with torch.no_grad():
85
- prediction = model(sequence_tensor)
86
-
87
- # ÁP DỤNG TEMPERATURE
88
- prediction = prediction / temperature
89
- probabilities = torch.softmax(prediction, dim=1).numpy()[0]
90
-
91
- # Chọn nốt dựa trên phân phối xác suất
92
- index = np.random.choice(len(probabilities), p=probabilities)
93
-
94
- result_note = int_to_note[index]
95
- generated_notes.append(result_note)
96
-
97
- # Cập nhật cửa sổ trượt (thêm nốt mới, xóa nốt cũ nhất)
98
- pattern.append(index)
99
- pattern = pattern[1:]
100
-
101
- # ==========================================
102
- # 3. CHUYỂN NGỮ AI THÀNH FILE MIDI
103
- # ==========================================
104
- offset = 0
105
- output_stream = stream.Stream()
106
- output_stream.append(instrument.Piano()) # Chọn nhạc cụ
107
-
108
- for pattern_note in generated_notes:
109
- # Nếu là hợp âm (có dấu chấm, ví dụ '4.7.11')
110
- if ('.' in pattern_note) or pattern_note.isdigit():
111
- notes_in_chord = pattern_note.split('.')
112
- chord_notes = []
113
- for current_note in notes_in_chord:
114
- new_note = note.Note(int(current_note))
115
- new_note.storedInstrument = instrument.Piano()
116
- chord_notes.append(new_note)
117
- new_chord = chord.Chord(chord_notes)
118
- new_chord.offset = offset
119
- output_stream.append(new_chord)
120
- # Nếu là nốt đơn (Ví dụ: 'C4')
121
- else:
122
- new_note = note.Note(pattern_note)
123
- new_note.offset = offset
124
- new_note.storedInstrument = instrument.Piano()
125
- output_stream.append(new_note)
126
-
127
- # Tịnh tiến thời gian cho nốt tiếp theo
128
- offset += base_offset
129
-
130
- output_stream.write('midi', fp=output_file)
131
-
132
- # ==========================================
133
- # 4. API ENDPOINT
134
- # ==========================================
135
- @app.post("/generate-vibe")
136
- async def generate_vibe(data: HeartRateData, request: Request):
137
- # Đường dẫn file
138
- midi_file = f"music/ai_vibe_{data.bpm}.mid"
139
- wav_file = f"music/ai_vibe_{data.bpm}.wav"
140
- soundfont_path = "soundfonts/Piano.sf2" # Đường dẫn tới file sf2 bạn vừa tải
141
-
142
- # Bước 1: PyTorch sinh ra cấu trúc nốt nhạc (MIDI)
143
- # Bước 1: PyTorch sinh ra cấu trúc nốt nhạc (MIDI)
144
- generate_ai_midi(data.bpm, midi_file)
145
-
146
- # Bước 2: Tự viết lệnh Render bằng Subprocess chuẩn xác cho FluidSynth 2.5+
147
- print("Đang render MIDI thành âm thanh Piano...")
148
- try:
149
- subprocess.run([
150
- "fluidsynth",
151
- "-ni", # Chạy ẩn không cần giao diện
152
- "-r", "44100", # Chất lượng Sample rate
153
- "-F", wav_file, # Xuất ra file thay vì phát ra loa laptop!
154
- soundfont_path, # Dàn nhạc (Soundfont)
155
- midi_file # Kịch bản (MIDI)
156
- ], check=True)
157
- except Exception as e:
158
- print(f"Lỗi khi render âm thanh: {e}")
159
- return {"status": "error", "message": "Render failed"}
160
-
161
- server_url = str(request.base_url).rstrip("/")
162
-
163
- # Bước 3: Trả về link file âm thanh xịn xò cho App Flutter
164
- return {"status": "success", "audio_url": f"{server_url}/{wav_file}"}