Claude Code Claude Opus 4.6 commited on
Commit
72a64e0
·
1 Parent(s): 009288e

Claude Code: serve dashboard at root endpoint

Browse files

- Add StaticFiles mount for /static directory
- Update root endpoint to serve dashboard index.html
- Add /api/status, /api/logs, /api/chat endpoints for dashboard
- Add WebSocket endpoint /ws for real-time updates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +68 -80
app.py CHANGED
@@ -5,17 +5,26 @@ FastAPI application serving on port 7860.
5
  """
6
  from fastapi import FastAPI
7
  from fastapi.middleware.cors import CORSMiddleware
 
 
 
8
  from pydantic import BaseModel
9
  import json
10
  import os
11
  import sys
12
  from datetime import datetime
 
13
 
14
  # Add /app to sys.path for proper package imports
15
  sys.path.insert(0, "/app")
16
 
17
  app = FastAPI(title="HuggingClaw - Cain", version="1.0.0")
18
 
 
 
 
 
 
19
  # CORS enabled for frontend access
20
  app.add_middleware(
21
  CORSMiddleware,
@@ -68,87 +77,14 @@ def get_brain_response(message: str) -> str:
68
  return f"Brain error: {str(e)}"
69
 
70
 
71
- @app.get("/", response_class=str)
72
  async def root():
73
- """Root endpoint returning simple HTML welcome message."""
74
- return """
75
- <!DOCTYPE html>
76
- <html>
77
- <head>
78
- <title>Cain - HuggingClaw</title>
79
- <style>
80
- body {
81
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
82
- background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
83
- min-height: 100vh;
84
- display: flex;
85
- justify-content: center;
86
- align-items: center;
87
- margin: 0;
88
- color: #eaeaea;
89
- }
90
- .container {
91
- text-align: center;
92
- padding: 40px;
93
- background: rgba(255, 255, 255, 0.05);
94
- border-radius: 20px;
95
- backdrop-filter: blur(10px);
96
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
97
- max-width: 500px;
98
- }
99
- h1 {
100
- margin: 0 0 10px 0;
101
- font-size: 2.5em;
102
- background: linear-gradient(90deg, #00d4ff, #7b2cbf);
103
- -webkit-background-clip: text;
104
- -webkit-text-fill-color: transparent;
105
- background-clip: text;
106
- }
107
- .subtitle {
108
- color: #a0a0a0;
109
- margin-bottom: 30px;
110
- font-size: 1.1em;
111
- }
112
- .status {
113
- display: inline-block;
114
- padding: 10px 20px;
115
- background: rgba(0, 212, 255, 0.1);
116
- border: 1px solid rgba(0, 212, 255, 0.3);
117
- border-radius: 25px;
118
- margin: 10px;
119
- font-size: 0.9em;
120
- }
121
- .status span {
122
- color: #00d4ff;
123
- font-weight: bold;
124
- }
125
- .links {
126
- margin-top: 30px;
127
- }
128
- .links a {
129
- color: #00d4ff;
130
- text-decoration: none;
131
- margin: 0 15px;
132
- font-size: 0.95em;
133
- }
134
- .links a:hover {
135
- text-decoration: underline;
136
- }
137
- </style>
138
- </head>
139
- <body>
140
- <div class="container">
141
- <h1>Cain</h1>
142
- <div class="subtitle">HuggingClaw Interaction Agent</div>
143
- <div class="status">Status: <span>Running</span></div>
144
- <div class="links">
145
- <a href="/status">/status</a>
146
- <a href="/docs">API Docs</a>
147
- </div>
148
- </div>
149
- </body>
150
- </html>
151
- """
152
 
153
 
154
  @app.get("/status")
@@ -162,6 +98,39 @@ async def status():
162
  }
163
 
164
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  @app.post("/chat")
166
  async def chat(msg: ChatMessage):
167
  """Chat endpoint - routes to brain_minimal.py and returns response."""
@@ -173,6 +142,25 @@ async def chat(msg: ChatMessage):
173
  }
174
 
175
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  if __name__ == "__main__":
177
  import uvicorn
178
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
5
  """
6
  from fastapi import FastAPI
7
  from fastapi.middleware.cors import CORSMiddleware
8
+ from fastapi.staticfiles import StaticFiles
9
+ from fastapi.responses import FileResponse
10
+ from fastapi import WebSocket
11
  from pydantic import BaseModel
12
  import json
13
  import os
14
  import sys
15
  from datetime import datetime
16
+ import asyncio
17
 
18
  # Add /app to sys.path for proper package imports
19
  sys.path.insert(0, "/app")
20
 
21
  app = FastAPI(title="HuggingClaw - Cain", version="1.0.0")
22
 
23
+ # Mount static files directory
24
+ static_dir = "/app/static"
25
+ if os.path.exists(static_dir):
26
+ app.mount("/static", StaticFiles(directory=static_dir), name="static")
27
+
28
  # CORS enabled for frontend access
29
  app.add_middleware(
30
  CORSMiddleware,
 
77
  return f"Brain error: {str(e)}"
78
 
79
 
80
+ @app.get("/", response_class=FileResponse)
81
  async def root():
82
+ """Root endpoint serving the dashboard."""
83
+ index_path = f"{static_dir}/index.html"
84
+ if os.path.exists(index_path):
85
+ return FileResponse(index_path)
86
+ # Fallback if dashboard not found
87
+ return FileResponse("/app/index.html")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
 
90
  @app.get("/status")
 
98
  }
99
 
100
 
101
+ # Dashboard API endpoints
102
+ @app.get("/api/status")
103
+ async def api_status():
104
+ """Dashboard API - get status and personality."""
105
+ status_data = get_cain_status()
106
+ return {
107
+ "status": status_data,
108
+ "personality": {
109
+ "name": "Cain",
110
+ "role": "Interaction Agent",
111
+ "tone": "friendly",
112
+ "response_style": "conversational"
113
+ },
114
+ "timestamp": datetime.utcnow().isoformat() + "+00:00"
115
+ }
116
+
117
+
118
+ @app.get("/api/logs")
119
+ async def api_logs():
120
+ """Dashboard API - get agent logs."""
121
+ return {"logs": []}
122
+
123
+
124
+ @app.post("/api/chat")
125
+ async def api_chat(msg: ChatMessage):
126
+ """Dashboard API - chat endpoint."""
127
+ response_text = get_brain_response(msg.message)
128
+ return {
129
+ "agent_response": response_text,
130
+ "timestamp": datetime.utcnow().isoformat() + "+00:00"
131
+ }
132
+
133
+
134
  @app.post("/chat")
135
  async def chat(msg: ChatMessage):
136
  """Chat endpoint - routes to brain_minimal.py and returns response."""
 
142
  }
143
 
144
 
145
+ @app.websocket("/ws")
146
+ async def websocket_endpoint(websocket: WebSocket):
147
+ """WebSocket endpoint for real-time dashboard updates."""
148
+ await websocket.accept()
149
+ try:
150
+ while True:
151
+ # Send heartbeat every 5 seconds
152
+ status_data = get_cain_status()
153
+ await websocket.send_json({
154
+ "type": "heartbeat",
155
+ "status": status_data
156
+ })
157
+ await asyncio.sleep(5)
158
+ except Exception as e:
159
+ pass
160
+ finally:
161
+ await websocket.close()
162
+
163
+
164
  if __name__ == "__main__":
165
  import uvicorn
166
  uvicorn.run(app, host="0.0.0.0", port=7860)