Jd Vijay commited on
Commit
7983734
Β·
verified Β·
1 Parent(s): 6839ece

Add full OpenManus UI

Browse files
Files changed (1) hide show
  1. app.py +427 -5
app.py CHANGED
@@ -1,12 +1,434 @@
1
  """
2
- Minimal Gradio App
 
3
  """
 
4
  import gradio as gr
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- def greet(name):
7
- return f"Hello, {name}!"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
- demo = gr.Interface(fn=greet, inputs=gr.Textbox(), outputs=gr.Textbox(), title="Test")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
  if __name__ == "__main__":
12
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
1
  """
2
+ OpenManus Web UI - A sleek dark-themed interface for AI Agent interactions
3
+ Built with Gradio for Hugging Face Spaces deployment
4
  """
5
+
6
  import gradio as gr
7
+ import os
8
+ import json
9
+ import time
10
+ from datetime import datetime
11
+ from typing import List, Dict, Any, Optional
12
+
13
+ # ============== Configuration ==============
14
+ # Theme colors for the dark UI
15
+ THEME = {
16
+ "background": "#0d0d0d",
17
+ "surface": "#1a1a1a",
18
+ "surface_hover": "#252525",
19
+ "border": "#333333",
20
+ "text_primary": "#ffffff",
21
+ "text_secondary": "#a0a0a0",
22
+ "accent": "#6366f1", # Indigo accent
23
+ "accent_hover": "#818cf8",
24
+ "success": "#10b981",
25
+ "error": "#ef4444",
26
+ "warning": "#f59e0b",
27
+ }
28
+
29
+ # ============== OpenManus Agent Wrapper ==============
30
+ class OpenManusAgent:
31
+ """Wrapper class for OpenManus-style agent interactions"""
32
+
33
+ def __init__(self, base_url: str, model_name: str, api_key: str):
34
+ self.base_url = base_url.strip()
35
+ self.model_name = model_name.strip()
36
+ self.api_key = api_key.strip()
37
+
38
+ def _build_headers(self) -> Dict[str, str]:
39
+ """Build request headers"""
40
+ return {
41
+ "Authorization": f"Bearer {self.api_key}",
42
+ "Content-Type": "application/json"
43
+ }
44
+
45
+ @staticmethod
46
+ def format_message_history(messages: List[Dict]) -> List[Dict]:
47
+ """Format message history for display"""
48
+ formatted = []
49
+ for msg in messages:
50
+ role = msg.get("role", "user")
51
+ content = msg.get("content", "")
52
+ formatted.append({
53
+ "role": role,
54
+ "content": content
55
+ })
56
+ return formatted
57
+
58
+ def call_api(self, prompt: str, history: Optional[List[Dict]] = None) -> str:
59
+ """Call the OpenManus API"""
60
+ if not self.base_url:
61
+ return "⚠️ Please configure the Base URL in settings."
62
+
63
+ if not self.api_key:
64
+ return "⚠️ Please configure the API Key in settings."
65
+
66
+ # Build the conversation context
67
+ messages = []
68
+ if history:
69
+ messages = self.format_message_history(history)
70
+ messages.append({"role": "user", "content": prompt})
71
+
72
+ try:
73
+ import requests
74
+
75
+ payload = {
76
+ "model": self.model_name or "default",
77
+ "messages": messages,
78
+ "stream": False
79
+ }
80
+
81
+ response = requests.post(
82
+ f"{self.base_url}/chat/completions",
83
+ headers=self._build_headers(),
84
+ json=payload,
85
+ timeout=120
86
+ )
87
+
88
+ if response.status_code == 200:
89
+ result = response.json()
90
+ if "choices" in result and len(result["choices"]) > 0:
91
+ return result["choices"][0]["message"]["content"]
92
+ return str(result)
93
+ else:
94
+ return f"⚠️ API Error ({response.status_code}): {response.text[:200]}"
95
+
96
+ except ImportError:
97
+ return "⚠️ Requests library not available. Please install dependencies."
98
+ except requests.exceptions.ConnectionError:
99
+ return "⚠️ Could not connect to the API. Check your Base URL."
100
+ except requests.exceptions.Timeout:
101
+ return "⚠️ Request timed out. The server may be busy."
102
+ except Exception as e:
103
+ return f"⚠️ Error: {str(e)[:200]}"
104
+
105
+ # ============== UI Components ==============
106
+ def create_custom_css() -> str:
107
+ """Generate custom CSS for dark theme"""
108
+ return f"""
109
+ /* Global Dark Theme */
110
+ body {{
111
+ background-color: {THEME['background']} !important;
112
+ color: {THEME['text_primary']} !important;
113
+ }}
114
+
115
+ /* Main container */
116
+ .gradio-container {{
117
+ background: {THEME['background']} !important;
118
+ }}
119
+
120
+ /* Chat interface */
121
+ .chat-message {{
122
+ background: {THEME['surface']} !important;
123
+ border: 1px solid {THEME['border']} !important;
124
+ border-radius: 12px !important;
125
+ padding: 16px !important;
126
+ margin: 8px 0 !important;
127
+ }}
128
+
129
+ .chat-message.user {{
130
+ background: {THEME['accent']}15 !important;
131
+ border-left: 3px solid {THEME['accent']} !important;
132
+ }}
133
+
134
+ .chat-message.assistant {{
135
+ background: {THEME['surface']} !important;
136
+ }}
137
+
138
+ /* Buttons */
139
+ button.primary {{
140
+ background: {THEME['accent']} !important;
141
+ color: white !important;
142
+ border: none !important;
143
+ border-radius: 8px !important;
144
+ padding: 12px 24px !important;
145
+ font-weight: 600 !important;
146
+ transition: all 0.2s ease !important;
147
+ }}
148
+
149
+ button.primary:hover {{
150
+ background: {THEME['accent_hover']} !important;
151
+ transform: translateY(-1px) !important;
152
+ }}
153
+
154
+ /* Input fields */
155
+ input, textarea {{
156
+ background: {THEME['surface']} !important;
157
+ border: 1px solid {THEME['border']} !important;
158
+ color: {THEME['text_primary']} !important;
159
+ border-radius: 8px !important;
160
+ }}
161
+
162
+ input:focus, textarea:focus {{
163
+ border-color: {THEME['accent']} !important;
164
+ outline: none !important;
165
+ }}
166
+
167
+ /* Tabs */
168
+ .tab-nav button {{
169
+ background: transparent !important;
170
+ color: {THEME['text_secondary']} !important;
171
+ border: none !important;
172
+ }}
173
+
174
+ .tab-nav button.selected {{
175
+ color: {THEME['accent']} !important;
176
+ border-bottom: 2px solid {THEME['accent']} !important;
177
+ }}
178
+
179
+ /* File upload area */
180
+ .upload-area {{
181
+ background: {THEME['surface']} !important;
182
+ border: 2px dashed {THEME['border']} !important;
183
+ border-radius: 12px !important;
184
+ }}
185
+
186
+ .upload-area:hover {{
187
+ border-color: {THEME['accent']} !important;
188
+ }}
189
+
190
+ /* Status indicators */
191
+ .status-connected {{
192
+ color: {THEME['success']} !important;
193
+ }}
194
+
195
+ .status-disconnected {{
196
+ color: {THEME['error']} !important;
197
+ }}
198
+
199
+ /* Panel styling */
200
+ .panel {{
201
+ background: {THEME['surface']} !important;
202
+ border: 1px solid {THEME['border']} !important;
203
+ border-radius: 12px !important;
204
+ padding: 20px !important;
205
+ }}
206
+
207
+ /* Scrollbar styling */
208
+ ::-webkit-scrollbar {{
209
+ width: 8px;
210
+ }}
211
+
212
+ ::-webkit-scrollbar-track {{
213
+ background: {THEME['background']};
214
+ }}
215
+
216
+ ::-webkit-scrollbar-thumb {{
217
+ background: {THEME['border']};
218
+ border-radius: 4px;
219
+ }}
220
+
221
+ ::-webkit-scrollbar-thumb:hover {{
222
+ background: {THEME['text_secondary']};
223
+ }}
224
+
225
+ /* Logo/Header */
226
+ .header-logo {{
227
+ font-size: 28px;
228
+ font-weight: 700;
229
+ background: linear-gradient(135deg, {THEME['accent']}, #a855f7);
230
+ -webkit-background-clip: text;
231
+ -webkit-text-fill-color: transparent;
232
+ }}
233
+ """
234
+
235
+ # ============== Chat Interface ==============
236
+ def chat_response(prompt: str, history: List[Dict], agent_config: Dict) -> str:
237
+ """Process chat messages with OpenManus agent"""
238
+ if not prompt.strip():
239
+ return history, ""
240
+
241
+ # Initialize agent with config
242
+ agent = OpenManusAgent(
243
+ base_url=agent_config.get("base_url", ""),
244
+ model_name=agent_config.get("model_name", ""),
245
+ api_key=agent_config.get("api_key", "")
246
+ )
247
+
248
+ # Call the API
249
+ response = agent.call_api(prompt, history)
250
+
251
+ # Add to history
252
+ history.append({"role": "user", "content": prompt})
253
+ history.append({"role": "assistant", "content": response})
254
+
255
+ return history, ""
256
 
257
+ # ============== Main App ==============
258
+ def create_app() -> gr.Blocks:
259
+ """Create the Gradio application"""
260
+
261
+ # Global state
262
+ agent_state = {"config": {}}
263
+
264
+ with gr.Blocks(
265
+ title="JD OpenManus Engine",
266
+ theme=gr.themes.Soft(
267
+ primary_hue="indigo",
268
+ secondary_hue="purple",
269
+ neutral_hue="slate",
270
+ font="Inter",
271
+ ),
272
+ css=create_custom_css(),
273
+ ) as app:
274
+
275
+ # Header
276
+ gr.HTML("""
277
+ <div style="text-align: center; padding: 20px 0; border-bottom: 1px solid #333; margin-bottom: 20px;">
278
+ <h1 class="header-logo">πŸ€– JD OpenManus Engine</h1>
279
+ <p style="color: #a0a0a0; margin-top: 8px;">
280
+ AI Agent Interface β€’ Powered by OpenManus Framework
281
+ </p>
282
+ </div>
283
+ """)
284
+
285
+ with gr.Tab("πŸ’¬ Chat"):
286
+ with gr.Row():
287
+ with gr.Column(scale=3):
288
+ # Chat display
289
+ chatbot = gr.Chatbot(
290
+ height=500,
291
+ bubble_full_width=False,
292
+ avatar_images=(
293
+ "πŸ‘€", # User avatar
294
+ "πŸ€–", # Bot avatar
295
+ ),
296
+ elem_classes="chat-container"
297
+ )
298
+
299
+ # Chat input
300
+ with gr.Row():
301
+ msg_input = gr.Textbox(
302
+ placeholder="Type your message here...",
303
+ show_label=False,
304
+ lines=3,
305
+ scale=4,
306
+ container=False,
307
+ )
308
+
309
+ with gr.Row():
310
+ submit_btn = gr.Button("Send", variant="primary", scale=1)
311
+ clear_btn = gr.Button("Clear Chat", variant="secondary", scale=1)
312
+
313
+ with gr.Column(scale=1):
314
+ # Sidebar with config
315
+ with gr.Group(elem_classes="panel"):
316
+ gr.Markdown("### βš™οΈ Configuration")
317
+
318
+ with gr.Accordion("API Settings", open=True):
319
+ base_url = gr.Textbox(
320
+ label="Base URL",
321
+ placeholder="https://api.openai.com/v1",
322
+ info="API endpoint URL"
323
+ )
324
+
325
+ model_name = gr.Textbox(
326
+ label="Model Name",
327
+ placeholder="gpt-4-turbo",
328
+ info="Model identifier"
329
+ )
330
+
331
+ api_key = gr.Textbox(
332
+ label="API Key",
333
+ placeholder="sk-...",
334
+ type="password",
335
+ info="Your API key"
336
+ )
337
+
338
+ save_config_btn = gr.Button("πŸ’Ύ Save Configuration", variant="primary")
339
+ config_status = gr.Markdown("")
340
+
341
+ # Chat handlers
342
+ def save_config(burl, mname, key):
343
+ agent_state["config"] = {
344
+ "base_url": burl or "",
345
+ "model_name": mname or "",
346
+ "api_key": key or ""
347
+ }
348
+ return "βœ… Configuration saved!"
349
+
350
+ save_config_btn.click(
351
+ save_config,
352
+ inputs=[base_url, model_name, api_key],
353
+ outputs=[config_status]
354
+ )
355
+
356
+ def handle_submit(msg, history):
357
+ if not msg.strip():
358
+ return history, ""
359
+ return chat_response(msg, history, agent_state["config"])
360
+
361
+ submit_btn.click(
362
+ handle_submit,
363
+ inputs=[msg_input, chatbot],
364
+ outputs=[chatbot, msg_input]
365
+ )
366
+
367
+ msg_input.submit(
368
+ handle_submit,
369
+ inputs=[msg_input, chatbot],
370
+ outputs=[chatbot, msg_input]
371
+ )
372
+
373
+ clear_btn.click(
374
+ lambda: ([], ""),
375
+ outputs=[chatbot, msg_input]
376
+ )
377
+
378
+ with gr.Tab("πŸ“ Files"):
379
+ with gr.Row():
380
+ with gr.Column():
381
+ gr.Markdown("### πŸ“€ File Upload")
382
+ gr.Markdown("Upload files for the AI agent to process.")
383
+
384
+ file_output = gr.File(
385
+ file_count="multiple",
386
+ label="Upload Files",
387
+ file_types=[".txt", ".pdf", ".doc", ".docx", ".csv", ".json", ".py", ".js", ".md"]
388
+ )
389
+
390
+ with gr.Row():
391
+ upload_btn = gr.Button("Upload", variant="primary")
392
+
393
+ upload_status = gr.Markdown("")
394
+
395
+ with gr.Tab("ℹ️ About"):
396
+ gr.Markdown("""
397
+ ## πŸ€– JD OpenManus Engine
398
+
399
+ **Version:** 1.0.0
400
+ **Framework:** OpenManus
401
+
402
+ ### Features:
403
+ - πŸ’¬ **Chat Interface** - Interact with AI agents
404
+ - πŸ“ **File Upload** - Process documents and data
405
+ - βš™οΈ **Flexible Configuration** - Connect to any API
406
+
407
+ ### How to Use:
408
+ 1. Configure your API credentials in the Settings tab
409
+ 2. Enter your message in the chat input
410
+ 3. Press Send or hit Enter to get a response
411
+
412
+ ⚠️ **Note:** This is a Web UI wrapper. You'll need to configure a valid API endpoint (like OpenAI, Anthropic, or custom) to use the chat functionality.
413
+ """)
414
+
415
+ return app
416
 
417
+ # ============== Main Entry Point ==============
418
+ def main():
419
+ """Application entry point"""
420
+ print("πŸš€ Starting JD OpenManus Engine...")
421
+ print("=" * 50)
422
+
423
+ app = create_app()
424
+
425
+ # Launch the app
426
+ app.launch(
427
+ server_name="0.0.0.0",
428
+ server_port=7860,
429
+ share=True,
430
+ show_error=True
431
+ )
432
 
433
  if __name__ == "__main__":
434
+ main()