You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Next.js中使用@google/generative-AI通过URL上传视频的问题

在Next.js中通过URL上传视频到Google Gemini的解决方案

问题原因

GoogleAIFileManager.uploadFile()方法的第一个参数仅支持本地文件路径,不直接接受远程URL。你传入Vercel Blob的视频URL后,系统会将其解析为本地文件路径(比如错误信息里的C:\Users\...\https:\...mp4),导致找不到文件报错。

解决方案

需要先把远程视频下载到本地临时文件,再将临时文件上传到Google AI平台,完成推理后清理临时文件和云端文件。具体步骤:

  • 下载远程视频到Buffer
  • 创建本地临时文件存储视频内容
  • 上传临时文件到GoogleAIFileManager
  • 等待文件处理完成后调用模型生成摘要
  • 清理本地临时文件和云端文件

修改后的完整代码

"use server"

const { GoogleGenerativeAI } = require("@google/generative-ai");
import { GoogleAIFileManager, FileState } from "@google/generative-ai/server";
import { redirect } from "next/navigation";
import fetchVideoById from "./fetchVideoById";
import { writeFile, unlink } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import crypto from "node:crypto";

// Initialize GoogleAIFileManager with your API_KEY.
const fileManager = new GoogleAIFileManager(process.env.API_KEY);

// Access your API key as an environment variable
const genAI = new GoogleGenerativeAI(process.env.API_KEY);

// Choose a Gemini model.
const model = genAI.getGenerativeModel({
  model: "gemini-1.5-pro",
});

export async function generateSummary(formData) {
  const rows = await fetchVideoById(formData.get("id"));
  const url = rows["url"];
  let tempFilePath = null;
  let cloudFileName = null;

  try {
    console.log("Downloading remote video...");
    // 1. 下载远程视频到Buffer
    const response = await fetch(url);
    if (!response.ok) throw new Error(`Failed to download video: ${response.statusText}`);
    const videoBuffer = await response.arrayBuffer();

    // 2. 创建临时文件
    const tempFileName = `${crypto.randomUUID()}.mp4`;
    tempFilePath = join(tmpdir(), tempFileName);
    await writeFile(tempFilePath, Buffer.from(videoBuffer));

    console.log("Uploading file to Google AI...");
    // 3. 上传临时文件到GoogleAIFileManager
    const uploadResponse = await fileManager.uploadFile(tempFilePath, {
      mimeType: "video/mp4",
      displayName: rows["title"],
    });
    cloudFileName = uploadResponse.file.name;
    console.log(`Uploaded file ${uploadResponse.file.displayName} as: ${uploadResponse.file.uri}`);

    // 4. 等待文件处理完成
    let file = await fileManager.getFile(cloudFileName);
    while (file.state === FileState.PROCESSING) {
      process.stdout.write(".");
      await new Promise(resolve => setTimeout(resolve, 10000)); // 等待10秒再轮询
      file = await fileManager.getFile(cloudFileName);
    }

    if (file.state === FileState.FAILED) {
      throw new Error("Video processing failed.");
    }

    console.log(`File ${file.displayName} is ready for inference as ${file.uri}`);

    // 5. 调用模型生成摘要
    const result = await model.generateContent([
      {
        fileData: {
          mimeType: uploadResponse.file.mimeType,
          fileUri: uploadResponse.file.uri
        }
      },
      { text: "Summarize this video." },
    ]);

    const summary = result.response.text();
    console.log(summary);
    return summary;

  } catch (error) {
    console.error("Error during summary generation:", error);
    throw error;
  } finally {
    // 6. 清理资源:删除本地临时文件和云端文件
    if (tempFilePath) {
      try {
        await unlink(tempFilePath);
        console.log("Deleted local temp file.");
      } catch (err) {
        console.error("Failed to delete temp file:", err);
      }
    }
    if (cloudFileName) {
      try {
        await fileManager.deleteFile(cloudFileName);
        console.log("Deleted cloud file.");
      } catch (err) {
        console.error("Failed to delete cloud file:", err);
      }
    }
  }
}

关键说明

  • 使用node:os/tmpdir()获取系统临时目录,避免权限问题
  • 用crypto.randomUUID()生成唯一临时文件名,防止冲突
  • 用finally块确保无论成功失败都会清理临时文件和云端文件
  • 增加了下载视频的错误处理,确保下载失败时能及时抛出错误

内容的提问来源于stack exchange,提问作者kool

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 14:50:04