specialized-agents / static /medium-report.html
pvanand's picture
Update static/medium-report.html
19bfd93 verified
raw
history blame contribute delete
No virus
17.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blog Writer</title>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css">
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
.container {
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
color: rgba(0,0,0,0.8);
position: relative;
min-height: 100vh;
font-family: source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif;
font-size: 20px;
line-height: 1.58;
color: rgba(0, 0, 0, 0.8);
background-color: #fff;
max-width: 800px;
margin: 0 auto;
padding: 0 20px;
}
/* Typography */
h1, h2, h3, h4, h5, h6 {
font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: 700;
color: rgba(0, 0, 0, 0.84);
letter-spacing: -0.022em;
line-height: 1.2;
}
h1 {
font-size: 40px;
margin-bottom: 0.5em;
}
h2 {
font-size: 32px;
margin-top: 1.5em;
margin-bottom: 0.5em;
}
h3 {
font-size: 26px;
margin-top: 1.5em;
margin-bottom: 0.5em;
}
p {
margin-bottom: 32px;
}
/* Links */
a {
color: #1a8917;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* Input container */
#input-container {
margin-bottom: 40px;
background-color: #f9f9f9;
padding: 32px;
border-radius: 5px;
}
textarea {
width: 100%;
padding: 12px;
margin-bottom: 20px;
border: 1px solid rgba(0, 0, 0, 0.15);
border-radius: 4px;
font-size: 18px;
resize: vertical;
box-sizing: border-box;
font-family: inherit;
}
button {
padding: 12px 24px;
background-color: #1a8917;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 18px;
transition: background-color 0.3s;
}
button:hover {
background-color: #0f6b0f;
}
/* Output container */
#output-container {
display: flex;
flex-direction: column;
gap: 40px;
}
#report-container, #sources-container {
background-color: #fff;
padding: 32px;
border-radius: 5px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-word;
}
/* Sources */
.source-item {
margin-bottom: 32px;
padding: 24px;
background-color: #f9f9f9;
border: 1px solid #e0e0e0;
border-radius: 5px;
position: relative;
cursor: pointer;
transition: box-shadow 0.3s;
}
.source-item:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.source-url {
color: #1a8917;
text-decoration: none;
word-break: break-all;
font-weight: bold;
display: block;
margin-bottom: 16px;
font-size: 18px;
}
.source-content {
margin-top: 16px;
position: relative;
overflow: hidden;
}
.source-snippet {
max-height: 150px;
overflow: hidden;
}
.source-full {
display: none;
}
.expand-indicator {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 40px;
background: linear-gradient(to bottom, rgba(249,249,249,0), rgba(249,249,249,1));
display: flex;
align-items: center;
justify-content: center;
}
.expand-indicator::after {
content: '▼';
font-size: 14px;
color: #666;
}
.expanded .expand-indicator::after {
content: '▲';
}
/* Responsive adjustments */
@media (max-width: 768px) {
.container {
padding: 0 16px;
}
h1 {
font-size: 32px;
}
h2 {
font-size: 24px;
}
#input-container, #report-container, #sources-container {
padding: 24px;
}
}
</style>
<link rel="stylesheet" href="/css/ai-sidebar.css">
</head>
<body>
<div id="app" class="ai-sidebar__container">
<sidebar-component></sidebar-component>
<main class="ai-sidebar__content">
<div class="container">
<div id="input-container">
<h1>Blog Post Generator</h1>
<textarea id="description" rows="4" placeholder="Enter description">write a medium article on nvidia stock performance</textarea>
<button onclick="generateReport()">Generate Blog</button>
</div>
<div id="output-container">
<div id="report-container"></div>
<div id="sources-container"></div>
<div class="button-container">
<button id="downloadBtn" onclick="downloadHTML()" style="display: none;" title="Download HTML Blog">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 15v4c0 1.1.9 2 2 2h14a2 2 0 0 0 2-2v-4M17 9l-5 5-5-5M12 12.8V2.5"/>
</svg>
</button>
</div>
</div>
</div>
</main>
</div>
<script>
async function generateReport() {
const description = document.getElementById('description').value;
const reportContainer = document.getElementById('report-container');
const sourcesContainer = document.getElementById('sources-container');
reportContainer.innerHTML = 'Searching results...';
sourcesContainer.innerHTML = '';
try {
const response = await fetch('https://iresearcher-api.elevatics.cloud/generate_blog', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'text/plain'
},
body: JSON.stringify({
description: description,
user_id: "",
user_name: "multi-agent-research-generate-blog",
internet: true,
output_format: "report_table",
data_format: "Structured data",
generate_charts: true,
output_as_md: true
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let markdown = '';
let metadata = '';
let isReadingMetadata = false;
while (true) {
const { value, done } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
if (chunk.includes('<report-metadata>')) {
isReadingMetadata = true;
metadata = '';
}
if (isReadingMetadata) {
metadata += chunk;
if (chunk.includes('</report-metadata>')) {
isReadingMetadata = false;
processMetadata(metadata);
}
} else {
markdown += chunk;
renderMarkdown(markdown);
}
}
document.getElementById('downloadBtn').style.display = 'block';
} catch (error) {
reportContainer.innerHTML = `Error generating blog: ${error.message}`;
}
}
function renderMarkdown(markdown) {
const reportContainer = document.getElementById('report-container');
const reportContent = markdown.match(/<report>([\s\S]*)<\/report>/);
if (reportContent) {
reportContainer.innerHTML = marked.parse(reportContent[1]);
} else {
reportContainer.innerHTML = marked.parse(markdown);
}
const scripts = reportContainer.getElementsByTagName('script');
Array.from(scripts).forEach(script => {
const newScript = document.createElement('script');
newScript.textContent = script.textContent;
script.parentNode.replaceChild(newScript, script);
});
// Make Plotly charts responsive
const plots = reportContainer.querySelectorAll('.js-plotly-plot');
plots.forEach(plot => {
Plotly.Plots.resize(plot);
});
}
function processMetadata(metadata) {
const sourcesContainer = document.getElementById('sources-container');
const metadataMatch = metadata.match(/all-text-with-urls: (.+)/);
if (metadataMatch) {
const metadataObj = JSON.parse(metadataMatch[1]);
sourcesContainer.innerHTML = '<h2>Sources</h2>';
metadataObj.forEach(([content, url]) => {
if (content.trim() !== "") {
const sourceItem = document.createElement('div');
sourceItem.className = 'source-item';
const snippet = content.length > 400 ? content.substring(0, 400) + '...' : content;
sourceItem.innerHTML = `
<a href="${url}" target="_blank" class="source-url">${url}</a>
<div class="source-content">
<div class="source-snippet">${marked.parse(snippet)}</div>
<div class="source-full">${marked.parse(content)}</div>
<div class="expand-indicator"></div>
</div>
`;
sourcesContainer.appendChild(sourceItem);
const sourceUrl = sourceItem.querySelector('.source-url');
const sourceContent = sourceItem.querySelector('.source-content');
const snippetDiv = sourceItem.querySelector('.source-snippet');
const fullDiv = sourceItem.querySelector('.source-full');
sourceContent.addEventListener('click', function(e) {
if (!sourceItem.classList.contains('expanded')) {
sourceItem.classList.add('expanded');
snippetDiv.style.display = 'none';
fullDiv.style.display = 'block';
} else if (e.clientY > sourceContent.getBoundingClientRect().bottom - 30) {
sourceItem.classList.remove('expanded');
snippetDiv.style.display = 'block';
fullDiv.style.display = 'none';
}
});
sourceUrl.addEventListener('click', function(e) {
e.stopPropagation();
});
}
});
} else {
sourcesContainer.innerHTML = '<h2>Sources</h2><p>No source information available.</p>';
}
}
// Make Plotly charts responsive on window resize
window.addEventListener('resize', function() {
const plots = document.querySelectorAll('.js-plotly-plot');
plots.forEach(plot => {
Plotly.Plots.resize(plot);
});
});
function sanitizeFileName(name) {
// Keep only alphanumeric characters and spaces
name = name.replace(/[^a-z0-9\s]/gi, '');
// Convert to lowercase
name = name.toLowerCase();
// Replace spaces with underscores
name = name.replace(/\s+/g, '_');
// Limit the length to 50 characters
name = name.substring(0, 50);
// If the name is empty after sanitization, use a default name
return name || 'generated_report';
}
async function downloadHTML() {
try {
// Get styles from current document
let css = '';
const styleTags = document.getElementsByTagName('style');
for (let styleTag of styleTags) {
css += styleTag.innerHTML;
}
// Add additional styles for expanded sources and body max-width
css += `
body.report-body {
max-width: 804px;
margin: 0 auto;
}
.source-item {
margin-bottom: 20px;
}
.source-content {
margin-top: 10px;
}
.source-snippet, .expand-indicator {
display: none;
}
.source-full {
display: block;
}
`;
// Clone the document
const htmlContent = document.implementation.createHTMLDocument('Report');
// Set up the basic structure
htmlContent.documentElement.lang = 'en';
const head = htmlContent.head;
const body = htmlContent.body;
body.className = 'report-body';
// Add meta tags
const meta = htmlContent.createElement('meta');
meta.charset = 'UTF-8';
head.appendChild(meta);
const viewport = htmlContent.createElement('meta');
viewport.name = 'viewport';
viewport.content = 'width=device-width, initial-scale=1.0';
head.appendChild(viewport);
// Copy the report content
const reportContainer = document.getElementById('report-container');
body.innerHTML = reportContainer.innerHTML;
// Generate file name from content
let fileName = 'generatedreport';
const headings = body.querySelector('h1, h2, h3');
if (headings) {
fileName = sanitizeFileName(headings.textContent);
}
// Add title
const title = htmlContent.createElement('title');
title.textContent = fileName;
head.appendChild(title);
// Add style
const style = htmlContent.createElement('style');
style.textContent = css;
head.appendChild(style);
// Add necessary scripts
const markedScript = htmlContent.createElement('script');
markedScript.src = 'https://cdn.jsdelivr.net/npm/marked/marked.min.js';
head.appendChild(markedScript);
const plotlyScript = htmlContent.createElement('script');
plotlyScript.src = 'https://cdn.plot.ly/plotly-latest.min.js';
head.appendChild(plotlyScript);
// Copy and modify the sources content
const sourcesContainer = document.getElementById('sources-container');
const sourcesDiv = htmlContent.createElement('div');
sourcesDiv.innerHTML = sourcesContainer.innerHTML;
// Expand all sources
const sourceItems = sourcesDiv.querySelectorAll('.source-item');
sourceItems.forEach(item => {
item.classList.add('expanded');
const snippetDiv = item.querySelector('.source-snippet');
const fullDiv = item.querySelector('.source-full');
if (snippetDiv) snippetDiv.style.display = 'none';
if (fullDiv) fullDiv.style.display = 'block';
});
body.appendChild(sourcesDiv);
// Create blob and download
const blob = new Blob([htmlContent.documentElement.outerHTML], { type: 'text/html' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${fileName}.html`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
} catch (error) {
console.error('Error downloading HTML:', error);
}
}
</script>
</body>
</html>