### 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 (
);
}
// 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.