from PIL import Image
from io import BytesIO
import base64
import os
import re
from groq import Groq
import gradio as gr
# Read key from Hugging Face secrets or default fallback
api_key = os.getenv("GROQ_API_KEY", "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")
client = Groq(api_key=api_key)
def encode_image(image_input):
"""Encode image (path, dict, or base64 data URI) to base64 string."""
try:
# If Gradio passes a FileData dictionary
if isinstance(image_input, dict):
image_input = image_input.get("path", "")
# If already a base64 Data URI string
if isinstance(image_input, str) and image_input.startswith("data:image"):
return image_input.split(",")[1]
# Otherwise treat as a local file path and open via PIL
image = Image.open(image_input).convert("RGB")
base_height = 512
h_percent = (base_height / float(image.size[1]))
w_size = int((float(image.size[0]) * float(h_percent)))
image = image.resize((w_size, base_height), Image.LANCZOS)
buffered = BytesIO()
image.save(buffered, format="JPEG")
return base64.b64encode(buffered.getvalue()).decode("utf-8")
except Exception as e:
print(f"Error encoding image: {e}")
return None
def feifeichat(image):
try:
if image is None:
return "Please upload a photo"
base64_image = encode_image(image)
if not base64_image:
return "Error processing image"
messages = [
{
"role": "user",
"content": [
{
"type": "text",
"text": "Analyze the image and return strictly valid JSON format with keys 'title', 'description', 'meta_title' (max 60 chars), 'meta_description' (max 155 chars), 'tags' (array of 5-8 strings), 'style_breakdown' (object with keys: aesthetic, top, bottom, legwear, accessories), and 'faqs' (array of two objects with 'q' and 'a'). Follow these strict copywriting guidelines: 1. Description must be an elegant, descriptive paragraph (3-4 sentences) written like an alternative fashion lookbook. 2. Focus on physical aesthetics: mention terms like 'slender body', 'petite frame', 'youthful appeal', 'cute vibe', and 'sexy style' naturally. 3. Avoid literal camera actions: DO NOT say 'taking a selfie', 'mirror picture', or 'holding a phone'. Describe the pose as casual, relaxed, or playful. 4. Tags must be individual aesthetic search terms (e.g., ['egirl-aesthetic', 'thigh-highs', 'white-tights', 'alternative-fashion'])."
},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
}
}
]
}
]
response = client.chat.completions.create(
model="qwen/qwen3.6-27b",
messages=messages,
response_format={"type": "json_object"},
temperature=0.7,
stream=False
)
raw_content = response.choices[0].message.content or ""
# Strip Qwen reasoning/thinking blocks (...)
cleaned = re.sub(r'.*?', '', raw_content, flags=re.DOTALL).strip()
# Strip markdown fences if present
cleaned = re.sub(r'^```(?:json)?\s*', '', cleaned)
cleaned = re.sub(r'\s*```$', '', cleaned)
return cleaned.strip()
except Exception as e:
print(f"Error: {e}")
return f"An error occurred while processing your request: {e}"
with gr.Blocks() as demo:
gr.Markdown("Image To Flux Prompt")
with gr.Tab(label="Image To Flux Prompt"):
input_img = gr.Image(label="Input Picture", height=320, type="filepath")
output_text = gr.Textbox(label="Flux Prompt")
submit_btn = gr.Button(value="Submit")
submit_btn.click(
fn=feifeichat,
inputs=input_img,
outputs=output_text,
api_name="feifeichat"
)
# Disabling SSR mode resolves SvelteKit 405 Method Not Allowed errors on Gradio 5
demo.launch(ssr_mode=False)