#!/usr/bin/env python3 """ AI文案生成服务集成 使用AI大模型为照片生成创意文案 支持多种文案风格和用途 支持DeepSeek和DashScope两种大模型 """ import os import json import requests from dotenv import load_dotenv # 加载环境变量 load_dotenv() class AICopywriter: """AI文案生成服务类""" def __init__(self, provider='deepseek'): """初始化AI文案生成客户端""" self.provider = provider if provider == 'deepseek': self.api_key = os.getenv('DEEPSEEK_API_KEY') if not self.api_key: raise Exception("DeepSeek API密钥未配置,请在.env文件中设置DEEPSEEK_API_KEY") self.base_url = "https://api.deepseek.com/v1/chat/completions" elif provider == 'dashscope': self.api_key = os.getenv('DASHSCOPE_API_KEY') if not self.api_key: raise Exception("DashScope API密钥未配置,请在.env文件中设置DASHSCOPE_API_KEY") else: raise Exception(f"不支持的AI提供商: {provider}") def generate_photo_caption(self, image_description, style='creative', length='medium'): """为照片生成文案""" try: if self.provider == 'deepseek': return self._generate_with_deepseek(image_description, style, length) elif self.provider == 'dashscope': return self._generate_with_dashscope(image_description, style, length) else: raise Exception(f"不支持的AI提供商: {self.provider}") except Exception as e: raise Exception(f"AI文案生成失败: {str(e)}") def _generate_with_deepseek(self, image_description, style, length): """使用DeepSeek生成文案""" try: prompt = self._build_prompt(image_description, style, length) headers = { 'Authorization': f'Bearer {self.api_key}', 'Content-Type': 'application/json' } data = { 'model': 'deepseek-chat', 'messages': [ { 'role': 'system', 'content': '你是一个专业的创意文案创作助手,擅长为照片生成各种风格的创意文案。你具有丰富的文学素养和营销知识,能够根据照片内容创作出富有创意和感染力的文案。' }, { 'role': 'user', 'content': prompt } ], 'max_tokens': 500, 'temperature': 0.8, 'top_p': 0.9 } response = requests.post(self.base_url, headers=headers, json=data) result = response.json() if 'choices' in result and len(result['choices']) > 0: caption = result['choices'][0]['message']['content'].strip() # 清理可能的格式标记 caption = caption.replace('"', '').replace('\n', ' ').strip() return caption else: # 如果API调用失败,使用备用文案生成 return self._generate_fallback_caption(image_description, style, length) except Exception as e: # API调用失败时使用备用方案 return self._generate_fallback_caption(image_description, style, length) def _generate_with_dashscope(self, image_description, style, length): """使用DashScope生成文案""" try: url = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation" headers = { 'Authorization': f'Bearer {self.api_key}', 'Content-Type': 'application/json' } # 根据风格和长度构建提示词 prompt = self._build_prompt(image_description, style, length) data = { 'model': 'qwen-turbo', 'input': { 'messages': [ { 'role': 'system', 'content': '你是一个专业的文案创作助手,擅长为照片生成各种风格的创意文案。' }, { 'role': 'user', 'content': prompt } ] }, 'parameters': { 'max_tokens': 500, 'temperature': 0.8 } } response = requests.post(url, headers=headers, json=data) result = response.json() if 'output' in result and 'text' in result['output']: return result['output']['text'] else: # 如果API调用失败,使用备用文案生成 return self._generate_fallback_caption(image_description, style, length) except Exception as e: # API调用失败时使用备用方案 return self._generate_fallback_caption(image_description, style, length) def _build_prompt(self, image_description, style, length): """构建AI提示词""" style_descriptions = { 'creative': '创意文艺风格,富有诗意和想象力', 'professional': '专业正式风格,简洁明了', 'social': '社交媒体风格,活泼有趣,适合朋友圈', 'marketing': '营销推广风格,吸引眼球,促进转化', 'simple': '简单描述风格,直接明了', 'emotional': '情感表达风格,温暖感人' } length_descriptions = { 'short': '10-20字,简洁精炼', 'medium': '30-50字,适中长度', 'long': '80-120字,详细描述' } prompt = f""" 请为以下照片内容生成{style_descriptions.get(style, '创意')}的文案,要求{length_descriptions.get(length, '适中长度')}。 照片内容描述:{image_description} 文案要求: 1. 符合{style}风格 2. 长度{length} 3. 有创意,吸引人 4. 适合社交媒体分享 请直接输出文案内容,不要添加其他说明。 """ return prompt.strip() def _generate_fallback_caption(self, image_description, style, length): """备用文案生成(当AI服务不可用时)""" # 基于照片描述的简单文案生成 keywords = image_description.lower().split() # 提取关键信息 objects = [] scenes = [] # 简单的关键词分类(实际应用中可以使用更复杂的NLP处理) object_keywords = ['人', '建筑', '天空', '树', '花', '动物', '车', '食物', '水', '山'] scene_keywords = ['户外', '室内', '自然', '城市', '夜景', '日出', '日落', '海滩', '森林'] for word in keywords: if any(obj in word for obj in object_keywords): objects.append(word) if any(scene in word for scene in scene_keywords): scenes.append(word) # 根据风格生成文案 if style == 'creative': if scenes: caption = f"在{scenes[0]}的怀抱中,时光静静流淌" elif objects: caption = f"{objects[0]}的美丽瞬间,定格永恒" else: caption = "捕捉生活中的美好,让每一刻都值得珍藏" elif style == 'social': if objects: caption = f"今天遇到的{objects[0]}太可爱了!分享给大家~" else: caption = "分享一张美照,希望大家喜欢!" elif style == 'professional': if scenes and objects: caption = f"专业拍摄:{scenes[0]}场景中的{objects[0]}特写" else: caption = "专业摄影作品展示" elif style == 'marketing': if objects: caption = f"惊艳!这个{objects[0]}你一定要看看!" else: caption = "不容错过的精彩瞬间,点击了解更多!" else: # simple or emotional if objects: caption = f"美丽的{objects[0]}照片" else: caption = "一张值得分享的照片" # 根据长度调整 if length == 'long' and len(caption) < 50: caption += "。这张照片记录了珍贵的瞬间,展现了生活的美好,值得细细品味和珍藏。" elif length == 'short' and len(caption) > 20: # 简化长文案 caption = caption[:20] + "..." return caption def generate_multiple_captions(self, image_description, count=3, style='creative'): """生成多个文案选项""" try: if self.provider == 'deepseek': return self._generate_multiple_with_deepseek(image_description, count, style) elif self.provider == 'dashscope': return self._generate_multiple_with_dashscope(image_description, count, style) else: raise Exception(f"不支持的AI提供商: {self.provider}") except Exception as e: raise Exception(f"生成多个文案失败: {str(e)}") def _generate_multiple_with_deepseek(self, image_description, count=3, style='creative'): """使用DeepSeek生成多个文案选项""" try: captions = [] # 使用不同的提示词变体生成多个文案 prompt_variants = [ f"请为'{image_description}'照片创作一个{style}风格的文案,要求新颖独特", f"基于照片内容'{image_description}',写一个{style}风格的创意文案", f"为这张'{image_description}'的照片设计一个{style}风格的吸引人文案" ] for i in range(min(count, len(prompt_variants))): prompt = prompt_variants[i] headers = { 'Authorization': f'Bearer {self.api_key}', 'Content-Type': 'application/json' } data = { 'model': 'deepseek-chat', 'messages': [ { 'role': 'system', 'content': '你是专业的创意文案专家,擅长为照片创作多种风格的文案。' }, { 'role': 'user', 'content': prompt } ], 'max_tokens': 200, 'temperature': 0.9, # 提高温度增加多样性 'top_p': 0.95 } response = requests.post(self.base_url, headers=headers, json=data) result = response.json() if 'choices' in result and len(result['choices']) > 0: caption = result['choices'][0]['message']['content'].strip() caption = caption.replace('"', '').replace('\n', ' ').strip() captions.append({ 'option': i + 1, 'caption': caption, 'style': style, 'char_count': len(caption) }) return captions except Exception as e: raise Exception(f"DeepSeek多文案生成失败: {str(e)}") def _generate_multiple_with_dashscope(self, image_description, count=3, style='creative'): """使用DashScope生成多个文案选项""" try: captions = [] # 尝试使用不同的长度和微调风格 lengths = ['short', 'medium', 'long'] for i in range(min(count, len(lengths))): caption = self.generate_photo_caption(image_description, style, lengths[i]) captions.append({ 'option': i + 1, 'caption': caption, 'length': lengths[i], 'char_count': len(caption) }) # 如果数量不足,使用不同风格补充 if len(captions) < count: additional_styles = ['social', 'professional', 'emotional'] for i, add_style in enumerate(additional_styles): if len(captions) >= count: break caption = self.generate_photo_caption(image_description, add_style, 'medium') captions.append({ 'option': len(captions) + 1, 'caption': caption, 'style': add_style, 'char_count': len(caption) }) return captions except Exception as e: raise Exception(f"DashScope多文案生成失败: {str(e)}") def analyze_photo_suitability(self, image_description): """分析照片适合的文案风格""" try: # 简单的风格适合性分析 keywords = image_description.lower() suitability = { 'creative': 0, 'professional': 0, 'social': 0, 'marketing': 0, 'emotional': 0 } # 关键词匹配(实际应用中可以使用更复杂的NLP分析) creative_words = ['美丽', '艺术', '创意', '独特', '梦幻'] professional_words = ['专业', '商业', '产品', '展示', '特写'] social_words = ['朋友', '聚会', '日常', '分享', '生活'] marketing_words = ['促销', '优惠', '新品', '限时', '推荐'] emotional_words = ['情感', '感动', '回忆', '温暖', '幸福'] for word in creative_words: if word in keywords: suitability['creative'] += 1 for word in professional_words: if word in keywords: suitability['professional'] += 1 for word in social_words: if word in keywords: suitability['social'] += 1 for word in marketing_words: if word in keywords: suitability['marketing'] += 1 for word in emotional_words: if word in keywords: suitability['emotional'] += 1 # 排序并返回推荐 recommended = sorted(suitability.items(), key=lambda x: x[1], reverse=True) return { 'suitability_scores': suitability, 'recommended_styles': [style for style, score in recommended if score > 0], 'most_suitable': recommended[0][0] if recommended[0][1] > 0 else 'creative' } except Exception as e: raise Exception(f"照片适合性分析失败: {str(e)}") def generate_photo_caption(image_description, style='creative', length='medium', provider='dashscope'): """为照片生成文案""" try: copywriter = AICopywriter(provider) return copywriter.generate_photo_caption(image_description, style, length) except Exception as e: raise Exception(f"照片文案生成失败: {str(e)}") def generate_multiple_captions(image_description, count=3, style='creative', provider='dashscope'): """生成多个文案选项""" try: copywriter = AICopywriter(provider) return copywriter.generate_multiple_captions(image_description, count, style) except Exception as e: raise Exception(f"多文案生成失败: {str(e)}") def analyze_photo_suitability(image_description, provider='dashscope'): """分析照片适合的文案风格""" try: copywriter = AICopywriter(provider) return copywriter.analyze_photo_suitability(image_description) except Exception as e: raise Exception(f"照片适合性分析失败: {str(e)}") def check_copywriter_config(provider='deepseek'): """检查AI文案生成配置是否完整""" try: if provider == 'deepseek': api_key = os.getenv('DEEPSEEK_API_KEY') if not api_key: return False, "DeepSeek API密钥未配置" # 测试连接 copywriter = AICopywriter(provider) return True, "AI文案生成配置正确(DeepSeek大模型)" elif provider == 'dashscope': api_key = os.getenv('DASHSCOPE_API_KEY') if not api_key: return False, "DashScope API密钥未配置" # 测试连接 copywriter = AICopywriter(provider) return True, "AI文案生成配置正确(DashScope)" else: return False, f"不支持的AI提供商: {provider}" except Exception as e: return False, f"AI文案生成配置错误: {str(e)}"