mirror of
https://github.com/geekgeekrun/geekgeekrun.git
synced 2026-05-15 04:19:39 +08:00
252 lines
9.2 KiB
TypeScript
252 lines
9.2 KiB
TypeScript
import "reflect-metadata";
|
|
import { type DataSource } from "typeorm";
|
|
|
|
import { BossInfo } from "./entity/BossInfo";
|
|
import { BossInfoChangeLog } from "./entity/BossInfoChangeLog";
|
|
import { ChatStartupFrom, ChatStartupLog } from './entity/ChatStartupLog';
|
|
import { CompanyInfoChangeLog } from "./entity/CompanyInfoChangeLog";
|
|
import { CompanyInfo } from "./entity/CompanyInfo";
|
|
import { JobInfo } from "./entity/JobInfo";
|
|
import { JobInfoChangeLog } from "./entity/JobInfoChangeLog";
|
|
import { BossActiveStatusRecord } from "./entity/BossActiveStatusRecord";
|
|
import { UserInfo } from "./entity/UserInfo";
|
|
import { AutoStartChatRunRecord } from './entity/AutoStartChatRunRecord';
|
|
import { MarkAsNotSuitLog } from "./entity/MarkAsNotSuitLog"
|
|
import { VChatStartupLog } from "./entity/VChatStartupLog";
|
|
import { VBossLibrary } from "./entity/VBossLibrary";
|
|
import { VJobLibrary } from "./entity/VJobLibrary";
|
|
import { VCompanyLibrary } from "./entity/VCompanyLibrary"
|
|
import { VMarkAsNotSuitLog } from "./entity/VMarkAsNotSuitLog"
|
|
import { ChatMessageRecord } from './entity/ChatMessageRecord'
|
|
import { LlmModelUsageRecord } from './entity/LlmModelUsageRecord'
|
|
import { JobHireStatusRecord } from './entity/JobHireStatusRecord'
|
|
|
|
import {
|
|
saveChatStartupRecord,
|
|
saveJobInfoFromRecommendPage,
|
|
saveMarkAsNotSuitRecord,
|
|
getNotSuitMarkRecordsInLastSomeDays,
|
|
getChatStartupRecordsInLastSomeDays,
|
|
getBossIdsByJobIds,
|
|
saveJobHireStatusRecord
|
|
} from "./handlers";
|
|
import { UpdateChatStartupLogTable1729182577167 } from "./migrations/1729182577167-UpdateChatStartupLogTable";
|
|
import minimist from 'minimist'
|
|
import { UpdateBossInfoTable1732032381304 } from "./migrations/1732032381304-UpdateBossInfoTable";
|
|
import { JobHireStatus, MarkAsNotSuitOp, MarkAsNotSuitReason } from "./enums";
|
|
import { AddColumnForMarkAsNotSuitLog1746092370665 } from "./migrations/1746092370665-AddColumnForMarkAsNotSuitLog";
|
|
import { Init1000000000000 } from "./migrations/1000000000000-Init";
|
|
import { AddJobSourceColumnForChatStartupLogAndMarkAsNotSuitLog1752380078526 } from "./migrations/1752380078526-AddJobSourceColumnForChatStartupLogAndMarkAsNotSuitLog";
|
|
import { AddJobHireStatusTable1766466476822 } from "./migrations/1766466476822-AddJobHireStatusTable";
|
|
import chunk from 'lodash/chunk'
|
|
import * as typeorm from 'typeorm'
|
|
|
|
export function initDb(dbFilePath) {
|
|
const { DataSource } = typeorm
|
|
const appDataSource = new DataSource({
|
|
type: "better-sqlite3",
|
|
synchronize: false,
|
|
logging: true,
|
|
logger: "simple-console",
|
|
database: dbFilePath,
|
|
entities: [
|
|
ChatStartupLog,
|
|
BossInfo,
|
|
BossInfoChangeLog,
|
|
CompanyInfo,
|
|
CompanyInfoChangeLog,
|
|
JobInfo,
|
|
JobInfoChangeLog,
|
|
BossActiveStatusRecord,
|
|
UserInfo,
|
|
AutoStartChatRunRecord,
|
|
VChatStartupLog,
|
|
VBossLibrary,
|
|
VJobLibrary,
|
|
VCompanyLibrary,
|
|
MarkAsNotSuitLog,
|
|
VMarkAsNotSuitLog,
|
|
ChatMessageRecord,
|
|
LlmModelUsageRecord,
|
|
JobHireStatusRecord,
|
|
],
|
|
migrations: [
|
|
Init1000000000000,
|
|
UpdateChatStartupLogTable1729182577167,
|
|
UpdateBossInfoTable1732032381304,
|
|
AddColumnForMarkAsNotSuitLog1746092370665,
|
|
AddJobSourceColumnForChatStartupLogAndMarkAsNotSuitLog1752380078526,
|
|
AddJobHireStatusTable1766466476822
|
|
],
|
|
migrationsRun: true
|
|
});
|
|
return appDataSource.initialize();
|
|
}
|
|
|
|
export default class SqlitePlugin {
|
|
initPromise: Promise<DataSource>;
|
|
runRecordId: number;
|
|
|
|
constructor(dbFilePath) {
|
|
this.initPromise = initDb(dbFilePath);
|
|
this.runRecordId = minimist(process.argv.slice(2))['run-record-id'] ?? 0
|
|
}
|
|
|
|
userInfo = null
|
|
|
|
apply(hooks) {
|
|
hooks.pageGotten.tap(
|
|
'SqlitePlugin',
|
|
(page) => {
|
|
page.on('response', async (response) => {
|
|
const ds = await this.initPromise;
|
|
if (response.url().startsWith('https://www.zhipin.com/wapi/zpgeek/job/detail.json')) {
|
|
const data = await response.json()
|
|
if (data.code === 0) {
|
|
await saveJobInfoFromRecommendPage(await ds, data.zpData)
|
|
await saveJobHireStatusRecord(await ds, {
|
|
encryptJobId: data.zpData.jobInfo.encryptId,
|
|
hireStatus: JobHireStatus.HIRING,
|
|
lastSeenDate: new Date()
|
|
})
|
|
}
|
|
}
|
|
})
|
|
}
|
|
)
|
|
hooks.userInfoResponse.tapPromise(
|
|
"SqlitePlugin",
|
|
async (userInfoResponse) => {
|
|
if (!userInfoResponse || userInfoResponse.code !== 0) {
|
|
return;
|
|
}
|
|
const { zpData: userInfo } = userInfoResponse;
|
|
this.userInfo = userInfo
|
|
console.log(userInfo);
|
|
|
|
const ds = await this.initPromise;
|
|
const userInfoRepository = ds.getRepository(UserInfo);
|
|
|
|
const user = new UserInfo();
|
|
user.encryptUserId = userInfo.encryptUserId;
|
|
user.name = userInfo.name;
|
|
|
|
return await userInfoRepository.save(user);
|
|
}
|
|
);
|
|
hooks.mainFlowWillLaunch.tapPromise(
|
|
"SqlitePlugin",
|
|
async ({
|
|
jobNotMatchStrategy,
|
|
jobNotActiveStrategy,
|
|
expectCityNotMatchStrategy,
|
|
blockJobNotSuit,
|
|
blockBossNotActive,
|
|
blockBossNotNewChat
|
|
}) => {
|
|
if (
|
|
jobNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL ||
|
|
jobNotActiveStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL ||
|
|
expectCityNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
|
|
) {
|
|
const ds = await this.initPromise;
|
|
const last7DayMarkRecords = (await getNotSuitMarkRecordsInLastSomeDays(ds, 7)) ?? [];
|
|
if (
|
|
jobNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL ||
|
|
jobNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
|
|
) {
|
|
last7DayMarkRecords
|
|
.filter(it =>
|
|
[
|
|
MarkAsNotSuitReason.JOB_NOT_SUIT,
|
|
MarkAsNotSuitReason.USER_MANUAL_OPERATION_WITH_UNKNOWN_REASON
|
|
].includes(it.markReason)
|
|
)
|
|
.map(
|
|
it => it.encryptJobId
|
|
)
|
|
.forEach(
|
|
id => blockJobNotSuit.add(id)
|
|
)
|
|
}
|
|
if (
|
|
jobNotActiveStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL ||
|
|
jobNotActiveStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
|
|
) {
|
|
last7DayMarkRecords
|
|
.filter(it => it.markReason === MarkAsNotSuitReason.BOSS_INACTIVE)
|
|
.map(
|
|
it => it.encryptJobId
|
|
)
|
|
.forEach(
|
|
id => blockJobNotSuit.add(id)
|
|
)
|
|
}
|
|
if (
|
|
expectCityNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL ||
|
|
expectCityNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
|
|
) {
|
|
last7DayMarkRecords
|
|
.filter(it => it.markReason === MarkAsNotSuitReason.JOB_CITY_NOT_SUIT)
|
|
.map(
|
|
it => it.encryptJobId
|
|
)
|
|
.forEach(
|
|
id => blockJobNotSuit.add(id)
|
|
)
|
|
}
|
|
const last30DayChatStartupRecords = (await getChatStartupRecordsInLastSomeDays(ds, 30)) ?? [];
|
|
const chattedJobIds = last30DayChatStartupRecords.map(it => it.encryptJobId)
|
|
if (chattedJobIds.length === 0) {
|
|
return
|
|
}
|
|
const chattedJobIdChunks = chunk(chattedJobIds, 200)
|
|
const chattedBossIds = [];
|
|
for (const chattedJobIdChunk of chattedJobIdChunks) {
|
|
const chattedBossIdChunk = ((await getBossIdsByJobIds(ds, chattedJobIdChunk)) ?? []).map(it => it.encryptBossId)
|
|
chattedBossIds.push(...chattedBossIdChunk)
|
|
}
|
|
for (const id of chattedBossIds) {
|
|
blockBossNotNewChat.add(id)
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
hooks.jobDetailIsGetFromRecommendList.tapPromise("SqlitePlugin", async (_jobInfo) => {
|
|
const ds = await this.initPromise;
|
|
await saveJobInfoFromRecommendPage(ds, _jobInfo);
|
|
});
|
|
|
|
hooks.jobDetailIsGetFromRecommendList.tapPromise("SqlitePlugin", async ({ jobInfo }) => {
|
|
const ds = await this.initPromise;
|
|
return await saveJobHireStatusRecord(ds, {
|
|
encryptJobId: jobInfo.encryptId,
|
|
hireStatus: JobHireStatus.HIRING,
|
|
lastSeenDate: new Date()
|
|
});
|
|
});
|
|
|
|
hooks.newChatStartup.tapPromise("SqlitePlugin", async (_jobInfo, { chatStartupFrom = ChatStartupFrom.AutoFromRecommendList, jobSource = undefined } = {}) => {
|
|
const ds = await this.initPromise;
|
|
return await saveChatStartupRecord(ds, _jobInfo, this.userInfo, {
|
|
autoStartupChatRecordId: this.runRecordId,
|
|
chatStartupFrom,
|
|
jobSource
|
|
});
|
|
});
|
|
|
|
hooks.jobMarkedAsNotSuit.tapPromise("SqlitePlugin", async (_jobInfo, { markFrom = ChatStartupFrom.AutoFromRecommendList, markReason = undefined, extInfo = undefined, markOp = undefined, jobSource = undefined } = {}) => {
|
|
const ds = await this.initPromise;
|
|
return await saveMarkAsNotSuitRecord(ds, _jobInfo, this.userInfo, {
|
|
autoStartupChatRecordId: this.runRecordId,
|
|
markFrom,
|
|
markReason,
|
|
extInfo,
|
|
markOp,
|
|
jobSource
|
|
});
|
|
});
|
|
}
|
|
}
|