홈으로 돌아가기

Roomify: React Puter에서 AI 인테리어 렌더링

Roomify — React와 Puter를 사용해 2D 평면도에서 3D 인테리어 렌더를 생성하는 웹 애플리케이션. 서버리스 워커 아키텍처로 백엔드 제거. 제공된 워커 코드, 프론트엔드 훅 및 문제 해결.

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를 통한 HMR이 지원되는 타입 안전 프론트엔드.
  • React Router 7: 홈페이지와 비주얼라이저를 위한 라우팅.
  • Tailwind CSS: 커스텀 CSS 없이 유틸리티 우선 스타일링.
  • Lucide React: UI용 아이콘.
  • Puter.js: 브라우저에서 파일 저장소, KV, 워커, AI 모델에 접근.

Puter는 서버리스 워커, KV 저장소, 영구 파일 저장소를 제공합니다. 워커는 puter.action으로 호출하고, AI는 puter.ai.generate로 호출합니다.

Google AdInline article slot

아키텍처: 업로드부터 렌더링까지

처리 워크플로우:

  • 평면도를 puter.file.write에 업로드.
  • 파일의 공개 URL 획득.
  • project.create 워커 호출하여 메타데이터를 KV에 기록.
  • ai.render3d 워커를 통한 생성: 이미지 로드, 프롬프트 작성, Claude/Gemini 호출, 결과 저장.
  • 렌더링 URL로 KV 업데이트 후 프론트엔드 반환.

프론트엔드는 원본 평면도와 렌더링을 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
  };
};

KV는 메타데이터를 저장합니다: 프로젝트 이름, 소유자, 공개 설정, 파일 링크.

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 없이 로컬로 관리됩니다.

일반적인 문제 해결

  • CORS: 개발 환경에서 Vite 프록시 사용.
  • Base64 크기: 파일을 별도로 저장하고 KV에 링크 저장.
  • 이중 생성: useRef + 확인 절차.
  • 비동기성: 로딩 상태, 스켈레톤 UI.
  • 모바일 UI: Tailwind 반응형 디자인, 슬라이더 터치 지원.

검증: 최대 10 MB 파일, JPG/PNG 형식. 10-15초 생성 시간에 대한 로더.

핵심 요약

  • Puter가 백엔드를 대체합니다: 워커, KV, 파일, AI를 하나의 SDK로.
  • React 훅으로 외부 라이브러리 없이 상태 관리.
  • 프롬프트가 품질을 정의합니다: 벽, 가구, 조명을 세부적으로 기술.
  • 이 아키텍처는 DevOps 없이 프로덕션 규모로 확장 가능.
  • 코드는 오픈소스로, 포크와 실험에 적합.

— Editorial Team

Advertisement 728x90

다음 읽기