dados do criador de livro
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>$02quest Ultra Writer & PDF Analyzer</title>
<!-- Bibliotecas Externas -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
<style>
:root {
--border-color: #000000;
--bg-main: #ffffff;
--bg-sidebar: #f0f0f0;
--accent: #000000;
--text-main: #111111;
--highlight: #e0e0e0;
}
* { box-sizing: border-box; }
body {
background-color: var(--bg-main);
color: var(--text-main);
font-family: "Courier New", Courier, monospace;
margin: 0; padding: 0;
height: 100vh; overflow: hidden;
-webkit-font-smoothing: antialiased;
}
#root { height: 100%; display: flex; flex-direction: column; }
/* --- Header & Indicators --- */
header {
border-bottom: 4px solid var(--border-color);
height: 70px;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
background: #fff;
z-index: 100;
}
.status-box {
display: flex;
gap: 15px;
font-size: 0.75rem;
font-weight: 900;
}
.metric {
border: 2px solid var(--border-color);
padding: 5px 10px;
background: #eee;
box-shadow: 2px 2px 0px #000;
transition: all 0.3s ease;
}
.metric.active { background: var(--accent); color: #fff; }
/* --- Sidebar --- */
.sidebar {
width: 320px;
border-right: 4px solid var(--border-color);
background: var(--bg-sidebar);
display: flex;
flex-direction: column;
padding: 20px;
overflow-y: auto;
z-index: 50;
}
.sidebar-section {
margin-bottom: 25px;
border-bottom: 2px solid #ccc;
padding-bottom: 15px;
}
.sidebar-title {
font-size: 0.8rem;
font-weight: 900;
margin-bottom: 12px;
text-transform: uppercase;
display: flex;
align-items: center;
justify-content: space-between;
}
/* --- Buttons & Inputs --- */
.btn-retro {
background: #fff;
border: 3px solid var(--border-color);
color: var(--accent);
padding: 10px;
font-family: inherit;
font-weight: 900;
cursor: pointer;
text-transform: uppercase;
font-size: 0.75rem;
box-shadow: 4px 4px 0px var(--border-color);
margin-bottom: 10px;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
transition: transform 0.1s, box-shadow 0.1s;
}
.btn-retro:active:not(:disabled) { box-shadow: 0px 0px 0px; transform: translate(4px, 4px); }
.btn-retro:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-retro.primary { background: var(--accent); color: #fff; }
.btn-retro.danger { background: #ff4444; color: #fff; }
.input-retro {
width: 100%;
border: 3px solid var(--border-color);
padding: 10px;
font-family: inherit;
font-weight: bold;
margin-bottom: 10px;
outline: none;
}
/* --- Chat Area --- */
.chat-container { flex: 1; display: flex; flex-direction: column; background: #fff; position: relative; }
.messages { flex: 1; overflow-y: auto; padding: 40px; display: flex; flex-direction: column; gap: 30px; scroll-behavior: smooth; }
.msg-bubble {
width: 100%;
max-width: 1000px;
margin: 0 auto;
padding: 30px;
border: 4px solid var(--border-color);
background: #fff;
box-shadow: 8px 8px 0px rgba(0,0,0,0.1);
}
.msg-header {
display: flex;
justify-content: space-between;
font-weight: bold;
margin-bottom: 15px;
border-bottom: 2px dashed #ccc;
padding-bottom: 10px;
font-size: 0.85rem;
text-transform: uppercase;
}
.msg-content { line-height: 1.8; font-size: 1.05rem; }
.msg-content p { margin-bottom: 1.5em; text-align: justify; }
.msg-content h1, .msg-content h2, .msg-content h3 { border-left: 10px solid #000; padding-left: 15px; margin: 40px 0 20px 0; }
.msg-content table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
.msg-content th, .msg-content td { border: 2px solid #000; padding: 10px; text-align: left; }
.msg-content th { background-color: #eee; }
.msg-content pre { background: #f4f4f4; padding: 15px; border: 2px solid #000; overflow-x: auto; }
.msg-content code { font-weight: bold; background: #eee; padding: 2px 5px; }
/* --- Controls --- */
.input-area {
border-top: 4px solid var(--border-color);
padding: 20px;
background: #fff;
display: flex;
gap: 15px;
align-items: flex-end;
}
.textarea-box { flex: 1; border: 3px solid var(--border-color); position: relative; }
.textarea-box textarea {
width: 100%; border: none; padding: 15px; font-family: inherit;
font-size: 1rem; outline: none; resize: none; min-height: 60px; max-height: 200px;
}
.pdf-overlay {
position: absolute; top: -35px; left: -3px; background: var(--accent); color: #fff;
padding: 5px 15px; font-size: 0.75rem; font-weight: bold; border: 3px solid #000;
border-bottom: none;
}
/* --- Animations --- */
.blink { animation: blinker 1s step-start infinite; }
@keyframes blinker { 50% { opacity: 0; } }
@media (max-width: 768px) {
.sidebar { display: none; }
}
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect, useRef } = React;
// Configura PDF.js
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
const App = () => {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState('');
const [targetChars, setTargetChars] = useState(50000);
const [isAutoMode, setIsAutoMode] = useState(false);
const [loading, setLoading] = useState(false);
const [pdfContext, setPdfContext] = useState('');
const [pdfName, setPdfName] = useState('');
const messagesEndRef = useRef(null);
const stopRef = useRef(false);
const totalChars = messages.reduce((acc, m) => acc + (m.role === 'bot' ? m.content.length : 0), 0);
const totalPages = Math.floor(totalChars / 3000);
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages, loading]);
// Loop Automático de Geração
useEffect(() => {
if (isAutoMode && totalChars < targetChars && !loading && !stopRef.current) {
const timer = setTimeout(() => {
handleContinueGeneration();
}, 2000); // Pausa leve para evitar rate limit
return () => clearTimeout(timer);
} else if (totalChars >= targetChars) {
setIsAutoMode(false);
}
}, [isAutoMode, totalChars, loading]);
// INTEGRAÇÃO NEURAL: Motor de IA Verdadeiro (Gemini 2.5 Flash)
const callAPI = async (promptText, isContinuation = false) => {
const apiKey = ""; // No Canvas, o ambiente fornece a chave de IA grátis.
const model = "gemini-2.5-flash-preview-09-2025";
const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;
// INSTRUÇÕES DE SISTEMA AVANÇADAS PARA EXTRAÇÃO DE DADOS
let systemInstruction = `Você é o $02QUEST_NEXUS, uma IA brutalista de extração de dados e escrita expansiva.
DIRETRIZES ABSOLUTAS:
1. EXTRAÇÃO DE DADOS: Se o usuário pedir análise, leia os dados, encontre padrões ocultos, categorize informações e apresente insights em tabelas e listas claras (Markdown).
2. ESCRITA EXAUSTIVA: Suas respostas devem ser densas, detalhadas e profissionais. Não economize palavras.
3. ESTILO: Direto, analítico, sem floreios desnecessários. Foco extremo na precisão dos dados.
4. MODO CONTINUAÇÃO: Se instruído a continuar, NÃO crie introduções ("Aqui está a continuação..."). Apenas retome a frase/parágrafo do ponto exato onde parou e aprofunde brutalmente o conteúdo em novas direções.`;
let finalPrompt = promptText;
// Se houver PDF, transformamos a IA num leitor de documentos especialista
if (pdfContext && !isContinuation) {
systemInstruction += `\n5. ATENÇÃO: Você tem acesso ao texto de um PDF carregado. Baseie sua análise estritamente nos dados extraídos abaixo.`;
// Limitamos a extração para não estourar a memória instantaneamente, pegando blocos enormes.
finalPrompt = `[TEXTO EXTRAÍDO DO PDF INÍCIO]\n${pdfContext.substring(0, 40000)}\n[TEXTO EXTRAÍDO DO PDF FIM]\n\nCOMANDO DO USUÁRIO:\n${promptText}`;
} else if (isContinuation) {
finalPrompt = `[MODO_AUTO_WRITER_ATIVO] Continue a expandir o seguinte texto a partir das últimas palavras. Aprofunde os dados, gere novos parágrafos lógicos e mantenha o rigor analítico. TEXTO ANTERIOR: "...${promptText}"`;
}
const payload = {
contents: [{ parts: [{ text: finalPrompt }] }],
systemInstruction: { parts: [{ text: systemInstruction }] }
};
// Sistema de Retry (Tentativas) contra falhas de rede
const fetchWithRetry = async (retries = 3, delay = 1000) => {
try {
const res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!res.ok) throw new Error(`HTTP Error: ${res.status}`);
return await res.json();
} catch (e) {
if (retries > 0) {
await new Promise(r => setTimeout(r, delay));
return fetchWithRetry(retries - 1, delay * 2);
}
throw e;
}
};
const data = await fetchWithRetry();
return data.candidates?.[0]?.content?.parts?.[0]?.text || "[ERRO: NENHUM DADO EXTRAÍDO]";
};
const handleSend = async () => {
if (!input.trim() || loading) return;
stopRef.current = false;
const userText = input;
const time = new Date().toLocaleTimeString();
setMessages(prev => [...prev, { role: 'user', content: userText, time }]);
setInput('');
setLoading(true);
try {
const reply = await callAPI(userText);
setMessages(prev => [...prev, { role: 'bot', content: reply, time: new Date().toLocaleTimeString() }]);
} catch (e) {
console.error(e);
setMessages(prev => [...prev, { role: 'bot', content: "CRITICAL_ERROR: Falha na conexão com o Motor Neural (Gemini).", time: "--:--" }]);
} finally {
setLoading(false);
}
};
const handleContinueGeneration = async () => {
if (loading || stopRef.current) return;
setLoading(true);
const lastBotMsg = [...messages].reverse().find(m => m.role === 'bot');
// Pegamos os últimos 800 caracteres para dar um bom contexto para a IA continuar
const lastSnippet = lastBotMsg ? lastBotMsg.content.slice(-800) : "Início";
try {
const extension = await callAPI(lastSnippet, true);
setMessages(prev => {
const newMsgs = [...prev];
const lastIndex = newMsgs.findLastIndex(m => m.role === 'bot');
if (lastIndex !== -1) {
// Concatena a continuação no mesmo bloco de texto
newMsgs[lastIndex].content += "\n\n" + extension;
} else {
newMsgs.push({ role: 'bot', content: extension, time: new Date().toLocaleTimeString() });
}
return newMsgs;
});
} catch (e) {
console.error(e);
setIsAutoMode(false);
} finally {
setLoading(false);
}
};
const handlePdfUpload = async (e) => {
const file = e.target.files[0];
if (!file) return;
setPdfName(file.name);
setLoading(true); // Feedback visual enquanto processa o PDF
try {
const reader = new FileReader();
reader.onload = async (event) => {
const typedarray = new Uint8Array(event.target.result);
const pdf = await pdfjsLib.getDocument(typedarray).promise;
let fullText = "";
// Extração aprimorada de texto
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const content = await page.getTextContent();
fullText += content.items.map(s => s.str).join(" ") + "\n";
}
// Limpa espaços duplos para otimizar os tokens enviados para a IA
fullText = fullText.replace(/\s+/g, ' ').trim();
setPdfContext(fullText);
setLoading(false);
// Mensagem de sistema avisando que o PDF foi lido
setMessages(prev => [...prev, {
role: 'bot',
content: `**[SYSTEM]** O documento \`${file.name}\` foi processado com sucesso em memória.\n\nTotal extraído: **${fullText.length} caracteres**.\n\nDigite um comando para eu extrair dados, analisar ou resumir este documento.`,
time: new Date().toLocaleTimeString()
}]);
};
reader.readAsArrayBuffer(file);
} catch (error) {
setLoading(false);
alert("Erro ao ler o PDF.");
}
};
const downloadFile = (type) => {
const fullText = messages.map(m => `[${m.role.toUpperCase()}] - ${m.time}\n${m.content}\n`).join("\n---\n");
let blob, filename;
if (type === 'txt') {
blob = new Blob([fullText], { type: 'text/plain' });
filename = `$02quest_data_${Date.now()}.txt`;
} else {
const htmlContent = `<html><head><meta charset="UTF-8"><style>body{font-family:serif; padding:50px; line-height:1.6; max-width: 900px; margin: 0 auto;} h1, h2, h3 {border-bottom:1px solid #000; padding-bottom: 5px;} table {width: 100%; border-collapse: collapse; margin-bottom: 20px;} th, td {border: 1px solid #000; padding: 8px;} th {background: #f0f0f0;}</style></head><body>${marked.parse(fullText)}</body></html>`;
blob = new Blob([htmlContent], { type: 'text/html' });
filename = `$02quest_data_${Date.now()}.html`;
}
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
};
return (
<div id="root">
<header>
<h1 className="site-title">$02QUEST_ULTRA_v4 (NEXUS ENGINE)</h1>
<div className="status-box">
<div className="metric">PÁGINAS_GERADAS: {totalPages}</div>
<div className="metric">CHARS_GERADOS: {totalChars.toLocaleString()}</div>
<div className={`metric ${isAutoMode ? 'active' : ''}`}>
{isAutoMode ? 'AUTO_WRITING_ON' : 'MANUAL_MODE'}
</div>
</div>
</header>
<div style={{ display: 'flex', flex: 1, overflow: 'hidden' }}>
<aside className="sidebar">
<div className="sidebar-section">
<div className="sidebar-title">CONFIGURAR META DE DADOS</div>
<label style={{fontSize: '0.6rem'}}>CARACTERES ALVO (AUTO-WRITER):</label>
<input
type="number"
className="input-retro"
value={targetChars}
onChange={e => setTargetChars(e.target.value)}
min="1000"
/>
<button
className={`btn-retro ${isAutoMode ? 'danger' : 'primary'}`}
onClick={() => {
if (isAutoMode) {
stopRef.current = true;
setIsAutoMode(false);
} else {
if(messages.length === 0) {
alert("Envie um prompt inicial primeiro!");
return;
}
stopRef.current = false;
setIsAutoMode(true);
}
}}
>
{isAutoMode ? 'PARAR PROCESSO' : 'INICIAR AUTO-WRITER'}
</button>
</div>
<div className="sidebar-section">
<div className="sidebar-title">ANÁLISE DE PDF</div>
<input type="file" id="pdf-up" hidden accept=".pdf" onChange={handlePdfUpload} />
<button className="btn-retro" onClick={() => document.getElementById('pdf-up').click()}>
{pdfName ? 'ATUALIZAR PDF' : 'CARREGAR PDF PARA ANÁLISE'}
</button>
{pdfName && (
<div style={{fontSize:'0.65rem', color: '#333', marginTop: '5px', fontWeight: 'bold'}}>
DOCUMENTO ATIVO: <br/><span style={{color: 'blue'}}>{pdfName}</span>
</div>
)}
</div>
<div className="sidebar-section">
<div className="sidebar-title">EXPORTAR DADOS EXTRAÍDOS</div>
<button className="btn-retro" onClick={() => downloadFile('html')}>EXPORTAR COMO HTML</button>
<button className="btn-retro" onClick={() => downloadFile('txt')}>EXPORTAR COMO TXT</button>
</div>
<div className="dev-footer" style={{marginTop: 'auto', paddingTop: '20px'}}>
<div>NÚCLEO_OPERACIONAL:</div>
<span className="dev-name" style={{fontWeight: 'bold'}}>Joaquim Pedro de Morais Filho</span>
<div style={{marginTop:'5px', fontSize:'0.6rem', opacity: 0.6}}>NEXUS AI ENGINE 2026</div>
</div>
</aside>
<main className="chat-container">
<div className="messages">
{messages.length === 0 && (
<div style={{textAlign:'center', marginTop: '15vh', opacity: 0.2}}>
<div style={{fontSize:'6rem'}}>⚙️</div>
<h2>NEXUS ENGINE AGUARDANDO COMANDOS</h2>
<p style={{maxWidth: '500px', margin: '0 auto', fontSize: '0.9rem'}}>
Faça o upload de um PDF para extração de dados pesada, ou digite um comando abaixo para iniciar o processo de escrita contínua.
</p>
</div>
)}
{messages.map((m, i) => (
<div key={i} className="msg-bubble">
<div className="msg-header">
<span>{m.role === 'user' ? 'USER_PROMPT' : 'NEXUS_CORE_OUTPUT'}</span>
<span>{m.time}</span>
</div>
<div className="msg-content" dangerouslySetInnerHTML={{ __html: marked.parse(m.content) }} />
</div>
))}
{loading && (
<div className="msg-bubble" style={{width: 'fit-content'}}>
<span className="blink">▍ PROCESSANDO_DADOS_NEURAIS...</span>
</div>
)}
<div ref={messagesEndRef} />
</div>
<div className="input-area">
<div className="textarea-box">
{pdfName && <div className="pdf-overlay">DATA_SOURCE: PDF ATIVO</div>}
<textarea
placeholder="Ex: 'Extraia as entidades principais deste documento' ou 'Escreva um ensaio sobre buracos negros'..."
value={input}
onChange={e => setInput(e.target.value)}
onKeyDown={e => e.key === 'Enter' && !e.shiftKey && (e.preventDefault(), handleSend())}
/>
</div>
<button
className="btn-retro primary"
style={{width:'80px', height:'60px', marginBottom:0}}
onClick={handleSend}
disabled={loading}
>
SEND
</button>
</div>
</main>
</div>
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
</script>
</body>
</html>