Upload folder using huggingface_hub
Browse files
frontend/src/components/views/chat/chat.tsx
CHANGED
|
@@ -30,6 +30,7 @@ import SampleTasks from "./sampletasks";
|
|
| 30 |
import ProgressBar from "./progressbar";
|
| 31 |
import { Tabs } from "antd";
|
| 32 |
import Vision from "./vision";
|
|
|
|
| 33 |
|
| 34 |
// Extend RunStatus for sidebar status reporting
|
| 35 |
type SidebarRunStatus = BaseRunStatus | "final_answer_awaiting_input";
|
|
@@ -1361,6 +1362,15 @@ export default function ChatView({
|
|
| 1361 |
</div>
|
| 1362 |
),
|
| 1363 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1364 |
]}
|
| 1365 |
/>
|
| 1366 |
</div>
|
|
|
|
| 30 |
import ProgressBar from "./progressbar";
|
| 31 |
import { Tabs } from "antd";
|
| 32 |
import Vision from "./vision";
|
| 33 |
+
import Logs from "./logs";
|
| 34 |
|
| 35 |
// Extend RunStatus for sidebar status reporting
|
| 36 |
type SidebarRunStatus = BaseRunStatus | "final_answer_awaiting_input";
|
|
|
|
| 1362 |
</div>
|
| 1363 |
),
|
| 1364 |
},
|
| 1365 |
+
{
|
| 1366 |
+
key: "logs",
|
| 1367 |
+
label: "Logs",
|
| 1368 |
+
children: (
|
| 1369 |
+
<div className="h-[calc(100vh-150px)] w-full">
|
| 1370 |
+
<Logs />
|
| 1371 |
+
</div>
|
| 1372 |
+
),
|
| 1373 |
+
},
|
| 1374 |
]}
|
| 1375 |
/>
|
| 1376 |
</div>
|
frontend/src/components/views/chat/logs.tsx
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import * as React from "react";
|
| 2 |
+
import { getServerUrl } from "../../utils";
|
| 3 |
+
|
| 4 |
+
export default function Logs() {
|
| 5 |
+
const [logs, setLogs] = React.useState<string[]>([]);
|
| 6 |
+
const logsEndRef = React.useRef<HTMLDivElement>(null);
|
| 7 |
+
|
| 8 |
+
React.useEffect(() => {
|
| 9 |
+
// Determine the WebSocket URL based on the server URL
|
| 10 |
+
const serverUrl = getServerUrl();
|
| 11 |
+
const isSecure = serverUrl.startsWith("https://");
|
| 12 |
+
const wsProtocol = isSecure ? "wss://" : "ws://";
|
| 13 |
+
// Usually getServerUrl returns something like http://localhost:8081/api
|
| 14 |
+
const domainAndPath = serverUrl.replace(/^https?:\/\//, "");
|
| 15 |
+
|
| 16 |
+
// Fallback if getServerUrl returns something unexpected
|
| 17 |
+
let wsUrl = "";
|
| 18 |
+
if (domainAndPath.includes("/api")) {
|
| 19 |
+
wsUrl = `${wsProtocol}${domainAndPath}/ws/app_logs`;
|
| 20 |
+
} else {
|
| 21 |
+
wsUrl = `${wsProtocol}${domainAndPath}/api/ws/app_logs`;
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
const socket = new WebSocket(wsUrl);
|
| 25 |
+
|
| 26 |
+
socket.onmessage = (event) => {
|
| 27 |
+
setLogs((prev) => {
|
| 28 |
+
// Keep the last 1000 logs to prevent memory issues
|
| 29 |
+
const newLogs = [...prev, event.data];
|
| 30 |
+
if (newLogs.length > 1000) {
|
| 31 |
+
return newLogs.slice(newLogs.length - 1000);
|
| 32 |
+
}
|
| 33 |
+
return newLogs;
|
| 34 |
+
});
|
| 35 |
+
};
|
| 36 |
+
|
| 37 |
+
socket.onclose = () => {
|
| 38 |
+
console.log("Log WebSocket connection closed");
|
| 39 |
+
};
|
| 40 |
+
|
| 41 |
+
return () => {
|
| 42 |
+
socket.close();
|
| 43 |
+
};
|
| 44 |
+
}, []);
|
| 45 |
+
|
| 46 |
+
React.useEffect(() => {
|
| 47 |
+
// Auto-scroll to bottom when new logs arrive
|
| 48 |
+
if (logsEndRef.current) {
|
| 49 |
+
logsEndRef.current.scrollIntoView({ behavior: "smooth" });
|
| 50 |
+
}
|
| 51 |
+
}, [logs]);
|
| 52 |
+
|
| 53 |
+
return (
|
| 54 |
+
<div className="h-full w-full bg-[#1e1e1e] text-green-400 font-mono text-xs p-4 overflow-y-auto rounded-md shadow-inner">
|
| 55 |
+
{logs.length === 0 ? (
|
| 56 |
+
<div className="opacity-50 text-gray-500 italic">Waiting for logs...</div>
|
| 57 |
+
) : (
|
| 58 |
+
logs.map((log, index) => (
|
| 59 |
+
<div key={index} className="whitespace-pre-wrap mb-1 break-all">
|
| 60 |
+
{log}
|
| 61 |
+
</div>
|
| 62 |
+
))
|
| 63 |
+
)}
|
| 64 |
+
<div ref={logsEndRef} />
|
| 65 |
+
</div>
|
| 66 |
+
);
|
| 67 |
+
}
|
src/magentic_ui/backend/web/routes/ws.py
CHANGED
|
@@ -14,6 +14,44 @@ from ...utils.utils import construct_task
|
|
| 14 |
router = APIRouter()
|
| 15 |
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
@router.websocket("/runs/{run_id}")
|
| 18 |
async def run_websocket(
|
| 19 |
websocket: WebSocket,
|
|
|
|
| 14 |
router = APIRouter()
|
| 15 |
|
| 16 |
|
| 17 |
+
class LogStreamer:
|
| 18 |
+
def __init__(self):
|
| 19 |
+
self.queues: list[asyncio.Queue] = []
|
| 20 |
+
|
| 21 |
+
def sink(self, message):
|
| 22 |
+
record = message.record
|
| 23 |
+
log_str = f"{record['time'].strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]} | {record['level'].name:<8} | {record['name']}:{record['function']}:{record['line']} - {record['message']}"
|
| 24 |
+
for q in self.queues:
|
| 25 |
+
# Non-blocking put, skip if full to avoid blocking the logger
|
| 26 |
+
try:
|
| 27 |
+
q.put_nowait(log_str)
|
| 28 |
+
except asyncio.QueueFull:
|
| 29 |
+
pass
|
| 30 |
+
|
| 31 |
+
log_streamer = LogStreamer()
|
| 32 |
+
logger.add(log_streamer.sink, format="{message}")
|
| 33 |
+
|
| 34 |
+
@router.websocket("/app_logs")
|
| 35 |
+
async def app_logs_websocket(websocket: WebSocket):
|
| 36 |
+
"""WebSocket endpoint to stream application logs"""
|
| 37 |
+
await websocket.accept()
|
| 38 |
+
queue = asyncio.Queue(maxsize=1000)
|
| 39 |
+
log_streamer.queues.append(queue)
|
| 40 |
+
try:
|
| 41 |
+
while True:
|
| 42 |
+
# Wait for a log message
|
| 43 |
+
log_str = await queue.get()
|
| 44 |
+
# Send the log message to the client
|
| 45 |
+
await websocket.send_text(log_str)
|
| 46 |
+
except WebSocketDisconnect:
|
| 47 |
+
pass
|
| 48 |
+
except Exception as e:
|
| 49 |
+
logger.error(f"Error streaming logs: {e}")
|
| 50 |
+
finally:
|
| 51 |
+
if queue in log_streamer.queues:
|
| 52 |
+
log_streamer.queues.remove(queue)
|
| 53 |
+
|
| 54 |
+
|
| 55 |
@router.websocket("/runs/{run_id}")
|
| 56 |
async def run_websocket(
|
| 57 |
websocket: WebSocket,
|