-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/gateway unified analysis #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
✅ Deploy Preview for crowncode-by-rthur ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces a unified analysis gateway to consolidate YouTube and file analysis workflows, reducing code duplication and standardizing error handling. The changes also update file size limits from 100MB to 30MB and add new backend error states for graceful degradation.
Key changes:
- Created
analysisGateway.tsto centralize analysis API calls for both YouTube and file sources - Updated file size limit from 100MB to 30MB (~6 minutes) with corresponding translations
- Added three new error codes for backend issues:
backend_not_configured,backend_unreachable, andbackend_unexpected_response
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| platform/hooks/analysisGateway.ts | New unified gateway that handles API calls for both YouTube and file analysis, with built-in error handling and validation |
| platform/hooks/useYouTubeAnalysis.ts | Refactored to use the new gateway, removing duplicate fetch logic and timeout handling |
| platform/hooks/useFileAnalysis.ts | Refactored to use the new gateway, replacing direct preview fallback with backend integration |
| platform/pages/ai-music-detection/index.tsx | Added error message resolution for the three new backend error codes |
| platform/locales/en.json | Updated file size limit messages and added translations for new backend error codes |
| platform/locales/tr.json | Updated file size limit messages and added Turkish translations for new backend error codes |
Comments suppressed due to low confidence (1)
platform/hooks/useYouTubeAnalysis.ts:86
- The host validation on line 73-76 is performed after URL parsing but before extracting the videoId. However, the logic on lines 78-86 checks specific hosts again. This creates redundancy - if isYouTubeHost is true on line 73, the subsequent checks on lines 78 and 80 are guaranteed to pass for at least one condition. Consider restructuring to eliminate the redundant host checks.
const isYouTubeHost = host.includes('youtube.com') || host.includes('youtu.be') || host.includes('music.youtube.com')
if (!isYouTubeHost) {
return null
}
if (host === 'youtu.be' || host === 'www.youtu.be') {
videoId = path.replace('/', '').split('/')[0] || null
} else if (host.includes('youtube.com') || host.includes('music.youtube.com')) {
if (path === '/watch') {
videoId = params.get('v')
} else if (path.startsWith('/shorts/') || path.startsWith('/live/') || path.startsWith('/embed/')) {
videoId = path.split('/')[2] || null
}
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return | ||
| } | ||
|
|
||
| if (gatewayError === 'backend_not_configured' || gatewayError === 'backend_unreachable' || gatewayError === 'backend_unexpected_response') { |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check for 'backend_not_configured' on line 197 is unreachable. If apiBaseUrl is undefined, the code already calls fallbackToPreview('backend_not_configured') on line 180 before reaching the analyzeSource call. The analyzeSource function will also return 'backend_not_configured' when apiBaseUrl is falsy, but this code path is never executed because of the early return on line 181. Consider removing 'backend_not_configured' from this condition.
| if (gatewayError === 'backend_not_configured' || gatewayError === 'backend_unreachable' || gatewayError === 'backend_unexpected_response') { | |
| if (gatewayError === 'backend_unreachable' || gatewayError === 'backend_unexpected_response') { |
| } catch (fetchError) { | ||
| warningsBuffer.push('backend_unreachable') | ||
| const elapsedSec = (Date.now() - startTimeRef.current) / 1000 | ||
| setAnalysisResult(buildPreviewResult(parsed, url, elapsedSec, warningsBuffer)) | ||
| setWarnings(warningsBuffer) | ||
| setProcessingState('complete') | ||
| fallbackToPreview('backend_unreachable') | ||
| } |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The catch block on line 262-264 is redundant because analyzeSource already wraps its fetch call in a try-catch block and returns 'backend_unreachable' on errors (see analysisGateway.ts lines 72-73). This means the catch block here will never be reached since analyzeSource doesn't throw exceptions. Consider removing this catch block to simplify the error handling flow.
| try { | ||
| setProcessingState('analyzing') | ||
| const { result, error: gatewayError } = await analyzeSource(apiBaseUrl, { | ||
| sourceType: 'file', | ||
| file: selectedFile | ||
| }) | ||
|
|
||
| if (result) { | ||
| setAnalysisResult(result) | ||
| setProcessingState('complete') | ||
| return | ||
| } | ||
|
|
||
| if (gatewayError === 'backend_not_configured' || gatewayError === 'backend_unreachable' || gatewayError === 'backend_unexpected_response') { | ||
| fallbackToPreview(gatewayError) | ||
| } else { | ||
| setError(gatewayError || 'unsupportedFileType') | ||
| setProcessingState('error') | ||
| } | ||
| } catch (fetchError) { | ||
| fallbackToPreview('backend_unreachable') |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The catch block on line 203-205 is redundant because analyzeSource already wraps its fetch call in a try-catch block and returns 'backend_unreachable' on errors (see analysisGateway.ts lines 72-73). This means the catch block here will never be reached since analyzeSource doesn't throw exceptions. Consider removing this catch block to simplify the error handling flow.
| try { | |
| setProcessingState('analyzing') | |
| const { result, error: gatewayError } = await analyzeSource(apiBaseUrl, { | |
| sourceType: 'file', | |
| file: selectedFile | |
| }) | |
| if (result) { | |
| setAnalysisResult(result) | |
| setProcessingState('complete') | |
| return | |
| } | |
| if (gatewayError === 'backend_not_configured' || gatewayError === 'backend_unreachable' || gatewayError === 'backend_unexpected_response') { | |
| fallbackToPreview(gatewayError) | |
| } else { | |
| setError(gatewayError || 'unsupportedFileType') | |
| setProcessingState('error') | |
| } | |
| } catch (fetchError) { | |
| fallbackToPreview('backend_unreachable') | |
| setProcessingState('analyzing') | |
| const { result, error: gatewayError } = await analyzeSource(apiBaseUrl, { | |
| sourceType: 'file', | |
| file: selectedFile | |
| }) | |
| if (result) { | |
| setAnalysisResult(result) | |
| setProcessingState('complete') | |
| return | |
| } | |
| if (gatewayError === 'backend_not_configured' || gatewayError === 'backend_unreachable' || gatewayError === 'backend_unexpected_response') { | |
| fallbackToPreview(gatewayError) | |
| } else { | |
| setError(gatewayError || 'unsupportedFileType') | |
| setProcessingState('error') |
| setWarnings(warningsBuffer) | ||
| setProcessingState('complete') | ||
| return | ||
| if (gatewayError === 'backend_not_configured' || gatewayError === 'backend_unreachable' || gatewayError === 'backend_unexpected_response') { |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check for 'backend_not_configured' on line 256 is unreachable. If apiBaseUrl is undefined, the code already calls fallbackToPreview('backend_not_configured') on line 239 before reaching the analyzeSource call. The analyzeSource function will also return 'backend_not_configured' when apiBaseUrl is falsy, but this code path is never executed because of the early return on line 240. Consider removing 'backend_not_configured' from this condition.
| if (gatewayError === 'backend_not_configured' || gatewayError === 'backend_unreachable' || gatewayError === 'backend_unexpected_response') { | |
| if (gatewayError === 'backend_unreachable' || gatewayError === 'backend_unexpected_response') { |
| return { result: null, error: 'backend_unexpected_response' as AnalysisErrorCode } | ||
| } | ||
|
|
||
| return { result: data.result, error: null } |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The warnings from the backend response are being lost. The gateway's analyzeSource function receives warnings in the backend response (data.warnings on line 13 of analysisGateway.ts), but only returns the result and error. When a successful result is returned, the warnings are not propagated to the caller. This means useYouTubeAnalysis won't be able to set the warnings state on line 227, and they'll be lost. Consider extending the return type of analyzeSource to include warnings.
| const elapsedSec = (Date.now() - startTimeRef.current) / 1000 | ||
| setAnalysisResult(buildPreviewResult(parsed, url, elapsedSec, warningsBuffer)) | ||
| setWarnings(warningsBuffer) | ||
| if (result) { |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a successful result is returned from analyzeSource, the warnings state is not being updated. Line 251-253 sets the analysis result and completes processing, but never calls setWarnings. This means any warnings from the backend response will be lost. The warnings should be extracted from the result if available, or the gateway should be updated to return warnings separately.
| if (result) { | |
| if (result) { | |
| const resultWarnings = | |
| typeof (result as any) === 'object' && result !== null && Array.isArray((result as any).warnings) | |
| ? (result as any).warnings | |
| : [] | |
| setWarnings(resultWarnings) |
| const isYouTubeHost = host.includes('youtube.com') || host.includes('youtu.be') || host.includes('music.youtube.com') | ||
| if (!isYouTubeHost) { | ||
| return null | ||
| } | ||
|
|
||
| if (host === 'youtu.be' || host === 'www.youtu.be') { | ||
| videoId = path.replace('/', '').split('/')[0] || null | ||
| } else if (host.includes('youtube.com')) { | ||
| } else if (host.includes('youtube.com') || host.includes('music.youtube.com')) { |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check for 'music.youtube.com' on line 73 is redundant because 'music.youtube.com' contains 'youtube.com', so it would already be matched by the first condition. This makes the explicit check for 'music.youtube.com' unnecessary in both lines 73 and 80.
| case 'unsupportedFileType': | ||
| return t.aiDetection.errors?.unsupportedFileType || t.aiDetection.error.title | ||
| case 'fileTooLarge': | ||
| return t.aiDetection.errors?.fileTooLarge || t.aiDetection.error.title | ||
| case 'fileTooSmall': | ||
| return t.aiDetection.errors?.fileTooSmall || t.aiDetection.error.title | ||
| case 'invalidFileName': | ||
| return t.aiDetection.errors?.invalidFileName || t.aiDetection.error.title | ||
| case 'backend_not_configured': | ||
| return t.aiDetection.errors?.backend_not_configured || t.aiDetection.error.title | ||
| case 'backend_unreachable': | ||
| return t.aiDetection.errors?.backend_unreachable || t.aiDetection.error.title | ||
| case 'backend_unexpected_response': | ||
| return t.aiDetection.errors?.backend_unexpected_response || t.aiDetection.error.title | ||
| default: | ||
| return t.aiDetection.error.title |
Copilot
AI
Dec 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The indentation is inconsistent here. Lines 123-130 should have 6 spaces of indentation to match lines 117-122, but they only have 4 spaces. This makes the code structure unclear and violates formatting consistency.
| case 'unsupportedFileType': | |
| return t.aiDetection.errors?.unsupportedFileType || t.aiDetection.error.title | |
| case 'fileTooLarge': | |
| return t.aiDetection.errors?.fileTooLarge || t.aiDetection.error.title | |
| case 'fileTooSmall': | |
| return t.aiDetection.errors?.fileTooSmall || t.aiDetection.error.title | |
| case 'invalidFileName': | |
| return t.aiDetection.errors?.invalidFileName || t.aiDetection.error.title | |
| case 'backend_not_configured': | |
| return t.aiDetection.errors?.backend_not_configured || t.aiDetection.error.title | |
| case 'backend_unreachable': | |
| return t.aiDetection.errors?.backend_unreachable || t.aiDetection.error.title | |
| case 'backend_unexpected_response': | |
| return t.aiDetection.errors?.backend_unexpected_response || t.aiDetection.error.title | |
| default: | |
| return t.aiDetection.error.title | |
| case 'unsupportedFileType': | |
| return t.aiDetection.errors?.unsupportedFileType || t.aiDetection.error.title | |
| case 'fileTooLarge': | |
| return t.aiDetection.errors?.fileTooLarge || t.aiDetection.error.title | |
| case 'fileTooSmall': | |
| return t.aiDetection.errors?.fileTooSmall || t.aiDetection.error.title | |
| case 'invalidFileName': | |
| return t.aiDetection.errors?.invalidFileName || t.aiDetection.error.title | |
| case 'backend_not_configured': | |
| return t.aiDetection.errors?.backend_not_configured || t.aiDetection.error.title | |
| case 'backend_unreachable': | |
| return t.aiDetection.errors?.backend_unreachable || t.aiDetection.error.title | |
| case 'backend_unexpected_response': | |
| return t.aiDetection.errors?.backend_unexpected_response || t.aiDetection.error.title | |
| default: | |
| return t.aiDetection.error.title |

No description provided.