Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,93 +1,94 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
import google.generativeai as genai
|
| 3 |
import os
|
| 4 |
-
|
|
|
|
| 5 |
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
-
#
|
| 8 |
custom_css = """
|
| 9 |
-
|
| 10 |
-
.
|
| 11 |
-
.
|
| 12 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
"""
|
| 14 |
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
# 自动从您设置的环境变量中读取 Key
|
| 18 |
-
api_key = os.getenv("MY_API_KEY")
|
| 19 |
-
genai.configure(api_key=api_key)
|
| 20 |
-
|
| 21 |
-
def analyze_lighting(image):
|
| 22 |
-
if image is None:
|
| 23 |
-
return "请先上传一张场景截图。"
|
| 24 |
-
if not api_key:
|
| 25 |
-
return "未检测到 GOOGLE_API_KEY,请在 Settings 中配置。"
|
| 26 |
-
|
| 27 |
try:
|
| 28 |
-
#
|
| 29 |
-
|
| 30 |
-
|
| 31 |
|
| 32 |
-
# 编写针对灯光艺术师的专业 Prompt
|
| 33 |
-
prompt = """
|
| 34 |
-
作为 UE5 灯光总监,分析截图。请严格按照以下格式输出分析结果:
|
| 35 |
-
[SCORE] 0-100的数字
|
| 36 |
-
[COLORS] 识别出的主色调(用逗号隔开)
|
| 37 |
-
[ANALYSIS] 氛围与明暗的深度分析
|
| 38 |
-
[TECH] 技术建议(体积雾、GI等)
|
| 39 |
-
[IMPROVE] 具体的 3 条优化建议(每条建议用“|”分隔)
|
| 40 |
-
"""
|
| 41 |
-
|
| 42 |
-
# 发送图片和文字
|
| 43 |
-
response = model.generate_content([prompt, image])
|
| 44 |
-
return response.text
|
| 45 |
-
|
| 46 |
-
except Exception as e:
|
| 47 |
-
return f"Gemini 分析出错: {str(e)}"
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
def format_output(ai_text):
|
| 51 |
-
# 简单的文本切割逻辑(可以根据实际 Prompt 调整)
|
| 52 |
-
try:
|
| 53 |
-
# 这里仅为逻辑演示,实际可以使用正则表达式提取
|
| 54 |
-
score = "85" # 假设提取出的分数
|
| 55 |
html = f"""
|
| 56 |
-
<div class="report-
|
| 57 |
-
<div class="
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
</div>
|
| 63 |
"""
|
| 64 |
return html
|
| 65 |
except:
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
# 构建 Gradio 界面
|
| 71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
with gr.Row():
|
| 77 |
-
with gr.Column(scale=
|
| 78 |
-
|
| 79 |
-
|
|
|
|
| 80 |
|
| 81 |
-
with gr.Column(scale=
|
| 82 |
-
|
| 83 |
-
|
| 84 |
|
| 85 |
-
|
| 86 |
-
def run_analysis(img):
|
| 87 |
-
raw_res = analyze_lighting(img) # 调用你之前的 Gemini 函数
|
| 88 |
-
# 这里的 format_to_pro_ui 是一个将纯文本转为漂亮 HTML 的函数
|
| 89 |
-
return format_to_pro_ui(raw_res)
|
| 90 |
-
|
| 91 |
-
btn.click(run_analysis, inputs=[input_img], outputs=[output_panel])
|
| 92 |
|
| 93 |
demo.launch()
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import google.generativeai as genai
|
| 3 |
import os
|
| 4 |
+
import json
|
| 5 |
+
import re
|
| 6 |
|
| 7 |
+
# 配置 API
|
| 8 |
+
api_key = os.getenv("GOOGLE_API_KEY")
|
| 9 |
+
genai.configure(api_key=api_key)
|
| 10 |
|
| 11 |
+
# --- 定义 CSS 样式 ---
|
| 12 |
custom_css = """
|
| 13 |
+
body { background-color: #0b0f14; }
|
| 14 |
+
.report-container { background: #111827; border: 1px solid #1f2937; border-radius: 12px; padding: 20px; color: #e5e7eb; font-family: 'Inter', sans-serif; }
|
| 15 |
+
.header-row { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #374151; padding-bottom: 15px; margin-bottom: 20px; }
|
| 16 |
+
.score-circle { background: radial-gradient(circle, #3b82f6, #1d4ed8); width: 60px; height: 60px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: bold; color: white; box-shadow: 0 0 15px rgba(59, 130, 246, 0.5); }
|
| 17 |
+
.section-title { color: #60a5fa; font-size: 16px; font-weight: bold; margin: 15px 0 10px 0; display: flex; align-items: center; gap: 8px; }
|
| 18 |
+
.card { background: #1f2937; border-radius: 8px; padding: 12px; margin-bottom: 10px; border-left: 4px solid #3b82f6; }
|
| 19 |
+
.tag-container { display: flex; gap: 8px; margin-top: 10px; }
|
| 20 |
+
.tag { background: #374151; padding: 4px 10px; border-radius: 4px; font-size: 12px; color: #9ca3af; border: 1px solid #4b5563; }
|
| 21 |
+
.suggestion { background: #064e3b; border-left: 4px solid #10b981; padding: 10px; border-radius: 6px; margin-top: 8px; font-size: 14px; }
|
| 22 |
"""
|
| 23 |
|
| 24 |
+
def parse_and_format(ai_response):
|
| 25 |
+
"""提取 JSON 并渲染 HTML"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
try:
|
| 27 |
+
# 尝试从回复中找到 JSON 部分
|
| 28 |
+
json_str = re.search(r'\{.*\}', ai_response, re.DOTALL).group()
|
| 29 |
+
data = json.loads(json_str)
|
| 30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
html = f"""
|
| 32 |
+
<div class="report-container">
|
| 33 |
+
<div class="header-row">
|
| 34 |
+
<div>
|
| 35 |
+
<h2 style="margin:0; color:white;">灯光分析报告</h2>
|
| 36 |
+
<div class="tag-container">
|
| 37 |
+
<span class="tag">UE5.4</span><span class="tag">Lumen</span><span class="tag">Cinema_Light</span>
|
| 38 |
+
</div>
|
| 39 |
+
</div>
|
| 40 |
+
<div class="score-circle">{data.get('score', '??')}</div>
|
| 41 |
+
</div>
|
| 42 |
+
|
| 43 |
+
<div class="section-title">🎨 色彩与氛围</div>
|
| 44 |
+
<div class="card">{data.get('atmosphere', '')}</div>
|
| 45 |
+
|
| 46 |
+
<div class="section-title">⚙️ 技术优化分析</div>
|
| 47 |
+
<div class="card" style="border-left-color: #f59e0b;">
|
| 48 |
+
<p style="margin:0; font-size:14px;">{data.get('technical', '')}</p>
|
| 49 |
+
</div>
|
| 50 |
+
|
| 51 |
+
<div class="section-title">🚀 灯光优化建议</div>
|
| 52 |
+
{" ".join([f'<div class="suggestion">💡 {s}</div>' for s in data.get('suggestions', [])])}
|
| 53 |
</div>
|
| 54 |
"""
|
| 55 |
return html
|
| 56 |
except:
|
| 57 |
+
# 如果解析 JSON 失败,回退到 Markdown 显示
|
| 58 |
+
return f"<div class='report-container'>{ai_response}</div>"
|
|
|
|
|
|
|
|
|
|
| 59 |
|
| 60 |
+
def analyze_lighting(image):
|
| 61 |
+
if image is None: return "请上传图片"
|
| 62 |
+
try:
|
| 63 |
+
model = genai.GenerativeModel('gemini-3-flash-preview')
|
| 64 |
+
# 强制 AI 输出 JSON 格式
|
| 65 |
+
prompt = """
|
| 66 |
+
你是一位顶级游戏灯光艺术总监。请分析这张 UE5 截图,并严格按以下 JSON 格式输出(不要有其他废话):
|
| 67 |
+
{
|
| 68 |
+
"score": "评分数字",
|
| 69 |
+
"atmosphere": "分析色温对比、氛围感",
|
| 70 |
+
"technical": "分析曝光、死黑、体积雾、GI表现",
|
| 71 |
+
"suggestions": ["建议1", "建议2", "建议3"]
|
| 72 |
+
}
|
| 73 |
+
请用专业中文。
|
| 74 |
+
"""
|
| 75 |
+
response = model.generate_content([prompt, image])
|
| 76 |
+
return parse_and_format(response.text)
|
| 77 |
+
except Exception as e:
|
| 78 |
+
return f"<div style='color:red;'>错误: {str(e)}</div>"
|
| 79 |
|
| 80 |
+
# --- 构建 UI ---
|
| 81 |
+
with gr.Blocks(css=custom_css) as demo:
|
|
|
|
| 82 |
with gr.Row():
|
| 83 |
+
with gr.Column(scale=1):
|
| 84 |
+
gr.Markdown("### 📷 场景画面上传")
|
| 85 |
+
input_img = gr.Image(label=None, type="pil")
|
| 86 |
+
btn = gr.Button("生成专业灯光分析报告", variant="primary")
|
| 87 |
|
| 88 |
+
with gr.Column(scale=1):
|
| 89 |
+
gr.Markdown("### 📊 分析结果预览")
|
| 90 |
+
output_html = gr.HTML("<div style='color:#666;'>等待分析数据...</div>")
|
| 91 |
|
| 92 |
+
btn.click(analyze_lighting, inputs=[input_img], outputs=[output_html])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
|
| 94 |
demo.launch()
|