发布于 2026-01-06 0 阅读
0

📻 我用 Gemini + Lyria 打造了一个无限循环的 90 年代复古音响(它还有个 AI DJ!)

📻 我用 Gemini + Lyria 打造了一个无限循环的 90 年代复古音响(它还有个 AI DJ!)

我最近做了一个实验,说实话,我简直爱不释手。它是一个基于网络的虚拟音响。你调频,电台切换,音乐实时淡入淡出。

但最关键的是:这位DJ是人工智能。

每次你选定一个电台,一个动态生成的语音(由Gemini 文本转语音技术提供)就会响起,介绍歌曲和类型,而且完全符合上下文语境。这感觉就像机器里的一个幽灵,它是由 Google Gen AI SDK、Lit 和 Lyria 实时模型构建的。

以下是我搭建它的方法。

技术栈

  • 氛围编码平台: 谷歌人工智能工作室
  • 框架: Lit(Web Components)+ Vite
  • 音乐世代:谷歌的lyria-realtime-exp模型
  • DJ语音和脚本: Gemini 2.5 Flash 和 Gemini TTS(Fenrir语音)
  • 视觉效果:收音机使用 CSS,背景使用 Gemini 2.5 Flash Image。

1. 无限音乐流🎵

该应用程序的核心是……LiveMusicHelper它与模型连接lyria-realtime-exp。与生成静态 MP3 文件不同,它建立了一个会话,我们可以通过发送“加权提示”来实时控制音乐。

当你在用户界面上转动调谐旋钮时,我们并不是在下载一首新歌;我们是在告诉人工智能转移注意力。

// from utils/LiveMusicHelper.ts

public readonly setWeightedPrompts = throttle(async (prompts: Map<string, Prompt>) => {
  // Convert our UI map to an array for the API
  const weightedPrompts = this.activePrompts.map((p) => {
    return { text: p.text, weight: p.weight };
  });

  try {
    // This is where the magic happens. 
    // We tell the model: "be 100% Bossa Nova" or "mix 50% Dubstep and 50% Jazz"
    await this.session.setWeightedPrompts({
      weightedPrompts,
    });
  } catch (e: any) {
    console.error(e);
  }
}, 200);
Enter fullscreen mode Exit fullscreen mode

可视化旋钮组件将旋转角度映射到提示数组中的索引。如果您位于索引 0,则“Bossa Nova”的权重为1.0

2. AI DJ(“秘诀”)🎙️

这是我最喜欢的部分。没有DJ告诉你正在播放什么节目,收音机就不能称之为收音机。我RadioAnnouncer为此创建了一个类。

它的运作分为两步:

  1. 生成脚本:我们要求 Gemini 写一句介绍语。
  2. 生成音频:我们将该文本传递给 TTS 模型。

第一步:性格

我们要求 Gemini 2.5 Flash 赋予一个角色。请注意具体限制:简短有力,不含引号。

// from utils/RadioAnnouncer.ts

const scriptResponse = await this.ai.models.generateContent({
  model: 'gemini-2.5-flash',
  contents: `You are a charismatic radio DJ. Write a single, short, punchy sentence to introduce the current song.
  The station frequency is ${freq} FM.
  The music genre is ${station}.
  Do not use quotes. Just the spoken text.
  Example: "You're locked in to 104.5, keeping it smooth with Bossa Nova."`,
});
Enter fullscreen mode Exit fullscreen mode

第二步:声音

我们使用Fenrir预置配置中的语音。

const ttsResponse = await this.ai.models.generateContent({
  model: 'gemini-2.5-flash-preview-tts',
  contents: {
    parts: [{ text: script }]
  },
  config: {
    responseModalities: [Modality.AUDIO],
    speechConfig: {
      voiceConfig: {
        prebuiltVoiceConfig: { voiceName: 'Fenrir' }
      }
    }
  }
});
Enter fullscreen mode Exit fullscreen mode

逻辑:去抖动

因为用户可能快速滚动浏览 5 个电台直接找到“Dubstep”,所以我们不希望 DJ 逐个播报。我使用了防抖功能,这样只有在用户停止转动旋钮 800 毫秒后,才会触发信号生成。

3. 美学 🎨

用户界面采用 Lit 构建。音箱本身则结合了 CSS 样式和 SVG 技术来呈现扬声器和旋钮。

扬声器脉冲:
我使用 Web Audio API 创建了一个。我们获取当前频率数据并将其映射到扬声器锥体上的AudioAnalyserCSS 。transform: scale()

/* from components/PromptDjMidi.ts */
.speaker-cone {
  /* ... textures and gradients ... */
  transition: transform 0.05s cubic-bezier(0.1, 0.7, 1.0, 0.1);
}
Enter fullscreen mode Exit fullscreen mode
// In the render loop
const pulseScale = 1 + (this.audioLevel * 0.15); 
const speakerStyle = styleMap({
    transform: `scale(${pulseScale})`
});
Enter fullscreen mode Exit fullscreen mode

背景:
为了更好地营造氛围,我在页面加载时生成了一张背景图片。

// The prompt used for the background
text: 'A 90s-style girl\'s bedroom, dreamy, nostalgic, vaporwave aesthetic, anime posters on the wall, lava lamp, beaded curtains, photorealistic.'
Enter fullscreen mode Exit fullscreen mode

4. 应对“舆论风暴”😵‍💫

这个项目最难的部分之一是调谐旋钮的数学计算。我们需要将鼠标/触摸移动转换为旋转,然后将旋转锁定到特定的“档位”。

我实现了一个循环捕获逻辑:

  1. 计算旋钮中心与鼠标光标之间的角度。
  2. delta从点击开始计算(变化)。
  3. 处理 0/360 度环绕逻辑,以便您可以无限旋转它。
// from components/PromptDjMidi.ts
private handlePointerMove(e: PointerEvent) {
  // ... math to get angle ...

  // Handle crossing the 0/360 boundary smoothly
  if (delta > 180) delta -= 360;
  if (delta < -180) delta += 360;

  this.rotation = (this.startRotation + delta + 360) % 360;

  // Map rotation to station index
  const index = Math.floor(((this.rotation + segmentSize/2) % 360) / segmentSize);
  this.setStation(index);
}
Enter fullscreen mode Exit fullscreen mode

太长不看

这个项目的开发过程非常愉快,因为它结合了传统界面的触感和尖端的生成式人工智能。

“幽灵DJ”效果确实增添了一层纯粹的生成式音乐应用通常缺乏的沉浸感。它赋予了人工智能声音——字面意义上的声音——让无限循环的电台音乐听起来鲜活起来。

您可以在 AI Studio 中查看完整代码: https://aistudio.google.com/apps/drive/1L23eufECJSn0KPta3eAVo-PGdM4iXm-1

如果你尝试创建自己的电台,请告诉我!我现在正在听 94.0 “Shoegaze” 频道。📻

文章来源:https://dev.to/googleai/i-built-an-infinite-90s-boombox-with-gemini-lyria-and-it-has-an-ai-dj-3jh8