Spaces:
Running
Running
import { Client } from 'https://cdn.jsdelivr.net/npm/@gradio/[email protected]/+esm' | |
import MarkdownIt from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm' | |
const md = new MarkdownIt(); | |
const majorArcana = [ | |
"The Fool", | |
"The Magician", | |
"The High Priestess", | |
"The Empress", | |
"The Emperor", | |
"The Hierophant", | |
"The Lovers", | |
"The Chariot", | |
"Strength", | |
"The Hermit", | |
"Wheel of Fortune", | |
"Justice", | |
"The Hanged Man", | |
"Death", | |
"Temperance", | |
"The Devil", | |
"The Tower", | |
"The Star", | |
"The Moon", | |
"The Sun", | |
"Judgement", | |
"The World" | |
]; | |
const ask = async function (question, card1, card2, card3) { | |
const predictionElement = document.getElementById('response-output'); | |
const llmSpace = document.getElementById('llm-server').value; | |
if (!question) { | |
predictionElement.textContent = "Please enter a question first."; | |
return; | |
} | |
predictionElement.innerHTML = '<span>.</span><span>.</span><span>.</span>'; | |
try { | |
const client = await Client.connect(llmSpace); | |
const result = await client.submit("/chat", { | |
message: `${question}`, | |
system_prompt: `You are multilingual tarot card reader and fortune teller. You picked from your Tarot Deck **${majorArcana[card1]}**, **${majorArcana[card2]}**, **${majorArcana[card3]}**. Answer to the question using same language and format using Markdown.`, | |
max_new_tokens: 288, | |
// temperature: 0.7, | |
// top_p: 0.95, | |
// top_k: 50, | |
// repetition_penalty: 1, | |
}); | |
let fullResponse = ''; | |
for await (const msg of result) { | |
if (msg.type === "data") { | |
fullResponse = msg.data[0]; | |
predictionElement.innerHTML = md.render(fullResponse); | |
} else { | |
console.log(msg) | |
} | |
} | |
} catch (error) { | |
console.error('Error:', error); | |
predictionElement.textContent = "The cards are clouded. Please try again later."; | |
} | |
} | |
document.addEventListener('DOMContentLoaded', () => { | |
const welcomeDialog = document.getElementById('welcome'); | |
const deckSelectionDialog = document.getElementById('deck-selection'); | |
const questionDialog = document.getElementById('question'); | |
const responseDialog = document.getElementById('response'); | |
const cardsContainer = document.getElementById("cards-container"); | |
const settingsDialog = document.getElementById('settings'); | |
// Funzione per aprire il dialogo di benvenuto | |
function openWelcomeDialog() { | |
welcomeDialog.showModal(); | |
} | |
// Funzione per aprire il dialogo di selezione del mazzo | |
function openDeckSelectionDialog() { | |
welcomeDialog.close(); // Chiudi il dialogo di benvenuto | |
deckSelectionDialog.showModal(); // Apri il dialogo di selezione del mazzo | |
} | |
const fortuneTellerProfiles = document.querySelectorAll('.fortune-teller-profile'); | |
fortuneTellerProfiles.forEach(profile => { | |
const fortuneTellerId = profile.getAttribute('data-fortune-teller-id'); | |
profile.addEventListener('click', (event) => { | |
changeBackgroundImage(fortuneTellerId); // Cambia il background-image di body | |
}); | |
}); | |
const CARDS_WIDTH = 512; | |
const CARDS_HEIGHT = 768; | |
const CARDS_NUMERALS = ['0', 'I', 'II', 'III', 'IV', '', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII']; | |
function resetDeck() { | |
cardsContainer.innerHTML = ''; // Rimuove le card esistenti | |
for (let i = 0; i < 22; i++) { | |
const card = document.createElement("div"); | |
card.classList.add("card"); | |
card.id = `card-${i}`; | |
card.innerHTML = `<h2>${CARDS_NUMERALS[i]}</h2>`; | |
const randomX = parseInt(1 + Math.random() * 8) * 10; | |
const randomY = parseInt(3 + Math.random() * 4) * 10; | |
card.style.top = randomY + "lvh"; | |
card.style.left = randomX + "lvw"; | |
card.style.backgroundPositionX = -(parseInt(i % 11) * CARDS_WIDTH) + "px"; | |
card.style.backgroundPositionY = -(parseInt(i / 11) * CARDS_HEIGHT) + "px"; | |
cardsContainer.appendChild(card); | |
} | |
} | |
// Funzione per cambiare il background-image di body in base all'ID del cartomante | |
function changeBackgroundImage(fortuneTellerId) { | |
selectedButton.removeAttribute('disabled'); | |
const oldSelectedItem = document.querySelector('.fortune-teller-profile.selected'); | |
if (oldSelectedItem && oldSelectedItem.getAttribute('data-fortune-teller-id') == fortuneTellerId) { | |
return; | |
} | |
resetDeck() | |
document.body.classList.remove('background-01', 'background-02', 'background-03', 'background-04', 'background-05', 'background-06', 'background-07'); | |
const fortuneTellerClass = 'background-' + fortuneTellerId; | |
document.body.classList.add(fortuneTellerClass); | |
const newSelectedItem = document.querySelector(`[data-fortune-teller-id="${fortuneTellerId}"]`) | |
if (oldSelectedItem) { | |
oldSelectedItem.classList.remove('selected'); | |
} | |
newSelectedItem.classList.add('selected'); | |
} | |
const openSettingsDialog = () => { | |
settingsDialog.showModal(); | |
} | |
const closeSettingsDialog = () => { | |
settingsDialog.close(); | |
} | |
const startButton = document.getElementById('start'); | |
startButton.addEventListener('click', openDeckSelectionDialog); | |
const settingsButton = document.getElementById('settings-button'); | |
settingsButton.addEventListener('click', openSettingsDialog); | |
const closeSettingsButton = document.getElementById('close-settings-button'); | |
closeSettingsButton.addEventListener('click', closeSettingsDialog); | |
const selectedButton = document.getElementById('fortune-teller-selected'); | |
selectedButton.addEventListener('click', () => { | |
deckSelectionDialog.close(); // Chiudi il dialogo di selezione del mazzo | |
questionDialog.showModal(); // Apri il dialogo delle domande | |
}); | |
function recollectCards(positionX = 50, positionY = 50) { | |
return new Promise((resolve, reject) => { | |
const deck = Array.from(document.querySelectorAll('.card')); | |
const animationDuration = 1000; // Durata dell'animazione in millisecondi | |
deck.forEach((card, index) => { | |
// card.style.transition = `top ${animationDuration}ms ease-out, left ${animationDuration}ms ease-out`; | |
card.classList.add('flipped'); | |
card.style.top = positionY + 'lvh'; | |
card.style.left = positionX + 'lvw'; | |
// Utilizziamo l'ultimo elemento nell'array per individuare la fine dell'animazione | |
if (index === deck.length - 1) { | |
card.addEventListener('transitionend', () => { | |
resolve(); // Risolviamo la Promise quando l'ultima carta ha terminato l'animazione | |
}, { once: true }); | |
} | |
}); | |
}); | |
} | |
function shuffleCards() { | |
const cardsContainer = document.getElementById('cards-container'); | |
const cards = cardsContainer.querySelectorAll('.card'); | |
// Convertiamo NodeList in un array per poterlo manipolare facilmente | |
const cardsArray = Array.from(cards); | |
// Usiamo l'algoritmo di Fisher-Yates per mescolare l'array | |
for (let i = cardsArray.length - 1; i > 0; i--) { | |
const j = Math.floor(Math.random() * (i + 1)); | |
[cardsArray[i], cardsArray[j]] = [cardsArray[j], cardsArray[i]]; | |
} | |
// Rimuoviamo le carte esistenti dal container | |
cardsContainer.innerHTML = ''; | |
// Aggiungiamo le carte mescolate nuovamente al container | |
cardsArray.forEach(card => { | |
cardsContainer.appendChild(card); | |
card.style.top = '50lvh'; | |
card.style.left = '50lvw'; | |
}); | |
} | |
const questionButton = document.getElementById('questionButton'); | |
questionButton.addEventListener('click', () => { | |
recollectCards().then(() => { | |
shuffleCards(); | |
const animation = () => { | |
recollectCards(100, 10).then(() => { | |
setTimeout(() => { | |
const cardsContainer = document.getElementById('cards-container'); | |
const cards = Array.from(cardsContainer.querySelectorAll('.card')); | |
const card1 = cards[21]; | |
card1.addEventListener('transitionend', () => { | |
card1.classList.remove('flipped') | |
}, { once: true }); | |
card1.style.top = '30lvh'; | |
card1.style.left = '30lvw'; | |
const card2 = cards[20]; | |
card2.addEventListener('transitionend', () => { | |
card2.classList.remove('flipped') | |
card2.style.transitionDelay = '0s'; | |
}, { once: true }); | |
card2.style.transitionDelay = '0.6s' | |
card2.style.top = '30lvh'; | |
card2.style.left = '50lvw'; | |
const card3 = cards[19]; | |
card3.addEventListener('transitionend', () => { | |
card3.classList.remove('flipped') | |
card3.style.transitionDelay = '0s'; | |
setTimeout(() => { | |
responseDialog.showModal(); | |
}, 1000) | |
}, { once: true }); | |
card3.style.top = '30lvh'; | |
card3.style.left = '70lvw'; | |
card3.style.transitionDelay = '1.2s' | |
const cardID1 = parseInt(card1.getAttribute('id').replace('card-', '')); | |
const cardID2 = parseInt(card2.getAttribute('id').replace('card-', '')) | |
const cardID3 = parseInt(card3.getAttribute('id').replace('card-', '')) | |
const question = document.getElementById('questionInput').value; | |
ask(question, cardID1, cardID2, cardID3); | |
}, 600); | |
}) | |
} | |
setTimeout(animation, 600); | |
}) | |
//deckSelectionDialog.close(); // Chiudi il dialogo di selezione del mazzo | |
questionDialog.close(); // Apri il dialogo delle domande | |
}); | |
const newQuestionButton = document.getElementById('new-question'); | |
newQuestionButton.addEventListener('click', () => { | |
responseDialog.close(); | |
const responseOutputElement = document.getElementById('response-output'); | |
document.getElementById('questionInput').value = '' | |
responseOutputElement.innerHTML = '<span>.</span><span>.</span><span>.</span>' | |
questionDialog.showModal(); | |
}) | |
const changeFortuneTellerButton = document.getElementById('changeFortuneTellerButton'); | |
changeFortuneTellerButton.addEventListener('click', () => { | |
questionDialog.close(); | |
openDeckSelectionDialog(); | |
}) | |
const comingSoonButton = document.getElementById('coming-soon'); | |
const comingSoonDialog = document.getElementById('coming-soon-dialog'); | |
comingSoonButton.addEventListener('click', () => { | |
comingSoonDialog.showModal(); | |
}) | |
const comingSoonCloseButton = document.getElementById('close-coming-soon-button'); | |
comingSoonCloseButton.addEventListener('click', () => { | |
comingSoonDialog.close(); | |
}) | |
// Chiamata alla funzione per aprire il dialogo di benvenuto all'avvio dell'app | |
openDeckSelectionDialog(); | |
openWelcomeDialog(); | |
const dialogs = document.querySelectorAll('dialog'); | |
dialogs.forEach(dialog => { | |
dialog.addEventListener('keydown', (event) => { | |
if (event.key === 'Escape') { | |
event.preventDefault(); // Impedisce la chiusura | |
} | |
}); | |
}); | |
}); | |