feat: document language checker on round overview
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m15s

- New roundLanguageSummary query in file router aggregates per-round document
  language data from existing detectedLang/langConfidence fields
- Document Languages card on round overview tab shows analysis status and
  flags non-English documents grouped by project with confidence scores
- Green border when all documents are English, amber when issues detected
- Project names link to project detail page for easy navigation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 11:53:43 +01:00
parent d4c946470a
commit 3180bfa946
2 changed files with 135 additions and 0 deletions

View File

@@ -1622,4 +1622,62 @@ export const fileRouter = router({
const { analyzeAllUnanalyzed } = await import('../services/document-analyzer')
return analyzeAllUnanalyzed()
}),
/**
* Get document language summary for a specific round.
* Returns per-project file language data, flagging non-English documents.
*/
roundLanguageSummary: adminProcedure
.input(z.object({ roundId: z.string() }))
.query(async ({ ctx, input }) => {
const files = await ctx.prisma.projectFile.findMany({
where: { roundId: input.roundId },
select: {
id: true,
fileName: true,
fileType: true,
mimeType: true,
pageCount: true,
detectedLang: true,
langConfidence: true,
analyzedAt: true,
project: { select: { id: true, title: true } },
},
orderBy: { createdAt: 'desc' },
})
const totalFiles = files.length
const analyzedFiles = files.filter((f) => f.analyzedAt !== null)
const nonEnglish = analyzedFiles.filter(
(f) => f.detectedLang && f.detectedLang !== 'eng' && f.detectedLang !== 'und' && (f.langConfidence ?? 0) >= 0.4
)
const unanalyzed = files.filter((f) => f.analyzedAt === null)
// Group non-English files by project
const projectMap = new Map<string, {
projectId: string
projectTitle: string
files: typeof nonEnglish
}>()
for (const file of nonEnglish) {
const existing = projectMap.get(file.project.id)
if (existing) {
existing.files.push(file)
} else {
projectMap.set(file.project.id, {
projectId: file.project.id,
projectTitle: file.project.title,
files: [file],
})
}
}
return {
totalFiles,
analyzedCount: analyzedFiles.length,
unanalyzedCount: unanalyzed.length,
nonEnglishCount: nonEnglish.length,
flaggedProjects: Array.from(projectMap.values()),
}
}),
})