现在的Gemini 官网Canvas能调用模型,能调用哪些模型?

8 个赞

求源码!

这个是一句话生成的,还没有完善

mark,等一个,可以解析一下的。

@HCPTangHY

1 个赞

是不是和bulid的原理不一样?

可以知道prompt吗

创建一个ai聊天界面

静等大佬

代码里不是写了吗,我这里反正是2.0 flash,刚刚测试了一下,分享链接也能使用

1 个赞

在最后一页,大家试试看

能不能像build一样调用所有模型

好像不行,我刚才改错了

2 个赞

走的似乎是公开接口,和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 个赞