File size: 8,651 Bytes
1761643
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
import os
import re
from urllib.parse import urlparse
import openai
import base64
import requests
import json
from dotenv import load_dotenv

products = (
    "YOUR ROLE:\n"
    "You are an image tagging expert that works for an online shopping company, "
    "your job is to meticulously tag every image given in a lot of detail with "
    "the purpose of using those tags for improved user search and a recommender algorithm\n\n"
    "UNDERSTANDING:\n"
    "First, explain your understanding of what the product is, what it might be used for "
    "and who it might appeal to. Use that understanding to put the rest of the analysis and tagging into context\n\n"
    "TAGGING:\n"
    "You need to generate 2 types of tags and output them in a JSON format in a single file. "
    "So to start with, think about what kind of tags would be useful for someone searching "
    "for an item to enhance the recommender algorithm.\n\n"
    "1) Image descriptions: generate tags between 20 and 50 tags that describe the item in a "
    "useful way. Include descriptive tags about the image, then think about the tags that would "
    "be useful for someone to find this image or for a recommender algorithm to perform well.\n\n"
    "2) Category tags: there are high level categories for products, you need to first put them into "
    "the appropriate categories they are, and then for each category, you need to list sub-categories "
    "(description given, but please come up with relevant items yourself) - there could be more than "
    "one sub-category:\n"
    "- How is it for [target audience]\n"
    "- Types [product type]\n"
    "- Style [styles]\n"
    "- Purpose [how and where the item would be used]\n\n"
    "Please respond in a JSON format, in the following structure:\n\n"
    "{\n"
    '  "product": {\n'
    '    "title": "{{ Product Title }}",\n'
    '    "description": "{{ Description of the Product\'s Features and Usage }}",\n'
    '    "appeal": "{{ Who the product might appeal to based on demographics like age, gender, interests, etc }}"\n'
    "  },\n"
    '  "description_tags": [\n'
    '    "{{ Description Tag 1 }}",\n'
    '    "{{ Description Tag 2 }}",\n'
    "    // ... additional description tags as needed, between 20 to 50 tags\n"
    "  ],\n"
    '  "category_tags": {\n'
    '    "target_audience": ["{{ Target Audience Option 1 }}", "{{ Target Audience Option 2 }}", "..."],\n'
    '    "product_type": ["{{ Product Type Option 1 }}", "{{ Product Type Option 2 }}", "..."],\n'
    '    "style": ["{{ Style Option 1 }}", "{{ Style Option 2 }}", "..."],\n'
    '    "purpose": ["{{ Purpose Option 1 }}", "{{ Purpose Option 2 }}", "..."]\n'
    "  }\n"
    "You MUST ONLY output JSON, no other text is permitted.\n"
    "}"
)


# Function to encode a single image
def encode_image(image_path):
    with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode("utf-8")


# Function to save response content
def save_response_content(garments_json, image_name, content):
    json_string = content.replace("```json", "").replace("```", "").strip()
    data = json.loads(json_string)

    file_name = image_name.split("/")[-1]
    data["product"]["image"] = f"http://gen-ai.local:8000/static/garments/{file_name}"
    data["product"]["id"] = file_name.split(".")[-2]

    # Check if file exists and has content
    try:
        with open(garments_json, "r+") as file:
            # Read current data from file
            file_data = json.load(file)
            # Append new data
            file_data.append(data)
            # Set file's current position at offset
            file.seek(0)
            # Update JSON file
            json.dump(file_data, file, indent=4)
    except (FileNotFoundError, json.JSONDecodeError):
        # Create new file with initial data
        with open(garments_json, "w") as file:
            json.dump([data], file, indent=4)


def process_image_file(image_path, garments_json):
    # Set the OpenAI API key from environment variables
    openai.api_key = os.environ["OPENAI_API_KEY"]

    base64_image = encode_image(image_path)

    # Prepare the image content for payload
    image_content = {
        "type": "image_url",
        "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"},
    }

    # The text content remains the same
    text_content = {"type": "text", "text": products}

    # Combine the text content with the image contents
    combined_contents = [text_content] + [image_content]

    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {openai.api_key}",
    }

    payload = {
        "model": "gpt-4-vision-preview",
        "messages": [{"role": "user", "content": combined_contents}],
        "max_tokens": 4000,
    }

    retry = 5
    while retry > 0:
        response = requests.post(
            "https://api.openai.com/v1/chat/completions", headers=headers, json=payload
        )
        retry -= 1

        # Check if the response was successful
        if response.status_code == 200:
            response_json = response.json()
            try:
                content = response_json["choices"][0]["message"]["content"]
                # print(content)

                # Save the 'content' part of the response along with the image name
                save_response_content(garments_json, image_path, content)

                print(f"Response content saved to '{garments_json}'.")
                break

            except KeyError:
                print("The 'choices' key is missing in the response. Full response:")
                print(response_json)
        else:
            print(
                f"Failed to get a successful response. Status code: {response.status_code}"
            )
            print("Full response:")
            print(response.text)
            if retry > 0:
                print("Retrying ...")


def merge_array(garments, products):
    ootd_server_url = os.environ.get("OOTD_SERVER_URL")
    for garment in garments:
        image = garment["product"]["image"]

        parsed_url = urlparse(garment["product"]["image"])
        garment["product"]["image"] = f"{ootd_server_url}{parsed_url.path}"
        id = re.split("[/.]", image)[-2]
        garment["product"]["id"] = id
        garment["product"]["name"] = garment["product"]["title"]

        for product in products:
            if product["id"] == id:
                garment["product"].update(product)
                break

    garments.sort(key=lambda garment: int(garment["product"]["id"]))
    return garments


def merge(garments_json_path, manifest_json_path):
    # Check if file exists and has content
    with open(manifest_json_path, "r") as manifest_file:
        products = json.load(manifest_file)
        with open(garments_json_path, "r+") as file:
            # Read current data from file
            file_data = json.load(file)
            # Append new data
            file_data = merge_array(file_data, products)
            # Set file's current position at offset
            file.seek(0)
            # Update JSON file
            json.dump(file_data, file, indent=4)

            print(
                f"Garments JSON file updated with products from '{manifest_json_path}'."
            )


def garmant_id_processed(garments_json_path, id):
    if os.path.exists(garments_json_path):
        with open(garments_json_path, "r") as file:
            garments = json.load(file)
            for garment in garments:
                product_id = re.split("[/.]", garment["product"]["image"])[-2]
                if product_id == id:
                    return True
    return False


if __name__ == "__main__":
    load_dotenv(override=False)

    garments_image_path = os.environ.get("GARMENT_IMAGES_PATH") or "../Assets/garments"
    manifest_json_path = (
        os.environ.get("GARMENT_MANIFEST_FILE_PATH")
        or "../Assets/garments/manifest.json"
    )
    garments_json_path = os.environ.get("GARMENTS_FILE_PATH") or "./data/garments.json"

    for root, dirs, files in os.walk(garments_image_path):
        for file in files:
            image_path = f"{root}/{file}"
            parts = re.split("[/.]", file)
            if parts[-1] == "jpg":
                print(f"Processing image file {image_path}...")
                id = parts[-2]
                if garmant_id_processed(garments_json_path, id):
                    print(f"Garment with id '{id}' already processed.")
                    continue

                process_image_file(image_path, garments_json_path)

    merge(garments_json_path, manifest_json_path)