oki 发表于 2025-8-15 16:19:27

一个有点简陋的2api

全部通过AI生成,运行在deno平台,功能有点简陋,有能力的大佬可以完善一下{tieba42}

import { serve } from "https://deno.land/std@0.224.0/http/server.ts";

// ===== 配置 =====
const TARGET_API = Deno.env.get("TARGET_API");
const TARGET_MODEL = Deno.env.get("TARGET_MODEL");
const MODEL_ALIAS = Deno.env.get("MODEL_ALIAS");
const API_KEY = Deno.env.get("API_KEY");

if (!API_KEY) {
console.error("❌ 缺少 API_KEY 环境变量");
Deno.exit(1);
}

//密钥列表)
const authorizedKeys: Record<string, string> = {
"用户认证密钥": "备注",
// 你可以添加更多用户密钥
};

// ===== 工具函数 =====
function checkAuth(req: Request): string | null {
const authHeader = req.headers.get("Authorization");
if (!authHeader || !authHeader.startsWith("Bearer ")) {
    return null;
}
const token = authHeader.slice(7).trim();
if (token in authorizedKeys) {
    return token; // 返回通过验证的密钥(也可以返回用户名等)
}
return null;
}

function jsonError(message: string, status = 401) {
return new Response(
    JSON.stringify({
      error: {
      message,
      type: "authentication_error",
      status,
      },
    }),
    {
      status,
      headers: { "Content-Type": "application/json; charset=utf-8" },
    }
);
}

// ===== 主服务 =====
serve(async (req) => {
const url = new URL(req.url);
const pathname = url.pathname;

// 需要验证的路径
const protectedPaths = ["/v1/models", "/v1/chat/completions"];
if (protectedPaths.includes(pathname)) {
    const userKey = checkAuth(req);
    if (!userKey) {
      return jsonError("Invalid or missing access token", 401);
    }
    // 这里可以用 userKey 做日志、限流、配额等后续处理
    console.log(`用户密钥验证通过: ${userKey}`);
}

if (pathname === "/v1/models") {
    return new Response(
      JSON.stringify({
      object: "list",
      data: [
          {
            id: MODEL_ALIAS,
            object: "model",
            created: Date.now(),
            owned_by: "gmi-cloud",
          },
      ],
      }),
      { headers: { "Content-Type": "application/json; charset=utf-8" } },
    );
}

if (pathname === "/v1/chat/completions") {
    if (req.method !== "POST") {
      return new Response("Method Not Allowed", { status: 405 });
    }

    const body = await req.json();
    const isStream = body.stream === true;

    if (body.model === MODEL_ALIAS) {
      body.model = TARGET_MODEL;
    } else if (body.model !== TARGET_MODEL) {
      return new Response(
      JSON.stringify({
          error: {
            message: `Only model "${MODEL_ALIAS}" is supported.`,
            type: "invalid_request_error",
          },
      }),
      {
          status: 400,
          headers: { "Content-Type": "application/json; charset=utf-8" },
      },
      );
    }

    const res = await fetch(TARGET_API, {
      method: "POST",
      headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
      "Accept": "application/json",
      },
      body: JSON.stringify(body),
    });

    if (!isStream) {
      const text = await res.text();
      return new Response(text, {
      status: res.status,
      headers: { "Content-Type": "application/json; charset=utf-8" },
      });
    }

    const readableStream = new ReadableStream({
      async start(controller) {
      const reader = res.body?.getReader();
      const decoder = new TextDecoder();
      const encoder = new TextEncoder();

      if (!reader) {
          controller.enqueue(encoder.encode("data: \n\n"));
          controller.close();
          return;
      }

      try {
          while (true) {
            const { done, value } = await reader.read();
            if (done) break;
            controller.enqueue(encoder.encode(decoder.decode(value, { stream: true })));
          }
      } finally {
          controller.close();
      }
      },
    });

    return new Response(readableStream, {
      status: 200,
      headers: {
      "Content-Type": "text/event-stream; charset=utf-8",
      "Cache-Control": "no-cache",
      "Connection": "keep-alive",
      "Access-Control-Allow-Origin": "*",
      },
    });
}

if (pathname === "/v1/test") {
    const testBody = {
      model: TARGET_MODEL,
      messages: [{ role: "user", content: "你好,请返回你好。" }],
      temperature: 0.3,
      stream: false,
    };

    try {
      const = await Promise.all([
      fetch(TARGET_API, {
          method: "POST",
          headers: {
            "Authorization": `Bearer ${API_KEY}`,
            "Content-Type": "application/json",
            "Accept": "application/json",
          },
          body: JSON.stringify(testBody),
      }),
      fetch("https://api.ipify.org?format=json"),
      ]);

      const = await Promise.all();

      const now = new Intl.DateTimeFormat("zh-CN", {
      timeZone: "Asia/Shanghai",
      dateStyle: "full",
      timeStyle: "long",
      }).format(new Date());

      if (res.ok) {
      return new Response(
          JSON.stringify({
            success: true,
            message: "API 可用",
            ip: ipJson.ip,
            now,
          }),
          { headers: { "Content-Type": "application/json; charset=utf-8" } },
      );
      } else {
      return new Response(
          JSON.stringify({
            success: false,
            message: "API 响应异常",
            ip: ipJson.ip,
            now,
            error: json,
          }),
          {
            status: res.status,
            headers: { "Content-Type": "application/json; charset=utf-8" },
          },
      );
      }
    } catch (err) {
      return new Response(
      JSON.stringify({
          success: false,
          message: "请求失败",
          error: err.message,
      }),
      { status: 500, headers: { "Content-Type": "application/json; charset=utf-8" } },
      );
    }
}

    return new Response("Not Found", { status: 404 });
});
页: [1]
查看完整版本: 一个有点简陋的2api