Skip to content

Commit 88647c3

Browse files
leandroBorgesFerreiraLeandro Ferreira
andauthored
Section generation (#416)
* Section generation * ktlint * Update DefaultDrawersJs.kt * version bump --------- Co-authored-by: Leandro Ferreira <[email protected]>
1 parent 19176ea commit 88647c3

File tree

16 files changed

+473
-129
lines changed

16 files changed

+473
-129
lines changed

application/composeApp/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ compose.desktop {
140140
}
141141

142142
linux {
143-
packageVersion = "0.38.0"
143+
packageVersion = "0.39.0"
144144
iconFile.set(iconsRoot.resolve("icon-linux.png"))
145145
}
146146

application/core/resources/src/commonMain/composeResources/values-en/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
<string name="download_models">Download Model</string>
5252
<string name="suggestions">Suggestions:</string>
5353
<string name="error_model_download">Error when downloading model.</string>
54-
<string name="version">"Version: alpha38 - Amado, Jorge"</string>
54+
<string name="version">"Version: alpha39 - Amado, Jorge"</string>
5555
<string name="light_theme">Light</string>
5656
<string name="dark_theme">Dark</string>
5757
<string name="system_theme">System</string>

application/core/resources/src/commonMain/composeResources/values-pt/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
<string name="download_models">Baixar modelos</string>
5252
<string name="suggestions">Sugestões:</string>
5353
<string name="error_model_download">Error ao baixar modelo.</string>
54-
<string name="version">"Versão: alpha38 - Amado, Jorge"</string>
54+
<string name="version">"Versão: alpha39 - Amado, Jorge"</string>
5555
<string name="light_theme">Claro</string>
5656
<string name="dark_theme">Escuro</string>
5757
<string name="system_theme">Sistema</string>

application/core/resources/src/commonMain/composeResources/values/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
<string name="download_models">Download Model</string>
5454
<string name="suggestions">Suggestions:</string>
5555
<string name="error_model_download">Error when downloading model.</string>
56-
<string name="version">Version: alpha38 - Amado, Jorge</string>
56+
<string name="version">Version: alpha39 - Amado, Jorge</string>
5757
<string name="light_theme">Light</string>
5858
<string name="dark_theme">Dark</string>
5959
<string name="system_theme">System</string>

application/features/editor/src/commonMain/kotlin/io/writeopia/editor/features/editor/ui/TextEditor.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ internal fun TextEditor(
7272
groupsBackgroundColor = Color.Transparent,
7373
drawConfig = DrawConfigFactory.getDrawConfig(),
7474
fontFamily = fontFamily,
75+
generateSection = noteEditorViewModel::aiSection,
7576
receiveExternalFile = noteEditorViewModel::receiveExternalFile,
76-
onDocumentLinkClick = onDocumentLinkClick
77+
onDocumentLinkClick = onDocumentLinkClick,
7778
),
7879
storyState = storyState,
7980
)

application/features/editor/src/commonMain/kotlin/io/writeopia/editor/features/editor/viewmodel/NoteEditorKmpViewModel.kt

Lines changed: 22 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import io.writeopia.sdk.model.story.StoryState
2626
import io.writeopia.sdk.models.document.Document
2727
import io.writeopia.sdk.models.files.ExternalFile
2828
import io.writeopia.sdk.models.span.Span
29-
import io.writeopia.sdk.models.story.StoryStep
3029
import io.writeopia.sdk.models.story.StoryTypes
3130
import io.writeopia.sdk.persistence.core.tracker.OnUpdateDocumentTracker
3231
import io.writeopia.sdk.repository.DocumentRepository
@@ -53,9 +52,7 @@ import kotlinx.coroutines.flow.combine
5352
import kotlinx.coroutines.flow.filterNotNull
5453
import kotlinx.coroutines.flow.flatMapLatest
5554
import kotlinx.coroutines.flow.map
56-
import kotlinx.coroutines.flow.onCompletion
5755
import kotlinx.coroutines.flow.onEach
58-
import kotlinx.coroutines.flow.onStart
5956
import kotlinx.coroutines.flow.stateIn
6057
import kotlinx.coroutines.launch
6158
import kotlinx.coroutines.withContext
@@ -440,61 +437,7 @@ class NoteEditorKmpViewModel(
440437
if (ollamaRepository == null) return
441438

442439
viewModelScope.launch(Dispatchers.Default) {
443-
val text = writeopiaManager.getCurrentText()
444-
val position = writeopiaManager.getNextPosition()
445-
446-
if (text != null && position != null) {
447-
val url = ollamaRepository.getConfiguredOllamaUrl()?.trim()
448-
449-
if (url == null) {
450-
writeopiaManager.changeStoryState(
451-
Action.StoryStateChange(
452-
storyStep = StoryStep(
453-
type = StoryTypes.AI_ANSWER.type,
454-
text = "Ollama is not configured or not running."
455-
),
456-
position = position,
457-
)
458-
)
459-
} else {
460-
val model = ollamaRepository.getOllamaSelectedModel("disconnected_user")
461-
?: return@launch
462-
463-
ollamaRepository.streamReply(model, text, url)
464-
.onStart {
465-
writeopiaManager.addAtPosition(
466-
storyStep = StoryStep(
467-
type = StoryTypes.LOADING.type,
468-
ephemeral = true
469-
),
470-
position = position
471-
)
472-
}
473-
.onCompletion {
474-
writeopiaManager.trackState()
475-
}
476-
.collect { result ->
477-
val text = when (result) {
478-
is ResultData.Complete -> result.data
479-
is ResultData.Error -> "Error. Message: ${result.exception.message}"
480-
is ResultData.Loading,
481-
is ResultData.Idle,
482-
is ResultData.InProgress -> ""
483-
}
484-
485-
writeopiaManager.changeStoryState(
486-
Action.StoryStateChange(
487-
storyStep = StoryStep(
488-
type = StoryTypes.AI_ANSWER.type,
489-
text = text
490-
),
491-
position = position,
492-
),
493-
trackIt = false
494-
)
495-
}
496-
}
497-
}
440+
PromptService.promptBySelection(writeopiaManager, ollamaRepository)
498441
}
499442
}
500443

@@ -522,6 +465,26 @@ class NoteEditorKmpViewModel(
522465
documentPrompt(ollamaRepository::streamTags)
523466
}
524467

468+
override fun aiSection(position: Int) {
469+
if (ollamaRepository == null) return
470+
471+
val sectionText = writeopiaManager.getStory(position)?.text ?: return
472+
473+
viewModelScope.launch(Dispatchers.Default) {
474+
val prompt =
475+
"""
476+
Create a document section for a document.
477+
The document is:
478+
```
479+
${writeopiaManager.getDocumentText()}
480+
```
481+
482+
Use the language of the text. Do not add titles. Create contect for this section: $sectionText
483+
"""
484+
PromptService.prompt(prompt = prompt, writeopiaManager, ollamaRepository, position + 1)
485+
}
486+
}
487+
525488
override fun addPage() {
526489
viewModelScope.launch(Dispatchers.Default) {
527490
writeopiaManager.addLinkToDocument()
@@ -576,62 +539,7 @@ class NoteEditorKmpViewModel(
576539
if (ollamaRepository == null) return
577540

578541
viewModelScope.launch(Dispatchers.Default) {
579-
val text = writeopiaManager.getCurrentSelectionText()
580-
?: writeopiaManager.getDocumentText()
581-
582-
val position =
583-
writeopiaManager.positionAfterSelection() ?: writeopiaManager.lastPosition()
584-
585-
val url = ollamaRepository.getConfiguredOllamaUrl()?.trim()
586-
587-
if (url == null) {
588-
writeopiaManager.changeStoryState(
589-
Action.StoryStateChange(
590-
storyStep = StoryStep(
591-
type = StoryTypes.AI_ANSWER.type,
592-
text = "Ollama is not configured or not running."
593-
),
594-
position = position,
595-
)
596-
)
597-
} else {
598-
val model = ollamaRepository.getOllamaSelectedModel("disconnected_user")
599-
?: return@launch
600-
601-
promptFn(model, text, url)
602-
.onStart {
603-
writeopiaManager.addAtPosition(
604-
storyStep = StoryStep(
605-
type = StoryTypes.LOADING.type,
606-
ephemeral = true
607-
),
608-
position = position
609-
)
610-
}
611-
.onCompletion {
612-
writeopiaManager.trackState()
613-
}
614-
.collect { result ->
615-
val text = when (result) {
616-
is ResultData.Complete -> result.data
617-
is ResultData.Error -> "Error. Message: ${result.exception.message}"
618-
is ResultData.Loading,
619-
is ResultData.Idle,
620-
is ResultData.InProgress -> ""
621-
}
622-
623-
writeopiaManager.changeStoryState(
624-
Action.StoryStateChange(
625-
storyStep = StoryStep(
626-
type = StoryTypes.AI_ANSWER.type,
627-
text = text
628-
),
629-
position = position,
630-
),
631-
trackIt = false
632-
)
633-
}
634-
}
542+
PromptService.documentPrompt(promptFn, writeopiaManager, ollamaRepository)
635543
}
636544
}
637545

application/features/editor/src/commonMain/kotlin/io/writeopia/editor/features/editor/viewmodel/NoteEditorViewModel.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ interface NoteEditorViewModel : BackstackInform, BackstackHandler {
101101

102102
fun aiTags()
103103

104+
fun aiSection(position: Int)
105+
104106
fun addPage()
105107

106108
fun copySelection()
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package io.writeopia.editor.features.editor.viewmodel
2+
3+
import io.writeopia.OllamaRepository
4+
import io.writeopia.common.utils.ResultData
5+
import io.writeopia.sdk.model.action.Action
6+
import io.writeopia.sdk.models.story.StoryStep
7+
import io.writeopia.sdk.models.story.StoryTypes
8+
import io.writeopia.ui.manager.WriteopiaStateManager
9+
import kotlinx.coroutines.flow.Flow
10+
import kotlinx.coroutines.flow.map
11+
import kotlinx.coroutines.flow.onCompletion
12+
import kotlinx.coroutines.flow.onStart
13+
14+
object PromptService {
15+
16+
suspend fun documentPrompt(
17+
promptFn: (String, String, String) -> Flow<ResultData<String>>,
18+
writeopiaManager: WriteopiaStateManager,
19+
ollamaRepository: OllamaRepository
20+
) {
21+
val text = writeopiaManager.getCurrentSelectionText()
22+
?: writeopiaManager.getDocumentText()
23+
24+
val position =
25+
writeopiaManager.positionAfterSelection() ?: writeopiaManager.lastPosition()
26+
27+
val url = ollamaRepository.getConfiguredOllamaUrl()?.trim()
28+
29+
if (url == null) {
30+
writeopiaManager.changeStoryState(
31+
Action.StoryStateChange(
32+
storyStep = StoryStep(
33+
type = StoryTypes.AI_ANSWER.type,
34+
text = "Ollama is not configured or not running."
35+
),
36+
position = position,
37+
)
38+
)
39+
} else {
40+
val model = ollamaRepository.getOllamaSelectedModel("disconnected_user")
41+
?: return
42+
43+
promptFn(model, text, url).handleStream(writeopiaManager, position)
44+
}
45+
}
46+
47+
suspend fun promptBySelection(
48+
writeopiaManager: WriteopiaStateManager,
49+
ollamaRepository: OllamaRepository
50+
) {
51+
val text = writeopiaManager.getCurrentText()
52+
53+
prompt(text, writeopiaManager, ollamaRepository)
54+
}
55+
56+
suspend fun prompt(
57+
prompt: String?,
58+
writeopiaManager: WriteopiaStateManager,
59+
ollamaRepository: OllamaRepository,
60+
promptPosition: Int? = null
61+
) {
62+
val position = promptPosition ?: writeopiaManager.getNextPosition()
63+
64+
if (prompt != null && position != null) {
65+
val url = ollamaRepository.getConfiguredOllamaUrl()?.trim()
66+
67+
if (url == null) {
68+
writeopiaManager.changeStoryState(
69+
Action.StoryStateChange(
70+
storyStep = StoryStep(
71+
type = StoryTypes.AI_ANSWER.type,
72+
text = "Ollama is not configured or not running."
73+
),
74+
position = position,
75+
)
76+
)
77+
} else {
78+
val model = ollamaRepository.getOllamaSelectedModel("disconnected_user")
79+
?: return
80+
81+
ollamaRepository.streamReply(model, prompt, url)
82+
.handleStream(writeopiaManager, position)
83+
}
84+
}
85+
}
86+
87+
private suspend fun Flow<ResultData<String>>.handleStream(
88+
writeopiaManager: WriteopiaStateManager,
89+
position: Int
90+
) {
91+
this.onStart {
92+
writeopiaManager.addAtPosition(
93+
storyStep = StoryStep(
94+
type = StoryTypes.LOADING.type,
95+
ephemeral = true
96+
),
97+
position = position
98+
)
99+
}
100+
.onCompletion {
101+
writeopiaManager.trackState()
102+
}
103+
.map { result ->
104+
when (result) {
105+
is ResultData.Complete -> result.data
106+
is ResultData.Error -> "Error. Message: ${result.exception.message}"
107+
is ResultData.Loading,
108+
is ResultData.Idle,
109+
is ResultData.InProgress -> ""
110+
}
111+
}
112+
.collect { resultText ->
113+
writeopiaManager.changeStoryState(
114+
Action.StoryStateChange(
115+
storyStep = StoryStep(
116+
type = StoryTypes.AI_ANSWER.type,
117+
text = resultText
118+
),
119+
position = position,
120+
),
121+
trackIt = false
122+
)
123+
}
124+
}
125+
}

0 commit comments

Comments
 (0)