import { useState, useEffect } from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import './App.css'; interface Job { status: 'processing' | 'completed' | 'failed'; result?: { response: { content: Array<{ type: string; text: string }>; }; }; error?: string; } interface Doc { name: string; path: string; } function App() { const [docsUrl, setDocsUrl] = useState(''); const [extractionType, setExtractionType] = useState(''); const [loading, setLoading] = useState(false); const [jobId, setJobId] = useState(null); const [result, setResult] = useState(null); const [error, setError] = useState(null); const [generatedDocs, setGeneratedDocs] = useState([]); const [selectedDoc, setSelectedDoc] = useState(null); const [docContent, setDocContent] = useState(null); const API_BASE = 'http://localhost:8000'; const loadGeneratedDocs = async () => { try { const response = await fetch(`${API_BASE}/api/docs`); const data = await response.json(); setGeneratedDocs(data.docs || []); } catch (err) { console.error('Error loading docs:', err); } }; const loadDocContent = async (filename: string) => { try { const response = await fetch(`${API_BASE}/api/docs/${filename}`); const content = await response.text(); setDocContent(content); setSelectedDoc(filename); } catch (err) { console.error('Error loading doc content:', err); } }; useEffect(() => { loadGeneratedDocs(); }, []); useEffect(() => { if (!jobId) return; const pollInterval = setInterval(async () => { try { const response = await fetch(`${API_BASE}/api/job/${jobId}`); const job: Job = await response.json(); if (job.status === 'completed') { clearInterval(pollInterval); setLoading(false); if (job.result?.response?.content) { const textContent = job.result.response.content .filter(item => item.type === 'text') .map(item => item.text) .join('\n\n'); setResult(textContent); } setJobId(null); loadGeneratedDocs(); } else if (job.status === 'failed') { clearInterval(pollInterval); setLoading(false); setError(job.error || 'Extraction failed'); setJobId(null); } } catch (err) { console.error('Error polling job:', err); } }, 2000); return () => clearInterval(pollInterval); }, [jobId]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); setError(null); setResult(null); try { const response = await fetch(`${API_BASE}/api/extract`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ docsUrl, extractionType }), }); if (!response.ok) { throw new Error('Failed to start extraction'); } const data = await response.json(); setJobId(data.jobId); } catch (err) { setLoading(false); setError(err instanceof Error ? err.message : 'An error occurred'); } }; const exampleTypes = [ 'Quick installation guide', 'Main features overview', 'Getting started tutorial', 'API reference summary', 'Configuration guide', ]; return (

📚 Docs Extractor

AI-powered documentation generator using Zypher Agent

Extract Documentation

setDocsUrl(e.target.value)} required disabled={loading} /> Enter the URL of the documentation you want to extract