init.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. package init
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "time"
  7. _ "embed"
  8. tea "github.com/charmbracelet/bubbletea"
  9. "github.com/langgenius/dify-plugin-daemon/internal/types/entities/constants"
  10. "github.com/langgenius/dify-plugin-daemon/internal/types/entities/plugin_entities"
  11. "github.com/langgenius/dify-plugin-daemon/internal/utils/log"
  12. )
  13. //go:embed templates/python/icon.svg
  14. var icon []byte
  15. func InitPlugin() {
  16. m := initialize()
  17. p := tea.NewProgram(m)
  18. if result, err := p.Run(); err != nil {
  19. fmt.Println("Error running program:", err)
  20. } else {
  21. if m, ok := result.(model); ok {
  22. if m.completed {
  23. m.createPlugin()
  24. }
  25. } else {
  26. log.Error("Error running program:", err)
  27. return
  28. }
  29. }
  30. }
  31. type subMenuKey string
  32. const (
  33. SUB_MENU_KEY_PROFILE subMenuKey = "profile"
  34. SUB_MENU_KEY_LANGUAGE subMenuKey = "language"
  35. SUB_MENU_KEY_PERMISSION subMenuKey = "permission"
  36. )
  37. type model struct {
  38. subMenus map[subMenuKey]subMenu
  39. subMenuSeq []subMenuKey
  40. currentSubMenu subMenuKey
  41. completed bool
  42. }
  43. func initialize() model {
  44. m := model{}
  45. m.subMenus = map[subMenuKey]subMenu{
  46. SUB_MENU_KEY_PROFILE: newProfile(),
  47. SUB_MENU_KEY_LANGUAGE: newLanguage(),
  48. SUB_MENU_KEY_PERMISSION: newPermission(),
  49. }
  50. m.currentSubMenu = SUB_MENU_KEY_PROFILE
  51. m.subMenuSeq = []subMenuKey{
  52. SUB_MENU_KEY_PROFILE,
  53. SUB_MENU_KEY_LANGUAGE,
  54. SUB_MENU_KEY_PERMISSION,
  55. }
  56. return m
  57. }
  58. func (m model) Init() tea.Cmd {
  59. return nil
  60. }
  61. func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
  62. currentSubMenu, event, cmd := m.subMenus[m.currentSubMenu].Update(msg)
  63. m.subMenus[m.currentSubMenu] = currentSubMenu
  64. switch event {
  65. case SUB_MENU_EVENT_NEXT:
  66. if m.currentSubMenu != m.subMenuSeq[len(m.subMenuSeq)-1] {
  67. // move the current sub menu to the next one
  68. for i, key := range m.subMenuSeq {
  69. if key == m.currentSubMenu {
  70. m.currentSubMenu = m.subMenuSeq[i+1]
  71. break
  72. }
  73. }
  74. } else {
  75. m.completed = true
  76. return m, tea.Quit
  77. }
  78. case SUB_MENU_EVENT_PREV:
  79. if m.currentSubMenu != m.subMenuSeq[0] {
  80. // move the current sub menu to the previous one
  81. for i, key := range m.subMenuSeq {
  82. if key == m.currentSubMenu {
  83. m.currentSubMenu = m.subMenuSeq[i-1]
  84. break
  85. }
  86. }
  87. }
  88. }
  89. return m, cmd
  90. }
  91. func (m model) View() string {
  92. return m.subMenus[m.currentSubMenu].View()
  93. }
  94. func (m model) createPlugin() {
  95. permission := m.subMenus[SUB_MENU_KEY_PERMISSION].(permission).Permission()
  96. manifest := &plugin_entities.PluginDeclaration{
  97. PluginDeclarationWithoutAdvancedFields: plugin_entities.PluginDeclarationWithoutAdvancedFields{
  98. Version: "0.0.1",
  99. Type: plugin_entities.PluginType,
  100. Icon: "icon.svg",
  101. Author: m.subMenus[SUB_MENU_KEY_PROFILE].(profile).Author(),
  102. Name: m.subMenus[SUB_MENU_KEY_PROFILE].(profile).Name(),
  103. CreatedAt: time.Now(),
  104. Resource: plugin_entities.PluginResourceRequirement{
  105. Memory: 1024 * 1024 * 256, // 256MB
  106. Permission: &permission,
  107. },
  108. Label: plugin_entities.I18nObject{
  109. EnUS: m.subMenus[SUB_MENU_KEY_PROFILE].(profile).Name(),
  110. },
  111. },
  112. }
  113. manifest.Meta = plugin_entities.PluginMeta{
  114. Version: "0.0.1",
  115. Arch: []constants.Arch{
  116. constants.AMD64,
  117. constants.ARM64,
  118. },
  119. Runner: plugin_entities.PluginRunner{},
  120. }
  121. switch m.subMenus[SUB_MENU_KEY_LANGUAGE].(language).Language() {
  122. case constants.Python:
  123. manifest.Meta.Runner.Entrypoint = "main"
  124. manifest.Meta.Runner.Language = constants.Python
  125. manifest.Meta.Runner.Version = "3.10"
  126. default:
  127. log.Error("unsupported language: %s", m.subMenus[SUB_MENU_KEY_LANGUAGE].(language).Language())
  128. return
  129. }
  130. success := false
  131. clear := func() {
  132. if !success {
  133. os.RemoveAll(manifest.Name)
  134. }
  135. }
  136. defer clear()
  137. manifest_file := marshalYamlBytes(manifest)
  138. // create the plugin directory
  139. cwd, err := os.Getwd()
  140. if err != nil {
  141. log.Error("failed to get current working directory: %s", err)
  142. return
  143. }
  144. plugin_dir := filepath.Join(cwd, manifest.Name)
  145. if err := os.MkdirAll(plugin_dir, 0o755); err != nil {
  146. log.Error("failed to create plugin directory: %s", err)
  147. return
  148. }
  149. manifest_file_path := filepath.Join(plugin_dir, "manifest.yaml")
  150. if err := os.WriteFile(manifest_file_path, manifest_file, 0o644); err != nil {
  151. log.Error("failed to write manifest file: %s", err)
  152. return
  153. }
  154. // create _assets directory
  155. assets_dir := filepath.Join(plugin_dir, "_assets")
  156. if err := os.MkdirAll(assets_dir, 0o755); err != nil {
  157. log.Error("failed to create assets directory: %s", err)
  158. return
  159. }
  160. // create icon.svg
  161. icon_file_path := filepath.Join(assets_dir, "icon.svg")
  162. if err := os.WriteFile(icon_file_path, icon, 0o644); err != nil {
  163. log.Error("failed to write icon file: %s", err)
  164. return
  165. }
  166. err = createPythonEnvironment(plugin_dir, manifest.Meta.Runner.Entrypoint)
  167. if err != nil {
  168. log.Error("failed to create python environment: %s", err)
  169. return
  170. }
  171. success = true
  172. log.Info("plugin %s created successfully", manifest.Name)
  173. }