给Flux-schnell网站加上翻译接口和历史记录

感谢大佬的喂饭教程https://linux.do/t/topic/184550
1、在原代码基础上加了翻译接口,使用openai类型的ai翻译,可以直接中文输入提示词生成图片
2、保留了10张历史记录图片
在原变量后新增加翻译模型变量
TS_URL:openai格式,eg:https://api.siliconflow.cn/v1/chat/completions
TS_KEY:对应API KEY
TS_MODEL:自选模型,我用的 siliconflow模型deepseek-ai/DeepSeek-V2-Chat

代码如下:

// Function to generate a secure random token
function generateToken() {
    return crypto.randomUUID();
  }
  
  // Function to verify Turnstile token
  async function verifyTurnstileToken(token) {
    const formData = new FormData();
    formData.append('secret', TURNSTILE_SECRET_KEY);
    formData.append('response', token);
  
    const url = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
    const result = await fetch(url, {
      body: formData,
      method: 'POST',
    });
  
    const outcome = await result.json();
    return outcome.success;
  }
  
  // Function to set a secure cookie
  function setCookie(name, value, maxAge = 3600) {
    return `${name}=${value}; HttpOnly; Secure; SameSite=Strict; Max-Age=${maxAge}; Path=/`;
  }
  
  // Function to get cookie value
  function getCookie(request, name) {
    const cookieString = request.headers.get('Cookie') || '';
    const cookies = cookieString.split(';').map(cookie => cookie.trim());
    const targetCookie = cookies.find(cookie => cookie.startsWith(`${name}=`));
    return targetCookie ? targetCookie.split('=')[1] : null;
  }
  
  // Middleware to check authentication
  async function checkAuth(request) {
    const sessionToken = getCookie(request, 'session');
    if (!sessionToken) return false;
  
    try {
      const [username, expirationTime] = atob(sessionToken).split(':');
      if (Date.now() > parseInt(expirationTime)) return false;
      return username === AUTH_USERNAME;
    } catch {
      return false;
    }
  }
  
  // Handle login request
  async function handleLogin(request) {
    if (request.method !== 'POST') {
      return new Response('Method Not Allowed', { status: 405 });
    }
  
    const formData = await request.formData();
    const username = formData.get('username');
    const password = formData.get('password');
    const turnstileResponse = formData.get('cf-turnstile-response');
  
    if (!await verifyTurnstileToken(turnstileResponse)) {
      return new Response('Turnstile verification failed', { status: 400 });
    }
  
    if (username === AUTH_USERNAME && password === AUTH_PASSWORD) {
      const expirationTime = Date.now() + 3600000; // 1 hour from now
      const sessionToken = btoa(`${username}:${expirationTime}`);
      const headers = new Headers();
      headers.append('Set-Cookie', setCookie('session', sessionToken));
      headers.append('Location', '/');
      return new Response(null, { status: 302, headers });
    } else {
      return new Response('Invalid credentials', { status: 401 });
    }
  }
  
  // Handle logout request
  function handleLogout() {
    const headers = new Headers();
    headers.append('Set-Cookie', setCookie('session', '', 0)); // Expire the cookie
    headers.append('Location', '/login');
    return new Response(null, { status: 302, headers });
  }
  
  // 语言检测函数
  function detectLanguage(text) {
      // 简单的语言检测:检查是否包含中文字符
      const chineseRegex = /[\u4e00-\u9fa5]/;
      return chineseRegex.test(text) ? 'zh' : 'en';
  }
  
  async function translatePrompt(prompt) {
      const detectedLanguage = detectLanguage(prompt);
      
      if (detectedLanguage === 'en') {
          console.log('Input is already in English, skipping translation');
          return prompt;
      }
  
      try {
          console.log('Translating from Chinese to English');
          const response = await fetch(TS_URL, {
              method: 'POST',
              headers: {
                  'Accept': 'application/json',
                  'Content-Type': 'application/json',
                  'Authorization': `Bearer ${TS_KEY}`
              },
              body: JSON.stringify({
                  model: TS_MODEL,
                  messages: [
                      { "role": "system", "content": "Translate the following Chinese text to English." },
                      { "role": "user", "content": prompt }
                  ]
              })
          });
  
          if (!response.ok) {
              throw new Error(`API Error: ${response.statusText}`);
          }
  
          const result = await response.json();
          const translatedText = result.choices[0].message.content.trim();
          return translatedText;
  
      } catch (error) {
          console.error('Translation Error:', error);
          throw new Error('Failed to translate the prompt.');
      }
  }
  
  
  
  // Generate image
  async function generateImage(request) {
      try {
          const { prompt, width, height, num_inference_steps } = await request.json();
        
          console.log('Original prompt:', prompt);
          const translatedPrompt = await translatePrompt(prompt);
          console.log('Prompt after translation check:', translatedPrompt);
        
          const response = await fetch(API_URL, {
              method: 'POST',
              headers: {
                  'Accept': 'application/json',
                  'Content-Type': 'application/json',
                  'Authorization': `Bearer ${API_KEY}`
              },
              body: JSON.stringify({ prompt: translatedPrompt, width, height, num_inference_steps })
          });
    
          if (!response.ok) {
              const errorData = await response.json();
              throw new Error(`API request failed: ${errorData.error || response.statusText}`);
          }
    
          const result = await response.json();
          
          // 添加翻译信息到结果中
          result.wasTranslated = (prompt !== translatedPrompt);
          result.originalPrompt = prompt;
          result.translatedPrompt = translatedPrompt;
          
          return new Response(JSON.stringify(result), {
              status: 200,
              headers: { 'Content-Type': 'application/json' }
          });
      } catch (error) {
          console.error('Error in generateImage:', error);
          return new Response(JSON.stringify({ error: error.message }), {
              status: 500,
              headers: { 'Content-Type': 'application/json' }
          });
      }
  }
  
    
  
  
  // Get login page HTML
  function getLoginHTML() {
    return `
  <!DOCTYPE html>
  <html lang="en">
  <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Login - Flux.1-schnell Generator</title>
      <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
      <style>
          body {
              font-family: 'Roboto', sans-serif;
              display: flex;
              justify-content: center;
              align-items: center;
              height: 100vh;
              margin: 0;
              background-color: #f4f4f4;
          }
          form {
              background-color: white;
              padding: 2rem;
              border-radius: 8px;
              box-shadow: 0 4px 6px rgba(0,0,0,0.1);
              width: 100%;
              max-width: 400px;
          }
          h2 {
              margin-top: 0;
              color: #333;
              text-align: center;
          }
          input {
              display: block;
              width: 100%;
              padding: 0.75rem;
              margin: 1rem 0;
              border: 1px solid #ddd;
              border-radius: 4px;
              box-sizing: border-box;
              font-size: 1rem;
          }
          button {
              width: 100%;
              padding: 0.75rem;
              background-color: #3498db;
              color: white;
              border: none;
              border-radius: 4px;
              cursor: pointer;
              font-size: 1rem;
              transition: background-color 0.3s ease;
          }
          button:hover {
              background-color: #2980b9;
          }
      </style>
  </head>
  <body>
      <form method="POST" action="/login">
          <h2>Login</h2>
          <input type="text" name="username" placeholder="Username" required>
          <input type="password" name="password" placeholder="Password" required>
          <div class="cf-turnstile" data-sitekey="${TURNSTILE_SITE_KEY}"></div>
          <button type="submit">Login</button>
      </form>
  </body>
  </html>
    `;
  }
  
  // Get main page HTML
  function getMainHTML() {
    return `
  <!DOCTYPE html>
  <html lang="en">
  <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Flux.1-schnell Generator</title>
      <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap" rel="stylesheet">
      <style>
          :root {
              --background-color: #f4f4f4;
              --card-background: #ffffff;
              --text-color: #333333;
              --primary-color: #3498db;
              --primary-hover: #2980b9;
              --error-color: #e74c3c;
          }
          body {
              font-family: 'Roboto', sans-serif;
              line-height: 1.6;
              color: var(--text-color);
              background-color: var(--background-color);
              margin: 0;
              padding: 0;
              min-height: 100vh;
              display: flex;
              flex-direction: column;
              justify-content: center;
              align-items: center;
          }
          .container {
              width: 100%;
              max-width: 800px;
              margin: 2rem auto;
              padding: 2rem;
              background-color: var(--card-background);
              border-radius: 10px;
              box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
          }
          h1 {
              color: var(--text-color);
              text-align: center;
              margin-bottom: 1.5rem;
          }
          .image-container {
              margin-bottom: 2rem;
              text-align: center;
              background-color: var(--background-color);
              padding: 2rem;
              border-radius: 8px;
              min-height: 300px;
              display: flex;
              align-items: center;
              justify-content: center;
          }
          .image-container img {
              max-width: 100%;
              border-radius: 8px;
              box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
          }
          .form-group {
              margin-bottom: 1.5rem;
          }
          label {
              display: block;
              margin-bottom: 0.5rem;
              font-weight: bold;
          }
          input[type="text"] {
              width: 100%;
              padding: 0.8rem;
              border: 1px solid #ddd;
              border-radius: 4px;
              font-size: 1rem;
          }
          .image-ratio-group {
              display: grid;
              grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
              gap: 1rem;
              margin-top: 0.5rem;
          }
          .image-ratio-option input[type="radio"] {
              display: none;
          }
          .image-ratio-option label {
              display: block;
              padding: 0.5rem;
              text-align: center;
              background-color: var(--background-color);
              border: 2px solid #ddd;
              border-radius: 4px;
              cursor: pointer;
              transition: all 0.3s ease;
          }
          .image-ratio-option input[type="radio"]:checked + label {
              background-color: var(--primary-color);
              color: white;
              border-color: var(--primary-color);
          }
          .generate-btn {
              display: block;
              width: 100%;
              padding: 1rem;
              background-color: var(--primary-color);
              color: white;
              border: none;
              border-radius: 4px;
              font-size: 1rem;
              cursor: pointer;
              transition: background-color 0.3s ease;
          }
          .generate-btn:hover {
              background-color: var(--primary-hover);
          }
          .generate-btn:disabled {
              background-color: #bdc3c7;
              cursor: not-allowed;
          }
          .logout-btn {
              display: inline-block;
              margin-top: 2rem;
              padding: 0.8rem 1.5rem;
              background-color: var(--error-color);
              color: white;
              text-decoration: none;
              border-radius: 4px;
              transition: background-color 0.3s ease;
          }
          .logout-btn:hover {
              background-color: #c0392b;
          }
          #error-message {
              color: var(--error-color);
              text-align: center;
              margin-top: 1rem;
          }
          .loading {
              font-style: italic;
              color: #7f8c8d;
          }
          .history-container {
              margin-top: 2rem;
          }
          .history-container h2 {
              text-align: center;
              margin-bottom: 1rem;
          }
          #image-history {
              display: flex;
              flex-wrap: wrap;
              gap: 1rem;
              justify-content: center;
          }
          .history-image {
              width: 200px;
              height: 200px;
              object-fit: cover;
              border-radius: 8px;
              box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
              cursor: pointer;
              transition: transform 0.3s ease;
          }
          .history-image:hover {
              transform: scale(1.05);
          }
      #translation-info {
          margin-top: 0.5rem;
          font-size: 0.9em;
          color: #666;
          }
      </style>
  </head>
  <body>
      <div class="container">
          <h1>Flux.1-schnell Generator</h1>
          
          <div class="image-container" id="image-container">
              <p>Your generated image will appear here</p>
          </div>
          
          <form id="image-form">
              <div class="form-group">
                  <label for="prompt">Describe your image:</label>
                  <input type="text" id="prompt" name="prompt" placeholder="Enter your image description" required>
          <div id="translation-info"></div>
              </div>
              
              <div class="form-group">
                  <label>Select image ratio:</label>
                  <div class="image-ratio-group">
                      <div class="image-ratio-option">
                          <input type="radio" id="ratio-1-1" name="image_ratio" value="1:1" checked>
                          <label for="ratio-1-1">1:1</label>
                      </div>
                      <div class="image-ratio-option">
                          <input type="radio" id="ratio-1-2" name="image_ratio" value="1:2">
                          <label for="ratio-1-2">1:2</label>
                      </div>
                      <div class="image-ratio-option">
                          <input type="radio" id="ratio-3-2" name="image_ratio" value="3:2">
                          <label for="ratio-3-2">3:2</label>
                      </div>
                      <div class="image-ratio-option">
                          <input type="radio" id="ratio-3-4" name="image_ratio" value="3:4">
                          <label for="ratio-3-4">3:4</label>
                      </div>
                      <div class="image-ratio-option">
                          <input type="radio" id="ratio-16-9" name="image_ratio" value="16:9">
                          <label for="ratio-16-9">16:9</label>
                      </div>
                      <div class="image-ratio-option">
                          <input type="radio" id="ratio-9-16" name="image_ratio" value="9:16">
                          <label for="ratio-9-16">9:16</label>
                      </div>
                  </div>
              </div>
              
              <button type="submit" class="generate-btn">Generate Image</button>
          </form>
  
          <div class="history-container">
              <h2>Generated Images History</h2>
              <div id="image-history"></div>
          </div>        
          
          <div id="error-message"></div>
          <a href="/logout" class="logout-btn">Logout</a>
      </div>
  
      <script>
      document.getElementById('image-form').addEventListener('submit', async function(event) {
      event.preventDefault();
  
      const prompt = document.getElementById('prompt').value;
      const imageRatio = document.querySelector('input[name="image_ratio"]:checked').value;
      const imageContainer = document.getElementById('image-container');
      const errorMessage = document.getElementById('error-message');
      const generateButton = document.querySelector('.generate-btn');
      const translationInfo = document.getElementById('translation-info');
  
      const numInferenceSteps = 20;
  
      updateUI('generating');
  
      const { width, height } = getImageDimensions(imageRatio);
  
      try {
          const response = await fetch('/generate-image', {
              method: 'POST',
              headers: {
                  'Content-Type': 'application/json',
              },
              body: JSON.stringify({
                  prompt,
                  width,
                  height,
                  num_inference_steps: numInferenceSteps
              })
          });
  
          if (!response.ok) {
              throw new Error('Failed to generate image. Please try again.');
          }
  
          const data = await response.json();
  
          if (data.images && data.images.length > 0) {
              const imageUrl = data.images[0].url;
              imageContainer.innerHTML = '<img src="' + imageUrl + '" alt="Generated Image">';
              addImageToHistory(imageUrl);
              
              // 添加这段代码来更新翻译信息
              const translationInfo = document.getElementById('translation-info');
              if (data.wasTranslated) {
                translationInfo.textContent = 'Original: "' + data.originalPrompt + '" | Translated: "' + data.translatedPrompt + '"';
              } else {
                  translationInfo.textContent = 'No translation needed';
              }
          } else {
              throw new Error('Failed to generate image. Please try again.');
          }
      } catch (error) {
          console.error('Error:', error);
          errorMessage.textContent = error.message;
      } finally {
          updateUI('idle');
      }
  });
  
  
    function getImageDimensions(ratio) {
        const dimensions = {
            '1:1': { width: 1024, height: 1024 },
            '1:2': { width: 512, height: 1024 },
            '3:2': { width: 768, height: 512 },
            '3:4': { width: 768, height: 1024 },
            '16:9': { width: 1024, height: 576 },
            '9:16': { width: 576, height: 1024 }
        };
        return dimensions[ratio] || dimensions['1:1'];
    }
  
    function updateUI(state) {
        const imageContainer = document.getElementById('image-container');
        const errorMessage = document.getElementById('error-message');
        const generateButton = document.querySelector('.generate-btn');
  
        if (state === 'generating') {
            imageContainer.innerHTML = '<p class="loading">Translating prompt and generating your image... This may take a moment.</p>';
            errorMessage.textContent = '';
            generateButton.disabled = true;
            generateButton.textContent = 'Generating...';
        } else {
            generateButton.disabled = false;
            generateButton.textContent = 'Generate Image';
        }
    }
  
    // 在这里添加新的 JavaScript 代码
    let imageHistory = [];
  
      function addImageToHistory(imageUrl) {
          imageHistory.unshift(imageUrl);
          if (imageHistory.length > 10) {
              imageHistory.pop();
          }
          updateImageHistory();
          saveImageHistory();
      }
  
      function updateImageHistory() {
          const historyContainer = document.getElementById('image-history');
          historyContainer.innerHTML = '';
          imageHistory.forEach(url => {
              const img = document.createElement('img');
              img.src = url;
              img.alt = 'Generated Image';
              img.className = 'history-image';
              img.onclick = () => {
                  document.getElementById('image-container').innerHTML = '<img src="' + url + '" alt="Generated Image">';
  
              };
              historyContainer.appendChild(img);
          });
      }
  
      function saveImageHistory() {
          localStorage.setItem('imageHistory', JSON.stringify(imageHistory));
      }
  
      function loadImageHistory() {
          const savedHistory = localStorage.getItem('imageHistory');
          if (savedHistory) {
              imageHistory = JSON.parse(savedHistory);
              updateImageHistory();
          }
      }
  
      // 在页面加载时调用
      loadImageHistory();
    </script>
  </body>
  </html>
  `;
  }
  
  // Main request handler
  async function handleRequest(request) {
  const url = new URL(request.url);
  
  // Login route
  if (url.pathname === '/login') {
    if (request.method === 'GET') {
      return new Response(getLoginHTML(), {
        headers: { 'Content-Type': 'text/html' },
      });
    } else if (request.method === 'POST') {
      return handleLogin(request);
    }
  }
  
  // Logout route
  if (url.pathname === '/logout') {
    return handleLogout();
  }
  
  // Check authentication for all other routes
  const isAuthenticated = await checkAuth(request);
  if (!isAuthenticated) {
    const headers = new Headers();
    headers.append('Location', '/login');
    return new Response(null, { status: 302, headers });
  }
  
  // Generate image route
  if (request.method === 'POST' && url.pathname === '/generate-image') {
    return generateImage(request);
  }
  
  // Main page route
  if (request.method === 'GET' && url.pathname === '/') {
    return new Response(getMainHTML(), {
      headers: { 'Content-Type': 'text/html' },
    });
  }
  
  // 404 for all other routes
  return new Response('Not Found', { status: 404 });
  }
  
  // Event listener
  addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request));
  });
3 个赞

帮顶帮顶 这代码可以Python运行吗?
可以我就去试试

感谢分享这个代码

这个代码是运行在cf上的

我不会整CF部署
难受

喂饭教程

直接MARK 感谢分享

大佬太强了,持续进化了

哇,感谢大佬喂饭

谢谢大佬分享

From 人工智能 to 资源荟萃