Download app.py from goedev/rayt-web: direct link, hf CLI and curl.
- Browser
- Download file 5.28 kB
-
https://huggingface.co/spaces/goedev/rayt-web/resolve/main/app.py
- Command line
-
hf download hf://spaces/goedev/rayt-web/app.py
-
curl -L -o app.py https://huggingface.co/spaces/goedev/rayt-web/resolve/main/app.py
5.28 kB
| import gradio as gr | |
| import io | |
| import sys | |
| import pandas as pd | |
| from PIL import Image | |
| from rayt_rust._core import Camera, Point3, Vec3 | |
| from rayt.gpu_utils import is_cuda_available | |
| from rayt.scene import random_scene | |
| from rayt.cuda_renderer import render_with_cuda | |
| from rayt.numba_renderer import render_with_numba | |
| from rayt.rust_renderer import render_with_rust | |
| from numba import cuda | |
| IS_CUDA_AVAILABE, _ = is_cuda_available() | |
| def render_image(image_width, samples_per_pixel, aspect_ratio_str, max_depth, engine): | |
| """ | |
| Renders an image using the rayt library and returns it. | |
| """ | |
| # --- Capture stdout --- | |
| old_stdout = sys.stdout | |
| sys.stdout = captured_output = io.StringIO() | |
| # --- Run the rendering logic --- | |
| aspect_ratio = eval(aspect_ratio_str) | |
| image_height = int(image_width / aspect_ratio) | |
| world = random_scene() | |
| camera = Camera( | |
| lookfrom=Point3(13, 2, 3), | |
| lookat=Point3(0, 0, 0), | |
| vup=Vec3(0, 1, 0), | |
| vfov=20.0, | |
| aspect_ratio=aspect_ratio, | |
| aperture=0.1, | |
| focus_dist=10.0, | |
| ) | |
| render_funcs = { | |
| "rust": render_with_rust, | |
| "numba": render_with_numba, | |
| "cuda": render_with_cuda, | |
| } | |
| if engine == "cuda" and not IS_CUDA_AVAILABE: | |
| gr.Warning( | |
| "CUDA renderer is not available in this server. Falling back to numba." | |
| ) | |
| engine = "numba" | |
| render_func = render_funcs[engine] | |
| render_func(world, camera, image_width, image_height, samples_per_pixel, max_depth) | |
| # --- Restore stdout and get the PPM data --- | |
| sys.stdout = old_stdout | |
| ppm_data = captured_output.getvalue() | |
| # --- Convert PPM to Image --- | |
| # The PPM data is in a string, so we need to wrap it in a file-like object | |
| ppm_file = io.BytesIO(ppm_data.encode()) | |
| image = Image.open(ppm_file) | |
| return image | |
| # --- Create the Gradio Interface --- | |
| with gr.Blocks() as iface: | |
| gr.Markdown("# Ray Tracing in One Weekend") | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown( | |
| "A Python implementation of the book by Peter Shirley, rendered with Numba." | |
| ) | |
| if IS_CUDA_AVAILABE: | |
| device = cuda.get_current_device() | |
| cc = device.compute_capability | |
| cuda_info_dataframe = pd.DataFrame( | |
| { | |
| "CUDA support": ["AVAILABLE"], | |
| "Found GPU": [device.name.decode("utf-8")], | |
| "Compute Capability": [f"{cc[0]}.{cc[1]}"], | |
| } | |
| ) | |
| else: | |
| cuda_info_dataframe = pd.DataFrame( | |
| { | |
| "CUDA support": ["NOT AVAILABLE"], | |
| "Found GPU": ["-"], | |
| "Compute Capability": ["-"], | |
| } | |
| ) | |
| gr.DataFrame(cuda_info_dataframe) | |
| gr.Markdown( | |
| "If you have an NVIDIA GPU on your local machine, you can clone the project and " | |
| "run it locally. You can also deploy it to a server with CUDA support for faster " | |
| "rendering." | |
| ) | |
| gr.Image( | |
| label="Sample Output", | |
| value="image.webp", | |
| show_download_button=False, | |
| show_fullscreen_button=False, | |
| show_label=True, | |
| ) | |
| with gr.Column(): | |
| gr.Markdown("## PERFORMANCE") | |
| gr.Markdown("RAYT tested on this machine:") | |
| test_info_dataframe = pd.DataFrame( | |
| { | |
| "CPU": ["AMD Radeon 9 9900X"], | |
| "GPU": ["NVIDIA RTX 5080"], | |
| "Image Width": ["600"], | |
| "Samples Per Pixel": ["100"], | |
| } | |
| ) | |
| gr.DataFrame(test_info_dataframe) | |
| gr.Image( | |
| label="Performance", | |
| value="performance.png", | |
| show_download_button=False, | |
| show_fullscreen_button=False, | |
| show_label=True, | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("## INPUT") | |
| image_width = gr.Slider( | |
| label="Image Width", minimum=100, maximum=1200, value=300, step=10 | |
| ) | |
| samples_per_pixel = gr.Slider( | |
| label="Samples Per Pixel", minimum=1, maximum=200, value=20, step=1 | |
| ) | |
| max_depth = gr.Slider( | |
| label="Max Ray Depth", minimum=1, maximum=100, value=50, step=1 | |
| ) | |
| aspect_ratio = gr.Dropdown( | |
| label="Aspect Ratio", choices=["16/9", "3/2", "1/1"], value="16/9" | |
| ) | |
| engine = gr.Dropdown( | |
| label="Engine", choices=["rust", "numba", "cuda"], value="rust" | |
| ) | |
| render_button = gr.Button("Render Image") | |
| with gr.Column(): | |
| gr.Markdown("## OUTPUT") | |
| output_image = gr.Image(label="Rendered Image", type="pil") | |
| render_button.click( | |
| fn=render_image, | |
| inputs=[image_width, samples_per_pixel, aspect_ratio, max_depth, engine], | |
| outputs=output_image, | |
| ) | |
| if __name__ == "__main__": | |
| iface.launch() | |