package cli import ( "encoding/json" "fmt" "os" "path/filepath" "strconv" "strings" "github.com/danielmiessler/fabric/plugins/tools/youtube" "github.com/danielmiessler/fabric/common" "github.com/danielmiessler/fabric/core" "github.com/danielmiessler/fabric/plugins/ai" "github.com/danielmiessler/fabric/plugins/db/fsdb" "github.com/danielmiessler/fabric/plugins/tools/converter" "github.com/danielmiessler/fabric/restapi" ) // Cli Controls the cli. It takes in the flags and runs the appropriate functions func Cli(version string) (err error) { var currentFlags *Flags if currentFlags, err = Init(); err != nil { return } if currentFlags.Version { fmt.Println(version) return } var homedir string if homedir, err = os.UserHomeDir(); err != nil { return } fabricDb := fsdb.NewDb(filepath.Join(homedir, ".config/fabric")) if err = fabricDb.Configure(); err != nil { if !currentFlags.Setup { println(err.Error()) currentFlags.Setup = true } } var registry *core.PluginRegistry if registry, err = core.NewPluginRegistry(fabricDb); err != nil { return } // if the setup flag is set, run the setup function if currentFlags.Setup { err = registry.Setup() return } if currentFlags.Serve { registry.ConfigureVendors() err = restapi.Serve(registry, currentFlags.ServeAddress, currentFlags.ServeAPIKey) return } if currentFlags.ServeOllama { registry.ConfigureVendors() err = restapi.ServeOllama(registry, currentFlags.ServeAddress, version) return } if currentFlags.UpdatePatterns { err = registry.PatternsLoader.PopulateDB() return } if currentFlags.ChangeDefaultModel { if err = registry.Defaults.Setup(); err != nil { return } err = registry.SaveEnvFile() return } if currentFlags.LatestPatterns != "0" { var parsedToInt int if parsedToInt, err = strconv.Atoi(currentFlags.LatestPatterns); err != nil { return } if err = fabricDb.Patterns.PrintLatestPatterns(parsedToInt); err != nil { return } return } if currentFlags.ListPatterns { err = fabricDb.Patterns.ListNames(currentFlags.ShellCompleteOutput) return } if currentFlags.ListAllModels { var models *ai.VendorsModels if models, err = registry.VendorManager.GetModels(); err != nil { return } models.Print(currentFlags.ShellCompleteOutput) return } if currentFlags.ListAllContexts { err = fabricDb.Contexts.ListNames(currentFlags.ShellCompleteOutput) return } if currentFlags.ListAllSessions { err = fabricDb.Sessions.ListNames(currentFlags.ShellCompleteOutput) return } if currentFlags.WipeContext != "" { err = fabricDb.Contexts.Delete(currentFlags.WipeContext) return } if currentFlags.WipeSession != "" { err = fabricDb.Sessions.Delete(currentFlags.WipeSession) return } if currentFlags.PrintSession != "" { err = fabricDb.Sessions.PrintSession(currentFlags.PrintSession) return } if currentFlags.PrintContext != "" { err = fabricDb.Contexts.PrintContext(currentFlags.PrintContext) return } if currentFlags.HtmlReadability { if msg, cleanErr := converter.HtmlReadability(currentFlags.Message); cleanErr != nil { fmt.Println("use original input, because can't apply html readability", err) } else { currentFlags.Message = msg } } if currentFlags.ListExtensions { err = registry.TemplateExtensions.ListExtensions() return } if currentFlags.AddExtension != "" { err = registry.TemplateExtensions.RegisterExtension(currentFlags.AddExtension) return } if currentFlags.RemoveExtension != "" { err = registry.TemplateExtensions.RemoveExtension(currentFlags.RemoveExtension) return } if currentFlags.ListStrategies { err = registry.Strategies.ListStrategies(currentFlags.ShellCompleteOutput) return } if currentFlags.ListVendors { err = registry.ListVendors(os.Stdout) return } // if the interactive flag is set, run the interactive function // if currentFlags.Interactive { // interactive.Interactive() // } // if none of the above currentFlags are set, run the initiate chat function var messageTools string if currentFlags.YouTube != "" { if !registry.YouTube.IsConfigured() { err = fmt.Errorf("YouTube is not configured, please run the setup procedure") return } var videoId string var playlistId string if videoId, playlistId, err = registry.YouTube.GetVideoOrPlaylistId(currentFlags.YouTube); err != nil { return } else if (videoId == "" || currentFlags.YouTubePlaylist) && playlistId != "" { if currentFlags.Output != "" { err = registry.YouTube.FetchAndSavePlaylist(playlistId, currentFlags.Output) } else { var videos []*youtube.VideoMeta if videos, err = registry.YouTube.FetchPlaylistVideos(playlistId); err != nil { err = fmt.Errorf("error fetching playlist videos: %v", err) return } for _, video := range videos { var message string if message, err = processYoutubeVideo(currentFlags, registry, video.Id); err != nil { return } if !currentFlags.IsChatRequest() { if err = WriteOutput(message, fmt.Sprintf("%v.md", video.TitleNormalized)); err != nil { return } } else { messageTools = AppendMessage(messageTools, message) } } } return } if messageTools, err = processYoutubeVideo(currentFlags, registry, videoId); err != nil { return } if !currentFlags.IsChatRequest() { err = currentFlags.WriteOutput(messageTools) return } } if (currentFlags.ScrapeURL != "" || currentFlags.ScrapeQuestion != "") && registry.Jina.IsConfigured() { // Check if the scrape_url flag is set and call ScrapeURL if currentFlags.ScrapeURL != "" { var website string if website, err = registry.Jina.ScrapeURL(currentFlags.ScrapeURL); err != nil { return } messageTools = AppendMessage(messageTools, website) } // Check if the scrape_question flag is set and call ScrapeQuestion if currentFlags.ScrapeQuestion != "" { var website string if website, err = registry.Jina.ScrapeQuestion(currentFlags.ScrapeQuestion); err != nil { return } messageTools = AppendMessage(messageTools, website) } if !currentFlags.IsChatRequest() { err = currentFlags.WriteOutput(messageTools) return } } if messageTools != "" { currentFlags.AppendMessage(messageTools) } var chatter *core.Chatter if chatter, err = registry.GetChatter(currentFlags.Model, currentFlags.ModelContextLength, currentFlags.Strategy, currentFlags.Stream, currentFlags.DryRun); err != nil { return } var session *fsdb.Session var chatReq *common.ChatRequest if chatReq, err = currentFlags.BuildChatRequest(strings.Join(os.Args[1:], " ")); err != nil { return } if chatReq.Language == "" { chatReq.Language = registry.Language.DefaultLanguage.Value } var chatOptions *common.ChatOptions if chatOptions, err = currentFlags.BuildChatOptions(); err != nil { return } if session, err = chatter.Send(chatReq, chatOptions); err != nil { return } result := session.GetLastMessage().Content if !currentFlags.Stream { // print the result if it was not streamed already fmt.Println(result) } // if the copy flag is set, copy the message to the clipboard if currentFlags.Copy { if err = CopyToClipboard(result); err != nil { return } } // if the output flag is set, create an output file if currentFlags.Output != "" { if currentFlags.OutputSession { sessionAsString := session.String() err = CreateOutputFile(sessionAsString, currentFlags.Output) } else { err = CreateOutputFile(result, currentFlags.Output) } } return } func processYoutubeVideo( flags *Flags, registry *core.PluginRegistry, videoId string) (message string, err error) { if (!flags.YouTubeComments && !flags.YouTubeMetadata) || flags.YouTubeTranscript || flags.YouTubeTranscriptWithTimestamps { var transcript string var language = "en" if flags.Language != "" || registry.Language.DefaultLanguage.Value != "" { if flags.Language != "" { language = flags.Language } else { language = registry.Language.DefaultLanguage.Value } } if flags.YouTubeTranscriptWithTimestamps { if transcript, err = registry.YouTube.GrabTranscriptWithTimestamps(videoId, language); err != nil { return } } else { if transcript, err = registry.YouTube.GrabTranscript(videoId, language); err != nil { return } } message = AppendMessage(message, transcript) } if flags.YouTubeComments { var comments []string if comments, err = registry.YouTube.GrabComments(videoId); err != nil { return } commentsString := strings.Join(comments, "\n") message = AppendMessage(message, commentsString) } if flags.YouTubeMetadata { var metadata *youtube.VideoMetadata if metadata, err = registry.YouTube.GrabMetadata(videoId); err != nil { return } metadataJson, _ := json.MarshalIndent(metadata, "", " ") message = AppendMessage(message, string(metadataJson)) } return } func WriteOutput(message string, outputFile string) (err error) { fmt.Println(message) if outputFile != "" { err = CreateOutputFile(message, outputFile) } return }