基于Flask框架的人工智能的音乐创作辅助系统执行时,当前端网页显示

出现报错
报错提示就是

估计就是前端或后端传递数据传错了。
前端代码
project/template/xx.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>生成旋律</title>
<link rel="stylesheet" href="../static/layui/css/layui.css">
<style>
/* 自定义样式 */
body {
background-image: url("../static/images/background.webp");
background-size: cover;
background-position: center;
background-attachment: fixed;
opacity: 0;
animation: fadeIn 0.5s ease-out forwards;
}
.layui-card {
background-color: rgba(255, 255, 255, 0.8);
border-radius: 10px;
padding: 20px;
}
.layui-card-header {
font-size: 24px;
font-weight: bold;
color: #333;
}
.layui-card-body {
color: #555;
}
.footer {
text-align: center;
margin-top: 40px;
color: #666;
font-size: 14px;
}
/* 动画:body 渐显 */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
</style>
</head>
<body>
<div class="layui-container">
<!-- 页面标题 -->
<div class="layui-row">
<div class="layui-col-xs12">
<div class="layui-card">
<div class="layui-card-header">生成旋律</div>
<div class="layui-card-body">
<p>请选择旋律风格和长度,然后点击“生成旋律”按钮。</p>
<div class="layui-form">
<label class="layui-form-label">风格</label>
<div class="layui-input-block">
<select id="style" class="layui-select">
<option value="">请选择风格</option> <!-- 提供默认空选项 -->
<option value="Pop">流行 (Pop)</option>
<option value="Rock">摇滚 (Rock)</option>
<option value="Jazz">爵士 (Jazz)</option>
<option value="Classical">古典 (Classical)</option>
<option value="Electronic">电子 (Electronic)</option>
<option value="Folk">民谣 (Folk)</option>
<option value="Hip-Hop">嘻哈 (Hip-Hop)</option>
<option value="Blues">蓝调 (Blues)</option>
<option value="Country">乡村 (Country)</option>
<option value="World">世界音乐 (World)</option>
</select>
</div>
<label class="layui-form-label">长度</label>
<div class="layui-input-block">
<input id="length" type="number" value="16" class="layui-input" min="1" max="128">
</div>
<button id="generate-button" class="layui-btn layui-btn-normal" style="margin-top: 15px;">生成旋律</button>
</div>
<!-- 显示生成结果 -->
<div id="result" style="margin-top: 20px;"></div>
</div>
</div>
</div>
</div>
</div>
<!-- 页脚 -->
<div class="footer">
© 2024 贵池威廉 | 基于人工智能的音乐创作辅助系统
</div>
<!-- 引入 Layui JS -->
<script src="../static/layui/layui.js"></script>
<script>
document.getElementById('generate-button').addEventListener('click', function() {
const styleSelect = document.getElementById('style');
const styleIndex = styleSelect.value; // 获取选中的索引值
const style = styleSelect.options[styleIndex]?.text?.trim(); // 获取对应的文本值
const lengthInput = document.getElementById('length').value;
const length = parseInt(lengthInput, 10);
// 校验输入
if (isNaN(length) || length <= 0) {
document.getElementById('result').innerHTML = `<p style="color: red;">错误: 长度必须是正整数!</p>`;
return;
}
if (!style) {
document.getElementById('result').innerHTML = `<p style="color: red;">错误: 请选择一个有效的风格!</p>`;
return;
}
// 发送请求
fetch('/melody_generation', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
style: style, // 确保传递的是真实的风格名称
length: length
})
})
.then(response => response.json())
.then(data => {
if (data.code === 0) {
document.getElementById('result').innerHTML = `<p style="color: green;">生成的旋律: ${data.melody.join(', ')}</p>`;
} else {
document.getElementById('result').innerHTML = `<p style="color: red;">错误: ${data.msg}</p>`;
}
})
.catch(error => {
document.getElementById('result').innerHTML = `<p style="color: red;">请求失败: ${error.message}</p>`;
});
});
// 使用 layui 渲染表单
layui.use(['form'], function() {
const form = layui.form;
form.render(); // 渲染表单
});
</script>
</body>
</html>
music_logic.py
import os
import time
import logging
import torch
# 初始化日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class LSTMAIModel(torch.nn.Module):
def __init__(self, input_size, hidden_size, num_layers, output_size):
super().__init__() # 正确调用父类的 __init__ 方法
self.lstm = torch.nn.LSTM(input_size, hidden_size, num_layers)
self.fc = torch.nn.Linear(hidden_size, output_size)
def forward(self, x):
out, _ = self.lstm(x)
out = self.fc(out)
return out
# 添加一个 generate_audio 方法 (stub)
def generate_audio(self, melody_tensor, style):
# 假设该方法生成音频的张量作为返回值
# 这里只是一个示例,您需要根据实际需求实现生成逻辑
logger.info(f"Generating audio for style: {style}")
return torch.randn(44100 * 10).numpy() # 假设 10 秒的音频
class MusicLogic:
SUPPORTED_STYLES = [
"Pop", "Rock", "Jazz", "Classical", "Electronic",
"Folk", "Hip-Hop", "Blues", "Country", "World"
]
def __init__(self, model, output_dir="output"):
"""
初始化 MusicLogic 实例
:param model: AI音乐生成模型实例
:param output_dir: 生成的音乐文件存储目录
"""
self.model = model
self.output_dir = output_dir
# 确保输出目录存在
os.makedirs(self.output_dir, exist_ok=True)
def validate_inputs(self, melody, style):
"""
验证输入的旋律和风格是否有效。
:param melody: 原始旋律
:param style: 音乐风格
:raises ValueError: 如果输入无效
"""
# 检查 melody 是否为 None 或空张量/列表
if melody is None:
raise ValueError("Melody must be provided.")
if isinstance(melody, torch.Tensor) and melody.numel() == 0: # 检查张量是否为空
raise ValueError("Melody tensor cannot be empty.")
if isinstance(melody, (list, tuple)) and len(melody) == 0: # 检查列表是否为空
raise ValueError("Melody list cannot be empty.")
# 检查 style 是否提供并支持
if not style:
raise ValueError("Style must be provided.")
if style not in self.SUPPORTED_STYLES:
raise ValueError(f"Unsupported style '{style}'. Supported styles are: {self.SUPPORTED_STYLES}")
def generate_melody(self, melody, style):
try:
logger.debug(f"Received melody:{melody},style:{style}")
file_name = f"music_{int(time.time())}.wav"
file_path = os.path.join(self.output_dir, file_name)
# 验证输入
self.validate_inputs(melody, style)
# 将输入的旋律转换为 PyTorch 张量
if isinstance(melody, torch.Tensor):
melody_tensor = melody.clone().detach()
else:
# 确保 melody 是一个可迭代对象且元素可转换为 float32 类型
if not isinstance(melody, (list, tuple)):
raise ValueError("Melody must be a list or tuple.")
if len(melody) == 0:
raise ValueError("Melody list cannot be empty.")
melody_tensor = torch.tensor([float(item) for item in melody], dtype=torch.float32).clone().detach()
# 确保模型和张量在 CUDA 上,如果 CUDA 可用
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
self.model = self.model.to(device)
melody_tensor = melody_tensor.to(device)
# 调用 generate_audio 方法生成音频
audio_data = self.model.generate_audio(melody_tensor, style)
# 将音频数据转换为 NumPy 数组
audio_data = torch.tensor(audio_data).cpu().numpy()
# 保存音频数据到文件
with open(file_path, "wb") as f:
f.write(audio_data.tobytes())
return file_path
except Exception as e:
logger.error(f"Error during melody generation: {str(e)}")
raise RuntimeError(f"Error during melody generation: {str(e)}")
def generate_audio_stream(self, melody, style):
"""
流式生成音频数据。
:param melody: 原始旋律(字符串或其他表示形式)
:param style: 音乐风格(字符串)
:yield: 音频数据块
"""
self.validate_inputs(melody, style)
try:
logger.info(f"Starting stream generation for melody: {melody} with style: {style}")
# 将输入的旋律转换为 PyTorch 张量
if isinstance(melody, torch.Tensor):
melody_tensor = melody.clone().detach()
else:
# 确保 melody 是一个可迭代对象且元素可转换为 float32 类型
if not isinstance(melody, (list, tuple)):
raise ValueError("Melody must be a list or tuple.")
melody_tensor = torch.tensor([float(item) for item in melody], dtype=torch.float32).clone().detach()
# 确保模型和张量在 CUDA 上,如果 CUDA 可用
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
self.model = self.model.to(device)
melody_tensor = melody_tensor.to(device)
# 调用AI模型生成完整音频
full_audio = self.model.generate_audio(melody_tensor, style)
# 模拟将音频分成小块流式输出
chunk_size = len(full_audio) // 10 # 分为10段
for i in range(10):
time.sleep(0.1) # 模拟生成延迟
start = i * chunk_size
end = (i + 1) * chunk_size if i < 9 else len(full_audio)
logger.info(f"Streaming chunk {i + 1}/10")
yield full_audio[start:end]
except Exception as e:
logger.error(f"Error during audio stream generation: {str(e)}")
raise RuntimeError(f"Error during audio stream generation: {str(e)}")