diff --git a/server/providers/OpenAI.js b/server/providers/OpenAI.js index 19b0f52a3..570c3e919 100644 --- a/server/providers/OpenAI.js +++ b/server/providers/OpenAI.js @@ -240,12 +240,25 @@ class OpenAI { return resultBooks.map((book) => { const seriesName = this.normalizeSeriesName(book.seriesName) const sequence = this.normalizeSequence(book.sequence) + const reason = typeof book.reason === 'string' ? book.reason.trim() : '' if (seriesName && !sequence) { - throw new Error(`OpenAI returned a series without a valid sequence for "${book.id}"`) + Logger.warn(`[OpenAI] Series "${seriesName}" for book "${book.id}" did not include a valid sequence - skipping assignment`) + return { + id: book.id, + seriesName: null, + sequence: null, + reason: reason ? `${reason} (skipped due to missing or invalid sequence)` : 'Skipped due to missing or invalid sequence' + } } if (!seriesName && sequence) { - throw new Error(`OpenAI returned a sequence without a series for "${book.id}"`) + Logger.warn(`[OpenAI] Sequence "${sequence}" for book "${book.id}" did not include a series name - skipping assignment`) + return { + id: book.id, + seriesName: null, + sequence: null, + reason: reason ? `${reason} (skipped due to missing series name)` : 'Skipped due to missing series name' + } } if (seriesName && sequence) { @@ -259,7 +272,7 @@ class OpenAI { id: book.id, seriesName: null, sequence: null, - reason: typeof book.reason === 'string' ? `${book.reason.trim()} (skipped due to duplicate inferred sequence)` : 'Skipped due to duplicate inferred sequence' + reason: reason ? `${reason} (skipped due to duplicate inferred sequence)` : 'Skipped due to duplicate inferred sequence' } } seriesSequences.get(key).add(sequence) @@ -269,7 +282,7 @@ class OpenAI { id: book.id, seriesName, sequence, - reason: typeof book.reason === 'string' ? book.reason.trim() : '' + reason } }) } diff --git a/test/server/providers/OpenAI.test.js b/test/server/providers/OpenAI.test.js index fee086e4d..30ead5305 100644 --- a/test/server/providers/OpenAI.test.js +++ b/test/server/providers/OpenAI.test.js @@ -67,17 +67,34 @@ describe('OpenAI', () => { expect(result[1].sequence).to.equal('1.5') }) - it('rejects a series assignment without sequence', () => { - expect(() => - openAI.validateSeriesDetectionPayload( - { - books: [ - { id: 'a', seriesName: 'Series Name', sequence: null } - ] - }, - [{ id: 'a' }] - ) - ).to.throw('without a valid sequence') + it('skips a series assignment without sequence', () => { + const result = openAI.validateSeriesDetectionPayload( + { + books: [ + { id: 'a', seriesName: 'Series Name', sequence: null, reason: 'folder match' } + ] + }, + [{ id: 'a' }] + ) + + expect(result[0].seriesName).to.equal(null) + expect(result[0].sequence).to.equal(null) + expect(result[0].reason).to.contain('skipped due to missing or invalid sequence') + }) + + it('skips a sequence without series name', () => { + const result = openAI.validateSeriesDetectionPayload( + { + books: [ + { id: 'a', seriesName: null, sequence: '2', reason: 'sequence found' } + ] + }, + [{ id: 'a' }] + ) + + expect(result[0].seriesName).to.equal(null) + expect(result[0].sequence).to.equal(null) + expect(result[0].reason).to.contain('skipped due to missing series name') }) }) })