<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Verge API：GPT Image 2 与 Gemini 生图接口</title>
  <meta
    name="description"
    content="同一个 Base URL 支持 GPT Image 2 与 Gemini 同步和异步生图。"
  />
  <link id="page-favicon" rel="icon" href="" type="image/png" />
  <link rel="stylesheet" href="style.css" />
  <script src="config.js"></script>
</head>
<body>
  <header class="pages-header">
    <a class="pages-brand" data-link-key="home" href="/">
      <span class="icon-slot pages-brand-logo" data-icon-key="logo" aria-hidden="true"></span>
      <span>Verge API</span>
    </a>
    <nav class="pages-nav" data-i18n-aria="nav.aria" aria-label="主导航">
      <a data-link-key="home" data-i18n="nav.home" href="/">首页</a>
      <a data-link-key="playground" data-i18n="nav.playground" href="/playground">生图工作台</a>
      <a data-link-key="console" data-i18n="nav.console" href="/console">控制台</a>
      <a data-link-key="docs" data-i18n="nav.docs" href="/verge-api-docs/">文档</a>
    </nav>
    <div class="pages-header-actions" data-i18n-aria="header.actionsAria" aria-label="用户操作">
      <button type="button" class="pages-icon-button" data-i18n-aria="header.notice" aria-label="系统公告">
        <span class="icon-slot" data-icon-key="bell" aria-hidden="true"></span>
      </button>
      <div class="pages-action-wrap">
        <button type="button" class="pages-icon-button" id="theme-button" data-i18n-aria="header.theme" aria-label="切换主题" aria-haspopup="menu" aria-expanded="false">
          <span class="icon-slot" data-icon-key="theme" aria-hidden="true"></span>
        </button>
        <div class="pages-dropdown pages-theme-menu" id="theme-menu" role="menu" hidden>
          <button type="button" class="pages-dropdown-item" data-theme-option="light" role="menuitem">
            <span class="icon-slot pages-dropdown-icon" data-icon-key="themeLight" aria-hidden="true"></span>
            <span class="pages-dropdown-copy">
              <strong data-i18n="header.themeMenu.light.0">浅色模式</strong>
              <small data-i18n="header.themeMenu.light.1">始终使用浅色主题</small>
            </span>
          </button>
          <button type="button" class="pages-dropdown-item" data-theme-option="dark" role="menuitem">
            <span class="icon-slot pages-dropdown-icon" data-icon-key="themeDark" aria-hidden="true"></span>
            <span class="pages-dropdown-copy">
              <strong data-i18n="header.themeMenu.dark.0">深色模式</strong>
              <small data-i18n="header.themeMenu.dark.1">始终使用深色主题</small>
            </span>
          </button>
          <button type="button" class="pages-dropdown-item" data-theme-option="auto" role="menuitem">
            <span class="icon-slot pages-dropdown-icon" data-icon-key="themeAuto" aria-hidden="true"></span>
            <span class="pages-dropdown-copy">
              <strong data-i18n="header.themeMenu.auto.0">自动模式</strong>
              <small data-i18n="header.themeMenu.auto.1">跟随系统主题设置</small>
            </span>
          </button>
        </div>
      </div>
      <div class="pages-action-wrap">
        <button type="button" class="pages-icon-button" id="language-button" data-i18n-aria="header.language" aria-label="切换语言" aria-haspopup="menu" aria-expanded="false">
          <span class="icon-slot" data-icon-key="language" aria-hidden="true"></span>
        </button>
        <div class="pages-dropdown pages-language-menu" id="language-menu" role="menu" hidden>
          <button type="button" class="pages-language-item" data-locale-option="zh-CN" data-i18n="header.languageMenu.zh" role="menuitem">简体中文</button>
          <button type="button" class="pages-language-item" data-locale-option="en" data-i18n="header.languageMenu.en" role="menuitem">English</button>
        </div>
      </div>
      <div class="pages-auth-actions">
        <a class="pages-login" data-link-key="login" data-i18n="header.login" href="/login">登录</a>
        <a class="pages-register" data-link-key="register" data-i18n="header.register" href="/register">注册</a>
      </div>
    </div>
  </header>

  <main class="classic-home-page">
    <section class="classic-home-default" data-i18n-aria="desktop.title" aria-label="Verge API 首页">
      <div class="classic-home-hero">
        <div class="blur-ball blur-ball-indigo" aria-hidden="true"></div>
        <div class="blur-ball blur-ball-teal" aria-hidden="true"></div>

        <div class="classic-home-hero-content">
          <div class="classic-home-hero-inner">
            <div class="classic-home-provider-row" data-i18n-aria="desktop.providersAria" aria-label="支持的生图服务">
              <span class="classic-home-provider-chip">
                <span class="icon-slot classic-home-provider-icon" data-icon-key="openai" aria-hidden="true"></span>
                <span>OpenAI</span>
              </span>
              <span class="classic-home-provider-chip">
                <span class="icon-slot classic-home-provider-icon" data-icon-key="gemini" aria-hidden="true"></span>
                <span>Gemini</span>
              </span>
            </div>

            <h1 class="classic-home-title" data-i18n="desktop.title">Verge API：GPT Image 2 与 Gemini 生图接口</h1>
            <p class="classic-home-subtitle" data-i18n="desktop.subtitle">
              同一个 Base URL 支持 GPT Image 2 与 Gemini 同步和异步生图
            </p>

            <div class="classic-home-api-shell" data-i18n-aria="desktop.apiAria" aria-label="API 调用地址">
              <div class="classic-home-api-base">
                <span class="classic-home-api-base-text" id="api-base">http://localhost:3000</span>
              </div>
              <div class="classic-home-endpoint-pill">
                <button
                  type="button"
                  class="classic-home-endpoint-button"
                  id="endpoint-button"
                  data-i18n-aria="desktop.switchEndpoint"
                  aria-label="切换 API 端点"
                  title="/v1/images/generations"
                >
                  <span class="classic-home-endpoint-text" id="endpoint-text">/v1/images/generations</span>
                </button>
              </div>
              <button
                type="button"
                class="classic-home-copy-button"
                id="copy-button"
                data-i18n-aria="desktop.copyEndpoint"
                aria-label="复制 API 调用地址"
              >
                <span class="icon-slot classic-home-copy-icon" data-icon-key="copy" aria-hidden="true"></span>
              </button>
            </div>

            <div class="classic-home-actions">
              <a class="classic-home-action-btn classic-home-action-primary" data-link-key="startImage" href="/playground">
                <span class="classic-home-button-content">
                  <span class="icon-slot classic-home-action-icon" data-icon-key="imagePlus" aria-hidden="true"></span>
                  <span class="classic-home-button-content-right" data-i18n="desktop.startImage">开始生图</span>
                </span>
              </a>
              <a class="classic-home-action-btn classic-home-action-primary" data-link-key="apiKey" href="/console/token">
                <span class="classic-home-button-content">
                  <span class="icon-slot classic-home-action-icon" data-icon-key="key" aria-hidden="true"></span>
                  <span class="classic-home-button-content-right" data-i18n="desktop.apiKey">获取密钥</span>
                </span>
              </a>
              <a class="classic-home-action-btn classic-home-action-ghost" data-link-key="docs" href="/verge-api-docs/">
                <span class="classic-home-button-content">
                  <span class="icon-slot classic-home-action-icon" data-icon-key="file" aria-hidden="true"></span>
                  <span class="classic-home-button-content-right" data-i18n="desktop.docs">文档</span>
                </span>
              </a>
            </div>

            <section class="classic-home-reasons" aria-labelledby="classic-home-reasons-title">
              <h2 id="classic-home-reasons-title" data-i18n="desktop.reasonsTitle">为什么选择 Verge API？</h2>
              <div class="classic-home-reason-grid">
                <div class="classic-home-reason-card">
                  <p class="classic-home-reason-text" data-i18n="desktop.reasons.0">充值汇率，美元和人民币 1:1</p>
                </div>
                <div class="classic-home-reason-card">
                  <p class="classic-home-reason-text" data-i18n="desktop.reasons.1">OpenAI 与 Gemini 生图接口，资源无掺水</p>
                </div>
                <div class="classic-home-reason-card">
                  <p class="classic-home-reason-text" data-i18n="desktop.reasons.2">效果稳定、质量高</p>
                </div>
              </div>
            </section>

            <div class="classic-home-framework-strip" aria-hidden="true">
              <span class="icon-slot classic-home-framework-icon" data-icon-key="gallery"></span>
            </div>
          </div>
        </div>
      </div>
    </section>

    <section class="verge-mobile-home" data-i18n-aria="mobile.aria" aria-label="Verge API 移动首页">
      <div class="verge-mobile-home-hero">
        <div class="verge-mobile-home-eyebrow">
          <span class="icon-slot" data-icon-key="logo" aria-hidden="true"></span>
          <span>Verge API</span>
        </div>
        <div class="verge-mobile-home-providers" data-i18n-aria="desktop.providersAria" aria-label="支持的生图服务">
          <span>
            <span class="icon-slot" data-icon-key="openai" aria-hidden="true"></span>
            OpenAI
          </span>
          <span>
            <span class="icon-slot" data-icon-key="gemini" aria-hidden="true"></span>
            Gemini
          </span>
        </div>
        <h1 data-i18n="mobile.title">让每一次创作，都更简单。</h1>
        <p data-i18n="mobile.subtitle">
          一个支持 GPT Image 2 与 Gemini 的生图 API 和移动工作台，随时开始，结果清晰可追踪。
        </p>
        <a class="verge-mobile-home-primary" data-link-key="startImage" href="/playground">
          <span class="icon-slot" data-icon-key="imagePlus" aria-hidden="true"></span>
          <span data-i18n="desktop.startImage">开始生图</span>
          <span class="verge-mobile-arrow">→</span>
        </a>
        <a class="verge-mobile-home-secondary" data-link-key="apiKey" href="/console/token">
          <span class="icon-slot" data-icon-key="key" aria-hidden="true"></span>
          <span data-i18n="mobile.apiKey">获取 API 密钥</span>
        </a>
      </div>

      <div class="verge-mobile-home-api">
        <div class="verge-mobile-home-section-title">
          <span data-i18n="mobile.apiTitle">API 调用地址</span>
          <button type="button" id="mobile-endpoint-switch" data-i18n="mobile.switchEndpoint">切换端点</button>
        </div>
        <button type="button" class="verge-mobile-endpoint" id="mobile-copy-button">
          <span>
            <small id="mobile-api-base">http://localhost:3000</small>
            <strong id="mobile-endpoint-text">/v1/images/generations</strong>
          </span>
          <span class="icon-slot" data-icon-key="copy" aria-hidden="true"></span>
        </button>
      </div>

      <div class="verge-mobile-home-benefits">
        <h2 data-i18n="mobile.benefitsTitle">为什么选择 Verge API</h2>
        <div class="verge-mobile-benefit-row">
          <span class="verge-mobile-check">✓</span>
          <div>
            <strong data-i18n="mobile.benefits.0.0">充值汇率，美元和人民币 1:1</strong>
            <p data-i18n="mobile.benefits.0.1">余额清晰，使用成本一眼可见</p>
          </div>
        </div>
        <div class="verge-mobile-benefit-row">
          <span class="verge-mobile-check">✓</span>
          <div>
            <strong data-i18n="mobile.benefits.1.0">OpenAI 与 Gemini 生图接口，资源无掺水</strong>
            <p data-i18n="mobile.benefits.1.1">统一 Base URL，接入方式简单直接</p>
          </div>
        </div>
        <div class="verge-mobile-benefit-row">
          <span class="verge-mobile-check">✓</span>
          <div>
            <strong data-i18n="mobile.benefits.2.0">效果稳定、质量高</strong>
            <p data-i18n="mobile.benefits.2.1">任务进度、结果和账单全程可追踪</p>
          </div>
        </div>
        <a class="verge-mobile-docs-link" data-link-key="docs" href="/verge-api-docs/">
          <span data-i18n="mobile.docs">查看开发文档</span>
          <span>→</span>
        </a>
      </div>
    </section>
  </main>

  <footer class="pages-footer" data-i18n="footer">
    © 2026 Verge API. 版权所有
  </footer>

  <script>
    const ENDPOINTS = [
      { path: '/v1/images/generations' },
      { path: '/v1/images/tasks' },
    ];

    const pageConfig = window.VERGE_PAGES_CONFIG || {};
    const links = pageConfig.links || {};
    const icons = pageConfig.icons || {};
    const locales = pageConfig.locales || {};
    const siteBaseUrl = String(pageConfig.siteBaseUrl || '').replace(/\/+$/, '');
    const publicApiBaseUrl = String(pageConfig.publicApiBaseUrl || siteBaseUrl || window.location.origin).replace(/\/+$/, '');
    const storageKey = 'verge_pages_locale';
    const themeStorageKey = 'verge_pages_theme';
    const systemThemeQuery = window.matchMedia?.('(prefers-color-scheme: dark)');
    let endpointIndex = 0;
    let currentLocale =
      window.localStorage.getItem(storageKey) ||
      pageConfig.defaultLocale ||
      document.documentElement.lang ||
      'zh-CN';
    let currentThemeMode = window.localStorage.getItem(themeStorageKey) || 'auto';

    const nodes = {
      favicon: document.getElementById('page-favicon'),
      apiBase: document.getElementById('api-base'),
      endpointText: document.getElementById('endpoint-text'),
      endpointButton: document.getElementById('endpoint-button'),
      copyButton: document.getElementById('copy-button'),
      mobileApiBase: document.getElementById('mobile-api-base'),
      mobileEndpointText: document.getElementById('mobile-endpoint-text'),
      mobileEndpointSwitch: document.getElementById('mobile-endpoint-switch'),
      mobileCopyButton: document.getElementById('mobile-copy-button'),
      themeButton: document.getElementById('theme-button'),
      themeMenu: document.getElementById('theme-menu'),
      languageButton: document.getElementById('language-button'),
      languageMenu: document.getElementById('language-menu'),
    };

    function isAbsoluteUrl(value) {
      return /^https?:\/\//i.test(value) || /^\/\//.test(value);
    }

    function resolveUrl(value, baseUrl) {
      const rawValue = String(value || '').trim();
      if (!rawValue) return '';
      if (isAbsoluteUrl(rawValue)) return rawValue;
      if (!baseUrl) return rawValue;
      return `${baseUrl}${rawValue.startsWith('/') ? rawValue : `/${rawValue}`}`;
    }

    function getByPath(source, path) {
      return String(path || '')
        .split('.')
        .reduce((value, key) => (value == null ? value : value[key]), source);
    }

    function setIcon(slot, rawIcon) {
      const icon = String(rawIcon || '').trim();
      slot.replaceChildren();
      slot.classList.remove('is-empty');
      if (!icon) {
        slot.classList.add('is-empty');
        return;
      }
      const image = document.createElement('img');
      image.src = icon;
      image.alt = '';
      image.loading = 'lazy';
      image.decoding = 'async';
      image.addEventListener('error', () => slot.classList.add('is-empty'), { once: true });
      slot.appendChild(image);
    }

    function applyIcons() {
      document.querySelectorAll('[data-icon-key]').forEach((slot) => {
        setIcon(slot, icons[slot.dataset.iconKey]);
      });
      if (nodes.favicon && icons.logo) {
        nodes.favicon.setAttribute('href', icons.logo);
      }
    }

    function applyLinks() {
      document.querySelectorAll('[data-link-key]').forEach((link) => {
        const configuredHref = links[link.dataset.linkKey];
        const href = resolveUrl(configuredHref, siteBaseUrl);
        if (href) link.setAttribute('href', href);
      });
    }

    function normalizeThemeMode(mode) {
      return ['light', 'dark', 'auto'].includes(mode) ? mode : 'auto';
    }

    function effectiveTheme() {
      if (currentThemeMode === 'auto') {
        return systemThemeQuery?.matches ? 'dark' : 'light';
      }
      return currentThemeMode;
    }

    function themeIconKey() {
      if (currentThemeMode === 'light') return 'themeLight';
      if (currentThemeMode === 'dark') return 'themeDark';
      return 'themeAuto';
    }

    function closeMenus() {
      [nodes.themeMenu, nodes.languageMenu].forEach((menu) => {
        if (menu) menu.hidden = true;
      });
      [nodes.themeButton, nodes.languageButton].forEach((button) => {
        if (button) button.setAttribute('aria-expanded', 'false');
      });
    }

    function toggleMenu(menuName) {
      const targetMenu = menuName === 'theme' ? nodes.themeMenu : nodes.languageMenu;
      const targetButton = menuName === 'theme' ? nodes.themeButton : nodes.languageButton;
      const willOpen = Boolean(targetMenu?.hidden);
      closeMenus();
      if (targetMenu && targetButton && willOpen) {
        targetMenu.hidden = false;
        targetButton.setAttribute('aria-expanded', 'true');
      }
    }

    function updateMenuSelection() {
      document.querySelectorAll('[data-theme-option]').forEach((item) => {
        item.classList.toggle('is-selected', item.dataset.themeOption === currentThemeMode);
      });
      document.querySelectorAll('[data-locale-option]').forEach((item) => {
        item.classList.toggle('is-selected', item.dataset.localeOption === currentLocale);
      });
    }

    function applyTheme() {
      currentThemeMode = normalizeThemeMode(currentThemeMode);
      document.documentElement.dataset.themeMode = currentThemeMode;
      document.documentElement.dataset.theme = effectiveTheme();
      const themeIconSlot = nodes.themeButton?.querySelector('[data-icon-key]');
      if (themeIconSlot) {
        themeIconSlot.dataset.iconKey = themeIconKey();
        setIcon(themeIconSlot, icons[themeIconSlot.dataset.iconKey]);
      }
      updateMenuSelection();
    }

    function setThemeMode(mode) {
      currentThemeMode = normalizeThemeMode(mode);
      window.localStorage.setItem(themeStorageKey, currentThemeMode);
      applyTheme();
      closeMenus();
    }

    function setLocale(locale) {
      if (!locales[locale]) return;
      currentLocale = locale;
      window.localStorage.setItem(storageKey, currentLocale);
      applyLocale();
      closeMenus();
    }

    function localeData() {
      return locales[currentLocale] || locales[pageConfig.defaultLocale] || locales['zh-CN'] || {};
    }

    function applyLocale() {
      const text = localeData();
      document.documentElement.lang = currentLocale;
      if (text.meta?.title) document.title = text.meta.title;
      const description = document.querySelector('meta[name="description"]');
      if (description && text.meta?.description) {
        description.setAttribute('content', text.meta.description);
      }
      document.querySelectorAll('[data-i18n]').forEach((element) => {
        const value = getByPath(text, element.dataset.i18n);
        if (value != null) element.textContent = value;
      });
      document.querySelectorAll('[data-i18n-aria]').forEach((element) => {
        const value = getByPath(text, element.dataset.i18nAria);
        if (value != null) element.setAttribute('aria-label', value);
      });
      updateMenuSelection();
    }

    function currentEndpointPath() {
      return ENDPOINTS[endpointIndex]?.path || ENDPOINTS[0].path;
    }

    function renderEndpoint() {
      const path = currentEndpointPath();
      nodes.apiBase.textContent = publicApiBaseUrl;
      nodes.endpointText.textContent = path;
      nodes.endpointButton.title = path;
      nodes.mobileApiBase.textContent = publicApiBaseUrl;
      nodes.mobileEndpointText.textContent = path;
    }

    function switchEndpoint() {
      endpointIndex = (endpointIndex + 1) % ENDPOINTS.length;
      renderEndpoint();
    }

    async function copyEndpoint(button) {
      try {
        await navigator.clipboard.writeText(`${publicApiBaseUrl}${currentEndpointPath()}`);
        button.classList.add('is-copied');
        window.setTimeout(() => button.classList.remove('is-copied'), 1200);
      } catch (error) {
        console.error('copy failed', error);
      }
    }

    nodes.endpointButton.addEventListener('click', switchEndpoint);
    nodes.mobileEndpointSwitch.addEventListener('click', switchEndpoint);
    nodes.copyButton.addEventListener('click', () => copyEndpoint(nodes.copyButton));
    nodes.mobileCopyButton.addEventListener('click', () => copyEndpoint(nodes.mobileCopyButton));
    nodes.themeButton.addEventListener('click', (event) => {
      event.stopPropagation();
      toggleMenu('theme');
    });
    nodes.languageButton.addEventListener('click', (event) => {
      event.stopPropagation();
      toggleMenu('language');
    });
    document.querySelectorAll('[data-theme-option]').forEach((item) => {
      item.addEventListener('click', (event) => {
        event.stopPropagation();
        setThemeMode(item.dataset.themeOption);
      });
    });
    document.querySelectorAll('[data-locale-option]').forEach((item) => {
      item.addEventListener('click', (event) => {
        event.stopPropagation();
        setLocale(item.dataset.localeOption);
      });
    });
    document.addEventListener('click', closeMenus);
    document.addEventListener('keydown', (event) => {
      if (event.key === 'Escape') closeMenus();
    });
    systemThemeQuery?.addEventListener?.('change', () => {
      if (currentThemeMode === 'auto') applyTheme();
    });

    applyLinks();
    applyIcons();
    applyTheme();
    applyLocale();
    renderEndpoint();
    window.setInterval(switchEndpoint, 3000);
  </script>
</body>
</html>
