init.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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_CATEGORY subMenuKey = "category"
  36. SUB_MENU_KEY_PERMISSION subMenuKey = "permission"
  37. )
  38. type model struct {
  39. subMenus map[subMenuKey]subMenu
  40. subMenuSeq []subMenuKey
  41. currentSubMenu subMenuKey
  42. completed bool
  43. }
  44. func initialize() model {
  45. m := model{}
  46. m.subMenus = map[subMenuKey]subMenu{
  47. SUB_MENU_KEY_PROFILE: newProfile(),
  48. SUB_MENU_KEY_LANGUAGE: newLanguage(),
  49. SUB_MENU_KEY_CATEGORY: newCategory(),
  50. SUB_MENU_KEY_PERMISSION: newPermission(),
  51. }
  52. m.currentSubMenu = SUB_MENU_KEY_PROFILE
  53. m.subMenuSeq = []subMenuKey{
  54. SUB_MENU_KEY_PROFILE,
  55. SUB_MENU_KEY_LANGUAGE,
  56. SUB_MENU_KEY_PERMISSION,
  57. }
  58. return m
  59. }
  60. func (m model) Init() tea.Cmd {
  61. return nil
  62. }
  63. func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
  64. currentSubMenu, event, cmd := m.subMenus[m.currentSubMenu].Update(msg)
  65. m.subMenus[m.currentSubMenu] = currentSubMenu
  66. switch event {
  67. case SUB_MENU_EVENT_NEXT:
  68. if m.currentSubMenu != m.subMenuSeq[len(m.subMenuSeq)-1] {
  69. // move the current sub menu to the next one
  70. for i, key := range m.subMenuSeq {
  71. if key == m.currentSubMenu {
  72. m.currentSubMenu = m.subMenuSeq[i+1]
  73. break
  74. }
  75. }
  76. } else {
  77. m.completed = true
  78. return m, tea.Quit
  79. }
  80. case SUB_MENU_EVENT_PREV:
  81. if m.currentSubMenu != m.subMenuSeq[0] {
  82. // move the current sub menu to the previous one
  83. for i, key := range m.subMenuSeq {
  84. if key == m.currentSubMenu {
  85. m.currentSubMenu = m.subMenuSeq[i-1]
  86. break
  87. }
  88. }
  89. }
  90. }
  91. return m, cmd
  92. }
  93. func (m model) View() string {
  94. return m.subMenus[m.currentSubMenu].View()
  95. }
  96. func (m model) createPlugin() {
  97. permission := m.subMenus[SUB_MENU_KEY_PERMISSION].(permission).Permission()
  98. manifest := &plugin_entities.PluginDeclaration{
  99. PluginDeclarationWithoutAdvancedFields: plugin_entities.PluginDeclarationWithoutAdvancedFields{
  100. Version: "0.0.1",
  101. Type: plugin_entities.PluginType,
  102. Icon: "icon.svg",
  103. Author: m.subMenus[SUB_MENU_KEY_PROFILE].(profile).Author(),
  104. Name: m.subMenus[SUB_MENU_KEY_PROFILE].(profile).Name(),
  105. Description: plugin_entities.I18nObject{
  106. EnUS: m.subMenus[SUB_MENU_KEY_PROFILE].(profile).Description(),
  107. },
  108. CreatedAt: time.Now(),
  109. Resource: plugin_entities.PluginResourceRequirement{
  110. Memory: 1024 * 1024 * 256, // 256MB
  111. Permission: &permission,
  112. },
  113. Label: plugin_entities.I18nObject{
  114. EnUS: m.subMenus[SUB_MENU_KEY_PROFILE].(profile).Name(),
  115. },
  116. },
  117. }
  118. category_string := m.subMenus[SUB_MENU_KEY_CATEGORY].(category).Category()
  119. if category_string == "tool" {
  120. manifest.Plugins.Tools = []string{fmt.Sprintf("provider/%s.yaml", manifest.Name)}
  121. }
  122. manifest.Meta = plugin_entities.PluginMeta{
  123. Version: "0.0.1",
  124. Arch: []constants.Arch{
  125. constants.AMD64,
  126. constants.ARM64,
  127. },
  128. Runner: plugin_entities.PluginRunner{},
  129. }
  130. switch m.subMenus[SUB_MENU_KEY_LANGUAGE].(language).Language() {
  131. case constants.Python:
  132. manifest.Meta.Runner.Entrypoint = "main"
  133. manifest.Meta.Runner.Language = constants.Python
  134. manifest.Meta.Runner.Version = "3.10"
  135. default:
  136. log.Error("unsupported language: %s", m.subMenus[SUB_MENU_KEY_LANGUAGE].(language).Language())
  137. return
  138. }
  139. success := false
  140. clear := func() {
  141. if !success {
  142. os.RemoveAll(manifest.Name)
  143. }
  144. }
  145. defer clear()
  146. manifest_file := marshalYamlBytes(manifest)
  147. // create the plugin directory
  148. cwd, err := os.Getwd()
  149. if err != nil {
  150. log.Error("failed to get current working directory: %s", err)
  151. return
  152. }
  153. plugin_dir := filepath.Join(cwd, manifest.Name)
  154. if err := os.MkdirAll(plugin_dir, 0o755); err != nil {
  155. log.Error("failed to create plugin directory: %s", err)
  156. return
  157. }
  158. manifest_file_path := filepath.Join(plugin_dir, "manifest.yaml")
  159. if err := os.WriteFile(manifest_file_path, manifest_file, 0o644); err != nil {
  160. log.Error("failed to write manifest file: %s", err)
  161. return
  162. }
  163. // create _assets directory
  164. assets_dir := filepath.Join(plugin_dir, "_assets")
  165. if err := os.MkdirAll(assets_dir, 0o755); err != nil {
  166. log.Error("failed to create assets directory: %s", err)
  167. return
  168. }
  169. // create icon.svg
  170. icon_file_path := filepath.Join(assets_dir, "icon.svg")
  171. if err := os.WriteFile(icon_file_path, icon, 0o644); err != nil {
  172. log.Error("failed to write icon file: %s", err)
  173. return
  174. }
  175. err = createPythonEnvironment(
  176. plugin_dir,
  177. manifest.Meta.Runner.Entrypoint,
  178. manifest,
  179. m.subMenus[SUB_MENU_KEY_CATEGORY].(category).Category(),
  180. )
  181. if err != nil {
  182. log.Error("failed to create python environment: %s", err)
  183. return
  184. }
  185. success = true
  186. log.Info("plugin %s created successfully", manifest.Name)
  187. }