File size: 4,999 Bytes
86b6d7e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a744ece
86b6d7e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e2afbb3
86b6d7e
 
 
 
 
e2afbb3
 
 
 
 
86b6d7e
 
 
 
 
 
f154949
 
 
 
 
86b6d7e
f154949
 
86b6d7e
 
f154949
e2afbb3
f154949
 
86b6d7e
 
e2afbb3
 
86b6d7e
 
 
e2afbb3
86b6d7e
 
e2afbb3
 
 
 
 
 
 
 
86b6d7e
 
 
 
e2afbb3
86b6d7e
 
e2afbb3
86b6d7e
 
e2afbb3
86b6d7e
 
 
 
 
 
 
 
 
21b9286
 
 
 
 
 
 
 
86b6d7e
f154949
 
 
86b6d7e
 
e2afbb3
86b6d7e
e2afbb3
86b6d7e
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
"""
Voice-controlled image generator (Gradio) for deployment on Hugging Face Spaces.
"""

import os
import random
from typing import Optional
from contextlib import contextmanager

import torch
from PIL import Image
import gradio as gr
from transformers import pipeline
from diffusers import StableDiffusionPipeline, DPMSolverMultistepScheduler

HF_TOKEN = os.environ.get("HF_TOKEN")
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"

ASR_MODEL = "openai/whisper-small"
SD_MODEL = "runwayml/stable-diffusion-v1-5"

asr = None
pipe = None

def load_asr():
    global asr
    if asr is None:
        device_index = 0 if DEVICE == "cuda" else -1
        asr = pipeline("automatic-speech-recognition", model=ASR_MODEL, device=device_index, chunk_length_s=30)
    return asr

def load_sd():
    global pipe
    if pipe is None:
        pipe = StableDiffusionPipeline.from_pretrained(
            SD_MODEL,
            use_auth_token=HF_TOKEN if HF_TOKEN else None,
            safety_checker=None,
        )
        try:
            pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
        except Exception:
            pass
        pipe = pipe.to(DEVICE)
        try:
            pipe.enable_xformers_memory_efficient_attention()
        except Exception:
            pass
    return pipe

@contextmanager
def nullcontext():
    yield

# Gradio component (return numpy array + sample rate)
mic = gr.Audio(type="numpy", label="Record or upload audio")

def transcribe_audio(audio_input):
    if audio_input is None:
        return ""
    # audio_input = (numpy array, sample_rate)
    audio_array, sample_rate = audio_input
    asr_model = load_asr()
    try:
        result = asr_model({"array": audio_array, "sampling_rate": sample_rate})
        return result.get("text", "").strip() if isinstance(result, dict) else str(result).strip()
    except Exception as e:
        return f"Error: {str(e)}"

def generate_image(prompt: str, negative_prompt: str, steps: int, guidance: float, seed: int):
    if not prompt.strip():
        return None, "Please provide a prompt."
    pipe = load_sd()
    if seed is None or int(seed) < 0:
        seed = random.randint(1, 2**32 - 1)
    gen = torch.Generator(device=DEVICE).manual_seed(int(seed)) if DEVICE == "cuda" else torch.Generator().manual_seed(int(seed))
    autocast_ctx = torch.autocast(device_type="cuda") if DEVICE == "cuda" else nullcontext()
    with autocast_ctx:
        out = pipe(
            prompt=prompt,
            negative_prompt=negative_prompt or None,
            num_inference_steps=int(steps),
            guidance_scale=float(guidance),
            generator=gen,
        )
        image = out.images[0]
    return image, f"Seed: {seed} | Steps: {steps} | Guidance: {guidance}"

# --- Gradio UI ---
with gr.Blocks(title="Voice-controlled Image Generator") as demo:
    gr.Markdown("## 🎙️ Voice-controlled Image Generator\nRecord or upload a voice prompt → transcribe → edit → generate images.")
    with gr.Row():
        with gr.Column(scale=2):
            mic = gr.Audio(type="filepath", label="Record or upload audio")  # ✅ fixed
            transcribe_btn = gr.Button("Transcribe")
            prompt_box = gr.Textbox(label="Prompt (editable)", placeholder="Speak or type your prompt here", lines=3)
            negative = gr.Textbox(label="Negative prompt (optional)", placeholder="Things to avoid", lines=2)
            with gr.Row():
                steps = gr.Slider(minimum=10, maximum=60, value=28, step=1, label="Sampling steps")
                guidance = gr.Slider(minimum=1.0, maximum=25.0, value=7.5, step=0.5, label="Guidance scale (CFG)")
            with gr.Row():
                seed_in = gr.Number(label="Seed (leave -1 for random)", value=-1)
                gen_btn = gr.Button("Generate Image")
            status = gr.Textbox(label="Status / Info", interactive=False)
        with gr.Column(scale=3):
            image_out = gr.Image(label="Generated image", type="pil")
            gallery = gr.gallery = gr.Gallery(
    label="Generated Captions",
    show_label=True,
    elem_id="gallery",
    columns=[1],  # replaces grid=[1]
    height="auto"
)


    def on_transcribe(audio_data):
    transcript = transcribe_audio(audio_data)
    return transcript, "Transcription complete." if transcript else "Couldn't transcribe."

    def on_generate(prompt_text, negative_prompt, steps_val, guidance_val, seed_val):
        seed_int = int(seed_val) if seed_val is not None else -1
        img, info = generate_image(prompt_text, negative_prompt, steps_val, guidance_val, seed_int)
        return img, [img] if img else [], info

    transcribe_btn.click(fn=on_transcribe, inputs=[mic], outputs=[prompt_box, status])
    gen_btn.click(fn=on_generate, inputs=[prompt_box, negative, steps, guidance, seed_in], outputs=[image_out, gallery, status])

if __name__ == "__main__":
    demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))