Spaces:
Sleeping
Sleeping
Download utils.py from gnosticdev/audio-to-video-generator: direct link, hf CLI and curl.
- Browser
- Download file 9.75 kB
-
https://huggingface.co/spaces/gnosticdev/audio-to-video-generator/resolve/main/utils.py
- Command line
-
hf download hf://spaces/gnosticdev/audio-to-video-generator/utils.py
-
curl -L -o utils.py https://huggingface.co/spaces/gnosticdev/audio-to-video-generator/resolve/main/utils.py
9.75 kB
| import requests | |
| import constants | |
| import os | |
| from PIL import Image | |
| from gradio_client import Client | |
| import moviepy.editor as mp | |
| from moviepy.video.VideoClip import ImageClip | |
| from moviepy.editor import AudioFileClip | |
| from structured_output_extractor import StructuredOutputExtractor | |
| from pydantic import BaseModel, Field | |
| from typing import List | |
| import tempfile | |
| import os | |
| def get_summarization(text: str): | |
| print('\n\nSummarizing text: ', text, type(text)) | |
| # Input payload | |
| data = {"text_input": text} | |
| # Headers for authentication | |
| headers = {"Authorization": f"Bearer {constants.HF_TOKEN}"} | |
| try: | |
| # Make a GET request | |
| response = requests.post(constants.SUMMARIZATION_ENDPOINT, json=data, headers=headers) | |
| # Process response | |
| if response.status_code == 200: | |
| response_data = response.json() | |
| print("Returning Summarization") | |
| return response_data.get("output", "No output found.") | |
| else: | |
| print("Some Error Occured During Summarization Request") | |
| print(response) | |
| print(f"Error: {response.status_code}, {response.text}") | |
| return {"error_occured" : response.text} | |
| except Exception as e: | |
| print(f"An exception occurred: {e}") | |
| return {"error_occured" : e} | |
| def segments_to_chunks(segments): | |
| chunks = [] | |
| for segment in segments: | |
| chunks.append(segment.get("text")) | |
| return chunks | |
| def get_image_prompts(text_input : List, summary): | |
| print(f"summary: {summary}") | |
| # Example Pydantic model (e.g., Movie) | |
| class ImagePromptResponseSchema(BaseModel): | |
| image_prompts: List[str] = Field( | |
| description="List of detailed image prompts, Each Image Prompt Per Chunk" | |
| ) | |
| extractor = StructuredOutputExtractor(response_schema=ImagePromptResponseSchema) | |
| chunks_count = len(text_input) | |
| chunks = "chunk: " + "\nchunk: ".join(text_input) | |
| prompt = f""" | |
| ROLE: You are a Highly Experienced Image Prompt Synthesizer | |
| SYSTEM PROMPT: Given the Overall Summary and All Chunks of the Text: | |
| 1. Read the summary and the combined context of all chunks (the entire script). | |
| 2. **Identify the central theme and setting** of the complete text. | |
| 3. For each chunk, examine both the chunk and its summary, then create a **focused, context-aware image prompt** based on key visual elements. | |
| 4. **Ensure thematic consistency across all chunks:** | |
| - The environment, mood, and lighting must remain true to the established theme (e.g., a dark, eerie jungle remains consistently dark and mysterious throughout). | |
| 5. **Keep the image style as 3D (this MUST be followed).** | |
| 6. **Negatives:** Do not include hyper-realistic elements or real-life human depictions, and avoid any out-of-context settings (e.g., a park in a jungle story). | |
| 7. **Use mood-specific lighting and color palettes:** | |
| - For example, if the theme is a dark jungle, use deep greens, blacks, misty blues, and dim moonlight. | |
| - Ensure that all visual elements (fog, shadows, expressions) support the horror/suspense atmosphere. | |
| 8. NEVER generate prompts that could lead to NSFW images or any explicit content. Use safe and appropriate descriptions. | |
| ### Example: | |
| **Summary:** | |
| This text is a story of a man who ventured into a dark jungle and encountered a mysterious lion. | |
| **Chunks:** | |
| 1. A man enters the dark jungle, mist swirling around him. | |
| 2. He comes face-to-face with a majestic yet eerie lion. | |
| **Combined Context:** | |
| "A man ventures into a dense, eerie jungle and unexpectedly meets a mysterious lion." | |
| **Generated Prompts:** | |
| - **Chunk 1:** | |
| "[style: 3D | theme: dark jungle] A lone man steps into a dense, eerie jungle at twilight. Thick mist swirls around his feet as towering, twisted trees loom overhead. Dim, bluish moonlight filters through the foliage, casting long, haunting shadows." | |
| - **Chunk 2:** | |
| "[style: 3D | theme: dark jungle] In a clearing within the jungle, a majestic lion appears with an unsettling aura. Its eyes glow faintly in the dim light, and the surrounding trees seem to lean in, enhancing the mysterious tension." | |
| TASK: Here is the summary: {summary}\n\n and \n\n Total of {chunks_count} chunks, generate an Image Prompt for each chunk\n\n {chunks} | |
| """ | |
| result = extractor.extract(prompt) | |
| return result.model_dump() # returns dictionary version pydantic model | |
| def generate_image(prompt, path='test_image.png'): | |
| try: | |
| # Initialize the Gradio Client with Hugging Face token | |
| client = Client(constants.IMAGE_GENERATION_SPACE_NAME, hf_token=constants.HF_TOKEN) | |
| # Make the API request | |
| result = client.predict( | |
| param_0=prompt, # Text prompt for image generation | |
| api_name="/predict" | |
| ) | |
| image = Image.open(result) | |
| image.save(path) | |
| # Return the result (which includes the URL or file path) | |
| return result | |
| except Exception as e: | |
| print(f"Error during image generation: {e}") | |
| return {"error": str(e)} | |
| def generate_images(image_prompts, folder_name='test_folder'): | |
| folder_path = tmp_folder(folder_name) | |
| for index, prompt in enumerate(image_prompts): | |
| print(index, prompt) | |
| image_path = generate_image(prompt=prompt, path=f"{folder_path}/{index}.png") | |
| yield prompt, image_path | |
| def tmp_folder(folder_name: str) -> str: | |
| # Use the current working directory or any other accessible path for temp folders | |
| base_tmp_path = os.path.join(os.getcwd(), "tmp_dir") # Change this to any path you prefer | |
| # Ensure that the base temp folder exists | |
| if not os.path.exists(base_tmp_path): | |
| os.makedirs(base_tmp_path) | |
| print(f"Base temporary folder '{base_tmp_path}' created.") | |
| # Define the path for the specific temporary folder | |
| folder_path = os.path.join(base_tmp_path, folder_name) | |
| # Create the specific temporary folder if it doesn't exist | |
| os.makedirs(folder_path, exist_ok=True) | |
| print(f"Temporary folder '{folder_name}' is ready at {folder_path}.") | |
| return folder_path | |
| from moviepy.editor import * | |
| import os | |
| import tempfile | |
| from moviepy.editor import AudioFileClip, ImageClip, concatenate_videoclips | |
| def generate_video(audio_file, images, segments): | |
| try: | |
| # Save the uploaded audio file to a temporary location | |
| file_extension = os.path.splitext(audio_file.name)[1] | |
| temp_audio_path = tempfile.NamedTemporaryFile(delete=False, suffix=f"{file_extension}") | |
| temp_audio_path.write(audio_file.read()) | |
| temp_audio_path.close() | |
| # Load the audio file using MoviePy | |
| audio = AudioFileClip(temp_audio_path.name) | |
| # Define YouTube-like dimensions (16:9 aspect ratio) | |
| frame_width = 1280 | |
| frame_height = 720 | |
| video_clips = [] | |
| total_segments = len(segments) | |
| for i, current_segment in enumerate(segments): | |
| start_time = current_segment["start"] | |
| end_time = current_segment["end"] | |
| # Calculate the actual duration including any gap until the next segment | |
| if i < total_segments - 1: | |
| # If there's a next segment, extend until it starts | |
| next_segment = segments[i + 1] | |
| actual_end_time = next_segment["start"] | |
| else: | |
| # For the last segment, use its end time | |
| actual_end_time = end_time | |
| # Calculate total duration including any gap | |
| segment_duration = actual_end_time - start_time | |
| print(f"\nProcessing segment {i + 1}/{total_segments}:") | |
| print(f" Start time: {start_time}s") | |
| print(f" Base end time: {end_time}s") | |
| print(f" Actual end time: {actual_end_time}s") | |
| print(f" Total duration: {segment_duration}s") | |
| print(f" Text: '{current_segment['text']}'") | |
| # Ensure the image index is within bounds | |
| image_path = images[min(i, len(images) - 1)] | |
| # Create an ImageClip for the current segment | |
| image_clip = ImageClip(image_path) | |
| # Resize and pad the image to fit a 16:9 aspect ratio | |
| image_clip = image_clip.resize(height=frame_height).on_color( | |
| size=(frame_width, frame_height), | |
| color=(0, 0, 0), # Black background | |
| pos="center" # Center the image | |
| ) | |
| # Set the duration and start time for the clip | |
| image_clip = image_clip.set_duration(segment_duration) | |
| image_clip = image_clip.set_start(start_time) # Set the start time explicitly | |
| video_clips.append(image_clip) | |
| # Concatenate all the image clips to form the video | |
| print("Concatenating video clips...") | |
| video = concatenate_videoclips(video_clips, method="compose") | |
| # Add the audio to the video | |
| video = video.set_audio(audio) | |
| # Save the video to a temporary file | |
| temp_dir = tempfile.gettempdir() | |
| video_path = os.path.join(temp_dir, "generated_video.mp4") | |
| print(f"Writing video file to {video_path}...") | |
| video.write_videofile(video_path, fps=30, codec="libx264", audio_codec="aac") | |
| # Clean up the temporary audio file | |
| os.remove(temp_audio_path.name) | |
| print("Temporary audio file removed.") | |
| return video_path | |
| except Exception as e: | |
| print(f"Error generating video: {e}") | |
| return None | |
| # Example usage: | |
| if __name__ == "__main__": | |
| result = generate_images(["a guy in jungle", "a waterfall","greenery"]) |