Spaces:
Sleeping
Sleeping
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) | |