@@ -9,6 +9,9 @@ import io.github.jja08111.core.common.di.IoDispatcher
9
9
import io.github.jja08111.core.common.image.BitmapCreator
10
10
import io.jja08111.gemini.database.entity.ModelResponseStateEntity
11
11
import io.jja08111.gemini.feature.chat.data.BuildConfig
12
+ import io.jja08111.gemini.feature.chat.data.exception.EmptyContentException
13
+ import io.jja08111.gemini.feature.chat.data.exception.EmptyMessageGroupsOnRegenerationException
14
+ import io.jja08111.gemini.feature.chat.data.exception.NotJoinedException
12
15
import io.jja08111.gemini.feature.chat.data.extension.toContents
13
16
import io.jja08111.gemini.feature.chat.data.extension.toResponseContentPartials
14
17
import io.jja08111.gemini.feature.chat.data.model.AttachedImage
@@ -27,7 +30,6 @@ import kotlinx.coroutines.flow.Flow
27
30
import kotlinx.coroutines.flow.catch
28
31
import kotlinx.coroutines.flow.collect
29
32
import kotlinx.coroutines.flow.first
30
- import kotlinx.coroutines.flow.flowOf
31
33
import kotlinx.coroutines.flow.onCompletion
32
34
import kotlinx.coroutines.flow.onEach
33
35
import kotlinx.coroutines.launch
@@ -61,116 +63,118 @@ class GenerativeChatRepository @Inject constructor(
61
63
candidateCount = CANDIDATE_COUNT
62
64
},
63
65
)
64
- return try {
65
- chatLocalDataSource.getMessageGroupStream(roomId)
66
- } catch (e: Exception ) {
67
- flowOf(emptyList())
68
- }
66
+ return chatLocalDataSource.getMessageGroupStream(roomId)
69
67
}
70
68
71
69
override suspend fun sendMessage (
72
70
message : String ,
73
71
images : List <AttachedImage >,
74
72
onRoomCreated : (Flow <List <MessageGroup >>) -> Unit ,
75
73
): Result <Unit > {
76
- val roomId = joinedRoomId ? : throwNotJoinedError()
77
- val model = generativeModel ? : throwNotJoinedError()
78
- val messageGroupStream = chatLocalDataSource.getMessageGroupStream(roomId)
79
- val messageGroups = messageGroupStream.first()
80
- val isNewChat = messageGroups.isEmpty()
81
-
82
- if (isNewChat) {
83
- val title = when {
84
- message.isNotEmpty() -> message
85
- images.isNotEmpty() -> " Image question"
86
- else -> error(" Message is empty with null image" )
74
+ return runCatching {
75
+ val roomId = joinedRoomId ? : throw NotJoinedException ()
76
+ val model = generativeModel ? : throw NotJoinedException ()
77
+ val messageGroupStream = chatLocalDataSource.getMessageGroupStream(roomId)
78
+ val messageGroups = messageGroupStream.first()
79
+ val isNewChat = messageGroups.isEmpty()
80
+
81
+ if (isNewChat) {
82
+ val title = when {
83
+ message.isNotEmpty() -> message
84
+ images.isNotEmpty() -> " Image question"
85
+ else -> throw EmptyContentException ()
86
+ }
87
+ chatLocalDataSource.insertRoom(roomId = roomId, title = title)
88
+ onRoomCreated(messageGroupStream)
87
89
}
88
- chatLocalDataSource.insertRoom(roomId = roomId, title = title)
89
- onRoomCreated(messageGroupStream)
90
- }
91
90
92
- val promptId = createId()
93
- val responseTextBuilders = List (CANDIDATE_COUNT ) { ResponseTextBuilder () }
94
- val parentModelResponseId = messageGroups.lastOrNull()?.selectedResponse?.id
95
- val imageBitmaps = images.map {
96
- when (it) {
97
- is AttachedImage .Bitmap -> it.bitmap
98
- is AttachedImage .Uri -> bitmapCreator.create(it.uri)
91
+ val promptId = createId()
92
+ val responseTextBuilders = List (CANDIDATE_COUNT ) { ResponseTextBuilder () }
93
+ val parentModelResponseId = messageGroups.lastOrNull()?.selectedResponse?.id
94
+ val imageBitmaps = images.map {
95
+ when (it) {
96
+ is AttachedImage .Bitmap -> it.bitmap
97
+ is AttachedImage .Uri -> bitmapCreator.create(it.uri)
98
+ }
99
99
}
100
- }
101
100
102
- chatLocalDataSource.insertInitialMessageGroup(
103
- prompt = message,
104
- imageBitmaps = imageBitmaps,
105
- roomId = roomId,
106
- promptId = promptId,
107
- responseIds = responseTextBuilders.map { it.id },
108
- parentModelResponseId = parentModelResponseId,
109
- )
110
-
111
- return model.generateTextMessageStream(
112
- message = message,
113
- images = imageBitmaps,
114
- history = messageGroups.flatMap(MessageGroup ::toContents),
115
- promptId = promptId,
116
- responseTextBuilders = responseTextBuilders,
117
- )
101
+ chatLocalDataSource.insertInitialMessageGroup(
102
+ prompt = message,
103
+ imageBitmaps = imageBitmaps,
104
+ roomId = roomId,
105
+ promptId = promptId,
106
+ responseIds = responseTextBuilders.map { it.id },
107
+ parentModelResponseId = parentModelResponseId,
108
+ )
109
+
110
+ return model.generateTextMessageStream(
111
+ message = message,
112
+ images = imageBitmaps,
113
+ history = messageGroups.flatMap(MessageGroup ::toContents),
114
+ promptId = promptId,
115
+ responseTextBuilders = responseTextBuilders,
116
+ )
117
+ }
118
118
}
119
119
120
120
override suspend fun regenerateOnError (): Result <Unit > {
121
- val model = generativeModel ? : throwNotJoinedError()
122
- val roomId = joinedRoomId ? : throwNotJoinedError()
123
- val messageGroupStream = chatLocalDataSource.getMessageGroupStream(roomId)
124
- val messageGroups = messageGroupStream.first()
125
- val lastMessageGroup =
126
- messageGroups.lastOrNull() ? : error(" Message group list is empty when regenerating response" )
127
- val lastPrompt = lastMessageGroup.prompt
128
- val lastPromptId = lastPrompt.id
129
- val responseTextBuilders = List (CANDIDATE_COUNT ) { ResponseTextBuilder () }
130
-
131
- chatLocalDataSource.insertResponsesAndRemoveError(
132
- newResponseIds = responseTextBuilders.map { it.id },
133
- errorResponseId = lastMessageGroup.selectedResponse.id,
134
- roomId = roomId,
135
- promptId = lastPromptId,
136
- )
137
-
138
- return model.generateTextMessageStream(
139
- message = lastPrompt.text,
140
- images = lastPrompt.images.map { promptImageLocalDataSource.loadImage(it.path) },
141
- history = messageGroups
142
- .dropLast(1 )
143
- .flatMap(MessageGroup ::toContents),
144
- promptId = lastPromptId,
145
- responseTextBuilders = responseTextBuilders,
146
- )
121
+ return runCatching {
122
+ val model = generativeModel ? : throw NotJoinedException ()
123
+ val roomId = joinedRoomId ? : throw NotJoinedException ()
124
+ val messageGroupStream = chatLocalDataSource.getMessageGroupStream(roomId)
125
+ val messageGroups = messageGroupStream.first()
126
+ val lastMessageGroup =
127
+ messageGroups.lastOrNull() ? : throw EmptyMessageGroupsOnRegenerationException ()
128
+ val lastPrompt = lastMessageGroup.prompt
129
+ val lastPromptId = lastPrompt.id
130
+ val responseTextBuilders = List (CANDIDATE_COUNT ) { ResponseTextBuilder () }
131
+
132
+ chatLocalDataSource.insertResponsesAndRemoveError(
133
+ newResponseIds = responseTextBuilders.map { it.id },
134
+ errorResponseId = lastMessageGroup.selectedResponse.id,
135
+ roomId = roomId,
136
+ promptId = lastPromptId,
137
+ )
138
+
139
+ return model.generateTextMessageStream(
140
+ message = lastPrompt.text,
141
+ images = lastPrompt.images.map { promptImageLocalDataSource.loadImage(it.path) },
142
+ history = messageGroups
143
+ .dropLast(1 )
144
+ .flatMap(MessageGroup ::toContents),
145
+ promptId = lastPromptId,
146
+ responseTextBuilders = responseTextBuilders,
147
+ )
148
+ }
147
149
}
148
150
149
151
override suspend fun regenerateResponse (responseId : String ): Result <Unit > {
150
- val model = generativeModel ? : throwNotJoinedError()
151
- val roomId = joinedRoomId ? : throwNotJoinedError()
152
- val messageGroupStream = chatLocalDataSource.getMessageGroupStream(roomId)
153
- val messageGroups = messageGroupStream.first()
154
- val messageGroup = messageGroups.firstOrNull {
155
- it.selectedResponse.id == responseId
156
- } ? : error(" Message group list is empty when regenerating response" )
157
- val prompt = messageGroup.prompt
158
- val promptId = prompt.id
159
- val responseTextBuilders = List (CANDIDATE_COUNT ) { ResponseTextBuilder () }
160
-
161
- chatLocalDataSource.insertAndUnselectOldResponses(
162
- newResponseIds = responseTextBuilders.map { it.id },
163
- roomId = roomId,
164
- promptId = promptId,
165
- )
166
-
167
- return model.generateTextMessageStream(
168
- message = prompt.text,
169
- images = prompt.images.map { promptImageLocalDataSource.loadImage(it.path) },
170
- history = messageGroups.flatMap(MessageGroup ::toContents),
171
- promptId = promptId,
172
- responseTextBuilders = responseTextBuilders,
173
- )
152
+ return runCatching {
153
+ val model = generativeModel ? : throw NotJoinedException ()
154
+ val roomId = joinedRoomId ? : throw NotJoinedException ()
155
+ val messageGroupStream = chatLocalDataSource.getMessageGroupStream(roomId)
156
+ val messageGroups = messageGroupStream.first()
157
+ val messageGroup = messageGroups.firstOrNull {
158
+ it.selectedResponse.id == responseId
159
+ } ? : throw EmptyMessageGroupsOnRegenerationException ()
160
+ val prompt = messageGroup.prompt
161
+ val promptId = prompt.id
162
+ val responseTextBuilders = List (CANDIDATE_COUNT ) { ResponseTextBuilder () }
163
+
164
+ chatLocalDataSource.insertAndUnselectOldResponses(
165
+ newResponseIds = responseTextBuilders.map { it.id },
166
+ roomId = roomId,
167
+ promptId = promptId,
168
+ )
169
+
170
+ return model.generateTextMessageStream(
171
+ message = prompt.text,
172
+ images = prompt.images.map { promptImageLocalDataSource.loadImage(it.path) },
173
+ history = messageGroups.flatMap(MessageGroup ::toContents),
174
+ promptId = promptId,
175
+ responseTextBuilders = responseTextBuilders,
176
+ )
177
+ }
174
178
}
175
179
176
180
private suspend fun GenerativeModel.generateTextMessageStream (
@@ -211,10 +215,6 @@ class GenerativeChatRepository @Inject constructor(
211
215
}
212
216
}
213
217
214
- private fun throwNotJoinedError (): Nothing {
215
- error(" Must call join function before usage" )
216
- }
217
-
218
218
override fun exit () {
219
219
joinedRoomId = null
220
220
generativeModel = null
0 commit comments