import React, { useState, useEffect } from 'react' import { initiateLogin, initiateLogout, getCurrentUser, recommend, feedback, stats, getUsers, getContents, } from './api' export default function App() { const [authUser, setAuthUser] = useState(null) const [authChecked, setAuthChecked] = useState(false) const [ssoEnabled, setSsoEnabled] = useState(false) const [userId, setUserId] = useState('') const [contentId, setContentId] = useState('') const [algorithm, setAlgorithm] = useState('linucb') const [users, setUsers] = useState([]) const [contents, setContents] = useState([]) const [result, setResult] = useState(null) const [impressionId, setImpressionId] = useState(null) const [statsData, setStatsData] = useState(null) const [statusMsg, setStatusMsg] = useState('') async function refreshSession() { setStatusMsg('Checking authentication...') try { const auth = await getCurrentUser() setAuthUser(auth.user) setSsoEnabled(auth.sso_enabled) if (auth.user) { await loadLists() } setStatusMsg('') } catch (e) { setStatusMsg('Unable to verify authentication: ' + (e.message || e)) } finally { setAuthChecked(true) } } async function loadLists() { try { const [u, c] = await Promise.all([getUsers(), getContents()]) setUsers(u || []) setContents(c || []) if (u?.length && !userId) setUserId(u[0].user_id) if (c?.length && !contentId) setContentId(c[0].content_id) } catch (e) { setStatusMsg('Failed to load users or contents: ' + (e.message || e)) } } async function handleRecommend() { setStatusMsg('Requesting recommendation...') try { const res = await recommend(userId, contentId, algorithm) setResult(res) setImpressionId(res.impression_id) setStatsData(null) setStatusMsg(`Recommendation delivered in ${Math.round(res.latency_ms)} ms`) } catch (e) { setStatusMsg('Error: ' + (e.message || e)) } } async function handleFeedback(reward = 1.0) { if (!impressionId) { setStatusMsg('No recommendation available for feedback') return } setStatusMsg('Sending feedback...') try { await feedback(impressionId, reward) setStatusMsg('Feedback recorded successfully') } catch (e) { setStatusMsg('Error: ' + (e.message || e)) } } async function handleStats() { setStatusMsg('Loading production stats...') try { const s = await stats() setStatsData(s) setStatusMsg('Stats loaded') } catch (e) { setStatusMsg('Error: ' + (e.message || e)) } } useEffect(() => { refreshSession() }, []) const isReady = authChecked && (!!authUser || !authUser) return (

Artwork Bandit

Recommendation Studio

A modern SSO dashboard for artwork recommendation, feedback, and performance insights.

{authChecked ? ( authUser ? ( <>
{authUser.name} {authUser.email}
) : ssoEnabled ? ( ) : (
SSO is not configured Please set SSO environment variables to enable login.
) ) : ( Checking login... )}
{!authUser ? (

Secure access with SSO

Sign in to access the artwork recommendation engine, track model performance, and share feedback securely.

Configured backend SSO keeps your recommendation experiments protected while preserving the same fast feedback loop.

{!ssoEnabled &&

Set SSO_DISCOVERY_URL, SSO_CLIENT_ID, and SSO_CLIENT_SECRET to enable login.

}
) : (

Recommendation controls

Latest recommendation

{result ? (
{result.artwork_id}

{result.artwork_id}

Algorithm: {result.algorithm}

Impression ID: {result.impression_id}

Latency: {Math.round(result.latency_ms)} ms

) : (

No recommendation requested yet. Use the controls to generate your first prediction.

)}

Live KPI dashboard

{statsData ? (
Total impressions {statsData.total_impressions}
Total clicks {statsData.total_clicks}
Overall CTR {(statsData.overall_ctr * 100).toFixed(1)}%
) : (

Run the stats query to inspect production performance.

)}
)}
) }