Spaces:
Sleeping
Sleeping
File size: 7,730 Bytes
0be9545 361af0a 0be9545 995459b 0be9545 fe9b8a5 0be9545 fe9b8a5 995459b 0be9545 995459b 0be9545 995459b 0be9545 995459b 0be9545 995459b 0be9545 995459b 0be9545 995459b 0be9545 995459b 0be9545 995459b 0be9545 995459b 0be9545 995459b 0be9545 995459b 0be9545 995459b 0be9545 995459b 0be9545 995459b 0be9545 995459b 0be9545 fe9b8a5 0be9545 995459b 0be9545 995459b 0be9545 c888602 0be9545 fe9b8a5 c888602 fe9b8a5 0be9545 c888602 995459b |
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 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
import os
import base64
import requests
import json
from flask import Flask, render_template, request, jsonify
from PIL import Image
import io
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 10 * 1024 * 1024 # 10MB max file size
# Gemini API configuration
GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY')
GEMINI_API_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image-preview:generateContent"
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def optimize_image(image_bytes, max_size=(1024, 1024), quality=85):
"""优化图像大小和质量"""
try:
# 使用 io.BytesIO 将字节数据转换为文件对象,供 Pillow 使用
img = Image.open(io.BytesIO(image_bytes))
if img.mode in ('RGBA', 'LA'):
background = Image.new('RGB', img.size, (255, 255, 255))
if img.mode == 'RGBA':
background.paste(img, mask=img.split()[-1])
else:
background.paste(img, mask=img.split()[-1])
img = background
img.thumbnail(max_size, Image.Resampling.LANCZOS)
img_byte_arr = io.BytesIO()
img.save(img_byte_arr, format='JPEG', quality=quality, optimize=True)
img_byte_arr.seek(0)
return img_byte_arr.getvalue()
except Exception as e:
print(f"Image optimization error: {e}")
return image_bytes # 优化失败,返回原始字节数据
def call_gemini_api(text_content=None, image_data=None):
"""调用Gemini API进行分析"""
if not GEMINI_API_KEY:
return {"error": "未配置Gemini API密钥,请设置环境变量GEMINI_API_KEY"}
system_prompt = """你是一位经验丰富的皮肤科专家医生,具有多年的临床诊疗经验。请基于提供的信息进行专业的皮肤病分析。
分析要求:
仔细观察皮肤病变的形态、颜色、分布、边界等特征
结合患者描述的症状和病史
提供可能的诊断方向(按可能性大小排序)
给出详细的诊疗建议
必要时建议进一步检查
提醒患者注意事项
请按以下格式回复:
🔍 图像观察分析
[详细描述观察到的皮肤病变特征]
📋 症状综合评估
[结合文字描述的症状分析]
🎯 可能诊断
最可能诊断: [诊断名称] - 可能性: X%
依据: [具体理由]
次要考虑: [其他可能诊断]
💊 治疗建议
药物治疗
[具体用药建议]
生活护理
[日常护理要点]
🏥 进一步检查建议
[如需要其他检查,请列出]
⚠️ 注意事项
[重要提醒和注意事项]
免责声明: 此分析仅供临床参考,最终诊断需结合完整病史、体格检查等综合判断。建议患者及时就医,接受专业医师诊疗。"""
parts = []
if text_content:
parts.append({"text": f"{system_prompt}\n\n患者症状描述:{text_content}"})
else:
parts.append({"text": system_prompt + "\n\n请基于图像进行分析。"})
if image_data:
image_base64 = base64.b64encode(image_data).decode('utf-8')
parts.append({
"inline_data": {
"mime_type": "image/jpeg",
"data": image_base64
}
})
request_body = {
"contents": [
{
"parts": parts
}
],
"generationConfig": {
"temperature": 0.1,
"topK": 40,
"topP": 0.95,
"maxOutputTokens": 2048,
},
"safetySettings": [
{
"category": "HARM_CATEGORY_HARASSMENT",
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
},
{
"category": "HARM_CATEGORY_HATE_SPEECH",
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
},
{
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
},
{
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
"threshold": "BLOCK_MEDIUM_AND_ABOVE"
}
]
}
headers = {
'Content-Type': 'application/json',
'x-goog-api-key': GEMINI_API_KEY
}
try:
response = requests.post(
GEMINI_API_URL,
headers=headers,
json=request_body,
timeout=30
)
response.raise_for_status()
result = response.json()
if 'candidates' in result and len(result['candidates']) > 0:
content = result['candidates'][0]['content']['parts'][0]['text']
return {"result": content}
else:
return {"error": "API返回了空的响应"}
except requests.exceptions.Timeout:
return {"error": "请求超时,请稍后重试"}
except requests.exceptions.RequestException as e:
return {"error": f"网络请求失败: {str(e)}"}
except json.JSONDecodeError:
return {"error": "API返回了无效的JSON格式"}
except Exception as e:
return {"error": f"处理响应时发生错误: {str(e)}"}
@app.route('/')
def index():
"""主页路由"""
return render_template('index.html')
@app.route('/analyze', methods=['POST'])
def analyze():
"""分析皮肤图像和症状的API端点"""
try:
text_content = request.form.get('text', '').strip()
image_data = None
if 'image' in request.files:
file = request.files['image']
if file.filename != '':
if allowed_file(file.filename):
try:
# 核心修复:一次性将文件流读入内存
original_image_bytes = file.read()
# 调用优化函数,它现在接受字节数据
image_data = optimize_image(original_image_bytes)
except Exception as e:
return jsonify({"error": f"图像处理失败: {str(e)}"}), 400
else:
return jsonify({"error": "不支持的文件格式,请上传PNG、JPG、JPEG或GIF格式的图像"}), 400
if not text_content and not image_data:
return jsonify({"error": "请至少提供症状描述或上传皮肤图像"}), 400
result = call_gemini_api(text_content, image_data)
return jsonify(result)
except Exception as e:
return jsonify({"error": f"服务器内部错误: {str(e)}"}), 500
@app.route('/health')
def health_check():
"""健康检查端点"""
return jsonify({
"status": "healthy",
"service": "dermatology-assistant",
"version": "1.0.0"
})
@app.errorhandler(413)
def too_large(e):
return jsonify({"error": "上传的文件过大,请确保文件小于10MB"}), 413
@app.errorhandler(404)
def not_found(e):
return jsonify({"error": "请求的资源不存在"}), 404
@app.errorhandler(500)
def internal_error(e):
return jsonify({"error": "服务器内部错误"}), 500
if __name__ == '__main__':
os.makedirs('templates', exist_ok=True)
if not GEMINI_API_KEY:
print("⚠️ 警告: 未设置GEMINI_API_KEY环境变量")
print(" 请设置环境变量: export GEMINI_API_KEY=your_api_key")
port = int(os.environ.get('PORT', 7860))
app.run(host='0.0.0.0', port=port, debug=False)
|