2024-08-16 19:43:27 +00:00
|
|
|
package core
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"github.com/atotto/clipboard"
|
|
|
|
"github.com/danielmiessler/fabric/common"
|
|
|
|
"github.com/danielmiessler/fabric/db"
|
|
|
|
"github.com/danielmiessler/fabric/vendors/anthropic"
|
|
|
|
"github.com/danielmiessler/fabric/vendors/azure"
|
|
|
|
"github.com/danielmiessler/fabric/vendors/gemini"
|
|
|
|
"github.com/danielmiessler/fabric/vendors/grocq"
|
|
|
|
"github.com/danielmiessler/fabric/vendors/ollama"
|
|
|
|
"github.com/danielmiessler/fabric/vendors/openai"
|
2024-08-16 22:29:21 +00:00
|
|
|
"github.com/danielmiessler/fabric/youtube"
|
2024-08-16 19:43:27 +00:00
|
|
|
"github.com/pkg/errors"
|
2024-08-16 22:01:55 +00:00
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
2024-08-16 19:43:27 +00:00
|
|
|
)
|
|
|
|
|
2024-08-16 22:01:55 +00:00
|
|
|
const DefaultPatternsGitRepoUrl = "https://github.com/danielmiessler/fabric.git"
|
|
|
|
const DefaultPatternsGitRepoFolder = "patterns"
|
2024-08-16 19:43:27 +00:00
|
|
|
|
|
|
|
func NewFabric(db *db.Db) (ret *Fabric, err error) {
|
|
|
|
ret = NewFabricBase(db)
|
|
|
|
err = ret.Configure()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewFabricForSetup(db *db.Db) (ret *Fabric) {
|
|
|
|
ret = NewFabricBase(db)
|
|
|
|
_ = ret.Configure()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewFabricBase Create a new Fabric from a list of already configured VendorsController
|
|
|
|
func NewFabricBase(db *db.Db) (ret *Fabric) {
|
2024-08-16 22:01:55 +00:00
|
|
|
|
2024-08-16 19:43:27 +00:00
|
|
|
ret = &Fabric{
|
2024-08-16 22:01:55 +00:00
|
|
|
VendorsManager: NewVendorsManager(),
|
|
|
|
Db: db,
|
|
|
|
VendorsAll: NewVendorsManager(),
|
|
|
|
PatternsLoader: NewPatternsLoader(db.Patterns),
|
2024-08-16 22:29:21 +00:00
|
|
|
YouTube: youtube.NewYouTube(),
|
2024-08-16 19:43:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
label := "Default"
|
|
|
|
ret.Configurable = &common.Configurable{
|
|
|
|
Label: label,
|
|
|
|
EnvNamePrefix: common.BuildEnvVariablePrefix(label),
|
|
|
|
ConfigureCustom: ret.configure,
|
|
|
|
}
|
|
|
|
|
|
|
|
ret.DefaultVendor = ret.AddSetting("Vendor", true)
|
|
|
|
ret.DefaultModel = ret.AddSetupQuestionCustom("Model", true,
|
|
|
|
"Enter the index the name of your default model")
|
|
|
|
|
2024-08-16 22:01:55 +00:00
|
|
|
ret.VendorsAll.AddVendors(openai.NewClient(), azure.NewClient(), ollama.NewClient(), grocq.NewClient(),
|
2024-08-16 19:43:27 +00:00
|
|
|
gemini.NewClient(), anthropic.NewClient())
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
type Fabric struct {
|
|
|
|
*common.Configurable
|
2024-08-16 22:01:55 +00:00
|
|
|
*VendorsManager
|
|
|
|
VendorsAll *VendorsManager
|
2024-08-16 19:43:27 +00:00
|
|
|
*PatternsLoader
|
2024-08-16 22:29:21 +00:00
|
|
|
*youtube.YouTube
|
2024-08-16 19:43:27 +00:00
|
|
|
|
|
|
|
Db *db.Db
|
|
|
|
|
|
|
|
DefaultVendor *common.Setting
|
|
|
|
DefaultModel *common.SetupQuestion
|
|
|
|
}
|
|
|
|
|
|
|
|
type ChannelName struct {
|
|
|
|
channel chan []string
|
|
|
|
name string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *Fabric) SaveEnvFile() (err error) {
|
|
|
|
// Now create the .env with all configured VendorsController info
|
|
|
|
var envFileContent bytes.Buffer
|
|
|
|
|
|
|
|
o.Settings.FillEnvFileContent(&envFileContent)
|
|
|
|
o.PatternsLoader.FillEnvFileContent(&envFileContent)
|
|
|
|
|
2024-08-16 22:01:55 +00:00
|
|
|
for _, vendor := range o.Vendors {
|
2024-08-16 19:43:27 +00:00
|
|
|
vendor.GetSettings().FillEnvFileContent(&envFileContent)
|
|
|
|
}
|
|
|
|
|
2024-08-16 22:29:21 +00:00
|
|
|
o.YouTube.FillEnvFileContent(&envFileContent)
|
|
|
|
|
2024-08-16 19:43:27 +00:00
|
|
|
err = o.Db.SaveEnv(envFileContent.String())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *Fabric) Setup() (err error) {
|
|
|
|
if err = o.SetupVendors(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = o.SetupDefaultModel(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = o.PatternsLoader.Setup(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = o.SaveEnvFile()
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *Fabric) SetupDefaultModel() (err error) {
|
|
|
|
vendorsModels := o.GetModels()
|
|
|
|
|
|
|
|
vendorsModels.Print()
|
|
|
|
|
|
|
|
if err = o.Ask(o.Label); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
index, parseErr := strconv.Atoi(o.DefaultModel.Value)
|
|
|
|
if parseErr == nil {
|
|
|
|
o.DefaultVendor.Value, o.DefaultModel.Value = vendorsModels.GetVendorAndModelByModelIndex(index)
|
|
|
|
} else {
|
|
|
|
o.DefaultVendor.Value = vendorsModels.FindVendorsByModelFirst(o.DefaultModel.Value)
|
|
|
|
}
|
|
|
|
|
2024-08-16 22:01:55 +00:00
|
|
|
//verify
|
2024-08-16 19:43:27 +00:00
|
|
|
vendorNames := vendorsModels.FindVendorsByModel(o.DefaultModel.Value)
|
|
|
|
if len(vendorNames) == 0 {
|
|
|
|
err = errors.Errorf("You need to chose an available default model.")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println()
|
|
|
|
o.DefaultVendor.Print()
|
|
|
|
o.DefaultModel.Print()
|
|
|
|
|
|
|
|
err = o.SaveEnvFile()
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *Fabric) SetupVendors() (err error) {
|
2024-08-16 22:01:55 +00:00
|
|
|
o.Reset()
|
2024-08-16 19:43:27 +00:00
|
|
|
|
2024-08-16 22:01:55 +00:00
|
|
|
for _, vendor := range o.VendorsAll.Vendors {
|
2024-08-16 19:43:27 +00:00
|
|
|
fmt.Println()
|
|
|
|
if vendorErr := vendor.Setup(); vendorErr == nil {
|
|
|
|
fmt.Printf("[%v] configured\n", vendor.GetName())
|
2024-08-16 22:01:55 +00:00
|
|
|
o.AddVendors(vendor)
|
2024-08-16 19:43:27 +00:00
|
|
|
} else {
|
|
|
|
fmt.Printf("[%v] skiped\n", vendor.GetName())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-16 22:01:55 +00:00
|
|
|
if !o.HasVendors() {
|
2024-08-16 19:43:27 +00:00
|
|
|
err = errors.New("No vendors configured")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = o.SaveEnvFile()
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Configure buildClient VendorsController based on the environment variables
|
|
|
|
func (o *Fabric) configure() (err error) {
|
2024-08-16 22:01:55 +00:00
|
|
|
for _, vendor := range o.VendorsAll.Vendors {
|
2024-08-16 19:43:27 +00:00
|
|
|
if vendorErr := vendor.Configure(); vendorErr == nil {
|
2024-08-16 22:01:55 +00:00
|
|
|
o.AddVendors(vendor)
|
2024-08-16 19:43:27 +00:00
|
|
|
}
|
|
|
|
}
|
2024-08-16 22:29:21 +00:00
|
|
|
if err = o.PatternsLoader.Configure(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = o.YouTube.Configure()
|
|
|
|
|
2024-08-16 19:43:27 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *Fabric) GetChatter(model string, stream bool) (ret *Chatter, err error) {
|
|
|
|
ret = &Chatter{
|
|
|
|
db: o.Db,
|
|
|
|
Stream: stream,
|
|
|
|
}
|
|
|
|
|
|
|
|
if model == "" {
|
|
|
|
ret.vendor = o.FindByName(o.DefaultVendor.Value)
|
|
|
|
ret.model = o.DefaultModel.Value
|
|
|
|
} else {
|
|
|
|
ret.vendor = o.FindByName(o.GetModels().FindVendorsByModelFirst(model))
|
|
|
|
ret.model = model
|
|
|
|
}
|
|
|
|
|
|
|
|
if ret.vendor == nil {
|
|
|
|
err = fmt.Errorf(
|
|
|
|
"could not find vendor.\n Model = %s\n DefaultModel = %s\n DefaultVendor = %s",
|
|
|
|
model, o.DefaultModel.Value, o.DefaultVendor.Value)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *Fabric) CopyToClipboard(message string) (err error) {
|
|
|
|
if err = clipboard.WriteAll(message); err != nil {
|
|
|
|
err = fmt.Errorf("could not copy to clipboard: %v", err)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *Fabric) CreateOutputFile(message string, fileName string) (err error) {
|
|
|
|
var file *os.File
|
|
|
|
if file, err = os.Create(fileName); err != nil {
|
|
|
|
err = fmt.Errorf("error creating file: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
if _, err = file.WriteString(message); err != nil {
|
|
|
|
err = fmt.Errorf("error writing to file: %v", err)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-08-16 22:01:55 +00:00
|
|
|
func (o *Chat) BuildChatSession() (ret *db.Session, err error) {
|
|
|
|
// new messages will be appended to the session and used to send the message
|
|
|
|
if o.Session != nil {
|
|
|
|
ret = o.Session
|
|
|
|
} else {
|
|
|
|
ret = &db.Session{}
|
2024-08-16 19:43:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
systemMessage := strings.TrimSpace(o.Context) + strings.TrimSpace(o.Pattern)
|
|
|
|
|
|
|
|
if systemMessage != "" {
|
2024-08-16 22:01:55 +00:00
|
|
|
ret.Append(&common.Message{Role: "system", Content: systemMessage})
|
2024-08-16 19:43:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
userMessage := strings.TrimSpace(o.Message)
|
|
|
|
if userMessage != "" {
|
2024-08-16 22:01:55 +00:00
|
|
|
ret.Append(&common.Message{Role: "user", Content: userMessage})
|
2024-08-16 19:43:27 +00:00
|
|
|
}
|
|
|
|
|
2024-08-16 22:01:55 +00:00
|
|
|
if ret.IsEmpty() {
|
|
|
|
ret = nil
|
2024-08-16 19:43:27 +00:00
|
|
|
err = fmt.Errorf("no session, pattern or user messages provided")
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|