specialized-agents / static /graph-maker.html
pvanand's picture
Update static/graph-maker.html
ae3619c verified
raw
history blame
17.6 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Architecture Nexus</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap');
:root {
--bg-color: #f0f4f8;
--text-color: #333;
--card-bg: #fff;
--card-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--title-gradient: linear-gradient(45deg, #2862bf, #3fe1ab);
--subtitle-color: #4b5563;
--button-gradient: linear-gradient(45deg, #3b82f6, #10b981);
--button-text: white;
--border-color: #dee2e6;
}
[data-theme="dark"] {
--bg-color: #1a202c;
--text-color: #f8f8f9;
--card-bg: #65738a;
--card-shadow: 0 4px 6px rgba(56, 54, 54, 0.3);
--title-gradient: linear-gradient(45deg, #4299e1, #48bb78);
--subtitle-color: #a0aec0;
--button-gradient: linear-gradient(45deg, #4299e1, #48bb78);
--button-text: #1a202c;
--border-color: #4a5568;
}
body {
font-family: 'Poppins', sans-serif;
background-color: var(--bg-color);
color: var(--text-color);
margin: 0;
padding: 0;
transition: background-color 0.3s, color 0.3s;
}
.title {
font-weight: 700;
font-size: 60px !important;
background: var(--title-gradient);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
text-align: center;
margin: 0;
padding: 2rem 0 0.5rem;
}
.subtitle {
font-size: 24px;
color: var(--subtitle-color);
text-align: center;
}
.generate-button {
background: var(--button-gradient);
border: none;
color: var(--button-text);
font-weight: 600;
}
.generate-button:hover {
opacity: 0.9;
}
.card {
box-shadow: var(--card-shadow);
background-color: var(--card-bg);
border-color: var(--border-color);
}
#mermaid-output {
width: 100%;
height: 100%;
position: relative;
background-color: var(--card-bg);
}
.loading-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, 0.8);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.chart-output {
height: 800px;
width: 100%;
overflow: hidden;
position: relative;
}
#mermaid-output svg { width: 100%; height: 100%; }
@media (max-width: 768px) {
.input-group { flex-direction: column; }
.input-group > * { margin-bottom: 0.5rem; width: 100%; }
}
.fullscreen {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 9999;
background-color: var(--card-bg);
}
.fullscreen #mermaid-output {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: auto;
}
.form-control {
font-size: 1.2rem;
background-color: var(--card-bg);
color: var(--text-color);
min-width: 600px;
border-color: var(--border-color);
}
.chart-controls {
position: absolute;
top: 10px;
right: 10px;
z-index: 1001;
}
.fullscreen .chart-output {
height: 100vh;
}
.theme-toggle {
position: fixed;
top: 10px;
right: 10px;
z-index: 1002;
}
</style>
</head>
<body>
<div id="app" class="container">
<button @click="toggleTheme" class="btn btn-secondary theme-toggle">
<i :class="isDarkMode ? 'bi-sun' : 'bi-moon'"></i>
</button>
<h1 class="title">AI Graph Intelligence</h1>
<h2 class="subtitle">by Elevatics.ai</h2>
<div class="row justify-content-center">
<div class="col-12">
<div class="card mb-4">
<div class="card-body">
<div class="input-group mb-3">
<input
v-model="chartDescription"
:disabled="isInputDisabled"
class="form-control"
placeholder="Describe the chart you want..."
aria-label="Chart description"
/>
<button @click="generateChart" :disabled="isInputDisabled" class="btn generate-button">Generate</button>
</div>
<div class="chart-output position-relative" :class="{ 'fullscreen': isFullscreen }">
<div class="chart-controls btn-group">
<button @click="toggleFullscreen" class="btn btn-secondary" :title="isFullscreen ? 'Exit Fullscreen' : 'Enter Fullscreen'">
<i class="bi" :class="isFullscreen ? 'bi-fullscreen-exit' : 'bi-arrows-fullscreen'"></i>
</button>
<div class="btn-group">
<button type="button" class="btn btn-secondary " data-bs-toggle="dropdown" aria-expanded="false" title="Download">
<i class="bi bi-download"></i>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" @click="downloadChart('png')">Download as PNG</a></li>
<li><a class="dropdown-item" href="#" @click="downloadChart('svg')">Download as SVG</a></li>
</ul>
</div>
</div>
<div id="mermaid-output" class="border rounded">
<!-- Mermaid chart will be rendered here -->
</div>
<div v-if="loading" class="loading-overlay" aria-busy="true">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
<div v-if="error" class="alert alert-danger mt-3" role="alert">{{ error }}</div>
</div>
</div>
</div>
</div>
</div>
<!-- Scripts -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/html2canvas.min.js"></script>
<script src="https://bumbu.me/svg-pan-zoom/dist/svg-pan-zoom.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/uuid/8.3.2/uuid.min.js"></script>
<script>
mermaid.initialize({
startOnLoad: false,
securityLevel: 'strict',
theme: 'default'
});
const { createApp, ref, onMounted } = Vue;
createApp({
setup() {
const chartDescription = ref('');
const error = ref('');
const loading = ref(false);
const isInputDisabled = ref(false);
const isFullscreen = ref(false);
const isDarkMode = ref(false);
const API_ENDPOINT = 'https://pvanand-audio-chat.hf.space/llm-agent';
const API_KEY = '44d5c2ac18ced6fc25c1e57dcd06fc0b31fb4ad97bf56e67540671a647465df4';
const toggleTheme = () => {
isDarkMode.value = !isDarkMode.value;
document.body.setAttribute('data-theme', isDarkMode.value ? 'dark' : 'light');
localStorage.setItem('darkMode', isDarkMode.value);
updateMermaidTheme();
};
const updateMermaidTheme = () => {
mermaid.initialize({
theme: isDarkMode.value ? 'dark' : 'default'
});
if (hasChart()) {
generateChart();
}
};
onMounted(() => {
const savedDarkMode = localStorage.getItem('darkMode');
if (savedDarkMode !== null) {
isDarkMode.value = JSON.parse(savedDarkMode);
document.body.setAttribute('data-theme', isDarkMode.value ? 'dark' : 'light');
updateMermaidTheme();
}
});
const hasChart = () => {
const container = document.getElementById('mermaid-output');
return container && container.innerHTML.trim() !== '';
};
const generateChart = async () => {
if (!chartDescription.value.trim()) {
error.value = 'Please enter a chart description.';
return;
}
loading.value = true;
error.value = '';
isInputDisabled.value = true;
// Clear the previous chart
const container = document.getElementById('mermaid-output');
container.innerHTML = '';
try {
const conversationId = uuid.v4();
const response = await axios.post(API_ENDPOINT, {
prompt: `Generate Mermaid syntax for the following chart description: ${chartDescription.value} enclosed in <chart> </chart> tags. Respond only with the Mermaid syntax, no additional text.`,
system_message: "You are a Mermaid chart Maker. Respond only with the Mermaid syntax enclosed in <chart> </chart> tags. No additional text.",
model_id: "anthropic/claude-3.5-sonnet",
conversation_id: conversationId,
user_id: "ai-chart-generator",
}, {
headers: {
'accept': 'application/json',
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
}
});
const chartContent = extractChartContent(response.data);
if (chartContent) {
await renderMermaid(chartContent);
} else {
error.value = 'No valid chart content found in the response.';
}
} catch (err) {
error.value = 'Error generating chart. Please try again.';
console.error('API Error:', err.message);
} finally {
loading.value = false;
isInputDisabled.value = false;
}
};
const extractChartContent = (responseData) => {
const match = responseData.match(/<chart>([\s\S]*?)<\/chart>/);
if (match && match[1]) {
return match[1].trim().replace(/^```mermaid\n?/, '').replace(/```$/, '').trim();
}
return null;
};
const renderMermaid = async (input) => {
try {
const { svg } = await mermaid.render('mySvgId', input);
const container = document.getElementById('mermaid-output');
container.innerHTML = svg.replace(/[ ]*max-width:[ 0-9\.]*px;/i , '');
svgPanZoom('#mySvgId', {
zoomEnabled: true,
controlIconsEnabled: true,
fit: true,
center: true
});
error.value = '';
} catch (err) {
error.value = 'Error rendering diagram. Please check your Mermaid syntax.';
console.error('Mermaid Error:', err.message);
}
};
const toggleFullscreen = () => {
const element = document.querySelector('.chart-output');
if (!document.fullscreenElement) {
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen();
} else if (element.msRequestFullscreen) {
element.msRequestFullscreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
}
};
const downloadChart = async (format) => {
if (!hasChart()) {
console.error('Chart is not ready for download');
return;
}
const element = document.getElementById('mermaid-output');
const filename = 'chart';
try {
switch (format) {
case 'png':
{
const canvas = await html2canvas(element);
const pngData = canvas.toDataURL('image/png');
downloadURI(pngData, `${filename}.png`);
}
break;
case 'svg':
{
const svgElement = element.querySelector('svg');
if (!svgElement) throw new Error('SVG element not found');
const svgData = new XMLSerializer().serializeToString(svgElement);
const svgBlob = new Blob([svgData], {type: 'image/svg+xml;charset=utf-8'});
const svgUrl = URL.createObjectURL(svgBlob);
downloadURI(svgUrl, `${filename}.svg`);
URL.revokeObjectURL(svgUrl);
}
break;
}
} catch (err) {
console.error('Error downloading chart:', err.message);
}
};
const downloadURI = (uri, name) => {
const link = document.createElement('a');
link.download = name;
link.href = uri;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
document.addEventListener('fullscreenchange', () => {
isFullscreen.value = !!document.fullscreenElement;
});
return {
chartDescription,
error,
loading,
isInputDisabled,
isFullscreen,
isDarkMode,
generateChart,
toggleFullscreen,
downloadChart,
toggleTheme
};
}
}).mount('#app');
</script>
</body>
</html>