+
96
-

回答

vertex ai有个模型广场,里面有70+模型可以调用,注册google cloud送90天的150美元免费额度。可以白嫖里面的ai模型。

800_auto

800_auto

800_auto

800_auto

800_auto

800_auto

800_auto

800_auto

800_auto

800_auto

记得先要创建一个项目,然后把开通service account,获取json文件的key,忘记的可以看这个教程点击打开链接

我们以google自己的gemini为例,把他作为代理部署在cloudflare的worker上,其他的模型大同小异,直接把相关的url参数修改一下就好了。

800_auto

cloudflare的worker代码:

// 配置变量
const API_KEY ="你设定的key";
const PROJECT_ID = '';
const CLIENT_EMAIL = '';
const PRIVATE_KEY ="";
const API_ENDPOINT="us-central1-aiplatform.googleapis.com"

const LOCATION_ID="us-central1"
addEventListener("fetch", (event) => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  let headers = new Headers({
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Headers": "*",
      "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
  });
  if (request.method === "OPTIONS") {
      return new Response(null, { headers });
  } else if (request.method === "GET") {
    return new Response("404 Not Found", { status: 404 });
     // return createErrorResponse(405, "invalid_request_error", "GET method is not allowed");
  }

  const apiKey = request.headers.get("x-api-key");
  if (!API_KEY || API_KEY !== apiKey) {
      return createErrorResponse(401, "authentication_error", "invalid x-api-key");
  }

  const signedJWT = await createSignedJWT(CLIENT_EMAIL, PRIVATE_KEY)
  const [token, err] = await exchangeJwtForAccessToken(signedJWT)
  if (token === null) {
      console.log(`Invalid jwt token: ${err}`)
      return createErrorResponse(500, "api_error", "invalid authentication credentials");
  }

  try {

    return handleMessagesEndpoint(request, token);
     
  } catch (error) {
      console.error(error);
      return createErrorResponse(500, "api_error", "An unexpected error occurred");
  }
}

async function handleMessagesEndpoint(request, api_token) {
 

  let payload;
  try {
      payload = await request.json();
  } catch (err) {
      return createErrorResponse(400, "invalid_request_error", "The request body is not valid JSON.");
  }



  const stream = payload.stream || false;
  const model = payload.model;
  const url = `https://${API_ENDPOINT}/v1/projects/${PROJECT_ID}/locations/${LOCATION_ID}/publishers/google/models/${model}:streamGenerateContent`;
  delete payload.model;
  delete payload.stream;
  let response, contentType
  try {
      response = await fetch(url, {
          method: 'POST',
          headers: {
              'Content-Type': 'application/json',
              'Authorization': `Bearer ${api_token}`
          },
          body: JSON.stringify(payload)
      });
      contentType = response.headers.get("Content-Type") || "application/json";
  } catch (error) {
      return createErrorResponse(500, "api_error", "Server Error");
  }

  if (stream && contentType.startsWith('text/event-stream')) {
      if (!(response.body instanceof ReadableStream)) {
          return createErrorResponse(500, "api_error", "Server Error");
      }

      const encoder = new TextEncoder();
      const decoder = new TextDecoder("utf-8");
      let buffer = '';
      let { readable, writable } = new TransformStream({
          transform(chunk, controller) {
              let decoded = decoder.decode(chunk, { stream: true });
              buffer += decoded
              let eventList = buffer.split(/\r\n\r\n|\r\r|\n\n/g);
              if (eventList.length === 0) return;
              buffer = eventList.pop();

              for (let event of eventList) {
                  controller.enqueue(encoder.encode(`${event}\n\n`));
              }
          },
      });
      response.body.pipeTo(writable);
      return new Response(readable, {
          status: response.status,
          headers: {
              "Content-Type": response.headers.get("Content-Type") || "text/event-stream",
              "Access-Control-Allow-Origin": "*",
          },
      });
  } else {
      try {
          let data = await response.text();
          return new Response(data, {
              status: response.status,
              headers: {
                  "Content-Type": contentType,
                  "Access-Control-Allow-Origin": "*",
              },
          });
      } catch (error) {
          return createErrorResponse(500, "api_error", "Server Error");
      }
  }
}

function createErrorResponse(status, errorType, message) {
  const errorObject = { type: "error", error: { type: errorType, message: message } };
  return new Response(JSON.stringify(errorObject), {
      status: status,
      headers: {
          "Content-Type": "application/json",
          "Access-Control-Allow-Origin": "*",
      },
  });
}

async function createSignedJWT(email, pkey) {
  pkey = pkey.replace(/-----BEGIN PRIVATE KEY-----|-----END PRIVATE KEY-----|\r|\n|\\n/g, "");
  let cryptoKey = await crypto.subtle.importKey(
      "pkcs8",
      str2ab(atob(pkey)),
      {
          name: "RSASSA-PKCS1-v1_5",
          hash: { name: "SHA-256" },
      },
      false,
      ["sign"]
  );

  const authUrl = "https://www.googleapis.com/oauth2/v4/token";
  const issued = Math.floor(Date.now() / 1000);
  const expires = issued + 600;

  const header = {
      alg: "RS256",
      typ: "JWT",
  };

  const payload = {
      iss: email,
      aud: authUrl,
      iat: issued,
      exp: expires,
      scope: "https://www.googleapis.com/auth/cloud-platform",
  };

  const encodedHeader = urlSafeBase64Encode(JSON.stringify(header));
  const encodedPayload = urlSafeBase64Encode(JSON.stringify(payload));

  const unsignedToken = `${encodedHeader}.${encodedPayload}`;

  const signature = await crypto.subtle.sign(
      "RSASSA-PKCS1-v1_5",
      cryptoKey,
      str2ab(unsignedToken)
  );

  const encodedSignature = urlSafeBase64Encode(signature);
  return `${unsignedToken}.${encodedSignature}`;
}

async function exchangeJwtForAccessToken(signed_jwt) {
  const auth_url = "https://www.googleapis.com/oauth2/v4/token";
  const params = {
      grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
      assertion: signed_jwt,
  };

  const r = await fetch(auth_url, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: Object.entries(params)
          .map(([k, v]) => k + "=" + v)
          .join("&"),
  }).then((res) => res.json());

  if (r.access_token) {
      return [r.access_token, ""];
  }

  return [null, JSON.stringify(r)];
}

function str2ab(str) {
  const buffer = new ArrayBuffer(str.length);
  let bufferView = new Uint8Array(buffer);
  for (let i = 0; i < str.length; i++) {
      bufferView[i] = str.charCodeAt(i);
  }
  return buffer;
}

function urlSafeBase64Encode(data) {
  let base64 = typeof data === "string" ? btoa(encodeURIComponent(data).replace(/%([0-9A-F]{2})/g, (match, p1) => String.fromCharCode(parseInt("0x" + p1)))) : btoa(String.fromCharCode(...new Uint8Array(data)));
  return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}

部署worker后记得要绑定自己的独立域名,cloudflare的免费子域名国内访问不了

800_auto

最后就可以访问了

    <script type="text/javascript">
     fetch('https://worker绑定的自己的域名/',{body: JSON.stringify({
        model: 'gemini-1.5-pro-001',
        

    "contents": [
        {
            "role": "user",
            "parts": [
                {"text":"hello"}
            ]
        }
    ],
    "generationConfig": {
        "maxOutputTokens": 8192,
        "temperature": 1,
        "topP": 0.95,
    },
    "safetySettings": [
        {
            "category": "HARM_CATEGORY_HATE_SPEECH",
            "threshold": "BLOCK_MEDIUM_AND_ABOVE"
        },
        {
            "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
            "threshold": "BLOCK_MEDIUM_AND_ABOVE"
        },
        {
            "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
            "threshold": "BLOCK_MEDIUM_AND_ABOVE"
        },
        {
            "category": "HARM_CATEGORY_HARASSMENT",
            "threshold": "BLOCK_MEDIUM_AND_ABOVE"
        }
    ],
       
       
    }),
    method: 'POST',
    headers: {
        'content-type': 'application/json',
        'x-api-key':'自己设定的key'    

    }}) // 替换为实际的 JSON URL
  .then(response => response.json())
  .then(data => {
    // 遍历 JSON 数据并提取 text 字段
    data.forEach(item => {
      item.candidates.forEach(candidate => {
        candidate.content.parts.forEach(part => {
          if (part.text) {
            console.log(part.text);
          }
        });
      });
    });
  })
  .catch(error => console.error('Error fetching the JSON:', error));
    </script>
 
		

php

<?php
$url = 'https://自己绑定worker的域名/';
$apiKey = '你设定的key';

$data = [
    'model' => 'gemini-1.5-pro-001',
    'contents' => [
        [
            'role' => 'user',
            'parts' => [
                ['text' => 'hello']
            ]
        ]
    ],
    'generationConfig' => [
        'maxOutputTokens' => 8192,
        'temperature' => 1,
        'topP' => 0.95,
    ],
    'safetySettings' => [
        [
            'category' => 'HARM_CATEGORY_HATE_SPEECH',
            'threshold' => 'BLOCK_MEDIUM_AND_ABOVE'
        ],
        [
            'category' => 'HARM_CATEGORY_DANGEROUS_CONTENT',
            'threshold' => 'BLOCK_MEDIUM_AND_ABOVE'
        ],
        [
            'category' => 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
            'threshold' => 'BLOCK_MEDIUM_AND_ABOVE'
        ],
        [
            'category' => 'HARM_CATEGORY_HARASSMENT',
            'threshold' => 'BLOCK_MEDIUM_AND_ABOVE'
        ]
    ]
];

$jsonData = json_encode($data);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'x-api-key: ' . $apiKey
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);

if (curl_errno($ch)) {
    echo 'Error:' . curl_error($ch);
} else {
    $responseData = json_decode($response, true);
    foreach ($responseData as $item) {
        foreach ($item['candidates'] as $candidate) {
            foreach ($candidate['content']['parts'] as $part) {
                if (isset($part['text'])) {
                    echo $part['text'] . "\n";
                }
            }
        }
    }
}

curl_close($ch);
?>

网友回复

我知道答案,我要回答