454 lines
23 KiB
HTML
454 lines
23 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}语音克隆测试 - 儿童语言学习系统{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="container py-4">
|
||
<!-- 页面标题 -->
|
||
<div class="row mb-4">
|
||
<div class="col-12">
|
||
<div class="d-flex align-items-center">
|
||
<a href="{{ url_for('main.dashboard') }}" class="btn btn-outline-secondary me-3">
|
||
<i class="fas fa-arrow-left me-2"></i>返回主页
|
||
</a>
|
||
<div>
|
||
<h2 class="fw-bold mb-1">
|
||
<i class="fas fa-magic text-primary me-2"></i>
|
||
语音克隆技术测试
|
||
</h2>
|
||
<p class="text-muted mb-0">体验"听自己说"的神奇技术 - 让AI学会你的声音</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 连接状态检测 -->
|
||
<div class="row mb-4">
|
||
<div class="col-12">
|
||
<div class="card border-0 shadow-sm">
|
||
<div class="card-body">
|
||
<h5 class="card-title">
|
||
<i class="fas fa-plug me-2"></i>服务连接状态
|
||
</h5>
|
||
<div class="d-flex align-items-center">
|
||
<button id="test-connection-btn" class="btn btn-primary me-3">
|
||
<i class="fas fa-wifi me-2"></i>测试连接
|
||
</button>
|
||
<div id="connection-status" class="flex-grow-1">
|
||
<span class="text-muted">点击测试连接按钮检查服务状态</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 核心功能:语音克隆工作流程 -->
|
||
<div class="row mb-4">
|
||
<div class="col-12">
|
||
<div class="card border-0 shadow-sm border-primary" style="border-width: 2px !important;">
|
||
<div class="card-body">
|
||
<h4 class="card-title text-primary">
|
||
<i class="fas fa-clone me-2"></i>语音克隆工作流程
|
||
<span class="badge bg-primary ms-2">核心功能</span>
|
||
</h4>
|
||
<p class="text-muted mb-4">按照步骤操作,体验完整的语音克隆过程</p>
|
||
|
||
<!-- 步骤指示器 -->
|
||
<div class="row mb-4">
|
||
<div class="col-12">
|
||
<div class="d-flex justify-content-between position-relative">
|
||
<div class="step-indicator active" id="step-1-indicator">
|
||
<div class="step-circle">1</div>
|
||
<div class="step-label">录制声音</div>
|
||
</div>
|
||
<div class="step-line"></div>
|
||
<div class="step-indicator" id="step-2-indicator">
|
||
<div class="step-circle">2</div>
|
||
<div class="step-label">识别文字</div>
|
||
</div>
|
||
<div class="step-line"></div>
|
||
<div class="step-indicator" id="step-3-indicator">
|
||
<div class="step-circle">3</div>
|
||
<div class="step-label">克隆生成</div>
|
||
</div>
|
||
<div class="step-line"></div>
|
||
<div class="step-indicator" id="step-4-indicator">
|
||
<div class="step-circle">4</div>
|
||
<div class="step-label">效果对比</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<!-- 步骤1:语音样本采集 -->
|
||
<div class="col-lg-6 mb-4">
|
||
<div class="step-content" id="step-1-content">
|
||
<h5 class="text-success">
|
||
<i class="fas fa-microphone me-2"></i>步骤1:录制你的声音样本
|
||
</h5>
|
||
<p class="text-muted">录制一段3-10秒的清晰语音,作为语音克隆的模板</p>
|
||
|
||
<form id="voice-sample-form" enctype="multipart/form-data">
|
||
<div class="mb-3">
|
||
<label class="form-label">方式一:上传音频文件</label>
|
||
<input type="file" class="form-control" id="voice-sample-upload"
|
||
accept=".wav,.mp3,.m4a,.flac">
|
||
<div class="form-text">建议:WAV格式,16kHz采样率,3-10秒时长</div>
|
||
</div>
|
||
|
||
<div class="mb-3 text-center">
|
||
<span class="text-muted">或</span>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label">方式二:在线录音</label>
|
||
<div class="text-center">
|
||
<button type="button" id="start-recording" class="btn btn-danger me-2">
|
||
<i class="fas fa-record-vinyl me-2"></i>开始录音
|
||
</button>
|
||
<button type="button" id="stop-recording" class="btn btn-secondary" disabled>
|
||
<i class="fas fa-stop me-2"></i>停止录音
|
||
</button>
|
||
<div class="mt-2">
|
||
<small id="recording-status" class="text-muted">点击开始录音</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<button type="submit" class="btn btn-success w-100" disabled id="upload-sample-btn">
|
||
<i class="fas fa-upload me-2"></i>上传语音样本
|
||
</button>
|
||
</form>
|
||
|
||
<!-- 样本播放区域 -->
|
||
<div id="sample-player" class="mt-3" style="display: none;">
|
||
<div class="alert alert-info">
|
||
<h6><i class="fas fa-headphones me-2"></i>你的语音样本:</h6>
|
||
<audio controls class="w-100 mt-2" id="sample-audio">
|
||
<source id="sample-audio-source" type="audio/wav">
|
||
</audio>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 步骤2:语音识别 -->
|
||
<div class="col-lg-6 mb-4">
|
||
<div class="step-content" id="step-2-content">
|
||
<h5 class="text-info">
|
||
<i class="fas fa-text-width me-2"></i>步骤2:语音识别结果
|
||
</h5>
|
||
<p class="text-muted">AI识别出你说的内容,这将用于语音克隆训练</p>
|
||
|
||
<div id="recognition-result" style="display: none;">
|
||
<div class="mb-3">
|
||
<label class="form-label">识别的文本内容:</label>
|
||
<textarea class="form-control" id="recognized-text" rows="3"
|
||
placeholder="语音识别结果将显示在这里..."></textarea>
|
||
<div class="form-text">你可以手动修正识别错误的文字</div>
|
||
</div>
|
||
|
||
<div class="d-flex justify-content-between">
|
||
<small class="text-success">
|
||
<i class="fas fa-check-circle me-1"></i>识别完成
|
||
</small>
|
||
<button class="btn btn-outline-primary btn-sm" onclick="goToStep(3)">
|
||
下一步:克隆生成 <i class="fas fa-arrow-right ms-1"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="recognition-waiting" class="text-center text-muted">
|
||
<i class="fas fa-clock fa-2x mb-2"></i>
|
||
<p>等待上传语音样本...</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 步骤3:语音克隆生成 -->
|
||
<div class="col-lg-6 mb-4">
|
||
<div class="step-content" id="step-3-content">
|
||
<h5 class="text-warning">
|
||
<i class="fas fa-magic me-2"></i>步骤3:克隆你的声音
|
||
</h5>
|
||
<p class="text-muted">让AI用你的声音说新的话</p>
|
||
|
||
<form id="clone-generation-form">
|
||
<div class="mb-3">
|
||
<label class="form-label">想让AI用你的声音说什么?</label>
|
||
<textarea class="form-control" id="clone-text" rows="3"
|
||
placeholder="例如:你好,我是AI克隆的声音,听起来像真的一样!">你好,我是AI克隆的声音,听起来像真的一样!</textarea>
|
||
</div>
|
||
|
||
<div class="row mb-3">
|
||
<div class="col-6">
|
||
<label class="form-label">随机种子</label>
|
||
<div class="input-group">
|
||
<input type="number" class="form-control" id="clone-seed" value="42">
|
||
<button type="button" class="btn btn-outline-secondary" id="clone-random-seed">
|
||
<i class="fas fa-dice"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="col-6">
|
||
<label class="form-label">克隆质量</label>
|
||
<select class="form-select">
|
||
<option>高质量(推荐)</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<button type="submit" class="btn btn-warning w-100" disabled id="generate-clone-btn">
|
||
<i class="fas fa-magic me-2"></i>生成克隆语音
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 步骤4:效果对比 -->
|
||
<div class="col-lg-6 mb-4">
|
||
<div class="step-content" id="step-4-content">
|
||
<h5 class="text-success">
|
||
<i class="fas fa-balance-scale me-2"></i>步骤4:效果对比
|
||
</h5>
|
||
<p class="text-muted">对比原声和克隆声音的效果</p>
|
||
|
||
<div id="comparison-result" style="display: none;">
|
||
<div class="row">
|
||
<div class="col-6">
|
||
<h6><i class="fas fa-user me-2"></i>原声样本</h6>
|
||
<audio controls class="w-100" id="original-audio">
|
||
<source id="original-audio-source" type="audio/wav">
|
||
</audio>
|
||
<small class="text-muted">你录制的原始声音</small>
|
||
</div>
|
||
<div class="col-6">
|
||
<h6><i class="fas fa-robot me-2"></i>克隆声音</h6>
|
||
<audio controls class="w-100" id="cloned-audio">
|
||
<source id="cloned-audio-source" type="audio/wav">
|
||
</audio>
|
||
<small class="text-muted">AI克隆的声音</small>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mt-3 p-3 bg-light rounded">
|
||
<h6><i class="fas fa-star me-2"></i>给克隆效果打分:</h6>
|
||
<div class="btn-group" role="group">
|
||
<input type="radio" class="btn-check" name="rating" id="rating1">
|
||
<label class="btn btn-outline-warning" for="rating1">1★</label>
|
||
<input type="radio" class="btn-check" name="rating" id="rating2">
|
||
<label class="btn btn-outline-warning" for="rating2">2★</label>
|
||
<input type="radio" class="btn-check" name="rating" id="rating3">
|
||
<label class="btn btn-outline-warning" for="rating3">3★</label>
|
||
<input type="radio" class="btn-check" name="rating" id="rating4">
|
||
<label class="btn btn-outline-warning" for="rating4">4★</label>
|
||
<input type="radio" class="btn-check" name="rating" id="rating5">
|
||
<label class="btn btn-outline-warning" for="rating5">5★</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="comparison-waiting" class="text-center text-muted">
|
||
<i class="fas fa-hourglass-half fa-2x mb-2"></i>
|
||
<p>等待生成克隆语音...</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 重新开始按钮 -->
|
||
<div class="text-center mt-4">
|
||
<button class="btn btn-outline-primary" onclick="resetWorkflow()">
|
||
<i class="fas fa-redo me-2"></i>重新开始克隆流程
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 高级功能区域 -->
|
||
<div class="row mb-4">
|
||
<div class="col-12">
|
||
<div class="card border-0 shadow-sm">
|
||
<div class="card-body">
|
||
<h5 class="card-title">
|
||
<i class="fas fa-cogs me-2"></i>高级功能
|
||
<button class="btn btn-outline-secondary btn-sm float-end" type="button" data-bs-toggle="collapse" data-bs-target="#advanced-features">
|
||
<i class="fas fa-chevron-down"></i>
|
||
</button>
|
||
</h5>
|
||
|
||
<div class="collapse" id="advanced-features">
|
||
<div class="row">
|
||
<!-- 预训练音色测试 -->
|
||
<div class="col-lg-6 mb-4">
|
||
<h6 class="text-secondary">预训练音色测试</h6>
|
||
<form id="preset-voice-form">
|
||
<div class="mb-3">
|
||
<textarea class="form-control" id="preset-text" rows="2"
|
||
placeholder="输入要转换成语音的文字...">今天天气真不错,适合出门散步。</textarea>
|
||
</div>
|
||
<div class="mb-3">
|
||
<select class="form-select" id="preset-voice">
|
||
<option value="中文女">中文女</option>
|
||
</select>
|
||
</div>
|
||
<button type="submit" class="btn btn-secondary btn-sm">
|
||
<i class="fas fa-play me-2"></i>生成语音
|
||
</button>
|
||
</form>
|
||
<div id="preset-result" class="mt-2" style="display: none;">
|
||
<audio controls class="w-100">
|
||
<source id="preset-audio-source" type="audio/wav">
|
||
</audio>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 自然语言控制测试 -->
|
||
<div class="col-lg-6 mb-4">
|
||
<h6 class="text-secondary">自然语言控制</h6>
|
||
<form id="natural-control-form">
|
||
<div class="mb-3">
|
||
<textarea class="form-control" id="natural-text" rows="2"
|
||
placeholder="输入要合成的文字...">这是自然语言控制测试。</textarea>
|
||
</div>
|
||
<div class="mb-3">
|
||
<input class="form-control" id="natural-instruction"
|
||
placeholder="语音指令,如:请用温柔甜美的女声朗读"
|
||
value="请用温柔甜美的女声朗读">
|
||
</div>
|
||
<button type="submit" class="btn btn-secondary btn-sm">
|
||
<i class="fas fa-magic me-2"></i>生成语音
|
||
</button>
|
||
</form>
|
||
<div id="natural-result" class="mt-2" style="display: none;">
|
||
<audio controls class="w-100">
|
||
<source id="natural-audio-source" type="audio/wav">
|
||
</audio>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 操作日志 -->
|
||
<div class="row">
|
||
<div class="col-12">
|
||
<div class="card border-0 shadow-sm">
|
||
<div class="card-body">
|
||
<h5 class="card-title">
|
||
<i class="fas fa-history me-2"></i>操作日志
|
||
<button class="btn btn-outline-secondary btn-sm float-end" id="clear-log">
|
||
<i class="fas fa-trash me-1"></i>清空
|
||
</button>
|
||
</h5>
|
||
<div id="test-log" class="border rounded p-3" style="height: 300px; overflow-y: auto; background-color: #f8f9fa;">
|
||
<p class="text-muted">操作记录将显示在这里...</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Loading Modal -->
|
||
<div class="modal fade" id="loadingModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1">
|
||
<div class="modal-dialog modal-dialog-centered">
|
||
<div class="modal-content">
|
||
<div class="modal-body text-center py-4">
|
||
<div class="spinner-border text-primary mb-3" role="status"></div>
|
||
<h5 id="loading-message">正在处理中...</h5>
|
||
<p id="loading-detail" class="text-muted">请稍候...</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 添加步骤指示器样式 -->
|
||
<style>
|
||
.step-indicator {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
|
||
.step-circle {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
background-color: #e9ecef;
|
||
color: #6c757d;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-weight: bold;
|
||
margin-bottom: 8px;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.step-indicator.active .step-circle {
|
||
background-color: #0d6efd;
|
||
color: white;
|
||
}
|
||
|
||
.step-indicator.completed .step-circle {
|
||
background-color: #198754;
|
||
color: white;
|
||
}
|
||
|
||
.step-label {
|
||
font-size: 0.9rem;
|
||
text-align: center;
|
||
color: #6c757d;
|
||
}
|
||
|
||
.step-indicator.active .step-label {
|
||
color: #0d6efd;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.step-indicator.completed .step-label {
|
||
color: #198754;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.step-line {
|
||
flex: 1;
|
||
height: 2px;
|
||
background-color: #e9ecef;
|
||
margin: 20px 0;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.step-line.completed {
|
||
background-color: #198754;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.step-indicator {
|
||
flex-direction: row;
|
||
align-items: center;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.step-circle {
|
||
margin-bottom: 0;
|
||
margin-right: 10px;
|
||
}
|
||
}
|
||
</style>
|
||
{% endblock %}
|
||
|
||
{% block scripts %}
|
||
<script src="{{ url_for('static', filename='js/voice_test.js') }}"></script>
|
||
{% endblock %}
|