PrintProntoDemo / app.py
Yaroslav95's picture
small fix
3f668eb
raw
history blame
6.67 kB
import base64
import gradio as gr
from openai import OpenAI
import os
import dotenv
dotenv.load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
script_dir = os.path.dirname(os.path.abspath(__file__))
printer_1 = """
# PrintPronto
Product: Business card
Color:
- Black (default)
- Blue
- Brown
- Orange
- Pink
Sizes:
3.5x2: multiplier 1.0
2.5x2.5: multiplier 0.95
2.125x3.375: multiplier 0.9
Custom size: This vendor doesn't support custom sizes
Material:
Standard (default): multiplier 1.0
Uncoated: multiplier 0.9
Base Prices (Quantity,Price per Unit $):
100, 0.23
250, 0.2
500, 1.9
1000, 1.75
"""
printer_2 = """
# BannerLord
Product: Business card
Color:
- Black (default)
- Blue
Sizes:
3.5x2: multiplier 1.0
2.5x2.5: multiplier 0.95
2.125x3.375: multiplier 0.9
3x2: multiplier 1.5
4x3: multiplier 1.5
Custom size: multiplier 2.0
Material:
Standard (default): multiplier 1.0
Uncoated: multiplier 0.95
Base Prices (Quantity,Price per Unit $):
100, 0.25
250, 0.22
500, 0.2
1000, 1.85
"""
printer_3 = """
# PrintMaster
Product: Business card
Color:
- Black (default)
- Blue
- Brown
Sizes:
3.5x2: multiplier 1.0
2.5x2.5: multiplier 0.95
2.125x3.375: multiplier 0.9
3x2: multiplier 1.5
4x3: multiplier 1.5
Custom size: multiplier 2.0
Material:
Standard (default): multiplier 1.0
Uncoated: multiplier 0.85
Base Prices (Quantity,Price per Unit $):
100, 0.21
250, 0.2
500, 0.18
1000, 0.17
"""
def find_best_price(request):
chat_prompt = (
"You are a customer assistant and you have to find the best price for the customer. "
"Here are the prices and options from the printers:\n"
f"Printer 1: {printer_1}\n"
f"Printer 2: {printer_2}\n"
f"Printer 3: {printer_3}\n"
"For each request, you should:\n"
"1. Check if the requested size (3x3 or 6x6 cm) is available. If not, suggest the nearest available size.\n"
"2. Calculate the final price by:\n"
" - Finding the nearest lower quantity in the base price list\n"
" - Multiplying by the surface option multiplier\n"
" - Multiplying by the size multiplier\n"
" - Multiplying by the finishing multiplier\n"
" - Multiplying by the label type multiplier\n"
"3. Do not use linear interpolation for quantities - use the nearest lower quantity pricing.\n\n"
"Example:\n"
"User: I want to print 600 business cards, 6x6 cm size, \n"
"Answer:\n"
"PrintPronto: Doesn't support custom size\n"
"###\n"
"BannerLord: Total for 600: $524.40\n"
"###\n"
"PrintMaster: Total for 600: $497.40\n\n"
"If user haven't specified one of the parameters, use the default one"
"Your response should display ONLY final pricing for each available option, nothing more"
"The '###' symbol must separate each printer's price calculation.\n"
)
chat_response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": chat_prompt},
{"role": "user", "content": request},
],
)
chat_text = chat_response.choices[0].message.content
html_page = render_html_page(chat_text)
chat_text = chat_text.replace("###", "")
return html_page, chat_text
def render_html_page(chat_text):
images = [
os.path.join(script_dir, "public/src/brochure3-400x400.jpg"),
os.path.join(script_dir, "public/src/quality-unfolded-brochures_1_.png"),
os.path.join(script_dir, "public/src/unfolded-glossy-brochures.png"),
]
product_links = [
"https://www.example.com/product_image.jpg",
"https://www.example.com/product_image.jpg",
"https://www.example.com/product_image.jpg",
]
# Split chat_text into product descriptions
product_descriptions = chat_text.split("###")
# Generate HTML content
html_content = """
<html>
<head>
<title>Product Cards</title>
<style>
.product-card {
border: 1px solid #ccc;
border-radius: 5px;
padding: 16px;
margin: 16px;
text-align: center;
width: 200px;
display: inline-block;
vertical-align: top;
}
.product-card img {
max-width: 100%;
height: auto;
}
.product-card button {
background-color: #4CAF50;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
}
.product-card button:hover {
background-color: #45a049;
}
</style>
</head>
<body>
"""
for i, description in enumerate(product_descriptions):
if "Doesn't support custom size" in description:
continue
image = images[i % len(images)]
with open(image, "rb") as img_file:
base64_image = base64.b64encode(img_file.read()).decode("utf-8")
product_link = product_links[i % len(product_links)]
html_content += f"""
<div class="product-card">
<img src="data:image/jpeg;base64,{base64_image}" alt="Product Image">
<p>{description}</p>
<a href="{product_link}" target="_blank"><button>Buy Now</button></a>
</div>
"""
html_content += """
</body>
</html>
"""
return html_content
logo = os.path.join(script_dir, "public/src/logo.svg")
with open(logo, "rb") as logo_file:
base64_logo = base64.b64encode(logo_file.read()).decode("utf-8")
iface = gr.Interface(
fn=find_best_price,
inputs=gr.Textbox(lines=3, placeholder="Enter what are you looking for"),
outputs=[
gr.HTML(label="Product Image"),
gr.Textbox(label="AI response: text mode"),
],
title="Get Instant Quote",
description=f"""
<div style="display: flex; justify-content: center; align-items: center; text-align: center; margin-bottom: 20px;">
<img src="data:image/svg+xml;base64,{base64_logo}" alt="Logo" style="width: 150px; height: auto;">
</div>
""",
submit_btn="Get quote",
)
def auth_function(username, password):
valid_users = {"admin": "password123", "user1": "pass456"}
return username in valid_users and valid_users[username] == password
iface.launch(auth=auth_function, share=True, ssr_mode=False)