Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -23,7 +23,7 @@ gemini_key_cycler = itertools.cycle(GEMINI_API_KEYS)
|
|
| 23 |
|
| 24 |
DEFAULT_BYTEZ_MODEL = "ali-vilab/text-to-video-ms-1.7b"
|
| 25 |
|
| 26 |
-
# ---------- MODEL HUNTER FUNCTIONS
|
| 27 |
def find_best_groq_model(api_key):
|
| 28 |
try:
|
| 29 |
print("🤖 Hunting for the best Groq model...")
|
|
@@ -69,7 +69,7 @@ job_queue = queue.Queue()
|
|
| 69 |
generated_clips_dict = {}
|
| 70 |
clips_lock = threading.Lock()
|
| 71 |
|
| 72 |
-
# ---------- HELPER FUNCTIONS
|
| 73 |
def set_progress(log_message=None, **kwargs):
|
| 74 |
global progress
|
| 75 |
with threading.Lock():
|
|
@@ -81,7 +81,6 @@ def get_progress_copy():
|
|
| 81 |
with threading.Lock(): return progress.copy()
|
| 82 |
|
| 83 |
def get_prompt_from_gemini(image_data, user_text, mime_type, api_key):
|
| 84 |
-
# This function is correct, no changes needed
|
| 85 |
print(f"🧠 Contacting Gemini (Creative Director) using key ...{api_key[-4:]}")
|
| 86 |
try:
|
| 87 |
encoded_image = base64.b64encode(image_data).decode('utf-8')
|
|
@@ -104,7 +103,6 @@ def get_prompt_from_gemini(image_data, user_text, mime_type, api_key):
|
|
| 104 |
except Exception as e: return None, f"An unexpected error occurred with Gemini: {e}"
|
| 105 |
|
| 106 |
def generate_visual_blueprint_with_groq(user_prompt, api_key, model_name):
|
| 107 |
-
# This function is correct, no changes needed
|
| 108 |
print("🎨 Contacting Groq (Quality Enhancer)...")
|
| 109 |
try:
|
| 110 |
client = Groq(api_key=api_key)
|
|
@@ -115,16 +113,20 @@ def generate_visual_blueprint_with_groq(user_prompt, api_key, model_name):
|
|
| 115 |
return visual_blueprint, None
|
| 116 |
except Exception as e: return None, f"Groq API Error: {e}"
|
| 117 |
|
|
|
|
|
|
|
| 118 |
def generate_clip(prompt, idx, api_key, bytez_model):
|
| 119 |
-
# This is the "bulletproof" version that fixes the ValueError
|
| 120 |
from bytez import Bytez
|
| 121 |
sdk = Bytez(api_key)
|
| 122 |
model = sdk.model(bytez_model)
|
|
|
|
| 123 |
out = None
|
| 124 |
err = None
|
|
|
|
| 125 |
try:
|
| 126 |
result = model.run(prompt)
|
| 127 |
print(f"DEBUG: model.run() returned a '{type(result)}'. Full result: {result}")
|
|
|
|
| 128 |
if isinstance(result, tuple) and len(result) >= 2:
|
| 129 |
out = result[0]
|
| 130 |
err = result[1]
|
|
@@ -134,11 +136,14 @@ def generate_clip(prompt, idx, api_key, bytez_model):
|
|
| 134 |
else:
|
| 135 |
out = result
|
| 136 |
err = None
|
|
|
|
| 137 |
except Exception as e:
|
| 138 |
print(f"🛑 CRITICAL ERROR during model.run() call: {e}")
|
| 139 |
return None, str(e)
|
|
|
|
| 140 |
if err:
|
| 141 |
return None, f"Model Error (Key ...{api_key[-4:]}): {err}"
|
|
|
|
| 142 |
filename = f"clip_{idx}_{uuid.uuid4().hex}.mp4"
|
| 143 |
filepath = os.path.join(OUTPUT_FOLDER, filename)
|
| 144 |
try:
|
|
@@ -152,10 +157,10 @@ def generate_clip(prompt, idx, api_key, bytez_model):
|
|
| 152 |
return None, f"Unexpected or empty output from model. Output type: {type(out)}"
|
| 153 |
except Exception as e:
|
| 154 |
return None, f"Failed to save or download the generated clip: {e}"
|
|
|
|
| 155 |
return filepath, None
|
| 156 |
|
| 157 |
def process_and_merge_clips(clip_files):
|
| 158 |
-
# This function is correct, no changes needed
|
| 159 |
if not clip_files: return None
|
| 160 |
list_file = os.path.join(OUTPUT_FOLDER, f"clips_{uuid.uuid4().hex}.txt")
|
| 161 |
with open(list_file, "w") as f:
|
|
@@ -176,7 +181,6 @@ def process_and_merge_clips(clip_files):
|
|
| 176 |
except Exception as e: print(f"⚠️ Cinematic processing failed: {e}. Falling back to raw video."); return raw_merge_path
|
| 177 |
|
| 178 |
def worker(api_key):
|
| 179 |
-
# This function is correct, no changes needed
|
| 180 |
while True:
|
| 181 |
try:
|
| 182 |
prompt, idx, num_clips_in_job, bytez_model = job_queue.get()
|
|
@@ -190,7 +194,6 @@ def worker(api_key):
|
|
| 190 |
finally: job_queue.task_done()
|
| 191 |
|
| 192 |
def generate_video_job(prompt, num_clips, bytez_model):
|
| 193 |
-
# This function is correct, no changes needed
|
| 194 |
temp_clip_paths = []
|
| 195 |
try:
|
| 196 |
with clips_lock: generated_clips_dict.clear()
|
|
@@ -217,14 +220,13 @@ def generate_video_job(prompt, num_clips, bytez_model):
|
|
| 217 |
for clip in temp_clip_paths:
|
| 218 |
if os.path.exists(clip): os.remove(clip)
|
| 219 |
|
| 220 |
-
# ---------- FLASK ROUTES
|
| 221 |
@app.route("/", methods=["GET"])
|
| 222 |
def home():
|
| 223 |
return render_template("index.html")
|
| 224 |
|
| 225 |
@app.route("/start", methods=["POST"])
|
| 226 |
def start():
|
| 227 |
-
# This is the simplified version without the Prompt Distiller
|
| 228 |
set_progress(live_log=[])
|
| 229 |
if get_progress_copy().get("active", False): return jsonify({"error": "A video is already being generated. Please wait."}), 429
|
| 230 |
user_prompt = request.form.get("prompt", "").strip()
|
|
@@ -258,8 +260,13 @@ def start():
|
|
| 258 |
if err:
|
| 259 |
set_progress(status="error", error=err, active=False, log_message=f"🛑 Groq Enhancer Failure: {err}"); return jsonify({"error": err}), 500
|
| 260 |
set_progress(log_message=f"✨ Enhanced Blueprint: \"{visual_blueprint[:80]}...\"")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
|
| 262 |
negative_keywords = "blurry, deformed, ugly, bad anatomy, watermark, noise, grain, low quality, distortion, glitch, pixelated, artifacts"
|
|
|
|
| 263 |
final_prompt = f"{visual_blueprint}, {negative_keywords}"
|
| 264 |
|
| 265 |
print(f"🚀 Final Prompt for Bytez (Model: {bytez_model}): {final_prompt}")
|
|
@@ -276,9 +283,6 @@ def serve_output_file(filename):
|
|
| 276 |
if ".." in filename or filename.startswith("/"): abort(400)
|
| 277 |
return send_from_directory(OUTPUT_FOLDER, filename)
|
| 278 |
|
| 279 |
-
# /// --- यह PWA के लिए महत्वपूर्ण हिस्सा है --- ///
|
| 280 |
-
# यह सुनिश्चित करता है कि सर्वर manifest, service worker, और सभी आइकन फाइलों को परोस सकता है।
|
| 281 |
-
|
| 282 |
@app.route('/manifest.json')
|
| 283 |
def serve_manifest():
|
| 284 |
return send_from_directory('static', 'manifest.json')
|
|
@@ -287,13 +291,6 @@ def serve_manifest():
|
|
| 287 |
def serve_sw():
|
| 288 |
return send_from_directory('static', 'service-worker.js')
|
| 289 |
|
| 290 |
-
# /// --- यह वह "Missing Piece" है जो आइकन की समस्या को ठीक करेगा --- ///
|
| 291 |
-
@app.route('/static/<path:filename>')
|
| 292 |
-
def serve_static_files(filename):
|
| 293 |
-
return send_from_directory('static', filename)
|
| 294 |
-
|
| 295 |
-
# /// ---------------------------------------------------------------- ///
|
| 296 |
-
|
| 297 |
# ---------- RUN ----------
|
| 298 |
print(f"Starting {len(API_KEYS)} worker threads for this process...")
|
| 299 |
for api_key in API_KEYS:
|
|
|
|
| 23 |
|
| 24 |
DEFAULT_BYTEZ_MODEL = "ali-vilab/text-to-video-ms-1.7b"
|
| 25 |
|
| 26 |
+
# ---------- MODEL HUNTER FUNCTIONS ----------
|
| 27 |
def find_best_groq_model(api_key):
|
| 28 |
try:
|
| 29 |
print("🤖 Hunting for the best Groq model...")
|
|
|
|
| 69 |
generated_clips_dict = {}
|
| 70 |
clips_lock = threading.Lock()
|
| 71 |
|
| 72 |
+
# ---------- HELPER FUNCTIONS ----------
|
| 73 |
def set_progress(log_message=None, **kwargs):
|
| 74 |
global progress
|
| 75 |
with threading.Lock():
|
|
|
|
| 81 |
with threading.Lock(): return progress.copy()
|
| 82 |
|
| 83 |
def get_prompt_from_gemini(image_data, user_text, mime_type, api_key):
|
|
|
|
| 84 |
print(f"🧠 Contacting Gemini (Creative Director) using key ...{api_key[-4:]}")
|
| 85 |
try:
|
| 86 |
encoded_image = base64.b64encode(image_data).decode('utf-8')
|
|
|
|
| 103 |
except Exception as e: return None, f"An unexpected error occurred with Gemini: {e}"
|
| 104 |
|
| 105 |
def generate_visual_blueprint_with_groq(user_prompt, api_key, model_name):
|
|
|
|
| 106 |
print("🎨 Contacting Groq (Quality Enhancer)...")
|
| 107 |
try:
|
| 108 |
client = Groq(api_key=api_key)
|
|
|
|
| 113 |
return visual_blueprint, None
|
| 114 |
except Exception as e: return None, f"Groq API Error: {e}"
|
| 115 |
|
| 116 |
+
# हमने यहाँ से distill_prompt_for_short_video फंक्शन को हटा दिया है।
|
| 117 |
+
|
| 118 |
def generate_clip(prompt, idx, api_key, bytez_model):
|
|
|
|
| 119 |
from bytez import Bytez
|
| 120 |
sdk = Bytez(api_key)
|
| 121 |
model = sdk.model(bytez_model)
|
| 122 |
+
|
| 123 |
out = None
|
| 124 |
err = None
|
| 125 |
+
|
| 126 |
try:
|
| 127 |
result = model.run(prompt)
|
| 128 |
print(f"DEBUG: model.run() returned a '{type(result)}'. Full result: {result}")
|
| 129 |
+
|
| 130 |
if isinstance(result, tuple) and len(result) >= 2:
|
| 131 |
out = result[0]
|
| 132 |
err = result[1]
|
|
|
|
| 136 |
else:
|
| 137 |
out = result
|
| 138 |
err = None
|
| 139 |
+
|
| 140 |
except Exception as e:
|
| 141 |
print(f"🛑 CRITICAL ERROR during model.run() call: {e}")
|
| 142 |
return None, str(e)
|
| 143 |
+
|
| 144 |
if err:
|
| 145 |
return None, f"Model Error (Key ...{api_key[-4:]}): {err}"
|
| 146 |
+
|
| 147 |
filename = f"clip_{idx}_{uuid.uuid4().hex}.mp4"
|
| 148 |
filepath = os.path.join(OUTPUT_FOLDER, filename)
|
| 149 |
try:
|
|
|
|
| 157 |
return None, f"Unexpected or empty output from model. Output type: {type(out)}"
|
| 158 |
except Exception as e:
|
| 159 |
return None, f"Failed to save or download the generated clip: {e}"
|
| 160 |
+
|
| 161 |
return filepath, None
|
| 162 |
|
| 163 |
def process_and_merge_clips(clip_files):
|
|
|
|
| 164 |
if not clip_files: return None
|
| 165 |
list_file = os.path.join(OUTPUT_FOLDER, f"clips_{uuid.uuid4().hex}.txt")
|
| 166 |
with open(list_file, "w") as f:
|
|
|
|
| 181 |
except Exception as e: print(f"⚠️ Cinematic processing failed: {e}. Falling back to raw video."); return raw_merge_path
|
| 182 |
|
| 183 |
def worker(api_key):
|
|
|
|
| 184 |
while True:
|
| 185 |
try:
|
| 186 |
prompt, idx, num_clips_in_job, bytez_model = job_queue.get()
|
|
|
|
| 194 |
finally: job_queue.task_done()
|
| 195 |
|
| 196 |
def generate_video_job(prompt, num_clips, bytez_model):
|
|
|
|
| 197 |
temp_clip_paths = []
|
| 198 |
try:
|
| 199 |
with clips_lock: generated_clips_dict.clear()
|
|
|
|
| 220 |
for clip in temp_clip_paths:
|
| 221 |
if os.path.exists(clip): os.remove(clip)
|
| 222 |
|
| 223 |
+
# ---------- FLASK ROUTES ----------
|
| 224 |
@app.route("/", methods=["GET"])
|
| 225 |
def home():
|
| 226 |
return render_template("index.html")
|
| 227 |
|
| 228 |
@app.route("/start", methods=["POST"])
|
| 229 |
def start():
|
|
|
|
| 230 |
set_progress(live_log=[])
|
| 231 |
if get_progress_copy().get("active", False): return jsonify({"error": "A video is already being generated. Please wait."}), 429
|
| 232 |
user_prompt = request.form.get("prompt", "").strip()
|
|
|
|
| 260 |
if err:
|
| 261 |
set_progress(status="error", error=err, active=False, log_message=f"🛑 Groq Enhancer Failure: {err}"); return jsonify({"error": err}), 500
|
| 262 |
set_progress(log_message=f"✨ Enhanced Blueprint: \"{visual_blueprint[:80]}...\"")
|
| 263 |
+
|
| 264 |
+
### --- यह हिस्सा बदला गया है --- ###
|
| 265 |
+
# हमने यहाँ से "Prompt Distiller" को हटा दिया है।
|
| 266 |
+
# अब हम विस्तृत प्रॉम्प्ट को सीधे उपयोग करेंगे।
|
| 267 |
|
| 268 |
negative_keywords = "blurry, deformed, ugly, bad anatomy, watermark, noise, grain, low quality, distortion, glitch, pixelated, artifacts"
|
| 269 |
+
# अब हम `visual_blueprint` का सीधा उपयोग कर रहे हैं।
|
| 270 |
final_prompt = f"{visual_blueprint}, {negative_keywords}"
|
| 271 |
|
| 272 |
print(f"🚀 Final Prompt for Bytez (Model: {bytez_model}): {final_prompt}")
|
|
|
|
| 283 |
if ".." in filename or filename.startswith("/"): abort(400)
|
| 284 |
return send_from_directory(OUTPUT_FOLDER, filename)
|
| 285 |
|
|
|
|
|
|
|
|
|
|
| 286 |
@app.route('/manifest.json')
|
| 287 |
def serve_manifest():
|
| 288 |
return send_from_directory('static', 'manifest.json')
|
|
|
|
| 291 |
def serve_sw():
|
| 292 |
return send_from_directory('static', 'service-worker.js')
|
| 293 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 294 |
# ---------- RUN ----------
|
| 295 |
print(f"Starting {len(API_KEYS)} worker threads for this process...")
|
| 296 |
for api_key in API_KEYS:
|