import json import os import sys import time import httpx from pydantic import BaseModel, Field class AttachmentItem(BaseModel): name: str | None = None url: str mime: str | None = None class PositionItem(BaseModel): post_code: str | None = None dept: str | None = None post_name: str headcount: int | None = None education_min: str | None = None degree_required: bool | None = None majors: list[str] | None = None major_unlimited: bool | None = False age_max: int | None = None bianzhi: str | None = None salary_min: int | None = None salary_max: int | None = None work_city: str | None = None other_req: str | None = None extract_method: str = "edge_python" confidence: float | None = 1.0 class AnnouncementItem(BaseModel): url: str url_hash: str | None = None title: str kind: str = "招聘" employer: str | None = None employer_type: str | None = None published_at: str | None = None apply_start: str | None = None apply_end: str | None = None region_hint: str | None = None body_text: str | None = None attachments: list[AttachmentItem] = Field(default_factory=list) positions: list[PositionItem] = Field(default_factory=list) reconcile_positions: bool | None = None class CollectorMeta(BaseModel): name: str runtime: str | None = "python/3.12" auth_status: str = "none" duration_ms: int | None = None error_message: str | None = None class IngestPayload(BaseModel): protocol_version: str = "bangwen/v1" source_id: str batch_id: str collector: CollectorMeta | None = None items: list[AnnouncementItem] def emit_payload( payload: IngestPayload, push_url: str | None = None, token: str | None = None, ) -> None: data = payload.model_dump(mode="json") if push_url: token = token or os.environ.get("INGEST_TOKEN") headers = {} if token: headers["Authorization"] = f"Bearer {token.strip()}" max_retries = 3 last_exc = None for attempt in range(1, max_retries + 1): try: resp = httpx.post(push_url, json=data, headers=headers, timeout=30.0) resp.raise_for_status() sys.stderr.write( f"Pushed {len(payload.items)} items to {push_url}: {resp.text}\n" ) return except Exception as e: last_exc = e sys.stderr.write( f"Attempt {attempt}/{max_retries} failed to push to {push_url}: {e}\n" ) if attempt < max_retries: time.sleep(2 ** attempt) if last_exc: raise last_exc else: json_output = json.dumps(data, ensure_ascii=False) sys.stdout.write(json_output + "\n") sys.stdout.flush()