Conversation
- 이미지 메타데이터 활용하여 이미지 설명 생성
- 주석 제거
📝 WalkthroughWalkthroughThis PR introduces image description functionality by adding a new OpenAI-powered API endpoint, implementing backend repository logic, extending UI state management with toast notifications, and creating modal bottom sheet components to display AI-generated image descriptions alongside user feedback mechanisms. Changes
Sequence DiagramsequenceDiagram
actor User
participant UI as PhotoDetail UI
participant Presenter as PhotoDetailPresenter
participant Repo as ImageAnalysisRepository
participant OpenAI as OpenAI Service
participant DB as Local Database
User->>UI: Click Create Image Description
UI->>Presenter: OnCreateImageDescriptionButtonClick(uri)
Presenter->>Presenter: Toggle Loading = true
par Parallel Operations
Presenter->>Repo: Retrieve file name
Presenter->>DB: Fetch database name
end
Repo->>Repo: Build prompt with triple data
Repo->>OpenAI: Send chat completion request
OpenAI-->>Repo: Return AI-generated description
Repo-->>Presenter: Result<String>
alt Success
Presenter->>Presenter: Update imageDescription state
Presenter->>UI: Render ModalBottomSheet with description
else Error
Presenter->>Presenter: Handle exception
Presenter->>UI: Show toast message
end
Presenter->>Presenter: Toggle Loading = false
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly Related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
@feature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailUi.kt:
- Around line 45-49: LaunchedEffect currently only opens the sheet when
state.imageDescription is non-null but never closes it; update the
LaunchedEffect watching state.imageDescription to set isSheetOpen =
(state.imageDescription != null) so the sheet closes when imageDescription
becomes null (i.e., replace the conditional block with a single assignment
inside LaunchedEffect that sets isSheetOpen based on state.imageDescription).
🧹 Nitpick comments (5)
core/data/api/src/main/java/com/example/metasearch/core/data/api/repository/ImageAnalysisRepository.kt (1)
10-10: Consider return type semantics.
Result<String?>allows three states: success with value, success with null, and failure. Ifnullrepresents "no description available" as a valid outcome, this is appropriate. Otherwise, considerResult<String>with a descriptive error for the no-description case to simplify consumer logic.feature/detail/src/main/java/com/example/metasearch/feature/detail/photo/component/ImageDescriptionBottomSheetContent.kt (1)
23-25: Consider adding a text style to the title for consistency.The description
TextusesMetaSearchTheme.typography.bodyLarge, but the titleTexthas no style specified, defaulting to Material3's base style. For visual consistency, consider applying an appropriate typography style fromMetaSearchTheme.Suggested fix
Text( text = stringResource(R.string.photo_detail_screen_openai_bottom_sheet_title), + style = MetaSearchTheme.typography.titleMedium, )feature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailUi.kt (1)
86-95: Guard against empty description when sheet is open.While the current flow should prevent this scenario, if
isSheetOpenbecomes true butimageDescriptionis null (due to race conditions or future changes), the component will render with an empty string. Consider adding a defensive check.Suggested fix
- if (isSheetOpen) { + if (isSheetOpen && state.imageDescription != null) { ModalBottomSheet( onDismissRequest = { isSheetOpen = false }, sheetState = sheetState, containerColor = LightPink, dragHandle = { BottomSheetDefaults.DragHandle() }, ) { - ImageDescriptionBottomSheetContent(state.imageDescription ?: "") + ImageDescriptionBottomSheetContent(state.imageDescription) } }core/data/impl/src/main/java/com/example/metasearch/core/data/impl/repository/ImageAnalysisRepositoryImpl.kt (1)
115-120: Consider extracting the model name to a constant.The model
"gpt-3.5-turbo"is hardcoded. Consider moving it toPromptConstantsor a dedicated configuration for easier maintenance and potential future model upgrades.Suggested fix
+ // In PromptConstants.kt, add: + // const val OPENAI_MODEL = "gpt-3.5-turbo" val imageDescriptionResponse = openAIService.createChatCompletion( OpenAIRequest( - model = "gpt-3.5-turbo", + model = PromptConstants.OPENAI_MODEL, messages = listOf(OpenAIMessage(role = "user", content = fullPrompt)), ), )feature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailPresenter.kt (1)
53-57: Null check is redundant.The
ImageAnalysisRepositoryImpl.getImageDescriptionreturnsResult<String>(non-nullable). On success,descriptionis guaranteed to be non-null, making theif (description != null)check unnecessary.Suggested fix
.onSuccess { description -> - if (description != null) { - imageDescription = description - } + imageDescription = description }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
core/common/src/main/java/com/example/metasearch/core/common/constants/PromptConstants.ktcore/data/api/src/main/java/com/example/metasearch/core/data/api/repository/ImageAnalysisRepository.ktcore/data/impl/src/main/java/com/example/metasearch/core/data/impl/repository/ImageAnalysisRepositoryImpl.ktcore/network/src/main/java/com/example/metasearch/core/network/service/WebService.ktfeature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailPresenter.ktfeature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailToastEffect.ktfeature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailUi.ktfeature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailUiState.ktfeature/detail/src/main/java/com/example/metasearch/feature/detail/photo/component/ImageDescriptionBottomSheetContent.ktfeature/detail/src/main/res/values/strings.xmlfeature/graph/src/main/java/com/example/metasearch/feature/graph/GraphPresenter.kt
💤 Files with no reviewable changes (1)
- feature/graph/src/main/java/com/example/metasearch/feature/graph/GraphPresenter.kt
🧰 Additional context used
🧬 Code graph analysis (3)
feature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailUi.kt (4)
feature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailToastEffect.kt (1)
PhotoDetailToastEffect(7-19)core/ui/src/main/java/com/example/metasearch/core/ui/component/MetaSearchLoadingIndicator.kt (1)
MetaSearchLoadingIndicator(16-31)feature/detail/src/main/java/com/example/metasearch/feature/detail/photo/component/ImageDescriptionBottomSheetContent.kt (1)
ImageDescriptionBottomSheetContent(15-32)core/designsystem/src/main/java/com/example/metasearch/core/designsystem/component/MetaSearchToast.kt (1)
MetaSearchToast(22-57)
core/data/impl/src/main/java/com/example/metasearch/core/data/impl/repository/ImageAnalysisRepositoryImpl.kt (1)
core/common/src/main/java/com/example/metasearch/core/common/utils/RunCatching.kt (1)
runSuspendCatching(14-28)
feature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailPresenter.kt (1)
core/common/src/main/java/com/example/metasearch/core/common/utils/Exception.kt (1)
handleException(10-34)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: ci-build
🔇 Additional comments (10)
feature/detail/src/main/res/values/strings.xml (1)
29-29: LGTM!The new string resource follows the existing naming convention and appropriately supports the AI image analysis feature.
feature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailToastEffect.kt (1)
7-19: LGTM!The toast effect implementation correctly uses
LaunchedEffectkeyed ontoastMessage, ensuring each new message gets a fresh 1.5-second timer and prior effects are cancelled on message change.core/common/src/main/java/com/example/metasearch/core/common/constants/PromptConstants.kt (1)
38-48: LGTM!The new prompt constant is well-structured with clear instructions for the AI to generate natural, concise image descriptions in a polite Korean tone.
feature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailUiState.kt (2)
6-12: LGTM!The new state properties
toastMessageandimageDescriptionare well-designed with appropriate nullable types and default values. The state structure follows Circuit UI patterns correctly.
46-50: LGTM!The
ShowToastandHideToastevents are cleanly defined and integrate well with the existing event pattern.feature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailUi.kt (1)
97-100: LGTM!The toast integration with
MetaSearchToastand visibility driven bystate.toastMessageis correctly implemented.core/data/impl/src/main/java/com/example/metasearch/core/data/impl/repository/ImageAnalysisRepositoryImpl.kt (2)
103-125: LGTM on the overall structure.The implementation correctly uses
runSuspendCatchingfor error handling andcoroutineScopewithasyncfor parallel retrieval of filename and database name. The error handling properly propagates failures.
113-123: Verify timeout configuration for external API calls.The
webService.fetchTripleDataandopenAIService.createChatCompletioncalls have no explicit timeout. If the OkHttp/Retrofit client doesn't have appropriate timeouts configured, these calls could hang indefinitely, blocking the coroutine.feature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailPresenter.kt (2)
48-69: LGTM on the image description fetch flow.The coroutine-based async pattern is well-implemented with proper loading state management. The error handling via
handleExceptioncorrectly routes error messages to the toast.
89-89:ShowToastevent appears unused.The
ShowToastevent handler is implemented, but the current flow setstoastMessagedirectly via thehandleExceptioncallback. Either remove this event if not needed, or use it consistently for showing toast messages.#!/bin/bash # Check if ShowToast event is used anywhere in the codebase rg -n "ShowToast" --type=kotlin
| LaunchedEffect(state.imageDescription) { | ||
| if (state.imageDescription != null) { | ||
| isSheetOpen = true | ||
| } | ||
| } |
There was a problem hiding this comment.
Sheet doesn't close when imageDescription becomes null.
The LaunchedEffect only opens the sheet when imageDescription is non-null, but never closes it. If imageDescription is reset to null (e.g., state reset, error recovery), the sheet remains open with stale or empty content.
Suggested fix
LaunchedEffect(state.imageDescription) {
- if (state.imageDescription != null) {
- isSheetOpen = true
- }
+ isSheetOpen = state.imageDescription != null
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| LaunchedEffect(state.imageDescription) { | |
| if (state.imageDescription != null) { | |
| isSheetOpen = true | |
| } | |
| } | |
| LaunchedEffect(state.imageDescription) { | |
| isSheetOpen = state.imageDescription != null | |
| } |
🤖 Prompt for AI Agents
In
@feature/detail/src/main/java/com/example/metasearch/feature/detail/photo/PhotoDetailUi.kt
around lines 45 - 49, LaunchedEffect currently only opens the sheet when
state.imageDescription is non-null but never closes it; update the
LaunchedEffect watching state.imageDescription to set isSheetOpen =
(state.imageDescription != null) so the sheet closes when imageDescription
becomes null (i.e., replace the conditional block with a single assignment
inside LaunchedEffect that sets isSheetOpen based on state.imageDescription).
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Refactor
✏️ Tip: You can customize this high-level summary in your review settings.