chenglu commited on
Commit
c83d07f
·
1 Parent(s): 954641a
Files changed (1) hide show
  1. app.py +286 -236
app.py CHANGED
@@ -3,137 +3,120 @@ import sys
3
  import warnings
4
  warnings.filterwarnings("ignore")
5
 
6
- # 基础导入检查
7
  try:
8
  import gradio as gr
9
  from PIL import Image
10
  import torch
11
- print(f"✅ PyTorch 版本: {torch.__version__}")
12
-
13
- # 检查PyTorch版本
14
- torch_version = torch.__version__
15
- major, minor = map(int, torch_version.split('.')[:2])
16
- if major < 2 or (major == 2 and minor < 6):
17
- print(f"⚠️ PyTorch 版本 {torch_version} 可能存在安全问题")
18
-
19
  except ImportError as e:
20
- print(f"❌ 基础库导入失败: {e}")
21
- with gr.Blocks() as error_demo:
22
- gr.HTML("<h2>❌ 基础环境错误</h2>")
23
- error_demo.launch()
24
  sys.exit(1)
25
 
26
- # 尝试导入transformers
27
  try:
28
  from transformers import AutoTokenizer, AutoModel, AutoProcessor, Blip2ForConditionalGeneration
29
- print("✅ Transformers 导入成功")
30
  except ImportError as e:
31
- print(f"❌ Transformers 导入失败: {e}")
32
- with gr.Blocks() as error_demo:
33
- gr.HTML(f"<h2>❌ Transformers 未安装</h2><p>{str(e)}</p>")
34
- error_demo.launch()
35
- sys.exit(1)
36
 
37
- # HF Spaces 环境检测
38
  IS_SPACES = os.environ.get("SPACE_ID") is not None
39
  device = "cuda" if torch.cuda.is_available() else "cpu"
40
- print(f"环境: {'HF Spaces' if IS_SPACES else 'Local'}, 设备: {device}")
41
 
42
  # 全局变量
43
- tokenizer = None
44
- model = None
45
  processor = None
46
  blip_model = None
 
 
47
 
48
- def load_models():
49
- """加载模型 - 改进版本"""
50
- global tokenizer, model, processor, blip_model
51
 
 
 
 
52
  try:
53
- print("🔄 开始加载模型...")
54
 
55
- # 1. 首先加载图像模型(通常更稳定)
56
- vision_model = "Salesforce/blip2-opt-2.7b"
57
- print(f"📷 加载图像模型: {vision_model}")
58
 
59
- processor = AutoProcessor.from_pretrained(vision_model)
60
  blip_model = Blip2ForConditionalGeneration.from_pretrained(
61
- vision_model,
62
  torch_dtype=torch.float16 if device == "cuda" else torch.float32,
63
  device_map="auto" if device == "cuda" else None,
64
- load_in_8bit=device == "cuda",
65
- trust_remote_code=True
66
  )
67
 
68
  if device == "cpu":
69
  blip_model = blip_model.to("cpu")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
 
71
- print("✅ 图像模型加载完成")
 
72
 
73
- # 2. 加载对话模型 - 使用更兼容的配置
74
  model_name = "THUDM/chatglm2-6b-int4"
75
- print(f"💬 加载对话模型: {model_name}")
 
 
 
 
76
 
77
- try:
78
- tokenizer = AutoTokenizer.from_pretrained(
79
- model_name,
80
- trust_remote_code=True,
81
- use_fast=False # 使用慢速tokenizer可能更稳定
82
- )
83
-
84
- model = AutoModel.from_pretrained(
85
- model_name,
86
- trust_remote_code=True,
87
- torch_dtype=torch.float16 if device == "cuda" else torch.float32,
88
- low_cpu_mem_usage=True,
89
- device_map="auto" if device == "cuda" else None
90
- )
91
-
92
- if device == "cuda":
93
- model = model.half().cuda()
94
- model.eval()
95
-
96
- print("✅ 对话模型加载完成")
97
- return True
98
-
99
- except Exception as chat_error:
100
- print(f"⚠️ ChatGLM加载失败: {str(chat_error)}")
101
- print("🔄 尝试使用备用对话模型...")
102
-
103
- # 备用方案:使用更简单的对话模型
104
- try:
105
- backup_model = "microsoft/DialoGPT-medium"
106
- tokenizer = AutoTokenizer.from_pretrained(backup_model)
107
- model = AutoModel.from_pretrained(backup_model)
108
-
109
- if device == "cuda":
110
- model = model.cuda()
111
- model.eval()
112
-
113
- print("✅ 备用对话模型加载完成")
114
- return True
115
-
116
- except Exception as backup_error:
117
- print(f"❌ 备用模型也加载失败: {str(backup_error)}")
118
- # 至少图像模型可用
119
- return "partial"
120
 
121
  except Exception as e:
122
- print(f"❌ 模型加载完全失败: {str(e)}")
123
  return False
124
 
125
- def describe_image(image):
126
- """图像描述功能"""
127
- if blip_model is None or processor is None:
128
- return "图像模型未加载"
129
-
130
  try:
 
131
  if not isinstance(image, Image.Image):
132
  image = Image.fromarray(image)
 
 
 
 
 
133
 
134
- # 调整图像大小
135
- if image.size[0] > 512 or image.size[1] > 512:
136
- image.thumbnail((512, 512), Image.Resampling.LANCZOS)
137
 
138
  inputs = processor(image, return_tensors="pt")
139
 
@@ -143,138 +126,169 @@ def describe_image(image):
143
  with torch.no_grad():
144
  generated_ids = blip_model.generate(
145
  **inputs,
146
- max_new_tokens=50,
147
- num_beams=3,
148
- do_sample=True,
149
- temperature=0.7
 
 
150
  )
151
 
152
  caption = processor.batch_decode(generated_ids, skip_special_tokens=True)[0].strip()
 
 
 
 
 
 
 
153
  return caption
154
 
155
  except Exception as e:
156
- print(f"图像描述错误: {str(e)}")
157
- return "图像描述生成失败"
158
-
159
- def generate_analysis(caption):
160
- """生成艺术品分析"""
161
- if model is None or tokenizer is None:
162
- # 如果没有对话模型,使用预设的分析模板
163
- return f"""
164
- 基于图像内容: {caption}
165
-
166
- 这幅艺术作品展现了独特的视觉表现力。从构图角度来看,作品体现了艺术家对空间布局的精心安排。
167
- 色彩运用方面,展现了艺术家的色彩敏感度和表现技巧。
168
- 整体而言,这是一件具有艺术价值的作品,值得进一步欣赏和研究。
169
 
170
- 注:当前使用简化分析模式,如需详细分析请等待对话模型加载完成。
171
- """.strip()
172
-
173
  try:
174
- prompt = f"这是一幅艺术作品,描述为: {caption}。请用中文对这件艺术作品进行详细的介绍和分析。"
 
175
 
176
- # 检查模型类型
177
- if hasattr(model, 'chat'):
178
- # ChatGLM模型
179
- response, _ = model.chat(tokenizer, prompt, history=[])
 
 
 
 
 
180
  else:
181
- # 其他模型的通用方法
182
- inputs = tokenizer.encode(prompt, return_tensors="pt")
183
- if device == "cuda":
184
- inputs = inputs.cuda()
185
-
186
- with torch.no_grad():
187
- outputs = model.generate(
188
- inputs,
189
- max_length=inputs.shape[1] + 200,
190
- num_return_sequences=1,
191
- temperature=0.7,
192
- do_sample=True,
193
- pad_token_id=tokenizer.eos_token_id
194
- )
195
-
196
- response = tokenizer.decode(outputs[0][inputs.shape[1]:], skip_special_tokens=True)
197
 
198
- return response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
  except Exception as e:
201
- print(f"分析生成错误: {str(e)}")
202
- return f"基于图像内容 '{caption}' 的分析生成遇到问题,请重试。"
203
 
204
- def on_image_upload(image):
205
- """处理图像上传"""
206
  if image is None:
207
- return [], []
208
 
209
- try:
210
- print("🖼️ 处理图像...")
211
- history = []
212
- chat_history = []
213
-
214
- # 生成图像描述
215
- caption = describe_image(image)
216
- print(f"图像描述: {caption}")
217
-
218
- # 生成分析
219
- analysis = generate_analysis(caption)
220
-
221
- # Gradio Chatbot格式:[用户消息, AI回复]
222
- # 图像上传时,用户消息为None,AI回复为分析内容
223
- chat_history.append([None, analysis])
224
-
225
- return chat_history, history
226
-
227
- except Exception as e:
228
- print(f"图像处理错误: {str(e)}")
229
- return [[None, "图像处理失败,请重新上传。"]], []
230
 
231
- def on_user_message(user_message, chat_history, history):
232
- """处理用户消息"""
233
- if not user_message or not user_message.strip():
234
- yield chat_history or [], history or []
235
- return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
 
237
- chat_history = chat_history or []
238
  history = history or []
239
 
240
- if model is None or tokenizer is None:
241
- chat_history.append([user_message, "对话功能暂时不可用,仅支持图像分析。"])
242
- yield chat_history, history
243
- return
 
 
 
 
 
244
 
245
- try:
246
- chat_history.append([user_message, ""])
247
-
248
- # 检查模型类型并生成回复
249
- if hasattr(model, 'stream_chat'):
250
- # ChatGLM流式回复
251
- for output, new_history in model.stream_chat(tokenizer, user_message, history):
252
- chat_history[-1][1] = output
253
- yield chat_history, new_history
 
 
 
 
 
 
 
 
 
 
254
  else:
255
- # 其他模型的简单回复
256
- response = generate_analysis(user_message) # 复用分析功能
257
- chat_history[-1][1] = response
258
- yield chat_history, history
259
-
260
- except Exception as e:
261
- print(f"对话错误: {str(e)}")
262
- chat_history[-1][1] = "对话生成失败,请重试。"
263
- yield chat_history, history
264
-
265
- def clear_chat():
266
- return [], []
267
 
268
  # 创建界面
269
  def create_interface():
270
  with gr.Blocks(
271
- title="AI艺术品讲解智能体",
272
  theme=gr.themes.Soft()
273
  ) as demo:
 
274
  gr.HTML("""
275
  <div style="text-align: center; margin-bottom: 20px;">
276
  <h1>🎨 AI 艺术品讲解智能体</h1>
277
- <p>上传艺术品图像,获得专业的艺术分析</p>
278
  </div>
279
  """)
280
 
@@ -285,75 +299,111 @@ def create_interface():
285
  type="pil",
286
  height=350
287
  )
288
- clear_btn = gr.Button("🗑️ 清空对话", variant="secondary")
289
 
290
- # 模型状态显示
291
- status_display = gr.HTML(
292
- "<div style='padding:10px; background:#f0f0f0; border-radius:5px;'>"
293
- "<b>模型状态:</b> 正在加载..."
294
- "</div>"
295
- )
 
 
 
 
296
 
297
  with gr.Column(scale=2):
298
- chatbot = gr.Chatbot(
299
- label="🤖 AI 分析师",
300
- height=500
 
 
301
  )
302
-
303
- user_input = gr.Textbox(
304
- label="💬 继续提问",
305
- placeholder="请输入关于艺术作品的问题...",
 
 
 
 
 
 
 
 
 
306
  lines=2
307
  )
308
 
309
- state = gr.State([])
 
 
310
 
311
  # 事件绑定
312
- image_input.upload(
313
- fn=on_image_upload,
314
  inputs=image_input,
315
- outputs=[chatbot, state]
316
  )
317
 
318
- user_input.submit(
319
- fn=on_user_message,
320
- inputs=[user_input, chatbot, state],
321
- outputs=[chatbot, state]
322
  )
323
 
324
- user_input.submit(lambda: "", inputs=[], outputs=[user_input])
325
- clear_btn.click(fn=clear_chat, inputs=[], outputs=[chatbot, state])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326
 
327
  return demo
328
 
329
  # 主程序
330
  if __name__ == "__main__":
331
- print("🚀 启动 AI 艺术品讲解智能体...")
332
-
333
- demo = create_interface()
334
 
335
- # 加载模型
336
- model_status = load_models()
 
 
 
 
337
 
338
- if model_status == True:
339
- status_msg = "✅ 所有模型加载完成"
340
- print(status_msg)
341
- elif model_status == "partial":
342
- status_msg = "⚠️ 图像模型可用,对话功能受限"
343
- print(status_msg)
344
- else:
345
- status_msg = "❌ 模型加载失败"
346
- print(status_msg)
347
 
348
- # 启动应用
349
  try:
350
  demo.launch(
351
- share=True,
352
  show_error=True,
353
- quiet=False
 
354
  )
355
  except Exception as e:
356
- print(f"启动失败: {str(e)}")
357
- with gr.Blocks() as error_demo:
358
- gr.HTML(f"<h2>启动失败</h2><p>{str(e)}</p>")
359
- error_demo.launch()
 
 
3
  import warnings
4
  warnings.filterwarnings("ignore")
5
 
 
6
  try:
7
  import gradio as gr
8
  from PIL import Image
9
  import torch
10
+ print(f"✅ 基础库加载成功,PyTorch: {torch.__version__}")
 
 
 
 
 
 
 
11
  except ImportError as e:
12
+ print(f"❌ 基础库加载失败: {e}")
 
 
 
13
  sys.exit(1)
14
 
 
15
  try:
16
  from transformers import AutoTokenizer, AutoModel, AutoProcessor, Blip2ForConditionalGeneration
17
+ print("✅ Transformers 加载成功")
18
  except ImportError as e:
19
+ print(f"❌ Transformers 加载失败: {e}")
20
+ # 使用简化版本
21
+ USE_AI_MODELS = False
22
+ else:
23
+ USE_AI_MODELS = True
24
 
25
+ # 环境配置
26
  IS_SPACES = os.environ.get("SPACE_ID") is not None
27
  device = "cuda" if torch.cuda.is_available() else "cpu"
28
+ print(f"环境: {'HF Spaces' if IS_SPACES else 'Local'}, 设备: {device}, AI模型: {USE_AI_MODELS}")
29
 
30
  # 全局变量
 
 
31
  processor = None
32
  blip_model = None
33
+ tokenizer = None
34
+ chat_model = None
35
 
36
+ def load_image_model():
37
+ """加载图像理解模型"""
38
+ global processor, blip_model
39
 
40
+ if not USE_AI_MODELS:
41
+ return False
42
+
43
  try:
44
+ print("📷 加载图像理解模型...")
45
 
46
+ # 使用更小更稳定的BLIP模型
47
+ model_name = "Salesforce/blip2-opt-2.7b"
 
48
 
49
+ processor = AutoProcessor.from_pretrained(model_name)
50
  blip_model = Blip2ForConditionalGeneration.from_pretrained(
51
+ model_name,
52
  torch_dtype=torch.float16 if device == "cuda" else torch.float32,
53
  device_map="auto" if device == "cuda" else None,
54
+ load_in_8bit=device == "cuda"
 
55
  )
56
 
57
  if device == "cpu":
58
  blip_model = blip_model.to("cpu")
59
+
60
+ print("✅ 图像模型加载成功")
61
+ return True
62
+
63
+ except Exception as e:
64
+ print(f"❌ 图像模型加载失败: {str(e)}")
65
+ return False
66
+
67
+ def load_chat_model():
68
+ """加载对话模型"""
69
+ global tokenizer, chat_model
70
+
71
+ if not USE_AI_MODELS:
72
+ return False
73
 
74
+ try:
75
+ print("💬 加载对话模型...")
76
 
 
77
  model_name = "THUDM/chatglm2-6b-int4"
78
+ tokenizer = AutoTokenizer.from_pretrained(
79
+ model_name,
80
+ trust_remote_code=True,
81
+ use_fast=False
82
+ )
83
 
84
+ chat_model = AutoModel.from_pretrained(
85
+ model_name,
86
+ trust_remote_code=True,
87
+ torch_dtype=torch.float16 if device == "cuda" else torch.float32,
88
+ low_cpu_mem_usage=True
89
+ )
90
+
91
+ if device == "cuda":
92
+ chat_model = chat_model.half().cuda()
93
+ chat_model.eval()
94
+
95
+ print("✅ 对话模型加载成功")
96
+ return True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
  except Exception as e:
99
+ print(f"❌ 对话模型加载失败: {str(e)}")
100
  return False
101
 
102
+ def describe_image_ai(image):
103
+ """使用AI模型描述图像"""
104
+ if not processor or not blip_model:
105
+ return None
106
+
107
  try:
108
+ # 预处理图像
109
  if not isinstance(image, Image.Image):
110
  image = Image.fromarray(image)
111
+
112
+ # 调整图像大小,避免内存问题
113
+ max_size = 384
114
+ if max(image.size) > max_size:
115
+ image.thumbnail((max_size, max_size), Image.Resampling.LANCZOS)
116
 
117
+ # 确保图像是RGB模式
118
+ if image.mode != 'RGB':
119
+ image = image.convert('RGB')
120
 
121
  inputs = processor(image, return_tensors="pt")
122
 
 
126
  with torch.no_grad():
127
  generated_ids = blip_model.generate(
128
  **inputs,
129
+ max_new_tokens=20, # 减少token数量
130
+ min_length=5, # 最小长度
131
+ num_beams=2, # 减少beam数量
132
+ do_sample=False, # 关闭采样
133
+ early_stopping=True,
134
+ pad_token_id=processor.tokenizer.pad_token_id
135
  )
136
 
137
  caption = processor.batch_decode(generated_ids, skip_special_tokens=True)[0].strip()
138
+
139
+ # 验证描述质量
140
+ if len(caption) < 3 or caption.lower() in ['a', 'an', 'the', '']:
141
+ print(f"⚠️ AI描述质量差: '{caption}'")
142
+ return None
143
+
144
+ print(f"✅ AI图像描述: {caption}")
145
  return caption
146
 
147
  except Exception as e:
148
+ print(f" AI图像描述失败: {str(e)}")
149
+ return None
 
 
 
 
 
 
 
 
 
 
 
150
 
151
+ def describe_image_basic(image):
152
+ """基础图像分析(不依赖AI)"""
 
153
  try:
154
+ if not isinstance(image, Image.Image):
155
+ image = Image.fromarray(image)
156
 
157
+ width, height = image.size
158
+ mode = image.mode
159
+ aspect_ratio = width / height
160
+
161
+ # 基本尺寸分析
162
+ if aspect_ratio > 1.5:
163
+ orientation = "横向构图"
164
+ elif aspect_ratio < 0.7:
165
+ orientation = "纵向构图"
166
  else:
167
+ orientation = "方形构图"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
+ # 颜色分析
170
+ try:
171
+ colors = image.getcolors(maxcolors=256*256*256)
172
+ if colors:
173
+ # 分析主要颜色
174
+ sorted_colors = sorted(colors, key=lambda x: x[0], reverse=True)
175
+ dominant_color = sorted_colors[0][1]
176
+
177
+ # 简单色彩描述
178
+ r, g, b = dominant_color[:3] if len(dominant_color) >= 3 else (128, 128, 128)
179
+ if r > g and r > b:
180
+ color_tone = "偏红色调"
181
+ elif g > r and g > b:
182
+ color_tone = "偏绿色调"
183
+ elif b > r and b > g:
184
+ color_tone = "偏蓝色调"
185
+ else:
186
+ color_tone = "中性色调"
187
+ else:
188
+ color_tone = "色彩丰富"
189
+ except:
190
+ color_tone = "色彩复杂"
191
+
192
+ description = f"一幅{orientation}的艺术作品,{color_tone},尺寸为{width}x{height}像素"
193
+ return description
194
 
195
  except Exception as e:
196
+ print(f"基础图像分析失败: {str(e)}")
197
+ return "一幅艺术作品"
198
 
199
+ def analyze_artwork(image):
200
+ """综合艺术品分析"""
201
  if image is None:
202
+ return "请上传艺术品图像"
203
 
204
+ print("🎨 开始分析艺术品...")
205
+
206
+ # 尝试AI描述,失败则使用基础描述
207
+ ai_description = describe_image_ai(image) if USE_AI_MODELS else None
208
+
209
+ if ai_description:
210
+ description = ai_description
211
+ analysis_type = "AI智能分析"
212
+ else:
213
+ description = describe_image_basic(image)
214
+ analysis_type = "基础视觉分析"
215
+
216
+ # 生成分析报告
217
+ analysis = f"""
218
+ 🎨 艺术品分析报告 ({analysis_type})
 
 
 
 
 
 
219
 
220
+ 📷 图像描述: {description}
221
+
222
+ 🎯 艺术解读:
223
+ 从视觉构成来看,这幅作品体现了艺术家对空间、色彩和形式的独特理解。作品通过画面元素的组织和安排,创造出特定的视觉效果和情感氛围。
224
+
225
+ 🖌️ 技法特点:
226
+ • 构图安排体现了艺术家的空间意识
227
+ • 色彩运用展现了对色彩关系的掌握
228
+ • 整体风格反映了特定的艺术追求
229
+
230
+ 💭 欣赏建议:
231
+ 建议从构图平衡、色彩和谐、主题表达等角度深入欣赏这件作品。每一次观看都可能发现新的细节和感受。
232
+
233
+ ---
234
+ 💡 提示: 您可以在下方继续提问,探讨更多艺术话题
235
+ """
236
+
237
+ return analysis
238
+
239
+ def chat_with_ai(message, history):
240
+ """智能对话功能"""
241
+ if not message or not message.strip():
242
+ return history, ""
243
 
 
244
  history = history or []
245
 
246
+ # 尝试使用ChatGLM
247
+ if chat_model and tokenizer:
248
+ try:
249
+ response, _ = chat_model.chat(tokenizer, message, history=[])
250
+ history.append([message, response])
251
+ return history, ""
252
+ except Exception as e:
253
+ print(f"AI对话失败: {str(e)}")
254
+ # 继续使用预设回复
255
 
256
+ # 预设的艺术话题回复
257
+ responses = {
258
+ "颜色": "色彩是艺术作品中最直观的视觉元素。不同颜色能够唤起不同的情感反应,艺术家通过色彩的冷暖对比、明暗变化来营造画面氛围。",
259
+ "构图": "构图是艺术作品的骨架结构。经典的构图法则包括三分法、黄金分割、对称与均衡等,这些都有助于创造视觉焦点和引导观者视线。",
260
+ "风格": "艺术风格是艺术家个性和时代特征的体现。从古典主义的严谨到印象派的光影变化,每种风格都有其独特的表现语言。",
261
+ "技法": "绘画技法包括笔触运用、色彩调和、明暗处理等。掌握技法是艺术表达的基础,但真正的艺术超越技法,直达情感和思想。",
262
+ "历史": "艺术史是人类文明发展的重要组成部分。了解作品的历史背景有助于更好地理解艺术家的创作意图和作品的文化价值。"
263
+ }
264
+
265
+ # 简单的关键词匹配
266
+ response = "这是个很有趣的艺术问题。"
267
+ for keyword, reply in responses.items():
268
+ if keyword in message:
269
+ response = reply
270
+ break
271
+ else:
272
+ # 默认回复
273
+ if "?" in message or "?" in message:
274
+ response = "关于这个问题,建议从作品的视觉元素、创作背景和个人感受三个维度来思考。艺术欣赏很大程度上是主观的,重要的是培养自己的审美感受力。"
275
  else:
276
+ response = "您提到的观点很有见地。艺术作品往往承载着丰富的内涵,值得我们从多个角度去解读和欣赏。"
277
+
278
+ history.append([message, response])
279
+ return history, ""
 
 
 
 
 
 
 
 
280
 
281
  # 创建界面
282
  def create_interface():
283
  with gr.Blocks(
284
+ title="AI艺术品讲解智能体",
285
  theme=gr.themes.Soft()
286
  ) as demo:
287
+
288
  gr.HTML("""
289
  <div style="text-align: center; margin-bottom: 20px;">
290
  <h1>🎨 AI 艺术品讲解智能体</h1>
291
+ <p>上传艺术品图像,获得专业分析与互动讨论</p>
292
  </div>
293
  """)
294
 
 
299
  type="pil",
300
  height=350
301
  )
 
302
 
303
+ analyze_btn = gr.Button("🔍 开始分析", variant="primary", size="lg")
304
+
305
+ gr.HTML("""
306
+ <div style="margin-top: 15px; padding: 10px; background: #f8f9fa; border-radius: 8px; font-size: 0.9em;">
307
+ <b>💡 使用提示:</b><br>
308
+ • 支持JPG、PNG等常见格式<br>
309
+ • 建议上传清晰的艺术作品图像<br>
310
+ • 分析完成后可继续提问交流
311
+ </div>
312
+ """)
313
 
314
  with gr.Column(scale=2):
315
+ analysis_output = gr.Textbox(
316
+ label="📊 艺术品分析",
317
+ lines=15,
318
+ max_lines=20,
319
+ placeholder="上传图像后点击"开始分析"按钮..."
320
  )
321
+
322
+ # 对话区域
323
+ gr.HTML("<hr style='margin: 30px 0;'><h3>💬 继续探讨</h3>")
324
+
325
+ chatbot = gr.Chatbot(
326
+ label="与AI艺术顾问对话",
327
+ height=300,
328
+ placeholder="分析完成后,您可以在这里继续讨论艺术相关话题"
329
+ )
330
+
331
+ chat_input = gr.Textbox(
332
+ label="输入您的问题或观点",
333
+ placeholder="例如:这幅作品的色彩运用有什么特点?",
334
  lines=2
335
  )
336
 
337
+ with gr.Row():
338
+ clear_chat_btn = gr.Button("🗑️ 清空对话", variant="secondary")
339
+ clear_all_btn = gr.Button("🔄 重新开始", variant="secondary")
340
 
341
  # 事件绑定
342
+ analyze_btn.click(
343
+ fn=analyze_artwork,
344
  inputs=image_input,
345
+ outputs=analysis_output
346
  )
347
 
348
+ chat_input.submit(
349
+ fn=chat_with_ai,
350
+ inputs=[chat_input, chatbot],
351
+ outputs=[chatbot, chat_input]
352
  )
353
 
354
+ clear_chat_btn.click(
355
+ fn=lambda: [],
356
+ outputs=chatbot
357
+ )
358
+
359
+ def reset_all():
360
+ return None, "", []
361
+
362
+ clear_all_btn.click(
363
+ fn=reset_all,
364
+ outputs=[image_input, analysis_output, chatbot]
365
+ )
366
+
367
+ # 功能说明
368
+ gr.HTML(f"""
369
+ <div style="margin-top: 30px; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
370
+ color: white; border-radius: 10px;">
371
+ <h4 style="margin-top: 0;">🔧 系统状态</h4>
372
+ <p><strong>AI功能:</strong> {'✅ 已启用' if USE_AI_MODELS else '❌ 简化模式'}</p>
373
+ <p><strong>运行环境:</strong> {'Hugging Face Spaces' if IS_SPACES else '本地环境'}</p>
374
+ <p><strong>计算设备:</strong> {device.upper()}</p>
375
+
376
+ <h4>📚 支持的讨论话题</h4>
377
+ <p>色彩分析 • 构图技巧 • 艺术风格 • 绘画技法 • 艺术史背景</p>
378
+ </div>
379
+ """)
380
 
381
  return demo
382
 
383
  # 主程序
384
  if __name__ == "__main__":
385
+ print("🚀 启动艺术品分析应用...")
 
 
386
 
387
+ # 预加载模型(可选)
388
+ if USE_AI_MODELS:
389
+ print("📦 预加载AI模型...")
390
+ image_model_loaded = load_image_model()
391
+ chat_model_loaded = load_chat_model()
392
+ print(f"模型状态: 图像模型{'✅' if image_model_loaded else '❌'}, 对话模型{'✅' if chat_model_loaded else '❌'}")
393
 
394
+ # 创建并启动界面
395
+ demo = create_interface()
 
 
 
 
 
 
 
396
 
 
397
  try:
398
  demo.launch(
399
+ share=False,
400
  show_error=True,
401
+ server_name="0.0.0.0" if IS_SPACES else None,
402
+ server_port=7860 if IS_SPACES else None
403
  )
404
  except Exception as e:
405
+ print(f"启动失败: {str(e)}")
406
+ # 备用简化启动
407
+ with gr.Blocks() as backup:
408
+ gr.HTML(f"<h2>启动遇到问题</h2><p>错误: {str(e)}</p><p>请刷新页面重试</p>")
409
+ backup.launch()