Files
2026-05-11 11:06:25 +08:00

112 lines
5.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""浏览器插件 Service
表单填写AI生成:查简历 + 岗位 + agent_config → 调 AI 生成答案。
"""
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.ai.browser_plug.form_filler import generate_form_answer
from app.models.job import Job
from app.models.job_agent_config import JobAgentConfig
from app.services import customize_resume_store
class BrowserPlugService:
def __init__(self, session: AsyncSession):
self.session = session
async def form_fill_answer(self, user_id: int, job_id: int, label: str, reference: str | None, field_type: str) -> str:
"""生成表单字段的填写内容"""
# 1. 获取简历数据(有定制简历用定制,没有自动走默认)
resume_data = await customize_resume_store.get(user_id, job_id)
resume_text = self._serialize_resume(resume_data)
# 2. 获取岗位信息
job_text = await self._get_job_text(job_id)
# 3. 获取 agent_config
agent_config_text = await self._get_agent_config_text(user_id)
# 4. 调 AI 生成
return await generate_form_answer(resume_text, job_text, agent_config_text, label, reference, field_type)
async def _get_job_text(self, job_id: int) -> str:
"""获取岗位信息文本"""
if job_id == 0:
return "未指定岗位"
result = await self.session.execute(select(Job).where(Job.id == job_id))
job = result.scalar_one_or_none()
if not job:
return "未指定岗位"
parts = []
if job.title:
parts.append(f"岗位名称:{job.title}")
if job.description:
parts.append(f"岗位描述:{job.description}")
if job.requirement:
parts.append(f"岗位要求:{job.requirement}")
return "\n".join(parts) if parts else "未指定岗位"
async def _get_agent_config_text(self, user_id: int) -> str:
"""获取 agent_config 预设答案文本"""
result = await self.session.execute(
select(JobAgentConfig).where(JobAgentConfig.user_id == user_id))
config = result.scalar_one_or_none()
if not config:
return "无预设配置"
parts = []
if config.accept_dept_transfer:
parts.append(f"是否接受部门调剂:{config.accept_dept_transfer}")
if config.accept_location_transfer:
parts.append(f"是否接受地点调剂:{config.accept_location_transfer}")
if config.interview_type:
parts.append(f"可参加面试方式:{''.join(config.interview_type)}")
if config.languages:
lang_strs = [f"{l.get('language', '')}({l.get('proficiency', '')})" for l in config.languages]
parts.append(f"语言能力:{''.join(lang_strs)}")
if config.available_date:
parts.append(f"预计到岗时间:{config.available_date}")
if config.intern_days_per_week:
parts.append(f"每周实习天数:{config.intern_days_per_week}")
if config.intern_duration:
parts.append(f"预计实习时长:{config.intern_duration}")
return "\n".join(parts) if parts else "无预设配置"
@staticmethod
def _serialize_resume(data: dict) -> str:
"""将简历 dict 序列化为文本"""
if not data:
return "暂无简历信息"
parts = []
resume = data.get("resume", {})
if resume.get("name"):
parts.append(f"姓名:{resume['name']}")
if resume.get("email"):
parts.append(f"邮箱:{resume['email']}")
if resume.get("mobileNumber"):
parts.append(f"手机:{resume['mobileNumber']}")
if resume.get("city"):
parts.append(f"城市:{resume['city']}")
if resume.get("skills"):
parts.append(f"技能:{''.join(resume['skills'])}")
if resume.get("certificates"):
parts.append(f"证书:{''.join(resume['certificates'])}")
if resume.get("summary"):
parts.append(f"个人概述:{resume['summary']}")
for section, title in [("education", "教育经历"), ("work", "工作经历"), ("internship", "实习经历"), ("project", "项目经历"), ("competition", "竞赛经历")]:
items = data.get(section, [])
if items:
parts.append(f"{title}")
for item in items:
if section == "education":
parts.append(f" - {item.get('school', '')} {item.get('major', '')} {item.get('degree', '')}")
elif section in ("work", "internship"):
parts.append(f" - {item.get('companyName', '')} {item.get('position', '')}")
elif section == "project":
parts.append(f" - {item.get('projectName', '')} {item.get('role', '')}")
elif section == "competition":
parts.append(f" - {item.get('competitionName', '')} {item.get('award', '')}")
return "\n".join(parts) if parts else "暂无简历信息"