Skip to content

Commit

Permalink
feat(javascript): add AutoPageFlow and AutoPageTask #81
Browse files Browse the repository at this point in the history
Add the `AutoPageFlow` and `AutoPageTask` classes to handle the generation of pages in the JavaScript code. These classes are responsible for clarifying the requirements and designing the pages based on the selected components. The `AutoPageFlow` class generates prompts for the user to clarify the requirements and design the pages, while the `AutoPageTask` class runs the flow in the background and updates the progress indicator.
  • Loading branch information
phodal committed Jan 26, 2024
1 parent aa61744 commit d687152
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 110 deletions.
@@ -1,24 +1,19 @@
package cc.unitmesh.ide.javascript.actions

import cc.unitmesh.devti.AutoDevBundle
import cc.unitmesh.devti.flow.TaskFlow
import cc.unitmesh.devti.gui.chat.ChatCodingPanel
import cc.unitmesh.devti.gui.sendToChatPanel
import cc.unitmesh.devti.intentions.action.base.ChatBaseIntention
import cc.unitmesh.devti.llms.LLMProvider
import cc.unitmesh.devti.llms.LlmFactory
import cc.unitmesh.devti.template.TemplateRender
import cc.unitmesh.ide.javascript.flow.DsComponent
import cc.unitmesh.ide.javascript.flow.model.AutoPageContext
import cc.unitmesh.ide.javascript.flow.AutoPageFlow
import cc.unitmesh.ide.javascript.flow.AutoPageTask
import cc.unitmesh.ide.javascript.flow.ReactAutoPage
import cc.unitmesh.ide.javascript.util.LanguageApplicableUtil
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import kotlinx.coroutines.runBlocking

class AutoPageAction : ChatBaseIntention() {
override fun priority(): Int = 1010
Expand All @@ -39,111 +34,13 @@ class AutoPageAction : ChatBaseIntention() {
sendToChatPanel(project) { contentPanel, _ ->
val llmProvider = LlmFactory().create(project)
val context = AutoPageContext.build(reactAutoPage)
val prompter = GenComponentFlow(context, contentPanel, llmProvider)
val prompter = AutoPageFlow(context, contentPanel, llmProvider)

val task = GenComponentTask(project, prompter, editor, reactAutoPage)
val task = AutoPageTask(project, prompter, editor, reactAutoPage)
ProgressManager.getInstance()
.runProcessWithProgressAsynchronously(task, BackgroundableProcessIndicator(task))
}

}
}

class GenComponentTask(
private val project: Project,
private val flow: GenComponentFlow,
private val editor: Editor,
private val autoPage: ReactAutoPage
) : Task.Backgroundable(project, "Gen Page", true) {
override fun run(indicator: ProgressIndicator) {
indicator.fraction = 0.2

indicator.text = AutoDevBundle.message("autopage.generate.clarify")
val components = flow.clarify()
// tables will be list in string format, like: `[table1, table2]`, we need to parse to Lists
val componentNames = components.substringAfter("[").substringBefore("]")
.split(", ").map { it.trim() }

val filterComponents = autoPage.filterComponents(componentNames)
flow.context.components = filterComponents.map { it.format() }

indicator.fraction = 0.6
indicator.text = AutoDevBundle.message("autopage.generate.design")
flow.design(filterComponents)

indicator.fraction = 0.8

}
}

data class AutoPageContext(
val requirement: String,
var pages: List<String>,
val pageNames: List<String>,
var components: List<String>,
val componentNames: List<String>,
val routes: List<String>,
) {
companion object {
fun build(reactAutoPage: ReactAutoPage): AutoPageContext {
return AutoPageContext(
requirement = reactAutoPage.userTask,
pages = reactAutoPage.getPages().map { it.format() },
pageNames = reactAutoPage.getPages().map { it.name },
components = reactAutoPage.getComponents().map { it.format() },
componentNames = reactAutoPage.getComponents().map { it.name },
routes = reactAutoPage.getRoutes(),
)
}
}
}

class GenComponentFlow(val context: AutoPageContext, val panel: ChatCodingPanel, val llm: LLMProvider) :
TaskFlow<String> {
override fun clarify(): String {
val stepOnePrompt = generateStepOnePrompt(context)

panel.addMessage(stepOnePrompt, true, stepOnePrompt)
panel.addMessage(AutoDevBundle.message("autodev.loading"))

return runBlocking {
val prompt = llm.stream(stepOnePrompt, "")
return@runBlocking panel.updateMessage(prompt)
}
}

private fun generateStepOnePrompt(context: AutoPageContext): String {
val templateRender = TemplateRender("genius/page")
val template = templateRender.getTemplate("page-gen-clarify.vm")

templateRender.context = context

val prompter = templateRender.renderTemplate(template)
return prompter
}


override fun design(context: Any): List<String> {
val componentList = context as List<DsComponent>
val stepTwoPrompt = generateStepTwoPrompt(componentList)

panel.addMessage(stepTwoPrompt, true, stepTwoPrompt)
panel.addMessage(AutoDevBundle.message("autodev.loading"))

return runBlocking {
val prompt = llm.stream(stepTwoPrompt, "")
return@runBlocking panel.updateMessage(prompt)
}.let { listOf(it) }
}

private fun generateStepTwoPrompt(selectedComponents: List<DsComponent>): String {
val templateRender = TemplateRender("genius/page")
val template = templateRender.getTemplate("page-gen-design.vm")

context.pages = selectedComponents.map { it.format() }
templateRender.context = context

val prompter = templateRender.renderTemplate(template)
return prompter
}
}
@@ -1,6 +1,7 @@
package cc.unitmesh.ide.javascript.flow

import cc.unitmesh.devti.flow.TaskFlow
import cc.unitmesh.ide.javascript.flow.model.DsComponent

/**
* FrontendFlow is an interface that represents the flow of tasks in a frontend application.
Expand Down
@@ -0,0 +1,60 @@
package cc.unitmesh.ide.javascript.flow

import cc.unitmesh.devti.AutoDevBundle
import cc.unitmesh.devti.flow.TaskFlow
import cc.unitmesh.devti.gui.chat.ChatCodingPanel
import cc.unitmesh.devti.llms.LLMProvider
import cc.unitmesh.devti.template.TemplateRender
import cc.unitmesh.ide.javascript.flow.model.AutoPageContext
import cc.unitmesh.ide.javascript.flow.model.DsComponent
import kotlinx.coroutines.runBlocking

class AutoPageFlow(val context: AutoPageContext, val panel: ChatCodingPanel, val llm: LLMProvider) :
TaskFlow<String> {
override fun clarify(): String {
val stepOnePrompt = generateStepOnePrompt(context)

panel.addMessage(stepOnePrompt, true, stepOnePrompt)
panel.addMessage(AutoDevBundle.message("autodev.loading"))

return runBlocking {
val prompt = llm.stream(stepOnePrompt, "")
return@runBlocking panel.updateMessage(prompt)
}
}

private fun generateStepOnePrompt(context: AutoPageContext): String {
val templateRender = TemplateRender("genius/page")
val template = templateRender.getTemplate("page-gen-clarify.vm")

templateRender.context = context

val prompter = templateRender.renderTemplate(template)
return prompter
}


override fun design(context: Any): List<String> {
val componentList = context as List<DsComponent>
val stepTwoPrompt = generateStepTwoPrompt(componentList)

panel.addMessage(stepTwoPrompt, true, stepTwoPrompt)
panel.addMessage(AutoDevBundle.message("autodev.loading"))

return runBlocking {
val prompt = llm.stream(stepTwoPrompt, "")
return@runBlocking panel.updateMessage(prompt)
}.let { listOf(it) }
}

private fun generateStepTwoPrompt(selectedComponents: List<DsComponent>): String {
val templateRender = TemplateRender("genius/page")
val template = templateRender.getTemplate("page-gen-design.vm")

context.pages = selectedComponents.map { it.format() }
templateRender.context = context

val prompter = templateRender.renderTemplate(template)
return prompter
}
}
@@ -0,0 +1,34 @@
package cc.unitmesh.ide.javascript.flow

import cc.unitmesh.devti.AutoDevBundle
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.Project

class AutoPageTask(
private val project: Project,
private val flow: AutoPageFlow,
private val editor: Editor,
private val autoPage: ReactAutoPage
) : Task.Backgroundable(project, "Gen Page", true) {
override fun run(indicator: ProgressIndicator) {
indicator.fraction = 0.2

indicator.text = AutoDevBundle.message("autopage.generate.clarify")
val components = flow.clarify()
// tables will be list in string format, like: `[table1, table2]`, we need to parse to Lists
val componentNames = components.substringAfter("[").substringBefore("]")
.split(", ").map { it.trim() }

val filterComponents = autoPage.filterComponents(componentNames)
flow.context.components = filterComponents.map { it.format() }

indicator.fraction = 0.6
indicator.text = AutoDevBundle.message("autopage.generate.design")
flow.design(filterComponents)

indicator.fraction = 0.8

}
}
@@ -1,5 +1,6 @@
package cc.unitmesh.ide.javascript.flow

import cc.unitmesh.ide.javascript.flow.model.DsComponent
import cc.unitmesh.ide.javascript.util.ReactPsiUtil
import com.intellij.lang.ecmascript6.JSXHarmonyFileType
import com.intellij.lang.javascript.JavaScriptFileType
Expand Down
@@ -0,0 +1,25 @@
package cc.unitmesh.ide.javascript.flow.model

import cc.unitmesh.ide.javascript.flow.ReactAutoPage

data class AutoPageContext(
val requirement: String,
var pages: List<String>,
val pageNames: List<String>,
var components: List<String>,
val componentNames: List<String>,
val routes: List<String>,
) {
companion object {
fun build(reactAutoPage: ReactAutoPage): AutoPageContext {
return AutoPageContext(
requirement = reactAutoPage.userTask,
pages = reactAutoPage.getPages().map { it.format() },
pageNames = reactAutoPage.getPages().map { it.name },
components = reactAutoPage.getComponents().map { it.format() },
componentNames = reactAutoPage.getComponents().map { it.name },
routes = reactAutoPage.getRoutes(),
)
}
}
}
@@ -1,4 +1,4 @@
package cc.unitmesh.ide.javascript.flow
package cc.unitmesh.ide.javascript.flow.model

import kotlinx.serialization.Serializable

Expand Down
@@ -1,6 +1,6 @@
package cc.unitmesh.ide.javascript.util

import cc.unitmesh.ide.javascript.flow.DsComponent
import cc.unitmesh.ide.javascript.flow.model.DsComponent
import com.intellij.lang.ecmascript6.psi.ES6ExportDeclaration
import com.intellij.lang.ecmascript6.psi.ES6ExportDefaultAssignment
import com.intellij.lang.javascript.presentable.JSFormatUtil
Expand Down

0 comments on commit d687152

Please sign in to comment.