返回首页

Roomify:React Puter 上的 AI 室内渲染

Roomify — 使用 React 和 Puter 从 2D 平面图生成 3D 室内渲染的 Web 应用。基于无服务器 workers 的架构无需后端。提供 workers 代码、前端钩子和问题解决方案。

在 React+Puter 上创建像 Roomify 一样的 AI 可视化器
Advertisement 728x90

Roomify:使用React与无服务器Puter构建AI室内可视化工具

Roomify能在几秒内将2D平面图转换为逼真的3D渲染图。该应用前端采用React 19与TypeScript,后端逻辑、存储和AI生成则依托Puter平台。无需自定义后端,前端通过puter.js SDK直接与Puter API交互。

该架构摒弃了传统服务器:文件上传、项目创建和AI调用均在云端工作者中完成。这简化了中级和高级开发者的部署与扩展流程。

技术栈及其作用

  • React 19 + TypeScript:通过Vite实现热模块替换的强类型前端。
  • React Router 7:管理首页和可视化页面的路由。
  • Tailwind CSS:基于实用类的样式,无需自定义CSS。
  • Lucide React:用户界面图标库。
  • Puter.js:从浏览器访问文件存储、键值存储、工作者和AI模型。

Puter提供无服务器工作者、键值存储和持久化文件存储。工作者通过puter.action调用,AI则通过puter.ai.generate调用。

Google AdInline article slot

架构:从上传到渲染

处理流程:

  • 将平面图上传至puter.file.write
  • 获取文件的公开URL。
  • 调用project.create工作者,将元数据写入键值存储。
  • 通过ai.render3d工作者生成渲染:加载图像、构建提示词、调用Claude/Gemini、保存结果。
  • 更新键值存储中的渲染URL并返回前端。

前端使用react-compare-slider对比显示原始平面图和渲染图。

工作者函数:代码与逻辑

JavaScript工作者函数通过Puter CLI上传。

Google AdInline article slot

创建项目:

// lib/puter.action.ts
export async function createProject({ item, visibility }) {
  const result = await puter.action('project.create', {
    item,
    visibility,
  });
  return result;
}

export async function getProjects() {
  return await puter.action('project.list');
}

export async function getProjectById({ id }) {
  return await puter.action('project.get', { id });
}

生成渲染:

// worker: ai.render3d
export default async ({ sourceImage, style = 'photorealistic' }) => {
  const imageUrl = typeof sourceImage === 'string' ? sourceImage : await puter.file.url(sourceImage);
  
  const prompt = `
    将此平面图转换为${style}风格的3D室内渲染图。
    图像显示房间布局,包括墙壁、窗户和门。
    从最佳展示空间的角度生成逼真视图。
    添加合适的家具、纹理、照明和阴影。
    使其看起来像专业的建筑可视化效果。
  `;
  
  const result = await puter.ai.generate({
    model: 'claude-3-sonnet',
    prompt,
    images: [imageUrl],
    responseFormat: 'image'
  });
  
  const renderedPath = `/projects/${projectId}/rendered.png`;
  await puter.file.write(renderedPath, result.image);
  
  const key = `project:${projectId}`;
  const project = JSON.parse(await puter.kv.get(key));
  project.renderedImage = puter.file.url(renderedPath);
  await puter.kv.set(key, JSON.stringify(project));
  
  return {
    renderedImage: project.renderedImage,
    renderedPath
  };
};

键值存储保存元数据:项目名称、所有者、隐私设置和文件链接。

Google AdInline article slot

前端:组件与钩子

首页(Home)显示项目列表。Upload组件将文件转换为base64:

// components/Upload.tsx
const handleFileChange = async (e) => {
  const file = e.target.files[0];
  if (!file) return;
  const base64 = await toBase64(file);
  onComplete(base64);
};

可视化页面(VisualizerId)使用useEffect实现自动生成:

useEffect(() => {
  if (isProjectLoading || hasInitialGenerated.current || !project?.sourceImage) return;
  if (project.renderedImage) {
    setCurrentImage(project.renderedImage);
    hasInitialGenerated.current = true;
    return;
  }
  hasInitialGenerated.current = true;
  void runGeneration(project);
}, [project, isProjectLoading]);

useRef防止重复调用。状态本地管理,无需Redux。

解决常见问题

  • 跨域问题:开发环境中使用Vite代理。
  • Base64大小:单独保存文件,在键值存储中存储链接。
  • 重复生成useRef + 检查机制。
  • 异步处理:加载状态、骨架屏。
  • 移动端UI:Tailwind响应式设计、滑块触摸支持。

验证:文件最大10 MB,支持JPG/PNG格式。生成时间10-15秒,提供加载指示器。

关键要点

  • Puter替代后端:工作者、键值存储、文件和AI集成于一个SDK。
  • React钩子管理状态,无需外部库。
  • 提示词决定质量:详细描述墙壁、家具和照明。
  • 架构支持生产环境扩展,无需DevOps。
  • 代码开源,适合分叉和实验。

— Editorial Team

Advertisement 728x90

继续阅读