File size: 2,919 Bytes
dda6bed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
ui/components.py — reusable Gradio input widgets.

Each function returns (component, …) tuples so app.py stays declarative.
"""

import gradio as gr

from config import (
    MODELS,
    DEFAULT_PROMPT,
    DEFAULT_MAX_TOKENS,
    DEFAULT_TEMPERATURE,
)

PROMPT_EXAMPLES = [
    ["Describe this image in detail."],
    ["List every object you can see."],
    ["What is the mood or atmosphere of this image?"],
    ["What text, if any, appears in this image?"],
    ["Explain this image to someone who cannot see it."],
    ["What is unusual or interesting about this image?"],
]


def image_upload() -> gr.Image:
    return gr.Image(type="pil", label="📷 Input Image", height=320)


def prompt_box() -> gr.Textbox:
    return gr.Textbox(
        value=DEFAULT_PROMPT,
        label="💬 Prompt",
        lines=3,
        placeholder="Ask anything about the image…",
    )


def model_selector() -> gr.Radio:
    return gr.Radio(
        choices=list(MODELS.keys()),
        value=list(MODELS.keys())[0],
        label="🤖 Model",
    )


def generation_settings() -> tuple[gr.Slider, gr.Slider]:
    """Returns (max_tokens_slider, temperature_slider)."""
    with gr.Accordion("⚙️ Generation settings", open=False):
        max_tokens = gr.Slider(
            64, 2048, value=DEFAULT_MAX_TOKENS, step=64, label="Max tokens"
        )
        temperature = gr.Slider(
            0.0, 1.5, value=DEFAULT_TEMPERATURE, step=0.05, label="Temperature"
        )
    return max_tokens, temperature


def api_key_field() -> gr.Textbox:
    with gr.Accordion("🔑 API Key", open=False):
        box = gr.Textbox(
            label="Your API key (optional)",
            type="password",
            lines=1,
            placeholder="sk-…  leave blank to use the free public key",
        )
        gr.Markdown(
            "A **free public key** is used when this field is blank.  \n"
            "It is shared and rate-limited — paste your own key from "
            "[modelbest.cn](https://modelbest.cn) for unlimited use."
        )
    return box


def prompt_examples(prompt_input: gr.Textbox) -> gr.Examples:
    return gr.Examples(
        examples=PROMPT_EXAMPLES,
        inputs=[prompt_input],
        label="📝 Examples",
    )


def output_box() -> gr.Textbox:
    return gr.Textbox(
        label="📄 Model Description (streaming)",
        lines=22,
        placeholder="Response streams here token-by-token…",
    )


def info_panel() -> None:
    gr.Markdown(
        "---\n"
        "**API details**\n"
        "- Endpoint: `https://api.modelbest.cn/v1/chat/completions`\n"
        "- Protocol: OpenAI-compatible (SSE streaming)\n"
        "- Auth: Bearer token\n\n"
        "**Models**\n"
        "| Model | Params | Best for |\n"
        "|---|---|---|\n"
        "| Instruct | 1.3 B | Fast Q&A, descriptions |\n"
        "| Thinking | 1.3 B | Complex reasoning, OCR |\n"
    )