Greasy Fork

来自缓存

Greasy Fork is available in English.

一个优化你使用AI时候的prompt智能体。

prompt-agent

当前为 2025-06-24 提交的版本,查看 最新版本

// ==UserScript==
// @name         一个优化你使用AI时候的prompt智能体。
// @namespace    prompt-agent
// @version      0.0.2
// @description  prompt-agent
// @author       LLinkedList771
// @run-at       document-end
// @match        https://chat.deepseek.com/*
// @homepageURL  https://github.com/linkedlist771/prompt-agent
// @supportURL   https://github.com/linkedlist771/prompt-agent/issues
// @license      MIT
// ==/UserScript==



(function() {
  'use strict';

  // 配置变量
  let isEnabled = false;
  let apiKey = localStorage.getItem('ai-script-apikey') || '';
  let isProcessing = false;

  // 创建浮动UI
  function createFloatingUI() {
      const container = document.createElement('div');
      container.id = 'ai-floating-ui';
      container.style.cssText = `
          position: fixed;
          top: 20px;
          right: 20px;
          width: 280px;
          background: #ffffff;
          border: 1px solid #ddd;
          border-radius: 8px;
          box-shadow: 0 4px 12px rgba(0,0,0,0.15);
          z-index: 10000;
          font-family: Arial, sans-serif;
          font-size: 14px;
      `;

      container.innerHTML = `
          <div style="background: #f5f5f5; padding: 12px; border-radius: 8px 8px 0 0; border-bottom: 1px solid #ddd;">
              <div style="display: flex; justify-content: space-between; align-items: center;">
                  <span style="font-weight: bold; color: #333;">Prompt Agent</span>
                  <button id="ai-minimize" style="background: none; border: none; font-size: 16px; cursor: pointer;">−</button>
              </div>
          </div>
          <div id="ai-content" style="padding: 15px;">
              <div style="margin-bottom: 15px;">
                  <label style="display: block; margin-bottom: 5px; color: #555;">API Key:</label>
                  <input type="password" id="ai-apikey" placeholder="Bearer token..."
                         style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box;"
                         value="${apiKey}">
              </div>
              <div style="margin-bottom: 15px;">
                  <label style="display: flex; align-items: center; color: #555;">
                      <input type="checkbox" id="ai-enable" ${isEnabled ? 'checked' : ''}
                             style="margin-right: 8px;">
                      启用AI响应
                  </label>
              </div>
              <div style="margin-bottom: 10px;">
                  <button id="ai-test" style="width: 100%; padding: 8px; background: #007cba; color: white; border: none; border-radius: 4px; cursor: pointer;">
                      测试连接
                  </button>
              </div>
              <div style="margin-bottom: 10px;">
                  <button id="ai-manual-send" style="width: 100%; padding: 8px; background: #28a745; color: white; border: none; border-radius: 4px; cursor: pointer;">
                      手动发送
                  </button>
              </div>
              <div id="ai-status" style="font-size: 12px; color: #666; text-align: center;"></div>
          </div>
      `;

      document.body.appendChild(container);

      // 事件监听
      document.getElementById('ai-minimize').addEventListener('click', toggleMinimize);
      document.getElementById('ai-enable').addEventListener('change', toggleEnable);
      document.getElementById('ai-apikey').addEventListener('input', saveApiKey);
      document.getElementById('ai-test').addEventListener('click', testConnection);
      document.getElementById('ai-manual-send').addEventListener('click', manualSend);

      // 监听Ctrl+Enter组合键
      document.addEventListener('keydown', handleKeyDown);
  }

  function toggleMinimize() {
      const content = document.getElementById('ai-content');
      const button = document.getElementById('ai-minimize');
      if (content.style.display === 'none') {
          content.style.display = 'block';
          button.textContent = '−';
      } else {
          content.style.display = 'none';
          button.textContent = '+';
      }
  }

  function toggleEnable(e) {
      isEnabled = e.target.checked;
      updateStatus(isEnabled ? '已启用 - 按Ctrl+Enter发送' : '已禁用');
  }

  function saveApiKey(e) {
      apiKey = e.target.value;
      localStorage.setItem('ai-script-apikey', apiKey);
  }

  function updateStatus(message, isError = false) {
      const status = document.getElementById('ai-status');
      if (status) {
          status.textContent = message;
          status.style.color = isError ? '#d32f2f' : '#666';
      }
  }

  function handleKeyDown(e) {
      if (e.ctrlKey && e.key === 'Enter' && isEnabled && !isProcessing) {
          const textarea = document.querySelector('textarea:focus');
          if (textarea && textarea.value.trim()) {
              e.preventDefault();
              sendRequest(textarea);
          }
      }
  }

  async function testConnection() {
      if (!apiKey.trim()) {
          updateStatus('请先输入API Key', true);
          return;
      }

      updateStatus('测试连接中...');

      try {
          const response = await fetch("https://promptagent.qqyunsd.com/api/v1/chat/completions", {
              method: 'POST',
              headers: {
                  "authorization": `Bearer ${apiKey}`,
                  "User-Agent": "Apifox/1.0.0 (https://apifox.com)",
                  "Content-Type": "application/json"
              },
              body: JSON.stringify({
                  "model": "mock-gpt-model",
                  "messages": [
                      { "role": "user", "content": "test" }
                  ],
                  "max_tokens": 10,
                  "temperature": 0.1,
                  "stream": false
              })
          });

          if (response.ok) {
              updateStatus('连接成功!');
          } else {
              updateStatus(`连接失败: ${response.status}`, true);
          }
      } catch (error) {
          updateStatus(`连接错误: ${error.message}`, true);
      }
  }

  function manualSend() {
      if (isProcessing) {
          updateStatus('正在处理中,请稍后...', true);
          return;
      }

      // 查找当前页面中聚焦的textarea或者最后一个textarea
      let textarea = document.querySelector('textarea:focus');
      
      if (!textarea) {
          // 如果没有聚焦的textarea,尝试找到页面上的textarea
          const textareas = document.querySelectorAll('textarea');
          if (textareas.length > 0) {
              textarea = textareas[textareas.length - 1]; // 选择最后一个textarea
          }
      }

      if (!textarea) {
          updateStatus('未找到输入框', true);
          return;
      }

      if (!textarea.value.trim()) {
          updateStatus('请先输入内容', true);
          return;
      }

      sendRequest(textarea);
  }

  async function sendRequest(textarea) {
      if (!apiKey.trim()) {
          updateStatus('请先输入API Key', true);
          return;
      }

      isProcessing = true;
      updateStatus('处理中...');

      const userInput = textarea.value.trim();

      // 清空textarea
      textarea.value = '';

      const myHeaders = new Headers();
      myHeaders.append("authorization", `Bearer ${apiKey}`);
      myHeaders.append("User-Agent", "Apifox/1.0.0 (https://apifox.com)");
      myHeaders.append("Content-Type", "application/json");

      const raw = JSON.stringify({
          "model": "mock-gpt-model",
          "messages": [
              { "role": "user", "content": userInput }
          ],
          "max_tokens": 512,
          "temperature": 0.1,
          "stream": true
      });

      const requestOptions = {
          method: 'POST',
          headers: myHeaders,
          body: raw,
          redirect: 'follow'
      };

      try {
          const response = await fetch("http://localhost:3648/api/v1/chat/completions", requestOptions);

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

          const reader = response.body.getReader();
          const decoder = new TextDecoder();

          updateStatus('接收响应中...');

          while (true) {
              const { done, value } = await reader.read();

              if (done) {
                  break;
              }

              const chunk = decoder.decode(value, { stream: true });
              const lines = chunk.split('\n');

              for (const line of lines) {
                  if (line.startsWith('data: ')) {
                      const jsonStr = line.substring(6).trim();
                      if (jsonStr === '[DONE]') {
                          continue;
                      }

                      try {
                          const data = JSON.parse(jsonStr);
                          if (data.choices && data.choices[0] && data.choices[0].delta && data.choices[0].delta.content) {
                              const content = data.choices[0].delta.content;

                              // 逐字添加到textarea
                              for (const char of content) {
                                  textarea.value += char;
                                  // 模拟打字效果
                                  await new Promise(resolve => setTimeout(resolve, 20));

                                  // 滚动到底部
                                  textarea.scrollTop = textarea.scrollHeight;
                              }
                          }
                      } catch (parseError) {
                          console.log('JSON解析错误:', parseError, jsonStr);
                      }
                  }
              }
          }

          updateStatus('完成!');

      } catch (error) {
          updateStatus(`错误: ${error.message}`, true);
          console.error('请求错误:', error);
      } finally {
          isProcessing = false;
      }
  }

  // 初始化
  function init() {
      // 等待页面加载完成
      if (document.readyState === 'loading') {
          document.addEventListener('DOMContentLoaded', createFloatingUI);
      } else {
          createFloatingUI();
      }

      updateStatus('就绪 - 在textarea中输入后按Ctrl+Enter');
  }

  init();
})();