recruiter: add boss auto browse/chat flows, webhook, and candidate tables

- Add recruiter-side automation core and run-core entry
- Extend sqlite-plugin with candidate info + contact logs
- Add UI routes/pages, IPC handlers, progress + log panel
- Document current status and plans under plan/

Made-with: Cursor
This commit is contained in:
rqi14
2026-03-18 17:37:24 +08:00
parent 4048e3b323
commit 95c1e54c66
73 changed files with 15053 additions and 89 deletions

View File

@@ -1,10 +1,20 @@
import OpenAI from "openai";
/**
* 调用 Chat Completions API支持推理模型thinking 参数)。
*
* @param {{ baseURL: string, apiKey: string, model: string, max_tokens?: number, temperature?: number, thinking?: { enabled?: boolean, budget?: number } }} config
* @param {Array<{ role: string, content: string }>} messages
*/
export async function completes(
{
baseURL,
apiKey,
model
model,
max_tokens,
temperature,
thinking,
response_format
},
messages
) {
@@ -13,14 +23,49 @@ export async function completes(
apiKey,
});
const completion = await openai.chat.completions.create({
const isThinking = !!(thinking?.enabled && thinking?.budget)
// 推理模型开启 thinking 时max_tokens 必须大于 thinking_budget否则会因长度上限截断 JSON。
// 调用方若未显式传 max_tokens按是否启用 thinking 给一个安全的默认值。
const resolvedMaxTokens =
typeof max_tokens === 'number'
? max_tokens
: isThinking
? 8192
: 1200
// temperature推理模型启用 thinking 时建议 ≥0.5(部分 provider 限制),普通 JSON 输出用 0.1。
const resolvedTemperature =
typeof temperature === 'number'
? temperature
: isThinking
? 0.6
: 0.1
const createParams = {
messages,
model,
frequency_penalty: 0,
max_tokens: 100,
temperature: 0.1
});
max_tokens: resolvedMaxTokens,
temperature: resolvedTemperature,
}
console.log(completion.choices[0].message.content);
if (isThinking) {
// SiliconFlow / 火山方舟等兼容顶层参数OpenAI SDK 通过 extra_body 透传其他字段
createParams.enable_thinking = true
createParams.thinking_budget = thinking.budget
}
if (response_format) {
createParams.response_format = response_format
}
const completion = await openai.chat.completions.create(createParams);
// reasoning_content 仅推理模型填充,普通模型为 undefined
const msg = completion.choices[0].message
if (msg.reasoning_content) {
console.log('[gpt-request] reasoning_content:', String(msg.reasoning_content ?? '').slice(0, 200))
}
console.log('[gpt-request] content:', (msg.content ?? '').slice(0, 200));
return completion;
}

View File

@@ -4,6 +4,8 @@ export function sleep (t) {
})
}
export function sleepWithRandomDelay (base) {
return sleep(base + Math.random()*1000)
export function sleepWithRandomDelay (min, max) {
const lo = min ?? 0
const hi = max ?? (lo + 1000)
return sleep(lo + Math.random() * (hi - lo))
}