Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.simiacryptus.skyenet.Discussable.kt Maven / Gradle / Ivy
package com.simiacryptus.skyenet
import com.simiacryptus.jopenai.ApiModel.Role
import com.simiacryptus.skyenet.webui.application.ApplicationInterface
import com.simiacryptus.skyenet.webui.session.SessionTask
import com.simiacryptus.skyenet.webui.util.MarkdownUtil.renderMarkdown
import java.util.concurrent.Callable
import java.util.concurrent.Semaphore
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference
class Discussable(
private val task: SessionTask,
private val userMessage: () -> String,
private val initialResponse: (String) -> T,
private val outputFn: (T) -> String,
private val ui: ApplicationInterface,
private val reviseResponse: (List>) -> T,
private val atomicRef: AtomicReference = AtomicReference(),
private val semaphore: Semaphore = Semaphore(0),
private val heading: String
) : Callable {
val tabs = object : TabbedDisplay(task) {
override fun renderTabButtons() = """
${
tabs.withIndex().joinToString("\n")
{ (index: Int, t: Pair) ->
"""${t.first} """
}
}
${
ui.hrefLink("♻") {
val newTask = ui.newTask(false)
val header = newTask.header("Retrying...")
val idx: Int = size
this.set(label(idx), newTask.placeholder)
main(idx, newTask)
//this.selectedTab = idx
header?.clear()
newTask.complete()
}
}
""".trimMargin()
}
private val acceptGuard = AtomicBoolean(false)
private fun main(tabIndex: Int, task: SessionTask) {
log.info("Starting main function for tabIndex: $tabIndex")
try {
val history = mutableListOf>()
val userMessage = userMessage()
log.info("User message: $userMessage")
history.add(userMessage to Role.user)
val design = initialResponse(userMessage)
log.info("Initial response generated: $design")
val rendered = outputFn(design)
log.info("Rendered output: $rendered")
history.add(rendered to Role.assistant)
val tabContent = task.add(rendered)!!
val feedbackForm = feedbackForm(tabIndex, tabContent, design, history, task)
tabContent?.append("\n" + feedbackForm.placeholder)
task.complete()
} catch (e: Throwable) {
log.error("Error in discussable", e)
task.error(ui, e)
task.complete(ui.hrefLink("🔄 Retry") {
main(tabIndex = tabIndex, task = task)
})
}
}
private fun feedbackForm(
tabIndex: Int?,
tabContent: StringBuilder,
design: T,
history: List>,
task: SessionTask,
) = ui.newTask(false).apply {
log.info("Creating feedback form for tabIndex: $tabIndex")
val feedbackSB = add("
")!!
feedbackSB.clear()
feedbackSB.append(
"""
|
|${acceptLink(tabIndex, tabContent, design, feedbackSB, feedbackTask = this)}
|
|${textInput(design, tabContent, history, task, feedbackSB, feedbackTask = this)}
""".trimMargin()
)
complete()
}
private fun acceptLink(
tabIndex: Int?,
tabContent: StringBuilder,
design: T,
feedbackSB: StringBuilder,
feedbackTask: SessionTask,
) = ui.hrefLink("Accept", classname = "href-link cmd-button") {
log.info("Accept link clicked for tabIndex: $tabIndex")
feedbackSB.clear()
feedbackTask.complete()
accept(tabIndex, tabContent, design)
}
private fun textInput(
design: T,
tabContent: StringBuilder,
history: List>,
task: SessionTask,
feedbackSB: StringBuilder,
feedbackTask: SessionTask,
): String {
val feedbackGuard = AtomicBoolean(false)
return ui.textInput { userResponse ->
log.info("User response received: $userResponse")
if (feedbackGuard.getAndSet(true)) return@textInput
val prev = feedbackSB.toString()
try {
feedbackSB.clear()
feedbackTask.complete()
feedback(tabContent, userResponse, history, design, task)
} catch (e: Exception) {
log.error("Error processing user feedback", e)
task.error(ui, e)
feedbackSB.set(prev)
feedbackTask.complete()
throw e
} finally {
feedbackGuard.set(false)
}
}
}
private fun feedback(
tabContent: StringBuilder,
userResponse: String,
history: List>,
design: T,
task: SessionTask,
) {
log.info("Processing feedback for user response: $userResponse")
var history = history
history = history + (userResponse to Role.user)
val newValue = (tabContent.toString()
+ ""
+ renderMarkdown(userResponse, ui = ui)
+ "
")
tabContent.set(newValue)
val stringBuilder = task.add("Processing...")
tabs.update()
val newDesign = reviseResponse(history)
log.info("Revised design: $newDesign")
val newTask = ui.newTask(root = false)
tabContent.set(newValue + "\n" + newTask.placeholder)
tabs.update()
stringBuilder?.clear()
task.complete()
Retryable(ui, newTask) {
outputFn(newDesign) + "\n" + feedbackForm(
tabIndex = null,
tabContent = it,
design = newDesign,
history = history,
task = newTask
).placeholder
}
}
private fun accept(tabIndex: Int?, tabContent: StringBuilder, design: T) {
log.info("Accepting design for tabIndex: $tabIndex")
if (acceptGuard.getAndSet(true)) {
return
}
try {
//if (null != tabIndex) tabs.selectedTab = tabIndex
tabContent.apply {
val prevTab = toString()
set(prevTab)
tabs.update()
}
} catch (e: Exception) {
log.error("Error accepting design", e)
task.error(ui, e)
acceptGuard.set(false)
throw e
}
atomicRef.set(design)
semaphore.release()
}
override fun call(): T {
try {
//log.info("Calling Discussable with heading: $heading")
task.echo(heading)
val idx = tabs.size
val newTask = ui.newTask(false)
val header = newTask.header("Processing...")
tabs[tabs.label(idx)] = newTask.placeholder
try {
main(idx, newTask)
//tabs.selectedTab = idx
semaphore.acquire()
} catch (e: Throwable) {
log.error("Error in main function", e)
task.error(ui, e)
} finally {
header?.clear()
newTask.complete()
}
log.info("Returning result from Discussable")
return atomicRef.get()
} catch (e: Exception) {
log.warn("""
|Error in Discussable
|${e.message}
""".trimIndent(), e)
task.error(ui, e)
return null as T
}
}
companion object {
private val log = org.slf4j.LoggerFactory.getLogger(Discussable::class.java)
}
}
fun java.lang.StringBuilder.set(newValue: String) {
clear()
append(newValue)
}