news 2026/9/10 15:18:54

HeyGen + Remotion 集成指南:在 OpenMontage 中生成虚拟人视频并完成帧级精确合成

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HeyGen + Remotion 集成指南:在 OpenMontage 中生成虚拟人视频并完成帧级精确合成

HeyGen + Remotion 集成指南:在 OpenMontage 中生成虚拟人视频并完成帧级精确合成

【免费下载链接】OpenMontageWorld's first open-source, agentic video production system. 12 production pipelines, 100+ tools, 700+ agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage

导读

本文以 OpenMontage 仓库内 HeyGen 技能参考文档 remotion-integration.md 为核心,系统讲解如何把 HeyGen 云端 AI 虚拟人(Avatar)视频接入 Remotion 代码化视频合成流水线:从输出格式选型(MP4 带背景 / WebM 透明通道)、并行开发工作流、画幅对齐,到 Remotion 中基于OffthreadVideo的帧级精确渲染、Loom 风格圆形头像遮罩、分层合成与动态时长计算。读完本文,你将掌握一条「HeyGen 生成 → 轮询取 URL → Remotion 合成 → 命令行渲染」的完整可落地链路,并能结合仓库中的TalkingHead合成组件与 HeyGen 工具封装将其嵌入自己的生产管线。

Overview:一条典型的合成工作流

HeyGen 负责生成虚拟人口播视频,Remotion 负责把它与其他素材(背景、Logo、图表、动画、字幕)在代码层面合成最终成片。典型流程如下:

  1. 用 HeyGen 生成虚拟人视频(MP4 或 WebM);
  2. 等待生成完成,获取视频 URL;
  3. 在 Remotion 中直接使用 URL,或先下载到本地再引用;
  4. 与背景、叠加层、动画等其他元素合成。

仓库中 SKILL.md 对 HeyGen 技能的整体定位是:AI avatar video creation API for generating talking-head videos, explainers, and presentations,并在 Quick Reference 中明确将「与 Remotion 搭配使用」指向本文对应的 remotion-integration.md,说明该集成方案是仓库内 HeyGen 技能的官方推荐用法之一。

在 OpenMontage 的 remotion-composer 子项目中,已经存在与本文档同构的实战实现:TalkingHead.tsx 以videoSrc为输入,用OffthreadVideo承载口播视频层,用Sequence按秒级时间轴驱动图表、数据卡、标注框等 overlay 层,最上层叠加CaptionOverlay字幕——这正是本文所述分层合成思路在真实仓库中的落地形态,下文会多次回指该实现。

Quick Start:三步跑通最小闭环

// 1. Get avatar with default voice const avatar = await getAvatarDetails(avatarId); // 2. Generate video (MP4 with background - most common) const videoId = await generateVideo({ video_inputs: [{ character: { type: "avatar", avatar_id: avatar.id, avatar_style: "normal" }, voice: { type: "text", input_text: script, voice_id: avatar.default_voice_id }, background: { type: "color", value: "#1a1a2e" }, }], dimension: { width: 1920, height: 1080 }, }); // 3. Poll for completion (10-15+ min) // 4. Use in Remotion with motion graphics overlaid on top

关键点在于使用头像自带的default_voice_id:多数 HeyGen 头像自带预匹配的默认音色,语音与形象的自然度最好,也省去手动挑选音色的步骤(详见 avatars.md 与 voices.md)。

选择正确的输出格式

这是整个集成方案中第一个、也是最重要的决策点,因为它直接决定后续在 Remotion 中如何合成:

你的合成方案推荐格式原因
虚拟人作为主持人,上层叠加动效MP4 + 背景更简单,叠加层直接盖在视频上
Loom 风格(虚拟人叠加在录屏上)WebM +closeUp,在 Remotion 中做遮罩需要透明通道,用 CSS 圆形遮罩
虚拟人叠加在其他视频/内容之上WebM(透明)需要透过虚拟人看到背后内容
全屏虚拟人MP4 + 背景标准做法

绝大多数场景使用 MP4 带背景。只有当需要看到虚拟人背后的内容时才使用 WebM。

注意:WebM 只支持normalcloseUp两种风格。需要圆形构图时,请在 Remotion 中用 CSSborder-radius: 50%实现,而不是依赖 HeyGen 的circle风格。

这一点在 video-generation.md 的 WebM 一节中有同样结论:WebM 只用于「虚拟人叠加在录屏上」「虚拟人漂浮在视频背景上」「真正的 alpha 通道合成」三种场景。

推荐:并行开发工作流

HeyGen 视频生成耗时10-15 分钟以上,绝不应该干等。推荐的并行策略:

  1. 先启动 HeyGen 生成——把video_id存到文件里,立即退出;
  2. 并行构建 Remotion 合成——先用占位素材或头像的preview_video_url(一段短视频循环)顶着;
  3. 构建过程中周期性检查 HeyGen 状态,或者构建完成后再查;
  4. 就绪后把占位素材替换为真实视频 URL

根据脚本估算时长:语速约 150 词/分钟,因此wordCount / 150 * 60 * fps即可估算出大致帧数。

合成设计建议:把组件设计成「有无虚拟人视频都能工作」,这样动效可以独立于虚拟人进行测试。仓库中的 TalkingHead.tsx 正是这种设计——videoSrc只是众多 props 之一,overlay 与字幕层完全不依赖视频是否就位,可以在虚拟人视频渲染完成前独立预览全部动效。

画幅对齐:HeyGen 输出尺寸必须与 Remotion 合成尺寸一致

关键约束:HeyGen 的输出画幅必须与 Remotion 合成画幅完全一致,否则会出现黑边、裁切或缩放失真。

通用画幅预设常量

// Shared dimension constants for both HeyGen and Remotion const DIMENSIONS = { landscape_1080p: { width: 1920, height: 1080 }, landscape_720p: { width: 1280, height: 720 }, portrait_1080p: { width: 1080, height: 1920 }, portrait_720p: { width: 720, height: 1280 }, square_1080p: { width: 1080, height: 1080 }, square_720p: { width: 720, height: 720 }, } as const; type DimensionPreset = keyof typeof DIMENSIONS;

HeyGen 侧:按预设生成视频

// Generate HeyGen video with specific dimensions async function generateHeyGenVideo( script: string, avatarId: string, voiceId: string, preset: DimensionPreset ): Promise<string> { const dimension = DIMENSIONS[preset]; const response = await fetch("https://api.heygen.com/v2/video/generate", { method: "POST", headers: { "X-Api-Key": process.env.HEYGEN_API_KEY!, "Content-Type": "application/json", }, body: JSON.stringify({ video_inputs: [ { character: { type: "avatar", avatar_id: avatarId, avatar_style: "normal", }, voice: { type: "text", input_text: script, voice_id: voiceId, }, background: { type: "color", value: "#00FF00", // Green screen for compositing }, }, ], dimension, }), }); const { data } = await response.json(); return data.video_id; }

Remotion 侧:在 Root.tsx 中注册同尺寸合成

// remotion/src/Root.tsx import { Composition } from "remotion"; import { AvatarComposition } from "./AvatarComposition"; const DIMENSIONS = { landscape_1080p: { width: 1920, height: 1080 }, // ... same as above }; export const RemotionRoot: React.FC = () => { return ( <> <Composition id="AvatarVideo" component={AvatarComposition} durationInFrames={300} // Will be set dynamically fps={30} width={DIMENSIONS.landscape_1080p.width} height={DIMENSIONS.landscape_1080p.height} defaultProps={{ avatarVideoUrl: "", }} /> </> ); };

仓库中的 Root.tsx 注册了同构的TalkingHead合成,其默认画幅为 9:16(1080x1920),与TalkingHead.tsxPOSITION_STYLES按竖屏画幅设计的 overlay 定位(如lower_third底部留 320px 给字幕区)相互呼应——再次印证「先定画幅,再写合成」的工程顺序。

为 Remotion 生成虚拟人视频

标准做法:MP4 带背景

绝大多数 Remotion 合成采用 MP4 + 背景,叠加层与动效直接盖在视频上层:

async function generateAvatarForRemotion( script: string, avatarId: string, voiceId: string, options: { style?: "normal" | "closeUp" | "circle"; backgroundColor?: string; } = {} ): Promise<string> { const { style = "normal", backgroundColor = "#1a1a2e" } = options; const response = await fetch("https://api.heygen.com/v2/video/generate", { method: "POST", headers: { "X-Api-Key": process.env.HEYGEN_API_KEY!, "Content-Type": "application/json", }, body: JSON.stringify({ video_inputs: [{ character: { type: "avatar", avatar_id: avatarId, avatar_style: style, }, voice: { type: "text", input_text: script, voice_id: voiceId, }, background: { type: "color", value: backgroundColor, }, }], dimension: { width: 1920, height: 1080 }, }), }); const { data } = await response.json(); return data.video_id; }

透明背景:WebM 接口

仅当需要看到虚拟人背后的内容时使用(例如虚拟人叠加在录屏之上):

// Use /v1/video.webm endpoint for transparent background // Note: Different structure than /v2/video/generate const response = await fetch("https://api.heygen.com/v1/video.webm", { method: "POST", headers: { "X-Api-Key": process.env.HEYGEN_API_KEY!, "Content-Type": "application/json", }, body: JSON.stringify({ avatar_pose_id: avatarPoseId, // Required: avatar pose ID avatar_style: "normal", // Required: "normal" or "closeUp" only input_text: script, // Required (with voice_id) voice_id: voiceId, // Required (with input_text) dimension: { width: 1920, height: 1080 }, }), });

注意 WebM 端点(/v1/video.webm)的请求结构与/v2/video/generate不同:使用扁平字段avatar_pose_id/avatar_style/input_text/voice_id,且input_text+voice_idinput_audio二选一,不能同时提供。生成后与 MP4 使用相同的状态轮询接口,返回的video_url.webm文件(详见 video-generation.md 与 video-status.md)。

在 Remotion 中使用 HeyGen 视频

关键:渲染必须用OffthreadVideo而非Video

虚拟人视频一律使用OffthreadVideo。基础Video组件走浏览器视频解码器,无法做到逐帧精确,渲染时会产生抖动(jitter);OffthreadVideo通过 FFmpeg 逐帧抽取画面,保证平滑且帧精确。

OffthreadVideo属于remotion核心包,无需额外安装。

基础用法

// remotion/src/AvatarComposition.tsx import { OffthreadVideo, useVideoConfig } from "remotion"; interface AvatarCompositionProps { avatarVideoUrl: string; } export const AvatarComposition: React.FC<AvatarCompositionProps> = ({ avatarVideoUrl, }) => { return ( <div style={{ flex: 1, backgroundColor: "#1a1a2e" }}> <OffthreadVideo src={avatarVideoUrl} style={{ width: "100%", height: "100%", objectFit: "contain", }} /> </div> ); };

仓库实现与此一致:TalkingHead.tsx 中的口播视频层即用OffthreadVideo+objectFit: "cover"承载,且通过resolveAsset(videoSrc)统一解析本地静态资源与远程 URL。

WebM 透明通道合成(推荐)

使用/v1/video.webm生成的 WebM 自带 alpha 通道,无需任何色键处理:

import { OffthreadVideo, AbsoluteFill, Sequence } from "remotion"; export const AvatarWithMotionGraphics: React.FC<{ avatarWebmUrl: string }> = ({ avatarWebmUrl }) => { return ( <AbsoluteFill> {/* Layer 1: Your background/content */} <AbsoluteFill style={{ backgroundColor: "#1a1a2e" }}> <YourMotionGraphics /> </AbsoluteFill> {/* Layer 2: Avatar with transparent background - use OffthreadVideo for frame-accurate rendering */} <OffthreadVideo src={avatarWebmUrl} transparent style={{ position: "absolute", bottom: 0, right: 0, width: "50%", height: "auto", }} /> {/* Layer 3: Overlays on top of avatar */} <Sequence from={30}> <AnimatedTitle text="Welcome!" /> </Sequence> </AbsoluteFill> ); };

要点:WebM 加transparent属性;用Sequence控制叠加层出现时机(此处from={30}表示第 30 帧后出现,即第 1 秒)。

Loom 风格:圆形头像叠加录屏

使用closeUp风格 + WebM,再在 Remotion 中做圆形遮罩:

import { OffthreadVideo, AbsoluteFill } from "remotion"; export const LoomStyleComposition: React.FC<{ screenRecordingUrl: string; avatarWebmUrl: string; // Generated with avatar_style: "closeUp" via /v1/video.webm }> = ({ screenRecordingUrl, avatarWebmUrl }) => { return ( <AbsoluteFill> {/* Screen recording fills the frame */} <OffthreadVideo src={screenRecordingUrl} style={{ width: "100%", height: "100%" }} /> {/* Avatar with circular mask - transparent bg shows screen behind */} <OffthreadVideo src={avatarWebmUrl} transparent style={{ position: "absolute", bottom: 40, left: 40, width: 180, height: 180, borderRadius: "50%", // Circular mask applied in CSS overflow: "hidden", objectFit: "cover", }} /> </AbsoluteFill> ); };

注意:WebM 不支持circle风格——请用normalcloseUp生成,再用 CSS 圆形遮罩(border-radius: 50%+overflow: hidden+objectFit: cover)实现圆形头像效果。

遗留方案:绿幕 + 色键

如果手里只有绿幕 MP4(不推荐,应改用 WebM):

// Note: True chroma key requires WebGL or post-processing // WebM transparent background is much simpler <OffthreadVideo src={avatarVideoUrl} style={{ mixBlendMode: "multiply", // Basic compositing only }} />

真实色键需要 WebGL 或后期处理,mixBlendMode只能做基础合成,因此 WebM 透明通道是远为简单的方案。

分层合成示例

import { OffthreadVideo, Sequence, useVideoConfig, Img } from "remotion"; interface LayeredAvatarProps { avatarVideoUrl: string; backgroundUrl: string; logoUrl: string; title: string; } export const LayeredAvatarComposition: React.FC<LayeredAvatarProps> = ({ avatarVideoUrl, backgroundUrl, logoUrl, title, }) => { const { fps } = useVideoConfig(); return ( <div style={{ position: "relative", width: "100%", height: "100%" }}> {/* Layer 1: Background */} <Img src={backgroundUrl} style={{ position: "absolute", width: "100%", height: "100%", objectFit: "cover", }} /> {/* Layer 2: Avatar video - use OffthreadVideo to prevent jitter */} <OffthreadVideo src={avatarVideoUrl} style={{ position: "absolute", bottom: 0, right: 0, width: "40%", height: "auto", }} /> {/* Layer 3: Title (appears after 1 second) */} <Sequence from={fps}> <div style={{ position: "absolute", top: 50, left: 50, color: "white", fontSize: 48, fontWeight: "bold", }} > {title} </div> </Sequence> {/* Layer 4: Logo */} <Img src={logoUrl} style={{ position: "absolute", top: 20, right: 20, width: 100, height: "auto", }} /> </div> ); };

分层顺序(从底到顶):背景图 → 虚拟人视频 → 标题(延迟 1 秒出现)→ Logo。仓库 TalkingHead.tsx 采用了相同的分层哲学并加以泛化:视频层 → overlay 层(PositionedOverlay封装了淡入淡出与位置预设)→ 最顶层字幕,overlay 类型涵盖文本卡、数据卡、标注框、对比卡与柱状/折线/饼图等图表组件(见 components)。

完整工作流

生成并合成:从脚本到成片

import { bundle } from "@remotion/bundler"; import { renderMedia, selectComposition } from "@remotion/renderer"; async function generateAvatarVideoForRemotion( script: string, outputPath: string ) { // 1. Generate HeyGen video console.log("Generating HeyGen avatar video..."); const videoId = await generateHeyGenVideo( script, "josh_lite3_20230714", "1bd001e7e50f421d891986aad5158bc8", "landscape_1080p" ); // 2. Wait for completion console.log("Waiting for HeyGen video..."); const avatarVideoUrl = await waitForVideo(videoId); console.log(`HeyGen video ready: ${avatarVideoUrl}`); // 3. Get video duration for Remotion const avatarDuration = await getVideoDuration(avatarVideoUrl); const durationInFrames = Math.ceil(avatarDuration * 30); // 30 fps // 4. Bundle Remotion project console.log("Bundling Remotion project..."); const bundleLocation = await bundle({ entryPoint: "./remotion/src/index.ts", }); // 5. Select composition const composition = await selectComposition({ serveUrl: bundleLocation, id: "AvatarVideo", inputProps: { avatarVideoUrl, }, }); // 6. Render final video console.log("Rendering final composition..."); await renderMedia({ composition: { ...composition, durationInFrames, }, serveUrl: bundleLocation, codec: "h264", outputLocation: outputPath, inputProps: { avatarVideoUrl, }, }); console.log(`Final video rendered: ${outputPath}`); return outputPath; }

这条链路与 OpenMontage 的工程实现一一对应:仓库中 heygen_video.py 是 HeyGen 视频生成的工具封装(要求环境变量HEYGEN_API_KEY,走POST /v1/workflows/executions的 GenerateVideoNode 工作流),其底层轮询逻辑 poll_heygen 采用 5 秒起始间隔、1.2 倍指数退避、最长 600 秒超时的策略,与本文推荐「10-15 分钟生成、周期轮询」完全一致;Remotion 渲染器 则对应bundle/selectComposition/renderMedia的可编程渲染路径。

动态时长:用 calculateMetadata 自动对齐视频长度

// remotion/src/AvatarComposition.tsx import { CalculateMetadataFunction } from "remotion"; export const calculateAvatarMetadata: CalculateMetadataFunction< AvatarCompositionProps > = async ({ props }) => { // Fetch video duration from HeyGen video const duration = await getVideoDurationInSeconds(props.avatarVideoUrl); return { durationInFrames: Math.ceil(duration * 30), fps: 30, width: 1920, height: 1080, }; }; // In Root.tsx <Composition id="AvatarVideo" component={AvatarComposition} calculateMetadata={calculateAvatarMetadata} defaultProps={{ avatarVideoUrl: "", }} />

calculateMetadata让合成时长、帧率、画幅在渲染前按真实视频动态确定,避免写死durationInFrames={300}造成的截断或空帧。

最佳实践

1. 用绿幕换取合成灵活性

需要合成时,让 HeyGen 以纯绿背景生成:

background: { type: "color", value: "#00FF00", // Pure green for chroma key }

2. 匹配帧率

HeyGen 默认输出 25 fps,设置 Remotion 帧率时要考虑这一点:

// Option 1: Match HeyGen's 25 fps fps: 25 // Option 2: Use 30 fps with playback rate adjustment <OffthreadVideo src={avatarVideoUrl} playbackRate={25/30} // Slow down slightly to match />

3. URL 直用 vs 本地下载

直接使用 URL,当:

  • 在 Remotion Studio 中预览(npm run dev);
  • URL 在渲染完成前不会过期;
  • 开发期追求快速迭代。
// Direct URL usage - simpler, faster for dev <OffthreadVideo src={avatarVideoUrl} />

先下载到本地,当:

  • URL 会过期(HeyGen URL 约 24 小时后失效);
  • 渲染发生在之后或需要重复渲染;
  • 网络可靠性堪忧;
  • 需要离线渲染。
// Download with retry for reliability async function downloadVideoWithRetry( url: string, outputPath: string, maxRetries = 5 ): Promise<string> { for (let attempt = 0; attempt < maxRetries; attempt++) { try { const response = await fetch(url); if (!response.ok) throw new Error(`HTTP ${response.status}`); const buffer = await response.arrayBuffer(); await fs.promises.writeFile(outputPath, Buffer.from(buffer)); return outputPath; } catch (error) { const delay = 2000 * Math.pow(2, attempt); console.log(`Retry ${attempt + 1}/${maxRetries} in ${delay}ms...`); await new Promise((r) => setTimeout(r, delay)); } } throw new Error("Download failed after retries"); } // Use local file in Remotion const localPath = await downloadVideoWithRetry(avatarVideoUrl, "./public/avatar.mp4");

混合方案(生产环境推荐)

// Save both URL and local path in metadata const metadata = { videoUrl: result.video_url, // For quick preview localPath: "./public/avatar.mp4", // For reliable rendering expiresAt: Date.now() + 24 * 60 * 60 * 1000, // URL expiration }; // In Remotion component, prefer local if available const videoSrc = fs.existsSync(localPath) ? staticFile("avatar.mp4") : avatarVideoUrl;

4. 控制虚拟人位置

常见构图位置预设:

const AVATAR_POSITIONS = { fullscreen: { width: "100%", height: "100%", position: "center" }, bottomRight: { width: "40%", bottom: 0, right: 0 }, bottomLeft: { width: "40%", bottom: 0, left: 0 }, pictureInPicture: { width: "25%", bottom: 20, right: 20 }, leftThird: { width: "33%", left: 0, height: "100%" }, };

仓库 TalkingHead.tsx 以同样的思路为 9:16 画幅定义了lower_third/upper_third/left_panel/right_panel/full_overlay五档 overlay 位置预设,可参考其坐标数值设计自己的竖屏布局。

输出格式速查

HeyGen 输出

  • 格式:MP4(H.264)
  • 音频:AAC
  • 分辨率:按请求指定(如 1920x1080)

Remotion 输出

  • 编码器:H.264(默认)、VP8、VP9、ProRes
  • 质量应与 HeyGen 输出匹配或更高
await renderMedia({ codec: "h264", crf: 18, // High quality // ... });

故障排查

视频在 Remotion 中无法播放

  1. 检查 URL 可访问性(CORS 问题);
  2. 确认视频格式兼容性;
  3. 先尝试下载到本地再引用。

画幅不匹配

确保 HeyGen 与 Remotion 使用完全一致的尺寸:

// Shared config const VIDEO_CONFIG = { width: 1920, height: 1080, fps: 30, }; // HeyGen dimension: { width: VIDEO_CONFIG.width, height: VIDEO_CONFIG.height } // Remotion <Composition width={VIDEO_CONFIG.width} height={VIDEO_CONFIG.height} />

渲染时视频抖动

如果渲染结果中虚拟人画面抖动或卡顿:

  1. OffthreadVideo替换Video——基础Video组件走浏览器视频解码器,无法逐帧精确;
  2. 更新导入(无需额外安装,OffthreadVideo就在核心remotion包里):
    // Before (causes jitter) import { Video } from "remotion"; // After (frame-accurate) import { OffthreadVideo } from "remotion";
  3. 使用带透明通道的 WebM 时,加transparent属性:
    <OffthreadVideo src={avatarWebmUrl} transparent />

音画不同步

若虚拟人音频漂移:

  • 核对源视频帧率;
  • 检查编码问题;
  • 考虑用一致的参数重新编码。

总结

HeyGen + Remotion 的组合,本质上是「云端虚拟人口播能力」与「代码化合成渲染能力」的分工:HeyGen 负责把脚本变成可信的虚拟人视频,Remotion 负责在帧级精确的合成器中把视频、图表、字幕、品牌元素编排成最终成片。掌握本文的四条主线——输出格式选型(MP4 vs WebM)、并行开发工作流、画幅/帧率对齐、OffthreadVideo帧精确渲染——即可把这条链路稳定嵌入 OpenMontage 式的自动化视频生产线。进一步可阅读 video-generation.md(多场景视频、WebM 字段详解)、video-status.md(轮询与下载重试)、webhooks.md(生产环境替代轮询的方案),并对照仓库实现 TalkingHead.tsx 与 heygen_video.py 深化理解。

【免费下载链接】OpenMontageWorld's first open-source, agentic video production system. 12 production pipelines, 100+ tools, 700+ agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 15:16:02

GitHub MCP Server 如何在 Cursor 中接入远程服务器并用 PAT 认证?

GitHub MCP Server 如何在 Cursor 中接入远程服务器并用 PAT 认证&#xff1f; 【免费下载链接】github-mcp-server GitHubs official MCP Server 项目地址: https://gitcode.com/GitHub_Trending/gi/github-mcp-server 如果你想在 Cursor 中调用 GitHub MCP Server 的工…

作者头像 李华
网站建设 2026/9/10 15:14:17

MNIST手写数字识别作业的可复现性与结果归因实践

简介&#xff1a;本资源是一份面向计算机、电子信息工程及数学等专业本科生的机器学习课程实践项目&#xff0c;聚焦手写数字识别任务&#xff0c;完整覆盖模型设计、训练、测试与可视化全流程&#xff0c;适用于期末大作业、课程设计及毕业设计参考。压缩包共14个文件&#xf…

作者头像 李华
网站建设 2026/9/10 15:12:38

Logseq Zotero 集成:把文献库接进笔记流的 4 个操作

Logseq Zotero 集成&#xff1a;把文献库接进笔记流的 4 个操作 【免费下载链接】logseq A privacy-first, open-source platform for knowledge management and collaboration. Download link: http://github.com/logseq/logseq/releases. roadmap: https://logseq.io/p/NX4mc…

作者头像 李华
网站建设 2026/9/10 15:12:22

React Native在OpenHarmony上的组件开发与优化实践

1. 项目概述作为一名长期从事跨平台开发的工程师&#xff0c;我最近深入研究了React Native在OpenHarmony上的应用开发。这个系列教程的第四部分将带大家认识OpenHarmony中的核心组件体系。不同于传统的React Native开发&#xff0c;在OpenHarmony平台上我们需要理解其特有的组…

作者头像 李华