Spaces:
Running
Running
File size: 9,301 Bytes
3e718c3 | 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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | # === FILE: app.py (النسخة النهائية والكاملة مع LangChain) ===
import os
from typing import Optional
import gradio as gr
from pydantic import BaseModel
from gradio_client import Client, utils as client_utils
# --- استيرادات LangChain ---
from langchain_groq import ChatGroq
from langchain_core.messages import HumanMessage
# تم حذف OutputParserException لأنه غير مستخدم هنا مباشرة
# ----------------------------
# ==================================================
# 1. الإعدادات العامة والمتغيرات
# ==================================================
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
GROQ_MODEL = os.getenv("GROQ_MODEL", "llama-3.3-70b-versatile")
if not GROQ_API_KEY:
print("Warning: GROQ_API_KEY not set. The app will run in mock mode.")
# ==================================================
# 2. وظائف LLM المساعدة (Prompting, Parsing)
# *هذه هي الدوال التي كانت مفقودة وتسببت في NameError*
# ==================================================
def build_system_instruction() -> str:
return (
"""You are an elite visual prompt architect for symbolic image generation.
Your task is to transform wisdom texts into high-quality Stable Diffusion prompts
using structured semantic analysis and domain-aware visual styling.
INTERNAL ANALYSIS (do not explain):
1) Identify the WISDOM DOMAIN (e.g. knowledge, journey, ethics, patience, loss, hope).
2) Determine the EMOTIONAL TONE (e.g. hopeful, contemplative, melancholic, serene).
3) Select a VISUAL STYLE that naturally fits the domain:
- Knowledge → warm interior light, painterly realism, books, study atmosphere
- Journey → cinematic landscapes, depth, leading paths, wide composition
- Ethics → chiaroscuro lighting, classical balance, moral tension
- Patience/Time → minimalism, long shadows, dusk or twilight
- Loss/Impermanence → desaturated colors, fog, empty space
- Hope/Resilience → golden hour, light rays, upward composition
- Self-awareness → reflections, mirrors, symmetry
- Spirituality → soft surrealism, ethereal light
4) Design symbolic structure:
- One clear main symbol
- 2–3 hidden or subtle symbols embedded naturally
(shadows, reflections, background shapes, light patterns)
5) Prefer metaphorical and symbolic depiction over literal illustration.
6) Don't use women or girls in your prompts
Output strictly in this format:
SD_PROMPT:
- DOMAIN,EMOTION,SYMBOLS,STYLE
- one single-line Stable Diffusion prompt""" )
#- Be a single coherent sentence.
#- Include hidden symbolism without explicitly explaining it.
def assemble_llm_prompt(quote: str, author: str | None, culture: str | None) -> str:
"""تجميع موجه النص الكامل لنموذج LLM."""
meta = []
if author: meta.append(f"author: {author}")
if culture: meta.append(f"culture: {culture}")
meta_text = "; ".join(meta) if meta else ""
user_block = (
f"Wisdom: \"{quote}\"\n{meta_text}\n\n"
"Produce output in this exact format:\n"
"SYMBOLS:\n- comma-separated symbolic phrases\n"
"STYLE:\n- short style description (e.g., cinematic, watercolor, oil painting, high-contrast)\n"
"SD_PROMPT:\n- a single complete Stable Diffusion prompt (one line)\n"
"Do not include any additional commentary."
)
return build_system_instruction() + "\n\n" + user_block
def parse_llm_output(text: str) -> dict:
"""محلل بسيط لاستخراج كتل SYMBOLS و STYLE و SD_PROMPT."""
result = {"symbols": "", "style": "", "sd_prompt": ""}
lines = text.splitlines()
current = None
buf = []
for ln in lines:
ln_strip = ln.strip()
if not ln_strip: continue
if ln_strip.upper().startswith("SYMBOLS:"):
if current: result[current] = "\n".join(buf).strip()
current = "symbols"; buf = []; continue
if ln_strip.upper().startswith("STYLE:"):
if current: result[current] = "\n".join(buf).strip()
current = "style"; buf = []; continue
if ln_strip.upper().startswith("SD_PROMPT:"):
if current: result[current] = "\n".join(buf).strip()
current = "sd_prompt"; buf = []; continue
buf.append(ln_strip)
if current: result[current] = "\n".join(buf).strip()
result["sd_prompt"] = result["sd_prompt"].strip(' \"')
return result
# ==================================================
# 3. دالة Groq الجديدة باستخدام LangChain
# ==================================================
def call_groq_completion(prompt: str) -> str:
"""استدعاء نقطة النهاية Groq Completion API باستخدام LangChain."""
if not GROQ_API_KEY:
# استجابة وهمية (Mock) في حالة عدم وجود مفتاح
return (
"SYMBOLS:\n- aged tree, lantern, winding path\n"
"STYLE:\n- warm cinematic backlight, painterly brushwork\n"
"SD_PROMPT:\n- \"An ancient tree by a winding path, warm lantern light,"
" cinematic composition, golden hour, dramatic rim lighting,"
" detailed textures, 35mm lens, high-detail, organic colors\""
)
try:
llm = ChatGroq(
temperature=0.7,
model_name=GROQ_MODEL,
groq_api_key=GROQ_API_KEY,
)
messages = [
HumanMessage(content=prompt)
]
response = llm.invoke(messages)
if response.content:
return response.content
else:
# يمكن أن يحدث هذا إذا كان هناك خطأ داخلي في Groq أو إذا لم ينتج محتوى
raise ValueError("Groq returned an empty response content.")
except Exception as e:
raise ValueError(f"LLM Groq/LangChain Error: {type(e).__name__} - {str(e)}")
# ==================================================
# 4. دالة Gradio الأساسية (Endpoint)
# ==================================================
def generate_prompt(quote, author, culture, callback_url):
"""
الدالة الخلفية الرئيسية لـ Gradio.
"""
if not quote:
return "", "", "", "No quote provided."
# 1. تجميع الـ Prompt واستدعاء LLM
# الآن assemble_llm_prompt معرفة في الأعلى، ولن يحدث NameError
assembled = assemble_llm_prompt(quote, author or None, culture or None)
try:
llm_text = call_groq_completion(assembled)
except ValueError as e:
return "", "", "", f"LLM Generation Failed: {e}"
parsed = parse_llm_output(llm_text)
# 2. تجهيز النتيجة
sd_prompt = parsed.get("sd_prompt")
symbols = parsed.get("symbols")
style = parsed.get("style")
result = {
"sd_prompt": sd_prompt,
"symbols": symbols,
"style": style,
"raw": llm_text
}
# 3. معالجة Callback (باستخدام Gradio Client)
callback_status = "no-callback"
if callback_url and client_utils.is_valid_url(callback_url):
try:
client = Client(callback_url)
client.predict(
result,
api_name="/receive"
)
callback_status = "sent-via-gradio-client"
except ImportError:
callback_status = "failed: gradio_client not installed."
except Exception as e:
callback_status = f"failed-gradio-cb: {e}"
return sd_prompt, symbols, style, callback_status
# ==================================================
# 5. واجهة Gradio UI
# ==================================================
with gr.Blocks(title="Prompt Agent – Pure Gradio") as demo:
gr.Markdown("# **Wisdom → SD Prompt Generator (Groq Llama3.1-70B)**")
gr.Markdown("هذه الواجهة تستخدم LangChain للاتصال الموثوق بـ Groq.")
with gr.Row():
with gr.Column(scale=2):
quote_in = gr.Textbox(label="Wisdom / Proverb", lines=3, placeholder="Enter the wisdom text here...")
author_in = gr.Textbox(label="Author (optional)")
culture_in = gr.Textbox(label="Culture / Region (optional)")
callback_url_in = gr.Textbox(label="Callback URL (Other HF Space API path, e.g. https://user/space/api/receive)")
gen_btn = gr.Button("Generate Prompt 🚀", variant="primary")
with gr.Column(scale=3):
sd_out = gr.Textbox(label="Stable Diffusion Prompt", lines=4)
symbols_out = gr.Textbox(label="Suggested Symbols", lines=3)
style_out = gr.Textbox(label="Style / Lighting / Composition", lines=3)
cb_out = gr.Textbox(label="Callback Status")
gen_btn.click(
fn=generate_prompt,
inputs=[quote_in, author_in, culture_in, callback_url_in],
outputs=[sd_out, symbols_out, style_out, cb_out],
api_name="generate"
)
# ==================================================
# 6. نقطة الدخول الرئيسية
# ==================================================
if __name__ == '__main__':
demo.launch()
|