from talent.plugins import extract_education, extract_experience def serialize_talent_run(row) -> dict: return { "id": str(row.id) if row.id else None, "job_post_id": str(row.job_post_id) if row.job_post_id else None, "status": row.status, "actor_id": row.actor_id, "search_input": row.search_input or {}, "max_results": row.max_results, "profiles_found": row.profiles_found, "apify_run_id": row.apify_run_id, "apify_error": row.apify_error, "started_at": row.started_at.isoformat() if row.started_at else None, "finished_at": row.finished_at.isoformat() if row.finished_at else None, "created_at": row.created_at.isoformat() if row.created_at else None, } def serialize_talent_profile(row) -> dict: # `raw` stays server-side: it is an actor-shaped blob that can be large and # is only needed for debugging/re-mapping, not for the profile cards. return { "id": str(row.id) if row.id else None, "job_post_id": str(row.job_post_id) if row.job_post_id else None, "linkedin_url": row.linkedin_url, "public_id": row.public_id, "full_name": row.full_name, "headline": row.headline, "location": row.location, "current_title": row.current_title, "current_company": row.current_company, "avatar_url": row.avatar_url, "summary": row.summary, "skills": row.skills or [], "match_score": row.match_score, "first_seen_at": row.first_seen_at.isoformat() if row.first_seen_at else None, "last_seen_at": row.last_seen_at.isoformat() if row.last_seen_at else None, } def serialize_talent_profile_detail(row) -> dict: # The card payload plus employment/education history unpacked from the raw # actor item. Detail is fetched one profile at a time, so the extra weight # never rides along with the list endpoint. data = serialize_talent_profile(row) data["experience"] = extract_experience(row.raw or {}) data["education"] = extract_education(row.raw or {}) return data