-
Notifications
You must be signed in to change notification settings - Fork 178
Add gradio local inference demo #740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary of Changes
Hello @JiayiZhangA, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request introduces new Gradio-based local inference demonstrations for the FastVideo project, enabling users to generate videos directly from text prompts with customizable parameters. It also includes a structural reorganization, moving existing Gradio serving-related files into a dedicated "serving" subdirectory.
Highlights
- New Gradio Local Inference Demos: Implemented new Gradio local inference demos for FastVideo, providing an interactive interface for video generation.
- Advanced Gradio Demo Features: Introduced a comprehensive Gradio demo (gradio_local_demo.py) featuring model selection, detailed timing breakdowns for inference stages, and pre-defined example prompts.
- Configurable Video Generation Parameters: Enabled configuration of various video generation parameters directly from the Gradio interface, including prompt, negative prompt, random seed, guidance scale, number of frames, and output dimensions.
- Project Structure Refactoring: Refactored the project's Gradio-related serving components by moving gradio_frontend.py, ray_serve_backend.py, start.sh, and start_ray_serve_app.py into a new examples/inference/gradio/serving directory.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command>
or @gemini-code-assist <command>
. Below is a summary of the supported commands.
Feature | Command | Description |
---|---|---|
Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/
folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request adds a local Gradio inference demo. I've reviewed the new demo scripts and found a few issues. The most critical one is in gradio_local_demo.py
where the generated video is not saved, which would prevent it from being displayed in the UI. Both demo scripts also have a high-severity issue where they use raw user prompts for filenames, which is unsafe. I've also included some medium-severity suggestions to improve code robustness and clarity, such as avoiding hardcoded values and simplifying function calls. The file renames and the new SVG logo look fine.
safe_prompt = params.prompt[:100].replace(' ', '_').replace('/', '_').replace('\\', '_') | ||
video_filename = f"{params.prompt[:100]}.mp4" | ||
output_path = os.path.join(output_dir, video_filename) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The generated video is not being saved to a file, so the Gradio UI will be unable to display it. The generate_video
function is called with save_video=False
, and the returned frames are not handled. You should extract the frames from the result
object and save them to a video file using a library like imageio
.
Additionally, the safe_prompt
variable is correctly created to sanitize the prompt for use as a filename, but it's not used. The unsanitized prompt is used instead, which can lead to errors or security vulnerabilities if it contains special characters like /
.
safe_prompt = params.prompt[:100].replace(' ', '_').replace('/', '_').replace('\\', '_') | |
video_filename = f"{params.prompt[:100]}.mp4" | |
output_path = os.path.join(output_dir, video_filename) | |
safe_prompt = params.prompt[:100].replace(' ', '_').replace('/', '_').replace('\\', '_') | |
video_filename = f"{safe_prompt}.mp4" | |
output_path = os.path.join(output_dir, video_filename) | |
frames = result.get("frames") | |
if frames: | |
import imageio | |
imageio.mimsave(output_path, frames, fps=params.fps, format="mp4") | |
else: | |
raise ValueError("Video generation did not return any frames.") |
output_path = os.path.join(parsed_args.output_path, | ||
f"{params.prompt[:100]}.mp4") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The output video filename is constructed directly from the user's prompt. If the prompt contains special characters, such as /
, it could lead to the video being saved in an unintended directory or cause a file creation error. The prompt should be sanitized before being used as a filename.
output_path = os.path.join(parsed_args.output_path, | |
f"{params.prompt[:100]}.mp4") | |
safe_prompt = "".join(c for c in params.prompt[:100] if c.isalnum() or c in (' ', '_')).rstrip().replace(' ', '_') | |
output_path = os.path.join(parsed_args.output_path, | |
f"{safe_prompt}.mp4") |
else: | ||
params.negative_prompt = default_params.negative_prompt | ||
|
||
generator.generate_video(prompt=prompt, sampling_param=params,output_path=parsed_args.output_path,save_video=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The prompt
, output_path
, and save_video
arguments are passed to generator.generate_video
even though they are also part of the sampling_param
object. This is redundant and can be confusing. It would be cleaner to set all parameters in the params
object and pass only that to the generator.
params.output_path = parsed_args.output_path
params.save_video = True
generator.generate_video(sampling_param=params)
} | ||
|
||
def create_timing_display(inference_time, total_time, stage_execution_times, num_frames): | ||
dit_denoising_time = f"{stage_execution_times[5]:.2f}s" if len(stage_execution_times) > 5 else "N/A" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a hardcoded index 5
to access the denoising time is brittle. If the order or number of stages in the pipeline changes, this will break or report an incorrect value. It would be more robust to find the index of the 'DiT Denoising' stage dynamically, for example by searching for it in the stage_names
list that is available in the generate_video
function.
initial_values = get_default_values("FastWan2.1-T2V-1.3B") | ||
|
||
with gr.Blocks(title="FastWan", theme=theme) as demo: | ||
gr.Image("fastvideo-logos/main/svg/full.svg", show_label=False, container=False, height=80) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The path to the logo SVG fastvideo-logos/main/svg/full.svg
seems incorrect. A new SVG file full.svg
is added in the same directory as this script (examples/inference/gradio/local/
). The path should likely be relative to the current script's location to ensure it's found correctly.
gr.Image("fastvideo-logos/main/svg/full.svg", show_label=False, container=False, height=80) | |
gr.Image("full.svg", show_label=False, container=False, height=80) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename to README.md
sampling_param.output_video_name = original_output_video_name + f"_{i}" | ||
output_path = self._prepare_output_path( | ||
sampling_param.output_path, batch_prompt) | ||
kwargs["output_path"] = output_path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should be able to directly update sample_param.output_path
here instead.
|
||
sampling_param = deepcopy(sampling_param) | ||
output_path = kwargs["output_path"] | ||
kwargs["prompt"] = prompt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, if you are creating a new sampling_param
if it is not provided, we don't need to also update/use kwargs
raise ValueError("Either prompt or prompt_txt must be provided") | ||
output_path = self._prepare_output_path(sampling_param.output_path, | ||
prompt) | ||
kwargs["output_path"] = output_path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
No description provided.