File size: 6,481 Bytes
6abc72b 9e973d6 6abc72b 9e973d6 ea7a010 9e973d6 6abc72b 028a160 a5ca8b8 9e973d6 ea7a010 6abc72b 179e141 6abc72b 9e973d6 179e141 9e973d6 ea7a010 9b2b791 252ceca a272337 9b2b791 028a160 252ceca 9b2b791 252ceca 9b2b791 9e973d6 252ceca 9e973d6 ea7a010 9b2b791 d09ee43 028a160 3c8be11 028a160 252ceca 9b2b791 028a160 252ceca 028a160 252ceca a272337 d09ee43 252ceca 9e973d6 252ceca 028a160 252ceca 028a160 252ceca d09ee43 252ceca 6abc72b 36a16e0 9e973d6 6abc72b 252ceca 3c8be11 d09ee43 252ceca 36a16e0 ea7a010 a5ca8b8 028a160 9b2b791 a5ca8b8 6abc72b 16da1b8 | 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 | import os
import base64
import gradio as gr
from openai import OpenAI
def encode_image(image_path):
"""将本地图片文件转换为 Base64 编码"""
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode('utf-8')
def detect_language(text, history):
"""
智能检测用户语言:
1. 优先从当前提问检测
2. 若当前无文字,从最近一轮用户历史中推断
3. 默认返回中文
"""
# 1. 检查当前提问
if text:
clean_text = str(text).strip()
if clean_text:
# 计算中文字符和英文字母比例
chinese_chars = sum(1 for char in clean_text if '\u4e00' <= char <= '\u9fff')
alpha_chars = sum(1 for char in clean_text if char.isalpha())
if alpha_chars > 0:
# 中文字符占比 > 30% 判定为中文
if chinese_chars / alpha_chars > 0.3:
return "zh"
else:
return "en"
else:
# 没有字母(纯数字/符号),默认中文
return "zh"
# 2. 当前无文字,从历史中推断
for msg in reversed(history[-6:]):
if msg.get("role") == "user":
content = msg.get("content", "")
if isinstance(content, dict):
content = content.get("text", "")
if content:
clean_content = str(content).strip()
chinese_chars = sum(1 for char in clean_content if '\u4e00' <= char <= '\u9fff')
alpha_chars = sum(1 for char in clean_content if char.isalpha())
if alpha_chars > 0 and chinese_chars / alpha_chars > 0.3:
return "zh"
elif alpha_chars > 0:
return "en"
# 3. 默认中文
return "zh"
def predict(message, history):
api_key = os.getenv("SILICONFLOW_API_KEY", "")
if not api_key:
yield "❌ 未检测到 API Key!请先在 Space Settings -> Secrets 中添加 SILICONFLOW_API_KEY!"
return
api_key = api_key.strip()
try:
client = OpenAI(
api_key=api_key,
base_url="https://api.siliconflow.cn/v1"
)
text_content = ""
files = []
# Gradio 多模态输入解析
if isinstance(message, dict):
text_content = message.get("text", "")
files = message.get("files", [])
else:
text_content = str(message)
# 智能检测语言(含历史记忆)
user_lang = detect_language(text_content, history)
# 🔥 调试输出(可删除)
print(f"检测到语言: {user_lang}, 用户输入: {text_content[:50]}")
# 构建当前请求的 Message Payload
current_content = []
# 1. 解析当前上传的图片
for f in files:
file_path = f.get("path") if isinstance(f, dict) else f
if file_path:
try:
base64_img = encode_image(file_path)
current_content.append({
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{base64_img}"}
})
except Exception as img_err:
print(f"图片读取失败: {img_err}")
# 2. 解析文本说明
if not text_content or not str(text_content).strip():
if user_lang == "en":
prompt_text = "Please observe this image carefully and tell me what plant this is and its key features."
else:
prompt_text = "请仔细观察这张图片,告诉我这是什么植物?有哪些特征?"
else:
prompt_text = str(text_content).strip()
current_content.append({"type": "text", "text": prompt_text})
# 3. 根据用户语言设置 System Prompt
if user_lang == "en":
system_prompt = (
"You are a professional botanist and nature expert. "
"Identify the plant in the image and provide its scientific name, "
"family, genus, and key features in **English**. "
"Be concise and accurate."
)
else:
system_prompt = (
"你是一位专业的植物学家和自然科普专家。"
"请精准识别图片中的植物,并用简洁明了的中文回答其名称、科属及特点。"
)
messages = [
{"role": "system", "content": system_prompt}
]
# 仅保留最近 2 轮纯文本历史
for msg in history[-4:]:
role = "user" if msg.get("role") == "user" else "assistant"
content_val = msg.get("content", "")
if isinstance(content_val, dict):
content_val = content_val.get("text", "")
if content_val and not str(content_val).startswith("data:image"):
messages.append({"role": role, "content": str(content_val)})
# 放入最新一轮包含图片的请求
messages.append({"role": "user", "content": current_content})
# 4. 调用视觉模型
response = client.chat.completions.create(
model="Qwen/Qwen3-VL-32B-Instruct",
messages=messages,
stream=True,
temperature=0.2
)
# 5. 流式输出
partial_text = ""
for chunk in response:
if chunk.choices and chunk.choices[0].delta.content:
partial_text += chunk.choices[0].delta.content
yield partial_text
except Exception as e:
err_msg = str(e)
if "30001" in err_msg or "insufficient" in err_msg.lower():
yield "⚠️ **请求失败:硅基流动账号余额不足**"
elif "30003" in err_msg or "Model disabled" in err_msg:
yield "⚠️ **模型不可用,请检查模型名称是否正确**"
else:
yield f"❌ 请求失败: {err_msg}"
# 创建 Gradio 界面
demo = gr.ChatInterface(
fn=predict,
title="🌱 AI 植物识别专家 (智能双语)",
description="🌍 智能识别你的提问语言:中文问→中文答,英文问→英文答。连续对话自动记忆语言偏好!",
multimodal=True
)
if __name__ == "__main__":
demo.launch(ssr_mode=False) |