(raw: string, batchIds: Set<string>)
| 133 | } |
| 134 | |
| 135 | function parseResponse(raw: string, batchIds: Set<string>): LlmClassification[] { |
| 136 | // Extract JSON array from response (model might add markdown fences or commentary) |
| 137 | const jsonArray = extractJsonArray(raw); |
| 138 | if (!jsonArray) throw new Error('No JSON array found in response'); |
| 139 | |
| 140 | const parsed = JSON.parse(jsonArray); |
| 141 | if (!Array.isArray(parsed)) throw new Error('Response is not an array'); |
| 142 | |
| 143 | const results: LlmClassification[] = []; |
| 144 | for (const item of parsed) { |
| 145 | if (!item.id || !batchIds.has(item.id)) continue; |
| 146 | |
| 147 | const rawArr = item.categories ?? item.domains ?? []; |
| 148 | const categories = (Array.isArray(rawArr) ? rawArr : []) |
| 149 | .filter((c: string) => typeof c === 'string' && c.length > 0) |
| 150 | .map((c: string) => c.toLowerCase().trim()); |
| 151 | const primary = (typeof item.primary === 'string' && item.primary.length > 0) |
| 152 | ? item.primary.toLowerCase().trim() |
| 153 | : categories[0]; |
| 154 | |
| 155 | if (categories.length > 0 && primary) { |
| 156 | results.push({ id: item.id, categories, primary }); |
| 157 | } |
| 158 | } |
| 159 | return results; |
| 160 | } |
| 161 | |
| 162 | // ── Main classification pipeline ──────────────────────────────────────── |
| 163 |
no test coverage detected