Mr-profik commited on
Commit
dcdf36d
·
verified ·
1 Parent(s): 770b567

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +186 -0
app.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ import os
3
+ import random
4
+ from pathlib import Path
5
+
6
+ import gradio as gr
7
+ import spaces
8
+ import torch
9
+ from diffusers import CogVideoXPipeline
10
+ from diffusers.utils import export_to_video
11
+
12
+ MODEL_ID = "zai-org/CogVideoX-2b"
13
+ OUTPUT_DIR = Path("outputs")
14
+ OUTPUT_DIR.mkdir(exist_ok=True)
15
+ CHANNEL_URL = "https://t.me/Profik_Studio"
16
+
17
+ T = {
18
+ "ru": {
19
+ "title": "AI Video Studio", "sub": "Генератор видео из текста • CogVideoX-2B",
20
+ "lang": "Язык", "gen": "Генератор", "hist": "История", "settings": "Настройки",
21
+ "subscribe_title": "Доступ к генератору", "subscribe_text": "Подпишись на канал **@Profik_Studio**, затем нажми кнопку подтверждения.",
22
+ "open": "📢 Открыть канал", "check": "✅ Я подписался", "locked": "🔒 Сначала подпишись на канал и нажми «Я подписался». ",
23
+ "unlocked": "🟢 Доступ открыт — можно создавать видео.",
24
+ "prompt": "Описание видео", "prompt_ph": "Например: футуристический город ночью, неон, дождь, кинематографичный пролёт камеры...",
25
+ "negative": "Что исключить", "negative_ph": "Размытие, артефакты, плохое качество...",
26
+ "frames": "Кадры", "steps": "Шаги", "fps": "FPS", "guidance": "Guidance", "seed": "Seed (-1 = случайный)",
27
+ "create": "🚀 СОЗДАТЬ ВИДЕО", "result": "Результат", "ready": "🟢 Готово к генерации.",
28
+ "examples": "Примеры", "history_empty": "История пока пуста.", "refresh": "🔄 Обновить",
29
+ "settings_text": "**Модель:** CogVideoX-2B \n**Режим:** Hugging Face ZeroGPU \n**API-ключ:** не требуется",
30
+ "error_prompt": "Введите описание видео.", "error_access": "Сначала подпишитесь на @Profik_Studio.",
31
+ "error_model": "Модель ещё загружается. Попробуйте снова через несколько секунд.",
32
+ "footer": "AI Video Studio • Profik • CogVideoX-2B"
33
+ },
34
+ "en": {
35
+ "title": "AI Video Studio", "sub": "Text-to-video generator • CogVideoX-2B",
36
+ "lang": "Language", "gen": "Generator", "hist": "History", "settings": "Settings",
37
+ "subscribe_title": "Generator access", "subscribe_text": "Subscribe to **@Profik_Studio**, then press the confirmation button.",
38
+ "open": "📢 Open channel", "check": "✅ I subscribed", "locked": "🔒 Subscribe to the channel and press “I subscribed”.",
39
+ "unlocked": "🟢 Access unlocked — you can create videos.",
40
+ "prompt": "Video description", "prompt_ph": "Example: futuristic city at night, neon, rain, cinematic camera fly-through...",
41
+ "negative": "Negative prompt", "negative_ph": "Blur, artifacts, low quality...",
42
+ "frames": "Frames", "steps": "Steps", "fps": "FPS", "guidance": "Guidance", "seed": "Seed (-1 = random)",
43
+ "create": "🚀 CREATE VIDEO", "result": "Result", "ready": "🟢 Ready to generate.",
44
+ "examples": "Examples", "history_empty": "History is empty.", "refresh": "🔄 Refresh",
45
+ "settings_text": "**Model:** CogVideoX-2B \n**Runtime:** Hugging Face ZeroGPU \n**API key:** not required",
46
+ "error_prompt": "Enter a video description.", "error_access": "Subscribe to @Profik_Studio first.",
47
+ "error_model": "The model is still loading. Try again in a few seconds.",
48
+ "footer": "AI Video Studio • Profik • CogVideoX-2B"
49
+ }
50
+ }
51
+
52
+ CSS = """
53
+ body { background:#06080b !important; }
54
+ .gradio-container { max-width:1180px !important; background:transparent !important; }
55
+ .hero { text-align:center; padding:34px 12px 22px; }
56
+ .logo { width:72px;height:72px;margin:auto;border-radius:22px;display:flex;align-items:center;justify-content:center;font-size:34px;background:linear-gradient(145deg,#10251a,#0b1210);border:1px solid #245f3c;box-shadow:0 0 45px #1ce66b18; }
57
+ .hero h1 { font-size:38px !important; margin:12px 0 4px !important; letter-spacing:-1px; }
58
+ .hero p { color:#84909d !important; }
59
+ .panel { border:1px solid #1d2833 !important; border-radius:20px !important; background:linear-gradient(145deg,#0d1319,#090d12) !important; padding:18px !important; }
60
+ .badge { display:inline-block;padding:6px 10px;border:1px solid #254735;border-radius:999px;color:#63e99a;background:#0b1a12;font-size:12px; }
61
+ .gr-button-primary { background:linear-gradient(90deg,#20c96b,#42f58a) !important;color:#031008 !important;border:0 !important;font-weight:900 !important; }
62
+ .bigbtn button { min-height:56px !important;font-size:16px !important; }
63
+ .nav button { border-radius:13px !important; }
64
+ .footer { text-align:center;color:#667381;padding:25px 0 8px;font-size:12px; }
65
+ """
66
+
67
+ pipe = None
68
+ try:
69
+ pipe = CogVideoXPipeline.from_pretrained(MODEL_ID, torch_dtype=torch.float16)
70
+ pipe.enable_model_cpu_offload()
71
+ try: pipe.vae.enable_tiling()
72
+ except Exception: pass
73
+ except Exception as e:
74
+ print("MODEL LOAD ERROR:", repr(e))
75
+
76
+
77
+ def history(lang):
78
+ t=T[lang]; files=sorted(OUTPUT_DIR.glob("*.mp4"), key=lambda p:p.stat().st_mtime, reverse=True)
79
+ if not files: return f"### {t['history_empty']}"
80
+ return "### " + t["hist"] + "\n\n" + "\n".join(f"- `{p.name}` — {p.stat().st_size/1048576:.1f} MB" for p in files[:30])
81
+
82
+
83
+ def unlock(lang):
84
+ return True, T[lang]["unlocked"]
85
+
86
+
87
+ @spaces.GPU
88
+ def generate(prompt, negative, frames, steps, fps, guidance, seed, lang, access, progress=gr.Progress()):
89
+ t=T[lang]
90
+ if not access: raise gr.Error(t["error_access"])
91
+ if not prompt or not prompt.strip(): raise gr.Error(t["error_prompt"])
92
+ if pipe is None: raise gr.Error(t["error_model"])
93
+ seed=int(seed)
94
+ if seed < 0: seed=random.randint(0,2**31-1)
95
+ try:
96
+ progress(0.08, desc="Generating...")
97
+ g=torch.Generator(device="cuda").manual_seed(seed)
98
+ out=pipe(prompt=prompt.strip(), negative_prompt=(negative or "").strip() or None,
99
+ num_frames=int(frames), num_inference_steps=int(steps),
100
+ guidance_scale=float(guidance), generator=g)
101
+ progress(0.9, desc="Encoding...")
102
+ file=OUTPUT_DIR/f"video_{seed}_{random.randint(1000,9999)}.mp4"
103
+ export_to_video(out.frames[0], str(file), fps=int(fps))
104
+ progress(1.0)
105
+ return str(file), f"### 🟢 {t['result']}\nSeed: `{seed}`"
106
+ except Exception as e:
107
+ raise gr.Error(str(e))
108
+
109
+
110
+ def language_ui(lang):
111
+ t=T[lang]
112
+ hero=f'<div class="hero"><div class="logo">🎬</div><h1>{t["title"]}</h1><p>{t["sub"]}</p><span class="badge">● ZERO API KEY</span></div>'
113
+ return (hero,t["lang"],t["gen"],t["hist"],t["settings"],t["subscribe_title"],t["subscribe_text"],t["open"],t["check"],t["locked"],t["prompt"],t["prompt_ph"],t["negative"],t["negative_ph"],t["frames"],t["steps"],t["fps"],t["guidance"],t["seed"],t["create"],t["result"],t["ready"],t["examples"],t["settings_text"],t["refresh"],t["footer"],history(lang))
114
+
115
+ with gr.Blocks(css=CSS, title="AI Video Studio") as demo:
116
+ access=gr.State(False)
117
+ hero=gr.HTML()
118
+ language=gr.Radio(["ru","en"], value="ru", label="Язык", show_label=True)
119
+
120
+ with gr.Row(elem_classes="nav"):
121
+ nav_gen=gr.Button("🎬 Генератор", variant="primary")
122
+ nav_hist=gr.Button("📚 История")
123
+ nav_set=gr.Button("⚙️ Настройки")
124
+
125
+ with gr.Group(elem_classes="panel"):
126
+ sub_title=gr.Markdown()
127
+ sub_text=gr.Markdown()
128
+ with gr.Row():
129
+ open_btn=gr.Button("📢 Открыть канал")
130
+ check_btn=gr.Button("✅ Я подписался", variant="primary")
131
+ sub_status=gr.Markdown()
132
+
133
+ with gr.Tab("🎬 Генератор"):
134
+ with gr.Row():
135
+ with gr.Column(scale=7, elem_classes="panel"):
136
+ prompt=gr.Textbox(lines=5)
137
+ negative=gr.Textbox(lines=3)
138
+ with gr.Row():
139
+ frames=gr.Slider(8,49,49,step=1)
140
+ fps=gr.Slider(4,16,8,step=1)
141
+ with gr.Row():
142
+ steps=gr.Slider(10,50,30,step=1)
143
+ guidance=gr.Slider(1,12,6,step=.5)
144
+ seed=gr.Number(value=-1, precision=0)
145
+ create=gr.Button("🚀 СОЗДАТЬ ВИДЕО", variant="primary", elem_classes="bigbtn")
146
+ with gr.Column(scale=5, elem_classes="panel"):
147
+ result_title=gr.Markdown()
148
+ result=gr.Markdown()
149
+ video=gr.Video(label="Video", format="mp4")
150
+ examples_title=gr.Markdown()
151
+ gr.Examples([
152
+ ["Кинематографичный ночной город будущего, неон, дождь, плавный пролёт камеры"],
153
+ ["Заснеженные горы на рассвете, золотой свет, облака движутся над вершинами"],
154
+ ["Маленький робот идёт по космической станции, кинематографичный свет"],
155
+ ], inputs=prompt)
156
+
157
+ with gr.Tab("📚 История"):
158
+ history_box=gr.Markdown()
159
+ refresh=gr.Button("🔄 Обновить")
160
+
161
+ with gr.Tab("⚙️ Настройки"):
162
+ settings_box=gr.Markdown()
163
+
164
+ footer=gr.Markdown(elem_classes="footer")
165
+
166
+ vals=language_ui("ru")
167
+ for comp,val in zip([hero,language,nav_gen,nav_hist,nav_set,sub_title,sub_text,open_btn,check_btn,sub_status,prompt,negative,frames,steps,fps,guidance,seed,create,result_title,result,examples_title,settings_box,refresh,footer,history_box], vals):
168
+ if comp is language: continue
169
+ hero.value=vals[0]; language.label=vals[1]; nav_gen.value=vals[2]; nav_hist.value=vals[3]; nav_set.value=vals[4]
170
+ sub_title.value=vals[5]; sub_text.value=vals[6]; open_btn.value=vals[7]; check_btn.value=vals[8]; sub_status.value=vals[9]
171
+ prompt.label=vals[10]; prompt.placeholder=vals[11]; negative.label=vals[12]; negative.placeholder=vals[13]
172
+ frames.label=vals[14]; steps.label=vals[15]; fps.label=vals[16]; guidance.label=vals[17]; seed.label=vals[18]
173
+ create.value=vals[19]; result_title.value=vals[20]; result.value=vals[21]; examples_title.value=vals[22]; settings_box.value=vals[23]; refresh.value=vals[24]; footer.value=vals[25]; history_box.value=vals[26]
174
+
175
+ open_btn.click(None, None, None, js=f"() => window.open('{CHANNEL_URL}','_blank')")
176
+ check_btn.click(unlock, language, [access,sub_status])
177
+ create.click(generate, [prompt,negative,frames,steps,fps,guidance,seed,language,access], [video,result])
178
+ refresh.click(history, language, history_box)
179
+
180
+ language.change(
181
+ language_ui, language,
182
+ [hero,language,nav_gen,nav_hist,nav_set,sub_title,sub_text,open_btn,check_btn,sub_status,prompt,negative,frames,steps,fps,guidance,seed,create,result_title,result,examples_title,settings_box,refresh,footer,history_box],
183
+ )
184
+
185
+ if __name__ == "__main__":
186
+ demo.launch()