Skip to main content
Glama
content_generator.py20.6 kB
""" AI内容生成器 使用Claude/OpenAI生成个性化求职信和其他内容 """ import asyncio import logging import json from typing import Dict, Optional, List from pathlib import Path from src.utils.logger import get_logger logger = get_logger(__name__) class ContentGenerator: """AI驱动的内容生成器""" def __init__(self, ai_config: Dict): self.config = ai_config self.client = self._initialize_ai_client() def _initialize_ai_client(self): """初始化AI客户端""" try: if self.config.get('anthropic_api_key'): import anthropic return anthropic.Anthropic(api_key=self.config['anthropic_api_key']) elif self.config.get('openai_api_key'): import openai return openai.OpenAI(api_key=self.config['openai_api_key']) else: logger.warning("未配置AI API密钥,将使用模板生成") return None except ImportError as e: logger.error(f"AI库导入失败: {e}") return None async def generate_cover_letter( self, job_description: str, company_name: str, position_title: str, resume_summary: str = "", template_type: str = "generic" ) -> str: """生成个性化求职信 Args: job_description: 职位描述 company_name: 公司名称 position_title: 职位标题 resume_summary: 简历摘要 template_type: 模板类型 Returns: 生成的求职信 """ try: if self.client: return await self._generate_ai_cover_letter( job_description, company_name, position_title, resume_summary ) else: return await self._generate_template_cover_letter( job_description, company_name, position_title, resume_summary, template_type ) except Exception as e: logger.error(f"生成求职信失败: {e}") return await self._generate_fallback_cover_letter(company_name, position_title) async def _generate_ai_cover_letter( self, job_description: str, company_name: str, position_title: str, resume_summary: str ) -> str: """使用AI生成求职信""" try: prompt = self._build_cover_letter_prompt( job_description, company_name, position_title, resume_summary ) if 'anthropic' in str(type(self.client)): # Claude API message = self.client.messages.create( model=self.config.get('default_model', 'claude-3-sonnet-20240229'), max_tokens=self.config.get('max_tokens', 1000), temperature=self.config.get('temperature', 0.7), messages=[{"role": "user", "content": prompt}] ) return message.content[0].text elif 'openai' in str(type(self.client)): # OpenAI API response = self.client.chat.completions.create( model=self.config.get('default_model', 'gpt-3.5-turbo'), max_tokens=self.config.get('max_tokens', 1000), temperature=self.config.get('temperature', 0.7), messages=[{"role": "user", "content": prompt}] ) return response.choices[0].message.content else: raise Exception("未知的AI客户端类型") except Exception as e: logger.error(f"AI生成求职信失败: {e}") raise def _build_cover_letter_prompt( self, job_description: str, company_name: str, position_title: str, resume_summary: str ) -> str: """构建求职信生成提示""" prompt = f""" 作为一名专业的求职顾问,请为以下职位生成一份个性化的求职信: **职位信息:** - 公司: {company_name} - 职位: {position_title} - 职位描述: {job_description[:1500]}... **候选人信息:** {resume_summary if resume_summary else "请根据职位要求突出相关技能和经验"} **要求:** 1. 求职信长度控制在300-500字 2. 突出与职位要求最匹配的技能和经验 3. 体现对公司和行业的了解 4. 语气专业但不失热情 5. 包含具体的价值主张 6. 避免过于模板化的表达 **格式:** - 使用正式的商务信函格式 - 开头:"Dear Hiring Manager" 或 "Dear {company_name} Team" - 结尾:专业的结束语和签名 请生成求职信内容: """ return prompt async def _generate_template_cover_letter( self, job_description: str, company_name: str, position_title: str, resume_summary: str, template_type: str ) -> str: """使用模板生成求职信""" try: # 加载模板 templates = await self._load_cover_letter_templates() if template_type not in templates: template_type = "generic" template_data = templates[template_type] template = template_data["template"] # 提取关键信息 key_skills = self._extract_key_skills(job_description) company_strengths = self._extract_company_info(job_description) # 填充模板变量 variables = { "company": company_name, "position": position_title, "field": self._infer_field(position_title), "key_skills": ", ".join(key_skills[:3]), "relevant_skills": ", ".join(key_skills[:5]), "experience_paragraph": self._generate_experience_paragraph(resume_summary, key_skills), "company_strength": company_strengths[0] if company_strengths else "innovative approach", "candidate_name": "[Your Name]" } # 应用变量替换 cover_letter = template for key, value in variables.items(): cover_letter = cover_letter.replace(f"{{{key}}}", str(value)) return cover_letter except Exception as e: logger.error(f"模板生成求职信失败: {e}") return await self._generate_fallback_cover_letter(company_name, position_title) async def _load_cover_letter_templates(self) -> Dict: """加载求职信模板""" try: templates_path = Path("templates/cover_letter_templates.json") if templates_path.exists(): with open(templates_path, 'r', encoding='utf-8') as f: return json.load(f) except Exception as e: logger.warning(f"加载模板失败: {e}") # 返回默认模板 return { "generic": { "template": """Dear Hiring Manager, I am writing to express my strong interest in the {position} position at {company}. With my background in {field} and expertise in {key_skills}, I am confident I would be a valuable addition to your team. {experience_paragraph} I am particularly drawn to {company}'s {company_strength} and would be excited to contribute my skills in {relevant_skills} to help drive your continued success. Thank you for your consideration. I look forward to the opportunity to discuss how my experience and enthusiasm can benefit your team. Best regards, {candidate_name}""" } } def _extract_key_skills(self, job_description: str) -> List[str]: """从职位描述中提取关键技能""" # 常见技能关键词 skill_keywords = [ 'Python', 'JavaScript', 'Java', 'React', 'Node.js', 'SQL', 'AWS', 'Docker', 'Kubernetes', 'Machine Learning', 'Data Analysis', 'Project Management', 'Agile', 'Scrum', 'Git', 'API', 'REST', 'Microservices', 'Cloud', 'DevOps', 'CI/CD', 'Testing' ] found_skills = [] job_desc_lower = job_description.lower() for skill in skill_keywords: if skill.lower() in job_desc_lower: found_skills.append(skill) return found_skills[:10] # 返回前10个技能 def _extract_company_info(self, job_description: str) -> List[str]: """提取公司特色信息""" company_keywords = [ "innovative", "leading", "growth", "cutting-edge", "industry leader", "market leader", "technology", "collaborative", "dynamic", "fast-paced" ] found_info = [] job_desc_lower = job_description.lower() for keyword in company_keywords: if keyword in job_desc_lower: found_info.append(keyword) return found_info if found_info else ["innovative approach"] def _infer_field(self, position_title: str) -> str: """根据职位标题推断领域""" title_lower = position_title.lower() field_mapping = { 'software': 'software development', 'developer': 'software development', 'engineer': 'engineering', 'data': 'data science', 'analyst': 'data analysis', 'scientist': 'data science', 'manager': 'management', 'designer': 'design', 'marketing': 'marketing', 'sales': 'sales', 'product': 'product management' } for keyword, field in field_mapping.items(): if keyword in title_lower: return field return "technology" def _generate_experience_paragraph(self, resume_summary: str, key_skills: List[str]) -> str: """生成经验段落""" if resume_summary: return f"Based on my background in {resume_summary[:200]}{'...' if len(resume_summary) > 200 else ''}" if key_skills: return f"My experience with {', '.join(key_skills[:3])} has prepared me to tackle complex challenges and deliver high-quality solutions." return "My professional experience has equipped me with a strong foundation in problem-solving and collaborative teamwork." async def _generate_fallback_cover_letter(self, company_name: str, position_title: str) -> str: """生成后备求职信""" return f"""Dear Hiring Manager, I am writing to express my strong interest in the {position_title} position at {company_name}. With my professional background and technical skills, I am confident that I would be a valuable addition to your team. I am particularly excited about the opportunity to contribute to {company_name}'s continued success and growth. My experience has taught me the importance of continuous learning, collaboration, and delivering high-quality results. I am eager to bring these qualities to your organization and help drive meaningful impact. Thank you for considering my application. I look forward to the opportunity to discuss how my skills and enthusiasm can benefit your team. Best regards, [Your Name]""" async def generate_email_subject(self, position_title: str, company_name: str) -> str: """生成邮件主题""" subjects = [ f"Application for {position_title} - [Your Name]", f"Interest in {position_title} Position at {company_name}", f"{position_title} Application - Experienced Professional", f"Enthusiastic {position_title} Candidate - [Your Name]" ] return subjects[0] # 返回第一个作为默认 async def optimize_for_platform(self, content: str, platform: str) -> str: """针对平台优化内容""" if platform.lower() == 'linkedin': # LinkedIn字符限制优化 if len(content) > 2000: # 截取并添加省略 content = content[:1950] + "...\n\nI would welcome the opportunity to discuss my qualifications further.\n\nBest regards,\n[Your Name]" elif platform.lower() == 'seek': # SEEK平台优化 - 更多空间,可以更详细 if len(content) < 300: # 如果内容太短,添加更多细节 content = content.replace( "Thank you for considering my application.", "I am excited about the possibility of joining your team and contributing to your organization's success. Thank you for considering my application." ) return content async def optimize_keywords(self, content: str, job_posting: str, content_type: str = "resume") -> str: """优化关键词以提高ATS通过率""" try: if self.ai_client: prompt = f""" Please optimize the following {content_type} content to improve ATS (Applicant Tracking System) compatibility based on this job posting. Job Posting: {job_posting} Current {content_type.title()}: {content} Instructions: 1. Identify key skills, technologies, and qualifications mentioned in the job posting 2. Naturally incorporate these keywords into the {content_type} without keyword stuffing 3. Maintain readability and professional tone 4. Ensure all added keywords are relevant and truthful 5. Return only the optimized content Optimized {content_type.title()}: """ response = await self.ai_client.messages.create( model=self.config.get('default_model', 'claude-3-sonnet-20240229'), max_tokens=self.config.get('max_tokens', 2000), temperature=self.config.get('temperature', 0.3), messages=[{"role": "user", "content": prompt}] ) optimized_content = response.content[0].text.strip() logger.info(f"关键词优化完成 - {content_type}") return optimized_content else: # 简单的关键词优化逻辑 return await self._basic_keyword_optimization(content, job_posting, content_type) except Exception as e: logger.error(f"关键词优化失败: {e}") return content async def _basic_keyword_optimization(self, content: str, job_posting: str, content_type: str) -> str: """基础关键词优化(无AI时的备选方案)""" try: # 提取职位要求中的关键词 import re # 常见技能关键词 tech_keywords = re.findall(r'\b(?:Python|Java|JavaScript|React|SQL|AWS|Docker|Kubernetes|Git|Agile|Scrum|Machine Learning|AI|Data Science|API|REST|GraphQL|MongoDB|PostgreSQL|Redis|Linux|CI/CD|DevOps)\b', job_posting, re.IGNORECASE) # 软技能关键词 soft_keywords = re.findall(r'\b(?:leadership|communication|teamwork|problem-solving|analytical|creative|detail-oriented|self-motivated|adaptable|collaborative)\b', job_posting, re.IGNORECASE) # 去重并转换为小写 all_keywords = list(set([kw.lower() for kw in tech_keywords + soft_keywords])) # 在内容中查找可以自然插入关键词的位置 optimized_content = content # 简单的关键词插入逻辑 if content_type == "resume": # 在技能部分添加关键词 if "Skills" in content or "技能" in content: for keyword in all_keywords[:5]: # 限制数量 if keyword.lower() not in content.lower(): optimized_content = optimized_content.replace( "Skills:", f"Skills: {keyword.title()}, " ) return optimized_content except Exception as e: logger.error(f"基础关键词优化失败: {e}") return content async def generate_question_answers(self, questions: List[str], job_context: str = "", user_profile: str = "") -> List[str]: """生成申请问题的智能回答""" try: answers = [] for question in questions: if self.ai_client: prompt = f""" Please provide a professional and appropriate answer to this job application question. Job Context: {job_context} User Profile: {user_profile} Question: {question} Guidelines: 1. Keep answers concise but informative 2. Be honest and professional 3. Relate to the job context when possible 4. Avoid generic responses 5. Maximum 2-3 sentences for most questions Answer: """ response = await self.ai_client.messages.create( model=self.config.get('default_model', 'claude-3-sonnet-20240229'), max_tokens=500, temperature=0.7, messages=[{"role": "user", "content": prompt}] ) answer = response.content[0].text.strip() answers.append(answer) else: # 使用模板回答 answer = await self._get_template_answer(question) answers.append(answer) logger.info(f"生成问题回答: {len(answers)} 个") return answers except Exception as e: logger.error(f"生成问题回答失败: {e}") return ["I am excited about this opportunity and believe my skills align well with your requirements." for _ in questions] async def _get_template_answer(self, question: str) -> str: """获取模板化回答""" question_lower = question.lower() # 常见问题模板 if any(keyword in question_lower for keyword in ['salary', 'compensation', 'pay']): return "I am open to discussing competitive compensation that reflects the market rate and my experience level." elif any(keyword in question_lower for keyword in ['start', 'available', 'notice']): return "I am available to start within 2-4 weeks, allowing for proper transition of my current responsibilities." elif any(keyword in question_lower for keyword in ['why', 'interested', 'motivate']): return "I am interested in this role because it aligns with my career goals and offers opportunities to apply my skills in a meaningful way." elif any(keyword in question_lower for keyword in ['experience', 'years']): return "I have relevant experience that directly applies to this position and am excited to contribute to your team." elif any(keyword in question_lower for keyword in ['relocate', 'move', 'location']): return "I am open to discussing relocation options and am flexible regarding location for the right opportunity." else: return "Yes, I believe my background and enthusiasm make me well-suited for this position." if __name__ == "__main__": async def test_content_generator(): """测试内容生成器""" config = { 'anthropic_api_key': '', # 需要实际的API密钥 'default_model': 'claude-3-sonnet-20240229', 'max_tokens': 1000, 'temperature': 0.7 } generator = ContentGenerator(config) job_desc = """ We are looking for a Senior Python Developer to join our team. Requirements: 5+ years Python experience, Django, REST APIs, AWS, Docker. You will work on building scalable web applications and APIs. """ cover_letter = await generator.generate_cover_letter( job_description=job_desc, company_name="TechCorp Inc", position_title="Senior Python Developer", resume_summary="Experienced Python developer with 6 years in web development, Django expert, AWS certified" ) print("Generated Cover Letter:") print(cover_letter) asyncio.run(test_content_generator())

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/guangliangyang/mcp4Interview'

If you have feedback or need assistance with the MCP directory API, please join our Discord server