Type something to search...
解锁实时多模态魔法:使用 Next.js 构建一个快速的 Gemini 2.0 应用程序!

解锁实时多模态魔法:使用 Next.js 构建一个快速的 Gemini 2.0 应用程序!

使用 Gemini 2.0 API 和 Next.js 构建多模态实时应用:音频、视频和转录

Gemini终极开发教程

嘿,Gemini开发教程又来了。这次,我将介绍一个新的实践网页项目,演示如何使用Next.js框架构建一个基于Gemini 2.0多模态实时API的无服务器应用程序,实现一个生产就绪的聊天应用,支持实时音频和视频互动,使用Typescript编写。

请观看演示视频:

这个项目在架构和用户界面上相较于我之前的多模态聊天应用演示有了显著的改进,而非功能上的改进。摆脱了单独的客户端-服务器结构,我使用Next.js构建了一个紧凑的解决方案,作为统一的框架。

Next.js同时管理Node.js的服务器端操作和React支持的客户端UI更新,利用这些,我构建了一个高效的开发管道,便于维护和部署,最重要的是,该框架可以轻松扩展,以支持更多自定义功能,作为商业实时项目的启动器。

技术简要概述

该应用程序接受来自客户端摄像头和麦克风的视频和音频输入,通过自定义音频处理例程在本地处理这些流,并通过WebSocket将媒体数据发送到Gemini API端点。响应——包括Gemini生成的音频输出和转录——被处理并集成回由Shadcn UI组件支持的互动聊天界面中。

系统架构

该应用的架构专注于实时性能和最小延迟。以下是一个框图,展示了组件在框架栈内的交互以及过程工作流:

系统由以下主要功能模块组成:

1. 媒体捕获与处理:

  • 浏览器中的“CameraPreview 组件”使用标准 web API 捕获用户的视频和音频流。
  • 音频数据被发送到“音频处理模块”,在这里 AudioWorklet(在 audio-processor.js 中实现)将原始 PCM 音频处理为二进制块。

2. 发送到 Gemini API:

  • 处理后的 PCM 音频块(以及编码为 base64 图像的视频帧)被交给“GeminiWebSocket 服务”。
  • 此服务与 Gemini 多模态实时 API 端点保持可靠的 WebSocket 连接。

3. 音频输出处理:

  • 在接收到来自 Gemini API 的音频响应后,服务现在将传入的 PCM 数据路由到“音频输出管理器”。
  • 在这里,数据被推入队列,以确保音频块按顺序播放。
  • 此模块还计算音频播放级别以更新用户界面指示器。

4. 音频播放调度:

  • 排队的音频片段随后被发送到“音频播放模块”。
  • 使用 Web Audio API,该模块基于处理后的 PCM 数据创建一个 AudioBuffer 并进行播放。
  • 在一个片段播放完成后,服务检查队列以继续播放任何剩余音频,确保连续输出。

5. 转录服务:

  • 一旦通过 Gemini WebSocket 服务检测到完整的轮次,累积的音频(通过工具函数转换为 WAV 格式)将被发送到“转录工作流”。
  • 然后转录文本被返回并集成到聊天界面中。
  • 我们必须将 PCM 转换为 WAV 的原因是,尽管实验性的多模态实时 API 支持 PCM 格式,但 PCM 格式不在 Gemini 的基本音频理解支持列表中。

6. 聊天 UI 更新:

  • 最后,任何文本响应消息都会传递到“聊天 UI 组件”。该模块使用特定的 ShadcnUI 小部件,例如用于显示可滚动对话窗口的 ScrollArea 组件和 Avatar 组件。

代码讲解:关键功能模块

以下是项目中关键组件和功能模块的详细讲解。每个部分都包含简要说明和注释的代码片段。

0. 可自定义的参数

  • 环境变量:Gemini API 密钥存储在 .env.local 文件中。
  • 模型名称和端点:该项目使用特定的模型标识符。转录工作流使用“gemini-2.0-flash-lite-preview-02–05”或甚至“gemini-1.5-flash-8b”模型来完成这个简单的任务,而实时流媒体则引用“models/gemini-2.0-flash-exp”。
  • 音频采样率:配置了两种采样率:16000 Hz 采样率用于从 CameraPreview 组件捕获音频,24000 Hz 采样率用于播放音频响应。

1. Gemini WebSocket 服务

app/services/geminiWebSocket.ts 文件中的 GeminiWebSocket 类负责管理与 Gemini API 的 WebSocket 连接。

它处理初始设置、媒体数据块传输、音频播放和持续的媒体处理。

连接建立和设置

当调用 connect 方法时,它使用提供的 API 密钥构建的 URL 打开 WebSocket 连接。一旦连接成功,服务立即发送初始设置消息以配置响应方式(例如,AUDIO):

// GeminiWebSocket.connect method snippet
this.ws = new WebSocket(WS_URL);
this.ws.onopen = () => {
  this.isConnected = true;
  this.sendInitialSetup(); // Send configuration to Gemini API
};

发送媒体数据

当捕获音频(PCM)或图像(JPEG)数据时,它会被编码为 base64 并传递给 sendMediaChunk 函数。该函数相应地构建消息负载并通过 WebSocket 发送:

// sendMediaChunk function snippet
const message = {
  realtime_input: {
    media_chunks: [{
      mime_type: mimeType === "audio/pcm" ? "audio/pcm" : mimeType,
      data: b64Data
    }]
  }
};
this.ws?.send(JSON.stringify(message));

这种抽象确保每个媒体数据块都以一致的格式处理。

响应处理和音频播放

handleMessage 方法接收来自 Gemini API 的消息。它通过检查 MIME 类型来判断音频数据是否返回,并相应地进行处理:

// Key snippet from handleMessage (audio processing)
if (part.inlineData?.mimeType === "audio/pcm;rate=24000") {
  this.accumulatedPcmData.push(part.inlineData.data);
  this.playAudioResponse(part.inlineData.data);
}

在收集 PCM 数据后,该方法将其转换并排队进行播放。当系统确定模型的一个回合已完成时,它使用一个工具函数将累积的 PCM 数据转换为 WAV 格式(见下文),然后将其发送到转录服务。

2. 转录服务

app/services/transcriptionService.ts 中的 TranscriptionService 类封装了用于转录音频响应的逻辑。当 Gemini 回合完成时,累积的 PCM 数据被转换为 WAV,然后将该 WAV 数据传递给转录服务。

转录音频方法

transcribeAudio 方法接受 base64 编码的 WAV 数据,并将其发送到 Gemini 生成模型进行转录。然后解析响应并以纯文本形式返回:

// TranscriptionService.transcribeAudio method snippet
async transcribeAudio(audioBase64: string, mimeType: string = "audio/wav"): Promise<string> {
  // Calls Gemini’s generative model to generate transcription text
  const result = await this.model.generateContent([
    {
      inlineData: { mimeType: mimeType, data: audioBase64 }
    },
    { text: "Please transcribe the spoken language in this audio accurately." },
  ]);
  return result.response.text();
}

再一次,一旦 Genimi API 允许我们通过支持并发响应模式 [“AUDIO”, “TEXT”] 来响应组合音频和文本流,我们就可以取消这一转录部分。

3. 摄像头预览和音频捕获

CameraPreview.tsx 组件是客户端媒体捕获功能的核心。它管理视频显示、麦克风捕获和定期图像捕获以发送到 Gemini。

切换摄像头

toggleCamera 函数负责开启和关闭媒体流。它请求用户设备的视频和音频流,设置媒体源,并将其分配给相关元素:

// toggleCamera function snippet in CameraPreview.tsx
const toggleCamera = async () => {
  if (isStreaming && stream) {
    // Stop all tracks and clear the stream
    stream.getTracks().forEach(track => track.stop());
    videoRef.current.srcObject = null;
    setStream(null);
    setIsStreaming(false);
  } else {
    // Request media from the browser
    const videoStream = await navigator.mediaDevices.getUserMedia({ video: true });
    const audioStream = await navigator.mediaDevices.getUserMedia({
      audio: { sampleRate: 16000, channelCount: 1, echoCancellation: true }
    });
    // Combine the streams and set them for display and processing
    videoRef.current.srcObject = videoStream;
    setStream(new MediaStream([...videoStream.getTracks(), ...audioStream.getTracks()]));
    setIsStreaming(true);
  }
};

定期图像捕获

除了音频外,还定期从视频流中捕获图像以发送到 Gemini。captureAndSendImage 函数将当前视频帧绘制到一个隐藏的画布上,将其转换为 base64 编码的 JPEG,然后通过 WebSocket 连接发送:

// captureAndSendImage snippet from CameraPreview.tsx
const captureAndSendImage = () => {
  // Draw video frame onto canvas
  const canvas = videoCanvasRef.current;
  const context = canvas.getContext('2d');
  context.drawImage(videoRef.current, 0, 0);
  // Convert the canvas image to JPEG base64 data
  const imageData = canvas.toDataURL('image/jpeg', 0.8);
  const b64Data = imageData.split(',')[1];
  geminiWsRef.current.sendMediaChunk(b64Data, "image/jpeg");
};

这种定期轮询确保 Gemini 除了实时音频外,还能接收到稳定的视觉数据流。

4. 音频处理和 PCM 到 WAV 转换

为了确保从麦克风捕获的音频被正确处理和转录,我们创建了两个关键组件:一个用于实时 PCM 处理的 AudioWorklet 和一个将 PCM 数据转换为 WAV 格式的工具函数。

AudioWorklet 处理器

自定义的 AudioWorklet(在 public/worklets/audio-processor.js 中)实时累积和处理原始音频样本。当缓冲区满时,它将浮点样本转换为 16 位整数数组,计算音频水平,并将处理后的 PCM 数据发送回主线程:

// AudioProcessor class in audio-processor.js
class AudioProcessor extends AudioWorkletProcessor {
  process(inputs, outputs, parameters) {
    // Accumulate and process PCM samples
    // When buffer is full, convert samples to 16-bit PCM
    this.port.postMessage({
      pcmData: buffer,         // Buffer containing PCM samples
      level: Math.min(computedLevel * 5, 100)
    }, [buffer]);
    
    return true;
  }
}

registerProcessor('audio-processor', AudioProcessor);

这将重负载音频处理到专用线程,同时保持主 UI 的响应性。

PCM 到 WAV 转换工具

在将音频数据发送进行转录之前,必须将 PCM 数据转换为 WAV 格式。app/utils/audioUtils.ts 中的 pcmToWav 函数通过构造 WAV 头并附加原始音频样本来完成此操作:

// pcmToWav function snippet from audioUtils.ts
export function pcmToWav(pcmData: string, sampleRate: number = 24000): Promise<string> {
  // Decode base64 PCM string, create WAV header, combine with PCM samples
  // Return a promise that resolves to a base64-encoded WAV string
}

5. 聊天 UI 组件

聊天界面在 app/page.tsx 中渲染。该文件利用 ShacdnUI 组件实现干净且响应式的布局。关键组件包括:

  • ScrollArea:提供一个可滚动的容器用于聊天消息。
  • Avatar, AvatarImage, AvatarFallback:用于显示 Gemini 的个人资料图片,以确保视觉上的清晰区分。

聊天消息的渲染通过以下方式完成:

{messages.map((message, index) => (
  message.type === 'human' ? (
    <HumanMessage key={`msg-${index}`} text={message.text} />
  ) : (
    <GeminiMessage key={`msg-${index}`} text={message.text} />
  )
))}

运行应用程序

现在,掌握了这个项目的基本知识,我们可以运行应用程序。

克隆仓库:

首先从 GitHub 克隆完整的源代码:

git clone https://github.com/yeyu2/gemini-nextjs.git

安装依赖:

导航到项目根目录,并使用 npm(或 yarn)安装依赖:

cd gemini-nextjs
npm install

环境配置:

在根目录下创建一个 .env.local 文件,并添加您的 Gemini API 密钥:

NEXT_PUBLIC_GEMINI_API_KEY=YOUR_API_KEY_HERE

启动开发服务器:

使用 Next.js 开发服务器启动无服务器应用程序:

npm run dev

打开您的浏览器并访问 http://localhost:3000 以查看应用程序的运行情况。

结论

本教程概述了如何使用 Gemini 2.0 构建无服务器实时流应用程序。通过使用 Next.js 框架,该应用程序实现了更简单、更有效的架构,适用于演示和后续升级。

该应用程序的所有源代码都可以在我的 GitHub 仓库 中找到。欢迎下载、尝试,并在评论中分享您的想法。

感谢您的阅读。

Related Posts

结合chatgpt-o3-mini与perplexity Deep Research的3步提示:提升论文写作质量的终极指南

结合chatgpt-o3-mini与perplexity Deep Research的3步提示:提升论文写作质量的终极指南

AI 研究报告和论文写作 合并两个系统指令以获得两个模型的最佳效果 Perplexity AI 的 Deep Research 工具提供专家级的研究报告,而 OpenAI 的 ChatGPT-o3-mini-high 擅长推理。我发现你可以将它们结合起来生成令人难以置信的论文,这些论文比任何一个模型单独撰写的都要好。你只需要将这个一次性提示复制到 **

阅读更多
让 Excel 过时的 10 种 Ai 工具:实现数据分析自动化,节省手工作业时间

让 Excel 过时的 10 种 Ai 工具:实现数据分析自动化,节省手工作业时间

Non members click here作为一名软件开发人员,多年来的一个发现总是让我感到惊讶,那就是人们还在 Excel

阅读更多
使用 ChatGPT 搜索网络功能的 10 种创意方法

使用 ChatGPT 搜索网络功能的 10 种创意方法

例如,提示和输出 你知道可以使用 ChatGPT 的“搜索网络”功能来完成许多任务,而不仅仅是基本的网络搜索吗? 对于那些不知道的人,ChatGPT 新的“搜索网络”功能提供实时信息。 截至撰写此帖时,该功能仅对使用 ChatGPT 4o 和 4o-mini 的付费会员开放。 ![](https://images.weserv.nl/?url=https://cdn-im

阅读更多
掌握Ai代理:解密Google革命性白皮书的10个关键问题解答

掌握Ai代理:解密Google革命性白皮书的10个关键问题解答

10 个常见问题解答 本文是我推出的一个名为“10 个常见问题解答”的新系列的一部分。在本系列中,我旨在通过回答关于该主题的十个最常见问题来分解复杂的概念。我的目标是使用简单的语言和相关的类比,使这些想法易于理解。 图片来自 [Solen Feyissa](https://unsplash.com/@solenfeyissa?utm_source=medium&utm_medi

阅读更多
在人工智能和技术领域保持领先地位的 10 项必学技能 📚

在人工智能和技术领域保持领先地位的 10 项必学技能 📚

在人工智能和科技这样一个动态的行业中,保持领先意味着不断提升你的技能。无论你是希望深入了解人工智能模型性能、掌握数据分析,还是希望通过人工智能转变传统领域如法律,这些课程都是你成功的捷径。以下是一个精心策划的高价值课程列表,可以助力你的职业发展,并让你始终处于创新的前沿。 1. 生成性人工智能简介课程: [生成性人工智能简介](https://genai.works

阅读更多
揭开真相!深度探悉DeepSeek AI的十大误区,您被误导了吗?

揭开真相!深度探悉DeepSeek AI的十大误区,您被误导了吗?

在AI军备竞赛中分辨事实与虚构 DeepSeek AI真的是它所宣传的游戏规则改变者,还是仅仅聪明的营销和战略炒作?👀 虽然一些人将其视为AI效率的革命性飞跃,但另一些人则认为它的成功建立在借用(甚至窃取的)创新和可疑的做法之上。传言称,DeepSeek的首席执行官在疫情期间像囤积卫生纸一样囤积Nvidia芯片——这只是冰山一角。 从其声称的550万美元培训预算到使用Open

阅读更多
Type something to search...