IF THERE IS A SONG YOU WOULD LIKE THAT IS NOT IN THE LIBRARY, PLEASE LET YOUR KARAOKE HOST KNOW.  IF IT IS AVAILABLE, WE CAN GET IT INSTANTLY (PENDING AVAILABILITY) SO THAT YOU CAN SING IT TONIGHT!

import React, { useState } from 'react'; function App() { // State to store the song name entered by the user const [songName, setSongName] = useState(''); // State to store the musical key result const [songKey, setSongKey] = useState(''); // State to store the list of similar songs const [similarSongs, setSimilarSongs] = useState([]); // State to manage loading status during API call const [isLoading, setIsLoading] = useState(false); // State to store any error messages const [error, setError] = useState(''); // Function to fetch the song key and similar songs using the Gemini API const fetchSongKey = async () => { // Clear previous results and errors setSongKey(''); setSimilarSongs([]); setError(''); setIsLoading(true); // Set loading state to true try { // Construct the prompt for the LLM, asking for key and similar songs in JSON format const prompt = `What is the musical key of the song "${songName}"? Also, list 3-5 songs that are in a similar musical key. Provide the response as a JSON object with two fields: "key" for the musical key (e.g., "C Major" or "A Minor") and "similarSongs" as an array of strings for the similar song titles. If you cannot determine the key, set "key" to "Key not found" and "similarSongs" to an empty array.`; // Prepare the chat history for the API request let chatHistory = []; chatHistory.push({ role: "user", parts: [{ text: prompt }] }); // Define the payload for the API call, including the generationConfig for structured JSON output const payload = { contents: chatHistory, generationConfig: { responseMimeType: "application/json", // Request JSON response responseSchema: { // Define the expected JSON structure type: "OBJECT", properties: { "key": { "type": "STRING" }, "similarSongs": { "type": "ARRAY", "items": { "type": "STRING" } } }, "required": ["key", "similarSongs"] // Ensure both fields are present } } }; // API key is left empty as Canvas will provide it at runtime const apiKey = ""; const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`; // Make the fetch call to the Gemini API const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); // Parse the JSON response const result = await response.json(); // Check if the response contains valid content and parse it if (result.candidates && result.candidates.length > 0 && result.candidates[0].content && result.candidates[0].content.parts && result.candidates[0].content.parts.length > 0) { const jsonString = result.candidates[0].content.parts[0].text; const parsedJson = JSON.parse(jsonString); // Parse the JSON string // Update state with the extracted key and similar songs setSongKey(parsedJson.key || 'Key not found'); // Use 'Key not found' if key is missing setSimilarSongs(parsedJson.similarSongs || []); // Use empty array if similarSongs is missing } else { // Handle cases where the response structure is unexpected or content is missing setError('Could not retrieve the song key or similar songs. Please try again or check the song name.'); } } catch (err) { // Catch and display any network or API errors, including JSON parsing errors console.error('Error fetching song key:', err); setError('An error occurred while fetching the song key. Please try again.'); } finally { setIsLoading(false); // Set loading state to false regardless of success or failure } }; return (

Song Key & Similar Song Finder

setSongName(e.target.value)} onKeyPress={(e) => { // Allow pressing Enter to trigger search if (e.key === 'Enter') { fetchSongKey(); } }} />
{/* Display Area for Result or Error */} {isLoading && (
Loading...
)} {error && (

Error:

{error}

)} {songKey && !isLoading && !error && (

Musical Key:

{songKey}

)} {similarSongs.length > 0 && !isLoading && !error && (

Similar Songs:

    {similarSongs.map((song, index) => (
  • {song}
  • ))}
)}
); } export default App;