Team Ai
Apppublic

AddisonJi/claude-code-training

sourceHugging Facemitupdated 8mo agoView on Hugging Face
0likes
index.html510 linesDownload Raw Back to frontend
1<!DOCTYPE html>2<html lang="en">3<head>4    <meta charset="UTF-8">5    <meta name="viewport" content="width=device-width, initial-scale=1.0">6    <title>Company Intel Agent</title>7    <style>8        @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=DM+Sans:wght@400;500;600;700&display=swap');9 10        :root {11            --bg: #0a0a0f;12            --surface: #12121a;13            --surface-2: #1a1a26;14            --border: #2a2a3a;15            --text: #e4e4ef;16            --text-dim: #7a7a8f;17            --accent: #6c63ff;18            --accent-glow: rgba(108, 99, 255, 0.15);19            --green: #4ade80;20            --yellow: #fbbf24;21            --blue: #60a5fa;22            --red: #f87171;23            --orange: #fb923c;24        }25 26        * { margin: 0; padding: 0; box-sizing: border-box; }27 28        body {29            font-family: 'DM Sans', sans-serif;30            background: var(--bg);31            color: var(--text);32            min-height: 100vh;33        }34 35        /* ===== HEADER ===== */36        .header {37            padding: 24px 40px;38            border-bottom: 1px solid var(--border);39            display: flex;40            align-items: center;41            gap: 12px;42        }43        .header h1 {44            font-size: 20px;45            font-weight: 600;46            letter-spacing: -0.02em;47        }48        .header .badge {49            font-size: 11px;50            font-family: 'JetBrains Mono', monospace;51            background: var(--accent-glow);52            color: var(--accent);53            padding: 3px 10px;54            border-radius: 20px;55            border: 1px solid rgba(108, 99, 255, 0.25);56        }57 58        /* ===== MAIN LAYOUT ===== */59        .main {60            display: grid;61            grid-template-columns: 380px 1fr;62            height: calc(100vh - 73px);63        }64 65        /* ===== LEFT PANEL - INPUT ===== */66        .input-panel {67            padding: 28px;68            border-right: 1px solid var(--border);69            display: flex;70            flex-direction: column;71            gap: 20px;72            overflow-y: auto;73        }74 75        .section-label {76            font-size: 11px;77            font-weight: 600;78            text-transform: uppercase;79            letter-spacing: 0.08em;80            color: var(--text-dim);81            margin-bottom: 4px;82        }83 84        .input-group {85            display: flex;86            flex-direction: column;87            gap: 6px;88        }89 90        .input-group label {91            font-size: 13px;92            font-weight: 500;93            color: var(--text-dim);94        }95 96        .input-group input,97        .input-group textarea {98            background: var(--surface);99            border: 1px solid var(--border);100            border-radius: 8px;101            padding: 10px 14px;102            color: var(--text);103            font-family: 'DM Sans', sans-serif;104            font-size: 14px;105            transition: border-color 0.2s;106        }107        .input-group input:focus,108        .input-group textarea:focus {109            outline: none;110            border-color: var(--accent);111            box-shadow: 0 0 0 3px var(--accent-glow);112        }113        .input-group textarea {114            resize: vertical;115            min-height: 80px;116        }117 118        .btn-primary {119            background: var(--accent);120            color: white;121            border: none;122            border-radius: 8px;123            padding: 12px 20px;124            font-size: 14px;125            font-weight: 600;126            font-family: 'DM Sans', sans-serif;127            cursor: pointer;128            transition: all 0.2s;129            display: flex;130            align-items: center;131            justify-content: center;132            gap: 8px;133        }134        .btn-primary:hover { background: #5b52e8; }135        .btn-primary:disabled {136            opacity: 0.5;137            cursor: not-allowed;138        }139 140        /* Quick action buttons */141        .quick-actions {142            display: flex;143            flex-direction: column;144            gap: 8px;145        }146        .btn-quick {147            background: var(--surface);148            color: var(--text-dim);149            border: 1px solid var(--border);150            border-radius: 8px;151            padding: 10px 14px;152            font-size: 13px;153            font-family: 'DM Sans', sans-serif;154            cursor: pointer;155            text-align: left;156            transition: all 0.2s;157        }158        .btn-quick:hover {159            border-color: var(--accent);160            color: var(--text);161            background: var(--accent-glow);162        }163 164        /* ===== RIGHT PANEL - AGENT LOG + RESULT ===== */165        .output-panel {166            display: flex;167            flex-direction: column;168            height: 100%;169            overflow: hidden;170        }171 172        /* Agent Log - terminal style */173        .log-header {174            padding: 16px 28px;175            border-bottom: 1px solid var(--border);176            display: flex;177            align-items: center;178            gap: 8px;179        }180        .log-header .dot {181            width: 8px;182            height: 8px;183            border-radius: 50%;184            background: var(--text-dim);185        }186        .log-header .dot.active { background: var(--green); }187        .log-header span {188            font-size: 12px;189            font-family: 'JetBrains Mono', monospace;190            color: var(--text-dim);191        }192 193        .log-container {194            flex: 1;195            overflow-y: auto;196            padding: 20px 28px;197            font-family: 'JetBrains Mono', monospace;198            font-size: 13px;199            line-height: 1.7;200        }201 202        .log-entry {203            margin-bottom: 4px;204            animation: fadeIn 0.3s ease;205        }206 207        @keyframes fadeIn {208            from { opacity: 0; transform: translateY(4px); }209            to { opacity: 1; transform: translateY(0); }210        }211 212        .log-agent {213            font-weight: 600;214            margin-right: 6px;215        }216        .log-agent.router { color: var(--accent); }217        .log-agent.competitor { color: var(--orange); }218        .log-agent.founder { color: var(--blue); }219        .log-agent.business { color: var(--green); }220        .log-agent.tavily { color: #00d4aa; }221        .log-agent.system { color: var(--text-dim); }222 223        .log-event-thinking { color: var(--yellow); }224        .log-event-decision { color: var(--green); }225        .log-event-tool_call { color: var(--blue); }226        .log-event-tool_result { color: var(--text-dim); }227        .log-event-error { color: var(--red); }228 229        /* Final answer section */230        .result-section {231            border-top: 1px solid var(--border);232            padding: 24px 28px;233            max-height: 45%;234            overflow-y: auto;235        }236        .result-section.hidden { display: none; }237 238        .result-header {239            font-size: 12px;240            font-weight: 600;241            text-transform: uppercase;242            letter-spacing: 0.08em;243            color: var(--accent);244            margin-bottom: 12px;245        }246        .result-content {247            font-size: 14px;248            line-height: 1.8;249            white-space: pre-wrap;250        }251 252        /* ===== EMPTY STATE ===== */253        .empty-state {254            display: flex;255            flex-direction: column;256            align-items: center;257            justify-content: center;258            height: 100%;259            color: var(--text-dim);260            gap: 12px;261        }262        .empty-state .icon { font-size: 40px; opacity: 0.4; }263        .empty-state p { font-size: 14px; }264 265        /* ===== SCROLLBAR ===== */266        ::-webkit-scrollbar { width: 6px; }267        ::-webkit-scrollbar-track { background: transparent; }268        ::-webkit-scrollbar-thumb {269            background: var(--border);270            border-radius: 3px;271        }272 273        /* ===== LOADING SPINNER ===== */274        .spinner {275            display: inline-block;276            width: 14px;277            height: 14px;278            border: 2px solid rgba(255,255,255,0.3);279            border-top-color: white;280            border-radius: 50%;281            animation: spin 0.6s linear infinite;282        }283        @keyframes spin { to { transform: rotate(360deg); } }284    </style>285</head>286<body>287    <div class="header">288        <h1>๐Ÿ” Company Intel Agent</h1>289        <span class="badge">Claude + Tavily</span>290    </div>291 292    <div class="main">293        <!-- LEFT: Input Panel -->294        <div class="input-panel">295            <div class="section-label">Company Information</div>296 297            <div class="input-group">298                <label>Company Name</label>299                <input type="text" id="companyName" placeholder="e.g. Stripe" />300            </div>301 302            <div class="input-group">303                <label>Website (optional)</label>304                <input type="text" id="website" placeholder="e.g. stripe.com" />305            </div>306 307            <div class="input-group">308                <label>Your Question</label>309                <textarea id="query" placeholder="e.g. Who are their main competitors?"></textarea>310            </div>311 312            <button class="btn-primary" id="analyzeBtn" onclick="analyze()">313                ๐Ÿš€ Analyze314            </button>315 316            <div class="section-label" style="margin-top: 12px;">Quick Actions</div>317            <div class="quick-actions">318                <button class="btn-quick" onclick="quickAction('Who are the main competitors?')">319                    ๐Ÿข Find Competitors320                </button>321                <button class="btn-quick" onclick="quickAction('Who founded this company and who is the current CEO?')">322                    ๐Ÿ‘ค Find Founders323                </button>324                <button class="btn-quick" onclick="quickAction('What does this company do? Describe their business model and main products.')">325                    ๐Ÿ“Š Business Overview326                </button>327            </div>328 329            <!-- 330                ๐ŸŽฏ VIBE CODING CHALLENGE: 331                Add more quick action buttons here!332                For example: "Find funding history", "Find recent news"333                334                Hint: just copy a btn-quick button and change the text.335                For a REAL challenge: add a new agent in backend/agents/ 336                to handle the new intent type!337            -->338        </div>339 340        <!-- RIGHT: Agent Output -->341        <div class="output-panel">342            <div class="log-header">343                <div class="dot" id="statusDot"></div>344                <span id="statusText">Waiting for input...</span>345            </div>346 347            <div class="log-container" id="logContainer">348                <div class="empty-state" id="emptyState">349                    <div class="icon">๐Ÿค–</div>350                    <p>Enter a company name and question to see agents in action</p>351                </div>352            </div>353 354            <div class="result-section hidden" id="resultSection">355                <div class="result-header">๐Ÿ“‹ Final Answer</div>356                <div class="result-content" id="resultContent"></div>357            </div>358        </div>359    </div>360 361    <script>362        // ===== State =====363        let isRunning = false;364 365        // ===== Quick Actions =====366        function quickAction(queryText) {367            document.getElementById('query').value = queryText;368        }369 370        // ===== Main Analysis Function =====371        async function analyze() {372            if (isRunning) return;373 374            const companyName = document.getElementById('companyName').value.trim();375            const website = document.getElementById('website').value.trim();376            const query = document.getElementById('query').value.trim();377 378            if (!companyName || !query) {379                alert('Please enter a company name and your question.');380                return;381            }382 383            // Reset UI384            isRunning = true;385            const btn = document.getElementById('analyzeBtn');386            btn.disabled = true;387            btn.innerHTML = '<span class="spinner"></span> Analyzing...';388 389            const emptyState = document.getElementById('emptyState');390            if (emptyState) emptyState.style.display = 'none';391            document.getElementById('logContainer').innerHTML = '';392            document.getElementById('resultSection').classList.add('hidden');393            document.getElementById('resultContent').textContent = '';394            setStatus(true, 'Agents working...');395 396            try {397                const response = await fetch('/analyze', {398                    method: 'POST',399                    headers: { 'Content-Type': 'application/json' },400                    body: JSON.stringify({401                        company_name: companyName,402                        website: website || null,403                        query: query,404                    }),405                });406 407                if (!response.ok) {408                    throw new Error(`Server error: ${response.status}`);409                }410 411                const reader = response.body.getReader();412                const decoder = new TextDecoder();413                let buffer = '';414 415                while (true) {416                    const { done, value } = await reader.read();417                    if (done) break;418 419                    const chunk = decoder.decode(value, { stream: true });420                    buffer += chunk;421 422                    // Process all complete SSE events in buffer423                    // SSE events end with double newline (handle \r\n and \n)424                    let eventEnd;425                    while ((eventEnd = buffer.search(/\n\n|\r\n\r\n/)) !== -1) {426                        const eventBlock = buffer.slice(0, eventEnd);427                        buffer = buffer.slice(eventEnd + (buffer.slice(eventEnd, eventEnd + 4).includes('\r') ? 4 : 2));428 429                        // Extract data line from SSE event block430                        const lines = eventBlock.split(/\r?\n/);431                        const dataLine = lines.find(line => line.startsWith('data:'));432                        if (dataLine) {433                            const dataStr = dataLine.slice(5).trim();434                            try {435                                const data = JSON.parse(dataStr);436                                handleEvent(data);437                            } catch (e) {438                                // Skip malformed JSON439                            }440                        }441                    }442                }443            } catch (error) {444                addLog('System', 'error', `โŒ Connection error: ${error.message}`);445            }446 447            // Done448            isRunning = false;449            btn.disabled = false;450            btn.innerHTML = '๐Ÿš€ Analyze';451            setStatus(false, 'Done');452        }453 454        // ===== Handle SSE Events =====455        function handleEvent(data) {456            const { agent, event, content } = data;457 458            if (event === 'final_answer') {459                // Show in the result section460                document.getElementById('resultSection').classList.remove('hidden');461                document.getElementById('resultContent').textContent = content;462                addLog(agent, 'decision', 'โœ… Analysis complete - see results below');463            } else {464                addLog(agent, event, content);465            }466        }467 468        // ===== Add Log Entry =====469        function addLog(agent, event, content) {470            const container = document.getElementById('logContainer');471            const entry = document.createElement('div');472            entry.className = 'log-entry';473 474            const agentClass = agent.toLowerCase().includes('router') ? 'router'475                : agent.toLowerCase().includes('competitor') ? 'competitor'476                : agent.toLowerCase().includes('founder') ? 'founder'477                : agent.toLowerCase().includes('business') ? 'business'478                : agent.toLowerCase().includes('tavily') ? 'tavily'479                : 'system';480 481            entry.innerHTML = `<span class="log-agent ${agentClass}">[${agent}]</span><span class="log-event-${event}">${escapeHtml(content)}</span>`;482            container.appendChild(entry);483 484            // Auto-scroll to bottom485            container.scrollTop = container.scrollHeight;486        }487 488        // ===== Helpers =====489        function setStatus(active, text) {490            document.getElementById('statusDot').className = active ? 'dot active' : 'dot';491            document.getElementById('statusText').textContent = text;492        }493 494        function escapeHtml(text) {495            const div = document.createElement('div');496            div.textContent = text;497            return div.innerHTML;498        }499 500        // Allow Enter key in query field501        document.getElementById('query').addEventListener('keydown', (e) => {502            if (e.key === 'Enter' && !e.shiftKey) {503                e.preventDefault();504                analyze();505            }506        });507    </script>508</body>509</html>510