Code viewer for World: Calling APIs

// Cloned by Niall Ryan on 22 Nov 2023 from World "Chat with GPT model" by Starter user 
// Please leave this clone trail here.

// Sample prompt for a song
let prompt = "A relaxing song to study to influenced by LoFi and hip-hop"

// METHOD FOR CALLING AI APIs
async function fetchData(apiUrl, data) {
  const response = await fetch(apiUrl, {
    headers: {
      Authorization: "Bearer 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"
    },
    method: "POST",
    body: JSON.stringify(data),
  });

  if (!response.ok) {
    throw new Error(`HTTP Error! status: ${response.status}`);
  }
  return response;
}

// Function handles the query to the image generating AI API
async function queryImage(data) {
  // Add a 'loader' to the image container whilst awaiting the API
  let loader = document.createElement('div');
  loader.className = 'loader';
  document.getElementById('imageContainer').appendChild(loader);
 
  try {
    const response = await fetchData("https://api-inference.huggingface.co/models/runwayml/stable-diffusion-v1-5", data);
    const imageBlob = await response.blob();
    updateUI('imageContainer', imageBlob, true);
  } catch (error) {
    handleError('imageContainer', error.message);
  }
}

// General function for querying sound API (small & medium sized models)
async function querySound(data, apiUrl, containerId) {
  // Add a 'loader' to the image container whilst awaiting the API
  let loader = document.createElement('div');
  loader.className = 'loader';
  document.getElementById(containerId).appendChild(loader);

  try {
    const response = await fetchData(apiUrl, data);
    if (response.headers.get("content-type") === "audio/flac") {
      const audioBlob = await response.blob();
      updateUI(containerId, audioBlob, false);
    } else {
      const result = await response.json();
      return result;
    }
  } catch (error) {
    handleError(containerId, error.message);
  }
}


// Function updates the UI with new content or error messages
function updateUI(containerId, content, isImage) {
  const container = document.getElementById(containerId);
  container.innerHTML = ''; // Clear previous content or loaders

  if (isImage) {
    const image = document.createElement('img');
    image.src = URL.createObjectURL(content);
    container.appendChild(image);
  } else {
    const audio = new Audio(URL.createObjectURL(content));
    audio.controls = true;
    container.appendChild(audio);
    audio.addEventListener('canplaythrough', () => audio.play());
  }
}

// Error handler for UI updates
function handleError(containerId, status) {
  const container = document.getElementById(containerId);
  container.innerHTML = ''; // Clear loaders

  const errorElement = document.createElement('p');
  errorElement.className = 'errorText';
  errorElement.textContent = `ERROR: API returned ${status}`;
  container.appendChild(errorElement);

  console.error(`HTTP Error! status: ${status}`);
}

// The actual document HTML
document.write(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>API Demo</title>
<style>
  body {
    font-family: 'Arial', sans-serif;
    background-color: #f0f0f0;
    text-align: center;
    margin: 40px;
  }
  img {
    max-height: 400px; /* Adjust as needed */
    margin-top: 20px;
  }
  audio {
    margin-top: 20px;
    width: 300px; /* Adjust as needed */
  }
  .container {
    background-color: #fff;
    border-radius: 10px;
    box-shadow: 0 4px 8px rgba(0,0,0,0.1);
    margin: auto;
    padding: 20px;
    max-width: 800px;
  }
  .errorText {
      color: #f00
  }
  .prompt {
    background-color: #eee;
    border-left: 5px solid #333;
    padding: 10px;
    margin: 20px 0;
    text-align: left;
  }
   .loader {
    border: 5px solid #f3f3f3; /* Light grey */
    border-top: 5px solid #3498db; /* Blue */
    border-radius: 50%;
    width: 50px;
    height: 50px;
    animation: spin 2s linear infinite;
    margin: auto;
  }

  @keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
  }
  
  .pad {
      padding: 20px 0 0 20px
  }
  h1 {
    color: #333;
  }
  h3 {
    color: #666;
  }
</style>
</head>
<body>
<div class="container">
  <h1>Showcasing API</h1>
  <div class="prompt">
    <b>Prompt:</b> <span id="prompt">${prompt}</span>
  </div>
  <h1>Image:</h1>
    <div id="imageContainer">
    </div>
  <h1>Audio:</h1>
  <div id="audioContainerSmall" class="pad"></div>
  <div id="audioContainerMedium" class="pad"></div>
</div>
`);

// Execute the API calls
queryImage({ inputs: `Album cover art for a song described as "${prompt}"` });
querySound({ inputs: prompt }, "https://api-inference.huggingface.co/models/facebook/musicgen-small", 'audioContainerSmall');
querySound({ inputs: prompt }, "https://api-inference.huggingface.co/models/facebook/musicgen-medium", 'audioContainerMedium');