Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add: Interior Designer App #339

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions examples/interior-designer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Interior Designer

It allows you to upload a picture of your room and describe how you want it redesigned. The app will first analyze the image and identify the items in it. Then, based on your description, it will suggest changes you can make to redesign your room, including the color scheme, furniture, objects you can add, etc. and search for products on the internet and share their links as well.

## High-level overview

- Users can upload a picture of a room and provide a description of how their room wants to be.
- The Python backend takes this input and uses GPTScript’s Python module to execute the GPTScript.
- The vision tool first analyzes the image, followed by a generation of ideas.
- The output of both is sent to the search tool, which searches the Internet for products you can purchase and add to your room.
- These are saved within a markdown file that is read and displayed on the screen.

## Installation

### Prerequisites

- Python 3.8 or later
- Flask
- Python dependencies listed in `requirements.txt` respectively.

### Steps

1. Clone the repository:

``` bash
git clone https://github.com/gptscript-ai/gptscript.git
```

2. Navigate to the `examples/interior-designer` directory and install the dependencies:

Python:

```bash
pip install -r requirements.txt
```

3. Setup `OPENAI_API_KEY` (Eg: `export OPENAI_API_KEY="yourapikey123456"`). You can get your [API key here](https://platform.openai.com/api-keys).

4. Run the Flask application using `flask run` or `python app.py`

## Usage

1. Open your web browser and navigate to `http://127.0.0.1:5000/`.
2. Use the interface to provide upload an image and provide a description.
3. The application will generate ideas to redesing your room.
66 changes: 66 additions & 0 deletions examples/interior-designer/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from gptscript.command import stream_exec_file
from flask import Flask, render_template, request, jsonify
import os
import uuid
from werkzeug.utils import secure_filename

app = Flask(__name__)

# Setting the base directory
base_dir = os.path.dirname(os.path.abspath(__file__))
app.config['PWD'] = base_dir
SCRIPT_PATH = os.path.join(base_dir, 'designer.gpt')

# The output file name
def print_output(out, err):
# Error stream has the debug info that is useful to see
for line in err:
print(line)
for line in out:
print(line)

@app.route('/')
def index():
return render_template('index.html')

def save_image(image_file, image_file_name, request_id):
# Save the uploaded image to the current directory
image_path = os.path.join(app.config['PWD'], image_file_name)
image_file.save(image_path)

return image_path

@app.route('/get-ideas', methods=['POST'])
def get_ideas():
try:
# Generate a unique request ID
request_id = str(uuid.uuid4())

# Get the image file and prompt from the request
image_file = request.files['image']
prompt = request.form['prompt']

# Generate an input image and output file name based on the request ID
image_file_name = f"{request_id}_room.jpg"
output_file_name = f"{request_id}_output.md"
output_file_path = os.path.join(app.config['PWD'], output_file_name)

# Save the image file to the current directory
image_path = save_image(image_file, image_file_name, request_id)

# Execute the script with the prompt, image path and outputfile name
out, err, wait = stream_exec_file(SCRIPT_PATH, "--prompt " + prompt + " --outputfile "+output_file_name + " --imagefile "+image_file_name)
print_output(out, err)
wait()

# Read the output file
with open(output_file_path, 'r') as output_file:
summary = output_file.read()

# Return the summary content
return summary
except Exception as e:
return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
app.run(debug=os.environ.get('FLASK_DEBUG', True), host='0.0.0.0')
24 changes: 24 additions & 0 deletions examples/interior-designer/designer.gpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
tools: sys.find, sys.read, sys.write, search, github.com/gptscript-ai/gpt4-v-vision
args: prompt: Prompt from the user.
args: outputfile: Name of the output file.
args: imagefile: Name of the image file.

You are an ace interior designer and decorater. For the image provided, analyse the image and prompt and perform the following steps in order:

1. Call the vision tool and send a prompt to "Anaylse the image $(imagefilename) in the current directory and identify the objects in the image".
2. Based on the above analysis and the prompt provided, suggest the changes that can be done in the room in terms of paint color, theme, wallpaper, objects, furniture that can be added to the room.
3. If you feel that some of the identified objects can be resued, suggest them too.
4. Search google for new furnitures and objects suggested for the room based on the prompt.
5. Create a new md file named $(outputfile) and insert the $(imagefilename) image on the top followed by the analysis, recommendations, how to reuse some items and product links with proper headings, bullets etc.


---
name: search
description: Searches the internet for content
args: query: The query to search for
tools: sys.http.html2text?

1. Search google "https://www.google.com/search?q={$query}" for products and download content.
2. Look for the first 3 search results that have the products that relate to the room.
3. Download each search result and look for product that would best answer the query ${query}.
4. Return the link to products that one can buy.
26 changes: 26 additions & 0 deletions examples/interior-designer/dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Use the official Python image as the base image
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be named Dockerfile to follow convention.

FROM python:3.9-slim

# Set the working directory
WORKDIR /app

# Copy the requirements file
COPY requirements.txt .

# Install the Python dependencies
RUN pip install --no-cache-dir -r requirements.txt

# Copy the Flask app code
COPY . .

# Expose the port
EXPOSE 5000

# Set the environment variable
ENV FLASK_APP=app.py

# Set this to True/False to enable/disable debugging.
ENV FLASK_DEBUG=False

# Run app
CMD ["flask", "run", "--host=0.0.0.0"]
3 changes: 3 additions & 0 deletions examples/interior-designer/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Flask==2.0.1
gptscript==0.4.1
Werkzeug==2.2.2
46 changes: 46 additions & 0 deletions examples/interior-designer/static/css/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* style.css */
body {
background-color: #f8f2e6;
font-family: 'Merriweather', serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}

.container {
max-width: 500px;
width: 60%;
padding: 0 10px;
}

.input, .button {
border-radius: 0 !important;
}

.box {
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
border-radius: 0;
padding: 30px;
}

.markdown-body {
box-sizing: border-box;
background-color: #f5f5f5;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
border-radius: 0;
padding: 30px;
}

.gpt-logo {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}

.gpt-logo img {
width: 15%;
height: 15%;
}
63 changes: 63 additions & 0 deletions examples/interior-designer/static/js/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// app.js
new Vue({
el: '#app',
data: {
prompt: '',
imageFile: null,
imageUrl: null,
showIdeas: false,
ideasMarkdown: '',
renderedMarkdown: '',
isLoading: false
},
methods: {
handleImageUpload(event) {
this.imageFile = event.target.files[0];
this.imageUrl = URL.createObjectURL(event.target.files[0]);
},
getIdeas() {
this.isLoading = true;
const formData = new FormData();
formData.append('image', this.imageFile);
formData.append('prompt', this.prompt);

axios.post('/get-ideas', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => {
this.ideasMarkdown = response.data;
this.renderedMarkdown = marked.parse(this.ideasMarkdown);
this.showIdeas = true;
})
.catch(error => {
if (error.response && error.response.data && error.response.data.error) {
alert('Error: ' + error.response.data.error);
} else {
alert('An unexpected error occurred. Please try again later.');
}
})
.finally(() => {
this.isLoading = false;
});
}
}
});

// Initialize the marked library
marked.setOptions({
renderer: new marked.Renderer(),
highlight: function(code, language) {
const hljs = require('highlight.js');
const validLanguage = hljs.getLanguage(language) ? language : 'plaintext';
return hljs.highlight(validLanguage, code).value;
},
pedantic: false,
gfm: true,
breaks: false,
sanitize: false,
smartLists: true,
smartypants: false,
xhtml: false
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions examples/interior-designer/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Interior Designer</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.9.3/css/bulma.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css">
<link href="https://fonts.googleapis.com/css2?family=Merriweather:wght@400;700&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
</head>
<body>
<div id="app" class="container is-fluid">
<section class="hero is-primary is-medium is-bold" style="background-image: linear-gradient(to right, #dda77b, #945D5E);">
<div class="hero-body">
<h1 class="title">Interior Designer</h1>
<h2 class="subtitle">Are you bored of how your room looks? Want some inspiration to redesign your room? Simply click a picutre of your room, add a prompt and upload it here and see the magic unfold!</h2>
</div>
</section>

<div class="box">
<div class="field">
<label class="label">Image</label>
<div class="control">
<input class="input" type="file" accept="image/*" ref="imageInput" @change="handleImageUpload">
</div>
</div>
<div class="field">
<label class="label">Describe your desired room style</label>
<div class="control">
<textarea class="textarea" placeholder="I want a room that gives me summer chill vibes." v-model="prompt"></textarea>
</div>
</div>
<button class="button is-primary is-medium" style="background-color: #37123C;" @click="getIdeas" :disabled="isLoading">
<span v-if="isLoading" class="icon is-medium">
<i class="fas fa-spinner fa-spin"></i>
</span>
<span v-else>Design My Room</span>
</button>
</div>
<div class="box markdown-body" v-if="showIdeas">
<img :src="imageUrl" v-if="imageUrl" class="img-responsive" height="50%" width="50%" alt="Uploaded Image">
<div v-html="renderedMarkdown"></div>
</div>
<div class="gpt-logo"><a href="https://gptscript.ai" target="_blank"><img src="{{url_for('static', filename='made-with-gptscript.png')}}"/></a></div>
</div>

<script src="{{ url_for('static', filename='js/app.js') }}"></script>
<script defer src="https://use.fontawesome.com/releases/v5.15.4/js/all.js"></script>
</body>
</html>