Create templates/index.html
Browse files- templates/index.html +506 -0
templates/index.html
ADDED
|
@@ -0,0 +1,506 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="fa" dir="rtl">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>استودیو جادویی صدا | Magic Voice Studio</title>
|
| 7 |
+
|
| 8 |
+
<!-- وابستگیها -->
|
| 9 |
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
| 10 |
+
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
| 11 |
+
<link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@100;300;400;500;700;900&display=swap" rel="stylesheet">
|
| 12 |
+
|
| 13 |
+
<style>
|
| 14 |
+
:root {
|
| 15 |
+
--primary-color: #6366f1;
|
| 16 |
+
--accent-color: #ec4899;
|
| 17 |
+
--glass-bg: rgba(255, 255, 255, 0.85);
|
| 18 |
+
--glass-border: rgba(255, 255, 255, 0.6);
|
| 19 |
+
--text-main: #1e293b;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
/* جلوگیری از پرش صفحه هنگام تغییر ارتفاع */
|
| 23 |
+
html { overflow-y: scroll; }
|
| 24 |
+
|
| 25 |
+
body {
|
| 26 |
+
font-family: 'Vazirmatn', sans-serif;
|
| 27 |
+
background-color: #f0f2f5;
|
| 28 |
+
color: var(--text-main);
|
| 29 |
+
min-height: 100vh;
|
| 30 |
+
position: relative;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
/* پسزمینه متحرک مدرن */
|
| 34 |
+
.animated-bg {
|
| 35 |
+
position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1;
|
| 36 |
+
background: radial-gradient(at 0% 0%, hsla(253,16%,7%,1) 0, transparent 50%),
|
| 37 |
+
radial-gradient(at 50% 0%, hsla(225,39%,30%,1) 0, transparent 50%),
|
| 38 |
+
radial-gradient(at 100% 0%, hsla(339,49%,30%,1) 0, transparent 50%);
|
| 39 |
+
background-size: 200% 200%;
|
| 40 |
+
animation: gradientBG 15s ease infinite;
|
| 41 |
+
}
|
| 42 |
+
.bg-overlay {
|
| 43 |
+
position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: -1;
|
| 44 |
+
background: rgba(255,255,255,0.85); /* لایه روشن روی پس زمینه تیره */
|
| 45 |
+
backdrop-filter: blur(50px);
|
| 46 |
+
}
|
| 47 |
+
@keyframes gradientBG {
|
| 48 |
+
0% { background-position: 0% 50%; }
|
| 49 |
+
50% { background-position: 100% 50%; }
|
| 50 |
+
100% { background-position: 0% 50%; }
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
/* کارتهای شیشهای */
|
| 54 |
+
.glass-card {
|
| 55 |
+
background: rgba(255, 255, 255, 0.9);
|
| 56 |
+
backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
|
| 57 |
+
border: 1px solid white;
|
| 58 |
+
border-radius: 24px;
|
| 59 |
+
box-shadow: 0 10px 40px -10px rgba(0,0,0,0.1);
|
| 60 |
+
padding: 2rem;
|
| 61 |
+
transition: 0.3s;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
/* بخش توضیحات */
|
| 65 |
+
.info-hero {
|
| 66 |
+
background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
|
| 67 |
+
color: white;
|
| 68 |
+
border-radius: 20px;
|
| 69 |
+
padding: 2rem;
|
| 70 |
+
margin-bottom: 2rem;
|
| 71 |
+
box-shadow: 0 15px 30px -5px rgba(79, 70, 229, 0.3);
|
| 72 |
+
position: relative;
|
| 73 |
+
overflow: hidden;
|
| 74 |
+
}
|
| 75 |
+
.info-hero::after {
|
| 76 |
+
content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0;
|
| 77 |
+
background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.05'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
/* استایل فرم */
|
| 81 |
+
.form-control, .form-select {
|
| 82 |
+
border: 2px solid #e2e8f0; border-radius: 12px; padding: 12px;
|
| 83 |
+
background: #f8fafc; transition: 0.3s;
|
| 84 |
+
}
|
| 85 |
+
.form-control:focus {
|
| 86 |
+
background: white; border-color: var(--primary-color);
|
| 87 |
+
box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.1);
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
/* ناحیه آپلود */
|
| 91 |
+
.upload-zone {
|
| 92 |
+
border: 2px dashed #cbd5e1; border-radius: 16px; padding: 2rem;
|
| 93 |
+
text-align: center; cursor: pointer; transition: 0.3s; background: #fdfdfd;
|
| 94 |
+
}
|
| 95 |
+
.upload-zone:hover, .upload-zone.active {
|
| 96 |
+
border-color: var(--primary-color); background: #eef2ff;
|
| 97 |
+
}
|
| 98 |
+
.upload-zone i { font-size: 2.5rem; color: #94a3b8; transition: 0.3s; }
|
| 99 |
+
.upload-zone:hover i { color: var(--primary-color); transform: scale(1.1); }
|
| 100 |
+
|
| 101 |
+
/* پلیر پیشنمایش */
|
| 102 |
+
.preview-box {
|
| 103 |
+
display: none; /* پیشفرض مخفی */
|
| 104 |
+
background: #f1f5f9; padding: 10px; border-radius: 12px;
|
| 105 |
+
margin-top: 15px; border: 1px solid #e2e8f0;
|
| 106 |
+
animation: fadeIn 0.5s;
|
| 107 |
+
}
|
| 108 |
+
@keyframes fadeIn { from{opacity:0; transform:translateY(-10px)} to{opacity:1; transform:translateY(0)} }
|
| 109 |
+
|
| 110 |
+
/* دکمه جادویی */
|
| 111 |
+
.btn-magic {
|
| 112 |
+
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
|
| 113 |
+
color: white; border: none; padding: 16px; border-radius: 50px;
|
| 114 |
+
font-weight: 700; font-size: 1.1rem; width: 100%;
|
| 115 |
+
box-shadow: 0 10px 20px -5px rgba(99, 102, 241, 0.4);
|
| 116 |
+
transition: 0.3s; position: relative; overflow: hidden;
|
| 117 |
+
}
|
| 118 |
+
.btn-magic:hover { transform: translateY(-2px); box-shadow: 0 15px 30px -5px rgba(99, 102, 241, 0.5); }
|
| 119 |
+
.btn-magic:disabled { background: #cbd5e1; transform: none; box-shadow: none; cursor: not-allowed; }
|
| 120 |
+
|
| 121 |
+
/* آیتم تاریخچه */
|
| 122 |
+
.history-item {
|
| 123 |
+
background: white; border-radius: 16px; padding: 15px; margin-bottom: 12px;
|
| 124 |
+
border: 1px solid #f1f5f9; box-shadow: 0 2px 5px rgba(0,0,0,0.02);
|
| 125 |
+
position: relative; overflow: hidden;
|
| 126 |
+
}
|
| 127 |
+
.history-item.completed { border-right: 5px solid #10b981; }
|
| 128 |
+
.history-item.failed { border-right: 5px solid #ef4444; }
|
| 129 |
+
.history-item.processing { border-right: 5px solid #f59e0b; }
|
| 130 |
+
|
| 131 |
+
/* پلیر ساده تاریخچه */
|
| 132 |
+
audio { width: 100%; height: 35px; border-radius: 20px; }
|
| 133 |
+
audio::-webkit-media-controls-panel { background-color: #f1f5f9; }
|
| 134 |
+
|
| 135 |
+
/* دکمه حذف */
|
| 136 |
+
.btn-del {
|
| 137 |
+
position: absolute; top: 10px; left: 10px;
|
| 138 |
+
width: 28px; height: 28px; border-radius: 50%;
|
| 139 |
+
background: #fef2f2; color: #ef4444; border: none;
|
| 140 |
+
display: flex; align-items: center; justify-content: center;
|
| 141 |
+
transition: 0.2s;
|
| 142 |
+
}
|
| 143 |
+
.btn-del:hover { background: #ef4444; color: white; }
|
| 144 |
+
|
| 145 |
+
/* نوار پیشرفت */
|
| 146 |
+
.progress-slim { height: 4px; border-radius: 10px; background: #e2e8f0; overflow: hidden; margin-top: 8px; }
|
| 147 |
+
.progress-bar-anim {
|
| 148 |
+
height: 100%; background: var(--primary-color); width: 100%;
|
| 149 |
+
animation: shimmy 1.5s infinite linear;
|
| 150 |
+
background: linear-gradient(90deg, #6366f1, #ec4899, #6366f1);
|
| 151 |
+
background-size: 200% 100%;
|
| 152 |
+
}
|
| 153 |
+
@keyframes shimmy { 0%{background-position:100% 0} 100%{background-position:-100% 0} }
|
| 154 |
+
|
| 155 |
+
</style>
|
| 156 |
+
</head>
|
| 157 |
+
<body>
|
| 158 |
+
|
| 159 |
+
<!-- پس زمینه -->
|
| 160 |
+
<div class="animated-bg"></div>
|
| 161 |
+
<div class="bg-overlay"></div>
|
| 162 |
+
|
| 163 |
+
<div class="container py-5">
|
| 164 |
+
|
| 165 |
+
<!-- بخش توضیحات و هدر -->
|
| 166 |
+
<div class="info-hero">
|
| 167 |
+
<h1 class="fw-black mb-3"><i class="fas fa-magic me-2"></i>استودیو تغییر صدای آلفا</h1>
|
| 168 |
+
<p class="mb-4" style="line-height: 1.8; opacity: 0.9;">
|
| 169 |
+
به ابزار پیشرفته تغییر صدا (RVC) خوش آمدید. این سرویس به شما امکان میدهد صدای خود را با استفاده از مدلهای هوش مصنوعی به صدای شخصیتهای معروف، خوانندگان یا کاراکترهای انیمیشنی تبدیل کنید.
|
| 170 |
+
<br>
|
| 171 |
+
<strong>نحوه کار:</strong> کافیست فایل صدای خود را آپلود کنید و لینک مدل مورد نظر را وارد نمایید. سیستم ما با استفاده از پردازش ابری قدرتمند، صدا را بازسازی می کند. این سیستم برای کاربرانی است که مدل های تغییر صدا از پیش آموزش دیده شده دارند. اگر با این قسمت آشنایی ندارید از قسمت تغییر صدا با هوش مصنوعی آلفا استفاده کنید. اونجا مدل های تغییر صدا و ساخت مدل بصورت ساده وجود داره.
|
| 172 |
+
</p>
|
| 173 |
+
<div class="d-flex flex-wrap gap-3 p-3 bg-white bg-opacity-10 rounded-3 border border-white border-opacity-25">
|
| 174 |
+
<div class="d-flex align-items-center"><i class="fas fa-check-circle me-2 text-warning"></i> فرمت لینک: Zip مستقیم</div>
|
| 175 |
+
<div class="d-flex align-items-center"><i class="fas fa-check-circle me-2 text-warning"></i> محتوای Zip: فایل .pth و .index</div>
|
| 176 |
+
<div class="d-flex align-items-center"><i class="fas fa-cloud me-2 text-warning"></i> پردازش پایدار (حتی با بستن صفحه)</div>
|
| 177 |
+
</div>
|
| 178 |
+
</div>
|
| 179 |
+
|
| 180 |
+
<div class="row g-4">
|
| 181 |
+
|
| 182 |
+
<!-- ستون فرم (چپ) -->
|
| 183 |
+
<div class="col-lg-5">
|
| 184 |
+
<div class="glass-card h-100">
|
| 185 |
+
<h4 class="fw-bold mb-4 text-primary"><i class="fas fa-sliders-h me-2"></i>تنظیمات تبدیل</h4>
|
| 186 |
+
|
| 187 |
+
<form id="rvcForm">
|
| 188 |
+
<!-- 1. فایل صوتی -->
|
| 189 |
+
<div class="mb-4">
|
| 190 |
+
<label class="form-label fw-bold">۱. انتخاب فایل صوتی</label>
|
| 191 |
+
<div class="upload-zone" id="audioZone" onclick="document.getElementById('audioFile').click()">
|
| 192 |
+
<i class="fas fa-microphone-alt mb-2"></i>
|
| 193 |
+
<div class="fw-bold text-dark" id="audioFileName">برای انتخاب کلیک کنید</div>
|
| 194 |
+
<div class="small text-muted">پشتیبانی از MP3, WAV, OGG</div>
|
| 195 |
+
<input type="file" id="audioFile" hidden accept="audio/*">
|
| 196 |
+
</div>
|
| 197 |
+
|
| 198 |
+
<!-- پیشنمایش فایل انتخاب شده -->
|
| 199 |
+
<div id="audioPreview" class="preview-box">
|
| 200 |
+
<div class="d-flex align-items-center justify-content-between mb-1">
|
| 201 |
+
<small class="fw-bold text-primary">پیشنمایش ورودی:</small>
|
| 202 |
+
<button type="button" class="btn-close btn-close-sm" onclick="clearAudioInput()" aria-label="Close"></button>
|
| 203 |
+
</div>
|
| 204 |
+
<audio id="inputPlayer" controls></audio>
|
| 205 |
+
</div>
|
| 206 |
+
</div>
|
| 207 |
+
|
| 208 |
+
<!-- 2. لینک مدل -->
|
| 209 |
+
<div class="mb-4">
|
| 210 |
+
<label class="form-label fw-bold">۲. لینک مدل هوش مصنوعی</label>
|
| 211 |
+
<div class="input-group">
|
| 212 |
+
<span class="input-group-text bg-white"><i class="fas fa-link text-muted"></i></span>
|
| 213 |
+
<input type="text" id="modelUrl" class="form-control" dir="ltr" placeholder="https://example.com/...zip" required>
|
| 214 |
+
</div>
|
| 215 |
+
<div class="form-text text-muted">لینک باید مستقیم و با فرمت zip باشد.</div>
|
| 216 |
+
</div>
|
| 217 |
+
|
| 218 |
+
<!-- 3. تنظیمات پیشرفته (آکاردئون) -->
|
| 219 |
+
<div class="accordion mb-4" id="advSettings">
|
| 220 |
+
<div class="accordion-item border-0 bg-transparent">
|
| 221 |
+
<h2 class="accordion-header">
|
| 222 |
+
<button class="accordion-button collapsed bg-white rounded-3 shadow-sm border" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdv">
|
| 223 |
+
<i class="fas fa-cogs me-2 text-secondary"></i> تنظیمات حرفهای صدا
|
| 224 |
+
</button>
|
| 225 |
+
</h2>
|
| 226 |
+
<div id="collapseAdv" class="accordion-collapse collapse" data-bs-parent="#advSettings">
|
| 227 |
+
<div class="accordion-body bg-white rounded-3 mt-2 shadow-sm border">
|
| 228 |
+
|
| 229 |
+
<div class="mb-3">
|
| 230 |
+
<div class="d-flex justify-content-between small mb-1">
|
| 231 |
+
<span>تغییر گام (Pitch)</span>
|
| 232 |
+
<span class="badge bg-primary rounded-pill" id="pitchVal">0</span>
|
| 233 |
+
</div>
|
| 234 |
+
<input type="range" class="form-range" id="pitch" min="-12" max="12" step="1" value="0" oninput="document.getElementById('pitchVal').innerText=this.value">
|
| 235 |
+
<div class="d-flex justify-content-between small text-muted" style="font-size: 0.7rem;">
|
| 236 |
+
<span>مردانه (-12)</span>
|
| 237 |
+
<span>زنانه (+12)</span>
|
| 238 |
+
</div>
|
| 239 |
+
</div>
|
| 240 |
+
|
| 241 |
+
<div class="row g-2">
|
| 242 |
+
<div class="col-6">
|
| 243 |
+
<label class="small fw-bold">الگوریتم</label>
|
| 244 |
+
<select id="algo" class="form-select form-select-sm">
|
| 245 |
+
<option value="rmvpe+">RMVPE+ (پیشنهادی)</option>
|
| 246 |
+
<option value="rmvpe">RMVPE</option>
|
| 247 |
+
</select>
|
| 248 |
+
</div>
|
| 249 |
+
<div class="col-6">
|
| 250 |
+
<label class="small fw-bold">قدرت مدل</label>
|
| 251 |
+
<input type="number" id="indexInf" class="form-control form-control-sm text-center" value="0.75" step="0.05" max="1">
|
| 252 |
+
</div>
|
| 253 |
+
</div>
|
| 254 |
+
|
| 255 |
+
<div class="mt-3 d-flex gap-3 pt-2 border-top">
|
| 256 |
+
<div class="form-check form-switch">
|
| 257 |
+
<input class="form-check-input" type="checkbox" id="denoise">
|
| 258 |
+
<label class="form-check-label small" for="denoise">حذف نویز</label>
|
| 259 |
+
</div>
|
| 260 |
+
<div class="form-check form-switch">
|
| 261 |
+
<input class="form-check-input" type="checkbox" id="reverb">
|
| 262 |
+
<label class="form-check-label small" for="reverb">ریورب (اکو)</label>
|
| 263 |
+
</div>
|
| 264 |
+
</div>
|
| 265 |
+
|
| 266 |
+
</div>
|
| 267 |
+
</div>
|
| 268 |
+
</div>
|
| 269 |
+
</div>
|
| 270 |
+
|
| 271 |
+
<!-- دکمه شروع -->
|
| 272 |
+
<button type="submit" class="btn-magic" id="submitBtn">
|
| 273 |
+
<i class="fas fa-wand-magic-sparkles me-2"></i> شروع پردازش جادویی
|
| 274 |
+
</button>
|
| 275 |
+
|
| 276 |
+
<div class="text-center mt-3" id="loadingMsg" style="display:none;">
|
| 277 |
+
<small class="text-primary fw-bold blink">درخواست شما در حال ارسال به سرور است...</small>
|
| 278 |
+
</div>
|
| 279 |
+
</form>
|
| 280 |
+
</div>
|
| 281 |
+
</div>
|
| 282 |
+
|
| 283 |
+
<!-- ستون تاریخچه (راست) -->
|
| 284 |
+
<div class="col-lg-7">
|
| 285 |
+
<div class="glass-card h-100">
|
| 286 |
+
<div class="d-flex justify-content-between align-items-center mb-4 border-bottom pb-3">
|
| 287 |
+
<h4 class="fw-bold m-0 text-dark"><i class="fas fa-history me-2 text-primary"></i>فایلهای من</h4>
|
| 288 |
+
<button class="btn btn-outline-danger btn-sm rounded-pill px-3" onclick="confirmClearAll()">
|
| 289 |
+
<i class="fas fa-trash-alt"></i>
|
| 290 |
+
</button>
|
| 291 |
+
</div>
|
| 292 |
+
|
| 293 |
+
<div id="historyList" style="max-height: 600px; overflow-y: auto; padding-right: 5px;">
|
| 294 |
+
<!-- لیست توسط جاوااسکریپت پر میشود -->
|
| 295 |
+
</div>
|
| 296 |
+
</div>
|
| 297 |
+
</div>
|
| 298 |
+
</div>
|
| 299 |
+
</div>
|
| 300 |
+
|
| 301 |
+
<!-- Modal Delete -->
|
| 302 |
+
<div class="modal fade" id="deleteModal" tabindex="-1"><div class="modal-dialog modal-dialog-centered modal-sm"><div class="modal-content border-0 shadow"><div class="modal-body text-center p-4"><div class="text-danger mb-3"><i class="fas fa-exclamation-circle fa-3x"></i></div><h5 class="fw-bold mb-3">حذف فایل؟</h5><div class="d-flex gap-2 justify-content-center"><button class="btn btn-light rounded-pill w-50" data-bs-dismiss="modal">خیر</button><button class="btn btn-danger rounded-pill w-50" id="confirmDeleteBtn">بله، حذف کن</button></div></div></div></div></div>
|
| 303 |
+
|
| 304 |
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
| 305 |
+
<script>
|
| 306 |
+
// --- مدیریت فایل و پیشنمایش ---
|
| 307 |
+
const audioInput = document.getElementById('audioFile');
|
| 308 |
+
const audioName = document.getElementById('audioFileName');
|
| 309 |
+
const audioZone = document.getElementById('audioZone');
|
| 310 |
+
const audioPreview = document.getElementById('audioPreview');
|
| 311 |
+
const inputPlayer = document.getElementById('inputPlayer');
|
| 312 |
+
|
| 313 |
+
audioInput.addEventListener('change', function() {
|
| 314 |
+
const file = this.files[0];
|
| 315 |
+
if(file) {
|
| 316 |
+
audioName.innerText = file.name;
|
| 317 |
+
audioZone.classList.add('active');
|
| 318 |
+
audioZone.style.borderColor = 'var(--primary-color)';
|
| 319 |
+
|
| 320 |
+
// ایجاد لینک برای پخش
|
| 321 |
+
const objectUrl = URL.createObjectURL(file);
|
| 322 |
+
inputPlayer.src = objectUrl;
|
| 323 |
+
audioPreview.style.display = 'block';
|
| 324 |
+
}
|
| 325 |
+
});
|
| 326 |
+
|
| 327 |
+
function clearAudioInput() {
|
| 328 |
+
audioInput.value = '';
|
| 329 |
+
audioName.innerText = 'برای انتخاب کلیک کنید';
|
| 330 |
+
audioZone.classList.remove('active');
|
| 331 |
+
audioZone.style.borderColor = '#cbd5e1';
|
| 332 |
+
audioPreview.style.display = 'none';
|
| 333 |
+
inputPlayer.pause();
|
| 334 |
+
inputPlayer.src = '';
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
// --- توابع کمکی ---
|
| 338 |
+
let itemToDelete = null;
|
| 339 |
+
function humanizeLog(log) {
|
| 340 |
+
if (!log) return "در حال آمادهسازی...";
|
| 341 |
+
if (log.includes("chunks")) return "بخشبندی فایل برای افزایش سرعت...";
|
| 342 |
+
if (log.includes("worker") || log.includes("کارگر")) return "پردازش توسط موتور هوش مصنوعی...";
|
| 343 |
+
if (log.includes("download") || log.includes("دانلود")) return "دریافت فایل مدل از سرور...";
|
| 344 |
+
if (log.includes("stitching") || log.includes("ترکیب")) return "تولید و ترکیب نهایی صدا...";
|
| 345 |
+
if (log.includes("completed")) return "تکمیل شد.";
|
| 346 |
+
if (log.includes("failed")) return "خطا در پردازش.";
|
| 347 |
+
return log;
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
// --- مدیریت LocalStorage ---
|
| 351 |
+
function getJobs() { return JSON.parse(localStorage.getItem('alpha_voice_jobs_v2') || '[]'); }
|
| 352 |
+
function saveJob(job) { const jobs = getJobs(); jobs.unshift(job); localStorage.setItem('alpha_voice_jobs_v2', JSON.stringify(jobs)); renderHistory(); }
|
| 353 |
+
function updateJobStatus(id, status, filename, log) {
|
| 354 |
+
const jobs = getJobs(); const idx = jobs.findIndex(j => j.id === id);
|
| 355 |
+
if (idx !== -1 && (jobs[idx].status !== status || jobs[idx].log !== log)) {
|
| 356 |
+
jobs[idx].status = status; if(filename) jobs[idx].filename = filename; if(log) jobs[idx].log = log;
|
| 357 |
+
localStorage.setItem('alpha_voice_jobs_v2', JSON.stringify(jobs)); renderHistory();
|
| 358 |
+
}
|
| 359 |
+
}
|
| 360 |
+
function deleteJob(id) {
|
| 361 |
+
const jobs = getJobs().filter(j => j.id !== id);
|
| 362 |
+
localStorage.setItem('alpha_voice_jobs_v2', JSON.stringify(jobs)); renderHistory();
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
// --- توابع مدال ---
|
| 366 |
+
function confirmDelete(id) { itemToDelete = id; new bootstrap.Modal(document.getElementById('deleteModal')).show(); }
|
| 367 |
+
document.getElementById('confirmDeleteBtn').addEventListener('click', () => { if(itemToDelete) deleteJob(itemToDelete); bootstrap.Modal.getInstance(document.getElementById('deleteModal')).hide(); });
|
| 368 |
+
function confirmClearAll() { if(confirm("تمام تاریخچه پاک شود؟")) { localStorage.removeItem('alpha_voice_jobs_v2'); renderHistory(); } }
|
| 369 |
+
|
| 370 |
+
// --- PostMessage برای دانلود ---
|
| 371 |
+
async function sendDownloadToParent(filename) {
|
| 372 |
+
const btn = document.getElementById(`btn-${filename.split('.')[0]}`);
|
| 373 |
+
if(btn) { btn.innerHTML = '<i class="fas fa-circle-notch fa-spin"></i>'; btn.disabled = true; }
|
| 374 |
+
try {
|
| 375 |
+
const res = await fetch(`/download/${filename}`);
|
| 376 |
+
if (!res.ok) throw new Error("File not found");
|
| 377 |
+
const blob = await res.blob();
|
| 378 |
+
const blobUrl = URL.createObjectURL(blob);
|
| 379 |
+
window.parent.postMessage({ type: 'INITIATE_DOWNLOAD_FROM_URL', payload: { audioUrl: blobUrl } }, '*');
|
| 380 |
+
} catch (e) { alert("خطا در دانلود: " + e.message); }
|
| 381 |
+
finally { if(btn) { btn.innerHTML = '<i class="fas fa-download me-2"></i> دانلود'; btn.disabled = false; } }
|
| 382 |
+
}
|
| 383 |
+
|
| 384 |
+
// --- رندر لیست ---
|
| 385 |
+
function renderHistory() {
|
| 386 |
+
const jobs = getJobs();
|
| 387 |
+
const list = document.getElementById('historyList');
|
| 388 |
+
list.innerHTML = '';
|
| 389 |
+
|
| 390 |
+
if (jobs.length === 0) {
|
| 391 |
+
list.innerHTML = `
|
| 392 |
+
<div class="text-center py-5 text-muted opacity-50">
|
| 393 |
+
<i class="fas fa-music fa-3x mb-3"></i>
|
| 394 |
+
<p>لیست خالی است. اولین آهنگ خود را بسازید!</p>
|
| 395 |
+
</div>`;
|
| 396 |
+
return;
|
| 397 |
+
}
|
| 398 |
+
|
| 399 |
+
jobs.forEach(job => {
|
| 400 |
+
const btnId = `btn-${job.filename ? job.filename.split('.')[0] : job.id}`;
|
| 401 |
+
const cleanLog = humanizeLog(job.log);
|
| 402 |
+
let content = '';
|
| 403 |
+
let badge = '';
|
| 404 |
+
|
| 405 |
+
if (job.status === 'completed') {
|
| 406 |
+
badge = `<span class="badge bg-success rounded-pill fw-normal">آماده</span>`;
|
| 407 |
+
// پلیر ساده + دکمه دانلود تمیز
|
| 408 |
+
content = `
|
| 409 |
+
<div class="mt-3">
|
| 410 |
+
<audio controls src="/download/${job.filename}" class="mb-2"></audio>
|
| 411 |
+
<button id="${btnId}" onclick="sendDownloadToParent('${job.filename}')" class="btn btn-success btn-sm w-100 rounded-pill fw-bold">
|
| 412 |
+
<i class="fas fa-download me-2"></i> دانلود فایل
|
| 413 |
+
</button>
|
| 414 |
+
</div>`;
|
| 415 |
+
} else if (job.status === 'failed') {
|
| 416 |
+
badge = `<span class="badge bg-danger rounded-pill fw-normal">خطا</span>`;
|
| 417 |
+
content = `<div class="mt-2 text-danger small bg-danger bg-opacity-10 p-2 rounded"><i class="fas fa-bug me-1"></i> ${cleanLog}</div>`;
|
| 418 |
+
} else {
|
| 419 |
+
badge = `<span class="badge bg-warning text-dark rounded-pill fw-normal">در حال کار</span>`;
|
| 420 |
+
content = `
|
| 421 |
+
<div class="mt-2">
|
| 422 |
+
<div class="d-flex justify-content-between small text-primary mb-1">
|
| 423 |
+
<span>${cleanLog}</span>
|
| 424 |
+
<i class="fas fa-spinner fa-spin"></i>
|
| 425 |
+
</div>
|
| 426 |
+
<div class="progress-slim"><div class="progress-bar-anim"></div></div>
|
| 427 |
+
</div>`;
|
| 428 |
+
}
|
| 429 |
+
|
| 430 |
+
const item = document.createElement('div');
|
| 431 |
+
item.className = `history-item ${job.status}`;
|
| 432 |
+
item.innerHTML = `
|
| 433 |
+
<button class="btn-del" onclick="confirmDelete('${job.id}')"><i class="fas fa-times"></i></button>
|
| 434 |
+
<div class="ps-4">
|
| 435 |
+
<div class="d-flex justify-content-between align-items-center">
|
| 436 |
+
<div>
|
| 437 |
+
<div class="fw-bold">پروژه #${job.id.substring(0,5)}</div>
|
| 438 |
+
<div class="small text-muted">${job.date}</div>
|
| 439 |
+
</div>
|
| 440 |
+
${badge}
|
| 441 |
+
</div>
|
| 442 |
+
${content}
|
| 443 |
+
</div>
|
| 444 |
+
`;
|
| 445 |
+
list.appendChild(item);
|
| 446 |
+
});
|
| 447 |
+
}
|
| 448 |
+
|
| 449 |
+
// --- ارسال فرم ---
|
| 450 |
+
document.getElementById('rvcForm').addEventListener('submit', async (e) => {
|
| 451 |
+
e.preventDefault();
|
| 452 |
+
const btn = document.getElementById('submitBtn');
|
| 453 |
+
const file = document.getElementById('audioFile').files[0];
|
| 454 |
+
const url = document.getElementById('modelUrl').value;
|
| 455 |
+
|
| 456 |
+
if(!file) return alert("لطفا فایل صوتی را انتخاب کنید");
|
| 457 |
+
|
| 458 |
+
btn.disabled = true;
|
| 459 |
+
btn.innerHTML = '<i class="fas fa-cloud-upload-alt fa-bounce me-2"></i> در حال ارسال...';
|
| 460 |
+
document.getElementById('loadingMsg').style.display = 'block';
|
| 461 |
+
|
| 462 |
+
const fd = new FormData();
|
| 463 |
+
fd.append('audio_file', file);
|
| 464 |
+
fd.append('model_url', url);
|
| 465 |
+
fd.append('pitch', document.getElementById('pitch').value);
|
| 466 |
+
fd.append('algo', document.getElementById('algo').value);
|
| 467 |
+
fd.append('index_inf', document.getElementById('indexInf').value);
|
| 468 |
+
fd.append('denoise', document.getElementById('denoise').checked);
|
| 469 |
+
fd.append('reverb', document.getElementById('reverb').checked);
|
| 470 |
+
|
| 471 |
+
try {
|
| 472 |
+
const res = await fetch('/upload', { method: 'POST', body: fd });
|
| 473 |
+
const data = await res.json();
|
| 474 |
+
if(data.error) alert(data.error);
|
| 475 |
+
else {
|
| 476 |
+
saveJob({ id: data.job_id, status: 'queued', date: new Date().toLocaleTimeString('fa-IR'), log: 'در حال ارسال...', filename: null });
|
| 477 |
+
clearAudioInput(); // فرم را تمیز کن
|
| 478 |
+
monitorJob(data.job_id);
|
| 479 |
+
}
|
| 480 |
+
} catch (err) { alert("خطا: " + err); }
|
| 481 |
+
finally {
|
| 482 |
+
btn.disabled = false;
|
| 483 |
+
btn.innerHTML = '<i class="fas fa-wand-magic-sparkles me-2"></i> شروع پردازش جادویی';
|
| 484 |
+
document.getElementById('loadingMsg').style.display = 'none';
|
| 485 |
+
}
|
| 486 |
+
});
|
| 487 |
+
|
| 488 |
+
// --- پایش وضعیت ---
|
| 489 |
+
function startGlobalMonitor() { getJobs().forEach(j => { if(j.status !== 'completed' && j.status !== 'failed') monitorJob(j.id); }); }
|
| 490 |
+
function monitorJob(id) {
|
| 491 |
+
const interval = setInterval(async () => {
|
| 492 |
+
try {
|
| 493 |
+
const res = await fetch(`/status/${id}`);
|
| 494 |
+
const data = await res.json();
|
| 495 |
+
if (data.status === 'not_found') { updateJobStatus(id, 'failed', null, 'اطلاعات سرور از دست رفت'); clearInterval(interval); return; }
|
| 496 |
+
updateJobStatus(id, data.status, data.filename, data.log);
|
| 497 |
+
if (data.status === 'completed' || data.status === 'failed') clearInterval(interval);
|
| 498 |
+
} catch (e) {}
|
| 499 |
+
}, 3000);
|
| 500 |
+
}
|
| 501 |
+
|
| 502 |
+
renderHistory();
|
| 503 |
+
startGlobalMonitor();
|
| 504 |
+
</script>
|
| 505 |
+
</body>
|
| 506 |
+
</html>
|