Roomify: Wdrożenie AI-wizualizatora wnętrz z React i serverless Puter
Roomify przekształca dwuwymiarowy plan pomieszczenia w fotorealistyczny render 3D w ciągu sekund. Aplikacja wykorzystuje React 19 z TypeScript na frontendzie oraz platformę Puter do logiki serverless, przechowywania danych i generowania AI. Bez własnego backendu frontend komunikuje się bezpośrednio z API Puter przez SDK puter.js.
Architektura eliminuje tradycyjny serwer: przesyłanie plików, tworzenie projektów i wywoływanie AI odbywa się w workers. Upraszcza to wdrożenie i skalowanie dla programistów średniego i zaawansowanego poziomu.
Stos technologiczny i jego rola
- React 19 + TypeScript: typowany frontend z HMR przez Vite.
- React Router 7: routing dla strony głównej i wizualizatora.
- Tailwind CSS: style użytkowe bez własnego CSS.
- Lucide React: ikony do interfejsu użytkownika.
- Puter.js: dostęp do przechowywania plików, KV, workers i modeli AI z poziomu przeglądarki.
Puter dostarcza serverless workers, przechowywanie KV i trwałe przechowywanie plików. Workers są wywoływane przez puter.action, AI — przez puter.ai.generate.
Architektura: od przesyłania do renderowania
Proces przetwarzania:
- Przesłanie planu przez
puter.file.write. - Uzyskanie publicznego URL pliku.
- Wywołanie worker
project.createdo zapisu metadanych w KV. - Generowanie przez worker
ai.render3d: załadowanie obrazu, sformułowanie promptu, wywołanie Claude/Gemini, zapisanie wyniku. - Aktualizacja KV z URL renderu i zwrot na frontend.
Frontend wyświetla oryginalny plan i render z użyciem react-compare-slider do porównania.
Funkcje workers: kod i logika
Funkcje workers w JavaScript są ładowane przez Puter CLI.
Tworzenie projektu:
// 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 });
}
Generowanie renderu:
// worker: ai.render3d
export default async ({ sourceImage, style = 'photorealistic' }) => {
const imageUrl = typeof sourceImage === 'string' ? sourceImage : await puter.file.url(sourceImage);
const prompt = `
Przekształć ten plan pomieszczenia w ${style} render 3D wnętrza.
Obraz przedstawia układ pomieszczenia ze ścianami, oknami i drzwiami.
Wygeneruj realistyczny widok z perspektywy, która najlepiej prezentuje przestrzeń.
Dodaj odpowiednie meble, tekstury, oświetlenie i cienie.
Spraw, aby wyglądało jak profesjonalna wizualizacja architektoniczna.
`;
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 przechowuje metadane: nazwa projektu, właściciel, prywatność, linki do plików.
Frontend: komponenty i hooki
Strona główna (Home) pokazuje listę projektów. Komponent Upload konwertuje plik na base64:
// components/Upload.tsx
const handleFileChange = async (e) => {
const file = e.target.files[0];
if (!file) return;
const base64 = await toBase64(file);
onComplete(base64);
};
Wizualizator (VisualizerId) używa useEffect do autogeneracji:
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 zapobiega powtórnym wywołaniom. Stan jest lokalny, bez Redux.
Rozwiązanie typowych problemów
- CORS: proxy Vite w trybie deweloperskim.
- Rozmiar base64: zapis pliku osobno, link w KV.
- Podwójne generowanie:
useRef+ sprawdzenia. - Asynchroniczność: stany ładowania, skeleton loadery.
- UI mobilny: responsywność Tailwind, obsługa dotyku dla suwaka.
Walidacja: pliki do 10 MB, JPG/PNG. Loadery dla 10-15 sekund generowania.
Co jest ważne
- Puter zastępuje backend: workers, KV, pliki, AI w jednym SDK.
- Hooki React zarządzają stanem bez zewnętrznych bibliotek.
- Prompt decyduje o jakości: detale ścian, mebli, oświetlenia.
- Architektura skalowalna dla produkcji bez DevOps.
- Kod otwarty, nadaje się do forków i eksperymentów.
— Editorial Team
Brak komentarzy.