From deacf5991abfb777aae7823a8e7e352fbefdabd0 Mon Sep 17 00:00:00 2001 From: Jay V Date: Mon, 26 May 2025 16:36:30 -0400 Subject: Adding share page --- www/src/components/Header.astro | 57 ++++++ www/src/components/Share.tsx | 353 ++++++++++++++++++++++++++++++++++++++ www/src/pages/share/[...id].astro | 35 ++++ 3 files changed, 445 insertions(+) create mode 100644 www/src/components/Header.astro create mode 100644 www/src/components/Share.tsx create mode 100644 www/src/pages/share/[...id].astro (limited to 'www/src') diff --git a/www/src/components/Header.astro b/www/src/components/Header.astro new file mode 100644 index 000000000..85cdc2ea5 --- /dev/null +++ b/www/src/components/Header.astro @@ -0,0 +1,57 @@ +--- +import config from 'virtual:starlight/user-config'; +import { Icon } from '@astrojs/starlight/components'; +import { HeaderLinks } from 'toolbeam-docs-theme/components'; +import Default from 'toolbeam-docs-theme/overrides/Header.astro'; +import SiteTitle from '@astrojs/starlight/components/SiteTitle.astro'; + +const path = Astro.url.pathname; + +const links = config.social || []; +--- + +{ path.startsWith("/share/") + ?
+
+ +
+
+ +
+
+ : +} + + + diff --git a/www/src/components/Share.tsx b/www/src/components/Share.tsx new file mode 100644 index 000000000..66748bcab --- /dev/null +++ b/www/src/components/Share.tsx @@ -0,0 +1,353 @@ +import { createSignal, onCleanup, onMount, Show, For, createMemo } from "solid-js" + +type MessagePart = { + type: string + text?: string + [key: string]: any +} + +type MessageContent = { + role?: string + parts?: MessagePart[] + metadata?: { + time?: { + created?: number + } + } + [key: string]: any +} + +type Message = { + key: string + content: string +} + +type SessionInfo = { + tokens?: { + input?: number + output?: number + reasoning?: number + } +} + +export default function Share(props: { id: string, api: string }) { + const [messages, setMessages] = createSignal([]) + const [connectionStatus, setConnectionStatus] = createSignal("Disconnected") + const [sessionInfo, setSessionInfo] = createSignal(null) + + onMount(() => { + // Get the API URL from environment + const apiUrl = props.api + const shareId = props.id + + console.log("Mounting Share component with ID:", shareId) + console.log("API URL:", apiUrl) + + if (!shareId) { + console.error("Share ID not found in environment variables") + setConnectionStatus("Error: Share ID not found") + return + } + + if (!apiUrl) { + console.error("API URL not found in environment variables") + setConnectionStatus("Error: API URL not found") + return + } + + let reconnectTimer: number | undefined + let socket: WebSocket | null = null + + // Function to create and set up WebSocket with auto-reconnect + const setupWebSocket = () => { + // Close any existing connection + if (socket) { + socket.close() + } + + setConnectionStatus("Connecting...") + + // Always use secure WebSocket protocol (wss) + const wsBaseUrl = apiUrl.replace(/^https?:\/\//, "wss://") + const wsUrl = `${wsBaseUrl}/share_poll?shareID=${shareId}` + console.log("Connecting to WebSocket URL:", wsUrl) + + // Create WebSocket connection + socket = new WebSocket(wsUrl) + + // Handle connection opening + socket.onopen = () => { + setConnectionStatus("Connected") + console.log("WebSocket connection established") + } + + // Handle incoming messages + socket.onmessage = (event) => { + console.log("WebSocket message received") + try { + const data = JSON.parse(event.data) as Message + + // Check if this is a session info message + if (data.key.startsWith("session/info/")) { + try { + const infoContent = JSON.parse(data.content) as SessionInfo; + setSessionInfo(infoContent); + console.log("Session info updated:", infoContent); + } catch (e) { + console.error("Error parsing session info:", e); + } + } else { + // For all other messages + setMessages((prev) => { + // Check if message with this key already exists + const existingIndex = prev.findIndex(msg => msg.key === data.key) + + if (existingIndex >= 0) { + // Update existing message + const updated = [...prev] + updated[existingIndex] = data + return updated + } else { + // Add new message + return [...prev, data] + } + }) + } + } catch (error) { + console.error("Error parsing WebSocket message:", error) + } + } + + // Handle errors + socket.onerror = (error) => { + console.error("WebSocket error:", error) + setConnectionStatus("Error: Connection failed") + } + + // Handle connection close and reconnection + socket.onclose = (event) => { + console.log(`WebSocket closed: ${event.code} ${event.reason}`) + setConnectionStatus("Disconnected, reconnecting...") + + // Try to reconnect after 2 seconds + clearTimeout(reconnectTimer) + reconnectTimer = window.setTimeout( + setupWebSocket, + 2000, + ) as unknown as number + } + } + + // Initial connection + setupWebSocket() + + // Clean up on component unmount + onCleanup(() => { + console.log("Cleaning up WebSocket connection") + if (socket) { + socket.close() + } + clearTimeout(reconnectTimer) + }) + }) + + return ( +
+

Share: {props.id}

+ +
+

WebSocket Connection

+

+ Status: {connectionStatus()} +

+ +

Live Updates

+ + +
+

Session Information

+
+
+ Input Tokens: {sessionInfo()?.tokens?.input || 0} +
+
+ Output Tokens: {sessionInfo()?.tokens?.output || 0} +
+
+ Reasoning Tokens: {sessionInfo()?.tokens?.reasoning || 0} +
+
+
+
+ +
+ 0} + fallback={

Waiting for messages...

} + > +
    + + {(msg) => ( +
  • +
    + Key: {msg.key} +
    + + {(() => { + try { + const parsed = JSON.parse(msg.content) as MessageContent; + const createdTime = parsed.metadata?.time?.created + ? new Date(parsed.metadata.time.created).toLocaleString() + : 'Unknown time'; + + return ( + <> +
    + Full Content: +
    +                                {JSON.stringify(parsed, null, 2)}
    +                              
    +
    + + {parsed.parts && parsed.parts.length > 0 && ( +
    +
    + Role: {parsed.role || 'Unknown'} + + {createdTime} + +
    + +
    + + {(part, index) => ( +
    + {part.type === "text" ? ( +
    +                                            {part.text}
    +                                          
    + ) : ( +
    +
    + Part type: {part.type} +
    +
    +                                              {JSON.stringify(part, null, 2)}
    +                                            
    +
    + )} +
    + )} +
    +
    +
    + )} + + ); + } catch (e) { + return ( +
    + Content: +
    +                              {msg.content}
    +                            
    +
    + ); + } + })()} +
  • + )} +
    +
+
+
+
+
+ ) +} + diff --git a/www/src/pages/share/[...id].astro b/www/src/pages/share/[...id].astro new file mode 100644 index 000000000..c3bc50d3b --- /dev/null +++ b/www/src/pages/share/[...id].astro @@ -0,0 +1,35 @@ +--- +import config from "virtual:starlight/user-config"; + +import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro'; +import Share from "../../components/Share.tsx"; + +export const prerender = false; + +// TODO: Replace with API URL from environment + +const { id } = Astro.params; +console.log(Astro.url.pathname); +//console.log(config); +--- + + + + + + -- cgit v1.2.3