Copywriting / app.py
tunght's picture
add salt hash
12019ac
raw
history blame
12.5 kB
import traceback
import gradio as gr
import numpy as np
import os
from langchain_community.chat_models import ChatOpenAI
from langchain.schema import HumanMessage, SystemMessage, AIMessage
from langchain_anthropic import ChatAnthropic, ChatAnthropicMessages
from langchain_groq import ChatGroq
import openai
feature_text = "Brand: Duckly. \nProduct name: Duck runner pro. \nKey properties: t-shirt, for running, sweat wicking, for marathon, 100% cotton."
garment_type = "all"
reference_text = ""
structure_text = \
"""# Headline {{ headline | inspiring, bold, action-oriented, max 8 words }}
## Introduction
{{ introduction_paragraph | motivational, passionate, 2-3 sentences }}
## Features and Benefits
{% for feature in features %}
### Feature {{ loop.index }}: {{ feature.name | dynamic, direct, 5-6 words }}
{{ feature.details | energetic, clear, 3-4 sentences }}
{% endfor %}
## Technical Specifications
{{ technical_specs | informative, to the point, concise list format }}
"""
structure_text_1 = """[type: UK website, style=true, language=English]
{{ introduction_paragraph | motivational, passionate, 1-2 sentences }}
{% for feature in features as bulleted list %}
{{ feature.description | dynamic, direct, 3-6 words }}
{% endfor %}
{{ technical_specs | informative, to the point, concise list format }}"""
structure_text_2 = """[type: Japanese newsletter, style=true, language=Japanese]
{{ introduction_paragraph | motivational, passionate, 3-6 sentences }}"""
languages = ["American English",
"British English",
"German",
"French",
"Chinese",
"Spanish",
"Dutch",
"Italian",
"Japanese",
"Polish",
"Portuguese"]
models = ["gpt-4-turbo",
"gpt-4o",
"gpt-3.5-turbo",
"claude-3-sonnet-20240229",
"claude-3-opus-20240229",
#"llama3-70b-8192",
]
openai.api_key = os.environ["OPENAI_API_KEY"]
import base64
import requests
# OpenAI API Key
# Function to encode the image
def encode_image(image_path):
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode('utf-8')
import json
def get_json(text: str):
text = text.strip().replace('`', '').replace('json', '')
if text.startswith("No garment detected"):
return {
"features": [],
"intended_use": [],
"alt_text": []
}
return json.loads(text)
def detect_features(image_paths, garment_type, language="English"):
# Path to your image
# image_path = "path_to_your_image.jpg"
# Getting the base64 string
try:
base64_images = [encode_image(image_path[0]) for image_path in image_paths]
if garment_type == "" or garment_type == "all":
garment_type = "garment"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {openai.api_key}"
}
payload = {
"model": "gpt-4o",
# "model": "gpt-4-turbo",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": """Describe the features of the %s in the photos in less than 100 words.
What is the intended use of the %s in this image, use at most 5 words for intended use?
Generate alt text for each of the images.
Make sure to output the alt text in %s language.
If the photo does not contain a garment, return 'No garment detected'.
If the photo contains a garment, return the result in in the following JSON format without any preceding or trailing text:
{
"features": [list of comma separated features],
"intended_use": [list of comma separated intended uses],
"alt_text": [list of alt text for image 1, alt text for image 2]
}""" % (garment_type, garment_type, language)
},
] + [{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
}
} for base64_image in base64_images]
}
],
"temperature": 0.0,
"max_tokens": 300
}
response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)
print(response)
response = response.json()
print("image features", response["choices"][0]['message']['content'])
jresponse = get_json(response["choices"][0]['message']['content'])
return jresponse, base64_images
except Exception as e:
print(e.__class__, e)
traceback.print_exc()
return "", []
def generate(*data):
global visible
print("visible", visible)
feature, image, garment_type, model, temperature = data[:5]
struct_ref = data[5:]
print(f"features {feature},\n image {image},\n garment_type {garment_type},\n model {model},\n temperature {temperature},\n struct_ref {struct_ref}")
image_features, base64_images = detect_features(image, garment_type)
detected_features = ""
intended_use = ""
alt_texts = []
if image_features is not None and len(image_features) > 0:
alt_texts = image_features["alt_text"]
detected_features = ", ".join(image_features["features"])
intended_use = "Intended use: " + ", ".join(image_features["intended_use"])
print(f"Detected features: {detected_features}, Intended use: {intended_use}, Alt text: {alt_texts}")
if model.startswith("gpt"):
chat = ChatOpenAI(model=model)
elif model.startswith("claude"):
chat = ChatAnthropic(model_name=model, anthropic_api_key=os.environ["ANTHROPIC_API_KEY"])
else:
chat = ChatGroq(model_name=model, api_key=os.environ["GROQ_API_KEY"])
batch = []
for i in range(visible + 1):
structure = struct_ref[2 * i]
reference = struct_ref[2 * i + 1]
messages = [
SystemMessage(content=f"""You are a helpful assistant that writes about products for ecommerce websites."""),
HumanMessage(content=f"""Write a product description with the following features.
Make sure that the description follows the structure of the reference structure.
Make sure to use markdown format for the output.
Make sure that the entire output is written entirely in language defined in the reference structure.
Use language that is suitable for the type of document specified in the reference structure.
Use a consistent tone of voice throughout the text.
If the reference text is not empty, write the product description in the tone of voice of the reference text.
Make sure to output the product description only, do not include any preceeding text like "Here is your product description".
Do not include any part of the reference structure in the output.
\n\n {feature + detected_features} \n{intended_use} \nReference structure: {structure}\n Reference text: {reference}""")]
batch.append(messages)
description = ""
response = chat.batch(batch, temperature=temperature)
print(response)
description = "\n---\n".join([msg.content for msg in response])
md_content = description
alt_texts_str = '\n\n### Alt text\n\n' + '\n- ' + '\n- '.join(alt_texts) if len(alt_texts) > 0 else ""
alt_text_dict = {k[0]: v for (k, v) in zip(image, alt_texts)} if len(alt_texts) > 0 else {}
result_json = {"outputs": [msg.content for msg in response], "alt_text": alt_text_dict}
result_md = md_content + alt_texts_str + '\n'.join([f'![Product photo](data:image/png;base64,{base64_image} "{alt_text}")' if base64_image != "" else "" for (base64_image, alt_text) in zip(base64_images, alt_texts)])
return result_md, result_json
visible = 0
def add_output_click(*struct_ref):
global visible
print("Adding output ", visible)
# print(struct_ref)
visible += 1
structure_texts = struct_ref[::2]
reference_texts = struct_ref[1::2]
structures = [gr.Textbox(label=f"Structure {i}", lines=10, value=structure_texts[i], interactive=True, visible=i <= visible) for i in range(10)]
references = [gr.Textbox(label=f"Reference copy {i}", lines=3, value=reference_texts[i], interactive=True, visible=i <= visible) for i in range(10)]
struct_ref = [val for pair in zip(structures, references) for val in pair]
return struct_ref
def remove_output_click(*struct_ref):
global visible
print("Removing output", visible)
if visible == 0:
return struct_ref
visible -= 1
structure_texts = struct_ref[::2]
reference_texts = struct_ref[1::2]
structures = [gr.Textbox(label=f"Structure {i}", lines=10, value=structure_texts[i] if i <= visible else "", interactive=True, visible=i <= visible) for i in range(10)]
references = [gr.Textbox(label=f"Reference copy {i}", lines=3, value=reference_texts[i] if i <= visible else "", interactive=True, visible=i <= visible) for i in range(10)]
struct_ref = [val for pair in zip(structures, references) for val in pair]
return struct_ref
def show_advanced(model, temperature):
model = gr.Dropdown(models, value="gpt-4-turbo", interactive=True, label="Model", visible=True)
temperature = gr.Slider(minimum=0., maximum=1.0, value=0., interactive=True, label="Temperature", visible=True)
return model, temperature
with gr.Blocks() as demo:
with gr.Row():
with gr.Column():
feature = gr.Textbox(label="Features", value=feature_text, lines=3, interactive=True)
image = gr.Gallery(label="Images")
garment_type = gr.Textbox(label="Garment Type", value="all", lines=1, interactive=True)
# language = gr.Dropdown(languages, value="American English", interactive=True, label="Language")
with gr.Accordion(label="Advanced Options", open=False):
model = gr.Dropdown(models, value="gpt-4-turbo", interactive=True, label="Model", visible=True)
temperature = gr.Slider(minimum=0., maximum=1.0, value=0., interactive=True, label="Temperature", visible=True)
with gr.Row():
submit = gr.Button(value="Submit")
# advanced = gr.Button(value="Advanced")
with gr.Column():
struct_ref = [val for i in range(10) for val in
[gr.Textbox(label=f"Structure {i}", lines=10, value="", interactive=True, visible=i <= visible),
gr.Textbox(label=f"Reference copy {i}", lines=3, value="", interactive=True, visible=i <= visible)]]
struct_ref[0].value = structure_text_1
# struct_ref[2].value = structure_text_2
with gr.Row():
add_output = gr.Button(value="Add Output")
remove_output = gr.Button(value="Remove Output")
add_output.click(add_output_click, inputs=struct_ref, outputs=struct_ref)
remove_output.click(remove_output_click, inputs=struct_ref, outputs=struct_ref)
with gr.Column():
md_output = gr.Markdown(label="Output", show_label=True)
json_output = gr.JSON(label="JSON Output")
submit.click(generate, inputs=[feature, image, garment_type, model, temperature, *struct_ref],
outputs=[md_output, json_output])
# advanced.click(show_advanced, inputs=[], outputs=[model, temperature])
import bcrypt
def authf(username, password):
try:
with open("passwords.txt", "r") as f:
for line in f.readlines():
u, p = line.strip().split()
# print(u, p, password)
if u == username and bcrypt.checkpw(password.encode('utf-8'), p.encode('utf-8')):
return True
except Exception as e:
print("Error reading password", e)
traceback.print_exc()
return False
if __name__ == '__main__':
demo.launch(server_name="0.0.0.0", auth=authf)