AI蓝皮书:Gemini反代教程,免费API调用Gemini 3 pro模型(兼容酒馆/Chatbox)
AI本地布置&远端调用系列教程
[展开/折叠]-
从零开始了解本地AI部署
Ollama本地部署AI教程
-
盘点支持免费API调用的AI服务
远程接入API教程(Gemini/NVIDA/ModelScope/Hugging Face)
-
Gemini反代教程
支持免费接入酒馆/CHATBOX等应用
-
Docker&New-API搭建教程
整合不同的AI,创建自己的轮询API
Google AI/Gemini终于出3.0版本了!但是3.0版本当前仅允许在官方页面上免费试用,任何第三方API调用都要付费。虽然网页版给的很大方(100次/天),但是确实有很多应用第三方调用体验会更好。为了解决这个问题,BLOG主今天教大家如何通过反代(劫持网页端)的方式,让第三方软件也能免费调用GOOGLE最新的Gemini 3 pro模型!
PS:本教程整合自类脑多位大大的成果,原始教程参考的是这篇,已经集成了“𝓟𝓻𝓲𝓼𝓸𝓷𝓮𝓻”大佬提供的最新版本,安全性和稳定性都得到过验证。
SillyTavern(酒馆/AI猫娘)系列
[展开/折叠]-
SillyTavern(酒馆)从入门到精通
喂饭式教学,不可能学不会
-
手机(Android)安装布置教程
随时随地逗逗猫娘的方法
-
免费VPS服务器租用和布置教程
通过第三方服务器开设酒馆教程
-
各种技巧/插件的说明
玩酒馆必看的进阶教程
-
GPT-SoVITS文本转语音入门教程(含SillyTavern酒馆接入)
AI语音合成,提升沉浸感的好方法
-
酒馆本地跑文字模型测试和推荐
当前还不太行的本地模型测评
-
盘点支持免费API调用的AI服务
需要免费接入酒馆的AI,来看这里吧
-
Gemini反代,免费API调用Gemini 3 pro模型
当前酒馆免费接入的AI中效果最好的选择!
一、搭建Huggingface服务
我们首先需要使用Huggingface搭建一个反代服务器,架设一个从Google AI到终端服务(比如酒馆/chatbox)的桥梁。
1、打开官网,点击右上角Sign Up按钮,按照要求填写邮箱和密码(如果打不开网站,你应该需要梯子)。注册完成后,记住去邮箱点击验证链接,否则后面会无法继续操作。
2、接着打开BLOG主建立的这个仓库地址,点击上方右侧的三个点,在展开菜单中,选择“Duplicate this Space”,将会复制BLOG主这个仓库的内容到你自己的账号上。

3、在弹出的对话框中,Visibility中选择Public,确保服务器能被公网检索。然后下面的MY_SECRET_KEY是连接这个代理服务器的密码(展示密码为13579,第三方接入,这个密码是必须的),这里建议自己设置的复杂一些,以免出现安全风险。最后点击Duplicate Space,完成全部设置。

4、等待约1分钟,随后根据下图,确保这个新建的服务属于自己,确保服务已经正确运行。

5、然后再次点击上面的三个点,选择“Embed this Space”,随后在打开的窗口中,点击“Direct URL”右面的“Copy”按钮,这样就会在剪贴板中获得该服务的API接口地址(建议找个地方保存)。


6、保持这个网页开启,不能关闭!!不能关闭!!不能关闭!!
二、浏览器部分
1、类脑的大佬对服务部分做了更新,建议下载最新版本的“dark-browser-vps.js”(最新服务端dark-server-vps.js已经整合)。由于不同版本的内容需要对应,因此建议直接点击这里下载BLOG主整理好的文件。
扩展内容:更新服务器
[展开/折叠]-
如果未来代码有更新,并且希望手动更新到最新版,则需要到仓库下载“dark-server-vps.js”和“package.json”,上传并覆盖原本在“Files”下的同名文件。如有必要还需要更新Dockerfile中的代码(但一般不需要,BLOG主已经写好)。

2、接下来我们需要修改“dark-browser-vps.js”的一些配置,右键这个文件,选择笔记本打开,然后“CTRL+F”搜索“constructor(endpoint =”。最后在后面添加刚刚复制好的API接口地址。注意需要把原始地址中的“https”改成“wss”。

扩展内容:下载困难的朋友,可直接复制内容(记住修改)
[展开/折叠]-
const WS_ENDPOINT = “wss://wuchen.zeabur.app”;
const log = (…msgs) => {
const time = new Date().toLocaleTimeString(“zh-CN”, { hour12: false });
const ms = `.${new Date().getMilliseconds().toString().padStart(3, “0”)}`;
const timestamp = `[${time}${ms}]`;
console.log(`[ProxyClient]`, timestamp, …msgs);
const div = document.createElement(“div”);
div.textContent = `${timestamp} ${msgs.join(” “)}`;
document.body.appendChild(div);
};
class Connection extends EventTarget {
#ws = null;
#reconnectTimer = null;
#attempts = 0;
constructor(endpoint = “wss://hyy890627-studiosep.hf.space”) {
super();
this.endpoint = endpoint;
this.connected = false;
}
async connect() {
if (this.connected) return;
log(“连接中:”, this.endpoint);
try {
this.#ws = new WebSocket(this.endpoint);
this.#bindEvents();
} catch (err) {
log(“WS初始化失败:”, err.message);
this.#reconnect();
}
}
send(data) {
if (!this.connected) return log(“发送失败: 未连接”);
this.#ws.send(JSON.stringify(data));
}
#bindEvents() {
this.#ws.addEventListener(“open”, () => {
this.connected = true;
this.#attempts = 0;
this.#clearReconnectTimer();
log(“✅ 连接成功”);
this.dispatchEvent(new Event(“connected”));
});
this.#ws.addEventListener(“close”, () => {
if (this.connected) {
this.connected = false;
log(“❌ 连接断开”);
this.dispatchEvent(new Event(“disconnected”));
}
this.#reconnect();
});
this.#ws.addEventListener(“error”, (err) => log(“WS错误:”, err));
this.#ws.addEventListener(“message”, (e) => this.dispatchEvent(new MessageEvent(“message”, { data: e.data })));
}
#reconnect() {
if (this.#reconnectTimer) return;
this.#attempts++;
const delay = 5000;
log(`${delay / 1000}秒后尝试重连 (第 ${this.#attempts} 次)…`);
this.#reconnectTimer = setTimeout(() => {
this.#reconnectTimer = null;
this.connect();
}, delay);
}
#clearReconnectTimer() {
clearTimeout(this.#reconnectTimer);
this.#reconnectTimer = null;
}
}
class Processor {
#ops = new Map();
#domain = “generativelanguage.googleapis.com”;
async exec(spec, id) {
const ctrl = new AbortController();
this.#ops.set(id, ctrl);
try {
return await this.#retry(spec, ctrl);
} finally {
this.#ops.delete(id);
}
}
cancelAll() {
this.#ops.forEach((ctrl) => ctrl.abort(“Connection closed”));
this.#ops.clear();
}
async #retry(spec, ctrl) {
for (let i = 1; i <= 3; i++) {
try {
log(`执行请求 (${i}/3):`, spec.method, spec.path);
const url = this.#buildUrl(spec);
const config = this.#buildConfig(spec, ctrl.signal);
const res = await fetch(url, config);
if (!res.ok) throw new Error(`API错误: ${res.status} ${res.statusText} ${await res.text()}`);
return res;
} catch (err) {
if (err.name === “AbortError”) throw err;
log(`❌ 尝试 #${i} 失败: ${err.message.slice(0, 200)}`);
if (i < 3) await new Promise((r) => setTimeout(r, 2000));
else throw err;
}
}
}
#buildUrl(spec) {
let path = spec.path.startsWith(“/”) ? spec.path.slice(1) : spec.path;
const params = new URLSearchParams(spec.query_params);
if (spec.streaming_mode === “fake”) {
path = path.replace(“:streamGenerateContent”, “:generateContent”);
params.delete(“alt”);
}
const query = params.toString();
return `https://${this.#domain}/${path}${query ? `?${query}` : “”}`;
}
#buildConfig(spec, signal) {
const config = { method: spec.method, headers: this.#cleanHeaders(spec.headers), signal };
if ([“POST”, “PUT”, “PATCH”].includes(spec.method) && spec.body) config.body = spec.body;
return config;
}
#cleanHeaders = (headers) => {
const clean = { …headers };
[“host”, “connection”, “content-length”, “origin”, “referer”, “user-agent”, “sec-fetch-mode”, “sec-fetch-site”, “sec-fetch-dest”].forEach(h => delete clean[h]);
return clean;
}
}
class Proxy {
#conn;
#proc = new Processor();
constructor(endpoint) {
this.#conn = new Connection(endpoint);
this.#setup();
}
async init() {
log(“系统初始化…”);
await this.#conn.connect();
log(“系统就绪”);
}
#setup() {
this.#conn.addEventListener(“message”, (e) => this.#onMessage(e.data));
this.#conn.addEventListener(“disconnected”, () => this.#proc.cancelAll());
}
async #onMessage(data) {
try {
const spec = JSON.parse(data);
log(`收到请求: ${spec.method} ${spec.path} (${spec.streaming_mode || “fake”})`);
await this.#process(spec);
} catch (err) {
log(“处理错误:”, err.message);
this.#sendError(err, JSON.parse(data)?.request_id);
}
}
async #process(spec) {
const { request_id: id, streaming_mode: mode = “fake”, path } = spec;
const isStream = path.includes(“:streamGenerateContent”);
let finishReason = “UNKNOWN”;
try {
const res = await this.#proc.exec(spec, id);
this.#sendHeaders(res, id);
if (!res.body) {
this.#logComplete({ mode, isStream, fullBody: “”, finishReason });
return this.#sendEnd(id);
}
const stream = res.body.pipeThrough(new TextDecoderStream());
let fullBody = “”;
for await (const chunk of stream) {
if (mode === “real”) {
if (isStream) {
finishReason = this.#extractFinish(chunk, finishReason);
}
this.#sendChunk(chunk, id);
} else {
fullBody += chunk;
}
}
log(“流读取完成”);
this.#logComplete({ mode, isStream, fullBody, finishReason });
if (mode === “fake”) this.#sendChunk(fullBody, id);
this.#sendEnd(id);
} catch (err) {
log(`❌ 错误: ${err.message}`);
this.#sendError(err, id);
}
}
#extractFinish(chunk, currentReason) {
try {
const lines = chunk.split(‘\n’);
for (const line of lines) {
if (line.startsWith(‘data: ‘)) {
const payload = JSON.parse(line.slice(5));
const reason = payload.candidates?.[0]?.finishReason;
if (reason) return reason;
}
}
} catch {}
return currentReason;
}
#logComplete({ mode, isStream, fullBody, finishReason }) {
if (mode === “real”) {
if (!isStream) return log(“✅ 响应成功”);
return log(finishReason === “STOP” ? “✅ 响应成功” : `🤔 响应异常: ${finishReason}`);
}
let msg = “✅ 响应成功”;
if (isStream) {
try {
const parsed = JSON.parse(fullBody);
const reason = parsed.candidates?.[0]?.finishReason;
msg = reason === “STOP” ? “✅ 响应成功” : `🤔 响应异常: ${reason || “未知”}`;
} catch {
msg = “⚠️ 响应非JSON”;
}
}
log(msg);
}
#sendHeaders(res, id) {
const headers = {};
res.headers.forEach((v, k) => (headers[k] = v));
this.#conn.send({ request_id: id, event_type: “response_headers”, status: res.status, headers });
}
#sendChunk(chunk, id) {
if (chunk) this.#conn.send({ request_id: id, event_type: “chunk”, data: chunk });
}
#sendEnd(id) {
this.#conn.send({ request_id: id, event_type: “stream_close” });
log(“任务完成”);
}
#sendError(err, id) {
if (!id) return;
this.#conn.send({
request_id: id,
event_type: “error”,
status: 504,
message: `浏览器错误: ${err.name === “AbortError” ? “请求被中止” : err.message}`,
});
log(“错误已发送”);
}
}
async function main() {
document.body.innerHTML = “”;
try {
const proxy = new Proxy();
await proxy.init();
} catch (err) {
log(“启动失败:”, err.message);
}
}
main();
3、打开这个链接,登录自己的GOOGLE账号(需要梯子、不建议用大号)。在打开的页面中,点击“Code”,然后点击“index.tsx”,最后将上一步修改好的“dark-browser-vps.js”(或者直接复制修改好的上述代码)中所有内容,复制到右面的框中。

4、记住保存一下这个配置,点击右上角的保存图标,重新命名之后就可以保存(比如BLOG主保存名字是“酒馆”)。下一次使用的时候,我们只需要在GOOGLE AI主页,点击“Your apps”,然后选择刚刚保存的“酒馆”就可以再次载入,而无需再执行一次第三步。


5、我们回到“Preview”页面,正常来说等待几秒,看到绿色的“连接成功”标志,即代表GOOGLE AI已经正常工作。

6、我们再次观察浏览器,当前你的浏览器必须同时开启“Huggingface”和“Google AI”两个页面(只要使用服务就必须开启)。各位可以对照下图,再次确认是否左右两个网站都标注为绿色的“代理就绪”和绿色的“连接成功”,查看左右两边是否都是自己项目的名字。如果与下图一致,那么恭喜你,反代已经完成。

三、服务调用(范例)
1、以chatbox为例
添加“OpneAI API 兼容”页面,在下面填上Huggingface服务中生成的API链接以及刚刚自己设置的连接密码(如下图所示),然后点击右下角“获取”,即可得到当下支持的模型,这里选择最新的“gemini-3-pro-preview”。

回到主页面,选择好对应的模型,即可安心的使用。(反代当前有100次/天的使用限制,如果超过该数量,建议重复上面全部操作,做多一个API/KEY供使用。另外也可以根据BLOG主以前的NEW-API教程做API轮询)

2、以酒馆(SillyTavern)为例
打开酒馆API设置页面,按照下图进行设置。

如果OpenAI兼容有问题,可以选择使用Google AI Studio进行反代设置,跟着下图设置就行,理论上直接设置反代会比使用openai格式好一些。

完成API设置后,就可以愉快的免费使用Gemini 3.0逗猫娘了!对了,记住把预设中的“流式传输”打开才能正常输出哦。





一条评论
sink
666大佬