feat 新增 process lookbooks 接口

fix
This commit is contained in:
zhouchengrong
2024-10-21 11:01:28 +08:00
parent 3417bcb2ab
commit e88ba6994a
11 changed files with 371 additions and 6 deletions

View File

@@ -0,0 +1,128 @@
import json
import os
from openai import OpenAI
from app.service.lookbooks.utils.image_utils import base64_encode_image, generate_text_id
from app.service.lookbooks.utils.openai_utils import wait_for_job_completion
OPENAI_API_KEY = "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"
OPENAI_API_BASE = "https://pangkaichen-openai-prox-98.deno.dev/v1"
client = OpenAI(
api_key=OPENAI_API_KEY,
base_url=OPENAI_API_BASE,
)
def create_image_batch_requests(
image_list,
output_path,
prompt="""You are an AI assistant specializing in fashion analysis and tagging for an advanced clothing indexing system. Your task is to analyze images of outfits and provide concise, relevant information. Please structure your response as follows:
1. Brief Summary: Start with a one-sentence summary of the overall style and vibe of the outfit.
2. Tags: Provide relevant tags in the following categories. Use multiple tags where appropriate, separated by commas.
Season: [e.g., Spring/Summer, Fall/Winter]
Style: [e.g., Minimalist, Bohemian, Streetwear, Business Casual]
Occasion: [e.g., Office, Casual, Party, Outdoor]
Colors: [List main colors used]
Materials: [e.g., Cotton, Denim, Leather, Silk]
Key Elements: [Any distinctive fashion elements]
3. Item Descriptions:
- Briefly describe each main clothing item (top, bottom, outerwear). Number and categorize each item (e.g., 1. Top: ..., 2. Bottom: ...). Keep descriptions concise but include key details about style, color, and distinctive features.
- In a single sentence, list all accessories and their overall effect on the outfit.
Ensure your tags and descriptions are accurate, relevant to current fashion trends, and useful for indexing and retrieval purposes."""
):
# 预处理 prompt移除多余的空白和换行符
prompt = ' '.join(prompt.split())
completed_id = []
if os.path.exists(os.path.join(output_path, "image_description_results.jsonl")):
with open(os.path.join(output_path, "image_description_results.jsonl"), "r") as f:
for line in f:
completed_id.append(json.loads(line)["custom_id"])
tasks = []
id2img = {}
for idx, image_filename in enumerate(image_list):
image_base64 = base64_encode_image(image_filename)
if not image_base64:
continue
current_id = generate_text_id(image_base64)
if current_id in completed_id:
continue
task = {
"custom_id": current_id,
"method": "POST",
"url": "/v1/chat/completions",
"body": {
"model": "gpt-4o",
"temperature": 1.0,
"max_tokens": 500,
"messages": [
{
"role": "system",
"content": prompt
},
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{image_base64}",
"detail": "low"
}
}
]
}
]
}
}
tasks.append(task)
id2img[current_id] = image_filename
print(f"In total {len(tasks)} images")
if tasks:
batch_file_name = os.path.join(output_path, "image_batch_requests.jsonl")
with open(batch_file_name, 'w', encoding='utf-8') as file:
for obj in tasks:
file.write(json.dumps(obj, ensure_ascii=False) + '\n')
batch_file = client.files.create(
file=open(batch_file_name, "rb"),
purpose="batch"
)
batch_job = client.batches.create(
input_file_id=batch_file.id,
endpoint="/v1/chat/completions",
completion_window="24h"
)
if wait_for_job_completion(client, batch_job.id):
output_file_id = client.batches.retrieve(batch_job.id).output_file_id
file_response = client.files.content(output_file_id)
file_content_str = file_response.read().decode('utf-8')
with open(os.path.join(output_path, "image_description_results.jsonl"), "w", encoding='utf-8') as f:
for line in file_content_str.splitlines():
if line.strip():
try:
result = json.loads(line)
image_id = result['custom_id']
caption = result['response']['body']['choices'][0]['message']['content']
output = json.dumps({
"custom_id": image_id,
"summary": caption,
"url": id2img[image_id]
})
f.write(output + '\n')
except json.JSONDecodeError as error:
print(f"Error parsing: {error} -- at line: {line}")
else:
print("Job failed")
return os.path.join(output_path, "image_description_results.jsonl")
else:
return None