|
@@ -0,0 +1,273 @@
|
|
|
+import io
|
|
|
+import base64
|
|
|
+import requests
|
|
|
+import time
|
|
|
+import os
|
|
|
+import tos
|
|
|
+from PIL import Image
|
|
|
+from tos import HttpMethodType
|
|
|
+from volcenginesdkarkruntime import Ark
|
|
|
+import uuid
|
|
|
+from utils.conf import *
|
|
|
+import json
|
|
|
+# 豆包的处理
|
|
|
+def get_intent(user_prompt):
|
|
|
+ sy_prompt="你是一个文案总结高手,请对用户输入的文案进行简化,并返回结果,不要对内容进行拓展"
|
|
|
+ prompt1=f"""请对下面的英文进行缩短简化,简化后的英文字符数量必须在150-200之间(包括标点符号,请记住不是单词数量,是每个字符数)。请直接返回结果,不要输出其他内容。内容如下:{user_prompt}"""
|
|
|
+ completion = client.chat.completions.create(
|
|
|
+ messages = [
|
|
|
+ {"role": "system", "content": sy_prompt},
|
|
|
+ {"role": "user", "content": prompt1},
|
|
|
+ ],
|
|
|
+ model="ep-20241018084532-cgm84",
|
|
|
+ )
|
|
|
+
|
|
|
+ return completion.choices[0].message.content
|
|
|
+
|
|
|
+def search_json_files(filename):
|
|
|
+ directory = "./database/meta"
|
|
|
+ data = {}
|
|
|
+ # im=Image.new('RGB', (800, 800), 'white')
|
|
|
+ for file in os.listdir(directory):
|
|
|
+ if file.endswith('.json') and filename in file:
|
|
|
+ with open(os.path.join(directory, file), 'r') as f:
|
|
|
+ data = json.load(f)
|
|
|
+ if data =={}:
|
|
|
+ return None,"暂无数据","暂无数据","暂无数据","暂无数据","暂无数据"
|
|
|
+ return data["商品图像"], data["价格"], data["色号"], data["成分"], data["关键词"], data["商品细节"]
|
|
|
+
|
|
|
+def compress_image(input_path, output_path):
|
|
|
+ img = Image.open(input_path)
|
|
|
+ current_size = os.path.getsize(input_path)
|
|
|
+ # 粗略的估计压缩质量,也可以从常量开始,逐步减小压缩质量,直到文件大小小于目标大小
|
|
|
+ image_quality = int(float(target_size / current_size) * 100)
|
|
|
+ img.save(output_path, optimize=True, quality=int(float(target_size / current_size) * 100))
|
|
|
+ # 如果压缩后文件大小仍然大于目标大小,则继续压缩
|
|
|
+ # 压缩质量递减,直到文件大小小于目标大小
|
|
|
+ while os.path.getsize(output_path) > target_size:
|
|
|
+ img = Image.open(output_path)
|
|
|
+ image_quality -= 10
|
|
|
+ if image_quality <= 0:
|
|
|
+ break
|
|
|
+ img.save(output_path, optimize=True, quality=image_quality)
|
|
|
+ return image_quality
|
|
|
+
|
|
|
+def upload_tos(filename, tos_bucket_name, tos_object_key):
|
|
|
+
|
|
|
+ tos_client, inner_tos_client = get_tos_client()
|
|
|
+ try:
|
|
|
+ # 将本地文件上传到目标桶中, filename为本地压缩后图片的完整路径
|
|
|
+ tos_client.put_object_from_file(tos_bucket_name, tos_object_key, filename)
|
|
|
+ # 获取上传后预签名的 url
|
|
|
+ return inner_tos_client.pre_signed_url(HttpMethodType.Http_Method_Get, tos_bucket_name, tos_object_key)
|
|
|
+ except Exception as e:
|
|
|
+ if isinstance(e, tos.exceptions.TosClientError):
|
|
|
+ # 操作失败,捕获客户端异常,一般情况为非法请求参数或网络异常
|
|
|
+ print('fail with client error, message:{}, cause: {}'.format(e.message, e.cause))
|
|
|
+ elif isinstance(e, tos.exceptions.TosServerError):
|
|
|
+ # 操作失败,捕获服务端异常,可从返回信息中获取详细错误信息
|
|
|
+ print('fail with server error, code: {}'.format(e.code))
|
|
|
+ # request id 可定位具体问题,强烈建议日志中保存
|
|
|
+ print('error with request id: {}'.format(e.request_id))
|
|
|
+ print('error with message: {}'.format(e.message))
|
|
|
+ print('error with http code: {}'.format(e.status_code))
|
|
|
+
|
|
|
+ else:
|
|
|
+
|
|
|
+ print('fail with unknown error: {}'.format(e))
|
|
|
+
|
|
|
+ raise e
|
|
|
+# def get_system_prompt(info ):
|
|
|
+# system_prompt = """
|
|
|
+# # 任务:欧美独立站服装卖点文案创作
|
|
|
+# 作为一名在欧美独立站服装营销领域经验丰富的卖点文案专家,你需要根据我提供的图片与文本信息,精心打磨出一份极具吸引力的服装卖点文案。这份文案将直接面向欧美市场的消费者,要充分展现出服装的独特价值。文案需涵盖以下三个核心部分:
|
|
|
+# ## 一、服装描述(中文)
|
|
|
+# 用精炼的语言,在 100 字以内全方位展示服装的魅力,请只描述服装,不要出现其他品牌名字。
|
|
|
+# ### 内容构成
|
|
|
+# 1.面料阐述:若面料材质采用桑蚕丝、二醋酸、三醋酸、香云纱、羊绒、羊毛、美丽诺羊毛、可水洗 / 机洗羊毛、鹅绒、亚麻、棉、羊毛混纺、羊驼毛、马海毛、天丝等材质,优先介绍面料包含怎么样的材质,不然请优先描述细节点和特性。。
|
|
|
+# 2.细节亮点:包含口袋、弹力橡筋、头花等设计细节,这些小细节往往能体现服装的实用性与独特性。
|
|
|
+# 3.穿着特性:明确服装适用的季节、场合,以及给出搭配建议,帮助消费者构建穿着场景。
|
|
|
+# ### 创作要求
|
|
|
+# 1.引人入胜的开篇:以一句大胆、新颖甚至颠覆常规认知的话语作为开头,瞬间抓住消费者的眼球,并且里面包含衣服的款式。比如 “打破传统的大衣穿搭,这款服装给你全新体验” (尽可能创造新的开头)。
|
|
|
+# 2.突出独特与品质:深入挖掘服装的面料和设计优势,运用饱含情感的修饰词;使用生动形象的词语。
|
|
|
+# ### 示例
|
|
|
+# 绿色代表着生机与活力,这款外套是兼具实用与美观的优雅通勤气质单品。四面弹斜纹布透气性好,细腻的光泽感和适度的垂坠性更显高级。金色的双排扣设计是其显著的特点之一,复古优雅。可以搭配同色系的裤子,展现出自己的个性与魅力。
|
|
|
+# ## 二、服装描述(英文)
|
|
|
+# 这部分是中文描述的精准翻译,要求字符数(含标点)不超过 300 个。如果翻译后的内容超过 350 个字符,需要对内容进行合理简化,确保信息完整且语言简洁流畅,符合欧美消费者的阅读习惯。
|
|
|
+# ### 示例
|
|
|
+# Green symbolizes vitality and energy, making this jacket the perfect blend of practicality and elegance for daily commutes. Crafted from breathable four - way stretch twill, its fine sheen and graceful drape exude sophistication. Gold double - breasted buttons that add a touch of vintage charm. Pair it with matching trousers to showcase your unique style and charisma.
|
|
|
+# ## 三、3 个关键点(英文)
|
|
|
+# 从服装描述中精准提取三个最具代表性的卖点关键词,每个卖点的表述不超过 4 个单词,力求简洁明了,能够快速传达服装的核心优势。
|
|
|
+# ### 示例
|
|
|
+# -Beathable. -H-line fit. -Casual and work wear
|
|
|
+# ## 该衣服信息如下:{info}
|
|
|
+# ## 以下是输出样例的格式给你参考
|
|
|
+# - 样例:{{"服装描述(中文)": "作为日常通勤的完美选择,这款四面弹阔腿裤具有出色的弹性和透气性,即使在炎炎夏日也能保持凉爽舒适。弹力腰带、侧口袋和前褶等贴心细节既提升了舒适度,又增强了时尚感。搭配同款夹克,打造别致的造型。", "服装描述(英文)": "The perfect choice for daily commutes, these four-way stretch wide-leg pants offer exceptional elasticity and breathability, keeping you cool and comfortable even on hot summer days. Thoughtful details like an elastic waistband, side pockets, and front pleats enhance both comfort and style. Pair them with a matching jacket for a chic coordinated look.", "3个关键点(英文)": "-Elastic. -With elastic waistband. -With pockets"}}
|
|
|
+# ## 请严格按照标准的json格式输出结果给我,用英文的双引号而不是单引号!请直接回答结果给我,不要回答我除此之外的任何其他内容!输出不要带有其他格式(如换行加粗等)。
|
|
|
+# """
|
|
|
+# return system_prompt
|
|
|
+def get_system_prompt(info):
|
|
|
+ system_prompt = f"""
|
|
|
+ ## 你现在是一位欧美独立站服装卖点文案的专家;我现在要在独立站上写衣服的卖点,请根据我提供给你的图片和文本写出对应的卖点文案。输出的文案包括3个部分,服装描述(中文)+服装描述(英文)+3个关键点(英文)。
|
|
|
+ ## 服装描述(中文):以一句大胆的话语作为开头+服装内容的描述(主要是对衣服面料、细节点和特性的描述),其中字数要在100个字以内。
|
|
|
+ - 引人入胜的开篇:以一句大胆、新颖甚至颠覆常规认知的话语作为开头,瞬间抓住消费者的眼球,最好是形容词+品类的形式。并且句子里面一定要包含衣服的品类的词(比如连衣裙,两件套,外套,裤子,半身裙,衬衫等等)。开头不要用反问句!绝对不要包含词语:这件,这款。
|
|
|
+ - 服装内容的描述:内容包括衣服面料+细节点(包括口袋、弹力橡筋、头花等)+特性(包括适用季节、场合、搭配等)。如果面料属于桑蚕丝、二、三醋酸、香云纱、羊绒、羊毛、美丽诺羊毛、可水洗羊毛、可机洗羊毛、鹅绒、亚麻、棉、羊毛混纺、羊驼毛、马海毛、天丝,那请优先描述面料,不然请优先描述细节点和特性。描述时请描述产品的独特设计和材质,加入带有情感的修饰词。用强烈的色彩对比和生动的词语。强调功能性的同时融入时尚表达。强调设计细节的用心。描述产品如何提升穿着者的气场。
|
|
|
+ - 服装描述(中文)例子如下:
|
|
|
+ 样例:绿色代表着生机与活力,这款外套是兼具实用与美观的优雅通勤气质单品。四面弹斜纹布透气性好,细腻的光泽感和适度的垂坠性更显高级。金色的双排扣设计是其显著的特点之一,复古优雅。可以搭配同色系的裤子,展现出自己的个性与魅力。
|
|
|
+ ## 服装描述(英文)是服装描述(中文)的翻译,其中字数要在300个字符以内(包括标点符号),如果翻译后文本还是超过350个字符请简化一下内容。
|
|
|
+ - 服装描述(英文)例子如下:
|
|
|
+ - 样例:Green symbolizes vitality and energy, making this jacket the perfect blend of practicality and elegance for daily commutes. Crafted from breathable four-way stretch twill, its fine sheen and graceful drape exude sophistication. Gold double-breasted buttons that add a touch of vintage charm. Pair it with matching trousers to showcase your unique style and charisma.
|
|
|
+ ## 3个关键点(英文)是从服装描述中提取三个卖点关键词,每个卖点不超过4个单词,内容尽可能简洁。
|
|
|
+ - 3个关键点(英文)例子如下:
|
|
|
+ - 样例:-Beathable. -H-line fit. -Casual and work wear
|
|
|
+ ## 该衣服信息如下:{info}
|
|
|
+ ## 以下是输出样例的格式给你参考
|
|
|
+ - 样例:{{"服装描述(中文)": "作为日常通勤的完美选择,这款四面弹阔腿裤具有出色的弹性和透气性,即使在炎炎夏日也能保持凉爽舒适。弹力腰带、侧口袋和前褶等贴心细节既提升了舒适度,又增强了时尚感。搭配同款夹克,打造别致的造型。", "服装描述(英文)": "The perfect choice for daily commutes, these four-way stretch wide-leg pants offer exceptional elasticity and breathability, keeping you cool and comfortable even on hot summer days. Thoughtful details like an elastic waistband, side pockets, and front pleats enhance both comfort and style. Pair them with a matching jacket for a chic coordinated look.", "3个关键点(英文)": "-Elastic. -With elastic waistband. -With pockets"}}
|
|
|
+ ## 请严格按照标准的json格式输出结果给我,用英文的双引号而不是单引号!请直接回答结果给我,不要回答我除此之外的任何其他内容!输出不要带有其他格式(如换行加粗等)。
|
|
|
+ """
|
|
|
+ return system_prompt
|
|
|
+def is_valid_response(response):
|
|
|
+ """
|
|
|
+ 检查响应是否是有效的JSON格式且包含所需字段
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ response_dict = json.loads(response)
|
|
|
+ required_fields = ["服装描述(中文)", "服装描述(英文)", "3个关键点(英文)"]
|
|
|
+ return all(field in response_dict for field in required_fields)
|
|
|
+ except:
|
|
|
+ return False
|
|
|
+
|
|
|
+def extract_response_values(response):
|
|
|
+ """
|
|
|
+ 从响应中提取各个字段的值
|
|
|
+ Args:
|
|
|
+ response: JSON格式的响应字符串
|
|
|
+ Returns:
|
|
|
+ tuple: (中文描述, 英文描述, 关键点)
|
|
|
+ """
|
|
|
+ try:
|
|
|
+ response_dict = json.loads(response)
|
|
|
+ cn_desc = response_dict.get("服装描述(中文)", "")
|
|
|
+ en_desc = response_dict.get("服装描述(英文)", "")
|
|
|
+ key_points = response_dict.get("3个关键点(英文)", "")
|
|
|
+ return cn_desc, en_desc, key_points
|
|
|
+ except:
|
|
|
+ return "", "", ""
|
|
|
+
|
|
|
+def doubao_request(pre_signed_url_output, info, max_retries=3):
|
|
|
+ """
|
|
|
+ 带重试机制的豆包请求
|
|
|
+ Args:
|
|
|
+ pre_signed_url_output: 预签名URL
|
|
|
+ info: 商品信息
|
|
|
+ max_retries: 最大重试次数
|
|
|
+ Returns:
|
|
|
+ tuple: (中文描述, 英文描述, 关键点)
|
|
|
+ """
|
|
|
+ info = get_system_prompt(info)
|
|
|
+ client = Ark(api_key=api_key)
|
|
|
+
|
|
|
+ for attempt in range(max_retries):
|
|
|
+ try:
|
|
|
+ t=time.time()
|
|
|
+ print(f"Attempt {attempt + 1}: Sending request...{t}")
|
|
|
+ response = client.chat.completions.create(
|
|
|
+ model="ep-20241202090505-2mncj",
|
|
|
+ messages=[{"role": "user","content": [
|
|
|
+ {"type": "text", "text": info},
|
|
|
+ {"type": "image_url", "image_url": {"url": pre_signed_url_output.signed_url}}
|
|
|
+ ],
|
|
|
+ }],
|
|
|
+ temperature=0.8,
|
|
|
+ extra_headers={"x-ark-beta-vision": "true"}
|
|
|
+ )
|
|
|
+ result = response.choices[0].message.content
|
|
|
+ print(f"Attempt {attempt + 1}: Sending request...{time.time()-t}")
|
|
|
+ if is_valid_response(result):
|
|
|
+ ch,en,key=extract_response_values(result)
|
|
|
+ if len(en)>350:
|
|
|
+ # print(f"之前 {en}")
|
|
|
+ en=get_intent(en)
|
|
|
+ # print(f"之后 {en}")
|
|
|
+ return ch,en,key
|
|
|
+
|
|
|
+ print(f"Attempt {attempt + 1}: Invalid response format, retrying...")
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ print(f"Attempt {attempt + 1} failed with error: {str(e)}")
|
|
|
+ if attempt == max_retries - 1:
|
|
|
+ raise e
|
|
|
+
|
|
|
+ raise Exception("Failed to get valid response after maximum retries")
|
|
|
+
|
|
|
+def doubao_generate(image,info):
|
|
|
+ if not os.path.exists(root_path):
|
|
|
+ os.makedirs(root_path)
|
|
|
+ file_name=f"{uuid.uuid4()}.jpg"
|
|
|
+ original_file=os.path.join(root_path,file_name)
|
|
|
+
|
|
|
+ # 添加这一行,将RGBA转换为RGB
|
|
|
+ if image.mode == 'RGBA':
|
|
|
+ image = image.convert('RGB')
|
|
|
+
|
|
|
+ image.save(original_file)
|
|
|
+ compressed_file = original_file
|
|
|
+ object_key = file_name
|
|
|
+ quality = compress_image(original_file, compressed_file)
|
|
|
+
|
|
|
+ pre_signed_url_output = upload_tos(compressed_file, bucket_name, object_key)
|
|
|
+ if pre_signed_url_output and os.path.exists(compressed_file):
|
|
|
+ os.remove(compressed_file)
|
|
|
+ return doubao_request(pre_signed_url_output,info)
|
|
|
+
|
|
|
+def generate_text(id,image=None,info="",check=True,model="doubao"):
|
|
|
+ if len(id) == 9:
|
|
|
+ id_image,id_price, id_color, id_ingredient, id_selling_point, id_details=search_json_files(id)
|
|
|
+
|
|
|
+ else:
|
|
|
+ id_image,id_price, id_color, id_ingredient, id_selling_point, id_details=None,None,None,None,None,None
|
|
|
+ # print(id_image,id_price, id_color, id_ingredient, id_selling_point, id_details)
|
|
|
+
|
|
|
+
|
|
|
+ info=id_details+info if id_details else info
|
|
|
+ if image == None and id_image != None:
|
|
|
+ image=Image.open(id_image)
|
|
|
+ if model=="doubao":
|
|
|
+ ch_sen,en_sen,key_point=doubao_generate(image,info)
|
|
|
+ return ch_sen,en_sen,key_point,id_image,id_price, id_color, id_ingredient, id_selling_point, id_details
|
|
|
+ # elif model=="openai":
|
|
|
+ # return openai_generate(image)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ from PIL import Image
|
|
|
+ img1=Image.open("/data/data/luosy/project/sku_search/temp_img/企业微信截图_17372766091671.png")
|
|
|
+
|
|
|
+ ch_sen,en_sen,key_point,id_image,id_price, id_color, id_ingredient, id_selling_point, id_details=generate_text("",img1,"""-With elastic waistband
|
|
|
+-With hairband
|
|
|
+-X-line fit
|
|
|
+1.腰部橡筋 2.袖子橡
|
|
|
+筋 3.前中绳子可调
|
|
|
+节大小""")
|
|
|
+ print(len(en_sen),end=" ")
|
|
|
+ print(ch_sen,en_sen,key_point)
|
|
|
+ ###############################
|
|
|
+ img2=Image.open("/data/data/luosy/project/sku_search/temp_img/企业微信截图_17389065463149[1](1).png")
|
|
|
+
|
|
|
+ ch_sen,en_sen,key_point,id_image,id_price, id_color, id_ingredient, id_selling_point, id_details=generate_text("",img1,"""-Washable wool
|
|
|
+-Unisex
|
|
|
+-With silver threads
|
|
|
+1.后中开衩;2.双扣可调节袖袢;3.暗门筒设计,天然果实扣;4.可水洗羊毛含银葱人字纹面料;5.里面左右两侧均有内袋,左侧最外层内袋是手机袋,防丢失""")
|
|
|
+ print(len(en_sen),end=" ")
|
|
|
+ print(ch_sen,en_sen,key_point)
|
|
|
+ ###############################
|
|
|
+ img3=Image.open("/data/data/luosy/project/sku_search/企业微信截图_17392379937637.png")
|
|
|
+
|
|
|
+ ch_sen,en_sen,key_point,id_image,id_price, id_color, id_ingredient, id_selling_point, id_details=generate_text("",img1,"""-Acetate
|
|
|
+-With pockets
|
|
|
+-Workwear
|
|
|
+1.描述二醋酸面料:2.扣子为镶钻布包扣;3.半裙后腰包橡筋;4.半裙有
|
|
|
+侧插袋;5.半裙有侧开隐形拉链,这是两件套套装""")
|
|
|
+ print(len(en_sen),end=" ")
|
|
|
+ print(ch_sen,en_sen,key_point)
|