Fix AI tagging issues and improve error messages
Build and Push Docker Image / build (push) Successful in 9m33s
Details
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:
parent
6f6d5ef501
commit
7f95f681d6
|
|
@ -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) => {
|
||||||
|
if (result.errors && result.errors.length > 0) {
|
||||||
|
// 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(
|
toast.success(
|
||||||
`AI Tagging complete: ${result.processed} tagged, ${result.skipped} skipped, ${result.failed} failed`
|
`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()
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue