|
|
from typing import Tuple, Optional |
|
|
from PIL import Image, ImageDraw, ImageFont |
|
|
import pandas as pd |
|
|
|
|
|
def _placeholder_image(size: Tuple[int, int], text: str, bg=(230, 230, 230)) -> Image.Image: |
|
|
|
|
|
img = Image.new("RGB", size, color=bg) |
|
|
draw = ImageDraw.Draw(img) |
|
|
try: |
|
|
font = ImageFont.load_default() |
|
|
except Exception: |
|
|
font = None |
|
|
w, h = draw.textbbox((0, 0), text, font=font)[2:] |
|
|
draw.text(((size[0] - w) / 2, (size[1] - h) / 2), text, fill=(80, 80, 80), font=font) |
|
|
return img |
|
|
|
|
|
|
|
|
def load_weather_plot( |
|
|
size: Tuple[int, int] = (1024, 1024), |
|
|
kit_id: Optional[int] = None, |
|
|
df: Optional[pd.DataFrame] = None, |
|
|
) -> Image.Image: |
|
|
"""Load the weather plot image for a given kit. |
|
|
|
|
|
Tries to generate in-memory via weather_data_visualisation(); falls back to |
|
|
a placeholder if unavailable. |
|
|
""" |
|
|
try: |
|
|
|
|
|
from weather_data_visualisation import weather_data_visualisation |
|
|
|
|
|
img = weather_data_visualisation(kit=kit_id, df=df, save_to_disk=False) |
|
|
if isinstance(img, Image.Image): |
|
|
if img.size != size: |
|
|
img = img.resize(size, Image.LANCZOS) |
|
|
return img |
|
|
except Exception as e: |
|
|
print(f"Weather plot generation failed: {e}") |
|
|
|
|
|
return _placeholder_image(size, "Weather plot unavailable") |
|
|
|
|
|
|
|
|
def load_genai_output( |
|
|
size: Tuple[int, int] = (1024, 1024), |
|
|
kit_id: Optional[int] = None, |
|
|
df: Optional[pd.DataFrame] = None, |
|
|
) -> Image.Image: |
|
|
"""Load the GenAI output image for a given kit if available; otherwise a placeholder. |
|
|
|
|
|
Uses the selected kit's weather plot as the guiding input for the GenAI image. |
|
|
""" |
|
|
try: |
|
|
from genai import generate_genai_image |
|
|
|
|
|
|
|
|
base_img = None |
|
|
try: |
|
|
base_img = load_weather_plot(size, kit_id=kit_id, df=df) |
|
|
except Exception: |
|
|
base_img = None |
|
|
|
|
|
img = generate_genai_image(input_image=base_img, save_to_disk=False) |
|
|
if isinstance(img, Image.Image): |
|
|
if img.size != size: |
|
|
img = img.resize(size, Image.LANCZOS) |
|
|
return img |
|
|
except Exception as e: |
|
|
print(f"genai.py not usable yet: {e}") |
|
|
|
|
|
return _placeholder_image(size, "GenAI image pending") |
|
|
|
|
|
|
|
|
def get_both_images( |
|
|
kit_id: Optional[int] = None, |
|
|
df: Optional[pd.DataFrame] = None, |
|
|
size: Tuple[int, int] = (1024, 1024), |
|
|
) -> Tuple[Image.Image, Image.Image]: |
|
|
left = load_weather_plot(size, kit_id=kit_id, df=df) |
|
|
right = load_genai_output(size, kit_id=kit_id, df=df) |
|
|
return left, right |
|
|
|
|
|
|
|
|
def create_app(): |
|
|
"""Creates and returns the Gradio app with two side-by-side images.""" |
|
|
import gradio as gr |
|
|
|
|
|
with gr.Blocks(title="Weather × GenAI") as app: |
|
|
gr.Markdown("# Weather visualization and GenAI output") |
|
|
|
|
|
|
|
|
df_state = gr.State() |
|
|
|
|
|
with gr.Row(): |
|
|
kit_input = gr.Number(label="Kit ID", value=1001, precision=0) |
|
|
with gr.Row(): |
|
|
left_img = gr.Image(label="Weather plot", type="pil") |
|
|
right_img = gr.Image(label="GenAI output", type="pil") |
|
|
status_md = gr.Markdown(visible=True) |
|
|
|
|
|
|
|
|
def _disable_refresh(): |
|
|
|
|
|
return gr.update(interactive=False) |
|
|
|
|
|
def _prepare_data(kit_id): |
|
|
|
|
|
try: |
|
|
from api_call import get_kit_measurements_df |
|
|
|
|
|
kit = 1001 |
|
|
if kit_id is not None: |
|
|
try: |
|
|
kit = int(kit_id) |
|
|
except Exception: |
|
|
kit = 1001 |
|
|
|
|
|
df = get_kit_measurements_df(kit, page_size=60, max_pages=2) |
|
|
if df is None or getattr(df, "empty", True): |
|
|
return ( |
|
|
f"No data found for kit {kit}. Please try another kit.", |
|
|
gr.update(interactive=False), |
|
|
None, |
|
|
) |
|
|
return ( |
|
|
f"Data loaded for kit {kit}: {len(df)} rows.", |
|
|
gr.update(interactive=True), |
|
|
df, |
|
|
) |
|
|
except Exception as e: |
|
|
return (f"Failed to load data: {e}", gr.update(interactive=False), None) |
|
|
|
|
|
|
|
|
refresh_btn = gr.Button("Refresh") |
|
|
refresh_btn.click( |
|
|
fn=get_both_images, |
|
|
inputs=[kit_input, df_state], |
|
|
outputs=[left_img, right_img], |
|
|
) |
|
|
|
|
|
|
|
|
( |
|
|
app.load(fn=_disable_refresh, inputs=None, outputs=refresh_btn) |
|
|
.then( |
|
|
fn=_prepare_data, |
|
|
inputs=[kit_input], |
|
|
outputs=[status_md, refresh_btn, df_state], |
|
|
) |
|
|
.then( |
|
|
fn=get_both_images, |
|
|
inputs=[kit_input, df_state], |
|
|
outputs=[left_img, right_img], |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
( |
|
|
kit_input.change(fn=_disable_refresh, inputs=None, outputs=refresh_btn) |
|
|
.then( |
|
|
fn=_prepare_data, |
|
|
inputs=[kit_input], |
|
|
outputs=[status_md, refresh_btn, df_state], |
|
|
) |
|
|
) |
|
|
|
|
|
return app |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
app = create_app() |
|
|
app.launch() |