File size: 8,204 Bytes
83a0c1c
1277e7e
a6c95f0
1074e19
 
0070f2e
 
0edee28
1277e7e
 
 
1074e19
 
 
1277e7e
0070f2e
 
 
1277e7e
 
 
 
1074e19
1277e7e
 
 
 
 
 
1074e19
 
1277e7e
 
 
 
0edee28
1277e7e
 
 
 
 
 
 
 
 
1074e19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1277e7e
 
 
 
 
420c42c
1277e7e
 
 
420c42c
1277e7e
420c42c
1277e7e
420c42c
1277e7e
 
 
8ea64e7
1277e7e
1074e19
 
1277e7e
1074e19
1277e7e
8ea64e7
1074e19
1277e7e
 
 
 
 
 
 
 
 
 
 
1074e19
 
 
 
 
 
 
 
 
 
 
1277e7e
 
 
 
 
 
 
 
1074e19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1277e7e
1074e19
 
 
b7c4eb0
 
1074e19
 
b7c4eb0
1074e19
 
 
1277e7e
b7c4eb0
1277e7e
1074e19
 
b7c4eb0
1277e7e
 
b7c4eb0
1277e7e
1074e19
b7c4eb0
1277e7e
 
 
b7c4eb0
1277e7e
1074e19
1277e7e
 
1074e19
 
 
 
 
1277e7e
 
 
 
 
 
 
 
 
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
import os
import gradio as gr

from status_check import is_endpoint_healthy
from endpoint_utils import wake_endpoint


class ContentAgentUI:
    """
    Gradio UI that:
      - shows a minimal control panel first (status + Start button),
      - auto-initializes the agent on load if the endpoint is already healthy,
      - otherwise lets the user 'Start Agent' (wake -> health -> init),
      - reveals the main chat panel (with header, guidance, examples, footer) after init.
    """

    def __init__(self, endpoint_uri: str, is_healthy: bool, health_message: str, agent_initializer):
        self.endpoint_uri = endpoint_uri
        self.is_healthy = bool(is_healthy)
        self.health_message = health_message or ""
        self.agent_initializer = agent_initializer  # callable: (uri) -> CodeAgent

        # set in build()
        self.app: gr.Blocks | None = None
        self.status_box = None
        self.control_panel = None
        self.main_panel = None
        self.prompt = None
        self.reply = None
        self.agent_state = None
        self.examples_radio = None

    # ---------- helpers ----------

    def _read_css(self) -> str | None:
        css_path = os.path.join(os.getcwd(), "ui", "styles.css")
        if os.path.exists(css_path):
            try:
                with open(css_path, "r", encoding="utf-8") as f:
                    return f.read()
            except Exception:
                return None
        return None

    def _initial_status_text(self) -> str:
        # neutral; on_load will set real status and maybe auto-init
        return "Checking endpoint status…"

    def _load_examples(self) -> list[str]:
        ex_dir = os.path.join(os.path.dirname(__file__), "examples")
        out: list[str] = []
        if os.path.isdir(ex_dir):
            for name in sorted(os.listdir(ex_dir)):
                if name.lower().endswith(".txt"):
                    p = os.path.join(ex_dir, name)
                    try:
                        with open(p, "r", encoding="utf-8", errors="ignore") as f:
                            out.append(f.read())
                    except Exception:
                        pass
        return out

    # ---------- agent call ----------

    @staticmethod
    def _call_agent(text: str, agent) -> str:
        try:
            if agent is None:
                return "Agent not initialized yet. Click 'Start Agent'."
            return str(agent.run(text))  # smolagents.CodeAgent API
        except Exception as e:
            return f"Error: {e}"

    # ---------- UI build ----------

    def build(self) -> gr.Blocks:
        if self.app is not None:
            return self.app

        css = self._read_css()
        examples = self._load_examples()

        with gr.Blocks(css=css) as demo:
            # global header (always visible)
            gr.Markdown("# Content Agent")

            # Control panel (shown first; may auto-hide on load)
            with gr.Group(visible=True) as self.control_panel:
                self.status_box = gr.Textbox(
                    label="Status",
                    value=self._initial_status_text(),
                    lines=8,
                    interactive=False,
                )
                start_btn = gr.Button("Start Agent (wake if needed)")

            # Main panel (hidden until agent is initialized)
            with gr.Group(visible=False) as self.main_panel:
                # Guidance / about
                gr.Markdown(
                    "### What this does\n"
                    "Enter text below; the agent will classify tone (polite/neutral/impolite) and can use tools.\n\n"
                    "**Tech:**\n"
                    "- `deepseek-ai/DeepSeek-R1-Distill-Qwen-32B` (endpoint)\n"
                    "- Intel Polite Guard tool\n"
                    "- Runs via your Inference Endpoint\n"
                )

                # Chat controls
                self.agent_state = gr.State(None)
                self.prompt = gr.Textbox(label="Your Input", placeholder="Enter something here…")
                self.reply = gr.Textbox(label="Content feedback", interactive=False, lines=12)
                submit_btn = gr.Button("Submit")

                submit_btn.click(self._call_agent, inputs=[self.prompt, self.agent_state], outputs=self.reply)
                self.prompt.submit(self._call_agent, inputs=[self.prompt, self.agent_state], outputs=self.reply)

                # Examples (optional)
                gr.Markdown("### Try one of these examples")
                if examples:
                    self.examples_radio = gr.Radio(choices=examples, label="Examples")
                    # fill the prompt when an example is picked
                    self.examples_radio.change(lambda ex: ex, inputs=self.examples_radio, outputs=self.prompt)
                else:
                    gr.Markdown("*No examples found.*")

                # Footer
                gr.Markdown("<div id='footer'>Thanks for trying it out!</div>")

            # --- AUTO INIT ON LOAD IF HEALTHY ---
            def on_load():
                healthy, msg = is_endpoint_healthy(self.endpoint_uri)
                if healthy:
                    try:
                        agent = self.agent_initializer(self.endpoint_uri)
                        return (
                            f"Endpoint healthy ✅ — {msg}. Agent initialized.",
                            gr.update(visible=False),   # hide control panel
                            gr.update(visible=True),    # show main panel
                            agent,
                        )
                    except Exception as e:
                        return (
                            f"Agent init failed: {e}",
                            gr.update(visible=True),
                            gr.update(visible=False),
                            None,
                        )
                # not healthy → keep Start button path
                return (
                    f"Endpoint not healthy: {msg}\nClick 'Start Agent' to wake and initialize.",
                    gr.update(visible=True),
                    gr.update(visible=False),
                    None,
                )

            demo.load(
                on_load,
                inputs=None,
                outputs=[self.status_box, self.control_panel, self.main_panel, self.agent_state],
            )

            # --- MANUAL START (wake → health → init) ---
            def on_start():
                lines: list[str] = []

                def push(s: str):
                    lines.append(s)
                    return ("\n".join(lines), gr.update(), gr.update(), None)

                # Wake with progress
                yield push("Waking endpoint… (this can take several minutes for cold starts)")
                ok, err = wake_endpoint(self.endpoint_uri, max_wait=600, poll_every=5.0, log=lines.append)
                yield ("\n".join(lines), gr.update(), gr.update(), None)  # flush all logs

                if not ok:
                    yield push(f"[Server message] {err or 'wake failed'}")
                    return

                # Health → init
                yield push("Endpoint awake ✅. Checking health…")
                healthy, msg = is_endpoint_healthy(self.endpoint_uri)
                if not healthy:
                    yield push(f"[Server message] {msg}")
                    return

                yield push("Initializing agent…")
                try:
                    agent = self.agent_initializer(self.endpoint_uri)
                except Exception as e:
                    yield push(f"Agent init failed: {e}")
                    return

                yield ("Agent initialized ✅", gr.update(visible=False), gr.update(visible=True), agent)

            start_btn.click(
                on_start,
                inputs=None,
                outputs=[self.status_box, self.control_panel, self.main_panel, self.agent_state],
            )

            self.app = demo

        return self.app

    # ---------- public API ----------

    def launch(self, **kwargs):
        return self.build().launch(**kwargs)