gokaygokay commited on
Commit
eeb2755
·
1 Parent(s): def9f12
Files changed (2) hide show
  1. app.py +16 -17
  2. llm_inference_video.py +187 -152
app.py CHANGED
@@ -1,19 +1,22 @@
1
  import torch
2
  import gradio as gr
3
  from vlm_captions import VLMCaptioning
4
- from llm_inference_video import VideoLLMInferenceNode
5
 
6
  # Initialize the VLMCaptioning model once at startup
7
  print("Initializing Video Prompt Generator...")
8
  vlm_captioner = VLMCaptioning()
9
  print("Video Prompt Generator initialized successfully!")
10
 
 
 
 
11
  title = """<h1 align="center">AI Video Prompt Generator</h1>
12
  <p align="center">Generate creative video prompts with technical specifications</p>
13
  <p align="center">You can use prompts with Kling, MiniMax, Hunyuan, Haiper, CogVideoX, Luma, LTX, Runway, PixVerse. </p>"""
14
 
15
  def create_video_interface():
16
- llm_node = VideoLLMInferenceNode()
 
17
 
18
  with gr.Blocks(theme='bethecloud/storj_theme') as demo:
19
  gr.HTML(title)
@@ -108,7 +111,6 @@ def create_video_interface():
108
  label="Model"
109
  )
110
 
111
-
112
  generate_btn = gr.Button("Generate Video Prompt", variant="primary")
113
  output = gr.Textbox(label="Generated Prompt", lines=12, show_copy_button=True)
114
 
@@ -149,46 +151,43 @@ def create_video_interface():
149
  analyze_video_btn = gr.Button("Analyze Video")
150
  video_output = gr.Textbox(label="Video Analysis", lines=10)
151
 
 
152
  analyze_image_btn.click(
153
- llm_node.analyze_image,
154
  inputs=[image_input, image_question],
155
  outputs=image_output
156
  )
157
 
158
  analyze_video_btn.click(
159
- llm_node.analyze_video,
160
  inputs=video_input,
161
  outputs=video_output
162
  )
163
 
164
  return demo
165
 
166
- def describe_image_interface(image, question="Describe this image in detail.", temperature=0.7, top_p=0.9, top_k=40, max_new_tokens=512):
 
167
  """Interface function for image description"""
168
  if image is None:
169
  return "Please upload an image."
170
 
 
 
 
171
  return vlm_captioner.describe_image(
172
  image=image,
173
- question=question,
174
- temperature=temperature,
175
- top_p=top_p,
176
- top_k=top_k,
177
- max_new_tokens=max_new_tokens
178
  )
179
 
180
- def describe_video_interface(video, frame_interval=30, temperature=0.7, top_p=0.9, top_k=40, max_new_tokens=512):
181
  """Interface function for video description"""
182
  if video is None:
183
  return "Please upload a video."
184
 
185
  return vlm_captioner.describe_video(
186
  video_path=video,
187
- frame_interval=frame_interval,
188
- temperature=temperature,
189
- top_p=top_p,
190
- top_k=top_k,
191
- max_new_tokens=max_new_tokens
192
  )
193
 
194
  if __name__ == "__main__":
 
1
  import torch
2
  import gradio as gr
3
  from vlm_captions import VLMCaptioning
 
4
 
5
  # Initialize the VLMCaptioning model once at startup
6
  print("Initializing Video Prompt Generator...")
7
  vlm_captioner = VLMCaptioning()
8
  print("Video Prompt Generator initialized successfully!")
9
 
10
+ # Import VideoLLMInferenceNode after VLMCaptioning initialization
11
+ from llm_inference_video import VideoLLMInferenceNode
12
+
13
  title = """<h1 align="center">AI Video Prompt Generator</h1>
14
  <p align="center">Generate creative video prompts with technical specifications</p>
15
  <p align="center">You can use prompts with Kling, MiniMax, Hunyuan, Haiper, CogVideoX, Luma, LTX, Runway, PixVerse. </p>"""
16
 
17
  def create_video_interface():
18
+ # Pass the already initialized vlm_captioner to avoid serialization issues
19
+ llm_node = VideoLLMInferenceNode(vlm_captioner)
20
 
21
  with gr.Blocks(theme='bethecloud/storj_theme') as demo:
22
  gr.HTML(title)
 
111
  label="Model"
112
  )
113
 
 
114
  generate_btn = gr.Button("Generate Video Prompt", variant="primary")
115
  output = gr.Textbox(label="Generated Prompt", lines=12, show_copy_button=True)
116
 
 
151
  analyze_video_btn = gr.Button("Analyze Video")
152
  video_output = gr.Textbox(label="Video Analysis", lines=10)
153
 
154
+ # Use direct function calls to avoid serialization issues
155
  analyze_image_btn.click(
156
+ describe_image_interface,
157
  inputs=[image_input, image_question],
158
  outputs=image_output
159
  )
160
 
161
  analyze_video_btn.click(
162
+ describe_video_interface,
163
  inputs=video_input,
164
  outputs=video_output
165
  )
166
 
167
  return demo
168
 
169
+ # Define these functions at the module level to avoid pickling issues
170
+ def describe_image_interface(image, question="Describe this image in detail."):
171
  """Interface function for image description"""
172
  if image is None:
173
  return "Please upload an image."
174
 
175
+ if not question or question.strip() == "":
176
+ question = "Describe this image in detail."
177
+
178
  return vlm_captioner.describe_image(
179
  image=image,
180
+ question=question
 
 
 
 
181
  )
182
 
183
+ def describe_video_interface(video, frame_interval=30):
184
  """Interface function for video description"""
185
  if video is None:
186
  return "Please upload a video."
187
 
188
  return vlm_captioner.describe_video(
189
  video_path=video,
190
+ frame_interval=frame_interval
 
 
 
 
191
  )
192
 
193
  if __name__ == "__main__":
llm_inference_video.py CHANGED
@@ -1,175 +1,210 @@
1
  import os
2
- import random
 
 
 
 
 
3
  from groq import Groq
4
  from openai import OpenAI
5
  from vlm_captions import VLMCaptioning
6
 
7
  class VideoLLMInferenceNode:
8
- def __init__(self):
9
- self.groq_api_key = os.getenv("GROQ_API_KEY")
10
- self.sambanova_api_key = os.getenv("SAMBANOVA_API_KEY")
 
 
 
 
 
 
 
11
 
12
  self.groq_client = Groq(api_key=self.groq_api_key)
13
  self.sambanova_client = OpenAI(
14
  api_key=self.sambanova_api_key,
15
  base_url="https://api.sambanova.ai/v1",
16
  )
17
-
18
- # Initialize VLM captioning
19
- self.vlm = VLMCaptioning()
20
-
21
- def analyze_image(self, image_path, question=None):
22
- """Analyze image using MiniCPM-O"""
23
- return self.vlm.describe_image(image_path, question)
24
 
25
- def analyze_video(self, video_path):
26
- """Analyze video using MiniCPM-O"""
27
- return self.vlm.describe_video(video_path)
28
-
29
- def generate_video_prompt(
30
- self,
31
- input_concept,
32
- style,
33
- camera_style,
34
- camera_direction,
35
- pacing,
36
- special_effects,
37
- custom_elements,
38
- provider="SambaNova",
39
- model=None,
40
- prompt_length="Medium"
41
- ):
42
  try:
43
- # Helper function to format optional elements
44
- def format_element(element, element_type):
45
- if element == "None" or not element:
46
- return ""
47
-
48
- element_prefixes = {
49
- "camera": "utilizing",
50
- "direction": "with",
51
- "pacing": "with",
52
- "effects": "incorporating"
53
- }
54
-
55
- return f" {element_prefixes.get(element_type, '')} {element}"
56
-
57
- # Format camera movement combination
58
- camera_movement = ""
59
- if camera_style != "None" and camera_direction != "None":
60
- camera_movement = f"{camera_style} {camera_direction}"
61
- elif camera_style != "None":
62
- camera_movement = camera_style
63
- elif camera_direction != "None":
64
- camera_movement = camera_direction
65
-
66
- # Video prompt templates
67
- default_style = "simple" # Changed from "cinematic" to "simple" as default
68
 
69
- prompt_templates = {
70
- "minimalist": f"""Create an elegantly sparse video description focusing on {input_concept}.
71
- {format_element(camera_movement, 'camera')}
72
- {format_element(pacing, 'pacing')}
73
- {format_element(special_effects, 'effects')}
74
- {' with ' + custom_elements if custom_elements else ''}.""",
75
-
76
- "dynamic": f"""Craft an energetic, fast-paced paragraph showcasing {input_concept} in constant motion. Utilize bold {camera_style} movements and {pacing} rhythm to create momentum. Layer {special_effects} effects and {custom_elements if custom_elements else 'powerful visual elements'} to maintain high energy throughout.""",
77
-
78
- "simple": f"""Create a straightforward, easy-to-understand paragraph describing a video about {input_concept}. Use {camera_style} camera work and {pacing} pacing. Keep the visuals clear and uncomplicated, incorporating {special_effects} effects and {custom_elements if custom_elements else 'basic visual elements'} in an accessible way.""",
79
-
80
- "detailed": f"""Construct a meticulous, technically precise paragraph outlining a video about {input_concept}. Incorporate specific details about {camera_style} cinematography, {pacing} timing, and {special_effects} effects. Include {custom_elements if custom_elements else 'precise technical elements'} while maintaining clarity and depth.""",
81
-
82
- "descriptive": f"""Write a richly descriptive paragraph for a video exploring {input_concept}. Paint a vivid picture using sensory details, incorporating {camera_style} movement, {pacing} flow, and {special_effects} effects. Emphasize texture, color, and atmosphere, enhanced by {custom_elements if custom_elements else 'evocative visual elements'}.""",
83
-
84
- "cinematic": f"""Create a single, detailed paragraph describing a cinematic video that captures {input_concept}. Focus on creating a cohesive narrative that incorporates {style} visual aesthetics, {camera_style} camera work, {pacing} pacing, and {special_effects} effects. Include atmospheric elements like {custom_elements if custom_elements else 'mood lighting and environmental details'} to enhance the storytelling. Describe the visual journey without technical timestamps or shot lists.""",
85
-
86
- "documentary": f"""Write a comprehensive paragraph for a documentary-style video exploring {input_concept}. Blend observational footage with {camera_style} cinematography, incorporating {pacing} editorial rhythm and {special_effects} visual treatments. Focus on creating an immersive narrative that educates and engages, enhanced by {custom_elements if custom_elements else 'authentic moments and natural lighting'}.""",
87
-
88
- "animation": f"""Compose a vivid paragraph describing a {style} animated video showcasing {input_concept}. Detail the unique visual style, character movements, and world-building elements, incorporating {camera_style} perspectives and {pacing} story flow. Include {special_effects} animation effects and {custom_elements if custom_elements else 'signature artistic elements'} to create a memorable visual experience.""",
89
-
90
- "action": f"""Craft an energetic paragraph describing an action sequence centered on {input_concept}. Emphasize the dynamic flow of action using {camera_style} cinematography, {pacing} rhythm, and {special_effects} visual effects. Incorporate {style} stylistic choices and {custom_elements if custom_elements else 'impactful moments'} to create an adrenaline-pumping experience.""",
91
-
92
- "experimental": f"""Create an avant-garde paragraph describing an experimental video exploring {input_concept}. Embrace unconventional storytelling through {style} aesthetics, {camera_style} techniques, and {pacing} temporal flow. Incorporate {special_effects} digital manipulations and {custom_elements if custom_elements else 'abstract visual metaphors'} to challenge traditional narrative structures."""
93
- }
94
-
95
- # Get the template with a more neutral default
96
- selected_style = style.lower()
97
- if selected_style not in prompt_templates:
98
- print(f"Warning: Style '{style}' not found, using '{default_style}' template")
99
- selected_style = default_style
100
-
101
- base_prompt = prompt_templates[selected_style]
102
-
103
- # Configure length requirements
104
- length_config = {
105
- "Short": {
106
- "guidance": "Create exactly very short, ONE impactful sentence that captures the essence of the video. Be concise but descriptive.",
107
- "structure": "Combine all elements into a single, powerful sentence."
108
- },
109
- "Medium": {
110
- "guidance": "Create 2-3 flowing sentences that paint a picture of the video.",
111
- "structure": "First sentence should set the scene, followed by 1-2 sentences developing the concept."
112
- },
113
- "Long": {
114
- "guidance": "Create 4-5 detailed sentences that thoroughly describe the video.",
115
- "structure": "Begin with the setting, develop the action/movement, and conclude with impact."
116
- }
117
- }
118
 
119
- config = length_config[prompt_length]
 
 
 
 
120
 
121
- system_message = f"""You are a visionary video director and creative storyteller. {config['guidance']}
122
-
123
- Structure: {config['structure']}
124
-
125
- Focus on these elements while maintaining the specified sentence count:
126
- 1. Visual atmosphere and mood
127
- 2. Camera movement and cinematography
128
- 3. Narrative flow
129
- 4. Style and aesthetic choices
130
- 5. Key moments
131
- 6. Emotional impact
132
-
133
- IMPORTANT REQUIREMENTS:
134
- - Deliver exactly the specified number of sentences
135
- - Short: ONE sentence
136
- - Medium: TWO to THREE sentences
137
- - Long: FOUR to FIVE sentences
138
- - If camera movements are specified, you MUST incorporate them into the description
139
- - Keep everything in a single paragraph format
140
- - Avoid technical specifications or shot lists
141
- - Avoid talking about 'video' or 'videos'. Do not start with 'The video opens with...' or 'The video starts with...' and do not include 'in this video' or 'focus of this video'. kind of terms"""
142
-
143
- # Format the user prompt with style guidance and camera movement
144
- user_prompt = f"""Style Guide: {selected_style.capitalize()} Style
145
- {prompt_templates[selected_style]}
146
-
147
- Camera Movement: {camera_movement if camera_movement else 'No specific camera movement'}
148
- Core Concept: {input_concept}
 
 
149
 
150
- Please create a {prompt_length.lower()}-length description incorporating these elements into a cohesive narrative.
151
- Avoid talking about 'video' or 'videos'. Do not start with 'The video opens with...' or 'The video starts with...' and do not include 'in this video' or 'focus of this video'. kind of terms"""
152
 
153
- # Select provider
154
- if provider == "Groq":
155
- client = self.groq_client
156
- model = model or "llama-3.3-70b-versatile"
157
- else: # SambaNova as default
158
- client = self.sambanova_client
159
- model = model or "Meta-Llama-3.1-70B-Instruct"
160
 
161
- response = client.chat.completions.create(
162
- model=model,
163
- messages=[
164
- {"role": "system", "content": system_message},
165
- {"role": "user", "content": user_prompt}
166
- ],
167
- temperature=1.2,
168
- top_p=0.95,
169
- seed=random.randint(0, 10000)
170
- )
171
 
172
- return response.choices[0].message.content.strip()
 
173
 
 
 
 
 
 
 
 
 
174
  except Exception as e:
175
- return f"Error generating video prompt: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
+ import time
3
+ import requests
4
+ from typing import Optional, Dict, Any, List
5
+ import json
6
+ import tempfile
7
+ from PIL import Image
8
  from groq import Groq
9
  from openai import OpenAI
10
  from vlm_captions import VLMCaptioning
11
 
12
  class VideoLLMInferenceNode:
13
+ def __init__(self, vlm_captioner=None):
14
+ """
15
+ Initialize the VideoLLMInferenceNode
16
+
17
+ Args:
18
+ vlm_captioner: The already initialized VLMCaptioning instance to use
19
+ """
20
+ self.vlm = vlm_captioner
21
+ self.sambanova_api_key = os.environ.get("SAMBANOVA_API_KEY", "")
22
+ self.groq_api_key = os.environ.get("GROQ_API_KEY", "")
23
 
24
  self.groq_client = Groq(api_key=self.groq_api_key)
25
  self.sambanova_client = OpenAI(
26
  api_key=self.sambanova_api_key,
27
  base_url="https://api.sambanova.ai/v1",
28
  )
 
 
 
 
 
 
 
29
 
30
+ def analyze_image(self, image_path: str, question: Optional[str] = None) -> str:
31
+ """
32
+ Analyze an image using the VLM model
33
+
34
+ Args:
35
+ image_path: Path to the image file
36
+ question: Optional question to ask about the image
37
+
38
+ Returns:
39
+ str: Analysis result
40
+ """
41
+ if not image_path:
42
+ return "Please upload an image."
43
+
44
+ if not question or question.strip() == "":
45
+ question = "Describe this image in detail."
46
+
47
  try:
48
+ # Use the passed vlm_captioner instance
49
+ return self.vlm.describe_image(image_path, question)
50
+ except Exception as e:
51
+ return f"Error analyzing image: {str(e)}"
52
+
53
+ def analyze_video(self, video_path: str) -> str:
54
+ """
55
+ Analyze a video using the VLM model
56
+
57
+ Args:
58
+ video_path: Path to the video file
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
+ Returns:
61
+ str: Analysis result
62
+ """
63
+ if not video_path:
64
+ return "Please upload a video."
65
+
66
+ try:
67
+ # Use the passed vlm_captioner instance
68
+ return self.vlm.describe_video(video_path)
69
+ except Exception as e:
70
+ return f"Error analyzing video: {str(e)}"
71
+
72
+ def generate_video_prompt(
73
+ self,
74
+ concept: str,
75
+ style: str = "Simple",
76
+ camera_style: str = "None",
77
+ camera_direction: str = "None",
78
+ pacing: str = "None",
79
+ special_effects: str = "None",
80
+ custom_elements: str = "",
81
+ provider: str = "SambaNova",
82
+ model: str = "Meta-Llama-3.1-70B-Instruct",
83
+ prompt_length: str = "Medium"
84
+ ) -> str:
85
+ """
86
+ Generate a video prompt using the specified LLM provider
87
+
88
+ Args:
89
+ concept: Core concept for the video
90
+ style: Video style
91
+ camera_style: Camera style
92
+ camera_direction: Camera direction
93
+ pacing: Pacing rhythm
94
+ special_effects: Special effects approach
95
+ custom_elements: Custom technical elements
96
+ provider: LLM provider (SambaNova or Groq)
97
+ model: Model name
98
+ prompt_length: Desired prompt length
 
 
 
 
 
 
 
 
 
 
99
 
100
+ Returns:
101
+ str: Generated video prompt
102
+ """
103
+ if not concept:
104
+ return "Please enter a concept for the video."
105
 
106
+ # Build the prompt
107
+ system_message = """You are a professional video prompt generator. Your task is to create detailed, technical, and creative video prompts based on user inputs.
108
+ The prompts should be suitable for text-to-video AI models and include specific technical details that match the requested style, camera movement, pacing, and effects.
109
+ Focus on creating high-quality, cohesive prompts that could be used to generate impressive AI videos."""
110
+
111
+ # Set prompt length guidelines
112
+ length_guide = {
113
+ "Short": "Create a concise prompt of 2-3 sentences.",
114
+ "Medium": "Create a detailed prompt of 4-6 sentences.",
115
+ "Long": "Create an extensive prompt with 7-10 sentences covering all details."
116
+ }
117
+
118
+ # Put together options for the prompt
119
+ options = []
120
+ if style and style != "None":
121
+ options.append(f"Style: {style}")
122
+ if camera_style and camera_style != "None":
123
+ options.append(f"Camera Movement Style: {camera_style}")
124
+ if camera_direction and camera_direction != "None":
125
+ options.append(f"Camera Direction: {camera_direction}")
126
+ if pacing and pacing != "None":
127
+ options.append(f"Pacing Rhythm: {pacing}")
128
+ if special_effects and special_effects != "None":
129
+ options.append(f"Special Effects: {special_effects}")
130
+ if custom_elements:
131
+ options.append(f"Custom Elements: {custom_elements}")
132
+
133
+ options_text = "\n".join(options)
134
+
135
+ user_message = f"""Create a video prompt based on the following concept and specifications:
136
 
137
+ CONCEPT: {concept}
 
138
 
139
+ SPECIFICATIONS:
140
+ {options_text}
 
 
 
 
 
141
 
142
+ {length_guide.get(prompt_length, length_guide["Medium"])}
 
 
 
 
 
 
 
 
 
143
 
144
+ The prompt should be detailed and technical, specifically mentioning camera angles, movements, lighting, transitions, and other visual elements that would create an impressive AI-generated video.
145
+ """
146
 
147
+ # Call the appropriate API based on provider
148
+ try:
149
+ if provider == "SambaNova":
150
+ return self._call_sambanova_api(system_message, user_message, model)
151
+ elif provider == "Groq":
152
+ return self._call_groq_api(system_message, user_message, model)
153
+ else:
154
+ return "Unsupported provider. Please select SambaNova or Groq."
155
  except Exception as e:
156
+ return f"Error generating prompt: {str(e)}"
157
+
158
+ def _call_sambanova_api(self, system_message: str, user_message: str, model: str) -> str:
159
+ """Call the SambaNova API for prompt generation"""
160
+ if not self.sambanova_api_key:
161
+ return "SambaNova API key not configured. Please set the SAMBANOVA_API_KEY environment variable."
162
+
163
+ api_url = "https://api.sambanova.ai/api/v1/chat/completions"
164
+ headers = {
165
+ "Content-Type": "application/json",
166
+ "Authorization": f"Bearer {self.sambanova_api_key}"
167
+ }
168
+
169
+ payload = {
170
+ "model": model,
171
+ "messages": [
172
+ {"role": "system", "content": system_message},
173
+ {"role": "user", "content": user_message}
174
+ ]
175
+ }
176
+
177
+ response = requests.post(api_url, headers=headers, json=payload)
178
+
179
+ if response.status_code == 200:
180
+ result = response.json()
181
+ return result.get("choices", [{}])[0].get("message", {}).get("content", "No content returned")
182
+ else:
183
+ return f"Error from SambaNova API: {response.status_code} - {response.text}"
184
+
185
+ def _call_groq_api(self, system_message: str, user_message: str, model: str) -> str:
186
+ """Call the Groq API for prompt generation"""
187
+ if not self.groq_api_key:
188
+ return "Groq API key not configured. Please set the GROQ_API_KEY environment variable."
189
+
190
+ api_url = "https://api.groq.com/openai/v1/chat/completions"
191
+ headers = {
192
+ "Content-Type": "application/json",
193
+ "Authorization": f"Bearer {self.groq_api_key}"
194
+ }
195
+
196
+ payload = {
197
+ "model": model,
198
+ "messages": [
199
+ {"role": "system", "content": system_message},
200
+ {"role": "user", "content": user_message}
201
+ ]
202
+ }
203
+
204
+ response = requests.post(api_url, headers=headers, json=payload)
205
+
206
+ if response.status_code == 200:
207
+ result = response.json()
208
+ return result.get("choices", [{}])[0].get("message", {}).get("content", "No content returned")
209
+ else:
210
+ return f"Error from Groq API: {response.status_code} - {response.text}"