Skip to content

Commit d8cfeea

Browse files
authored
Corrected issues (#56)
* Replaced download method for a new foreground download system * use okhttp * improved orchestration * upgraded version * upgraded version * solved issue with suggestions * corrected issue with generation loading spinner
1 parent c33f197 commit d8cfeea

File tree

5 files changed

+102
-59
lines changed

5 files changed

+102
-59
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ dependencyResolutionManagement {
134134
}
135135

136136
commonMain.dependencies {
137-
implementation("com.llamatik:library:0.14.0")
137+
implementation("com.llamatik:library:0.15.0")
138138
}
139139
```
140140

iosApp/Llamatik.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@
359359
"$(inherited)",
360360
"@executable_path/Frameworks",
361361
);
362-
MARKETING_VERSION = 1.2.0;
362+
MARKETING_VERSION = 1.3.0;
363363
OTHER_LDFLAGS = (
364364
"$(inherited)",
365365
"-framework",
@@ -399,7 +399,7 @@
399399
"$(inherited)",
400400
"@executable_path/Frameworks",
401401
);
402-
MARKETING_VERSION = 1.2.0;
402+
MARKETING_VERSION = 1.3.0;
403403
OTHER_LDFLAGS = (
404404
"$(inherited)",
405405
"-framework",

iosApp/iosApp/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<key>CFBundlePackageType</key>
1818
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
1919
<key>CFBundleShortVersionString</key>
20-
<string>1.2.0</string>
20+
<string>1.3.0</string>
2121
<key>CFBundleVersion</key>
2222
<string>1</string>
2323
<key>LSRequiresIPhoneOS</key>

shared/src/commonMain/kotlin/com/llamatik/app/feature/chatbot/ui/ChatInputBox.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ fun ChatInputBox(
8080

8181
Surface(
8282
onClick = {
83-
onInputChange(TextFieldValue(hint))
84-
val message = input.text.trim()
83+
val message = hint.trim()
8584
if (message.isNotEmpty()) {
8685
onInputChange(TextFieldValue())
8786
viewModel.onMessageSendDirect(message)

shared/src/commonMain/kotlin/com/llamatik/app/feature/chatbot/viewmodel/ChatBotViewModel.kt

Lines changed: 97 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -386,28 +386,56 @@ class ChatBotViewModel(
386386
if (existingJob?.isActive == true) return
387387

388388
val job = screenModelScope.launch(Dispatchers.IO) {
389-
updateDownload(url) { it.copy(inProgress = true, progress = 0, done = false, error = null) }
389+
updateDownload(url) {
390+
it.copy(
391+
inProgress = true,
392+
progress = 0,
393+
done = false,
394+
error = null
395+
)
396+
}
390397

391398
modelDownloadOrchestrator.download(model).collect { ev ->
392399
when (ev) {
393400
is DownloadEvent.Progress -> {
394401
updateDownload(url) { it.copy(inProgress = true, progress = ev.percent) }
395402
}
403+
396404
is DownloadEvent.Completed -> {
397-
updateDownload(url) { it.copy(inProgress = false, progress = 100, done = true, error = null) }
405+
updateDownload(url) {
406+
it.copy(
407+
inProgress = false,
408+
progress = 100,
409+
done = true,
410+
error = null
411+
)
412+
}
398413
getModelsUseCase.saveModelPath(model.name, ev.localPath)
399414

400415
_state.value = _state.value.copy(
401416
embedModels = _state.value.embedModels.map {
402-
if (it.url == url) it.copy(fileName = ev.localPath, localPath = ev.localPath) else it
417+
if (it.url == url) it.copy(
418+
fileName = ev.localPath,
419+
localPath = ev.localPath
420+
) else it
403421
},
404422
generateModels = _state.value.generateModels.map {
405-
if (it.url == url) it.copy(fileName = ev.localPath, localPath = ev.localPath) else it
423+
if (it.url == url) it.copy(
424+
fileName = ev.localPath,
425+
localPath = ev.localPath
426+
) else it
406427
},
407428
)
408429
}
430+
409431
is DownloadEvent.Failed -> {
410-
updateDownload(url) { it.copy(inProgress = false, done = false, error = ev.message) }
432+
updateDownload(url) {
433+
it.copy(
434+
inProgress = false,
435+
done = false,
436+
error = ev.message
437+
)
438+
}
411439
}
412440
}
413441
}
@@ -626,69 +654,76 @@ class ChatBotViewModel(
626654
val collapsed = tail.replace("\\s+".toRegex(), " ").trim()
627655
val commas = collapsed.count { it == ',' }
628656
if (commas > 60) return true
629-
val m = Regex("""\b([A-Za-z0-9]{1,3})\b(?:[,\s]+\1\b){25,}""").find(collapsed)
657+
val m =
658+
Regex("""\b([A-Za-z0-9]{1,3})\b(?:[,\s]+\1\b){25,}""").find(collapsed)
630659
return m != null
631660
}
632661

633662
val generateSettings = _state.value.generateSettings
634663

635-
ChatRunner.stream(
636-
system = currentSystemPrompt(),
637-
contexts = emptyList(),
638-
messages = chatHistory,
639-
template = currentGenerateTemplate(),
640-
maxTokens = generateSettings.maxTokens,
641-
onDelta = { chunk ->
642-
if (activeRequestId != requestId || completed) return@stream
643-
if (chunk.isEmpty()) return@stream
644-
645-
acc.append(chunk)
646-
_conversation.value = _conversation.value.dropLast(1) +
647-
ChatUiModel.Message(acc.toString(), ChatUiModel.Author.bot)
648-
_sideEffects.trySend(ChatBotSideEffects.ScrollToBottom)
649-
650-
if (looksLikeEchoOrLoop(full = acc.toString(), user = input)) {
651-
val trimmed = trimLoop(acc.toString(), user = input)
664+
try {
665+
ChatRunner.stream(
666+
system = currentSystemPrompt(),
667+
contexts = emptyList(),
668+
messages = chatHistory,
669+
template = currentGenerateTemplate(),
670+
maxTokens = generateSettings.maxTokens,
671+
onDelta = { chunk ->
672+
if (activeRequestId != requestId || completed) return@stream
673+
if (chunk.isEmpty()) return@stream
674+
675+
acc.append(chunk)
652676
_conversation.value = _conversation.value.dropLast(1) +
653-
ChatUiModel.Message(trimmed, ChatUiModel.Author.bot)
654-
completed = true
655-
activeRequestId = null
656-
_state.value = _state.value.copy(isGenerating = false)
657-
_sideEffects.trySend(ChatBotSideEffects.OnMessageLoaded)
658-
return@stream
659-
}
677+
ChatUiModel.Message(acc.toString(), ChatUiModel.Author.bot)
678+
_sideEffects.trySend(ChatBotSideEffects.ScrollToBottom)
660679

661-
if (looksLikeBabble(acc.toString())) {
680+
if (looksLikeEchoOrLoop(full = acc.toString(), user = input)) {
681+
val trimmed = trimLoop(acc.toString(), user = input)
682+
_conversation.value = _conversation.value.dropLast(1) +
683+
ChatUiModel.Message(trimmed, ChatUiModel.Author.bot)
684+
completed = true
685+
activeRequestId = null
686+
_state.value = _state.value.copy(isGenerating = false)
687+
_sideEffects.trySend(ChatBotSideEffects.OnMessageLoaded)
688+
return@stream
689+
}
690+
691+
if (looksLikeBabble(acc.toString())) {
692+
completed = true
693+
activeRequestId = null
694+
val cleaned = acc.toString().trim().trimEnd(',', ' ', '\n')
695+
_conversation.value = _conversation.value.dropLast(1) +
696+
ChatUiModel.Message(cleaned, ChatUiModel.Author.bot)
697+
_state.value = _state.value.copy(isGenerating = false)
698+
_sideEffects.trySend(ChatBotSideEffects.OnMessageLoaded)
699+
}
700+
},
701+
onComplete = { final ->
702+
if (activeRequestId != requestId || completed) return@stream
662703
completed = true
663704
activeRequestId = null
664-
val cleaned = acc.toString().trim().trimEnd(',', ' ', '\n')
665705
_conversation.value = _conversation.value.dropLast(1) +
666-
ChatUiModel.Message(cleaned, ChatUiModel.Author.bot)
706+
ChatUiModel.Message(final, ChatUiModel.Author.bot)
667707
_state.value = _state.value.copy(isGenerating = false)
668708
_sideEffects.trySend(ChatBotSideEffects.OnMessageLoaded)
709+
},
710+
onError = { err ->
711+
if (activeRequestId != requestId) return@stream
712+
_conversation.value = _conversation.value.dropLast(1) +
713+
ChatUiModel.Message(
714+
"There is a problem with the AI: $err",
715+
ChatUiModel.Author.bot
716+
)
717+
activeRequestId = null
718+
_state.value = _state.value.copy(isGenerating = false)
719+
_sideEffects.trySend(ChatBotSideEffects.OnLoadError)
669720
}
670-
},
671-
onComplete = { final ->
672-
if (activeRequestId != requestId || completed) return@stream
673-
completed = true
674-
activeRequestId = null
675-
_conversation.value = _conversation.value.dropLast(1) +
676-
ChatUiModel.Message(final, ChatUiModel.Author.bot)
677-
_state.value = _state.value.copy(isGenerating = false)
678-
_sideEffects.trySend(ChatBotSideEffects.OnMessageLoaded)
679-
},
680-
onError = { err ->
681-
if (activeRequestId != requestId) return@stream
682-
_conversation.value = _conversation.value.dropLast(1) +
683-
ChatUiModel.Message(
684-
"There is a problem with the AI: $err",
685-
ChatUiModel.Author.bot
686-
)
687-
activeRequestId = null
721+
)
722+
} finally {
723+
if (activeRequestId == null) { // stopped or finished
688724
_state.value = _state.value.copy(isGenerating = false)
689-
_sideEffects.trySend(ChatBotSideEffects.OnLoadError)
690725
}
691-
)
726+
}
692727
} catch (t: Throwable) {
693728
emitBot("There is a problem with the AI: ${t.message ?: "Unknown error"}")
694729
activeRequestId = null
@@ -705,6 +740,15 @@ class ChatBotViewModel(
705740
LlamaBridge.nativeCancelGenerate()
706741
activeRequestId = null
707742
_state.value = _state.value.copy(isGenerating = false)
743+
val messages = _conversation.value
744+
if (messages.isNotEmpty()) {
745+
val last = messages.last()
746+
if (last.author == ChatUiModel.Author.bot && last.text.isBlank()) {
747+
_conversation.value = messages.dropLast(1)
748+
}
749+
}
750+
_sideEffects.trySend(ChatBotSideEffects.OnMessageLoaded)
751+
_sideEffects.trySend(ChatBotSideEffects.ScrollToBottom)
708752
}
709753

710754
private fun emitBot(text: String) {

0 commit comments

Comments
 (0)