File size: 7,916 Bytes
9299a75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
"""
VIDEO GENERATOR WORKER - HuggingFace Space
==========================================
VEO 3.1 Only - Background worker
"""

import os
import gradio as gr
import threading
import time
import json
import traceback
from concurrent.futures import ThreadPoolExecutor

print(">>> [INIT] Starting Video Generator Worker (VEO 3.1 Only)...")

# Worker status
worker_status = {
    "running": False,
    "active_jobs": 0,
    "jobs_done": 0,
    "last_check": None,
    "errors": []
}

def load_worker_module():
    """Load video_core.py"""
    from huggingface_hub import hf_hub_download
    import shutil
    import importlib.util
    import sys
    
    # ==================== TOKEN CONFIGURATION ====================
    token = os.environ.get("HF_TOKEN")
    if not token:
        raise ValueError("HF_TOKEN not set!")
    
    # Dataset repository (semua file ada di sini)
    repo_id = os.environ.get("REPO_ID", "malikrf22/abcx")
    
    print(f">>> [INIT] Loading from dataset: {repo_id}")
    
    # ==================== DOWNLOAD VIDEO_CORE.PY ====================
    print(f">>> [INIT] Downloading video_core.py...")
    path_core = hf_hub_download(
        repo_id=repo_id,
        filename="video_core.py",
        repo_type="dataset",
        token=token,
        force_download=True
    )
    
    # ==================== DOWNLOAD DATALOGIN.JSON ====================
    print(f">>> [INIT] Downloading datalogin.json...")
    path_login = hf_hub_download(
        repo_id=repo_id,
        filename="datalogin.json",
        repo_type="dataset",
        token=token,
        force_download=True
    )
    
    # ==================== LOAD CREDENTIALS ====================
    with open(path_login, 'r') as f:
        login_data = json.load(f)
    
    print(f">>> [INIT] Login data keys: {list(login_data.keys())}")
    
    # Ambil data dari key utama (mmm123 atau key lainnya)
    main_key = os.environ.get("LOGIN_KEY", "mmm123")
    
    if main_key in login_data:
        credentials = login_data[main_key]
    else:
        # Fallback: ambil key pertama yang berisi dict
        for key, value in login_data.items():
            if isinstance(value, dict):
                credentials = value
                main_key = key
                break
        else:
            raise ValueError("No valid credentials found in datalogin.json")
    
    print(f">>> [INIT] Using credentials from key: {main_key}")
    
    # ==================== BUILD CONFIG ====================
    config = {
        "shared_pools": {
            "dreamina": {
                "accounts": credentials.get("dreamina_accounts", [])
            }
        },
        "max_concurrent_video_jobs": int(os.environ.get("MAX_CONCURRENT_JOBS", "5")),
        "gemini_refresh_cookie": credentials.get("gemini_refresh_cookie", []),
        "seedream_accounts": credentials.get("seedream_accounts", [])
    }
    
    dreamina_count = len(config["shared_pools"]["dreamina"]["accounts"])
    print(f">>> [INIT] βœ… Loaded {dreamina_count} Dreamina accounts")
    
    # ==================== IMPORT MODULE ====================
    shutil.copy(path_core, "video_module.py")
    
    spec = importlib.util.spec_from_file_location("video_module", "video_module.py")
    module = importlib.util.module_from_spec(spec)
    sys.modules["video_module"] = module
    spec.loader.exec_module(module)
    
    return module, config


def process_single_job(worker, job):
    """Process single job in separate thread"""
    job_id = job.get('id', 'unknown')[:8]
    try:
        success = worker.process_job(job)
        return (job_id, success)
    except Exception as e:
        return (job_id, False, str(e))


def worker_loop():
    """Background worker loop"""
    global worker_status
    
    try:
        module, config = load_worker_module()
        worker = module.VideoJobWorker(config)
        worker_status["running"] = True
        print(">>> [WORKER] VEO 3.1 Worker started successfully")
        
    except Exception as e:
        error_msg = str(e)[:200]
        worker_status["errors"].append(f"Init: {error_msg}")
        print(f">>> [WORKER] Init failed: {e}")
        traceback.print_exc()
        return
    
    max_workers = config.get("max_concurrent_video_jobs", 5)
    print(f">>> [WORKER] Max concurrent: {max_workers}")
    
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = {}
        
        while True:
            try:
                worker_status["last_check"] = time.strftime("%H:%M:%S")
                
                done_futures = [f for f in list(futures.keys()) if f.done()]
                for future in done_futures:
                    job_id = futures.pop(future)
                    try:
                        result = future.result()
                        if isinstance(result, tuple) and len(result) >= 2:
                            if result[1]:
                                worker_status["jobs_done"] += 1
                                print(f">>> [WORKER] βœ… Done: {job_id}")
                            else:
                                print(f">>> [WORKER] ❌ Failed: {job_id}")
                    except Exception as e:
                        print(f">>> [WORKER] ❌ Error {job_id}: {e}")
                
                slots_available = max_workers - len(futures)
                
                for _ in range(slots_available):
                    job = worker.claim_job()
                    if job:
                        job_id = job.get('id', 'unknown')[:8]
                        future = executor.submit(process_single_job, worker, job)
                        futures[future] = job_id
                        print(f">>> [WORKER] πŸš€ Started: {job_id} (active: {len(futures)})")
                    else:
                        break
                
                worker_status["active_jobs"] = len(futures)
                
                if not futures:
                    time.sleep(3)
                else:
                    time.sleep(1)
                    
            except Exception as e:
                error_msg = f"{time.strftime('%H:%M:%S')}: {str(e)[:100]}"
                worker_status["errors"] = worker_status["errors"][-10:] + [error_msg]
                print(f">>> [WORKER] Error: {e}")
                time.sleep(10)


# Start worker
worker_thread = threading.Thread(target=worker_loop, daemon=True)
worker_thread.start()
time.sleep(3)

# ==============================================================================
# GRADIO STATUS PAGE
# ==============================================================================

def get_status():
    errors_text = "\n".join([f"- {e}" for e in worker_status["errors"][-5:]]) if worker_status["errors"] else "- None"
    
    return f"""
# 🎬 Video Generator Worker (VEO 3.1)

| Item | Status |
|------|--------|
| **Running** | {'βœ… Yes' if worker_status['running'] else '❌ No'} |
| **Active Jobs** | πŸ”„ {worker_status['active_jobs']} |
| **Jobs Completed** | βœ… {worker_status['jobs_done']} |
| **Last Check** | {worker_status['last_check'] or 'Never'} |

### Engine:
- 🎬 **VEO 3.1** (Dreamina) - High quality video generation

### Recent Errors:
{errors_text}

---
*Click Refresh to update*
"""

with gr.Blocks(title="Video Generator Worker") as demo:
    gr.Markdown("# 🎬 Video Generator Worker")
    gr.Markdown("VEO 3.1 powered video generation")
    
    status_display = gr.Markdown(get_status())
    
    refresh_btn = gr.Button("πŸ”„ Refresh Status", variant="primary")
    refresh_btn.click(fn=get_status, inputs=None, outputs=[status_display])
    
    gr.Markdown("""
    ---
    ### Features:
    - βœ… Text-to-Video
    - βœ… Image-to-Video  
    - βœ… Auto-detect aspect ratio
    - βœ… Multiple aspect ratios (16:9, 9:16, 1:1)
    - βœ… Auto-refund on failure
    """)

if __name__ == "__main__":
    demo.queue().launch()