Files
dsProject/dsLightRag/static/LibLib/copyface.html
2025-09-04 11:51:32 +08:00

301 lines
10 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>人像换脸生成器</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
.container {
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
text-align: center;
margin-bottom: 30px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #555;
}
input[type="url"], select {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 14px;
}
button {
background-color: #007bff;
color: white;
padding: 12px 24px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
margin-right: 10px;
}
button:hover {
background-color: #0056b3;
}
button:disabled {
background-color: #6c757d;
cursor: not-allowed;
}
.image-preview {
margin-top: 20px;
text-align: center;
}
.image-preview img {
max-width: 300px;
max-height: 300px;
border: 2px solid #ddd;
border-radius: 5px;
}
.result {
margin-top: 30px;
padding: 20px;
background-color: #f8f9fa;
border-radius: 5px;
border-left: 4px solid #007bff;
}
.result img {
max-width: 100%;
max-height: 400px;
border: 2px solid #28a745;
border-radius: 5px;
}
.loading {
display: none;
text-align: center;
margin: 20px 0;
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #007bff;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.error {
color: #dc3545;
background-color: #f8d7da;
border: 1px solid #f5c6cb;
padding: 10px;
border-radius: 5px;
margin: 10px 0;
}
.success {
color: #155724;
background-color: #d4edda;
border: 1px solid #c3e6cb;
padding: 10px;
border-radius: 5px;
margin: 10px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>🎭 人像换脸生成器</h1>
<div class="form-group">
<label for="imageUrl">图片URL地址</label>
<input type="url" id="imageUrl" placeholder="请输入图片URL地址"
value="https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Backup/HuangWanQiao.jpg">
</div>
<div class="form-group">
<label for="modelSelect">选择生成模型:</label>
<select id="modelSelect">
<option value="">加载中...</option>
</select>
</div>
<div class="image-preview" id="previewContainer">
<h3>参考图片预览:</h3>
<img id="previewImage" src="https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Backup/HuangWanQiao.jpg"
alt="参考图片预览" onerror="this.style.display='none'">
</div>
<button onclick="generateImage()" id="generateBtn">生成换脸图片</button>
<button onclick="loadSamples()" id="refreshBtn">刷新模型列表</button>
<div class="loading" id="loading">
<div class="spinner"></div>
<p>正在生成中,请稍候...</p>
</div>
<div class="result" id="resultContainer" style="display: none;">
<h3>生成结果:</h3>
<div id="resultMessage"></div>
<div id="resultImage"></div>
</div>
</div>
<script>
const API_BASE = '/api/copyface';
// 页面加载时获取可用模型
document.addEventListener('DOMContentLoaded', function() {
loadSamples();
// 监听URL输入变化实时预览
document.getElementById('imageUrl').addEventListener('input', function() {
const url = this.value.trim();
const previewImg = document.getElementById('previewImage');
if (url) {
previewImg.src = url;
previewImg.style.display = 'block';
} else {
previewImg.style.display = 'none';
}
});
});
// 加载可用模型样例
async function loadSamples() {
const select = document.getElementById('modelSelect');
const refreshBtn = document.getElementById('refreshBtn');
refreshBtn.disabled = true;
refreshBtn.textContent = '加载中...';
try {
const response = await fetch(`${API_BASE}/samples`);
if (!response.ok) {
throw new Error('获取模型列表失败');
}
const samples = await response.json();
// 清空并填充选项
select.innerHTML = '';
samples.forEach(sample => {
const option = document.createElement('option');
option.value = sample.name;
option.textContent = sample.name;
select.appendChild(option);
});
if (samples.length > 0) {
select.value = samples[0].name;
}
} catch (error) {
console.error('加载模型失败:', error);
select.innerHTML = '<option value="">加载失败,点击刷新</option>';
} finally {
refreshBtn.disabled = false;
refreshBtn.textContent = '刷新模型列表';
}
}
// 生成换脸图片
async function generateImage() {
const imageUrl = document.getElementById('imageUrl').value.trim();
const modelName = document.getElementById('modelSelect').value;
const generateBtn = document.getElementById('generateBtn');
const loading = document.getElementById('loading');
const resultContainer = document.getElementById('resultContainer');
const resultMessage = document.getElementById('resultMessage');
const resultImage = document.getElementById('resultImage');
// 验证输入
if (!imageUrl) {
alert('请输入图片URL地址');
return;
}
if (!modelName) {
alert('请选择生成模型');
return;
}
// 显示加载状态
generateBtn.disabled = true;
loading.style.display = 'block';
resultContainer.style.display = 'none';
try {
let apiUrl = `${API_BASE}/generate`;
if (modelName) {
apiUrl = `${API_BASE}/generate/${encodeURIComponent(modelName)}`;
}
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
image_url: imageUrl
})
});
const result = await response.json();
if (response.ok && result.status === 'success') {
// 显示成功结果
resultMessage.innerHTML = `
<div class="success">
${result.message}<br>
📦 使用模型: ${result.model_used}<br>
🌐 OBS地址: <a href="${result.obs_url}" target="_blank">${result.obs_url}</a>
</div>
`;
resultImage.innerHTML = `
<h4>生成结果预览:</h4>
<img src="${result.obs_url}" alt="生成结果"
onerror="this.style.display='none'; alert('图片加载失败请检查OBS地址')">
`;
} else {
// 显示错误信息
resultMessage.innerHTML = `
<div class="error">
❌ 生成失败: ${result.detail || result.message || '未知错误'}
</div>
`;
resultImage.innerHTML = '';
}
resultContainer.style.display = 'block';
} catch (error) {
console.error('生成请求失败:', error);
resultMessage.innerHTML = `
<div class="error">
❌ 请求失败: ${error.message}
</div>
`;
resultContainer.style.display = 'block';
} finally {
generateBtn.disabled = false;
loading.style.display = 'none';
}
}
</script>
</body>
</html>