X commited on
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,399 +1,120 @@
|
|
| 1 |
-
import gradio as gr
|
| 2 |
-
import torch
|
| 3 |
-
import torch.nn as nn
|
| 4 |
-
import torch.nn.functional as F
|
| 5 |
-
import numpy as np
|
| 6 |
-
from PIL import Image
|
| 7 |
-
import imageio
|
| 8 |
import os
|
| 9 |
-
import
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
-
# ===
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
super().__init__()
|
| 15 |
-
|
| 16 |
-
# Encoder
|
| 17 |
-
self.enc1 = self._block(3, 32)
|
| 18 |
-
self.enc2 = self._block(32, 64)
|
| 19 |
-
self.enc3 = self._block(64, 128)
|
| 20 |
-
self.enc4 = self._block(128, 256)
|
| 21 |
-
self.pool = nn.MaxPool2d(2)
|
| 22 |
-
|
| 23 |
-
# LSTM
|
| 24 |
-
self.lstm = nn.LSTM(
|
| 25 |
-
input_size=256 * 8 * 8,
|
| 26 |
-
hidden_size=512,
|
| 27 |
-
num_layers=2,
|
| 28 |
-
batch_first=True,
|
| 29 |
-
dropout=0.2
|
| 30 |
-
)
|
| 31 |
-
|
| 32 |
-
# Decoder
|
| 33 |
-
self.dec4 = self._block(512, 256)
|
| 34 |
-
self.dec3 = self._block(256, 128)
|
| 35 |
-
self.dec2 = self._block(128, 64)
|
| 36 |
-
self.dec1 = self._block(64, 32)
|
| 37 |
-
|
| 38 |
-
self.up4 = nn.ConvTranspose2d(512, 256, 2, stride=2)
|
| 39 |
-
self.up3 = nn.ConvTranspose2d(256, 128, 2, stride=2)
|
| 40 |
-
self.up2 = nn.ConvTranspose2d(128, 64, 2, stride=2)
|
| 41 |
-
self.up1 = nn.ConvTranspose2d(64, 32, 2, stride=2)
|
| 42 |
-
|
| 43 |
-
self.frame_generator = nn.Sequential(
|
| 44 |
-
nn.Conv2d(32, 16, 3, padding=1),
|
| 45 |
-
nn.ReLU(),
|
| 46 |
-
nn.Conv2d(16, 3, 3, padding=1),
|
| 47 |
-
nn.Tanh()
|
| 48 |
-
)
|
| 49 |
-
|
| 50 |
-
def _block(self, in_ch, out_ch):
|
| 51 |
-
return nn.Sequential(
|
| 52 |
-
nn.Conv2d(in_ch, out_ch, 3, padding=1),
|
| 53 |
-
nn.BatchNorm2d(out_ch),
|
| 54 |
-
nn.ReLU(inplace=True),
|
| 55 |
-
nn.Conv2d(out_ch, out_ch, 3, padding=1),
|
| 56 |
-
nn.BatchNorm2d(out_ch),
|
| 57 |
-
nn.ReLU(inplace=True)
|
| 58 |
-
)
|
| 59 |
-
|
| 60 |
-
def forward(self, x, num_frames=20):
|
| 61 |
-
batch_size = x.size(0)
|
| 62 |
-
|
| 63 |
-
# Encoder
|
| 64 |
-
e1 = self.enc1(x)
|
| 65 |
-
e2 = self.enc2(self.pool(e1))
|
| 66 |
-
e3 = self.enc3(self.pool(e2))
|
| 67 |
-
e4 = self.enc4(self.pool(e3))
|
| 68 |
-
|
| 69 |
-
skips = [e1, e2, e3, e4]
|
| 70 |
-
|
| 71 |
-
# Bottleneck
|
| 72 |
-
bottleneck = e4.view(batch_size, -1)
|
| 73 |
-
|
| 74 |
-
frames = []
|
| 75 |
-
hidden = None
|
| 76 |
-
lstm_input = bottleneck.unsqueeze(1)
|
| 77 |
-
|
| 78 |
-
for t in range(num_frames):
|
| 79 |
-
lstm_out, hidden = self.lstm(lstm_input, hidden)
|
| 80 |
-
|
| 81 |
-
h = lstm_out.squeeze(1).view(batch_size, 256, 8, 8)
|
| 82 |
-
|
| 83 |
-
# Decoder с проверкой размеров
|
| 84 |
-
d4 = self.up4(h)
|
| 85 |
-
# Проверяем размеры и при необходимости ресайзим
|
| 86 |
-
if d4.size(2) != skips[3].size(2) or d4.size(3) != skips[3].size(3):
|
| 87 |
-
skips[3] = F.interpolate(skips[3], size=(d4.size(2), d4.size(3)), mode='bilinear')
|
| 88 |
-
d4 = torch.cat([d4, skips[3]], dim=1)
|
| 89 |
-
d4 = self.dec4(d4)
|
| 90 |
-
|
| 91 |
-
d3 = self.up3(d4)
|
| 92 |
-
if d3.size(2) != skips[2].size(2) or d3.size(3) != skips[2].size(3):
|
| 93 |
-
skips[2] = F.interpolate(skips[2], size=(d3.size(2), d3.size(3)), mode='bilinear')
|
| 94 |
-
d3 = torch.cat([d3, skips[2]], dim=1)
|
| 95 |
-
d3 = self.dec3(d3)
|
| 96 |
-
|
| 97 |
-
d2 = self.up2(d3)
|
| 98 |
-
if d2.size(2) != skips[1].size(2) or d2.size(3) != skips[1].size(3):
|
| 99 |
-
skips[1] = F.interpolate(skips[1], size=(d2.size(2), d2.size(3)), mode='bilinear')
|
| 100 |
-
d2 = torch.cat([d2, skips[1]], dim=1)
|
| 101 |
-
d2 = self.dec2(d2)
|
| 102 |
-
|
| 103 |
-
d1 = self.up1(d2)
|
| 104 |
-
if d1.size(2) != skips[0].size(2) or d1.size(3) != skips[0].size(3):
|
| 105 |
-
skips[0] = F.interpolate(skips[0], size=(d1.size(2), d1.size(3)), mode='bilinear')
|
| 106 |
-
d1 = torch.cat([d1, skips[0]], dim=1)
|
| 107 |
-
d1 = self.dec1(d1)
|
| 108 |
-
|
| 109 |
-
frame = self.frame_generator(d1)
|
| 110 |
-
frames.append(frame)
|
| 111 |
-
|
| 112 |
-
# Обновляем вход для LSTM
|
| 113 |
-
next_features = self.enc4(self.pool(self.enc3(self.pool(self.enc2(self.pool(self.enc1(frame)))))))
|
| 114 |
-
next_features = next_features.view(batch_size, -1)
|
| 115 |
-
lstm_input = next_features.unsqueeze(1)
|
| 116 |
-
|
| 117 |
-
return torch.stack(frames, dim=1)
|
| 118 |
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
def __init__(self):
|
| 122 |
-
super().__init__()
|
| 123 |
-
|
| 124 |
-
self.style_embeddings = nn.ParameterDict({
|
| 125 |
-
'wave': nn.Parameter(torch.randn(64)),
|
| 126 |
-
'pulse': nn.Parameter(torch.randn(64)),
|
| 127 |
-
'glitch': nn.Parameter(torch.randn(64)),
|
| 128 |
-
'melt': nn.Parameter(torch.randn(64)),
|
| 129 |
-
'twist': nn.Parameter(torch.randn(64)),
|
| 130 |
-
})
|
| 131 |
-
|
| 132 |
-
self.encoder = nn.Sequential(
|
| 133 |
-
nn.Conv2d(3, 32, 4, stride=2, padding=1),
|
| 134 |
-
nn.ReLU(),
|
| 135 |
-
nn.Conv2d(32, 64, 4, stride=2, padding=1),
|
| 136 |
-
nn.ReLU(),
|
| 137 |
-
nn.Conv2d(64, 128, 4, stride=2, padding=1),
|
| 138 |
-
nn.ReLU(),
|
| 139 |
-
nn.Conv2d(128, 256, 4, stride=2, padding=1),
|
| 140 |
-
nn.ReLU(),
|
| 141 |
-
)
|
| 142 |
-
|
| 143 |
-
self.lstm = nn.LSTM(
|
| 144 |
-
input_size=256 * 8 * 8,
|
| 145 |
-
hidden_size=512,
|
| 146 |
-
num_layers=2,
|
| 147 |
-
batch_first=True,
|
| 148 |
-
dropout=0.2
|
| 149 |
-
)
|
| 150 |
-
|
| 151 |
-
self.decoder = nn.Sequential(
|
| 152 |
-
nn.ConvTranspose2d(512 + 64, 256, 4, stride=2, padding=1),
|
| 153 |
-
nn.ReLU(),
|
| 154 |
-
nn.ConvTranspose2d(256, 128, 4, stride=2, padding=1),
|
| 155 |
-
nn.ReLU(),
|
| 156 |
-
nn.ConvTranspose2d(128, 64, 4, stride=2, padding=1),
|
| 157 |
-
nn.ReLU(),
|
| 158 |
-
nn.ConvTranspose2d(64, 3, 4, stride=2, padding=1),
|
| 159 |
-
nn.Tanh()
|
| 160 |
-
)
|
| 161 |
-
|
| 162 |
-
def forward(self, x, style='wave', num_frames=20):
|
| 163 |
-
batch_size = x.size(0)
|
| 164 |
-
|
| 165 |
-
features = self.encoder(x)
|
| 166 |
-
features_flat = features.view(batch_size, -1)
|
| 167 |
-
|
| 168 |
-
style_vector = self.style_embeddings[style]
|
| 169 |
-
style_vector = style_vector.unsqueeze(0).repeat(batch_size, 1)
|
| 170 |
-
|
| 171 |
-
frames = []
|
| 172 |
-
hidden = None
|
| 173 |
-
lstm_input = features_flat.unsqueeze(1)
|
| 174 |
-
|
| 175 |
-
for t in range(num_frames):
|
| 176 |
-
lstm_out, hidden = self.lstm(lstm_input, hidden)
|
| 177 |
-
|
| 178 |
-
h = lstm_out.squeeze(1).view(batch_size, 256, 8, 8)
|
| 179 |
-
style_expanded = style_vector.view(batch_size, 64, 1, 1).repeat(1, 1, 8, 8)
|
| 180 |
-
decoder_input = torch.cat([h, style_expanded], dim=1)
|
| 181 |
-
|
| 182 |
-
frame = self.decoder(decoder_input)
|
| 183 |
-
frames.append(frame)
|
| 184 |
-
|
| 185 |
-
next_features = self.encoder(frame)
|
| 186 |
-
next_features = next_features.view(batch_size, -1)
|
| 187 |
-
lstm_input = next_features.unsqueeze(1)
|
| 188 |
-
|
| 189 |
-
return torch.stack(frames, dim=1)
|
| 190 |
|
| 191 |
-
|
| 192 |
-
class NeuralAnimator:
|
| 193 |
-
def __init__(self):
|
| 194 |
-
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
| 195 |
-
print(f"🔥 Устройство: {self.device}")
|
| 196 |
-
|
| 197 |
-
self.animator = FullNeuralAnimator().to(self.device)
|
| 198 |
-
self.styler = StyleTransferAnimator().to(self.device)
|
| 199 |
-
|
| 200 |
-
self.load_models()
|
| 201 |
-
|
| 202 |
-
self.animator.eval()
|
| 203 |
-
self.styler.eval()
|
| 204 |
-
|
| 205 |
-
def load_models(self):
|
| 206 |
-
models_dir = 'neural_models'
|
| 207 |
-
os.makedirs(models_dir, exist_ok=True)
|
| 208 |
-
|
| 209 |
-
if os.path.exists(f'{models_dir}/animator.pth'):
|
| 210 |
-
self.animator.load_state_dict(torch.load(f'{models_dir}/animator.pth', map_location=self.device))
|
| 211 |
-
print("✅ Аниматор загружен")
|
| 212 |
-
else:
|
| 213 |
-
print("⚠️ Модель не найдена, используем случайную")
|
| 214 |
-
|
| 215 |
-
if os.path.exists(f'{models_dir}/styler.pth'):
|
| 216 |
-
self.styler.load_state_dict(torch.load(f'{models_dir}/styler.pth', map_location=self.device))
|
| 217 |
-
print("✅ Стилизатор загружен")
|
| 218 |
-
|
| 219 |
-
def generate_animation(self, image, style='wave', num_frames=20, size=128):
|
| 220 |
-
if image is None:
|
| 221 |
-
return None
|
| 222 |
-
|
| 223 |
-
if isinstance(image, np.ndarray):
|
| 224 |
-
img = Image.fromarray(image)
|
| 225 |
-
else:
|
| 226 |
-
img = image
|
| 227 |
-
|
| 228 |
-
img = img.resize((size, size))
|
| 229 |
-
img_tensor = torch.from_numpy(np.array(img)).float() / 127.5 - 1
|
| 230 |
-
img_tensor = img_tensor.permute(2, 0, 1).unsqueeze(0).to(self.device)
|
| 231 |
-
|
| 232 |
-
with torch.no_grad():
|
| 233 |
-
if style in ['wave', 'pulse', 'glitch', 'melt', 'twist']:
|
| 234 |
-
frames_tensor = self.styler(img_tensor, style=style, num_frames=num_frames)
|
| 235 |
-
else:
|
| 236 |
-
frames_tensor = self.animator(img_tensor, num_frames=num_frames)
|
| 237 |
-
|
| 238 |
-
frames = []
|
| 239 |
-
for t in range(num_frames):
|
| 240 |
-
frame = frames_tensor[0, t].cpu().numpy().transpose(1, 2, 0)
|
| 241 |
-
frame = np.clip((frame + 1) / 2, 0, 1)
|
| 242 |
-
frames.append((frame * 255).astype(np.uint8))
|
| 243 |
-
|
| 244 |
-
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.gif')
|
| 245 |
-
imageio.mimsave(temp_file.name, frames, duration=0.05, loop=0)
|
| 246 |
-
|
| 247 |
-
return temp_file.name
|
| 248 |
|
| 249 |
-
# ===
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
loss_style = loss_style_smooth + 0.5 * loss_style_consistency
|
| 284 |
-
|
| 285 |
-
opt_style.zero_grad()
|
| 286 |
-
loss_style.backward()
|
| 287 |
-
opt_style.step()
|
| 288 |
-
|
| 289 |
-
print(f"Epoch {epoch+1}/5 | Loss: {loss_anim.item():.4f} | Style: {loss_style.item():.4f}")
|
| 290 |
-
|
| 291 |
-
os.makedirs('neural_models', exist_ok=True)
|
| 292 |
-
torch.save(animator.state_dict(), 'neural_models/animator.pth')
|
| 293 |
-
torch.save(styler.state_dict(), 'neural_models/styler.pth')
|
| 294 |
-
|
| 295 |
-
print("✅ Обучение завершено!")
|
| 296 |
-
return "✅ Модель обучена!"
|
| 297 |
|
| 298 |
-
# ===
|
| 299 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 300 |
|
| 301 |
-
def
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
|
|
|
|
|
|
| 309 |
|
| 310 |
-
# С
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
type="numpy",
|
| 323 |
-
height=300
|
| 324 |
-
)
|
| 325 |
-
|
| 326 |
-
style = gr.Dropdown(
|
| 327 |
-
choices=[
|
| 328 |
-
("Волна 🌊", "wave"),
|
| 329 |
-
("Пульс 💓", "pulse"),
|
| 330 |
-
("Глитч 📺", "glitch"),
|
| 331 |
-
("Плавление 🕯️", "melt"),
|
| 332 |
-
("Скручивание 🌀", "twist"),
|
| 333 |
-
("Нейросетевой 🧠", "neural")
|
| 334 |
-
],
|
| 335 |
-
label="🎨 Стиль анимации",
|
| 336 |
-
value="wave"
|
| 337 |
-
)
|
| 338 |
-
|
| 339 |
-
frames = gr.Slider(
|
| 340 |
-
minimum=10,
|
| 341 |
-
maximum=30,
|
| 342 |
-
value=20,
|
| 343 |
-
step=5,
|
| 344 |
-
label="Количество кадров"
|
| 345 |
-
)
|
| 346 |
-
|
| 347 |
-
size = gr.Slider(
|
| 348 |
-
minimum=64,
|
| 349 |
-
maximum=256,
|
| 350 |
-
value=128,
|
| 351 |
-
step=64,
|
| 352 |
-
label="Размер (чем меньше, тем быстрее)"
|
| 353 |
-
)
|
| 354 |
-
|
| 355 |
-
with gr.Row():
|
| 356 |
-
generate_btn = gr.Button("🧠 Запустить!", variant="primary")
|
| 357 |
-
train_btn = gr.Button("🎓 Обучить", variant="secondary")
|
| 358 |
-
|
| 359 |
-
status = gr.Textbox(label="Статус", value="Готов к работе")
|
| 360 |
-
|
| 361 |
-
with gr.Column(scale=1):
|
| 362 |
-
output_gif = gr.Image(
|
| 363 |
-
label="🎬 Результат",
|
| 364 |
-
type="filepath",
|
| 365 |
-
height=400
|
| 366 |
-
)
|
| 367 |
-
|
| 368 |
-
download_btn = gr.DownloadButton(
|
| 369 |
-
label="📥 Скачать GIF",
|
| 370 |
-
variant="primary"
|
| 371 |
-
)
|
| 372 |
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
inputs=[input_image, style, frames, size],
|
| 376 |
-
outputs=[output_gif]
|
| 377 |
-
).then(
|
| 378 |
-
fn=lambda gif: gif if gif else None,
|
| 379 |
-
inputs=[output_gif],
|
| 380 |
-
outputs=[download_btn]
|
| 381 |
-
)
|
| 382 |
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
inputs=[],
|
| 386 |
-
outputs=[status]
|
| 387 |
-
)
|
| 388 |
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
+
import random
|
| 3 |
+
import json
|
| 4 |
+
from datasets import Dataset
|
| 5 |
+
from huggingface_hub import HfApi
|
| 6 |
|
| 7 |
+
# === ТОКЕН ИЗ СЕКРЕТОВ SPACE ===
|
| 8 |
+
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 9 |
+
USERNAME = "root39058" # Ваш username
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
+
if not HF_TOKEN:
|
| 12 |
+
raise ValueError("HF_TOKEN не найден! Добавьте секрет в Space")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
+
print("🚀 Начинаем генерацию датасета...")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
+
# === СЛОВАРИ ===
|
| 17 |
+
words = {
|
| 18 |
+
'nouns': [
|
| 19 |
+
'дом', 'лес', 'вода', 'огонь', 'земля', 'небо', 'ветер', 'дождь', 'снег', 'солнце',
|
| 20 |
+
'ночь', 'день', 'утро', 'вечер', 'зима', 'весна', 'лето', 'осень', 'город', 'деревня',
|
| 21 |
+
'машина', 'дорога', 'река', 'гора', 'море', 'океан', 'звезда', 'луна', 'птица', 'рыба',
|
| 22 |
+
'кот', 'пёс', 'волк', 'лиса', 'медведь', 'заяц', 'слон', 'тигр', 'лев', 'конь',
|
| 23 |
+
'стол', 'стул', 'кровать', 'окно', 'дверь', 'стена', 'пол', 'потолок', 'лампа', 'книга',
|
| 24 |
+
'компьютер', 'ноутбук', 'телефон', 'планшет', 'экран', 'клавиатура', 'мышь', 'монитор', 'память', 'процессор'
|
| 25 |
+
],
|
| 26 |
+
'verbs': [
|
| 27 |
+
'бежит', 'идёт', 'летит', 'плывёт', 'сидит', 'стоит', 'лежит', 'ходит', 'едет', 'смотрит',
|
| 28 |
+
'видит', 'слышит', 'говорит', 'молчит', 'думает', 'знает', 'спит', 'ест', 'пьёт', 'играет',
|
| 29 |
+
'работает', 'учится', 'читает', 'пишет', 'рисует', 'поёт', 'танцует', 'гуляет', 'плавает', 'ныряет',
|
| 30 |
+
'прыгает', 'ползает', 'строит', 'ломает', 'чинит', 'моет', 'убирает', 'готовит', 'варит', 'жарит'
|
| 31 |
+
],
|
| 32 |
+
'adjs': [
|
| 33 |
+
'большой', 'маленький', 'красивый', 'страшный', 'добрый', 'злой', 'умный', 'глупый',
|
| 34 |
+
'быстрый', 'медленный', 'высокий', 'низкий', 'широкий', 'узкий', 'длинный', 'короткий',
|
| 35 |
+
'глубокий', 'мелкий', 'толстый', 'тонкий', 'лёгкий', 'тяжёлый', 'горячий', 'холодный',
|
| 36 |
+
'тёплый', 'прохладный', 'мокрый', 'сухой', 'чистый', 'грязный', 'светлый', 'тёмный',
|
| 37 |
+
'яркий', 'тусклый', 'громкий', 'тихий', 'мягкий', 'жёсткий', 'вкусный', 'противный'
|
| 38 |
+
],
|
| 39 |
+
'advs': [
|
| 40 |
+
'очень', 'сильно', 'немного', 'слегка', 'едва', 'почти', 'вполне', 'совершенно',
|
| 41 |
+
'абсолютно', 'чрезвычайно', 'крайне', 'слишком', 'чересчур', 'вдруг', 'внезапно',
|
| 42 |
+
'постепенно', 'медленно', 'быстро', 'тихо', 'громко', 'весело', 'грустно', 'красиво'
|
| 43 |
+
],
|
| 44 |
+
'conj': [
|
| 45 |
+
'и', 'а', 'но', 'да', 'или', 'либо', 'же', 'вот', 'ещё', 'только',
|
| 46 |
+
'также', 'зато', 'однако', 'поэтому', 'потому что', 'так как', 'если',
|
| 47 |
+
'хотя', 'когда', 'пока', 'после', 'перед', 'через', 'около', 'рядом'
|
| 48 |
+
]
|
| 49 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
+
# === ГЕНЕРАТОРЫ ===
|
| 52 |
+
def generate_text():
|
| 53 |
+
noun = random.choice(words['nouns'])
|
| 54 |
+
adj = random.choice(words['adjs'])
|
| 55 |
+
verb = random.choice(words['verbs'])
|
| 56 |
+
adv = random.choice(words['advs']) if random.random() > 0.5 else ''
|
| 57 |
+
|
| 58 |
+
if random.random() > 0.6:
|
| 59 |
+
conj = random.choice(words['conj'])
|
| 60 |
+
noun2 = random.choice(words['nouns'])
|
| 61 |
+
verb2 = random.choice(words['verbs'])
|
| 62 |
+
text = f"{adj} {noun} {adv} {verb} {conj} {noun2} {verb2}"
|
| 63 |
+
else:
|
| 64 |
+
text = f"{adj} {noun} {adv} {verb}"
|
| 65 |
+
|
| 66 |
+
return text.capitalize() + "."
|
| 67 |
|
| 68 |
+
def generate_code():
|
| 69 |
+
codes = [
|
| 70 |
+
'def hello():\n print("Привет, мир!")',
|
| 71 |
+
'function greet(name) {\n console.log(`Привет, ${name}`);\n}',
|
| 72 |
+
'<h1>Заголовок</h1>\n<p>Текст</p>',
|
| 73 |
+
'.class {\n color: blue;\n font-size: 16px;\n}',
|
| 74 |
+
'SELECT * FROM users WHERE id = 1;',
|
| 75 |
+
'{"key": "value", "array": [1, 2, 3]}'
|
| 76 |
+
]
|
| 77 |
+
return random.choice(codes)
|
| 78 |
|
| 79 |
+
# === ГЕНЕРАЦИЯ ДАТАСЕТА ===
|
| 80 |
+
print("📊 Генерация...")
|
| 81 |
+
|
| 82 |
+
data = []
|
| 83 |
+
target_size = 100 * 1024 * 1024 # 100 МБ
|
| 84 |
+
current_size = 0
|
| 85 |
+
|
| 86 |
+
while current_size < target_size:
|
| 87 |
+
if random.random() > 0.2:
|
| 88 |
+
text = generate_text()
|
| 89 |
+
else:
|
| 90 |
+
text = generate_code()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
+
data.append({"text": text})
|
| 93 |
+
current_size = len(json.dumps(data, ensure_ascii=False).encode('utf-8'))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
|
| 95 |
+
if len(data) % 1000 == 0:
|
| 96 |
+
print(f"Готово {len(data)} записей, {current_size // 1024 // 1024} МБ")
|
|
|
|
|
|
|
|
|
|
| 97 |
|
| 98 |
+
print(f"✅ Сгенерировано {len(data)} записей, {current_size // 1024 // 1024} МБ")
|
| 99 |
+
|
| 100 |
+
# === СОЗДАНИЕ DATASET ===
|
| 101 |
+
dataset = Dataset.from_list(data)
|
| 102 |
+
|
| 103 |
+
# === СОХРАНЕНИЕ ЛОКАЛЬНО ===
|
| 104 |
+
os.makedirs("/data", exist_ok=True)
|
| 105 |
+
dataset.save_to_disk("/data/my_russian_dataset")
|
| 106 |
+
print("✅ Сохранено в /data")
|
| 107 |
+
|
| 108 |
+
# === ПУШ НА HF ===
|
| 109 |
+
print("☁️ Загрузка на Hugging Face...")
|
| 110 |
+
|
| 111 |
+
try:
|
| 112 |
+
dataset.push_to_hub(
|
| 113 |
+
f"{USERNAME}/Miniset",
|
| 114 |
+
token=HF_TOKEN,
|
| 115 |
+
private=False,
|
| 116 |
+
commit_message="Датасет сгенерирован через Space"
|
| 117 |
+
)
|
| 118 |
+
print(f"\n✅ ГОТОВО! https://huggingface.co/datasets/{USERNAME}/russian-dataset-100mb")
|
| 119 |
+
except Exception as e:
|
| 120 |
+
print(f"❌ Ошибка: {e}")
|