dotb_ai-platform/apps/web/src/lib/server/fixture-runner.ts
hungtran24 6577bb74be refactor: simplify scoring service, AI profile revisions and test suite
Phase 2 and 3 of the platform rework.

- Neutral request/response contract: external_id, metadata, X-AI-Key,
  run_id in the response; client-specific fields removed.
- AI profile is a revision table: saving creates an inactive revision,
  activation is separate, try-run does not store a run. One
  chat-completions gateway serves AIHub and OpenAI-compatible profiles.
- Add between and in rule operators.
- Contracts moved to contracts/lead-scoring/ with a score-response fixture.
- Admin Web updated for revisions, runs and the neutral fixture.
- Consolidate tests; remove rewrite_architect.md and the stale handoff doc;
  rewrite spec, CONTEXT and ARCHITECTURE for the current design.

Not verified: live AIHub/OpenAI behavior, Omni/EMS integration.
2026-10-09 08:23:21 +07:00

46 lines
1.7 KiB
TypeScript

import { env } from '$env/dynamic/private';
import type { RequestEvent } from '@sveltejs/kit';
import type { components } from '$lib/generated/api';
import fixture from '../../../../../contracts/lead-scoring/fixtures/run-request.json';
export type RunRequest = components['schemas']['RunRequest'];
export const scoringFixture = fixture as RunRequest;
export class FixtureRunnerNotConfigured extends Error {}
export function fixtureRunnerConfigured(): boolean {
return Boolean(env.LEAD_SCORING_FIXTURE_APP_API_KEY?.trim());
}
export async function submitScoringFixture(event: RequestEvent, useAI = false): Promise<Response> {
const base = env.BACKEND_INTERNAL_URL;
const appKey = env.LEAD_SCORING_FIXTURE_APP_API_KEY?.trim();
if (!appKey) throw new FixtureRunnerNotConfigured();
if (!base || !/^https?:\/\//.test(base)) {
throw new Error('BACKEND_INTERNAL_URL must be configured on the server');
}
const request: RunRequest = {
...scoringFixture,
scoring_config: {
...scoringFixture.scoring_config,
rule_weight: useAI ? 0.5 : 1,
ai_weight: useAI ? 0.5 : 0,
},
};
const aiKey = env.LEAD_SCORING_FIXTURE_AI_KEY?.trim();
return event.fetch(`${base.replace(/\/$/, '')}/v1/lead-scoring/score`, {
method: 'POST',
cache: 'no-store',
redirect: 'error',
headers: {
accept: 'application/json',
authorization: `Bearer ${appKey}`,
'content-type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
...(useAI && aiKey ? { 'X-AI-Key': aiKey } : {}),
},
body: JSON.stringify(request),
});
}