File size: 4,121 Bytes
87032c4
9558456
0c25ef0
9558456
87032c4
fad0968
9558456
 
6804860
 
fad0968
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9558456
 
fad0968
9558456
 
3f750cf
9558456
0c25ef0
 
 
 
 
 
 
 
 
 
 
 
9558456
0c25ef0
9558456
 
 
 
 
 
 
 
fad0968
9558456
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fad0968
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75f33dc
9558456
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
import gradio as gr
import requests
import base64
import os

API_KEY = os.environ.get("PLANTNET_API_KEY", "")
PROJECT = "all"
API_URL = f"https://my-api.plantnet.org/v2/identify/{PROJECT}?api-key={API_KEY}"


def test_connection():
    lines = []
    if API_KEY:
        lines.append(f"✅ API Key 已读取,前6位:{API_KEY[:6]}...")
    else:
        lines.append("❌ API Key 未读取到,请检查 Secrets 配置")
        return "\n".join(lines)
    try:
        r = requests.get(
            f"https://my-api.plantnet.org/v2/identify/all?api-key={API_KEY}",
            timeout=30
        )
        lines.append(f"✅ 网络连通,状态码:{r.status_code}")
        lines.append(f"返回内容:{r.text[:200]}")
    except requests.exceptions.Timeout:
        lines.append("❌ 网络请求超时(30秒)")
    except Exception as e:
        lines.append(f"❌ 网络错误:{e}")
    return "\n".join(lines)


def identify_plant(image, organ):
    if not API_KEY:
        return "⚠️ 未检测到 API Key,请检查 Secrets 配置"
    if image is None:
        return "请先上传一张植物照片"
    try:
        with open(image, "rb") as f:
            img_data = f.read()

        b64 = base64.b64encode(img_data).decode()
        payload = {
            "images": [b64],
            "organs": [organ]
        }
        response = requests.post(
            API_URL,
            json=payload,
            timeout=120
        )
    except requests.exceptions.Timeout:
        return "请求超时(120秒),HF服务器可能无法访问Pl@ntNet,建议改用魔搭部署"
    except requests.exceptions.RequestException as e:
        return f"网络请求失败:{e}"

    if response.status_code == 401:
        return "❌ API Key 无效或已过期"
    elif response.status_code == 429:
        return "⚠️ 已超出当日调用配额"
    elif response.status_code != 200:
        return f"识别失败,状态码:{response.status_code}\n{response.text[:200]}"

    result = response.json()
    results = result.get("results", [])
    if not results:
        return "未识别到匹配物种,建议换一张更清晰的照片重试"

    output = []
    for i, r in enumerate(results[:5], start=1):
        name = r["species"]["scientificNameWithoutAuthor"]
        family = r["species"].get("family", {}).get("scientificNameWithoutAuthor", "")
        common_names = r["species"].get("commonNames", [])
        common = "、".join(common_names[:2]) if common_names else "暂无常用名"
        score = r["score"]
        output.append(f"**{i}. {name}**({family})\n常用名:{common} 置信度:{score:.1%}")

    return "\n\n---\n\n".join(output)


with gr.Blocks(title="植物识别助手") as demo:
    gr.Markdown("# 🌿 植物识别助手\n识别引擎来自 [Pl@ntNet](https://plantnet.org)")

    with gr.Tab("植物识别"):
        with gr.Row():
            with gr.Column():
                image_input = gr.Image(type="filepath", label="上传植物照片")
                organ_input = gr.Dropdown(
                    choices=["auto", "leaf", "flower", "fruit", "bark", "habit"],
                    value="auto",
                    label="拍摄部位",
                    info="明确指定部位(如leaf/flower)通常比auto识别更准确"
                )
                submit_btn = gr.Button("开始识别", variant="primary")
            with gr.Column():
                output_text = gr.Markdown(label="识别结果")
        submit_btn.click(fn=identify_plant, inputs=[image_input, organ_input], outputs=output_text)

    with gr.Tab("🔧 连接测试"):
        gr.Markdown("点击下方按钮,测试 API Key 和网络是否正常")
        test_btn = gr.Button("开始测试", variant="secondary")
        test_output = gr.Textbox(label="测试结果", lines=6)
        test_btn.click(fn=test_connection, inputs=[], outputs=test_output)

    gr.Markdown("---\n数据来自 Pl@ntNet 官方 API,遵循 CC BY-SA / CC BY 授权协议。识别结果仅供参考。")

demo.launch(server_name="0.0.0.0", server_port=7860)