{
    "manifest_version": 3,
    "name": "Unity C# Code Challenge Redirector",
    "version": "1.1",
    "description": "Redirects search queries to a Unity C# code editor with ChatGPT-generated questions.",
    "permissions": [
      "storage",
      "scripting",
      "declarativeNetRequest"
    ],
    "host_permissions": [
      "*://www.google.com/*",
      "https://api.openai.com/*"
    ],
    "background": {
      "service_worker": "background.js"
    },
    "options_page": "popup.html",
    "content_scripts": [
      {
        "matches": ["*://www.google.com/*"],
        "js": ["contentScript.js"]
      }
    ],
    "declarative_net_request": {
      "rule_resources": [{
        "id": "ruleset_1",
        "enabled": true,
        "path": "rules.json"
      }]
    }
  }<!DOCTYPE html>
<html>
<head>
  <title>Extension Options</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <h2>Settings</h2>
  <label for="apiKey">OpenAI API Key:</label>
  <input type="password" id="apiKey" placeholder="Enter your API key" />
  <button id="save">Save</button>
  <p id="status"></p>

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

// Initialize Monaco Editor
require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.33.0/min/vs' }});
require(['vs/editor/editor.main'], function() {
  window.editor = monaco.editor.create(document.getElementById('editor'), {
    value: '// Write your Unity C# script here',
    language: 'csharp',
    theme: 'vs-light',
    automaticLayout: true
  });

  init();
});

async function init() {
  const urlParams = new URLSearchParams(window.location.search);
  const query = urlParams.get('query') || 'Generate a Unity C# 3D script that moves an object forward continuously.';
  
  // Fetch a question from ChatGPT
  const question = await getQuestion(query);
  document.getElementById('question').textContent = question;
}

async function getQuestion(searchQuery) {
  return new Promise((resolve, reject) => {
    chrome.storage.sync.get('openaiApiKey', async (data) => {
      const apiKey = data.openaiApiKey;
      if (!apiKey) {
        resolve('No API key found. Please set your OpenAI API key in the extension settings.');
        return;
      }

      try {
        const prompt = `Provide a Unity C# 3D programming question based on the following search query: "${searchQuery}". The question should require writing a script.`;

        const response = await fetch('https://api.openai.com/v1/completions', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${apiKey}`
          },
          body: JSON.stringify({
            model: "text-davinci-003",
            prompt: prompt,
            max_tokens: 150,
            temperature: 0.7
          })
        });

        if (!response.ok) {
          throw new Error(`OpenAI API error: ${response.statusText}`);
        }

        const data = await response.json();
        if (data.choices && data.choices.length > 0) {
          resolve(data.choices[0].text.trim());
        } else {
          resolve('Failed to fetch question from OpenAI.');
        }
      } catch (error) {
        console.error(error);
        resolve('Error fetching question.');
      }
    });
  });
}

document.getElementById('submit').addEventListener('click', async () => {
  const userCode = window.editor.getValue();
  const question = document.getElementById('question').textContent;

  const status = document.getElementById('status');
  status.textContent = 'Submitting...';
  status.style.color = 'black';

  const isValid = await validateCode(question, userCode);

  if (isValid) {
    status.textContent = 'Correct! Redirecting to search results...';
    status.style.color = 'green';
    // Proceed to the original search after a short delay
    setTimeout(() => {
      const urlParams = new URLSearchParams(window.location.search);
      const query = urlParams.get('query') || '';
      window.location.href = `https://www.google.com/search?q=${encodeURIComponent(query)}`;
    }, 2000);
  } else {
    status.textContent = 'Incorrect code. Please try again.';
    status.style.color = 'red';
  }
});

async function validateCode(question, code) {
  return new Promise((resolve, reject) => {
    chrome.storage.sync.get('openaiApiKey', async (data) => {
      const apiKey = data.openaiApiKey;
      if (!apiKey) {
        resolve(false);
        return;
      }

      try {
        const prompt = `Evaluate the following Unity C# 3D script based on the question: "${question}". Does the script correctly answer the question? Respond with "Yes" or "No" only. Script:\n\n${code}`;

        const response = await fetch('https://api.openai.com/v1/completions', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${apiKey}`
          },
          body: JSON.stringify({
            model: "text-davinci-003",
            prompt: prompt,
            max_tokens: 5,
            temperature: 0
          })
        });

        if (!response.ok) {
          throw new Error(`OpenAI API error: ${response.statusText}`);
        }

        const data = await response.json();
        if (data.choices && data.choices.length > 0) {
          const answer = data.choices[0].text.trim().toLowerCase();
          if (answer === 'yes') {
            resolve(true);
            return;
          }
        }
        resolve(false);
      } catch (error) {
        console.error(error);
        resolve(false);
      }
    });
  });
}<!DOCTYPE html>
<html>
<head>
  <title>Unity C# Code Challenge</title>
  <link rel="stylesheet" href="styles.css">
  <!-- Monaco Editor CDN -->
  <link rel="stylesheet" data-name="vs/editor/editor.main" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.33.0/min/vs/editor/editor.main.min.css" />
</head>
<body>
  <div id="container">
    <h1>Unity C# Code Challenge</h1>
    <div id="question"></div>
    <div id="editor" style="height: 400px; border: 1px solid #ccc;"></div>
    <button id="submit">Submit</button>
    <p id="status"></p>
  </div>

  <!-- Monaco Editor Scripts -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.33.0/min/vs/loader.min.js"></script>
  <script src="editor.js"></script>
</body>
</html>// contentScript.js

(function() {
    // Function to retrieve the 'q' parameter from the URL
    function getSearchQuery() {
      const urlParams = new URLSearchParams(window.location.search);
      return urlParams.get('q') || '';
    }
  
    // Check if we're on the redirected page (editor.html)
    if (window.location.pathname === '/editor.html') {
      // Do nothing if already redirected
      return;
    }
  
    // If on a Google search page, redirect with the query parameter
    const searchQuery = getSearchQuery();
    if (searchQuery) {
      // Redirect to the extension's editor.html with the search query
      const redirectUrl = chrome.runtime.getURL(`editor.html?query=${encodeURIComponent(searchQuery)}`);
      window.location.replace(redirectUrl);
    }
  })();// background.js

chrome.runtime.onInstalled.addListener(() => {
    chrome.declarativeNetRequest.updateDynamicRules({
      addRules: [],
      removeRuleIds: []
    }, () => {
      if (chrome.runtime.lastError) {
        console.error(chrome.runtime.lastError);
      } else {
        console.log('Declarative Net Request rules installed.');
      }
    });
  
    chrome.storage.sync.set({ openaiApiKey: '' }, () => {
      console.log('Default API key set.');
    });
  });{
  "rules": [
    {
      "id": 1,
      "priority": 1,
      "action": {
        "type": "redirect",
        "redirect": {
          "extensionPath": "/editor.html"
        }
      },
      "condition": {
        "urlFilter": "https://www.google.com/search*",
        "resourceTypes": ["main_frame"]
      }
    }
  ]
}/* styles.css */

body {
  font-family: Arial, sans-serif;
  margin: 20px;
}

#container {
  max-width: 800px;
  margin: auto;
}

h1 {
  text-align: center;
}

#question {
  margin-bottom: 20px;
  font-size: 1.2em;
  font-weight: bold;
}

#submit {
  margin-top: 10px;
  padding: 10px 20px;
  font-size: 1em;
}

#status {
  margin-top: 10px;
  font-weight: bold;
  color: green;
}

Where do I put my API key?