Spaces:
Sleeping
Sleeping
Commit
·
7a38b33
1
Parent(s):
0755ce5
initial commit
Browse files- .gitignore +58 -0
- app.py +107 -0
- llm_api/anthropic_api.py +122 -0
- llm_api/constants.py +20 -0
- llm_api/exceptions.py +5 -0
- llm_api/langchain_api.py +101 -0
- llm_api/native_api.py +30 -0
- llm_api/openai_api.py +94 -0
- llm_api/utils.py +14 -0
- read_schema_free.py +57 -0
- read_schema_structured.py +301 -0
- schema_free.py +57 -0
- schema_structured.py +301 -0
.gitignore
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# These are some examples of commonly ignored file patterns.
|
| 2 |
+
# You should customize this list as applicable to your project.
|
| 3 |
+
# Learn more about .gitignore:
|
| 4 |
+
# https://www.atlassian.com/git/tutorials/saving-changes/gitignore
|
| 5 |
+
|
| 6 |
+
# Node artifact files
|
| 7 |
+
node_modules/
|
| 8 |
+
dist/
|
| 9 |
+
|
| 10 |
+
# Compiled Java class files
|
| 11 |
+
*.class
|
| 12 |
+
|
| 13 |
+
# Compiled Python bytecode
|
| 14 |
+
*.py[cod]
|
| 15 |
+
|
| 16 |
+
# Log files
|
| 17 |
+
*.log
|
| 18 |
+
|
| 19 |
+
# Package files
|
| 20 |
+
*.jar
|
| 21 |
+
|
| 22 |
+
# Maven
|
| 23 |
+
target/
|
| 24 |
+
dist/
|
| 25 |
+
|
| 26 |
+
# JetBrains IDE
|
| 27 |
+
.idea/
|
| 28 |
+
|
| 29 |
+
# Unit test reports
|
| 30 |
+
TEST*.xml
|
| 31 |
+
|
| 32 |
+
# Generated by MacOS
|
| 33 |
+
.DS_Store
|
| 34 |
+
|
| 35 |
+
# Generated by Windows
|
| 36 |
+
Thumbs.db
|
| 37 |
+
|
| 38 |
+
# Applications
|
| 39 |
+
*.app
|
| 40 |
+
*.exe
|
| 41 |
+
*.war
|
| 42 |
+
|
| 43 |
+
# Large media files
|
| 44 |
+
*.mp4
|
| 45 |
+
*.tiff
|
| 46 |
+
*.avi
|
| 47 |
+
*.flv
|
| 48 |
+
*.mov
|
| 49 |
+
*.wmv
|
| 50 |
+
|
| 51 |
+
env/
|
| 52 |
+
__pycache__/
|
| 53 |
+
testcases/
|
| 54 |
+
*.ipynb
|
| 55 |
+
server.crt
|
| 56 |
+
server.key
|
| 57 |
+
server.csr
|
| 58 |
+
sample_data.json
|
app.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import gradio as gr
|
| 3 |
+
from dotenv import load_dotenv
|
| 4 |
+
from llm_api.exceptions import RefusalError
|
| 5 |
+
# from llm_api.langchain_api import extract_info, follow_structure
|
| 6 |
+
from llm_api.native_api import extract_info, follow_structure
|
| 7 |
+
from openai import BadRequestError
|
| 8 |
+
|
| 9 |
+
load_dotenv('.env', override=True)
|
| 10 |
+
|
| 11 |
+
def extract_free_fn(gallery, provider, schema):
|
| 12 |
+
img_paths = [item[0] for item in gallery]
|
| 13 |
+
# write schema to file before calling extract_free_properties
|
| 14 |
+
try:
|
| 15 |
+
if schema is not None and isinstance(schema, str) and 'import' not in schema.replace("'import'", '').replace("'important'", ''):
|
| 16 |
+
with open('schema_free.py', 'r') as f:
|
| 17 |
+
default_schema = f.read()
|
| 18 |
+
import_part = default_schema.split('#####')[0]
|
| 19 |
+
print('Executing freestyle schema...')
|
| 20 |
+
full_schema = import_part + schema
|
| 21 |
+
with open('read_schema_free.py', 'w') as f:
|
| 22 |
+
f.write(full_schema)
|
| 23 |
+
exec(import_part + schema, globals())
|
| 24 |
+
print('Executed freestyle schema')
|
| 25 |
+
else:
|
| 26 |
+
print('SCHEMA ELSE')
|
| 27 |
+
raise Exception('Invalid schema')
|
| 28 |
+
except Exception as e:
|
| 29 |
+
print(e)
|
| 30 |
+
return 'Invalid schema! Please check the schema or Reload this page to restore default settings', {}, []
|
| 31 |
+
|
| 32 |
+
try:
|
| 33 |
+
free_attributes = extract_info(img_paths, provider, Garment)
|
| 34 |
+
free_attributes = free_attributes.model_dump_json()
|
| 35 |
+
except RefusalError as e:
|
| 36 |
+
return e.message, {}, []
|
| 37 |
+
except BadRequestError as e:
|
| 38 |
+
return e.message, {}, []
|
| 39 |
+
|
| 40 |
+
return f'OK - provider: {provider}', free_attributes, [1] * 100
|
| 41 |
+
|
| 42 |
+
def follow_schema_fn(free_attributes, provider, probs, schema):
|
| 43 |
+
try:
|
| 44 |
+
if schema is not None and isinstance(schema, str) and 'import' not in schema.replace("'import'", '').replace("'important'", ''):
|
| 45 |
+
with open('schema_structured.py', 'r') as f:
|
| 46 |
+
default_schema = f.read()
|
| 47 |
+
import_part = default_schema.split('#####')[0]
|
| 48 |
+
print('executing structured schema\n')
|
| 49 |
+
full_schema = import_part + schema
|
| 50 |
+
with open('read_schema_structured.py', 'w') as f:
|
| 51 |
+
f.write(full_schema)
|
| 52 |
+
exec(full_schema, globals())
|
| 53 |
+
print('executed structured schema')
|
| 54 |
+
else:
|
| 55 |
+
print('SCHEMA ELSE')
|
| 56 |
+
raise Exception('Invalid schema')
|
| 57 |
+
except:
|
| 58 |
+
return 'Invalid schema! Please check the schema or Reload this page to restore default settings', {}
|
| 59 |
+
|
| 60 |
+
try:
|
| 61 |
+
schema_attributes = follow_structure(free_attributes, provider, Garment)
|
| 62 |
+
schema_attributes = schema_attributes.model_dump_json()
|
| 63 |
+
except RefusalError as e:
|
| 64 |
+
return e.message, {}
|
| 65 |
+
except BadRequestError as e:
|
| 66 |
+
return e.message, {}
|
| 67 |
+
|
| 68 |
+
return f'OK - provider: {provider}', schema_attributes
|
| 69 |
+
|
| 70 |
+
with gr.Blocks(title='Internal Demo for Attribution') as demo:
|
| 71 |
+
with gr.Row():
|
| 72 |
+
with gr.Column(scale=12):
|
| 73 |
+
gr.Markdown('''<div style="text-align: center; font-size: 24px;"><strong>Internal Demo for Attribution</strong></div>''')
|
| 74 |
+
with gr.Row():
|
| 75 |
+
with gr.Column(scale=4):
|
| 76 |
+
# gr.Markdown('''<div style="text-align: left; font-size: 18px;">Upload images of a garment and click Extract Freestyle</div>''')
|
| 77 |
+
gallery = gr.Gallery(label='Images', type='filepath')
|
| 78 |
+
probs_text = gr.Textbox(label='Probabilities', placeholder='Probabilities', visible=False)
|
| 79 |
+
provider = gr.Dropdown(label='Provider', choices=['openai', 'anthropic'], value='openai')
|
| 80 |
+
button_extract = gr.Button(value='Extract Freestyle')
|
| 81 |
+
with gr.Column(scale=4):
|
| 82 |
+
# gr.Markdown('''<div style="text-align: left; font-size: 18px;">Click Follow Schema to convert the freestyle output to predefined schema</div>''')
|
| 83 |
+
status_free_text = gr.Textbox(label='Request Status', placeholder='')
|
| 84 |
+
free_attributes = gr.JSON(label='Freestyle Attribute')
|
| 85 |
+
button_follow = gr.Button(value='Follow Schema')
|
| 86 |
+
with gr.Column(scale=4):
|
| 87 |
+
status_structured_text = gr.Textbox(label='Request Status', placeholder='')
|
| 88 |
+
schema_attributes = gr.JSON(label='Schema Attributes')
|
| 89 |
+
with gr.Row():
|
| 90 |
+
# free_schema = gr.Dataframe(row_count=(4, 'dynamic'), label='Freestyle Schema', col_count=(4, 'dynamic'), interactive=True)
|
| 91 |
+
# schema = gr.Dataframe(row_count=(4, 'dynamic'), label='Schema', col_count=(4, 'dynamic'), interactive=True)
|
| 92 |
+
with open('schema_free.py', 'r') as f:
|
| 93 |
+
schema_free_text = f.read()
|
| 94 |
+
schema_free_text = schema_free_text.split('#####')[1]
|
| 95 |
+
with open('schema_structured.py', 'r') as f:
|
| 96 |
+
schema_structured_text = f.read()
|
| 97 |
+
schema_structured_text = schema_structured_text.split('#####')[1]
|
| 98 |
+
free_schema = gr.TextArea(label='Freestyle Schema', placeholder='Freestyle Schema', visible=True, value=schema_free_text, interactive=True)
|
| 99 |
+
structured_schema = gr.TextArea(label='Structured Schema', placeholder='Schema', visible=True, value=schema_structured_text, interactive=True)
|
| 100 |
+
|
| 101 |
+
button_extract.click(extract_free_fn, [gallery, provider, free_schema], [status_free_text, free_attributes, probs_text])
|
| 102 |
+
button_follow.click(follow_schema_fn, [free_attributes, provider, probs_text, structured_schema], [status_structured_text, schema_attributes])
|
| 103 |
+
|
| 104 |
+
# demo.launch(server_name="0.0.0.0", server_port=7688, share=False, ssl_verify=True, ssl_certfile=None, ssl_keyfile=None, auth=None)
|
| 105 |
+
# demo.launch(server_name="0.0.0.0", server_port=7860, share=False, ssl_verify=False, ssl_certfile="server.crt", ssl_keyfile="server.key", auth=None)
|
| 106 |
+
demo.launch(server_name="0.0.0.0", server_port=7861)
|
| 107 |
+
|
llm_api/anthropic_api.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from anthropic import Anthropic
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
from llm_api.utils import get_data_format, get_image_data
|
| 4 |
+
from .constants import EXTRACT_INFO_HUMAN_MESSAGE, EXTRACT_INFO_SYSTEM_MESSAGE,FOLLOW_SCHEMA_HUMAN_MESSAGE, FOLLOW_SCHEMA_SYSTEM_MESSAGE
|
| 5 |
+
|
| 6 |
+
load_dotenv(override=True)
|
| 7 |
+
client = Anthropic()
|
| 8 |
+
|
| 9 |
+
def extract_info(img_paths, schema):
|
| 10 |
+
print('Extracting info via Anthropic...')
|
| 11 |
+
tools = [
|
| 12 |
+
{
|
| 13 |
+
"name": "extract_garment_info",
|
| 14 |
+
"description": "Extracts key information from the image.",
|
| 15 |
+
"input_schema": schema.model_json_schema(),
|
| 16 |
+
"cache_control": {"type": "ephemeral"}
|
| 17 |
+
}
|
| 18 |
+
]
|
| 19 |
+
|
| 20 |
+
image_messages = [
|
| 21 |
+
{
|
| 22 |
+
"type": "image",
|
| 23 |
+
"source": {
|
| 24 |
+
"type": "base64",
|
| 25 |
+
"media_type": f"image/{get_data_format(img_path)}",
|
| 26 |
+
"data": get_image_data(img_path)
|
| 27 |
+
}
|
| 28 |
+
} for img_path in img_paths
|
| 29 |
+
]
|
| 30 |
+
|
| 31 |
+
system_message = [
|
| 32 |
+
{
|
| 33 |
+
"type": "text",
|
| 34 |
+
"text": EXTRACT_INFO_SYSTEM_MESSAGE
|
| 35 |
+
}
|
| 36 |
+
]
|
| 37 |
+
|
| 38 |
+
text_messages = [{
|
| 39 |
+
"type": "text",
|
| 40 |
+
"text": EXTRACT_INFO_HUMAN_MESSAGE,
|
| 41 |
+
}]
|
| 42 |
+
|
| 43 |
+
messages=[
|
| 44 |
+
{
|
| 45 |
+
"role": "user",
|
| 46 |
+
"content": text_messages + image_messages
|
| 47 |
+
}
|
| 48 |
+
]
|
| 49 |
+
|
| 50 |
+
response = client.messages.create(
|
| 51 |
+
model="claude-3-5-sonnet-20240620",
|
| 52 |
+
extra_headers={
|
| 53 |
+
"anthropic-beta": "prompt-caching-2024-07-31"
|
| 54 |
+
},
|
| 55 |
+
max_tokens=2048,
|
| 56 |
+
system=system_message,
|
| 57 |
+
tools=tools,
|
| 58 |
+
messages=messages
|
| 59 |
+
)
|
| 60 |
+
|
| 61 |
+
for content in response.content:
|
| 62 |
+
if content.type == 'tool_use':
|
| 63 |
+
# print(content.input)
|
| 64 |
+
# print(type(content.input))
|
| 65 |
+
print('Found tool_use!')
|
| 66 |
+
return schema.model_validate(content.input)
|
| 67 |
+
|
| 68 |
+
print('ERROR: No tool_use found!')
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def follow_structure(json_info, schema):
|
| 72 |
+
print('Following structure via Anthropic...')
|
| 73 |
+
tools = [
|
| 74 |
+
{
|
| 75 |
+
"name": "extract_garment_info",
|
| 76 |
+
"description": FOLLOW_SCHEMA_HUMAN_MESSAGE,
|
| 77 |
+
"input_schema": schema.model_json_schema(),
|
| 78 |
+
"cache_control": {"type": "ephemeral"}
|
| 79 |
+
}
|
| 80 |
+
]
|
| 81 |
+
|
| 82 |
+
print('DEBUG: human message**************************')
|
| 83 |
+
print(FOLLOW_SCHEMA_HUMAN_MESSAGE.format(json_info=json_info))
|
| 84 |
+
text_messages = [{
|
| 85 |
+
"type": "text",
|
| 86 |
+
"text": FOLLOW_SCHEMA_HUMAN_MESSAGE.format(json_info=json_info),
|
| 87 |
+
}]
|
| 88 |
+
|
| 89 |
+
system_message = [
|
| 90 |
+
{
|
| 91 |
+
"type": "text",
|
| 92 |
+
"text": FOLLOW_SCHEMA_SYSTEM_MESSAGE
|
| 93 |
+
}
|
| 94 |
+
]
|
| 95 |
+
|
| 96 |
+
messages=[
|
| 97 |
+
{
|
| 98 |
+
"role": "user",
|
| 99 |
+
"content": text_messages
|
| 100 |
+
}
|
| 101 |
+
]
|
| 102 |
+
|
| 103 |
+
response = client.messages.create(
|
| 104 |
+
model="claude-3-5-sonnet-20240620",
|
| 105 |
+
extra_headers={
|
| 106 |
+
"anthropic-beta": "prompt-caching-2024-07-31"
|
| 107 |
+
},
|
| 108 |
+
max_tokens=2048,
|
| 109 |
+
system=system_message,
|
| 110 |
+
tools=tools,
|
| 111 |
+
messages=messages
|
| 112 |
+
)
|
| 113 |
+
|
| 114 |
+
for content in response.content:
|
| 115 |
+
if content.type == 'tool_use':
|
| 116 |
+
# print(content.input)
|
| 117 |
+
# print(type(content.input))
|
| 118 |
+
print('Found tool_use!***********************')
|
| 119 |
+
print(content.input)
|
| 120 |
+
return schema.model_validate(content.input['json_info'])
|
| 121 |
+
|
| 122 |
+
print('ERROR: No tool_use found!')
|
llm_api/constants.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
EXTRACT_INFO_HUMAN_MESSAGE = \
|
| 2 |
+
"Output properties of the product in the image."
|
| 3 |
+
|
| 4 |
+
EXTRACT_INFO_SYSTEM_MESSAGE = \
|
| 5 |
+
"You are an expert at structured data extraction. You will be given an image of a product and should output the its properties into the given structure."
|
| 6 |
+
|
| 7 |
+
FOLLOW_SCHEMA_HUMAN_MESSAGE = \
|
| 8 |
+
"""Convert following attributes to structured schema. Keep all the keys and number of values. Only replace the values themselves. :
|
| 9 |
+
|
| 10 |
+
{json_info}"""
|
| 11 |
+
|
| 12 |
+
FOLLOW_SCHEMA_SYSTEM_MESSAGE = \
|
| 13 |
+
"You are an expert at structured data extraction. You will be given an dictionary of attributes of a product and should output the its properties into the given structure."
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
if __name__ == '__main__':
|
| 17 |
+
print('Run test cases...')
|
| 18 |
+
print(FOLLOW_SCHEMA_HUMAN_MESSAGE.format(json_info='{"color": "red"}'))
|
| 19 |
+
print(FOLLOW_SCHEMA_HUMAN_MESSAGE.format(json_info='{"color": "red", "size": "small"}'))
|
| 20 |
+
print(FOLLOW_SCHEMA_HUMAN_MESSAGE.format(json_info='{"color": "red", "size": "small", "material": "cotton"}'))
|
llm_api/exceptions.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class RefusalError(Exception):
|
| 2 |
+
"""Exception raised when the model refuses to respond."""
|
| 3 |
+
def __init__(self, message="The model refused to respond to the given input."):
|
| 4 |
+
self.message = message
|
| 5 |
+
super().__init__(self.message)
|
llm_api/langchain_api.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .utils import get_data_format, get_image_data
|
| 2 |
+
from langchain_anthropic import ChatAnthropic
|
| 3 |
+
from langchain_openai import ChatOpenAI
|
| 4 |
+
from dotenv import load_dotenv
|
| 5 |
+
from langchain_core.messages import HumanMessage, SystemMessage
|
| 6 |
+
from schema_structured import Garment as StructuredGarment
|
| 7 |
+
from schema_free import Garment as FreeGarment
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
load_dotenv()
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
anthropic_llm = ChatAnthropic(
|
| 14 |
+
model="claude-3-5-sonnet-20240620",
|
| 15 |
+
temperature=0,
|
| 16 |
+
max_tokens=1024,
|
| 17 |
+
timeout=None,
|
| 18 |
+
max_retries=2,
|
| 19 |
+
# other params...
|
| 20 |
+
)
|
| 21 |
+
|
| 22 |
+
openai_llm = ChatOpenAI(
|
| 23 |
+
model="gpt-4o",
|
| 24 |
+
temperature=0,
|
| 25 |
+
max_tokens=None,
|
| 26 |
+
timeout=None,
|
| 27 |
+
max_retries=2,
|
| 28 |
+
# api_key="...", # if you prefer to pass api key in directly instaed of using env vars
|
| 29 |
+
# base_url="...",
|
| 30 |
+
# organization="...",
|
| 31 |
+
# other params...
|
| 32 |
+
)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def extract_info(image_paths, provider, schema):
|
| 36 |
+
if provider == 'anthropic':
|
| 37 |
+
llm = anthropic_llm
|
| 38 |
+
elif provider == 'openai':
|
| 39 |
+
llm = openai_llm
|
| 40 |
+
else:
|
| 41 |
+
raise ValueError('Invalid provider')
|
| 42 |
+
|
| 43 |
+
text_message = [{"type": "text", "text": "describe the product in the set of images"}]
|
| 44 |
+
image_message = [
|
| 45 |
+
{
|
| 46 |
+
"type": "image_url",
|
| 47 |
+
"image_url": {"url": f"data:image/{get_data_format(image_path)};base64,{get_image_data(image_path)}"},
|
| 48 |
+
}
|
| 49 |
+
for image_path in image_paths
|
| 50 |
+
]
|
| 51 |
+
system_text= "You are a helpful assistant that describes the product in the set of images."
|
| 52 |
+
human_message = HumanMessage(content=text_message + image_message)
|
| 53 |
+
structured_llm = llm.with_structured_output(schema)
|
| 54 |
+
if provider == 'anthropic':
|
| 55 |
+
ai_msg = structured_llm.invoke([human_message], system=system_text)
|
| 56 |
+
elif provider == 'openai':
|
| 57 |
+
system_message = SystemMessage(content=system_text)
|
| 58 |
+
ai_msg = structured_llm.invoke([system_message, human_message]) # add system message later
|
| 59 |
+
|
| 60 |
+
return ai_msg
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def follow_structure(json_info, provider, schema):
|
| 64 |
+
if provider == 'anthropic':
|
| 65 |
+
llm = anthropic_llm
|
| 66 |
+
elif provider == 'openai':
|
| 67 |
+
llm = openai_llm
|
| 68 |
+
else:
|
| 69 |
+
raise ValueError('Invalid provider')
|
| 70 |
+
|
| 71 |
+
text_message = [{"type": "text", "text": f"Convert following attributes to structured schema. Keep all the keys and number of values. Only replace the values themselves. :\n\n{json_info}"}]
|
| 72 |
+
system_text= "You are an expert at structured data extraction. You will be given an dictionary of attributes of a product and should output the its properties into the given structure."
|
| 73 |
+
human_message = HumanMessage(content=text_message)
|
| 74 |
+
structured_llm = llm.with_structured_output(schema)
|
| 75 |
+
if provider == 'anthropic':
|
| 76 |
+
ai_msg = structured_llm.invoke([human_message], system=system_text)
|
| 77 |
+
elif provider == 'openai':
|
| 78 |
+
system_message = SystemMessage(content=system_text)
|
| 79 |
+
ai_msg = structured_llm.invoke([system_message, human_message]) # add system message later
|
| 80 |
+
|
| 81 |
+
return ai_msg
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
if __name__ == '__main__':
|
| 85 |
+
print('Running tests...')
|
| 86 |
+
print("Test 1: Provider Anthropic, Schema Structure")
|
| 87 |
+
info = extract_info(['1.png', '2.png'], provider='anthropic', schema=StructuredGarment)
|
| 88 |
+
json_info = info.model_dump_json()
|
| 89 |
+
print(json_info)
|
| 90 |
+
print('Test 2: Provider OpenAI, Schema Structure')
|
| 91 |
+
info = extract_info(['1.png', '2.png'], provider='openai', schema=StructuredGarment)
|
| 92 |
+
json_info = info.model_dump_json()
|
| 93 |
+
print(json_info)
|
| 94 |
+
print('Test 3: Provider Anthropic, Schema Free')
|
| 95 |
+
info = extract_info(['1.png', '2.png'], provider='anthropic', schema=FreeGarment)
|
| 96 |
+
json_info = info.model_dump_json()
|
| 97 |
+
print(json_info)
|
| 98 |
+
print('Test 4: Provider OpenAI, Schema Free')
|
| 99 |
+
info = extract_info(['1.png', '2.png'], provider='openai', schema=FreeGarment)
|
| 100 |
+
json_info = info.model_dump_json()
|
| 101 |
+
print(json_info)
|
llm_api/native_api.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import base64
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
from . import openai_api as openai_info_extractor
|
| 4 |
+
from . import anthropic_api as anthropic_extractor
|
| 5 |
+
|
| 6 |
+
def encode_image(image_path):
|
| 7 |
+
with open(image_path, "rb") as image_file:
|
| 8 |
+
return base64.b64encode(image_file.read()).decode('utf-8')
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def extract_info(image_paths, provider, schema):
|
| 12 |
+
if provider == 'anthropic':
|
| 13 |
+
extractor = anthropic_extractor
|
| 14 |
+
elif provider == 'openai':
|
| 15 |
+
extractor = openai_info_extractor
|
| 16 |
+
else:
|
| 17 |
+
raise ValueError('Invalid provider')
|
| 18 |
+
|
| 19 |
+
return extractor.extract_info(image_paths, schema)
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def follow_structure(json_info, provider, schema):
|
| 23 |
+
if provider == 'anthropic':
|
| 24 |
+
extractor = anthropic_extractor
|
| 25 |
+
elif provider == 'openai':
|
| 26 |
+
extractor = openai_info_extractor
|
| 27 |
+
else:
|
| 28 |
+
raise ValueError('Invalid provider')
|
| 29 |
+
|
| 30 |
+
return extractor.follow_structure(json_info, schema)
|
llm_api/openai_api.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
from .utils import get_data_format, get_image_data
|
| 4 |
+
from openai import OpenAI, BadRequestError
|
| 5 |
+
from .exceptions import RefusalError
|
| 6 |
+
from .constants import EXTRACT_INFO_HUMAN_MESSAGE, EXTRACT_INFO_SYSTEM_MESSAGE,FOLLOW_SCHEMA_HUMAN_MESSAGE, FOLLOW_SCHEMA_SYSTEM_MESSAGE
|
| 7 |
+
|
| 8 |
+
load_dotenv(override=True)
|
| 9 |
+
client = OpenAI()
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def extract_info(img_paths, schema):
|
| 13 |
+
print('Extracting info via OpenAI...')
|
| 14 |
+
text_content = [
|
| 15 |
+
{
|
| 16 |
+
"type": "text",
|
| 17 |
+
"text": EXTRACT_INFO_HUMAN_MESSAGE,
|
| 18 |
+
},
|
| 19 |
+
]
|
| 20 |
+
image_content = [
|
| 21 |
+
{
|
| 22 |
+
"type": "image_url",
|
| 23 |
+
"image_url": {
|
| 24 |
+
"url": f"data:image/{get_image_data(img_path)};base64,{get_image_data(img_path)}",
|
| 25 |
+
},
|
| 26 |
+
}
|
| 27 |
+
for img_path in img_paths
|
| 28 |
+
]
|
| 29 |
+
response = client.beta.chat.completions.parse(
|
| 30 |
+
model="gpt-4o-2024-08-06",
|
| 31 |
+
messages=[
|
| 32 |
+
{
|
| 33 |
+
"role": "system",
|
| 34 |
+
"content": EXTRACT_INFO_SYSTEM_MESSAGE,
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
"role": "user",
|
| 38 |
+
"content": text_content + image_content,
|
| 39 |
+
}
|
| 40 |
+
],
|
| 41 |
+
max_tokens=1000,
|
| 42 |
+
response_format=schema,
|
| 43 |
+
logprobs=True,
|
| 44 |
+
top_logprobs=2,
|
| 45 |
+
temperature=0.0,
|
| 46 |
+
# top_p=.0000000000000000000001
|
| 47 |
+
)
|
| 48 |
+
if response.choices[0].message.refusal:
|
| 49 |
+
raise RefusalError('OpenAI refused to respond to the request')
|
| 50 |
+
|
| 51 |
+
content = response.choices[0].message.content
|
| 52 |
+
parsed_data = json.loads(content)
|
| 53 |
+
model_data = schema.model_validate(parsed_data)
|
| 54 |
+
|
| 55 |
+
return model_data
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def follow_structure(json_info, schema):
|
| 59 |
+
print('Following structure via OpenAI...')
|
| 60 |
+
text_content = [
|
| 61 |
+
{
|
| 62 |
+
"type": "text",
|
| 63 |
+
"text": FOLLOW_SCHEMA_HUMAN_MESSAGE.format(json_info=json_info),
|
| 64 |
+
},
|
| 65 |
+
]
|
| 66 |
+
response = client.beta.chat.completions.parse(
|
| 67 |
+
model="gpt-4o-2024-08-06",
|
| 68 |
+
messages=[
|
| 69 |
+
{
|
| 70 |
+
"role": "system",
|
| 71 |
+
"content": FOLLOW_SCHEMA_SYSTEM_MESSAGE,
|
| 72 |
+
},
|
| 73 |
+
{
|
| 74 |
+
"role": "user",
|
| 75 |
+
"content": text_content,
|
| 76 |
+
}
|
| 77 |
+
],
|
| 78 |
+
max_tokens=1000,
|
| 79 |
+
response_format=schema,
|
| 80 |
+
logprobs=True,
|
| 81 |
+
top_logprobs=2,
|
| 82 |
+
temperature=0.0,
|
| 83 |
+
# top_p=.0000000000000000000001
|
| 84 |
+
)
|
| 85 |
+
|
| 86 |
+
if response.choices[0].message.refusal:
|
| 87 |
+
raise RefusalError('OpenAI refused to respond to the request')
|
| 88 |
+
|
| 89 |
+
content = response.choices[0].message.content
|
| 90 |
+
parsed_data = json.loads(content)
|
| 91 |
+
model_data = schema.model_validate(parsed_data)
|
| 92 |
+
|
| 93 |
+
return model_data
|
| 94 |
+
|
llm_api/utils.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import base64
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def get_image_data(image_path):
|
| 5 |
+
with open(image_path, "rb") as f:
|
| 6 |
+
image_data = base64.b64encode(f.read()).decode("utf-8")
|
| 7 |
+
return image_data
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def get_data_format(image_path):
|
| 11 |
+
image_format = image_path.split(".")[-1]
|
| 12 |
+
if image_format == "jpg":
|
| 13 |
+
image_format = "jpeg"
|
| 14 |
+
return image_format
|
read_schema_free.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from enum import Enum
|
| 2 |
+
from typing import Union
|
| 3 |
+
from pydantic import BaseModel, Field
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
# avoid using the 'import' string, including words like 'important', etc.
|
| 7 |
+
class UpperGarmentProperties(BaseModel):
|
| 8 |
+
upper_category: str
|
| 9 |
+
neck: str
|
| 10 |
+
sleeve: str
|
| 11 |
+
shoulder: str
|
| 12 |
+
waist: str
|
| 13 |
+
length: str
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class LowerGarmentProperties(BaseModel):
|
| 17 |
+
lower_category: str
|
| 18 |
+
waist: str
|
| 19 |
+
hip: str
|
| 20 |
+
rise: str
|
| 21 |
+
leg: str
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class HatProperties(BaseModel):
|
| 25 |
+
style: str
|
| 26 |
+
brim: str
|
| 27 |
+
|
| 28 |
+
class TargetAudience(BaseModel):
|
| 29 |
+
age_range: str
|
| 30 |
+
style_preference: str
|
| 31 |
+
lifestyle: str
|
| 32 |
+
|
| 33 |
+
class Closure(BaseModel):
|
| 34 |
+
color: str
|
| 35 |
+
type: str
|
| 36 |
+
location: str
|
| 37 |
+
|
| 38 |
+
class Pattern(BaseModel):
|
| 39 |
+
type: str
|
| 40 |
+
color: list[str]
|
| 41 |
+
|
| 42 |
+
class Garment(BaseModel): # don't rename this class
|
| 43 |
+
category: str = Field(..., description='Category of the garment')
|
| 44 |
+
gender: str
|
| 45 |
+
material: str
|
| 46 |
+
color: list[str] = Field(..., description='Color of the garment')
|
| 47 |
+
pattern: Pattern
|
| 48 |
+
style: str
|
| 49 |
+
closure: Closure
|
| 50 |
+
fit: str = Field(..., description='Should be one of slim fit, regular fit, loose fit')
|
| 51 |
+
season: list[str]
|
| 52 |
+
occasion: list[str]
|
| 53 |
+
special_occasion: list[str] = Field(..., description='List up to three special occasions, such as weddings, halloween or graduation')
|
| 54 |
+
usage: list[str]
|
| 55 |
+
pairing: list[str]
|
| 56 |
+
target_audience: list[TargetAudience]
|
| 57 |
+
properties: Union[UpperGarmentProperties, LowerGarmentProperties, HatProperties]
|
read_schema_structured.py
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from enum import Enum
|
| 2 |
+
from typing import Union
|
| 3 |
+
from pydantic import BaseModel, Field
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
# avoid using the 'import' string, including words like 'important', etc.
|
| 8 |
+
class NeckType(str, Enum):
|
| 9 |
+
ROUND = "Round neck"
|
| 10 |
+
V_NECK = "V-neck"
|
| 11 |
+
COLLAR = "Collar"
|
| 12 |
+
OFF_SHOULDER = "Off-shoulder"
|
| 13 |
+
HALTER = "Halter"
|
| 14 |
+
OTHER = "Other"
|
| 15 |
+
|
| 16 |
+
class Color(str, Enum):
|
| 17 |
+
SCARLET = "Scarlet" # A bright red color
|
| 18 |
+
AZURE = "Azure" # A bright blue color
|
| 19 |
+
EMERALD = "Emerald" # A bright green color
|
| 20 |
+
AMBER = "Amber" # A yellow-orange color
|
| 21 |
+
EBONY = "Ebony" # A dark black color
|
| 22 |
+
IVORY = "Ivory" # A creamy white color
|
| 23 |
+
FUCHSIA = "Fuchsia" # A bright pink-purple color
|
| 24 |
+
VIOLET = "Violet" # A purple color
|
| 25 |
+
TANGERINE = "Tangerine" # A bright orange color
|
| 26 |
+
CHESTNUT = "Chestnut" # A reddish-brown color
|
| 27 |
+
SLATE = "Slate" # A gray color
|
| 28 |
+
NAVY = "Navy" # A dark blue color
|
| 29 |
+
SILVER = "Silver" # A metallic gray color
|
| 30 |
+
GOLD = "Gold" # A metallic yellow color
|
| 31 |
+
BEIGE = "Beige" # A light brown color
|
| 32 |
+
MULTI = "Multicolor" # Multiple colors
|
| 33 |
+
OTHER = "Other" # Any other color
|
| 34 |
+
|
| 35 |
+
# class Color(str, Enum):
|
| 36 |
+
# RED = "Red"
|
| 37 |
+
# ORANGE = "Orange"
|
| 38 |
+
# YELLOW = "Yellow"
|
| 39 |
+
# GREEN = "Green"
|
| 40 |
+
# BLUE = "Blue"
|
| 41 |
+
# PURPLE = "Purple"
|
| 42 |
+
# PINK = "Pink"
|
| 43 |
+
# BROWN = "Brown"
|
| 44 |
+
# BLACK = "Black"
|
| 45 |
+
# WHITE = "White"
|
| 46 |
+
# GRAY = "Gray"
|
| 47 |
+
# # OTHER = "Other"
|
| 48 |
+
|
| 49 |
+
class Sleeve(str, Enum):
|
| 50 |
+
SHORT = "Short"
|
| 51 |
+
LONG = "Long"
|
| 52 |
+
SLEEVELESS = "Sleeveless"
|
| 53 |
+
OTHER = "Other"
|
| 54 |
+
|
| 55 |
+
class Shoulder(str, Enum):
|
| 56 |
+
REGULAR = "Regular"
|
| 57 |
+
DROP = "Drop"
|
| 58 |
+
PUFF = "Puff"
|
| 59 |
+
COLD_SHOULDER = "Cold shoulder"
|
| 60 |
+
OTHER = "Other"
|
| 61 |
+
|
| 62 |
+
class Waist(str, Enum):
|
| 63 |
+
REGULAR = "Regular"
|
| 64 |
+
HIGH = "High"
|
| 65 |
+
LOW = "Low"
|
| 66 |
+
OTHER = "Other"
|
| 67 |
+
|
| 68 |
+
class UpperLength(str, Enum):
|
| 69 |
+
CROPPED = "Cropped"
|
| 70 |
+
REGULAR = "Regular"
|
| 71 |
+
LONG = "Long"
|
| 72 |
+
OTHER = "Other"
|
| 73 |
+
|
| 74 |
+
class UpperGarmentSubcategory(str, Enum):
|
| 75 |
+
T_SHIRT = "T-shirt"
|
| 76 |
+
BLOUSE = "Blouse"
|
| 77 |
+
SHIRT = "Shirt"
|
| 78 |
+
SWEATER = "Sweater"
|
| 79 |
+
JACKET = "Jacket"
|
| 80 |
+
HOODIE = "Hoodie"
|
| 81 |
+
DRESS = "Dress"
|
| 82 |
+
OTHER = "Other"
|
| 83 |
+
|
| 84 |
+
class LowerGarmentCategory(str, Enum):
|
| 85 |
+
SHORTS = "Shorts"
|
| 86 |
+
PANTS = "Pants"
|
| 87 |
+
SKIRT = "Skirt"
|
| 88 |
+
JEANS = "Jeans"
|
| 89 |
+
OTHER = "Other"
|
| 90 |
+
|
| 91 |
+
class PatternType(str, Enum):
|
| 92 |
+
SOLID = "Solid"
|
| 93 |
+
STRIPED = "Striped"
|
| 94 |
+
CHECKERED = "Checkered"
|
| 95 |
+
FLORAL = "Floral"
|
| 96 |
+
POLKA_DOT = "Polka dot"
|
| 97 |
+
OTHER = "Other"
|
| 98 |
+
|
| 99 |
+
class Pattern(BaseModel):
|
| 100 |
+
type: PatternType
|
| 101 |
+
color: list[Color]
|
| 102 |
+
|
| 103 |
+
class HipSize(str, Enum):
|
| 104 |
+
REGULAR = "Regular"
|
| 105 |
+
WIDE = "Wide"
|
| 106 |
+
SKINNY = "Skinny"
|
| 107 |
+
OTHER = "Other"
|
| 108 |
+
|
| 109 |
+
class Rise(str, Enum):
|
| 110 |
+
REGULAR = "Regular"
|
| 111 |
+
HIGH = "High"
|
| 112 |
+
LOW = "Low"
|
| 113 |
+
OTHER = "Other"
|
| 114 |
+
|
| 115 |
+
class LegWidth(str, Enum):
|
| 116 |
+
REGULAR = "Regular"
|
| 117 |
+
WIDE = "Wide"
|
| 118 |
+
SKINNY = "Skinny"
|
| 119 |
+
OTHER = "Other"
|
| 120 |
+
|
| 121 |
+
class UpperGarmentProperties(BaseModel):
|
| 122 |
+
upper_category: UpperGarmentSubcategory
|
| 123 |
+
neck: NeckType
|
| 124 |
+
sleeve: Sleeve
|
| 125 |
+
shoulder: Shoulder
|
| 126 |
+
waist: Waist
|
| 127 |
+
length: UpperLength
|
| 128 |
+
|
| 129 |
+
class LowerGarmentProperties(BaseModel):
|
| 130 |
+
lower_category: LowerGarmentCategory
|
| 131 |
+
waist: Waist
|
| 132 |
+
hip: HipSize
|
| 133 |
+
rise: Rise
|
| 134 |
+
leg: LegWidth
|
| 135 |
+
|
| 136 |
+
class HatStyle(str, Enum):
|
| 137 |
+
BEANIE = "Beanie"
|
| 138 |
+
BERET = "Beret"
|
| 139 |
+
BUCKET = "Bucket"
|
| 140 |
+
CAP = "Cap"
|
| 141 |
+
FEDORA = "Fedora"
|
| 142 |
+
VISOR = "Visor"
|
| 143 |
+
OTHER = "Other"
|
| 144 |
+
|
| 145 |
+
class Brim(str, Enum):
|
| 146 |
+
NONE = "None"
|
| 147 |
+
SHORT = "Short"
|
| 148 |
+
MEDIUM = "Medium"
|
| 149 |
+
LONG = "Long"
|
| 150 |
+
OTHER = "Other"
|
| 151 |
+
|
| 152 |
+
class HatProperties(BaseModel):
|
| 153 |
+
style: HatStyle
|
| 154 |
+
brim: Brim
|
| 155 |
+
|
| 156 |
+
class Category(str, Enum):
|
| 157 |
+
UPPER_GARMENT = "Upper garment"
|
| 158 |
+
LOWER_GARMENT = "Lower garment"
|
| 159 |
+
HAT = "Hat"
|
| 160 |
+
OTHER = "Other"
|
| 161 |
+
|
| 162 |
+
class Gender(str, Enum):
|
| 163 |
+
MALE = "Male"
|
| 164 |
+
FEMALE = "Female"
|
| 165 |
+
UNISEX = "Unisex"
|
| 166 |
+
OTHER = "Other"
|
| 167 |
+
|
| 168 |
+
class Material(str, Enum):
|
| 169 |
+
COTTON = "Cotton"
|
| 170 |
+
POLYESTER = "Polyester"
|
| 171 |
+
WOOL = "Wool"
|
| 172 |
+
SILK = "Silk"
|
| 173 |
+
LINEN = "Linen"
|
| 174 |
+
LEATHER = "Leather"
|
| 175 |
+
DENIM = "Denim"
|
| 176 |
+
OTHER = "Other"
|
| 177 |
+
|
| 178 |
+
class TargetAudienceAgeRange(str, Enum):
|
| 179 |
+
KIDS = "Kids"
|
| 180 |
+
TEENS = "Teens"
|
| 181 |
+
ADULTS = "Adults"
|
| 182 |
+
SENIORS = "Seniors"
|
| 183 |
+
OTHER = "Other"
|
| 184 |
+
|
| 185 |
+
class TargetAudienceStylePreference(str, Enum):
|
| 186 |
+
TRENDY = "Trendy"
|
| 187 |
+
CLASSIC = "Classic"
|
| 188 |
+
VINTAGE = "Vintage"
|
| 189 |
+
BOHEMIAN = "Bohemian"
|
| 190 |
+
OTHER = "Other"
|
| 191 |
+
|
| 192 |
+
class TargetAudienceLifestyle(str, Enum):
|
| 193 |
+
ACTIVE = "Active"
|
| 194 |
+
CASUAL = "Casual"
|
| 195 |
+
FORMAL = "Formal"
|
| 196 |
+
PARTY = "Party"
|
| 197 |
+
OTHER = "Other"
|
| 198 |
+
|
| 199 |
+
class TargetAudience(BaseModel):
|
| 200 |
+
age_range: TargetAudienceAgeRange
|
| 201 |
+
style_preference: TargetAudienceStylePreference
|
| 202 |
+
lifestyle: TargetAudienceLifestyle
|
| 203 |
+
|
| 204 |
+
class Style(str, Enum):
|
| 205 |
+
CASUAL = "Casual"
|
| 206 |
+
FORMAL = "Formal"
|
| 207 |
+
SPORTS = "Sports"
|
| 208 |
+
PARTY = "Party"
|
| 209 |
+
OTHER = "Other"
|
| 210 |
+
|
| 211 |
+
class ClosureType(str, Enum):
|
| 212 |
+
BUTTON = "Button"
|
| 213 |
+
ZIPPER = "Zipper"
|
| 214 |
+
LACE = "Lace"
|
| 215 |
+
HOOK = "Hook"
|
| 216 |
+
TIE = "Tie"
|
| 217 |
+
VELCRO = "Velcro"
|
| 218 |
+
BUCKLE = "Buckle"
|
| 219 |
+
NONE = "None"
|
| 220 |
+
OTHER = "Other"
|
| 221 |
+
|
| 222 |
+
class ClosureLocation(str, Enum):
|
| 223 |
+
FRONT = "Front"
|
| 224 |
+
BACK = "Back"
|
| 225 |
+
SIDE = "Side"
|
| 226 |
+
NECK = "Neck"
|
| 227 |
+
WAIST = "Waist"
|
| 228 |
+
OTHER = "Other"
|
| 229 |
+
|
| 230 |
+
class Closure(BaseModel):
|
| 231 |
+
color: Color
|
| 232 |
+
type: ClosureType
|
| 233 |
+
location: ClosureLocation
|
| 234 |
+
|
| 235 |
+
class Fit(str, Enum):
|
| 236 |
+
REGULAR = "Regular"
|
| 237 |
+
SLIM = "Slim"
|
| 238 |
+
LOOSE = "Loose"
|
| 239 |
+
OTHER = "Other"
|
| 240 |
+
|
| 241 |
+
class Season(str, Enum):
|
| 242 |
+
ALL_SEASONS = "All seasons"
|
| 243 |
+
SPRING = "Spring"
|
| 244 |
+
SUMMER = "Summer"
|
| 245 |
+
FALL = "Fall"
|
| 246 |
+
WINTER = "Winter"
|
| 247 |
+
|
| 248 |
+
class Occasion(str, Enum):
|
| 249 |
+
CASUAL = "Casual"
|
| 250 |
+
FORMAL = "Formal"
|
| 251 |
+
PARTY = "Party"
|
| 252 |
+
SPORTS = "Sports"
|
| 253 |
+
WORK = "Work"
|
| 254 |
+
OTHER = "Other"
|
| 255 |
+
|
| 256 |
+
class Usage(str, Enum):
|
| 257 |
+
DAILY = "Daily"
|
| 258 |
+
SPECIAL = "Special"
|
| 259 |
+
WORKOUT = "Workout"
|
| 260 |
+
SLEEP = "Sleep"
|
| 261 |
+
PARTY = "Party"
|
| 262 |
+
OTHER = "Other"
|
| 263 |
+
|
| 264 |
+
class Pairing(str, Enum):
|
| 265 |
+
JEANS = "Jeans"
|
| 266 |
+
SHORTS = "Shorts"
|
| 267 |
+
SKIRT = "Skirt"
|
| 268 |
+
LEGGINGS = "Leggings"
|
| 269 |
+
TROUSERS = "Trousers"
|
| 270 |
+
DRESS = "Dress"
|
| 271 |
+
CLUTCH = "Clutch"
|
| 272 |
+
HEELS = "Heels"
|
| 273 |
+
SANDALS = "Sandals"
|
| 274 |
+
JEWELRY = "Jewelry"
|
| 275 |
+
OTHER = "Other"
|
| 276 |
+
|
| 277 |
+
class SpecialOccasion(str, Enum):
|
| 278 |
+
WEDDING = "Wedding"
|
| 279 |
+
PROM = "Prom"
|
| 280 |
+
HALLOWEEN = "Halloween"
|
| 281 |
+
GRADUATION = "Graduation"
|
| 282 |
+
BIRTHDAY = "Birthday"
|
| 283 |
+
BRUNCH = "Brunch"
|
| 284 |
+
OTHER = "Other"
|
| 285 |
+
|
| 286 |
+
class Garment(BaseModel): # don't rename this class
|
| 287 |
+
category: Category
|
| 288 |
+
gender: Gender
|
| 289 |
+
material: Material
|
| 290 |
+
color: list[Color]
|
| 291 |
+
pattern: Pattern
|
| 292 |
+
style: Style
|
| 293 |
+
closure: Closure
|
| 294 |
+
fit: Fit
|
| 295 |
+
season: list[Season]
|
| 296 |
+
occasion: list[Occasion]
|
| 297 |
+
special_occasion: list[SpecialOccasion] = Field(..., description='List up to three special occasions, such as weddings, halloween or graduation')
|
| 298 |
+
usage: list[Usage]
|
| 299 |
+
pairing: list[Pairing]
|
| 300 |
+
target_audience: list[TargetAudience]
|
| 301 |
+
properties: Union[UpperGarmentProperties, LowerGarmentProperties, HatProperties]
|
schema_free.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from enum import Enum
|
| 2 |
+
from typing import Union
|
| 3 |
+
from pydantic import BaseModel, Field
|
| 4 |
+
|
| 5 |
+
#####
|
| 6 |
+
# avoid using the 'import' string, including words like 'important', etc.
|
| 7 |
+
class UpperGarmentProperties(BaseModel):
|
| 8 |
+
upper_category: str
|
| 9 |
+
neck: str
|
| 10 |
+
sleeve: str
|
| 11 |
+
shoulder: str
|
| 12 |
+
waist: str
|
| 13 |
+
length: str
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class LowerGarmentProperties(BaseModel):
|
| 17 |
+
lower_category: str
|
| 18 |
+
waist: str
|
| 19 |
+
hip: str
|
| 20 |
+
rise: str
|
| 21 |
+
leg: str
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class HatProperties(BaseModel):
|
| 25 |
+
style: str
|
| 26 |
+
brim: str
|
| 27 |
+
|
| 28 |
+
class TargetAudience(BaseModel):
|
| 29 |
+
age_range: str
|
| 30 |
+
style_preference: str
|
| 31 |
+
lifestyle: str
|
| 32 |
+
|
| 33 |
+
class Closure(BaseModel):
|
| 34 |
+
color: str
|
| 35 |
+
type: str
|
| 36 |
+
location: str
|
| 37 |
+
|
| 38 |
+
class Pattern(BaseModel):
|
| 39 |
+
type: str
|
| 40 |
+
color: list[str]
|
| 41 |
+
|
| 42 |
+
class Garment(BaseModel): # don't rename this class
|
| 43 |
+
category: str = Field(..., description='Category of the garment')
|
| 44 |
+
gender: str
|
| 45 |
+
material: str
|
| 46 |
+
color: list[str] = Field(..., description='Color of the garment')
|
| 47 |
+
pattern: Pattern
|
| 48 |
+
style: str
|
| 49 |
+
closure: Closure
|
| 50 |
+
fit: str = Field(..., description='Should be one of slim fit, regular fit, loose fit')
|
| 51 |
+
season: list[str]
|
| 52 |
+
occasion: list[str]
|
| 53 |
+
special_occasion: list[str] = Field(..., description='List up to three special occasions, such as weddings, halloween or graduation')
|
| 54 |
+
usage: list[str]
|
| 55 |
+
pairing: list[str]
|
| 56 |
+
target_audience: list[TargetAudience]
|
| 57 |
+
properties: Union[UpperGarmentProperties, LowerGarmentProperties, HatProperties]
|
schema_structured.py
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from enum import Enum
|
| 2 |
+
from typing import Union
|
| 3 |
+
from pydantic import BaseModel, Field
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
#####
|
| 7 |
+
# avoid using the 'import' string, including words like 'important', etc.
|
| 8 |
+
class NeckType(str, Enum):
|
| 9 |
+
ROUND = "Round neck"
|
| 10 |
+
V_NECK = "V-neck"
|
| 11 |
+
COLLAR = "Collar"
|
| 12 |
+
OFF_SHOULDER = "Off-shoulder"
|
| 13 |
+
HALTER = "Halter"
|
| 14 |
+
OTHER = "Other"
|
| 15 |
+
|
| 16 |
+
class Color(str, Enum):
|
| 17 |
+
SCARLET = "Scarlet" # A bright red color
|
| 18 |
+
AZURE = "Azure" # A bright blue color
|
| 19 |
+
EMERALD = "Emerald" # A bright green color
|
| 20 |
+
AMBER = "Amber" # A yellow-orange color
|
| 21 |
+
EBONY = "Ebony" # A dark black color
|
| 22 |
+
IVORY = "Ivory" # A creamy white color
|
| 23 |
+
FUCHSIA = "Fuchsia" # A bright pink-purple color
|
| 24 |
+
VIOLET = "Violet" # A purple color
|
| 25 |
+
TANGERINE = "Tangerine" # A bright orange color
|
| 26 |
+
CHESTNUT = "Chestnut" # A reddish-brown color
|
| 27 |
+
SLATE = "Slate" # A gray color
|
| 28 |
+
NAVY = "Navy" # A dark blue color
|
| 29 |
+
SILVER = "Silver" # A metallic gray color
|
| 30 |
+
GOLD = "Gold" # A metallic yellow color
|
| 31 |
+
BEIGE = "Beige" # A light brown color
|
| 32 |
+
MULTI = "Multicolor" # Multiple colors
|
| 33 |
+
OTHER = "Other" # Any other color
|
| 34 |
+
|
| 35 |
+
# class Color(str, Enum):
|
| 36 |
+
# RED = "Red"
|
| 37 |
+
# ORANGE = "Orange"
|
| 38 |
+
# YELLOW = "Yellow"
|
| 39 |
+
# GREEN = "Green"
|
| 40 |
+
# BLUE = "Blue"
|
| 41 |
+
# PURPLE = "Purple"
|
| 42 |
+
# PINK = "Pink"
|
| 43 |
+
# BROWN = "Brown"
|
| 44 |
+
# BLACK = "Black"
|
| 45 |
+
# WHITE = "White"
|
| 46 |
+
# GRAY = "Gray"
|
| 47 |
+
# # OTHER = "Other"
|
| 48 |
+
|
| 49 |
+
class Sleeve(str, Enum):
|
| 50 |
+
SHORT = "Short"
|
| 51 |
+
LONG = "Long"
|
| 52 |
+
SLEEVELESS = "Sleeveless"
|
| 53 |
+
OTHER = "Other"
|
| 54 |
+
|
| 55 |
+
class Shoulder(str, Enum):
|
| 56 |
+
REGULAR = "Regular"
|
| 57 |
+
DROP = "Drop"
|
| 58 |
+
PUFF = "Puff"
|
| 59 |
+
COLD_SHOULDER = "Cold shoulder"
|
| 60 |
+
OTHER = "Other"
|
| 61 |
+
|
| 62 |
+
class Waist(str, Enum):
|
| 63 |
+
REGULAR = "Regular"
|
| 64 |
+
HIGH = "High"
|
| 65 |
+
LOW = "Low"
|
| 66 |
+
OTHER = "Other"
|
| 67 |
+
|
| 68 |
+
class UpperLength(str, Enum):
|
| 69 |
+
CROPPED = "Cropped"
|
| 70 |
+
REGULAR = "Regular"
|
| 71 |
+
LONG = "Long"
|
| 72 |
+
OTHER = "Other"
|
| 73 |
+
|
| 74 |
+
class UpperGarmentSubcategory(str, Enum):
|
| 75 |
+
T_SHIRT = "T-shirt"
|
| 76 |
+
BLOUSE = "Blouse"
|
| 77 |
+
SHIRT = "Shirt"
|
| 78 |
+
SWEATER = "Sweater"
|
| 79 |
+
JACKET = "Jacket"
|
| 80 |
+
HOODIE = "Hoodie"
|
| 81 |
+
DRESS = "Dress"
|
| 82 |
+
OTHER = "Other"
|
| 83 |
+
|
| 84 |
+
class LowerGarmentCategory(str, Enum):
|
| 85 |
+
SHORTS = "Shorts"
|
| 86 |
+
PANTS = "Pants"
|
| 87 |
+
SKIRT = "Skirt"
|
| 88 |
+
JEANS = "Jeans"
|
| 89 |
+
OTHER = "Other"
|
| 90 |
+
|
| 91 |
+
class PatternType(str, Enum):
|
| 92 |
+
SOLID = "Solid"
|
| 93 |
+
STRIPED = "Striped"
|
| 94 |
+
CHECKERED = "Checkered"
|
| 95 |
+
FLORAL = "Floral"
|
| 96 |
+
POLKA_DOT = "Polka dot"
|
| 97 |
+
OTHER = "Other"
|
| 98 |
+
|
| 99 |
+
class Pattern(BaseModel):
|
| 100 |
+
type: PatternType
|
| 101 |
+
color: list[Color]
|
| 102 |
+
|
| 103 |
+
class HipSize(str, Enum):
|
| 104 |
+
REGULAR = "Regular"
|
| 105 |
+
WIDE = "Wide"
|
| 106 |
+
SKINNY = "Skinny"
|
| 107 |
+
OTHER = "Other"
|
| 108 |
+
|
| 109 |
+
class Rise(str, Enum):
|
| 110 |
+
REGULAR = "Regular"
|
| 111 |
+
HIGH = "High"
|
| 112 |
+
LOW = "Low"
|
| 113 |
+
OTHER = "Other"
|
| 114 |
+
|
| 115 |
+
class LegWidth(str, Enum):
|
| 116 |
+
REGULAR = "Regular"
|
| 117 |
+
WIDE = "Wide"
|
| 118 |
+
SKINNY = "Skinny"
|
| 119 |
+
OTHER = "Other"
|
| 120 |
+
|
| 121 |
+
class UpperGarmentProperties(BaseModel):
|
| 122 |
+
upper_category: UpperGarmentSubcategory
|
| 123 |
+
neck: NeckType
|
| 124 |
+
sleeve: Sleeve
|
| 125 |
+
shoulder: Shoulder
|
| 126 |
+
waist: Waist
|
| 127 |
+
length: UpperLength
|
| 128 |
+
|
| 129 |
+
class LowerGarmentProperties(BaseModel):
|
| 130 |
+
lower_category: LowerGarmentCategory
|
| 131 |
+
waist: Waist
|
| 132 |
+
hip: HipSize
|
| 133 |
+
rise: Rise
|
| 134 |
+
leg: LegWidth
|
| 135 |
+
|
| 136 |
+
class HatStyle(str, Enum):
|
| 137 |
+
BEANIE = "Beanie"
|
| 138 |
+
BERET = "Beret"
|
| 139 |
+
BUCKET = "Bucket"
|
| 140 |
+
CAP = "Cap"
|
| 141 |
+
FEDORA = "Fedora"
|
| 142 |
+
VISOR = "Visor"
|
| 143 |
+
OTHER = "Other"
|
| 144 |
+
|
| 145 |
+
class Brim(str, Enum):
|
| 146 |
+
NONE = "None"
|
| 147 |
+
SHORT = "Short"
|
| 148 |
+
MEDIUM = "Medium"
|
| 149 |
+
LONG = "Long"
|
| 150 |
+
OTHER = "Other"
|
| 151 |
+
|
| 152 |
+
class HatProperties(BaseModel):
|
| 153 |
+
style: HatStyle
|
| 154 |
+
brim: Brim
|
| 155 |
+
|
| 156 |
+
class Category(str, Enum):
|
| 157 |
+
UPPER_GARMENT = "Upper garment"
|
| 158 |
+
LOWER_GARMENT = "Lower garment"
|
| 159 |
+
HAT = "Hat"
|
| 160 |
+
OTHER = "Other"
|
| 161 |
+
|
| 162 |
+
class Gender(str, Enum):
|
| 163 |
+
MALE = "Male"
|
| 164 |
+
FEMALE = "Female"
|
| 165 |
+
UNISEX = "Unisex"
|
| 166 |
+
OTHER = "Other"
|
| 167 |
+
|
| 168 |
+
class Material(str, Enum):
|
| 169 |
+
COTTON = "Cotton"
|
| 170 |
+
POLYESTER = "Polyester"
|
| 171 |
+
WOOL = "Wool"
|
| 172 |
+
SILK = "Silk"
|
| 173 |
+
LINEN = "Linen"
|
| 174 |
+
LEATHER = "Leather"
|
| 175 |
+
DENIM = "Denim"
|
| 176 |
+
OTHER = "Other"
|
| 177 |
+
|
| 178 |
+
class TargetAudienceAgeRange(str, Enum):
|
| 179 |
+
KIDS = "Kids"
|
| 180 |
+
TEENS = "Teens"
|
| 181 |
+
ADULTS = "Adults"
|
| 182 |
+
SENIORS = "Seniors"
|
| 183 |
+
OTHER = "Other"
|
| 184 |
+
|
| 185 |
+
class TargetAudienceStylePreference(str, Enum):
|
| 186 |
+
TRENDY = "Trendy"
|
| 187 |
+
CLASSIC = "Classic"
|
| 188 |
+
VINTAGE = "Vintage"
|
| 189 |
+
BOHEMIAN = "Bohemian"
|
| 190 |
+
OTHER = "Other"
|
| 191 |
+
|
| 192 |
+
class TargetAudienceLifestyle(str, Enum):
|
| 193 |
+
ACTIVE = "Active"
|
| 194 |
+
CASUAL = "Casual"
|
| 195 |
+
FORMAL = "Formal"
|
| 196 |
+
PARTY = "Party"
|
| 197 |
+
OTHER = "Other"
|
| 198 |
+
|
| 199 |
+
class TargetAudience(BaseModel):
|
| 200 |
+
age_range: TargetAudienceAgeRange
|
| 201 |
+
style_preference: TargetAudienceStylePreference
|
| 202 |
+
lifestyle: TargetAudienceLifestyle
|
| 203 |
+
|
| 204 |
+
class Style(str, Enum):
|
| 205 |
+
CASUAL = "Casual"
|
| 206 |
+
FORMAL = "Formal"
|
| 207 |
+
SPORTS = "Sports"
|
| 208 |
+
PARTY = "Party"
|
| 209 |
+
OTHER = "Other"
|
| 210 |
+
|
| 211 |
+
class ClosureType(str, Enum):
|
| 212 |
+
BUTTON = "Button"
|
| 213 |
+
ZIPPER = "Zipper"
|
| 214 |
+
LACE = "Lace"
|
| 215 |
+
HOOK = "Hook"
|
| 216 |
+
TIE = "Tie"
|
| 217 |
+
VELCRO = "Velcro"
|
| 218 |
+
BUCKLE = "Buckle"
|
| 219 |
+
NONE = "None"
|
| 220 |
+
OTHER = "Other"
|
| 221 |
+
|
| 222 |
+
class ClosureLocation(str, Enum):
|
| 223 |
+
FRONT = "Front"
|
| 224 |
+
BACK = "Back"
|
| 225 |
+
SIDE = "Side"
|
| 226 |
+
NECK = "Neck"
|
| 227 |
+
WAIST = "Waist"
|
| 228 |
+
OTHER = "Other"
|
| 229 |
+
|
| 230 |
+
class Closure(BaseModel):
|
| 231 |
+
color: Color
|
| 232 |
+
type: ClosureType
|
| 233 |
+
location: ClosureLocation
|
| 234 |
+
|
| 235 |
+
class Fit(str, Enum):
|
| 236 |
+
REGULAR = "Regular"
|
| 237 |
+
SLIM = "Slim"
|
| 238 |
+
LOOSE = "Loose"
|
| 239 |
+
OTHER = "Other"
|
| 240 |
+
|
| 241 |
+
class Season(str, Enum):
|
| 242 |
+
ALL_SEASONS = "All seasons"
|
| 243 |
+
SPRING = "Spring"
|
| 244 |
+
SUMMER = "Summer"
|
| 245 |
+
FALL = "Fall"
|
| 246 |
+
WINTER = "Winter"
|
| 247 |
+
|
| 248 |
+
class Occasion(str, Enum):
|
| 249 |
+
CASUAL = "Casual"
|
| 250 |
+
FORMAL = "Formal"
|
| 251 |
+
PARTY = "Party"
|
| 252 |
+
SPORTS = "Sports"
|
| 253 |
+
WORK = "Work"
|
| 254 |
+
OTHER = "Other"
|
| 255 |
+
|
| 256 |
+
class Usage(str, Enum):
|
| 257 |
+
DAILY = "Daily"
|
| 258 |
+
SPECIAL = "Special"
|
| 259 |
+
WORKOUT = "Workout"
|
| 260 |
+
SLEEP = "Sleep"
|
| 261 |
+
PARTY = "Party"
|
| 262 |
+
OTHER = "Other"
|
| 263 |
+
|
| 264 |
+
class Pairing(str, Enum):
|
| 265 |
+
JEANS = "Jeans"
|
| 266 |
+
SHORTS = "Shorts"
|
| 267 |
+
SKIRT = "Skirt"
|
| 268 |
+
LEGGINGS = "Leggings"
|
| 269 |
+
TROUSERS = "Trousers"
|
| 270 |
+
DRESS = "Dress"
|
| 271 |
+
CLUTCH = "Clutch"
|
| 272 |
+
HEELS = "Heels"
|
| 273 |
+
SANDALS = "Sandals"
|
| 274 |
+
JEWELRY = "Jewelry"
|
| 275 |
+
OTHER = "Other"
|
| 276 |
+
|
| 277 |
+
class SpecialOccasion(str, Enum):
|
| 278 |
+
WEDDING = "Wedding"
|
| 279 |
+
PROM = "Prom"
|
| 280 |
+
HALLOWEEN = "Halloween"
|
| 281 |
+
GRADUATION = "Graduation"
|
| 282 |
+
BIRTHDAY = "Birthday"
|
| 283 |
+
BRUNCH = "Brunch"
|
| 284 |
+
OTHER = "Other"
|
| 285 |
+
|
| 286 |
+
class Garment(BaseModel): # don't rename this class
|
| 287 |
+
category: Category
|
| 288 |
+
gender: Gender
|
| 289 |
+
material: Material
|
| 290 |
+
color: list[Color]
|
| 291 |
+
pattern: Pattern
|
| 292 |
+
style: Style
|
| 293 |
+
closure: Closure
|
| 294 |
+
fit: Fit
|
| 295 |
+
season: list[Season]
|
| 296 |
+
occasion: list[Occasion]
|
| 297 |
+
special_occasion: list[SpecialOccasion] = Field(..., description='List up to three special occasions, such as weddings, halloween or graduation')
|
| 298 |
+
usage: list[Usage]
|
| 299 |
+
pairing: list[Pairing]
|
| 300 |
+
target_audience: list[TargetAudience]
|
| 301 |
+
properties: Union[UpperGarmentProperties, LowerGarmentProperties, HatProperties]
|