vertex ai有个模型广场,里面有70+模型可以调用,注册google cloud送90天的150美元免费额度。可以白嫖里面的ai模型。
记得先要创建一个项目,然后把开通service account,获取json文件的key,忘记的可以看这个教程点击打开链接
我们以google自己的gemini为例,把他作为代理部署在cloudflare的worker上,其他的模型大同小异,直接把相关的url参数修改一下就好了。
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的免费子域名国内访问不了
最后就可以访问了
<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); ?>
网友回复