抽象简历查询
This commit is contained in:
@@ -1,20 +1,14 @@
|
|||||||
"""求职助手 Agent 对话 Service
|
"""求职助手 Agent 对话 Service
|
||||||
|
|
||||||
主要功能:查询简历数据,调用 AI 模块完成对话。
|
主要功能:查询简历数据,调用 AI 模块完成对话。
|
||||||
依赖:UserResume + 5张子表 ORM、job_agent.chat AI 模块
|
依赖:resume_loader(简历统一查询)、job_agent.chat AI 模块
|
||||||
使用表:bg_user_resume、bg_user_resume_education/work/internship/project/competition(查询简历)
|
使用表:bg_user_resume + 5张子表(通过 resume_loader 查询)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from sqlalchemy import select
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.ai.job_agent.chat import agent_chat
|
from app.ai.job_agent.chat import agent_chat
|
||||||
from app.models.user_resume import UserResume
|
from app.services.resume_loader import ResumeDetail, load_resume_detail
|
||||||
from app.models.user_resume_education import UserResumeEducation
|
|
||||||
from app.models.user_resume_work import UserResumeWork
|
|
||||||
from app.models.user_resume_internship import UserResumeInternship
|
|
||||||
from app.models.user_resume_project import UserResumeProject
|
|
||||||
from app.models.user_resume_competition import UserResumeCompetition
|
|
||||||
|
|
||||||
|
|
||||||
class JobAgentChatService:
|
class JobAgentChatService:
|
||||||
@@ -26,31 +20,14 @@ class JobAgentChatService:
|
|||||||
history: list[dict], job_categories: list[str],
|
history: list[dict], job_categories: list[str],
|
||||||
regions: list[str], industries: list[str]) -> dict:
|
regions: list[str], industries: list[str]) -> dict:
|
||||||
"""求职助手对话:查简历 → 序列化 → 调 AI 模块"""
|
"""求职助手对话:查简历 → 序列化 → 调 AI 模块"""
|
||||||
resume = await self._get_resume(resume_id, user_id)
|
detail = await load_resume_detail(self.session, resume_id, user_id)
|
||||||
edu, work, intern, proj, comp = await self._load_sub_tables(resume_id)
|
resume_text = self._build_resume_text(detail)
|
||||||
resume_text = self._build_resume_text(resume, edu, work, intern, proj, comp)
|
|
||||||
return await agent_chat(resume_text, message, history, job_categories, regions, industries)
|
return await agent_chat(resume_text, message, history, job_categories, regions, industries)
|
||||||
|
|
||||||
async def _get_resume(self, resume_id: int, user_id: int) -> UserResume:
|
|
||||||
"""查指定简历"""
|
|
||||||
result = await self.session.execute(select(UserResume).where(UserResume.id == resume_id, UserResume.user_id == user_id))
|
|
||||||
resume = result.scalar_one_or_none()
|
|
||||||
if not resume:
|
|
||||||
raise ValueError("简历不存在")
|
|
||||||
return resume
|
|
||||||
|
|
||||||
async def _load_sub_tables(self, resume_id: int):
|
|
||||||
"""查询简历5张子表"""
|
|
||||||
edu = (await self.session.execute(select(UserResumeEducation).where(UserResumeEducation.resume_id == resume_id))).scalars().all()
|
|
||||||
work = (await self.session.execute(select(UserResumeWork).where(UserResumeWork.resume_id == resume_id))).scalars().all()
|
|
||||||
intern = (await self.session.execute(select(UserResumeInternship).where(UserResumeInternship.resume_id == resume_id))).scalars().all()
|
|
||||||
proj = (await self.session.execute(select(UserResumeProject).where(UserResumeProject.resume_id == resume_id))).scalars().all()
|
|
||||||
comp = (await self.session.execute(select(UserResumeCompetition).where(UserResumeCompetition.resume_id == resume_id))).scalars().all()
|
|
||||||
return edu, work, intern, proj, comp
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _build_resume_text(resume: UserResume, edu_list, work_list, intern_list, proj_list, comp_list) -> str:
|
def _build_resume_text(detail: ResumeDetail) -> str:
|
||||||
"""将简历数据序列化为文本供 AI 使用"""
|
"""将简历数据序列化为文本供 AI 使用"""
|
||||||
|
resume = detail.resume
|
||||||
parts = []
|
parts = []
|
||||||
if resume.name:
|
if resume.name:
|
||||||
parts.append(f"姓名:{resume.name}")
|
parts.append(f"姓名:{resume.name}")
|
||||||
@@ -62,24 +39,24 @@ class JobAgentChatService:
|
|||||||
parts.append(f"证书:{'、'.join(resume.certificates)}")
|
parts.append(f"证书:{'、'.join(resume.certificates)}")
|
||||||
if resume.summary:
|
if resume.summary:
|
||||||
parts.append(f"个人概述:{resume.summary}")
|
parts.append(f"个人概述:{resume.summary}")
|
||||||
if edu_list:
|
if detail.education:
|
||||||
parts.append("教育经历:")
|
parts.append("教育经历:")
|
||||||
for r in edu_list:
|
for r in detail.education:
|
||||||
parts.append(f" - {r.school or ''} {r.major or ''} {r.degree or ''}")
|
parts.append(f" - {r.school or ''} {r.major or ''} {r.degree or ''}")
|
||||||
if work_list:
|
if detail.work:
|
||||||
parts.append("工作经历:")
|
parts.append("工作经历:")
|
||||||
for r in work_list:
|
for r in detail.work:
|
||||||
parts.append(f" - {r.company_name or ''} {r.position or ''}")
|
parts.append(f" - {r.company_name or ''} {r.position or ''}")
|
||||||
if intern_list:
|
if detail.internship:
|
||||||
parts.append("实习经历:")
|
parts.append("实习经历:")
|
||||||
for r in intern_list:
|
for r in detail.internship:
|
||||||
parts.append(f" - {r.company_name or ''} {r.position or ''}")
|
parts.append(f" - {r.company_name or ''} {r.position or ''}")
|
||||||
if proj_list:
|
if detail.project:
|
||||||
parts.append("项目经历:")
|
parts.append("项目经历:")
|
||||||
for r in proj_list:
|
for r in detail.project:
|
||||||
parts.append(f" - {r.project_name or ''} {r.role or ''}")
|
parts.append(f" - {r.project_name or ''} {r.role or ''}")
|
||||||
if comp_list:
|
if detail.competition:
|
||||||
parts.append("竞赛经历:")
|
parts.append("竞赛经历:")
|
||||||
for r in comp_list:
|
for r in detail.competition:
|
||||||
parts.append(f" - {r.competition_name or ''} {r.award or ''}")
|
parts.append(f" - {r.competition_name or ''} {r.award or ''}")
|
||||||
return "\n".join(parts) if parts else "暂无简历信息"
|
return "\n".join(parts) if parts else "暂无简历信息"
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
"""简历统一查询模块
|
||||||
|
|
||||||
|
提供简历主表 + 5张子表的统一查询能力,返回脱离 session 的 ResumeDetail dataclass。
|
||||||
|
各 Service 统一复用,避免重复查询逻辑。
|
||||||
|
"""
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
from sqlalchemy import select, desc
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from app.models.user_resume import UserResume
|
||||||
|
from app.models.user_resume_education import UserResumeEducation
|
||||||
|
from app.models.user_resume_work import UserResumeWork
|
||||||
|
from app.models.user_resume_internship import UserResumeInternship
|
||||||
|
from app.models.user_resume_project import UserResumeProject
|
||||||
|
from app.models.user_resume_competition import UserResumeCompetition
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ResumeDetail:
|
||||||
|
"""简历完整数据,主表 + 5张子表"""
|
||||||
|
resume: UserResume
|
||||||
|
education: list[UserResumeEducation] = field(default_factory=list)
|
||||||
|
work: list[UserResumeWork] = field(default_factory=list)
|
||||||
|
internship: list[UserResumeInternship] = field(default_factory=list)
|
||||||
|
project: list[UserResumeProject] = field(default_factory=list)
|
||||||
|
competition: list[UserResumeCompetition] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
async def load_resume_detail(session: AsyncSession, resume_id: int, user_id: int) -> ResumeDetail:
|
||||||
|
"""按ID查简历主表(校验归属)+ 5张子表,返回 ResumeDetail"""
|
||||||
|
result = await session.execute(select(UserResume).where(UserResume.id == resume_id, UserResume.user_id == user_id))
|
||||||
|
resume = result.scalar_one_or_none()
|
||||||
|
if not resume:
|
||||||
|
raise ValueError("简历不存在")
|
||||||
|
edu, work, intern, proj, comp = await _load_sub_tables(session, resume_id)
|
||||||
|
return ResumeDetail(resume=resume, education=edu, work=work, internship=intern, project=proj, competition=comp)
|
||||||
|
|
||||||
|
|
||||||
|
async def load_default_resume_detail(session: AsyncSession, user_id: int) -> ResumeDetail:
|
||||||
|
"""自动选默认简历(先默认再最新)+ 5张子表,返回 ResumeDetail"""
|
||||||
|
result = await session.execute(
|
||||||
|
select(UserResume).where(UserResume.user_id == user_id, UserResume.is_default == 1)
|
||||||
|
.order_by(desc(UserResume.update_time)).limit(1))
|
||||||
|
resume = result.scalar_one_or_none()
|
||||||
|
if not resume:
|
||||||
|
result = await session.execute(
|
||||||
|
select(UserResume).where(UserResume.user_id == user_id)
|
||||||
|
.order_by(desc(UserResume.update_time)).limit(1))
|
||||||
|
resume = result.scalar_one_or_none()
|
||||||
|
if not resume:
|
||||||
|
raise ValueError("请先创建简历")
|
||||||
|
edu, work, intern, proj, comp = await _load_sub_tables(session, resume.id)
|
||||||
|
return ResumeDetail(resume=resume, education=edu, work=work, internship=intern, project=proj, competition=comp)
|
||||||
|
|
||||||
|
|
||||||
|
async def _load_sub_tables(session: AsyncSession, resume_id: int):
|
||||||
|
"""查询简历5张子表"""
|
||||||
|
edu = (await session.execute(select(UserResumeEducation).where(UserResumeEducation.resume_id == resume_id))).scalars().all()
|
||||||
|
work = (await session.execute(select(UserResumeWork).where(UserResumeWork.resume_id == resume_id))).scalars().all()
|
||||||
|
intern = (await session.execute(select(UserResumeInternship).where(UserResumeInternship.resume_id == resume_id))).scalars().all()
|
||||||
|
proj = (await session.execute(select(UserResumeProject).where(UserResumeProject.resume_id == resume_id))).scalars().all()
|
||||||
|
comp = (await session.execute(select(UserResumeCompetition).where(UserResumeCompetition.resume_id == resume_id))).scalars().all()
|
||||||
|
return edu, work, intern, proj, comp
|
||||||
@@ -11,7 +11,7 @@ import json
|
|||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
|
||||||
from sqlalchemy import select, desc
|
from sqlalchemy import select
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.ai.skill_gap_analyzer.analyzer import (
|
from app.ai.skill_gap_analyzer.analyzer import (
|
||||||
@@ -26,11 +26,7 @@ from app.schemas.skill_gap import (
|
|||||||
)
|
)
|
||||||
from app.models.job import Job
|
from app.models.job import Job
|
||||||
from app.models.user_resume import UserResume
|
from app.models.user_resume import UserResume
|
||||||
from app.models.user_resume_competition import UserResumeCompetition
|
from app.services.resume_loader import ResumeDetail, load_resume_detail, load_default_resume_detail
|
||||||
from app.models.user_resume_education import UserResumeEducation
|
|
||||||
from app.models.user_resume_internship import UserResumeInternship
|
|
||||||
from app.models.user_resume_project import UserResumeProject
|
|
||||||
from app.models.user_resume_work import UserResumeWork
|
|
||||||
|
|
||||||
# Redis 常量
|
# Redis 常量
|
||||||
CUSTOMIZE_RESUME_KEY_PREFIX = "customize:resume:"
|
CUSTOMIZE_RESUME_KEY_PREFIX = "customize:resume:"
|
||||||
@@ -63,24 +59,25 @@ def _build_paragraphs(description: list[dict] | None) -> list[Paragraph]:
|
|||||||
return [Paragraph(id=_rand_id(), text=item.get("text", "")) for item in description if isinstance(item, dict)]
|
return [Paragraph(id=_rand_id(), text=item.get("text", "")) for item in description if isinstance(item, dict)]
|
||||||
|
|
||||||
|
|
||||||
def _build_resume_json(resume: UserResume, edu_list, work_list, intern_list, proj_list, comp_list) -> str:
|
def _build_resume_json(detail: ResumeDetail) -> str:
|
||||||
"""拼装简历 JSON 字符串供 AI 使用"""
|
"""拼装简历 JSON 字符串供 AI 使用"""
|
||||||
|
resume = detail.resume
|
||||||
data = {
|
data = {
|
||||||
"skills": resume.skills or [],
|
"skills": resume.skills or [],
|
||||||
"certificates": resume.certificates or [],
|
"certificates": resume.certificates or [],
|
||||||
"summary": resume.summary or "",
|
"summary": resume.summary or "",
|
||||||
"targetPosition": resume.target_position or "",
|
"targetPosition": resume.target_position or "",
|
||||||
}
|
}
|
||||||
if edu_list:
|
if detail.education:
|
||||||
data["education"] = [{"school": r.school, "major": r.major, "degree": r.degree, "description": r.description} for r in edu_list]
|
data["education"] = [{"school": r.school, "major": r.major, "degree": r.degree, "description": r.description} for r in detail.education]
|
||||||
if work_list:
|
if detail.work:
|
||||||
data["work"] = [{"companyName": r.company_name, "position": r.position, "description": r.description} for r in work_list]
|
data["work"] = [{"companyName": r.company_name, "position": r.position, "description": r.description} for r in detail.work]
|
||||||
if intern_list:
|
if detail.internship:
|
||||||
data["internship"] = [{"companyName": r.company_name, "position": r.position, "description": r.description} for r in intern_list]
|
data["internship"] = [{"companyName": r.company_name, "position": r.position, "description": r.description} for r in detail.internship]
|
||||||
if proj_list:
|
if detail.project:
|
||||||
data["project"] = [{"companyName": r.company_name, "projectName": r.project_name, "role": r.role, "description": r.description} for r in proj_list]
|
data["project"] = [{"companyName": r.company_name, "projectName": r.project_name, "role": r.role, "description": r.description} for r in detail.project]
|
||||||
if comp_list:
|
if detail.competition:
|
||||||
data["competition"] = [{"competitionName": r.competition_name, "award": r.award, "description": r.description} for r in comp_list]
|
data["competition"] = [{"competitionName": r.competition_name, "award": r.award, "description": r.description} for r in detail.competition]
|
||||||
return json.dumps(data, ensure_ascii=False)
|
return json.dumps(data, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
@@ -94,21 +91,20 @@ class SkillGapService:
|
|||||||
async def analyze_skill_gap(self, user_id: int, job_id: int) -> dict:
|
async def analyze_skill_gap(self, user_id: int, job_id: int) -> dict:
|
||||||
"""差距分析完整流程:查简历 → 查岗位 → AI分析 → 计算匹配分"""
|
"""差距分析完整流程:查简历 → 查岗位 → AI分析 → 计算匹配分"""
|
||||||
# 1. 自动选择简历
|
# 1. 自动选择简历
|
||||||
resume = await self._pick_resume(user_id)
|
detail = await load_default_resume_detail(self.session, user_id)
|
||||||
# 2. 查岗位
|
# 2. 查岗位
|
||||||
job = await self._get_job(job_id)
|
job = await self._get_job(job_id)
|
||||||
skill_tags: list[str] = job.skill_tags or []
|
skill_tags: list[str] = job.skill_tags or []
|
||||||
# 3. skill_tags 为空 → 满分
|
# 3. skill_tags 为空 → 满分
|
||||||
if not skill_tags:
|
if not skill_tags:
|
||||||
return self._gap_result(10.0, job, resume, [])
|
return self._gap_result(10.0, job, detail.resume, [])
|
||||||
# 4. 查子表拼 AI 输入
|
# 4. 拼 AI 输入
|
||||||
edu, work, intern, proj, comp = await self._load_sub_tables(resume.id)
|
resume_json = _build_resume_json(detail)
|
||||||
resume_json = _build_resume_json(resume, edu, work, intern, proj, comp)
|
|
||||||
# 5. AI 分析
|
# 5. AI 分析
|
||||||
missing = await analyze_skill_gap(skill_tags, resume_json)
|
missing = await analyze_skill_gap(skill_tags, resume_json)
|
||||||
# 6. 计算匹配分
|
# 6. 计算匹配分
|
||||||
score = round((len(skill_tags) - len(missing)) / len(skill_tags) * 10, 1)
|
score = round((len(skill_tags) - len(missing)) / len(skill_tags) * 10, 1)
|
||||||
return self._gap_result(score, job, resume, missing)
|
return self._gap_result(score, job, detail.resume, missing)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _gap_result(score: float, job: Job, resume: UserResume, missing: list[str]) -> dict:
|
def _gap_result(score: float, job: Job, resume: UserResume, missing: list[str]) -> dict:
|
||||||
@@ -127,16 +123,15 @@ class SkillGapService:
|
|||||||
if not optimize_modules:
|
if not optimize_modules:
|
||||||
raise ValueError("请至少选择一个优化模块")
|
raise ValueError("请至少选择一个优化模块")
|
||||||
# 1. 查简历 + 岗位
|
# 1. 查简历 + 岗位
|
||||||
resume = await self._get_resume(resume_id, user_id)
|
detail = await load_resume_detail(self.session, resume_id, user_id)
|
||||||
job = await self._get_job(job_id)
|
job = await self._get_job(job_id)
|
||||||
edu_rows, work_rows, intern_rows, proj_rows, comp_rows = await self._load_sub_tables(resume.id)
|
|
||||||
# 2. 组装基础定制简历
|
# 2. 组装基础定制简历
|
||||||
cr = self._build_customize_resume(resume, edu_rows, work_rows, intern_rows, proj_rows, comp_rows)
|
cr = self._build_customize_resume(detail)
|
||||||
# 3. 并发 AI 优化
|
# 3. 并发 AI 优化
|
||||||
tasks = []
|
tasks = []
|
||||||
job_desc = f"{job.description or ''}\n{job.requirement or ''}"
|
job_desc = f"{job.description or ''}\n{job.requirement or ''}"
|
||||||
if "summary" in optimize_modules:
|
if "summary" in optimize_modules:
|
||||||
tasks.append(("summary", optimize_summary(job.title or "", add_skills, resume.summary or "")))
|
tasks.append(("summary", optimize_summary(job.title or "", add_skills, detail.resume.summary or "")))
|
||||||
if "experience" in optimize_modules:
|
if "experience" in optimize_modules:
|
||||||
for module_name, rows_json in self._experience_tasks(cr, job.title or "", job_desc):
|
for module_name, rows_json in self._experience_tasks(cr, job.title or "", job_desc):
|
||||||
tasks.append((module_name, optimize_module(job.title or "", job_desc, rows_json)))
|
tasks.append((module_name, optimize_module(job.title or "", job_desc, rows_json)))
|
||||||
@@ -371,30 +366,6 @@ class SkillGapService:
|
|||||||
|
|
||||||
# ===== 内部工具方法 =====
|
# ===== 内部工具方法 =====
|
||||||
|
|
||||||
async def _pick_resume(self, user_id: int) -> UserResume:
|
|
||||||
"""自动选择简历:先查默认,再查最新"""
|
|
||||||
result = await self.session.execute(
|
|
||||||
select(UserResume).where(UserResume.user_id == user_id, UserResume.is_default == 1)
|
|
||||||
.order_by(desc(UserResume.update_time)).limit(1))
|
|
||||||
resume = result.scalar_one_or_none()
|
|
||||||
if not resume:
|
|
||||||
result = await self.session.execute(
|
|
||||||
select(UserResume).where(UserResume.user_id == user_id)
|
|
||||||
.order_by(desc(UserResume.update_time)).limit(1))
|
|
||||||
resume = result.scalar_one_or_none()
|
|
||||||
if not resume:
|
|
||||||
raise ValueError("请先创建简历")
|
|
||||||
return resume
|
|
||||||
|
|
||||||
async def _get_resume(self, resume_id: int, user_id: int) -> UserResume:
|
|
||||||
"""查指定简历"""
|
|
||||||
result = await self.session.execute(
|
|
||||||
select(UserResume).where(UserResume.id == resume_id, UserResume.user_id == user_id))
|
|
||||||
resume = result.scalar_one_or_none()
|
|
||||||
if not resume:
|
|
||||||
raise ValueError("简历不存在")
|
|
||||||
return resume
|
|
||||||
|
|
||||||
async def _get_job(self, job_id: int) -> Job:
|
async def _get_job(self, job_id: int) -> Job:
|
||||||
"""查岗位"""
|
"""查岗位"""
|
||||||
result = await self.session.execute(select(Job).where(Job.id == job_id))
|
result = await self.session.execute(select(Job).where(Job.id == job_id))
|
||||||
@@ -403,18 +374,9 @@ class SkillGapService:
|
|||||||
raise ValueError("岗位不存在")
|
raise ValueError("岗位不存在")
|
||||||
return job
|
return job
|
||||||
|
|
||||||
async def _load_sub_tables(self, resume_id: int):
|
def _build_customize_resume(self, detail: ResumeDetail) -> CustomizeResume:
|
||||||
"""查询简历5张子表"""
|
"""从 ResumeDetail 组装 CustomizeResume"""
|
||||||
edu = (await self.session.execute(select(UserResumeEducation).where(UserResumeEducation.resume_id == resume_id))).scalars().all()
|
resume = detail.resume
|
||||||
work = (await self.session.execute(select(UserResumeWork).where(UserResumeWork.resume_id == resume_id))).scalars().all()
|
|
||||||
intern = (await self.session.execute(select(UserResumeInternship).where(UserResumeInternship.resume_id == resume_id))).scalars().all()
|
|
||||||
proj = (await self.session.execute(select(UserResumeProject).where(UserResumeProject.resume_id == resume_id))).scalars().all()
|
|
||||||
comp = (await self.session.execute(select(UserResumeCompetition).where(UserResumeCompetition.resume_id == resume_id))).scalars().all()
|
|
||||||
return edu, work, intern, proj, comp
|
|
||||||
|
|
||||||
def _build_customize_resume(self, resume: UserResume, edu_rows, work_rows,
|
|
||||||
intern_rows, proj_rows, comp_rows) -> CustomizeResume:
|
|
||||||
"""从数据库记录组装 CustomizeResume"""
|
|
||||||
profile = ResumeProfile(
|
profile = ResumeProfile(
|
||||||
avatarUrl=resume.avatar_url or "", name=resume.name or "", email=resume.email or "",
|
avatarUrl=resume.avatar_url or "", name=resume.name or "", email=resume.email or "",
|
||||||
mobileNumber=resume.mobile_number or "", city=resume.city or "",
|
mobileNumber=resume.mobile_number or "", city=resume.city or "",
|
||||||
@@ -427,19 +389,19 @@ class SkillGapService:
|
|||||||
education=[Education(id=_rand_id(), school=r.school or "", major=r.major or "",
|
education=[Education(id=_rand_id(), school=r.school or "", major=r.major or "",
|
||||||
degree=r.degree or "", studyType=r.study_type or "",
|
degree=r.degree or "", studyType=r.study_type or "",
|
||||||
startDate=r.start_date or "", endDate=r.end_date or "",
|
startDate=r.start_date or "", endDate=r.end_date or "",
|
||||||
description=_build_paragraphs(r.description)) for r in edu_rows],
|
description=_build_paragraphs(r.description)) for r in detail.education],
|
||||||
work=[Work(id=_rand_id(), companyName=r.company_name or "", position=r.position or "",
|
work=[Work(id=_rand_id(), companyName=r.company_name or "", position=r.position or "",
|
||||||
startDate=r.start_date or "", endDate=r.end_date or "",
|
startDate=r.start_date or "", endDate=r.end_date or "",
|
||||||
description=_build_paragraphs(r.description)) for r in work_rows],
|
description=_build_paragraphs(r.description)) for r in detail.work],
|
||||||
internship=[Internship(id=_rand_id(), companyName=r.company_name or "", position=r.position or "",
|
internship=[Internship(id=_rand_id(), companyName=r.company_name or "", position=r.position or "",
|
||||||
startDate=r.start_date or "", endDate=r.end_date or "",
|
startDate=r.start_date or "", endDate=r.end_date or "",
|
||||||
description=_build_paragraphs(r.description)) for r in intern_rows],
|
description=_build_paragraphs(r.description)) for r in detail.internship],
|
||||||
project=[Project(id=_rand_id(), companyName=r.company_name or "", projectName=r.project_name or "",
|
project=[Project(id=_rand_id(), companyName=r.company_name or "", projectName=r.project_name or "",
|
||||||
role=r.role or "", startDate=r.start_date or "", endDate=r.end_date or "",
|
role=r.role or "", startDate=r.start_date or "", endDate=r.end_date or "",
|
||||||
description=_build_paragraphs(r.description)) for r in proj_rows],
|
description=_build_paragraphs(r.description)) for r in detail.project],
|
||||||
competition=[Competition(id=_rand_id(), competitionName=r.competition_name or "", award=r.award or "",
|
competition=[Competition(id=_rand_id(), competitionName=r.competition_name or "", award=r.award or "",
|
||||||
awardDate=r.award_date or "",
|
awardDate=r.award_date or "",
|
||||||
description=_build_paragraphs(r.description)) for r in comp_rows],
|
description=_build_paragraphs(r.description)) for r in detail.competition],
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
Reference in New Issue
Block a user