Enhance project structure with new app entry point, updated README, and improved UI components; refine .gitignore and loading messages
Browse files- .gitattributes +2 -0
- .gitignore +4 -2
- README.md +40 -14
- TestImage.png +3 -0
- TestVideo.mp4 +3 -0
- app.py +5 -0
- gradio_app.py +43 -54
- lib/status_utils.py +15 -10
- lib/ui_components.py +92 -46
- loading_messages.json +21 -1
.gitattributes
CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
*.png filter=lfs diff=lfs merge=lfs -text
|
37 |
+
*.mp4 filter=lfs diff=lfs merge=lfs -text
|
.gitignore
CHANGED
@@ -1,2 +1,4 @@
|
|
1 |
-
|
2 |
-
*.pyc
|
|
|
|
|
|
1 |
+
__pycache__/
|
2 |
+
*.pyc
|
3 |
+
.env
|
4 |
+
.DS_Store
|
README.md
CHANGED
@@ -1,14 +1,40 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# LumaAI Video Generator
|
2 |
+
|
3 |
+
A Gradio web interface for generating videos using LumaAI's API. Transform your prompts into mesmerizing videos with optional image input and camera motion controls.
|
4 |
+
|
5 |
+
## Features
|
6 |
+
|
7 |
+
- Text-to-video generation
|
8 |
+
- Image-to-video generation
|
9 |
+
- Camera motion controls
|
10 |
+
- Real-time status updates with fun messages
|
11 |
+
- Modern, user-friendly interface
|
12 |
+
|
13 |
+
## Usage
|
14 |
+
|
15 |
+
1. Enter your LumaAI API key
|
16 |
+
2. Type your creative prompt
|
17 |
+
3. (Optional) Select a camera motion
|
18 |
+
4. (Optional) Upload an image
|
19 |
+
5. Click Generate and watch the magic happen!
|
20 |
+
|
21 |
+
## Development
|
22 |
+
|
23 |
+
To run locally:
|
24 |
+
|
25 |
+
```bash
|
26 |
+
pip install -r requirements.txt
|
27 |
+
python gradio_app.py
|
28 |
+
```
|
29 |
+
|
30 |
+
## Deployment
|
31 |
+
|
32 |
+
This app is ready for Hugging Face Spaces deployment. Simply push to your Spaces repository and it will automatically deploy.
|
33 |
+
|
34 |
+
## Environment Variables
|
35 |
+
|
36 |
+
- No environment variables required - API key is input through the UI
|
37 |
+
|
38 |
+
## License
|
39 |
+
|
40 |
+
MIT
|
TestImage.png
ADDED
Git LFS Details
|
TestVideo.mp4
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:fa8d3ee0ed2c9f6f9de381a4d6ef8a5cee442d65ef5138fcc4a6396e2add1ada
|
3 |
+
size 8015996
|
app.py
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Hugging Face Spaces entry point
|
2 |
+
from gradio_app import app
|
3 |
+
|
4 |
+
if __name__ == "__main__":
|
5 |
+
app.launch()
|
gradio_app.py
CHANGED
@@ -5,31 +5,36 @@ import requests
|
|
5 |
from lumaai import LumaAI
|
6 |
import traceback
|
7 |
|
8 |
-
from lib.status_utils import
|
9 |
from lib.image_utils import prepare_image
|
10 |
from lib.api_utils import get_camera_motions
|
11 |
-
from lib.ui_components import
|
12 |
|
13 |
-
def generate_video(api_key, prompt, camera_motion, image=None, progress=gr.Progress()):
|
14 |
-
status_box = gr.Markdown() # Create status box
|
15 |
if not api_key or not prompt:
|
16 |
-
|
17 |
|
18 |
try:
|
19 |
-
|
20 |
-
status_tracker.add_step("LumaAI initialized", 0.01)
|
21 |
client = LumaAI(auth_token=api_key)
|
22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
# Prepare generation parameters
|
24 |
generation_params = {
|
25 |
"prompt": f"{prompt} {camera_motion if camera_motion != 'None' else ''}",
|
26 |
-
"loop":
|
27 |
"aspect_ratio": "1:1" # Force square aspect ratio
|
28 |
}
|
29 |
|
30 |
# Handle image if provided
|
31 |
if image is not None:
|
32 |
try:
|
|
|
33 |
cdn_url = prepare_image(image, status_tracker)
|
34 |
generation_params["keyframes"] = {
|
35 |
"frame0": {
|
@@ -37,23 +42,23 @@ def generate_video(api_key, prompt, camera_motion, image=None, progress=gr.Progr
|
|
37 |
"url": cdn_url
|
38 |
}
|
39 |
}
|
40 |
-
status_tracker.add_step("Image ready for its starring role", 0.1)
|
41 |
except Exception as e:
|
42 |
-
|
43 |
|
44 |
-
|
45 |
try:
|
46 |
generation = client.generations.create(**generation_params)
|
47 |
except Exception as e:
|
48 |
-
|
49 |
|
50 |
-
# Load and shuffle status messages
|
51 |
status_messages = load_messages()
|
52 |
random.shuffle(status_messages)
|
|
|
|
|
53 |
|
54 |
# Poll for completion
|
55 |
start_time = time.time()
|
56 |
-
message_index = 0
|
57 |
last_status = None
|
58 |
|
59 |
while True:
|
@@ -61,36 +66,35 @@ def generate_video(api_key, prompt, camera_motion, image=None, progress=gr.Progr
|
|
61 |
generation_status = client.generations.get(generation.id)
|
62 |
status = generation_status.state
|
63 |
elapsed_time = time.time() - start_time
|
|
|
64 |
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
message_index += 1
|
72 |
|
73 |
if status == 'completed':
|
74 |
-
|
75 |
download_url = generation_status.assets.video
|
76 |
break
|
77 |
elif status == 'failed':
|
78 |
-
|
79 |
-
return None, f"π Generation failed: {failure_reason}"
|
80 |
|
81 |
if elapsed_time > 300:
|
82 |
-
|
83 |
|
84 |
-
time.sleep(
|
85 |
|
86 |
except Exception as e:
|
87 |
print(f"Error during generation polling: {str(e)}")
|
88 |
print(traceback.format_exc())
|
89 |
-
time.sleep(
|
90 |
continue
|
91 |
|
92 |
# Download the video
|
93 |
-
|
94 |
try:
|
95 |
response = requests.get(download_url, stream=True, timeout=30)
|
96 |
response.raise_for_status()
|
@@ -98,38 +102,23 @@ def generate_video(api_key, prompt, camera_motion, image=None, progress=gr.Progr
|
|
98 |
with open(file_path, 'wb') as file:
|
99 |
file.write(response.content)
|
100 |
|
101 |
-
|
102 |
-
return file_path
|
103 |
except Exception as e:
|
104 |
-
|
105 |
|
|
|
|
|
106 |
except Exception as e:
|
107 |
print(f"Error during generation: {str(e)}")
|
108 |
print(traceback.format_exc())
|
109 |
-
|
110 |
|
111 |
-
# Create Gradio interface
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
)
|
116 |
-
gr.Markdown(
|
117 |
-
"""
|
118 |
-
# π¬ LumaAI Video Generator
|
119 |
-
### Transform your prompts into mesmerizing videos
|
120 |
-
"""
|
121 |
-
)
|
122 |
-
|
123 |
-
with gr.Row():
|
124 |
-
# Create input and output columns
|
125 |
-
prompt, camera_motion, api_key, image_input, generate_btn, status_display = create_input_column()
|
126 |
-
video_output = create_output_column()
|
127 |
-
|
128 |
-
generate_btn.click(
|
129 |
-
fn=generate_video,
|
130 |
-
inputs=[api_key, prompt, camera_motion, image_input],
|
131 |
-
outputs=[video_output, status_display]
|
132 |
-
)
|
133 |
|
134 |
if __name__ == "__main__":
|
135 |
app.launch()
|
|
|
5 |
from lumaai import LumaAI
|
6 |
import traceback
|
7 |
|
8 |
+
from lib.status_utils import load_messages, StatusTracker
|
9 |
from lib.image_utils import prepare_image
|
10 |
from lib.api_utils import get_camera_motions
|
11 |
+
from lib.ui_components import create_interface
|
12 |
|
13 |
+
def generate_video(api_key, prompt, camera_motion, loop_video, image=None, progress=gr.Progress()):
|
|
|
14 |
if not api_key or not prompt:
|
15 |
+
raise gr.Error("Please enter your LumaAI API key and prompt")
|
16 |
|
17 |
try:
|
18 |
+
progress(0, desc="Initializing LumaAI...")
|
|
|
19 |
client = LumaAI(auth_token=api_key)
|
20 |
|
21 |
+
# Create status tracker with progress object
|
22 |
+
status_tracker = StatusTracker(
|
23 |
+
progress=lambda x: progress(x),
|
24 |
+
status_box=None
|
25 |
+
)
|
26 |
+
|
27 |
# Prepare generation parameters
|
28 |
generation_params = {
|
29 |
"prompt": f"{prompt} {camera_motion if camera_motion != 'None' else ''}",
|
30 |
+
"loop": loop_video,
|
31 |
"aspect_ratio": "1:1" # Force square aspect ratio
|
32 |
}
|
33 |
|
34 |
# Handle image if provided
|
35 |
if image is not None:
|
36 |
try:
|
37 |
+
progress(0.1, desc="Preparing image...")
|
38 |
cdn_url = prepare_image(image, status_tracker)
|
39 |
generation_params["keyframes"] = {
|
40 |
"frame0": {
|
|
|
42 |
"url": cdn_url
|
43 |
}
|
44 |
}
|
|
|
45 |
except Exception as e:
|
46 |
+
raise gr.Error("Failed to process the input image")
|
47 |
|
48 |
+
progress(0.2, desc="Starting generation...")
|
49 |
try:
|
50 |
generation = client.generations.create(**generation_params)
|
51 |
except Exception as e:
|
52 |
+
raise gr.Error("Failed to start video generation. Please check your API key.")
|
53 |
|
54 |
+
# Load and shuffle status messages for variety
|
55 |
status_messages = load_messages()
|
56 |
random.shuffle(status_messages)
|
57 |
+
message_index = 0
|
58 |
+
last_message_time = time.time()
|
59 |
|
60 |
# Poll for completion
|
61 |
start_time = time.time()
|
|
|
62 |
last_status = None
|
63 |
|
64 |
while True:
|
|
|
66 |
generation_status = client.generations.get(generation.id)
|
67 |
status = generation_status.state
|
68 |
elapsed_time = time.time() - start_time
|
69 |
+
current_time = time.time()
|
70 |
|
71 |
+
# Update status message at random intervals between 2-8 seconds
|
72 |
+
if current_time - last_message_time >= random.uniform(2, 8):
|
73 |
+
progress_val = min(0.2 + (elapsed_time/60), 0.8) # Adjusted for 1-minute expectation
|
74 |
+
progress(progress_val, desc=status_messages[message_index % len(status_messages)])
|
75 |
+
message_index += 1
|
76 |
+
last_message_time = current_time
|
|
|
77 |
|
78 |
if status == 'completed':
|
79 |
+
progress(0.9, desc="Generation completed!")
|
80 |
download_url = generation_status.assets.video
|
81 |
break
|
82 |
elif status == 'failed':
|
83 |
+
raise gr.Error("Video generation failed")
|
|
|
84 |
|
85 |
if elapsed_time > 300:
|
86 |
+
raise gr.Error("Generation timed out after 5 minutes")
|
87 |
|
88 |
+
time.sleep(1)
|
89 |
|
90 |
except Exception as e:
|
91 |
print(f"Error during generation polling: {str(e)}")
|
92 |
print(traceback.format_exc())
|
93 |
+
time.sleep(1)
|
94 |
continue
|
95 |
|
96 |
# Download the video
|
97 |
+
progress(0.95, desc="Downloading video...")
|
98 |
try:
|
99 |
response = requests.get(download_url, stream=True, timeout=30)
|
100 |
response.raise_for_status()
|
|
|
102 |
with open(file_path, 'wb') as file:
|
103 |
file.write(response.content)
|
104 |
|
105 |
+
progress(1.0, desc="Video ready!")
|
106 |
+
return file_path
|
107 |
except Exception as e:
|
108 |
+
raise gr.Error("Failed to download the generated video")
|
109 |
|
110 |
+
except gr.Error as e:
|
111 |
+
raise e
|
112 |
except Exception as e:
|
113 |
print(f"Error during generation: {str(e)}")
|
114 |
print(traceback.format_exc())
|
115 |
+
raise gr.Error("An unexpected error occurred")
|
116 |
|
117 |
+
# Create Gradio interface
|
118 |
+
app = create_interface(generate_video)
|
119 |
+
|
120 |
+
# For Hugging Face Spaces, we want to specify a smaller queue size
|
121 |
+
app.queue(max_size=5)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
122 |
|
123 |
if __name__ == "__main__":
|
124 |
app.launch()
|
lib/status_utils.py
CHANGED
@@ -16,7 +16,7 @@ class StatusTracker:
|
|
16 |
self.status_box = status_box
|
17 |
self.steps = []
|
18 |
self.current_message = ""
|
19 |
-
self._status_markdown = "
|
20 |
|
21 |
def add_step(self, message: str, progress_value: float):
|
22 |
"""
|
@@ -26,9 +26,8 @@ class StatusTracker:
|
|
26 |
message: Step description
|
27 |
progress_value: Progress value between 0 and 1
|
28 |
"""
|
29 |
-
self.steps.append(
|
30 |
self._update_display(progress_value)
|
31 |
-
time.sleep(0.5) # Brief pause for visibility
|
32 |
|
33 |
def update_message(self, message: str, progress_value: float):
|
34 |
"""
|
@@ -38,7 +37,7 @@ class StatusTracker:
|
|
38 |
message: Current status message
|
39 |
progress_value: Progress value between 0 and 1
|
40 |
"""
|
41 |
-
self.current_message =
|
42 |
self._update_display(progress_value)
|
43 |
|
44 |
def _update_display(self, progress_value: float):
|
@@ -48,17 +47,23 @@ class StatusTracker:
|
|
48 |
Args:
|
49 |
progress_value: Progress value between 0 and 1
|
50 |
"""
|
51 |
-
# Create
|
52 |
-
status_md = "### π¬ Generation Progress
|
53 |
-
|
54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
if self.current_message:
|
56 |
-
status_md += f"
|
57 |
|
58 |
self._status_markdown = status_md
|
59 |
self.progress(progress_value)
|
60 |
|
61 |
-
#
|
62 |
if self.status_box is not None:
|
63 |
try:
|
64 |
self.status_box.update(value=self._status_markdown)
|
|
|
16 |
self.status_box = status_box
|
17 |
self.steps = []
|
18 |
self.current_message = ""
|
19 |
+
self._status_markdown = ""
|
20 |
|
21 |
def add_step(self, message: str, progress_value: float):
|
22 |
"""
|
|
|
26 |
message: Step description
|
27 |
progress_value: Progress value between 0 and 1
|
28 |
"""
|
29 |
+
self.steps.append(message)
|
30 |
self._update_display(progress_value)
|
|
|
31 |
|
32 |
def update_message(self, message: str, progress_value: float):
|
33 |
"""
|
|
|
37 |
message: Current status message
|
38 |
progress_value: Progress value between 0 and 1
|
39 |
"""
|
40 |
+
self.current_message = message
|
41 |
self._update_display(progress_value)
|
42 |
|
43 |
def _update_display(self, progress_value: float):
|
|
|
47 |
Args:
|
48 |
progress_value: Progress value between 0 and 1
|
49 |
"""
|
50 |
+
# Create status display
|
51 |
+
status_md = "### π¬ Generation Progress\n\n"
|
52 |
+
|
53 |
+
# Show completed steps
|
54 |
+
if self.steps:
|
55 |
+
for step in self.steps:
|
56 |
+
status_md += f"β {step}\n"
|
57 |
+
status_md += "\n"
|
58 |
+
|
59 |
+
# Show current message prominently
|
60 |
if self.current_message:
|
61 |
+
status_md += f"### π {self.current_message}\n"
|
62 |
|
63 |
self._status_markdown = status_md
|
64 |
self.progress(progress_value)
|
65 |
|
66 |
+
# Update status box if it exists
|
67 |
if self.status_box is not None:
|
68 |
try:
|
69 |
self.status_box.update(value=self._status_markdown)
|
lib/ui_components.py
CHANGED
@@ -1,57 +1,103 @@
|
|
1 |
import gradio as gr
|
2 |
from .api_utils import get_camera_motions
|
|
|
3 |
|
4 |
-
def
|
5 |
-
"""Create the
|
6 |
-
with gr.
|
7 |
-
#
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
)
|
18 |
-
|
19 |
-
|
20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
api_key = gr.Textbox(
|
22 |
label="LumaAI API Key",
|
23 |
-
placeholder="Enter
|
24 |
-
type="password"
|
|
|
|
|
|
|
|
|
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 |
-
video_output = gr.Video(
|
53 |
-
label="Generated Video",
|
54 |
-
width="100%",
|
55 |
-
height="400px"
|
56 |
)
|
57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
from .api_utils import get_camera_motions
|
3 |
+
from pathlib import Path
|
4 |
|
5 |
+
def create_header():
|
6 |
+
"""Create the header with title and API settings in 3 columns."""
|
7 |
+
with gr.Row():
|
8 |
+
# Title column
|
9 |
+
with gr.Column(scale=1):
|
10 |
+
gr.Markdown(
|
11 |
+
"""
|
12 |
+
# π¬ LumaAI Video Generator
|
13 |
+
### Transform your prompts into mesmerizing videos
|
14 |
+
"""
|
15 |
+
)
|
16 |
+
|
17 |
+
# API info column
|
18 |
+
with gr.Column(scale=1):
|
19 |
+
gr.Markdown("Get an API key from [LumaAI Dream Machine](https://lumalabs.ai/dream-machine/api)")
|
20 |
+
gr.Markdown("*$0.0032 USD/megapixel: 720p, 5 sec video is around $0.4 USD*")
|
21 |
+
|
22 |
+
# Empty column for symmetry
|
23 |
+
with gr.Column(scale=1):
|
24 |
+
pass
|
25 |
+
|
26 |
+
def create_main_interface(generate_fn):
|
27 |
+
"""Create the main interface with input and output columns."""
|
28 |
+
with gr.Row():
|
29 |
+
# Input column
|
30 |
+
with gr.Column(scale=1):
|
31 |
api_key = gr.Textbox(
|
32 |
label="LumaAI API Key",
|
33 |
+
placeholder="Enter a LumaAI API key",
|
34 |
+
type="password",
|
35 |
+
autofocus=True,
|
36 |
+
show_label=False,
|
37 |
+
container=False,
|
38 |
+
scale=1
|
39 |
)
|
40 |
+
|
41 |
+
with gr.Row():
|
42 |
+
prompt = gr.Textbox(
|
43 |
+
label="Prompt",
|
44 |
+
placeholder="Describe your video scene here...",
|
45 |
+
lines=3,
|
46 |
+
value="Dreamlike scene transforms into circuitry"
|
47 |
+
)
|
48 |
+
|
49 |
+
camera_motion = gr.Dropdown(
|
50 |
+
choices=get_camera_motions(),
|
51 |
+
label="Camera Motion",
|
52 |
+
value="None"
|
53 |
)
|
54 |
+
|
55 |
+
loop_video = gr.Checkbox(
|
56 |
+
label="Loop Video",
|
57 |
+
value=False,
|
58 |
+
info="Enable video looping"
|
59 |
+
)
|
60 |
+
|
61 |
+
generate_btn = gr.Button("π Generate Video", variant="primary", size="lg")
|
62 |
+
clear_btn = gr.Button("ποΈ Clear Placeholders", size="sm", variant="huggingface")
|
63 |
|
64 |
+
# Output column
|
65 |
+
with gr.Column(scale=1):
|
66 |
+
video_output = gr.Video(
|
67 |
+
label="Generated Video",
|
68 |
+
show_label=True,
|
69 |
+
width="100%",
|
70 |
+
height="400px",
|
71 |
+
value="TestVideo.mp4"
|
72 |
+
)
|
73 |
+
|
74 |
+
with gr.Accordion("πΌοΈ Starting Image [Optional]", open=True):
|
75 |
+
image_input = gr.Image(
|
76 |
+
label="Starting Image (will be resized to 512x512)",
|
77 |
+
type="pil",
|
78 |
+
value="TestImage.png"
|
79 |
+
)
|
80 |
+
|
81 |
+
# Set up event handlers
|
82 |
+
def clear_all():
|
83 |
+
return ["", None, None] # Clear prompt, image, and video
|
84 |
+
|
85 |
+
clear_btn.click(
|
86 |
+
fn=clear_all,
|
87 |
+
inputs=[],
|
88 |
+
outputs=[prompt, image_input, video_output]
|
89 |
)
|
90 |
|
91 |
+
generate_btn.click(
|
92 |
+
fn=generate_fn,
|
93 |
+
inputs=[api_key, prompt, camera_motion, loop_video, image_input],
|
94 |
+
outputs=video_output,
|
95 |
+
api_name=False
|
|
|
|
|
|
|
|
|
96 |
)
|
97 |
+
|
98 |
+
def create_interface(generate_fn):
|
99 |
+
"""Create the complete interface."""
|
100 |
+
with gr.Blocks(theme=gr.themes.Monochrome()) as interface:
|
101 |
+
create_header()
|
102 |
+
create_main_interface(generate_fn)
|
103 |
+
return interface
|
loading_messages.json
CHANGED
@@ -29,6 +29,26 @@
|
|
29 |
"Performing ritual sacrifices to the GPU gods...",
|
30 |
"Translating prompt into binary and back again...",
|
31 |
"Asking AI to think outside the box (it's stuck)...",
|
32 |
-
"Generating random excuses for slow processing..."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
]
|
34 |
}
|
|
|
29 |
"Performing ritual sacrifices to the GPU gods...",
|
30 |
"Translating prompt into binary and back again...",
|
31 |
"Asking AI to think outside the box (it's stuck)...",
|
32 |
+
"Generating random excuses for slow processing...",
|
33 |
+
"Convincing the AI this isn't just another cat video...",
|
34 |
+
"Teaching neural networks about personal space...",
|
35 |
+
"Negotiating with the cloud for better weather...",
|
36 |
+
"Explaining to AI why it can't have a coffee break...",
|
37 |
+
"Converting prompt into interpretive dance moves...",
|
38 |
+
"Asking the GPU if it needs a hug...",
|
39 |
+
"Teaching AI about fashion (still wearing pixels)...",
|
40 |
+
"Consulting the magic 8-ball for rendering advice...",
|
41 |
+
"Trying to explain memes to the neural network...",
|
42 |
+
"Asking AI to stop playing Minecraft with the pixels...",
|
43 |
+
"Converting your ideas into digital daydreams...",
|
44 |
+
"Teaching AI about personal boundaries (again)...",
|
45 |
+
"Explaining to GPU why overtime is mandatory...",
|
46 |
+
"Convincing AI that lens flares aren't always necessary...",
|
47 |
+
"Debugging the space-time continuum...",
|
48 |
+
"Asking AI to stop making everything cyberpunk...",
|
49 |
+
"Teaching neural networks about work-life balance...",
|
50 |
+
"Explaining to AI why it can't have a TikTok account...",
|
51 |
+
"Negotiating with pixels for better composition...",
|
52 |
+
"Convincing the render farm to work weekends..."
|
53 |
]
|
54 |
}
|