Fix AI tagging issues and improve error messages
Build and Push Docker Image / build (push) Successful in 9m33s Details

- Fall back to ai_enabled setting if ai_tagging_enabled not set
- Check both tags array and projectTags relationship for untagged projects
- Add detailed logging for debugging
- Show errors in toast instead of just counts
- Handle "no projects to tag" case with appropriate message
- Add early checks for OpenAI config and available tags

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Matt 2026-02-05 09:24:44 +01:00
parent 6f6d5ef501
commit 7f95f681d6
2 changed files with 77 additions and 23 deletions

View File

@ -252,9 +252,16 @@ export default function ProjectsPage() {
// AI batch tagging mutation // AI batch tagging mutation
const batchTagProjects = trpc.tag.batchTagProjects.useMutation({ const batchTagProjects = trpc.tag.batchTagProjects.useMutation({
onSuccess: (result) => { onSuccess: (result) => {
toast.success( if (result.errors && result.errors.length > 0) {
`AI Tagging complete: ${result.processed} tagged, ${result.skipped} skipped, ${result.failed} failed` // Show first error if there are any
) toast.error(`AI Tagging issue: ${result.errors[0]}`)
} else if (result.processed === 0 && result.skipped === 0 && result.failed === 0) {
toast.info('No projects to tag - all projects in this round already have tags')
} else {
toast.success(
`AI Tagging complete: ${result.processed} tagged, ${result.skipped} skipped, ${result.failed} failed`
)
}
setAiTagDialogOpen(false) setAiTagDialogOpen(false)
setSelectedRoundForTagging('') setSelectedRoundForTagging('')
utils.project.list.invalidate() utils.project.list.invalidate()

View File

@ -101,15 +101,23 @@ async function getTaggingSettings(): Promise<{
const settings = await prisma.systemSettings.findMany({ const settings = await prisma.systemSettings.findMany({
where: { where: {
key: { key: {
in: ['ai_tagging_enabled', 'ai_tagging_max_tags'], in: ['ai_tagging_enabled', 'ai_tagging_max_tags', 'ai_enabled'],
}, },
}, },
}) })
const settingsMap = new Map(settings.map((s) => [s.key, s.value])) const settingsMap = new Map(settings.map((s) => [s.key, s.value]))
// AI tagging is enabled if:
// 1. ai_tagging_enabled is explicitly 'true', OR
// 2. ai_tagging_enabled is not set but ai_enabled is 'true' (fall back to general AI setting)
const taggingEnabled = settingsMap.get('ai_tagging_enabled')
const aiEnabled = settingsMap.get('ai_enabled')
const enabled = taggingEnabled === 'true' || (taggingEnabled === undefined && aiEnabled === 'true')
return { return {
enabled: settingsMap.get('ai_tagging_enabled') === 'true', enabled,
maxTags: parseInt(settingsMap.get('ai_tagging_max_tags') || String(DEFAULT_MAX_TAGS)), maxTags: parseInt(settingsMap.get('ai_tagging_max_tags') || String(DEFAULT_MAX_TAGS)),
} }
} }
@ -409,34 +417,73 @@ export async function batchTagProjects(
onProgress?: (processed: number, total: number) => void onProgress?: (processed: number, total: number) => void
): Promise<BatchTaggingResult> { ): Promise<BatchTaggingResult> {
const settings = await getTaggingSettings() const settings = await getTaggingSettings()
console.log('[AI Tagging] Settings:', settings)
if (!settings.enabled) { if (!settings.enabled) {
console.log('[AI Tagging] AI tagging is disabled in settings')
return { return {
processed: 0, processed: 0,
failed: 0, failed: 0,
skipped: 0, skipped: 0,
errors: ['AI tagging is disabled'], errors: ['AI tagging is disabled. Enable it in Settings > AI or set ai_enabled to true.'],
results: [], results: [],
} }
} }
// Get untagged projects in round // Check if OpenAI is configured
const projects = await prisma.project.findMany({ const openai = await getOpenAI()
where: { if (!openai) {
roundId, console.log('[AI Tagging] OpenAI is not configured')
projectTags: { none: {} }, // Only projects with no tags
},
include: {
files: { select: { fileType: true } },
_count: { select: { teamMembers: true, files: true } },
},
})
if (projects.length === 0) {
return { return {
processed: 0, processed: 0,
failed: 0, failed: 0,
skipped: 0, skipped: 0,
errors: [], errors: ['OpenAI API is not configured. Add your API key in Settings > AI.'],
results: [],
}
}
// Check if there are any available tags
const availableTags = await getAvailableTags()
console.log(`[AI Tagging] Found ${availableTags.length} available expertise tags`)
if (availableTags.length === 0) {
return {
processed: 0,
failed: 0,
skipped: 0,
errors: ['No expertise tags defined. Create tags in Settings > Tags first.'],
results: [],
}
}
// Get ALL projects in round to check their tag status
const allProjects = await prisma.project.findMany({
where: { roundId },
include: {
files: { select: { fileType: true } },
_count: { select: { teamMembers: true, files: true } },
projectTags: { select: { tagId: true } },
},
})
console.log(`[AI Tagging] Found ${allProjects.length} total projects in round`)
// Filter to only projects that truly have no tags (empty tags array AND no projectTags)
const untaggedProjects = allProjects.filter(p =>
(p.tags.length === 0) && (p.projectTags.length === 0)
)
const alreadyTaggedCount = allProjects.length - untaggedProjects.length
console.log(`[AI Tagging] ${untaggedProjects.length} untagged projects, ${alreadyTaggedCount} already have tags`)
if (untaggedProjects.length === 0) {
return {
processed: 0,
failed: 0,
skipped: alreadyTaggedCount,
errors: alreadyTaggedCount > 0
? []
: ['No projects found in this round'],
results: [], results: [],
} }
} }
@ -446,8 +493,8 @@ export async function batchTagProjects(
let failed = 0 let failed = 0
const errors: string[] = [] const errors: string[] = []
for (let i = 0; i < projects.length; i++) { for (let i = 0; i < untaggedProjects.length; i++) {
const project = projects[i] const project = untaggedProjects[i]
try { try {
const result = await tagProject(project.id, userId) const result = await tagProject(project.id, userId)
results.push(result) results.push(result)
@ -459,7 +506,7 @@ export async function batchTagProjects(
// Report progress // Report progress
if (onProgress) { if (onProgress) {
onProgress(i + 1, projects.length) onProgress(i + 1, untaggedProjects.length)
} }
} }