job-pro 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter.js +17 -0
- package/dist/alibaba.js +2 -2
- package/dist/baichuan.js +38 -123
- package/dist/bilibili.js +43 -0
- package/dist/byd.js +333 -112
- package/dist/deepseek.js +373 -25
- package/dist/galaxyuniversal.js +375 -23
- package/dist/horizonrobotics.js +52 -24
- package/dist/iflytek.js +299 -57
- package/dist/index.js +55 -50
- package/dist/megvii.js +387 -150
- package/dist/mihoyo.js +241 -67
- package/dist/moonshot.js +387 -54
- package/dist/oppo.js +212 -56
- package/dist/pdd.js +278 -129
- package/dist/sf.js +249 -36
- package/dist/stepfun.js +333 -105
- package/dist/vivo.js +291 -41
- package/dist/weibo.js +259 -88
- package/dist/zerooneai.js +40 -37
- package/package.json +2 -2
package/dist/adapter.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Canonical contract every company adapter must satisfy.
|
|
2
|
+
//
|
|
3
|
+
// Previously the dispatcher leaned on `type CompanyAdapter = typeof tencent`
|
|
4
|
+
// plus `as unknown as CompanyAdapter` casts on every entry in the ADAPTERS
|
|
5
|
+
// map. That silenced every shape mismatch — if an adapter's return value
|
|
6
|
+
// drifted, TypeScript was happy and the bug surfaced at runtime.
|
|
7
|
+
//
|
|
8
|
+
// This module defines an explicit method-signature interface so adapters
|
|
9
|
+
// can be wired with `satisfies Record<string, CompanyAdapter>` and any
|
|
10
|
+
// future drift becomes a compile error.
|
|
11
|
+
//
|
|
12
|
+
// The result types are intentionally permissive (`Promise<unknown>`-shaped):
|
|
13
|
+
// adapter-specific success payloads have rich, per-company keys (Tencent has
|
|
14
|
+
// recruitment fields Feishu doesn't, etc.) that we don't want to flatten here.
|
|
15
|
+
// The contract is "this method exists and is async"; the per-company JSON
|
|
16
|
+
// shape is documented in each adapter's source.
|
|
17
|
+
export {};
|
package/dist/alibaba.js
CHANGED
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
// bgs ← item.circleNames?.[0] ?? "" (BU / group name)
|
|
57
57
|
// work_cities ← item.workLocations.join(" / ")
|
|
58
58
|
// apply_url ← https://campus-talent.alibaba.com/campus/positionDetail?positionId=<id>
|
|
59
|
-
import { extractResumeSignals, scoreOverlap } from "./tencent.js";
|
|
60
|
-
export { extractResumeSignals, scoreOverlap };
|
|
59
|
+
import { extractResumeSignals, scoreOverlap, checkResume } from "./tencent.js";
|
|
60
|
+
export { extractResumeSignals, scoreOverlap, checkResume };
|
|
61
61
|
const API_ROOT = "https://campus-talent.alibaba.com";
|
|
62
62
|
const CAMPUS_PAGE = `${API_ROOT}/campus/position`;
|
|
63
63
|
const DETAIL_PAGE = (id) => `${API_ROOT}/campus/position/${encodeURIComponent(String(id))}`;
|
package/dist/baichuan.js
CHANGED
|
@@ -1,133 +1,48 @@
|
|
|
1
|
-
// 百川智能 (Baichuan AI)
|
|
1
|
+
// Thin client for 百川智能 (Baichuan AI) recruiting portal.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
3
|
+
// Portal: https://cq6qe6bvfr6.jobs.feishu.cn/baichuanzhaopin/
|
|
4
|
+
// Platform: Feishu Recruiting (ATSX) SaaS — same API surface as nio.ts / minimax.ts.
|
|
4
5
|
//
|
|
5
6
|
// ============================================================
|
|
6
|
-
//
|
|
7
|
+
// Discovery (2026-05):
|
|
7
8
|
//
|
|
8
|
-
// www.baichuan-ai.com/
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
9
|
+
// www.baichuan-ai.com/ → Next.js SPA with no /careers or /jobs route
|
|
10
|
+
// (the corporate site doesn't link to the portal)
|
|
11
|
+
// baichuan.jobs.feishu.cn/ → 400 (no portal configured on the obvious slug)
|
|
12
|
+
// baichuan-ai.jobs.feishu.cn/ → 404
|
|
12
13
|
//
|
|
13
|
-
// Feishu
|
|
14
|
-
//
|
|
15
|
-
// (TLS cert resolves — wildcard *.jobs.feishu.cn —
|
|
16
|
-
// but no portal is configured on the ATSX backend)
|
|
17
|
-
// baichuan-ai.jobs.feishu.cn → HTTP 404 (DNS only, no TLS/host)
|
|
18
|
-
// baichuan-inc.jobs.feishu.cn → HTTP 404
|
|
19
|
-
// baichuanai.jobs.feishu.cn → HTTP 404
|
|
14
|
+
// The real portal lives on a randomized Feishu tenant slug:
|
|
15
|
+
// cq6qe6bvfr6.jobs.feishu.cn/baichuanzhaopin/
|
|
20
16
|
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// registered at the CDN level but has no active recruiting portal behind it.
|
|
17
|
+
// Tenant: 百川智能 / "【百川智能】社会招聘官方网站-欢迎你的加入!"
|
|
18
|
+
// Channel slug: "baichuanzhaopin" (the company PATH on the tenant)
|
|
24
19
|
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
// app.mokahr.com/social-recruitment/baichuan → same error
|
|
28
|
-
// Moka orgId probes (numeric range) — all return the Moka SPA error shell;
|
|
29
|
-
// no slug "baichuan" maps to a live Moka org.
|
|
30
|
-
//
|
|
31
|
-
// Greenhouse:
|
|
32
|
-
// boards.greenhouse.io/baichuan → 404 "job board no longer active"
|
|
33
|
-
// (Greenhouse board existed historically but has been deactivated.)
|
|
34
|
-
//
|
|
35
|
-
// Lever, BOSS Zhipin, Lagou, Liepin — no unauthenticated public API found.
|
|
36
|
-
//
|
|
37
|
-
// Conclusion: Baichuan currently posts positions through internal/gated channels
|
|
38
|
-
// only. When a public JSON endpoint becomes available this adapter can be
|
|
39
|
-
// upgraded to a thin wrapper around feishu.ts (createAdapter) or a bespoke
|
|
40
|
-
// client in a single pass.
|
|
20
|
+
// This is the same multi-tenant ATSX pattern that MiniMax (vrfi1sk8a0)
|
|
21
|
+
// uses — the company path is the portal-channel header.
|
|
41
22
|
//
|
|
42
23
|
// ============================================================
|
|
43
|
-
// PositionSummary field mapping (
|
|
44
|
-
// post_id
|
|
45
|
-
// title
|
|
46
|
-
// project
|
|
47
|
-
// recruit_label
|
|
48
|
-
// bgs
|
|
49
|
-
// work_cities
|
|
50
|
-
// apply_url
|
|
24
|
+
// PositionSummary field mapping (Feishu → canonical):
|
|
25
|
+
// post_id ← String(item.id)
|
|
26
|
+
// title ← item.title
|
|
27
|
+
// project ← item.job_category?.name ?? item.job_function?.name
|
|
28
|
+
// recruit_label ← item.recruit_type?.name
|
|
29
|
+
// bgs ← "" (not exposed in public search)
|
|
30
|
+
// work_cities ← city_list joined " / " (city_info used as fallback)
|
|
31
|
+
// apply_url ← https://cq6qe6bvfr6.jobs.feishu.cn/baichuanzhaopin/position/${id}/detail
|
|
32
|
+
import { createAdapter } from "./feishu.js";
|
|
51
33
|
import { extractResumeSignals, scoreOverlap, checkResume } from "./tencent.js";
|
|
52
|
-
export { checkResume };
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"(
|
|
57
|
-
"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
export
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
export async function fetchAllPositions(_opts = {}) {
|
|
70
|
-
return {
|
|
71
|
-
ok: false,
|
|
72
|
-
source: SOURCE,
|
|
73
|
-
message: STUB_MESSAGE,
|
|
74
|
-
total: 0,
|
|
75
|
-
fetched: 0,
|
|
76
|
-
positions: [],
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
export async function fetchPositionDetail(postId) {
|
|
80
|
-
return {
|
|
81
|
-
ok: false,
|
|
82
|
-
source: SOURCE,
|
|
83
|
-
message: STUB_MESSAGE,
|
|
84
|
-
post_id: postId,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
export async function fetchDictionaries() {
|
|
88
|
-
return {
|
|
89
|
-
ok: false,
|
|
90
|
-
source: SOURCE,
|
|
91
|
-
message: STUB_MESSAGE,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
export async function listNotices() {
|
|
95
|
-
return {
|
|
96
|
-
ok: false,
|
|
97
|
-
source: SOURCE,
|
|
98
|
-
message: STUB_MESSAGE,
|
|
99
|
-
notices: [],
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
export async function getNotice(noticeId) {
|
|
103
|
-
return {
|
|
104
|
-
ok: false,
|
|
105
|
-
source: SOURCE,
|
|
106
|
-
message: STUB_MESSAGE,
|
|
107
|
-
notice_id: noticeId,
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
export async function findNoticesByQuestion(question, _opts = {}) {
|
|
111
|
-
return {
|
|
112
|
-
ok: false,
|
|
113
|
-
source: SOURCE,
|
|
114
|
-
question,
|
|
115
|
-
message: STUB_MESSAGE,
|
|
116
|
-
matches: [],
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
// ---------- matchResume ----------
|
|
120
|
-
// Extracts signals so callers can see what terms were parsed, even though
|
|
121
|
-
// no live positions are available to score against.
|
|
122
|
-
export async function matchResume(text, _opts = {}) {
|
|
123
|
-
const { terms, cities } = extractResumeSignals(text ?? "");
|
|
124
|
-
return {
|
|
125
|
-
ok: false,
|
|
126
|
-
source: SOURCE,
|
|
127
|
-
extracted_terms: terms,
|
|
128
|
-
city_preferences: cities,
|
|
129
|
-
matches: [],
|
|
130
|
-
message: STUB_MESSAGE,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
export { extractResumeSignals, scoreOverlap };
|
|
34
|
+
export { extractResumeSignals, scoreOverlap, checkResume };
|
|
35
|
+
const _adapter = createAdapter({
|
|
36
|
+
host: "cq6qe6bvfr6.jobs.feishu.cn",
|
|
37
|
+
channel: "baichuanzhaopin",
|
|
38
|
+
label: "Baichuan (百川智能)",
|
|
39
|
+
applyUrlPrefix: "https://cq6qe6bvfr6.jobs.feishu.cn/baichuanzhaopin/position",
|
|
40
|
+
});
|
|
41
|
+
export const searchPositions = _adapter.searchPositions;
|
|
42
|
+
export const fetchAllPositions = _adapter.fetchAllPositions;
|
|
43
|
+
export const fetchPositionDetail = _adapter.fetchPositionDetail;
|
|
44
|
+
export const fetchDictionaries = _adapter.fetchDictionaries;
|
|
45
|
+
export const listNotices = _adapter.listNotices;
|
|
46
|
+
export const getNotice = _adapter.getNotice;
|
|
47
|
+
export const findNoticesByQuestion = _adapter.findNoticesByQuestion;
|
|
48
|
+
export const matchResume = _adapter.matchResume;
|
package/dist/bilibili.js
CHANGED
|
@@ -295,6 +295,49 @@ export async function fetchAllPositions(opts = {}) {
|
|
|
295
295
|
positions: bucket,
|
|
296
296
|
};
|
|
297
297
|
}
|
|
298
|
+
// ---------- fetchPositionDetail ----------
|
|
299
|
+
// Bilibili's public search response carries description + requirement inline,
|
|
300
|
+
// so "detail" is a paginated scan-and-filter (same pattern as feishu.ts).
|
|
301
|
+
export async function fetchPositionDetail(postId) {
|
|
302
|
+
const id = (postId ?? "").trim();
|
|
303
|
+
if (!id)
|
|
304
|
+
return { ok: false, source: "jobs.bilibili.com", message: "post_id is required" };
|
|
305
|
+
const pageSize = 100;
|
|
306
|
+
const maxPages = 4;
|
|
307
|
+
for (let page = 1; page <= maxPages; page++) {
|
|
308
|
+
const result = await searchPositions({ page, pageSize });
|
|
309
|
+
if (!result.ok) {
|
|
310
|
+
return {
|
|
311
|
+
ok: false,
|
|
312
|
+
source: "jobs.bilibili.com",
|
|
313
|
+
post_id: id,
|
|
314
|
+
message: result.message,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
const found = result.positions.find((p) => p.post_id === id);
|
|
318
|
+
if (found) {
|
|
319
|
+
return {
|
|
320
|
+
ok: true,
|
|
321
|
+
source: "jobs.bilibili.com",
|
|
322
|
+
post_id: id,
|
|
323
|
+
title: found.title,
|
|
324
|
+
project: found.project,
|
|
325
|
+
recruit_label: found.recruit_label,
|
|
326
|
+
bgs: found.bgs,
|
|
327
|
+
work_cities: found.work_cities,
|
|
328
|
+
apply_url: found.apply_url,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
if (result.positions.length < pageSize)
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
return {
|
|
335
|
+
ok: false,
|
|
336
|
+
source: "jobs.bilibili.com",
|
|
337
|
+
post_id: id,
|
|
338
|
+
message: `post ${id} not found in public search results (scanned up to ${maxPages * pageSize} posts)`,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
298
341
|
// ---------- matchResume ----------
|
|
299
342
|
export async function matchResume(text, opts = {}) {
|
|
300
343
|
const topN = Math.max(1, opts.topN ?? 5);
|