### Install Project Dependencies Source: https://github.com/nutlope/roomgpt/blob/main/README.md Run this command in the root directory of the project to install all necessary npm dependencies. ```bash npm install ``` -------------------------------- ### Run RoomGPT Application Locally Source: https://github.com/nutlope/roomgpt/blob/main/README.md Execute this command to start the RoomGPT application. It will be accessible at http://localhost:3000. ```bash npm run dev ``` -------------------------------- ### Environment Configuration (.env file) Source: https://context7.com/nutlope/roomgpt/llms.txt Specifies required and optional environment variables for application functionality, including API keys for Replicate and Bytescale, and Redis configuration for rate limiting. ```bash # .env file configuration # Required - Replicate API key for ControlNet ML model REPLICATE_API_KEY=r8_xxxxxxxxxxxxxxxxxxxxxxxxxxxx # Required - Bytescale API key for image uploads NEXT_PUBLIC_UPLOAD_API_KEY=public_xxxxxxxxxxxx # Optional - Upstash Redis for rate limiting (5 requests/24 hours) UPSTASH_REDIS_REST_URL=https://xxxx.upstash.io UPSTASH_REDIS_REST_TOKEN=AxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxQ== ``` -------------------------------- ### Clone RoomGPT Repository Source: https://github.com/nutlope/roomgpt/blob/main/README.md Use this command to clone the RoomGPT repository to your local machine. ```bash git clone https://github.com/Nutlope/roomGPT ``` -------------------------------- ### Room Generation API Source: https://context7.com/nutlope/roomgpt/llms.txt The /generate endpoint processes room images using the ControlNet ML model. It accepts a room photo URL, theme, and room type, then polls Replicate's API until the generated image is ready. Optional rate limiting restricts users to 5 requests per 24 hours when Redis is configured. ```APIDOC ## POST /generate ### Description Generates a redesigned room image based on the provided room photo URL, theme, and room type. ### Method POST ### Endpoint /generate ### Parameters #### Request Body - **imageUrl** (string) - Required - The URL of the room photo to be transformed. - **theme** (string) - Required - The desired theme for the redesigned room. Possible values: "Modern", "Vintage", "Minimalist", "Professional", "Tropical". - **room** (string) - Required - The type of room to generate. Possible values: "Living Room", "Dining Room", "Bedroom", "Bathroom", "Office", "Gaming Room". ### Request Example ```json { "imageUrl": "https://bytescale.com/uploads/room-photo.jpg", "theme": "Modern", "room": "Living Room" } ``` ### Response #### Success Response (200) - **Array of strings** (string[]) - A list of URLs for the generated room images. #### Response Example ```json [ "https://replicate.com/generated-image-1.jpg", "https://replicate.com/generated-image-2.jpg" ] ``` ### Error Handling - **429 Too Many Requests**: Rate limit exceeded. Try again in 24 hours. ``` -------------------------------- ### Create a Reusable Dropdown Component Source: https://context7.com/nutlope/roomgpt/llms.txt A reusable dropdown component using Headless UI for selecting room themes and types. Supports accessible navigation, animations, and visual feedback. ```typescript import { Menu, Transition } from "@headlessui/react"; import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/20/solid"; import { roomType, themeType, themes, rooms } from "../utils/dropdownTypes"; interface DropDownProps { theme: themeType | roomType; setTheme: (theme: themeType | roomType) => void; themes: themeType[] | roomType[]; } function DropDown({ theme, setTheme, themes }: DropDownProps) { return ( {theme} {themes.map((themeItem) => ( {({ active }) => ( )} ))} ); } // Usage for theme selection setTheme(newTheme as themeType)} themes={themes} /> // Usage for room type selection setRoom(newRoom as roomType)} themes={rooms} /> ``` -------------------------------- ### Room Generation API Endpoint Source: https://context7.com/nutlope/roomgpt/llms.txt This Next.js API route processes room images using the ControlNet ML model. It accepts a room photo URL, theme, and room type, then polls Replicate's API for the generated image. Handles rate limiting if Redis is configured. ```typescript // POST /generate - Generate a redesigned room // Request body const requestBody = { imageUrl: "https://bytescale.com/uploads/room-photo.jpg", theme: "Modern", // "Modern" | "Vintage" | "Minimalist" | "Professional" | "Tropical" room: "Living Room" // "Living Room" | "Dining Room" | "Bedroom" | "Bathroom" | "Office" | "Gaming Room" }; // Frontend usage async function generatePhoto(fileUrl: string) { const res = await fetch("/generate", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ imageUrl: fileUrl, theme: "Modern", room: "Living Room" }), }); if (res.status === 429) { console.error("Rate limit exceeded - try again in 24 hours"); return; } const generatedImages = await res.json(); // Returns array of generated image URLs: ["url1", "url2"] const restoredImage = generatedImages[1]; } // cURL example // curl -X POST http://localhost:3000/generate \ // -H "Content-Type: application/json" \ // -d '{"imageUrl":"https://example.com/room.jpg","theme":"Modern","room":"Living Room"}' ``` -------------------------------- ### Bytescale Image Upload Widget Configuration Source: https://context7.com/nutlope/roomgpt/llms.txt Configures the Bytescale UploadDropzone component for drag-and-drop image uploads. It specifies API key, file limits, allowed MIME types, image editing options, and styling. The `onUpdate` callback processes uploaded files, generating a URL for the image. ```typescript import { UploadDropzone } from "@bytescale/upload-widget-react"; import { UrlBuilder } from "@bytescale/sdk"; import { UploadWidgetConfig } from "@bytescale/upload-widget"; // Configuration options const options: UploadWidgetConfig = { apiKey: process.env.NEXT_PUBLIC_UPLOAD_API_KEY || "free", maxFileCount: 1, mimeTypes: ["image/jpeg", "image/png", "image/jpg"], editor: { images: { crop: false } }, styles: { colors: { primary: "#2563EB", error: "#d23f4d", shade100: "#fff", }, }, }; // Usage in component function ImageUploader() { const [originalPhoto, setOriginalPhoto] = useState(null); const [photoName, setPhotoName] = useState(null); return ( { if (uploadedFiles.length !== 0) { const image = uploadedFiles[0]; const imageName = image.originalFile.originalFileName; const imageUrl = UrlBuilder.url({ accountId: image.accountId, filePath: image.filePath, options: { transformation: "preset", transformationPreset: "thumbnail" } }); setPhotoName(imageName); setOriginalPhoto(imageUrl); // Trigger room generation with the uploaded image URL generatePhoto(imageUrl); } }} width="670px" height="250px" /> ); } ``` -------------------------------- ### Download Photo Utility Function Source: https://context7.com/nutlope/roomgpt/llms.txt Downloads an image from a given URL to the user's device. It fetches the image as a blob and triggers a browser download. Requires a filename and the image URL. ```typescript // utils/downloadPhoto.ts function forceDownload(blobUrl: string, filename: string) { let a: any = document.createElement("a"); a.download = filename; a.href = blobUrl; document.body.appendChild(a); a.click(); a.remove(); } export default function downloadPhoto(url: string, filename: string) { fetch(url, { headers: new Headers({ Origin: location.origin, }), mode: "cors", }) .then((response) => response.blob()) .then((blob) => { let blobUrl = window.URL.createObjectURL(blob); forceDownload(blobUrl, filename); }) .catch((e) => console.error(e)); } ``` ```typescript // utils/appendNewToName.ts - Helper to create download filename export default function appendNewToName(name: string) { let insertPos = name.indexOf("."); let newName = name .substring(0, insertPos) .concat("-new", name.substring(insertPos)); return newName; // "bedroom.jpg" -> "bedroom-new.jpg" } ``` ```typescript // Usage in component import downloadPhoto from "../utils/downloadPhoto"; import appendNewToName from "../utils/appendNewToName"; ``` -------------------------------- ### Implement IP-based Rate Limiting with Redis Source: https://context7.com/nutlope/roomgpt/llms.txt Configures and applies IP-based rate limiting using Upstash Redis and the @upstash/ratelimit library. Gracefully disables when Redis credentials are not provided. ```typescript import { Ratelimit } from "@upstash/ratelimit"; import { Redis } from "@upstash/redis"; // Redis client setup (utils/redis.ts) const redis = !!process.env.UPSTASH_REDIS_REST_URL && !!process.env.UPSTASH_REDIS_REST_TOKEN ? new Redis({ url: process.env.UPSTASH_REDIS_REST_URL, token: process.env.UPSTASH_REDIS_REST_TOKEN, }) : undefined; // Rate limiter configuration - 5 requests per 24 hours (1440 minutes) const ratelimit = redis ? new Ratelimit({ redis: redis, limiter: Ratelimit.fixedWindow(5, "1440 m"), analytics: true, }) : undefined; // Usage in API route export async function POST(request: Request) { if (ratelimit) { const headersList = headers(); const ipIdentifier = headersList.get("x-real-ip"); const result = await ratelimit.limit(ipIdentifier ?? ""); if (!result.success) { return new Response( "Too many uploads in 1 day. Please try again in 24 hours.", { status: 429, headers: { "X-RateLimit-Limit": result.limit, "X-RateLimit-Remaining": result.remaining, } as any, } ); } } // Continue with image generation... } ``` -------------------------------- ### Bytescale Image Upload Widget Source: https://context7.com/nutlope/roomgpt/llms.txt The UploadDropzone component from Bytescale provides drag-and-drop image upload functionality. It handles file validation, uploads to Bytescale cloud storage, and returns a URL for the uploaded image. ```APIDOC ## Bytescale Image Upload Widget ### Description Provides drag-and-drop image upload functionality using the `@bytescale/upload-widget-react` component. It handles file uploads to Bytescale and returns a URL for the uploaded image. ### Component `UploadDropzone` from `@bytescale/upload-widget-react` ### Configuration Options - **apiKey** (string) - Optional - Your Bytescale API key. Defaults to "free". - **maxFileCount** (number) - Optional - Maximum number of files allowed for upload. Defaults to 1. - **mimeTypes** (string[]) - Optional - Allowed MIME types for uploaded files. Defaults to ["image/jpeg", "image/png", "image/jpg"]. - **editor** (object) - Optional - Image editor configuration. Example: `{ images: { crop: false } }`. - **styles** (object) - Optional - Custom styling for the upload widget. Example: `{ colors: { primary: "#2563EB", error: "#d23f4d", shade100: "#fff" } }`. ### Usage Example ```typescript import { UploadDropzone } from "@bytescale/upload-widget-react"; import { UrlBuilder } from "@bytescale/sdk"; import { UploadWidgetConfig } from "@bytescale/upload-widget"; const options: UploadWidgetConfig = { apiKey: process.env.NEXT_PUBLIC_UPLOAD_API_KEY || "free", maxFileCount: 1, mimeTypes: ["image/jpeg", "image/png", "image/jpg"], editor: { images: { crop: false } }, styles: { colors: { primary: "#2563EB", error: "#d23f4d", shade100: "#fff", }, }, }; function ImageUploader() { const [originalPhoto, setOriginalPhoto] = useState(null); const [photoName, setPhotoName] = useState(null); return ( { if (uploadedFiles.length !== 0) { const image = uploadedFiles[0]; const imageName = image.originalFile.originalFileName; const imageUrl = UrlBuilder.url({ accountId: image.accountId, filePath: image.filePath, options: { transformation: "preset", transformationPreset: "thumbnail" } }); setPhotoName(imageName); setOriginalPhoto(imageUrl); // Trigger room generation with the uploaded image URL // generatePhoto(imageUrl); } }} width="670px" height="250px" /> ); } ``` ### Callbacks - **onUpdate**: A callback function that is triggered when files are uploaded. It receives an object containing `uploadedFiles`. ``` -------------------------------- ### Define Room and Theme TypeScript Types Source: https://context7.com/nutlope/roomgpt/llms.txt Provides TypeScript type definitions for supported room types and design themes, ensuring type safety across frontend and API interactions. ```typescript // utils/dropdownTypes.ts export type themeType = | "Modern" | "Vintage" | "Minimalist" | "Professional" | "Tropical"; export type roomType = | "Living Room" | "Dining Room" | "Bedroom" | "Bathroom" | "Office" | "Gaming Room"; export const themes: themeType[] = [ "Modern", "Minimalist", "Professional", "Tropical", "Vintage", ]; export const rooms: roomType[] = [ "Living Room", "Dining Room", "Office", "Bedroom", "Bathroom", "Gaming Room", ]; // Usage in component state const [theme, setTheme] = useState("Modern"); const [room, setRoom] = useState("Living Room"); ``` -------------------------------- ### CompareSlider Component for Image Comparison Source: https://context7.com/nutlope/roomgpt/llms.txt Displays a side-by-side comparison of two images using an interactive slider. Requires 'react-compare-slider' and accepts URLs for the original and restored images. ```typescript import { ReactCompareSlider, ReactCompareSliderImage, } from "react-compare-slider"; interface CompareSliderProps { original: string; // URL of original room photo restored: string; // URL of AI-generated room photo } export const CompareSlider = ({ original, restored }: CompareSliderProps) => { return ( } itemTwo={} portrait className="flex w-[600px] mt-5 h-96" /> ); }; // Usage with toggle between side-by-side and slider view const [sideBySide, setSideBySide] = useState(false); const [originalPhoto, setOriginalPhoto] = useState(null); const [restoredImage, setRestoredImage] = useState(null); {restoredLoaded && sideBySide && ( )} ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.