Spaces:
Sleeping
Sleeping
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>PitchPerfect by Elevatics.ai</title> | |
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> | |
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css"> | |
<style> | |
:root { | |
--primary-color: #007bff; | |
--secondary-color: #6c757d; | |
--background-color: #ffffff; | |
--text-color: #333333; | |
--message-bg-user: #e9ecef; | |
--message-bg-bot: #f8f9fa; | |
--input-bg: #ffffff; | |
--border-color: #dee2e6; | |
--scrollbar-thumb: #adb5bd; | |
--scrollbar-track: #f1f3f5; | |
} | |
body.dark-mode { | |
--primary-color: #4da3ff; | |
--secondary-color: #a1a8ae; | |
--background-color: #1a1a1a; | |
--text-color: #ffffff; | |
--message-bg-user: #2c2c2c; | |
--message-bg-bot: #383838; | |
--input-bg: #2c2c2c; | |
--border-color: #4a4a4a; | |
--scrollbar-thumb: #4a4a4a; | |
--scrollbar-track: #2c2c2c; | |
} | |
body { | |
background-color: var(--background-color); | |
color: var(--text-color); | |
transition: background-color 0.3s, color 0.3s; | |
} | |
.title { | |
font-weight: 700; | |
font-size: 60px ; | |
background: var(--primary-color); | |
-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; | |
} | |
html, body, #app { | |
height: 100%; | |
} | |
.chat-outer-container { | |
max-width: 800px; | |
height: 100vh; | |
margin: 0 auto; | |
display: flex; | |
flex-direction: column; | |
} | |
.chat-container { | |
flex-grow: 1; | |
overflow-y: auto; | |
padding: 1rem; | |
scrollbar-width: thin; | |
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track); | |
} | |
.chat-container::-webkit-scrollbar { | |
width: 8px; | |
} | |
.chat-container::-webkit-scrollbar-track { | |
background: var(--scrollbar-track); | |
} | |
.chat-container::-webkit-scrollbar-thumb { | |
background-color: var(--scrollbar-thumb); | |
border-radius: 4px; | |
border: 2px solid var(--scrollbar-track); | |
} | |
.message { | |
padding: 0.75rem; | |
margin-bottom: 1rem; | |
border-radius: 15px; | |
} | |
.user-message { | |
background-color: var(--message-bg-user); | |
border-radius: 15px 15px 0 15px; | |
} | |
.bot-message { | |
background-color: var(--message-bg-bot); | |
border-radius: 15px 15px 15px 0; | |
} | |
.loading-spinner { | |
width: 3rem; | |
height: 3rem; | |
color: var(--primary-color); | |
} | |
.presentation-iframe { | |
width: 100%; | |
height: 60vh; | |
border: none; | |
} | |
.input-container { | |
padding: 1rem; | |
background-color: var(--input-bg); | |
border-top: 1px solid var(--border-color); | |
position: relative; | |
} | |
.reset-button { | |
position: absolute; | |
top: -40px; | |
right: 10px; | |
background-color: var(--secondary-color); | |
color: var(--background-color); | |
border: none; | |
border-radius: 50%; | |
width: 36px; | |
height: 36px; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
cursor: pointer; | |
transition: background-color 0.3s; | |
} | |
.reset-button:hover { | |
background-color: var(--primary-color); | |
} | |
.mode-toggle { | |
position: fixed; | |
top: 10px; | |
right: 10px; | |
background: none; | |
border: none; | |
color: var(--text-color); | |
font-size: 1.5rem; | |
cursor: pointer; | |
z-index: 1000; | |
} | |
input[type="text"] { | |
background-color: var(--input-bg); | |
color: var(--text-color); | |
border: 1px solid var(--border-color); | |
} | |
input[type="text"]::placeholder { | |
color: var(--secondary-color); | |
} | |
.btn-primary { | |
background-color: var(--primary-color); | |
border-color: var(--primary-color); | |
} | |
.btn-primary:hover { | |
background-color: var(--secondary-color); | |
border-color: var(--secondary-color); | |
} | |
</style> | |
</head> | |
<body> | |
<div id="app"> | |
<button @click="toggleDarkMode" class="mode-toggle" :title="isDarkMode ? 'Switch to Light Mode' : 'Switch to Dark Mode'"> | |
<i :class="isDarkMode ? 'fas fa-sun' : 'fas fa-moon'"></i> | |
</button> | |
<div class="chat-outer-container"> | |
<div class="chat-container"> | |
<h1 class="title">PitchPerfect</h1> | |
<h2 class="subtitle">by Elevatics.ai</h2> | |
<div v-for="(message, index) in chatHistory" :key="index" class="message" :class="message.type === 'user' ? 'user-message' : 'bot-message'"> | |
<div v-if="message.type === 'bot'" v-html="message.content"></div> | |
<div v-else>{{ message.content }}</div> | |
<div v-if="message.html" class="position-relative"> | |
<div class="position-absolute top-0 end-0 m-2"> | |
<div class="dropdown"> | |
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-bs-toggle="dropdown" aria-expanded="false"> | |
Download | |
</button> | |
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton"> | |
<li v-for="format in ['html', 'pdf', 'pptx']" :key="format"> | |
<a class="dropdown-item" href="#" @click.prevent="downloadPresentation(format, message.markdown_presentation)">{{ format.toUpperCase() }}</a> | |
</li> | |
</ul> | |
</div> | |
</div> | |
<iframe :srcdoc="message.html" class="presentation-iframe mt-2"></iframe> | |
</div> | |
</div> | |
<div v-if="isLoading" class="text-center"> | |
<div class="spinner-border loading-spinner" role="status"> | |
<span class="visually-hidden">Loading...</span> | |
</div> | |
</div> | |
</div> | |
<div class="alert alert-danger" v-if="errorMessage">{{ errorMessage }}</div> | |
<div class="input-container"> | |
<form @submit.prevent="sendMessage" class="d-flex"> | |
<input v-model="userInput" type="text" class="form-control me-2" placeholder="Type your message..."> | |
<button type="submit" class="btn btn-primary" :disabled="isLoading">Send</button> | |
</form> | |
<button @click="resetConversation" class="reset-button" title="Reset Conversation"> | |
<i class="fas fa-redo"></i> | |
</button> | |
</div> | |
</div> | |
</div> | |
<script> | |
const { createApp, ref, computed } = Vue | |
createApp({ | |
setup() { | |
const userInput = ref('') | |
const chatHistory = ref([]) | |
const conversationId = ref('') | |
const isLoading = ref(false) | |
const errorMessage = ref('') | |
const AUTH_TOKEN = "44d5c2ac18ced6fc25c1e57dcd06fc0b31fb4ad97bf56e67540671a647465df4" | |
const modelId = 'openai/gpt-4o-mini' | |
const isDarkMode = ref(false) | |
function resetConversation() { | |
chatHistory.value = [] | |
conversationId.value = generateUUID() | |
errorMessage.value = '' | |
} | |
function generateUUID() { | |
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) | |
} | |
function toggleDarkMode() { | |
isDarkMode.value = !isDarkMode.value | |
applyDarkMode() | |
} | |
function applyDarkMode() { | |
if (isDarkMode.value) { | |
document.body.classList.add('dark-mode') | |
} else { | |
document.body.classList.remove('dark-mode') | |
} | |
} | |
async function sendMessage() { | |
if (!userInput.value.trim()) return | |
chatHistory.value.push({ type: 'user', content: userInput.value }) | |
const userMessage = userInput.value | |
userInput.value = '' | |
isLoading.value = true | |
errorMessage.value = '' | |
const payload = { | |
prompt: userMessage, | |
model_id: modelId, | |
conversation_id: conversationId.value, | |
user_id: "web_user" | |
} | |
try { | |
const response = await fetch('https://pvanand-audio-chat.hf.space/presentation-agent', { | |
method: 'POST', | |
headers: { | |
'accept': 'application/json', | |
'X-API-Key': AUTH_TOKEN, | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify(payload) | |
}) | |
if (!response.ok) { | |
const errorText = await response.text() | |
throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`) | |
} | |
const data = await response.json() | |
const botMessage = { | |
type: 'bot', | |
content: data.response ? marked.parse(data.response) : '', | |
html: data.html_presentation || null, | |
markdown_presentation: data.markdown_presentation || null | |
} | |
chatHistory.value.push(botMessage) | |
} catch (error) { | |
errorMessage.value = `Error: ${error.message}` | |
setTimeout(() => { | |
errorMessage.value = '' | |
}, 5000) | |
} finally { | |
isLoading.value = false | |
} | |
} | |
async function downloadPresentation(format, markdown) { | |
if (!markdown) return | |
try { | |
const response = await fetch('https://pvanand-audio-chat.hf.space/convert-md-to-presentation', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
'accept': 'application/json' | |
}, | |
body: JSON.stringify({ | |
markdown: markdown, | |
output_format: format | |
}) | |
}) | |
if (!response.ok) { | |
throw new Error(`HTTP error! status: ${response.status}`) | |
} | |
let blob | |
if (format === 'html') { | |
const data = await response.json() | |
blob = new Blob([data.html], { type: 'text/html' }) | |
} else { | |
blob = await response.blob() | |
} | |
const url = URL.createObjectURL(blob) | |
const a = document.createElement('a') | |
a.href = url | |
a.download = `presentation.${format}` | |
a.click() | |
URL.revokeObjectURL(url) | |
} catch (error) { | |
console.error('Error:', error) | |
alert(`Failed to download ${format.toUpperCase()}`) | |
} | |
} | |
return { | |
userInput, | |
chatHistory, | |
isLoading, | |
errorMessage, | |
isDarkMode, | |
sendMessage, | |
resetConversation, | |
toggleDarkMode, | |
downloadPresentation | |
} | |
} | |
}).mount('#app') | |
</script> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script> | |
</body> | |
</html> |