diff models for diff work
This commit is contained in:
parent
e954cba4b1
commit
5d7c394650
@ -143,6 +143,9 @@ export async function getProfileProjects(): Promise<ResumeProjectCatalogItem[]>
|
|||||||
|
|
||||||
export async function updateSettings(update: {
|
export async function updateSettings(update: {
|
||||||
model?: string | null
|
model?: string | null
|
||||||
|
modelScorer?: string | null
|
||||||
|
modelTailoring?: string | null
|
||||||
|
modelProjectSelection?: string | null
|
||||||
pipelineWebhookUrl?: string | null
|
pipelineWebhookUrl?: string | null
|
||||||
jobCompleteWebhookUrl?: string | null
|
jobCompleteWebhookUrl?: string | null
|
||||||
resumeProjects?: ResumeProjectsSettings | null
|
resumeProjects?: ResumeProjectsSettings | null
|
||||||
|
|||||||
@ -57,6 +57,9 @@ function clampInt(value: number, min: number, max: number) {
|
|||||||
export const SettingsPage: React.FC = () => {
|
export const SettingsPage: React.FC = () => {
|
||||||
const [settings, setSettings] = useState<AppSettings | null>(null)
|
const [settings, setSettings] = useState<AppSettings | null>(null)
|
||||||
const [modelDraft, setModelDraft] = useState("")
|
const [modelDraft, setModelDraft] = useState("")
|
||||||
|
const [modelScorerDraft, setModelScorerDraft] = useState("")
|
||||||
|
const [modelTailoringDraft, setModelTailoringDraft] = useState("")
|
||||||
|
const [modelProjectSelectionDraft, setModelProjectSelectionDraft] = useState("")
|
||||||
const [pipelineWebhookUrlDraft, setPipelineWebhookUrlDraft] = useState("")
|
const [pipelineWebhookUrlDraft, setPipelineWebhookUrlDraft] = useState("")
|
||||||
const [jobCompleteWebhookUrlDraft, setJobCompleteWebhookUrlDraft] = useState("")
|
const [jobCompleteWebhookUrlDraft, setJobCompleteWebhookUrlDraft] = useState("")
|
||||||
const [resumeProjectsDraft, setResumeProjectsDraft] = useState<ResumeProjectsSettings | null>(null)
|
const [resumeProjectsDraft, setResumeProjectsDraft] = useState<ResumeProjectsSettings | null>(null)
|
||||||
@ -79,6 +82,9 @@ export const SettingsPage: React.FC = () => {
|
|||||||
if (!isMounted) return
|
if (!isMounted) return
|
||||||
setSettings(data)
|
setSettings(data)
|
||||||
setModelDraft(data.overrideModel ?? "")
|
setModelDraft(data.overrideModel ?? "")
|
||||||
|
setModelScorerDraft(data.overrideModelScorer ?? "")
|
||||||
|
setModelTailoringDraft(data.overrideModelTailoring ?? "")
|
||||||
|
setModelProjectSelectionDraft(data.overrideModelProjectSelection ?? "")
|
||||||
setPipelineWebhookUrlDraft(data.overridePipelineWebhookUrl ?? "")
|
setPipelineWebhookUrlDraft(data.overridePipelineWebhookUrl ?? "")
|
||||||
setJobCompleteWebhookUrlDraft(data.overrideJobCompleteWebhookUrl ?? "")
|
setJobCompleteWebhookUrlDraft(data.overrideJobCompleteWebhookUrl ?? "")
|
||||||
setResumeProjectsDraft(data.resumeProjects)
|
setResumeProjectsDraft(data.resumeProjects)
|
||||||
@ -107,6 +113,12 @@ export const SettingsPage: React.FC = () => {
|
|||||||
const effectiveModel = settings?.model ?? ""
|
const effectiveModel = settings?.model ?? ""
|
||||||
const defaultModel = settings?.defaultModel ?? ""
|
const defaultModel = settings?.defaultModel ?? ""
|
||||||
const overrideModel = settings?.overrideModel
|
const overrideModel = settings?.overrideModel
|
||||||
|
const effectiveModelScorer = settings?.modelScorer ?? ""
|
||||||
|
const overrideModelScorer = settings?.overrideModelScorer
|
||||||
|
const effectiveModelTailoring = settings?.modelTailoring ?? ""
|
||||||
|
const overrideModelTailoring = settings?.overrideModelTailoring
|
||||||
|
const effectiveModelProjectSelection = settings?.modelProjectSelection ?? ""
|
||||||
|
const overrideModelProjectSelection = settings?.overrideModelProjectSelection
|
||||||
const effectivePipelineWebhookUrl = settings?.pipelineWebhookUrl ?? ""
|
const effectivePipelineWebhookUrl = settings?.pipelineWebhookUrl ?? ""
|
||||||
const defaultPipelineWebhookUrl = settings?.defaultPipelineWebhookUrl ?? ""
|
const defaultPipelineWebhookUrl = settings?.defaultPipelineWebhookUrl ?? ""
|
||||||
const overridePipelineWebhookUrl = settings?.overridePipelineWebhookUrl
|
const overridePipelineWebhookUrl = settings?.overridePipelineWebhookUrl
|
||||||
@ -142,6 +154,12 @@ export const SettingsPage: React.FC = () => {
|
|||||||
if (!settings || !resumeProjectsDraft) return false
|
if (!settings || !resumeProjectsDraft) return false
|
||||||
const next = modelDraft.trim()
|
const next = modelDraft.trim()
|
||||||
const current = (overrideModel ?? "").trim()
|
const current = (overrideModel ?? "").trim()
|
||||||
|
const nextScorer = modelScorerDraft.trim()
|
||||||
|
const currentScorer = (overrideModelScorer ?? "").trim()
|
||||||
|
const nextTailoring = modelTailoringDraft.trim()
|
||||||
|
const currentTailoring = (overrideModelTailoring ?? "").trim()
|
||||||
|
const nextProjectSelection = modelProjectSelectionDraft.trim()
|
||||||
|
const currentProjectSelection = (overrideModelProjectSelection ?? "").trim()
|
||||||
const nextWebhook = pipelineWebhookUrlDraft.trim()
|
const nextWebhook = pipelineWebhookUrlDraft.trim()
|
||||||
const currentWebhook = (overridePipelineWebhookUrl ?? "").trim()
|
const currentWebhook = (overridePipelineWebhookUrl ?? "").trim()
|
||||||
const nextJobCompleteWebhook = jobCompleteWebhookUrlDraft.trim()
|
const nextJobCompleteWebhook = jobCompleteWebhookUrlDraft.trim()
|
||||||
@ -150,6 +168,9 @@ export const SettingsPage: React.FC = () => {
|
|||||||
const searchTermsChanged = JSON.stringify(searchTermsDraft) !== JSON.stringify(overrideSearchTerms ?? null)
|
const searchTermsChanged = JSON.stringify(searchTermsDraft) !== JSON.stringify(overrideSearchTerms ?? null)
|
||||||
return (
|
return (
|
||||||
next !== current ||
|
next !== current ||
|
||||||
|
nextScorer !== currentScorer ||
|
||||||
|
nextTailoring !== currentTailoring ||
|
||||||
|
nextProjectSelection !== currentProjectSelection ||
|
||||||
nextWebhook !== currentWebhook ||
|
nextWebhook !== currentWebhook ||
|
||||||
nextJobCompleteWebhook !== currentJobCompleteWebhook ||
|
nextJobCompleteWebhook !== currentJobCompleteWebhook ||
|
||||||
!resumeProjectsEqual(resumeProjectsDraft, settings.resumeProjects) ||
|
!resumeProjectsEqual(resumeProjectsDraft, settings.resumeProjects) ||
|
||||||
@ -164,9 +185,15 @@ export const SettingsPage: React.FC = () => {
|
|||||||
}, [
|
}, [
|
||||||
settings,
|
settings,
|
||||||
modelDraft,
|
modelDraft,
|
||||||
|
modelScorerDraft,
|
||||||
|
modelTailoringDraft,
|
||||||
|
modelProjectSelectionDraft,
|
||||||
pipelineWebhookUrlDraft,
|
pipelineWebhookUrlDraft,
|
||||||
jobCompleteWebhookUrlDraft,
|
jobCompleteWebhookUrlDraft,
|
||||||
overrideModel,
|
overrideModel,
|
||||||
|
overrideModelScorer,
|
||||||
|
overrideModelTailoring,
|
||||||
|
overrideModelProjectSelection,
|
||||||
overridePipelineWebhookUrl,
|
overridePipelineWebhookUrl,
|
||||||
overrideJobCompleteWebhookUrl,
|
overrideJobCompleteWebhookUrl,
|
||||||
resumeProjectsDraft,
|
resumeProjectsDraft,
|
||||||
@ -191,6 +218,9 @@ export const SettingsPage: React.FC = () => {
|
|||||||
try {
|
try {
|
||||||
setIsSaving(true)
|
setIsSaving(true)
|
||||||
const trimmed = modelDraft.trim()
|
const trimmed = modelDraft.trim()
|
||||||
|
const trimmedScorer = modelScorerDraft.trim()
|
||||||
|
const trimmedTailoring = modelTailoringDraft.trim()
|
||||||
|
const trimmedProjectSelection = modelProjectSelectionDraft.trim()
|
||||||
const webhookTrimmed = pipelineWebhookUrlDraft.trim()
|
const webhookTrimmed = pipelineWebhookUrlDraft.trim()
|
||||||
const jobCompleteTrimmed = jobCompleteWebhookUrlDraft.trim()
|
const jobCompleteTrimmed = jobCompleteWebhookUrlDraft.trim()
|
||||||
const resumeProjectsOverride = resumeProjectsEqual(resumeProjectsDraft, settings.defaultResumeProjects)
|
const resumeProjectsOverride = resumeProjectsEqual(resumeProjectsDraft, settings.defaultResumeProjects)
|
||||||
@ -205,6 +235,9 @@ export const SettingsPage: React.FC = () => {
|
|||||||
const jobspyLinkedinFetchDescriptionOverride = jobspyLinkedinFetchDescriptionDraft === defaultJobspyLinkedinFetchDescription ? null : jobspyLinkedinFetchDescriptionDraft
|
const jobspyLinkedinFetchDescriptionOverride = jobspyLinkedinFetchDescriptionDraft === defaultJobspyLinkedinFetchDescription ? null : jobspyLinkedinFetchDescriptionDraft
|
||||||
const updated = await api.updateSettings({
|
const updated = await api.updateSettings({
|
||||||
model: trimmed.length > 0 ? trimmed : null,
|
model: trimmed.length > 0 ? trimmed : null,
|
||||||
|
modelScorer: trimmedScorer.length > 0 ? trimmedScorer : null,
|
||||||
|
modelTailoring: trimmedTailoring.length > 0 ? trimmedTailoring : null,
|
||||||
|
modelProjectSelection: trimmedProjectSelection.length > 0 ? trimmedProjectSelection : null,
|
||||||
pipelineWebhookUrl: webhookTrimmed.length > 0 ? webhookTrimmed : null,
|
pipelineWebhookUrl: webhookTrimmed.length > 0 ? webhookTrimmed : null,
|
||||||
jobCompleteWebhookUrl: jobCompleteTrimmed.length > 0 ? jobCompleteTrimmed : null,
|
jobCompleteWebhookUrl: jobCompleteTrimmed.length > 0 ? jobCompleteTrimmed : null,
|
||||||
resumeProjects: resumeProjectsOverride,
|
resumeProjects: resumeProjectsOverride,
|
||||||
@ -218,6 +251,9 @@ export const SettingsPage: React.FC = () => {
|
|||||||
})
|
})
|
||||||
setSettings(updated)
|
setSettings(updated)
|
||||||
setModelDraft(updated.overrideModel ?? "")
|
setModelDraft(updated.overrideModel ?? "")
|
||||||
|
setModelScorerDraft(updated.overrideModelScorer ?? "")
|
||||||
|
setModelTailoringDraft(updated.overrideModelTailoring ?? "")
|
||||||
|
setModelProjectSelectionDraft(updated.overrideModelProjectSelection ?? "")
|
||||||
setPipelineWebhookUrlDraft(updated.overridePipelineWebhookUrl ?? "")
|
setPipelineWebhookUrlDraft(updated.overridePipelineWebhookUrl ?? "")
|
||||||
setJobCompleteWebhookUrlDraft(updated.overrideJobCompleteWebhookUrl ?? "")
|
setJobCompleteWebhookUrlDraft(updated.overrideJobCompleteWebhookUrl ?? "")
|
||||||
setResumeProjectsDraft(updated.resumeProjects)
|
setResumeProjectsDraft(updated.resumeProjects)
|
||||||
@ -266,6 +302,9 @@ export const SettingsPage: React.FC = () => {
|
|||||||
setIsSaving(true)
|
setIsSaving(true)
|
||||||
const updated = await api.updateSettings({
|
const updated = await api.updateSettings({
|
||||||
model: null,
|
model: null,
|
||||||
|
modelScorer: null,
|
||||||
|
modelTailoring: null,
|
||||||
|
modelProjectSelection: null,
|
||||||
pipelineWebhookUrl: null,
|
pipelineWebhookUrl: null,
|
||||||
jobCompleteWebhookUrl: null,
|
jobCompleteWebhookUrl: null,
|
||||||
resumeProjects: null,
|
resumeProjects: null,
|
||||||
@ -279,6 +318,9 @@ export const SettingsPage: React.FC = () => {
|
|||||||
})
|
})
|
||||||
setSettings(updated)
|
setSettings(updated)
|
||||||
setModelDraft("")
|
setModelDraft("")
|
||||||
|
setModelScorerDraft("")
|
||||||
|
setModelTailoringDraft("")
|
||||||
|
setModelProjectSelectionDraft("")
|
||||||
setPipelineWebhookUrlDraft("")
|
setPipelineWebhookUrlDraft("")
|
||||||
setJobCompleteWebhookUrlDraft("")
|
setJobCompleteWebhookUrlDraft("")
|
||||||
setResumeProjectsDraft(updated.resumeProjects)
|
setResumeProjectsDraft(updated.resumeProjects)
|
||||||
@ -327,9 +369,56 @@ export const SettingsPage: React.FC = () => {
|
|||||||
|
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="text-sm font-medium">Task-Specific Overrides</div>
|
||||||
|
|
||||||
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="text-sm">Scoring Model</div>
|
||||||
|
<Input
|
||||||
|
value={modelScorerDraft}
|
||||||
|
onChange={(event) => setModelScorerDraft(event.target.value)}
|
||||||
|
placeholder={effectiveModel || "inherit"}
|
||||||
|
disabled={isLoading || isSaving}
|
||||||
|
/>
|
||||||
|
<div className="text-xs text-muted-foreground">
|
||||||
|
Effective: <span className="font-mono">{effectiveModelScorer || effectiveModel}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="text-sm">Tailoring Model</div>
|
||||||
|
<Input
|
||||||
|
value={modelTailoringDraft}
|
||||||
|
onChange={(event) => setModelTailoringDraft(event.target.value)}
|
||||||
|
placeholder={effectiveModel || "inherit"}
|
||||||
|
disabled={isLoading || isSaving}
|
||||||
|
/>
|
||||||
|
<div className="text-xs text-muted-foreground">
|
||||||
|
Effective: <span className="font-mono">{effectiveModelTailoring || effectiveModel}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="text-sm">Project Selection Model</div>
|
||||||
|
<Input
|
||||||
|
value={modelProjectSelectionDraft}
|
||||||
|
onChange={(event) => setModelProjectSelectionDraft(event.target.value)}
|
||||||
|
placeholder={effectiveModel || "inherit"}
|
||||||
|
disabled={isLoading || isSaving}
|
||||||
|
/>
|
||||||
|
<div className="text-xs text-muted-foreground">
|
||||||
|
Effective: <span className="font-mono">{effectiveModelProjectSelection || effectiveModel}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Separator />
|
||||||
|
|
||||||
<div className="grid gap-2 text-sm sm:grid-cols-2">
|
<div className="grid gap-2 text-sm sm:grid-cols-2">
|
||||||
<div>
|
<div>
|
||||||
<div className="text-xs text-muted-foreground">Effective</div>
|
<div className="text-xs text-muted-foreground">Global Effective</div>
|
||||||
<div className="break-words font-mono text-xs">{effectiveModel || "—"}</div>
|
<div className="break-words font-mono text-xs">{effectiveModel || "—"}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -270,6 +270,16 @@ apiRouter.get('/settings', async (_req: Request, res: Response) => {
|
|||||||
const defaultModel = process.env.MODEL || 'openai/gpt-4o-mini';
|
const defaultModel = process.env.MODEL || 'openai/gpt-4o-mini';
|
||||||
const model = overrideModel || defaultModel;
|
const model = overrideModel || defaultModel;
|
||||||
|
|
||||||
|
// Specific AI models
|
||||||
|
const overrideModelScorer = await settingsRepo.getSetting('modelScorer');
|
||||||
|
const modelScorer = overrideModelScorer || model;
|
||||||
|
|
||||||
|
const overrideModelTailoring = await settingsRepo.getSetting('modelTailoring');
|
||||||
|
const modelTailoring = overrideModelTailoring || model;
|
||||||
|
|
||||||
|
const overrideModelProjectSelection = await settingsRepo.getSetting('modelProjectSelection');
|
||||||
|
const modelProjectSelection = overrideModelProjectSelection || model;
|
||||||
|
|
||||||
const overridePipelineWebhookUrl = await settingsRepo.getSetting('pipelineWebhookUrl');
|
const overridePipelineWebhookUrl = await settingsRepo.getSetting('pipelineWebhookUrl');
|
||||||
const defaultPipelineWebhookUrl = process.env.PIPELINE_WEBHOOK_URL || process.env.WEBHOOK_URL || '';
|
const defaultPipelineWebhookUrl = process.env.PIPELINE_WEBHOOK_URL || process.env.WEBHOOK_URL || '';
|
||||||
const pipelineWebhookUrl = overridePipelineWebhookUrl || defaultPipelineWebhookUrl;
|
const pipelineWebhookUrl = overridePipelineWebhookUrl || defaultPipelineWebhookUrl;
|
||||||
@ -326,6 +336,12 @@ apiRouter.get('/settings', async (_req: Request, res: Response) => {
|
|||||||
model,
|
model,
|
||||||
defaultModel,
|
defaultModel,
|
||||||
overrideModel,
|
overrideModel,
|
||||||
|
modelScorer,
|
||||||
|
overrideModelScorer,
|
||||||
|
modelTailoring,
|
||||||
|
overrideModelTailoring,
|
||||||
|
modelProjectSelection,
|
||||||
|
overrideModelProjectSelection,
|
||||||
pipelineWebhookUrl,
|
pipelineWebhookUrl,
|
||||||
defaultPipelineWebhookUrl,
|
defaultPipelineWebhookUrl,
|
||||||
overridePipelineWebhookUrl,
|
overridePipelineWebhookUrl,
|
||||||
@ -364,6 +380,9 @@ apiRouter.get('/settings', async (_req: Request, res: Response) => {
|
|||||||
|
|
||||||
const updateSettingsSchema = z.object({
|
const updateSettingsSchema = z.object({
|
||||||
model: z.string().trim().min(1).max(200).nullable().optional(),
|
model: z.string().trim().min(1).max(200).nullable().optional(),
|
||||||
|
modelScorer: z.string().trim().min(1).max(200).nullable().optional(),
|
||||||
|
modelTailoring: z.string().trim().min(1).max(200).nullable().optional(),
|
||||||
|
modelProjectSelection: z.string().trim().min(1).max(200).nullable().optional(),
|
||||||
pipelineWebhookUrl: z.string().trim().min(1).max(2000).nullable().optional(),
|
pipelineWebhookUrl: z.string().trim().min(1).max(2000).nullable().optional(),
|
||||||
jobCompleteWebhookUrl: z.string().trim().min(1).max(2000).nullable().optional(),
|
jobCompleteWebhookUrl: z.string().trim().min(1).max(2000).nullable().optional(),
|
||||||
resumeProjects: z.object({
|
resumeProjects: z.object({
|
||||||
@ -392,6 +411,16 @@ apiRouter.patch('/settings', async (req: Request, res: Response) => {
|
|||||||
await settingsRepo.setSetting('model', model);
|
await settingsRepo.setSetting('model', model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('modelScorer' in input) {
|
||||||
|
await settingsRepo.setSetting('modelScorer', input.modelScorer ?? null);
|
||||||
|
}
|
||||||
|
if ('modelTailoring' in input) {
|
||||||
|
await settingsRepo.setSetting('modelTailoring', input.modelTailoring ?? null);
|
||||||
|
}
|
||||||
|
if ('modelProjectSelection' in input) {
|
||||||
|
await settingsRepo.setSetting('modelProjectSelection', input.modelProjectSelection ?? null);
|
||||||
|
}
|
||||||
|
|
||||||
if ('pipelineWebhookUrl' in input) {
|
if ('pipelineWebhookUrl' in input) {
|
||||||
const pipelineWebhookUrl = input.pipelineWebhookUrl ?? null;
|
const pipelineWebhookUrl = input.pipelineWebhookUrl ?? null;
|
||||||
await settingsRepo.setSetting('pipelineWebhookUrl', pipelineWebhookUrl);
|
await settingsRepo.setSetting('pipelineWebhookUrl', pipelineWebhookUrl);
|
||||||
@ -455,6 +484,15 @@ apiRouter.patch('/settings', async (req: Request, res: Response) => {
|
|||||||
const defaultModel = process.env.MODEL || 'openai/gpt-4o-mini';
|
const defaultModel = process.env.MODEL || 'openai/gpt-4o-mini';
|
||||||
const model = overrideModel || defaultModel;
|
const model = overrideModel || defaultModel;
|
||||||
|
|
||||||
|
const overrideModelScorer = await settingsRepo.getSetting('modelScorer');
|
||||||
|
const modelScorer = overrideModelScorer || model;
|
||||||
|
|
||||||
|
const overrideModelTailoring = await settingsRepo.getSetting('modelTailoring');
|
||||||
|
const modelTailoring = overrideModelTailoring || model;
|
||||||
|
|
||||||
|
const overrideModelProjectSelection = await settingsRepo.getSetting('modelProjectSelection');
|
||||||
|
const modelProjectSelection = overrideModelProjectSelection || model;
|
||||||
|
|
||||||
const overridePipelineWebhookUrl = await settingsRepo.getSetting('pipelineWebhookUrl');
|
const overridePipelineWebhookUrl = await settingsRepo.getSetting('pipelineWebhookUrl');
|
||||||
const defaultPipelineWebhookUrl = process.env.PIPELINE_WEBHOOK_URL || process.env.WEBHOOK_URL || '';
|
const defaultPipelineWebhookUrl = process.env.PIPELINE_WEBHOOK_URL || process.env.WEBHOOK_URL || '';
|
||||||
const pipelineWebhookUrl = overridePipelineWebhookUrl || defaultPipelineWebhookUrl;
|
const pipelineWebhookUrl = overridePipelineWebhookUrl || defaultPipelineWebhookUrl;
|
||||||
@ -512,6 +550,12 @@ apiRouter.patch('/settings', async (req: Request, res: Response) => {
|
|||||||
model,
|
model,
|
||||||
defaultModel,
|
defaultModel,
|
||||||
overrideModel,
|
overrideModel,
|
||||||
|
modelScorer,
|
||||||
|
overrideModelScorer,
|
||||||
|
modelTailoring,
|
||||||
|
overrideModelTailoring,
|
||||||
|
modelProjectSelection,
|
||||||
|
overrideModelProjectSelection,
|
||||||
pipelineWebhookUrl,
|
pipelineWebhookUrl,
|
||||||
defaultPipelineWebhookUrl,
|
defaultPipelineWebhookUrl,
|
||||||
overridePipelineWebhookUrl,
|
overridePipelineWebhookUrl,
|
||||||
|
|||||||
@ -241,6 +241,8 @@ function mapRowToJob(row: typeof jobs.$inferSelect): Job {
|
|||||||
suitabilityScore: row.suitabilityScore,
|
suitabilityScore: row.suitabilityScore,
|
||||||
suitabilityReason: row.suitabilityReason,
|
suitabilityReason: row.suitabilityReason,
|
||||||
tailoredSummary: row.tailoredSummary,
|
tailoredSummary: row.tailoredSummary,
|
||||||
|
tailoredHeadline: row.tailoredHeadline ?? null,
|
||||||
|
tailoredSkills: row.tailoredSkills ?? null,
|
||||||
selectedProjectIds: row.selectedProjectIds ?? null,
|
selectedProjectIds: row.selectedProjectIds ?? null,
|
||||||
pdfPath: row.pdfPath,
|
pdfPath: row.pdfPath,
|
||||||
notionPageId: row.notionPageId,
|
notionPageId: row.notionPageId,
|
||||||
|
|||||||
@ -8,6 +8,9 @@ import { db, schema } from '../db/index.js'
|
|||||||
const { settings } = schema
|
const { settings } = schema
|
||||||
|
|
||||||
export type SettingKey = 'model'
|
export type SettingKey = 'model'
|
||||||
|
| 'modelScorer'
|
||||||
|
| 'modelTailoring'
|
||||||
|
| 'modelProjectSelection'
|
||||||
| 'pipelineWebhookUrl'
|
| 'pipelineWebhookUrl'
|
||||||
| 'jobCompleteWebhookUrl'
|
| 'jobCompleteWebhookUrl'
|
||||||
| 'resumeProjects'
|
| 'resumeProjects'
|
||||||
|
|||||||
@ -21,7 +21,9 @@ export async function pickProjectIdsForJob(args: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const overrideModel = await getSetting('model');
|
const overrideModel = await getSetting('model');
|
||||||
const model = overrideModel || process.env.MODEL || 'openai/gpt-4o-mini';
|
const overrideModelProjectSelection = await getSetting('modelProjectSelection');
|
||||||
|
// Precedence: Project-specific override > Global override > Env var > Default
|
||||||
|
const model = overrideModelProjectSelection || overrideModel || process.env.MODEL || 'openai/gpt-4o-mini';
|
||||||
|
|
||||||
const prompt = buildProjectSelectionPrompt({
|
const prompt = buildProjectSelectionPrompt({
|
||||||
jobDescription: args.jobDescription,
|
jobDescription: args.jobDescription,
|
||||||
|
|||||||
@ -26,7 +26,9 @@ export async function scoreJobSuitability(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const overrideModel = await getSetting('model');
|
const overrideModel = await getSetting('model');
|
||||||
const model = overrideModel || process.env.MODEL || 'openai/gpt-4o-mini';
|
const overrideModelScorer = await getSetting('modelScorer');
|
||||||
|
// Precedence: Scorer-specific override > Global override > Env var > Default
|
||||||
|
const model = overrideModelScorer || overrideModel || process.env.MODEL || 'openai/gpt-4o-mini';
|
||||||
|
|
||||||
const prompt = buildScoringPrompt(job, profile);
|
const prompt = buildScoringPrompt(job, profile);
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
* Service for generating tailored resume content (Summary, Headline, Skills).
|
* Service for generating tailored resume content (Summary, Headline, Skills).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { getSetting } from '../repositories/settings.js';
|
||||||
|
|
||||||
const OPENROUTER_API_URL = 'https://openrouter.ai/api/v1/chat/completions';
|
const OPENROUTER_API_URL = 'https://openrouter.ai/api/v1/chat/completions';
|
||||||
|
|
||||||
export interface TailoredData {
|
export interface TailoredData {
|
||||||
@ -30,7 +32,10 @@ export async function generateTailoring(
|
|||||||
return { success: false, error: 'API key not configured' };
|
return { success: false, error: 'API key not configured' };
|
||||||
}
|
}
|
||||||
|
|
||||||
const model = process.env.MODEL || 'openai/gpt-4o-mini';
|
const overrideModel = await getSetting('model');
|
||||||
|
const overrideModelTailoring = await getSetting('modelTailoring');
|
||||||
|
// Precedence: Tailoring-specific override > Global override > Env var > Default
|
||||||
|
const model = overrideModelTailoring || overrideModel || process.env.MODEL || 'openai/gpt-4o-mini';
|
||||||
const prompt = buildTailoringPrompt(profile, jobDescription);
|
const prompt = buildTailoringPrompt(profile, jobDescription);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -211,6 +211,14 @@ export interface AppSettings {
|
|||||||
model: string;
|
model: string;
|
||||||
defaultModel: string;
|
defaultModel: string;
|
||||||
overrideModel: string | null;
|
overrideModel: string | null;
|
||||||
|
// Specific model overrides
|
||||||
|
modelScorer: string; // resolved
|
||||||
|
overrideModelScorer: string | null;
|
||||||
|
modelTailoring: string; // resolved
|
||||||
|
overrideModelTailoring: string | null;
|
||||||
|
modelProjectSelection: string; // resolved
|
||||||
|
overrideModelProjectSelection: string | null;
|
||||||
|
|
||||||
pipelineWebhookUrl: string;
|
pipelineWebhookUrl: string;
|
||||||
defaultPipelineWebhookUrl: string;
|
defaultPipelineWebhookUrl: string;
|
||||||
overridePipelineWebhookUrl: string | null;
|
overridePipelineWebhookUrl: string | null;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user