Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
/**
|
|
|
|
|
* AI-Powered Award Eligibility Service
|
|
|
|
|
*
|
|
|
|
|
* Determines project eligibility for special awards using:
|
|
|
|
|
* - Deterministic field matching (tags, country, category)
|
|
|
|
|
* - AI interpretation of plain-language criteria
|
2026-02-03 11:58:12 +01:00
|
|
|
*
|
|
|
|
|
* GDPR Compliance:
|
|
|
|
|
* - All project data is anonymized before AI processing
|
|
|
|
|
* - IDs replaced with sequential identifiers
|
|
|
|
|
* - No personal information sent to OpenAI
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
*/
|
|
|
|
|
|
2026-02-03 11:58:12 +01:00
|
|
|
import { getOpenAI, getConfiguredModel, buildCompletionParams } from '@/lib/openai'
|
|
|
|
|
import { logAIUsage, extractTokenUsage } from '@/server/utils/ai-usage'
|
|
|
|
|
import { classifyAIError, createParseError, logAIError } from './ai-errors'
|
|
|
|
|
import {
|
|
|
|
|
anonymizeProjectsForAI,
|
|
|
|
|
validateAnonymizedProjects,
|
2026-02-05 20:31:08 +01:00
|
|
|
toProjectWithRelations,
|
2026-02-03 11:58:12 +01:00
|
|
|
type AnonymizedProjectForAI,
|
|
|
|
|
type ProjectAIMapping,
|
|
|
|
|
} from './anonymization'
|
|
|
|
|
import type { SubmissionSource } from '@prisma/client'
|
|
|
|
|
|
|
|
|
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
const BATCH_SIZE = 20
|
|
|
|
|
|
|
|
|
|
// Optimized system prompt
|
|
|
|
|
const AI_ELIGIBILITY_SYSTEM_PROMPT = `Award eligibility evaluator. Evaluate projects against criteria, return JSON.
|
|
|
|
|
Format: {"evaluations": [{project_id, eligible: bool, confidence: 0-1, reasoning: str}]}
|
|
|
|
|
Be objective. Base evaluation only on provided data. No personal identifiers in reasoning.`
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
|
|
|
|
|
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
export type AutoTagRule = {
|
|
|
|
|
field: 'competitionCategory' | 'country' | 'geographicZone' | 'tags' | 'oceanIssue'
|
|
|
|
|
operator: 'equals' | 'contains' | 'in'
|
|
|
|
|
value: string | string[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface EligibilityResult {
|
|
|
|
|
projectId: string
|
|
|
|
|
eligible: boolean
|
|
|
|
|
confidence: number
|
|
|
|
|
reasoning: string
|
|
|
|
|
method: 'AUTO' | 'AI'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface ProjectForEligibility {
|
|
|
|
|
id: string
|
|
|
|
|
title: string
|
|
|
|
|
description?: string | null
|
|
|
|
|
competitionCategory?: string | null
|
|
|
|
|
country?: string | null
|
|
|
|
|
geographicZone?: string | null
|
|
|
|
|
tags: string[]
|
|
|
|
|
oceanIssue?: string | null
|
2026-02-03 11:58:12 +01:00
|
|
|
institution?: string | null
|
|
|
|
|
foundedAt?: Date | null
|
|
|
|
|
wantsMentorship?: boolean
|
|
|
|
|
submissionSource?: SubmissionSource
|
|
|
|
|
submittedAt?: Date | null
|
|
|
|
|
_count?: {
|
|
|
|
|
teamMembers?: number
|
|
|
|
|
files?: number
|
|
|
|
|
}
|
|
|
|
|
files?: Array<{ fileType: string | null }>
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── Auto Tag Rules ─────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
export function applyAutoTagRules(
|
|
|
|
|
rules: AutoTagRule[],
|
|
|
|
|
projects: ProjectForEligibility[]
|
|
|
|
|
): Map<string, boolean> {
|
|
|
|
|
const results = new Map<string, boolean>()
|
|
|
|
|
|
|
|
|
|
for (const project of projects) {
|
|
|
|
|
const matches = rules.every((rule) => {
|
|
|
|
|
const fieldValue = getFieldValue(project, rule.field)
|
|
|
|
|
|
|
|
|
|
switch (rule.operator) {
|
|
|
|
|
case 'equals':
|
|
|
|
|
return String(fieldValue).toLowerCase() === String(rule.value).toLowerCase()
|
|
|
|
|
case 'contains':
|
|
|
|
|
if (Array.isArray(fieldValue)) {
|
|
|
|
|
return fieldValue.some((v) =>
|
|
|
|
|
String(v).toLowerCase().includes(String(rule.value).toLowerCase())
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
return String(fieldValue || '').toLowerCase().includes(String(rule.value).toLowerCase())
|
|
|
|
|
case 'in':
|
|
|
|
|
if (Array.isArray(rule.value)) {
|
|
|
|
|
return rule.value.some((v) =>
|
|
|
|
|
String(v).toLowerCase() === String(fieldValue).toLowerCase()
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
default:
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
results.set(project.id, matches)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return results
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getFieldValue(
|
|
|
|
|
project: ProjectForEligibility,
|
|
|
|
|
field: AutoTagRule['field']
|
|
|
|
|
): unknown {
|
|
|
|
|
switch (field) {
|
|
|
|
|
case 'competitionCategory':
|
|
|
|
|
return project.competitionCategory
|
|
|
|
|
case 'country':
|
|
|
|
|
return project.country
|
|
|
|
|
case 'geographicZone':
|
|
|
|
|
return project.geographicZone
|
|
|
|
|
case 'tags':
|
|
|
|
|
return project.tags
|
|
|
|
|
case 'oceanIssue':
|
|
|
|
|
return project.oceanIssue
|
|
|
|
|
default:
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ─── AI Criteria Interpretation ─────────────────────────────────────────────
|
|
|
|
|
|
2026-02-03 11:58:12 +01:00
|
|
|
/**
|
|
|
|
|
* Process a batch for AI eligibility evaluation
|
|
|
|
|
*/
|
|
|
|
|
async function processEligibilityBatch(
|
|
|
|
|
openai: NonNullable<Awaited<ReturnType<typeof getOpenAI>>>,
|
|
|
|
|
model: string,
|
|
|
|
|
criteriaText: string,
|
|
|
|
|
anonymized: AnonymizedProjectForAI[],
|
|
|
|
|
mappings: ProjectAIMapping[],
|
|
|
|
|
userId?: string,
|
|
|
|
|
entityId?: string
|
|
|
|
|
): Promise<{
|
|
|
|
|
results: EligibilityResult[]
|
|
|
|
|
tokensUsed: number
|
|
|
|
|
}> {
|
|
|
|
|
const results: EligibilityResult[] = []
|
|
|
|
|
let tokensUsed = 0
|
|
|
|
|
|
|
|
|
|
const userPrompt = `CRITERIA: ${criteriaText}
|
|
|
|
|
PROJECTS: ${JSON.stringify(anonymized)}
|
|
|
|
|
Evaluate eligibility for each project.`
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const params = buildCompletionParams(model, {
|
|
|
|
|
messages: [
|
|
|
|
|
{ role: 'system', content: AI_ELIGIBILITY_SYSTEM_PROMPT },
|
|
|
|
|
{ role: 'user', content: userPrompt },
|
|
|
|
|
],
|
|
|
|
|
jsonMode: true,
|
|
|
|
|
temperature: 0.3,
|
|
|
|
|
maxTokens: 4000,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const response = await openai.chat.completions.create(params)
|
|
|
|
|
const usage = extractTokenUsage(response)
|
|
|
|
|
tokensUsed = usage.totalTokens
|
|
|
|
|
|
|
|
|
|
// Log usage
|
|
|
|
|
await logAIUsage({
|
|
|
|
|
userId,
|
|
|
|
|
action: 'AWARD_ELIGIBILITY',
|
|
|
|
|
entityType: 'Award',
|
|
|
|
|
entityId,
|
|
|
|
|
model,
|
|
|
|
|
promptTokens: usage.promptTokens,
|
|
|
|
|
completionTokens: usage.completionTokens,
|
|
|
|
|
totalTokens: usage.totalTokens,
|
|
|
|
|
batchSize: anonymized.length,
|
|
|
|
|
itemsProcessed: anonymized.length,
|
|
|
|
|
status: 'SUCCESS',
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const content = response.choices[0]?.message?.content
|
|
|
|
|
if (!content) {
|
|
|
|
|
throw new Error('Empty response from AI')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const parsed = JSON.parse(content) as {
|
|
|
|
|
evaluations: Array<{
|
|
|
|
|
project_id: string
|
|
|
|
|
eligible: boolean
|
|
|
|
|
confidence: number
|
|
|
|
|
reasoning: string
|
|
|
|
|
}>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Map results back to real IDs
|
|
|
|
|
for (const eval_ of parsed.evaluations || []) {
|
|
|
|
|
const mapping = mappings.find((m) => m.anonymousId === eval_.project_id)
|
|
|
|
|
if (mapping) {
|
|
|
|
|
results.push({
|
|
|
|
|
projectId: mapping.realId,
|
|
|
|
|
eligible: eval_.eligible,
|
|
|
|
|
confidence: eval_.confidence,
|
|
|
|
|
reasoning: eval_.reasoning,
|
|
|
|
|
method: 'AI',
|
|
|
|
|
})
|
|
|
|
|
}
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
}
|
|
|
|
|
|
2026-02-03 11:58:12 +01:00
|
|
|
} catch (error) {
|
|
|
|
|
if (error instanceof SyntaxError) {
|
|
|
|
|
const parseError = createParseError(error.message)
|
|
|
|
|
logAIError('AwardEligibility', 'batch processing', parseError)
|
|
|
|
|
|
|
|
|
|
await logAIUsage({
|
|
|
|
|
userId,
|
|
|
|
|
action: 'AWARD_ELIGIBILITY',
|
|
|
|
|
entityType: 'Award',
|
|
|
|
|
entityId,
|
|
|
|
|
model,
|
|
|
|
|
promptTokens: 0,
|
|
|
|
|
completionTokens: 0,
|
|
|
|
|
totalTokens: tokensUsed,
|
|
|
|
|
batchSize: anonymized.length,
|
|
|
|
|
itemsProcessed: 0,
|
|
|
|
|
status: 'ERROR',
|
|
|
|
|
errorMessage: parseError.message,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Flag all for manual review
|
|
|
|
|
for (const mapping of mappings) {
|
|
|
|
|
results.push({
|
|
|
|
|
projectId: mapping.realId,
|
|
|
|
|
eligible: false,
|
|
|
|
|
confidence: 0,
|
|
|
|
|
reasoning: 'AI response parse error — requires manual review',
|
|
|
|
|
method: 'AI',
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
throw error
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return { results, tokensUsed }
|
|
|
|
|
}
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
|
|
|
|
|
export async function aiInterpretCriteria(
|
|
|
|
|
criteriaText: string,
|
2026-02-03 11:58:12 +01:00
|
|
|
projects: ProjectForEligibility[],
|
|
|
|
|
userId?: string,
|
|
|
|
|
awardId?: string
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
): Promise<EligibilityResult[]> {
|
|
|
|
|
const results: EligibilityResult[] = []
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const openai = await getOpenAI()
|
|
|
|
|
if (!openai) {
|
2026-02-03 11:58:12 +01:00
|
|
|
console.warn('[AI Eligibility] OpenAI not configured')
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
return projects.map((p) => ({
|
|
|
|
|
projectId: p.id,
|
|
|
|
|
eligible: false,
|
|
|
|
|
confidence: 0,
|
|
|
|
|
reasoning: 'AI unavailable — requires manual eligibility review',
|
|
|
|
|
method: 'AI' as const,
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const model = await getConfiguredModel()
|
2026-02-03 11:58:12 +01:00
|
|
|
console.log(`[AI Eligibility] Using model: ${model} for ${projects.length} projects`)
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
|
2026-02-03 11:58:12 +01:00
|
|
|
// Convert and anonymize projects
|
|
|
|
|
const projectsWithRelations = projects.map(toProjectWithRelations)
|
|
|
|
|
const { anonymized, mappings } = anonymizeProjectsForAI(projectsWithRelations, 'ELIGIBILITY')
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
|
2026-02-03 11:58:12 +01:00
|
|
|
// Validate anonymization
|
|
|
|
|
if (!validateAnonymizedProjects(anonymized)) {
|
|
|
|
|
console.error('[AI Eligibility] Anonymization validation failed')
|
|
|
|
|
throw new Error('GDPR compliance check failed: PII detected in anonymized data')
|
|
|
|
|
}
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
|
2026-02-03 11:58:12 +01:00
|
|
|
let totalTokens = 0
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
|
2026-02-03 11:58:12 +01:00
|
|
|
// Process in batches
|
|
|
|
|
for (let i = 0; i < anonymized.length; i += BATCH_SIZE) {
|
|
|
|
|
const batchAnon = anonymized.slice(i, i + BATCH_SIZE)
|
|
|
|
|
const batchMappings = mappings.slice(i, i + BATCH_SIZE)
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
|
2026-02-03 11:58:12 +01:00
|
|
|
console.log(`[AI Eligibility] Processing batch ${Math.floor(i / BATCH_SIZE) + 1}/${Math.ceil(anonymized.length / BATCH_SIZE)}`)
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
|
2026-02-03 11:58:12 +01:00
|
|
|
const { results: batchResults, tokensUsed } = await processEligibilityBatch(
|
|
|
|
|
openai,
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
model,
|
2026-02-03 11:58:12 +01:00
|
|
|
criteriaText,
|
|
|
|
|
batchAnon,
|
|
|
|
|
batchMappings,
|
|
|
|
|
userId,
|
|
|
|
|
awardId
|
|
|
|
|
)
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
|
2026-02-03 11:58:12 +01:00
|
|
|
results.push(...batchResults)
|
|
|
|
|
totalTokens += tokensUsed
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
}
|
2026-02-03 11:58:12 +01:00
|
|
|
|
|
|
|
|
console.log(`[AI Eligibility] Completed. Total tokens: ${totalTokens}`)
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const classified = classifyAIError(error)
|
|
|
|
|
logAIError('AwardEligibility', 'aiInterpretCriteria', classified)
|
|
|
|
|
|
|
|
|
|
// Log failed attempt
|
|
|
|
|
await logAIUsage({
|
|
|
|
|
userId,
|
|
|
|
|
action: 'AWARD_ELIGIBILITY',
|
|
|
|
|
entityType: 'Award',
|
|
|
|
|
entityId: awardId,
|
|
|
|
|
model: 'unknown',
|
|
|
|
|
promptTokens: 0,
|
|
|
|
|
completionTokens: 0,
|
|
|
|
|
totalTokens: 0,
|
|
|
|
|
batchSize: projects.length,
|
|
|
|
|
itemsProcessed: 0,
|
|
|
|
|
status: 'ERROR',
|
|
|
|
|
errorMessage: classified.message,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// Return all as needing manual review
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
return projects.map((p) => ({
|
|
|
|
|
projectId: p.id,
|
|
|
|
|
eligible: false,
|
|
|
|
|
confidence: 0,
|
2026-02-03 11:58:12 +01:00
|
|
|
reasoning: `AI error: ${classified.message}`,
|
Implement Prototype 1 improvements: unified members, project filters, audit expansion, filtering rounds, special awards
- Unified Member Management: merge /admin/users and /admin/mentors into /admin/members with role tabs, search, pagination
- Project List Filters: add search, multi-status filter, round/category/country selects, boolean toggles, URL persistence
- Audit Log Expansion: track logins, round state changes, evaluation submissions, file access, role changes via shared logAudit utility
- Founding Date Field: add foundedAt to Project model with CSV import support
- Filtering Round System: configurable rules (field-based, document check, AI screening), execution engine, results review with override/reinstate
- Special Awards System: named awards with eligibility criteria, dedicated jury, PICK_WINNER/RANKED/SCORED voting modes, AI eligibility
- Dashboard resilience: wrap heavy queries in try-catch to prevent error boundary on transient DB failures
- Reusable pagination component extracted to src/components/shared/pagination.tsx
- Old /admin/users and /admin/mentors routes redirect to /admin/members
- Prisma migration for all schema additions (additive, no data loss)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 16:58:29 +01:00
|
|
|
method: 'AI' as const,
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return results
|
|
|
|
|
}
|