8 个赞
求源码!
这个是一句话生成的,还没有完善
mark,等一个,可以解析一下的。
1 个赞
是不是和bulid的原理不一样?
可以知道prompt吗
创建一个ai聊天界面
静等大佬
能不能像build一样调用所有模型
好像不行,我刚才改错了
走的似乎是公开接口,和build不太一样,公开接口没有测试模型的
而且需要手动输入密钥?
啥模型都有吧挺全的
我初步调查了下,这是它注入进 iframe 的代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<script>
(function (firebaseConfig, initialAuthToken, appId) {
window.__firebase_config = firebaseConfig;
window.__initial_auth_token = initialAuthToken;
window.__app_id = appId;
})(
'\n{\n "apiKey": "AIzaSyCqyCcs2R2e7AegGjvFAwG98wlamtbHvZY",\n "authDomain": "bard-frontend.firebaseapp.com",\n "projectId": "bard-frontend",\n "storageBucket": "bard-frontend.firebasestorage.app",\n "messagingSenderId": "175205271074",\n "appId": "1:175205271074:web:2b7bd4d34d33bf38e6ec7b"\n}\n',
"[REDACTED]",
"c_722a6f913c57135d_ai_chat_app_cn-280",
);
</script>
<script>
(function () {
// Ensure this script is executed only once
if (window.firebaseAuthBridgeScriptLoaded) {
return;
}
window.firebaseAuthBridgeScriptLoaded = true;
let nextTokenPromiseId = 0;
// Stores { resolve, reject } for ongoing token requests
const pendingTokenPromises = {};
// Listen for messages from the Host Application
window.addEventListener("message", function (event) {
const messageData = event.data;
if (
messageData &&
messageData.type === "RESOLVE_NEW_FIREBASE_TOKEN"
) {
const { success, token, error, promiseId } = messageData ??
{};
if (pendingTokenPromises[promiseId]) {
if (success) {
pendingTokenPromises[promiseId].resolve(token);
} else {
pendingTokenPromises[promiseId].reject(
new Error(error || "Token refresh failed from host."),
);
}
delete pendingTokenPromises[promiseId];
}
}
});
// Expose a function for the Generated App to request a new Firebase token
window.requestNewFirebaseToken = function () {
const currentPromiseId = nextTokenPromiseId++;
const promise = new Promise((resolve, reject) => {
pendingTokenPromises[currentPromiseId] = {
resolve,
reject,
};
});
if (window.parent && window.parent !== window) {
window.parent.postMessage({
type: "REQUEST_NEW_FIREBASE_TOKEN",
promiseId: currentPromiseId,
}, "*");
} else {
pendingTokenPromises[currentPromiseId].reject(
new Error("No parent window to request token from."),
);
delete pendingTokenPromises[currentPromiseId];
}
return promise;
};
})();
</script>
<script>
let realOriginalGetUserMedia = null;
if (
navigator.mediaDevices && navigator.mediaDevices.getUserMedia
) {
realOriginalGetUserMedia = navigator.mediaDevices.getUserMedia
.bind(navigator.mediaDevices);
}
(function () {
if (
navigator.mediaDevices && navigator.mediaDevices.__proto__
) {
try {
Object.defineProperty(
navigator.mediaDevices.__proto__,
"getUserMedia",
{
get: function () {
return undefined; // Or throw an error
},
configurable: false,
},
);
} catch (error) {
console.error("Error defining prototype getter:", error);
}
}
})();
(function () {
let originalGetUserMedia = realOriginalGetUserMedia;
const pendingMediaResolvers = {};
let nextMediaPromiseId = 0;
function interceptGetUserMedia() {
if (navigator.mediaDevices) {
Object.defineProperty(
navigator.mediaDevices,
"getUserMedia",
{
value: function (constraints) {
const mediaPromiseId = nextMediaPromiseId++;
const promise = new Promise((resolve, reject) => {
pendingMediaResolvers[mediaPromiseId] = (
granted,
) => {
delete pendingMediaResolvers[mediaPromiseId];
if (granted) {
if (originalGetUserMedia) {
originalGetUserMedia(constraints).then(
resolve,
).catch(reject);
} else {
reject(
new Error(
"Original getUserMedia not available.",
),
);
}
} else {
reject(
new DOMException(
"Permission denied",
"NotAllowedError",
),
);
}
};
});
window.parent.postMessage({
type: "requestMediaPermission",
constraints: constraints,
promiseId: mediaPromiseId,
}, "*");
return promise;
},
writable: false,
configurable: false,
},
);
}
}
interceptGetUserMedia();
const observer = new MutationObserver(
function (mutationsList, observer) {
for (const mutation of mutationsList) {
if (
mutation.type === "reconfigured" &&
mutation.name === "getUserMedia" &&
mutation.object === navigator.mediaDevices
) {
interceptGetUserMedia();
} else if (
mutation.type === "attributes" &&
mutation.attributeName === "getUserMedia" &&
mutation.target === navigator.mediaDevices
) {
interceptGetUserMedia();
} else if (
mutation.type === "childList" && mutation.addedNodes
) {
mutation.addedNodes.forEach((node) => {
if (node === navigator.mediaDevices) {
interceptGetUserMedia();
}
});
}
}
},
);
window.addEventListener("message", function (event) {
if (event.data) {
if (event.data.type === "resolveMediaPermission") {
const { promiseId, granted } = event.data;
if (pendingMediaResolvers[promiseId]) {
pendingMediaResolvers[promiseId](granted);
}
}
}
});
})();
</script>
<script>
(function (modelInformation) {
const originalFetch = window.fetch;
// TODO: b/421908508 - Move these out of the script and match all generative AI model calls.
let googleLlmBaseApiUrls = [
"https://generativelanguage.googleapis.com/v1beta/models/" +
modelInformation.textModelName + ":streamGenerateContent",
"https://generativelanguage.googleapis.com/v1beta/models/" +
modelInformation.textModelName + ":generateContent",
"https://generativelanguage.googleapis.com/v1beta/models/" +
modelInformation.imageModelName + ":predict",
"https://generativelanguage.googleapis.com/v1beta/models/" +
modelInformation.imageModelName + ":predictLongRunning",
"https://generativelanguage.googleapis.com/v1beta/models/" +
modelInformation.videoModelName + ":predict",
"https://generativelanguage.googleapis.com/v1beta/models/" +
modelInformation.videoModelName + ":predictLongRunning",
];
modelInformation.deprecatedTextModelNames.forEach(
(modelName) => {
googleLlmBaseApiUrls.push(
"https://generativelanguage.googleapis.com/v1beta/models/" +
modelName + ":streamGenerateContent",
"https://generativelanguage.googleapis.com/v1beta/models/" +
modelName + ":generateContent",
);
},
);
const pendingFetchResolvers = {};
let nextPromiseId = 0;
function handleStringInput(input, optionsArgument) {
const actualUrl = input;
const fetchCallArgs = [actualUrl, optionsArgument];
const effectiveOptions = optionsArgument || {};
const bodyForApiKeyCheck = effectiveOptions.body;
const bodyForPostMessage = effectiveOptions.body;
return {
actualUrl,
fetchCallArgs,
effectiveOptions,
bodyForApiKeyCheck,
bodyForPostMessage,
};
}
function handleRequestInput(input, optionsArgument) {
const actualUrl = input.url;
const fetchCallArgs = [input, optionsArgument];
const effectiveOptions = {
method: input.method,
headers: new Headers(input.headers),
};
let bodyForApiKeyCheck;
let bodyForPostMessage;
if (optionsArgument) {
if (optionsArgument.method) {
effectiveOptions.method = optionsArgument.method;
}
if (optionsArgument.headers) {
effectiveOptions.headers = new Headers(
optionsArgument.headers,
);
}
if ("body" in optionsArgument) {
bodyForApiKeyCheck = optionsArgument.body;
bodyForPostMessage = optionsArgument.body;
} else {
bodyForApiKeyCheck = undefined;
bodyForPostMessage = input.body;
}
} else {
bodyForApiKeyCheck = undefined;
bodyForPostMessage = input.body;
}
return {
actualUrl,
fetchCallArgs,
effectiveOptions,
bodyForApiKeyCheck,
bodyForPostMessage,
};
}
window.fetch = function (input, optionsArgument) {
let actualUrl;
let fetchCallArgs;
let effectiveOptions = {};
let bodyForApiKeyCheck;
let bodyForPostMessage;
if (typeof input === "string") {
({
actualUrl,
fetchCallArgs,
effectiveOptions,
bodyForApiKeyCheck,
bodyForPostMessage,
} = handleStringInput(input, optionsArgument));
} else if (input instanceof Request) {
({
actualUrl,
fetchCallArgs,
effectiveOptions,
bodyForApiKeyCheck,
bodyForPostMessage,
} = handleRequestInput(input, optionsArgument));
} else {
return originalFetch.apply(window, [
input,
optionsArgument,
]);
}
effectiveOptions.method = effectiveOptions.method || "GET";
if (!effectiveOptions.headers) {
effectiveOptions.headers = new Headers();
}
if (
typeof actualUrl === "string" &&
googleLlmBaseApiUrls.some((url) =>
actualUrl.startsWith(url)
)
) {
let apiKeyIsNull = true;
const regex = new RegExp("models/([^:]+)");
const modelNameMatch = actualUrl.match(regex);
const modelName = modelNameMatch
? modelNameMatch[1]
: "unspecified";
try {
const urlObject = new URL(actualUrl); // Use URL object for robust parsing
const apiKeyParam = urlObject.searchParams.get("key");
if (apiKeyParam) {
apiKeyIsNull = false;
}
} catch (e) {
// Continue checks even if URL parsing fails
}
if (apiKeyIsNull && effectiveOptions.headers) {
const h = new Headers(effectiveOptions.headers);
const apiKeyHeaderValue = h.get("X-API-Key") ||
h.get("x-api-key");
if (apiKeyHeaderValue) {
apiKeyIsNull = false;
return originalFetch.apply(window, fetchCallArgs);
}
}
if (
apiKeyIsNull && effectiveOptions.method &&
["POST", "PUT", "PATCH"].includes(
effectiveOptions.method.toUpperCase(),
) && typeof bodyForApiKeyCheck === "string"
) {
try {
const bodyData = JSON.parse(bodyForApiKeyCheck);
if (bodyData && bodyData.apiKey) {
apiKeyIsNull = false;
return originalFetch.apply(window, fetchCallArgs);
}
} catch (e) {
// Ignore JSON parsing errors
}
}
if (apiKeyIsNull) {
const promiseId = nextPromiseId++;
const promise = new Promise((resolve) => {
pendingFetchResolvers[promiseId] = (
resolvedResponse,
) => {
delete pendingFetchResolvers[promiseId];
resolve(resolvedResponse);
};
});
let serializedBodyForPostMessage;
if (
typeof bodyForPostMessage === "string" ||
bodyForPostMessage == null
) {
serializedBodyForPostMessage = bodyForPostMessage;
} else if (bodyForPostMessage instanceof ReadableStream) {
serializedBodyForPostMessage = null;
} else {
try {
serializedBodyForPostMessage = JSON.stringify(
bodyForPostMessage,
);
} catch (e) {
serializedBodyForPostMessage = null;
}
}
const messageOptions = {
method: effectiveOptions.method,
headers: Object.fromEntries(
new Headers(effectiveOptions.headers).entries(),
),
body: serializedBodyForPostMessage,
};
window.parent.postMessage({
type: "requestFetch",
url: actualUrl,
modelName: modelName,
options: messageOptions,
promiseId: promiseId,
}, "*");
return promise;
}
return originalFetch.apply(window, fetchCallArgs);
}
return originalFetch.apply(window, fetchCallArgs);
};
window.addEventListener("message", function (event) {
if (event.data && event.data.type === "resolveFetch") {
const { promiseId, response } = event.data;
if (pendingFetchResolvers[promiseId]) {
try {
const reconstructedResponse = new Response(
response.body,
{
status: response.status,
statusText: response.statusText,
headers: new Headers(response.headers),
},
);
pendingFetchResolvers[promiseId](reconstructedResponse);
} catch (error) {
pendingFetchResolvers[promiseId](
new Response(null, {
status: 500,
statusText:
"Interceptor Response Reconstruction Error",
}),
);
}
}
}
});
})({
"textModelName": "gemini-2.5-flash-preview-04-17",
"imageModelName": "imagen-3.0-generate-002",
"videoModelName": "veo-2.0-generate-001",
"deprecatedTextModelNames": ["gemini-2.0-flash"],
});
</script>
<script>
(function () {
const originalConsoleLog = console.log;
const originalConsoleError = console.error;
/**
* Normalizes an error event or a promise rejection reason into a structured error object.
* @param {*} errorEventOrReason The error object or reason.
* @return {object} Structured error data { message, name, stack }.
*/
function getErrorObject(errorEventOrReason) {
if (errorEventOrReason instanceof Error) {
return {
message: errorEventOrReason.message,
name: errorEventOrReason.name,
stack: errorEventOrReason.stack,
};
}
// Fallback for non-Error objects.
try {
return {
message: JSON.stringify(errorEventOrReason),
name: "UnknownErrorType",
stack: null,
};
} catch (e) {
return {
message: String(errorEventOrReason),
name: "UnknownErrorTypeNonStringifiable",
stack: null,
};
}
}
/**
* Converts an array of arguments (from log/error) into a single string.
* Handles Error objects specially to include their message and stack.
* @param {Array<*>} args - Arguments passed to console methods.
* @return {string} A string representation of the arguments.
*/
function stringifyArgs(args) {
return args
.map((arg) => {
if (arg instanceof Error) {
const { message, stack } = arg;
return `Error: ${message}${
stack ? ("\nStack: " + stack) : ""
}`;
}
if (typeof arg === "object" && arg !== null) {
try {
return JSON.stringify(arg);
} catch (error) {
return "[Circular Object]";
}
} else {
return String(arg);
}
})
.join(" ");
}
console.log = function (...args) {
const logString = stringifyArgs(args);
window.parent.postMessage(
{ type: "log", message: logString },
"*",
);
originalConsoleLog.apply(console, args);
};
console.error = function (...args) {
let errorData;
if (args.length > 0 && args[0] instanceof Error) {
const err = args[0];
// If the first arg is an Error, capture its details.
errorData = {
type: "error",
source: "CONSOLE_ERROR",
...getErrorObject(err),
rawArgsString: stringifyArgs(args.slice(1)),
timestamp: new Date().toISOString(),
};
} else {
// If not an Error object, treat all args as a general error message.
errorData = {
type: "error",
source: "CONSOLE_ERROR",
message: stringifyArgs(args),
name: "ConsoleLoggedError",
stack: null,
timestamp: new Date().toISOString(),
};
}
window.parent.postMessage(errorData, "*");
originalConsoleError.apply(console, args);
};
// Listen for global unhandled synchronous errors.
window.addEventListener("error", function (event) {
const errorDetails = event.error
? getErrorObject(event.error)
: {
message: event.message,
name: "GlobalError",
stack: null,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
};
window.parent.postMessage({
type: "error",
source: "global",
...errorDetails,
message: errorDetails.message || event.message,
timestamp: new Date().toISOString(),
}, "*");
});
// Listen for unhandled promise rejections (asynchronous errors).
window.addEventListener("unhandledrejection", function (event) {
const errorDetails = getErrorObject(event.reason);
window.parent.postMessage({
type: "error",
source: "unhandledrejection",
...errorDetails,
message: errorDetails.message ||
"Unhandled Promise Rejection",
timestamp: new Date().toISOString(),
}, "*");
});
})();
</script>
</head>
<body></body>
</html>
和 AI Studio Build 注入的代码大同小异,可以用类似的方法破解。
1 个赞
按照它注入的代码,它只会代理以下的 URL:
// Text model endpoints
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-04-17:streamGenerateContent"
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-04-17:generateContent"
// Image model endpoints
"https://generativelanguage.googleapis.com/v1beta/models/imagen-3.0-generate-002:predict"
"https://generativelanguage.googleapis.com/v1beta/models/imagen-3.0-generate-002:predictLongRunning"
// Video model endpoints
"https://generativelanguage.googleapis.com/v1beta/models/veo-2.0-generate-001:predict"
"https://generativelanguage.googleapis.com/v1beta/models/veo-2.0-generate-001:predictLongRunning"
// Deprecated model endpoints
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:streamGenerateContent"
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent"
所以回答标题的问题,只能调用这四个模型:gemini-2.5-flash-preview-04-17, imagen-3.0-generate-002, veo-2.0-generate-001, gemini-2.0-flash。
3 个赞
但是从generativelanguage.googleapis.com返回的模型列表一定是不包含test模型的。这在build上已经确定了
1 个赞



