I want you to rewrite the addition to make the text appear in the area where I want it to appear, and modify what you deem appropriate, so make sure it works on all sites. I want professional work.


// content.js

(function() {
  console.log('Speech to Text Converter: content.js loaded');

  // Create the floating microphone button
  const button = document.createElement('button');
  button.id = 'speech-to-text-button';
  button.innerHTML = '🎤'; // Microphone emoji
  document.body.appendChild(button);

  let isRecording = false;
  let mediaRecorder;
  let audioChunks = [];

  // Toggle Recording Function
  function toggleRecording(state) {
    isRecording = state;
    if (isRecording) {
      button.classList.add('active');
      startRecording();
      console.log('Recording started');
    } else {
      button.classList.remove('active');
      stopRecording();
      console.log('Recording stopped');
    }
  }

  // Handle Button Click
  button.addEventListener('click', () => {
    toggleRecording(!isRecording);
  });

  // Start Recording
  async function startRecording() {
    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
      alert('Your browser does not support audio recording.');
      console.error('getUserMedia not supported');
      toggleRecording(false);
      return;
    }

    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      mediaRecorder = new MediaRecorder(stream);

      mediaRecorder.start();
      console.log('MediaRecorder started');

      mediaRecorder.onstart = () => {
        audioChunks = [];
        console.log('MediaRecorder started capturing audio');
      };

      mediaRecorder.ondataavailable = (event) => {
        audioChunks.push(event.data);
        console.log('Audio data available:', event.data);
      };

      mediaRecorder.onstop = async () => {
        const audioBlob = new Blob(audioChunks, { type: 'audio/m4a' });
        console.log('MediaRecorder stopped, Blob created:', audioBlob);

        // Convert Blob to Base64
        const base64Audio = await blobToBase64(audioBlob);
        console.log('Audio converted to Base64:', base64Audio.substring(0, 30) + '...'); // Log first 30 chars

        // Send Base64 audio to background for transcription
        const transcription = await sendAudioForTranscription(base64Audio);
        console.log('Transcription received:', transcription);

        if (transcription) {
          // Send the transcription to the popup
          chrome.runtime.sendMessage({ type: 'transcription', transcription });
        }

        // Stop all tracks
        stream.getTracks().forEach(track => track.stop());

        // Reset recording state
        isRecording = false;
        button.classList.remove('active');
      };

      mediaRecorder.onerror = (event) => {
        console.error('MediaRecorder Error:', event.error);
        toggleRecording(false);
      };
    } catch (err) {
      console.error('Error accessing microphone:', err);
      alert('Error accessing microphone. Please check permissions.');
      toggleRecording(false);
    }
  }

  // Stop Recording
  function stopRecording() {
    if (mediaRecorder && mediaRecorder.state !== 'inactive') {
      mediaRecorder.stop();
      console.log('MediaRecorder stopping...');
    }
  }

  // Helper function to convert Blob to Base64
  function blobToBase64(blob) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onloadend = function() {
        const dataUrl = reader.result;
        const base64Data = dataUrl.split(',')[1]; // Remove data:audio/m4a;base64, part
        resolve(base64Data);
      };
      reader.onerror = function(error) {
        console.error('FileReader Error:', error);
        reject(error);
      };
      reader.readAsDataURL(blob);
    });
  }

  // Communication with background script
  function sendAudioForTranscription(base64Audio) {
    return new Promise((resolve, reject) => {
      chrome.runtime.sendMessage({ type: 'transcribe', audio: { base64: base64Audio } }, (response) => {
        if (chrome.runtime.lastError) {
          console.error('Runtime error:', chrome.runtime.lastError);
          resolve(null); // Resolve with null to avoid uncaught errors
        } else {
          console.log('Response received from background script:', response);
          if (response && response.transcription) {
            resolve(response.transcription);
          } else {
            console.error('No transcription received in response:', response);
            resolve(null); // Resolve with null to avoid uncaught errors
          }
        }
      });
    });
  }
})();

// background.js

// Listen for messages from content scripts
chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
  if (request.type === 'transcribe' && request.audio && request.audio.base64) {
    console.log('Audio data received in background script:', request.audio.base64.substring(0, 30) + '...'); // Log first 30 chars
    try {
      const transcription = await transcribeAudio(request.audio.base64);
      console.log('Transcription successful:', transcription);
      sendResponse({ transcription }); // Send the transcription back
    } catch (error) {
      console.error('Transcription Error:', error);
      sendResponse({ transcription: null }); // Send null in case of error
    }
    // Indicate that the response is asynchronous
    return true;
  } else {
    // Handle other types of messages or invalid requests
    sendResponse({ transcription: null });
    return true;
  }
});

// Function to transcribe audio using Groq API
async function transcribeAudio(base64Audio) {
  const apiKey = '<TRUFFLEHOG_REDACTED_GROQ>'; // Replace with your actual Groq API key
  const url = 'https://api.groq.com/openai/v1/audio/transcriptions'; // Correct Groq API endpoint

  // Convert Base64 back to Blob
  const audioBlob = base64ToBlob(base64Audio, 'audio/m4a');

  const formData = new FormData();
  formData.append('file', audioBlob, 'audio.m4a');
  formData.append('model', 'whisper-large-v3'); // Correct model name as per documentation
  formData.append('response_format', 'json'); // You can set this to 'text' or 'verbose_json' if needed

  console.log('Sending transcription request to:', url);

  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`
      },
      body: formData
    });

    console.log('Received response status:', response.status);

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`Groq API Error: ${response.status} ${response.statusText} - ${errorText}`);
    }

    const data = await response.json();
    console.log('Transcription data received:', data);
    return data.text || 'No transcription available.';
  } catch (error) {
    console.error('Error in transcribeAudio:', error);
    throw error;
  }
}

// Helper function to convert Base64 to Blob
function base64ToBlob(base64, mime) {
  const byteCharacters = atob(base64);
  const byteNumbers = new Array(byteCharacters.length);
  for (let i = 0; i < byteCharacters.length; i++) {
    byteNumbers[i] = byteCharacters.charCodeAt(i);
  }
  const byteArray = new Uint8Array(byteNumbers);
  return new Blob([byteArray], { type: mime });
}

<!-- popup.html -->
<!DOCTYPE html>
<html>
<head>
  <title>Speech to Text Converter</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      min-width: 200px;
      padding: 10px;
    }
    button {
      width: 100%;
      padding: 10px;
      font-size: 16px;
      background-color: #0078D7;
      color: white;
      border: none;
      border-radius: 5px;
      cursor: pointer;
    }
    button.active {
      background-color: #D70022;
    }
    #status {
      margin-top: 10px;
      font-size: 14px;
    }
    #transcription {
      margin-top: 10px;
      width: 100%;
      height: 100px;
      font-size: 14px;
      padding: 5px;
      box-sizing: border-box;
    }
  </style>
</head>
<body>
  <button id="toggle-recording">🎤 Start Recording</button>
  <div id="status"></div>
  <textarea id="transcription" placeholder="Transcription will appear here..." readonly></textarea>

  <script src="popup.js"></script>
</body>
</html>

// popup.js

document.addEventListener('DOMContentLoaded', () => {
  const button = document.getElementById('toggle-recording');
  const statusDiv = document.getElementById('status');
  const transcriptionTextarea = document.getElementById('transcription');
  let isRecording = false;

  button.addEventListener('click', () => {
    isRecording = !isRecording;
    if (isRecording) {
      button.classList.add('active');
      button.textContent = '🎤 Stop Recording';
      statusDiv.textContent = 'Recording...';
      startRecording();
    } else {
      button.classList.remove('active');
      button.textContent = '🎤 Start Recording';
      statusDiv.textContent = 'Stopped.';
      stopRecording();
    }
  });

  function startRecording() {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      if (tabs[0].id) {
        chrome.tabs.sendMessage(tabs[0].id, { type: 'toggleRecording', state: true });
      }
    });
  }

  function stopRecording() {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      if (tabs[0].id) {
        chrome.tabs.sendMessage(tabs[0].id, { type: 'toggleRecording', state: false });
      }
    });
  }

  // Listen for messages from the content script
  chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.type === 'transcription') {
      transcriptionTextarea.value = request.transcription;
      statusDiv.textContent = 'Transcription complete.';
    }
  });
});

/* styles.css */

/* Floating Microphone Button */
#speech-to-text-button {
  position: fixed;
  bottom: 20px;
  right: 20px;
  width: 60px;
  height: 60px;
  border: none;
  border-radius: 50%;
  background-color: #0078D7;
  color: white;
  font-size: 30px; /* Larger font size for the emoji */
  cursor: pointer;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  z-index: 10000;
  transition: background-color 0.3s;
}

#speech-to-text-button.active {
  background-color: #D70022; /* Red color when active */
}

/* Transcribed Text Display */
#speech-to-text-display {
  position: fixed;
  bottom: 90px; /* Positioned above the button */
  right: 20px;
  width: 300px;
  max-height: 200px;
  overflow-y: auto;
  background-color: rgba(0, 0, 0, 0.8);
  color: #ffffff;
  padding: 15px;
  border-radius: 8px;
  z-index: 10000;
  font-size: 14px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  display: none; /* Hidden by default */
}


{
  "manifest_version": 3,
  "name": "Speech to Text Converter",
  "version": "1.0",
  "description": "Convert spoken words into text using the Groq API.",
  "permissions": [
    "activeTab",
    "scripting",
    "storage"
  ],
  "host_permissions": [
    "<all_urls>"
  ],
  "background": {
    "service_worker": "background.js",
    "type": "module"
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"],
      "css": ["styles.css"],
      "run_at": "document_idle"
    }
  ],
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  },
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  }
}