diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a95d5f..ab62ff2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,15 @@ ### Added * Add interactive mode for text command -* Add parameter `history`, `model`, `temp`, `system` for text command +* Add parameter for text command + * `sdk` : Select the sdk to use + * `history` : Select the history to use + * `model` : Select the model to use + * `temp` : Set the temperature + * `system` : Prompt with system role + * `file` : Add content of file text to history + * `clear` : Clear the history + * `list-history` : List all history * Add history with name for text command * Add sdk claude for text command * Add sdk openai for text command diff --git a/commands/text.go b/commands/text.go index b8050a8..c6e4445 100644 --- a/commands/text.go +++ b/commands/text.go @@ -30,6 +30,18 @@ func TextFlags() []cli.Flag { textSdk := sdk.GetSdkText() return []cli.Flag{ + &cli.StringFlag{ + Name: "sdk", + Aliases: []string{"S"}, + Usage: l.Get("text-sdk-usage"), + DefaultText: textSdk.GetName(), + Action: func(c *cli.Context, value string) error { + if err := sdk.InitSdkText(value); err != nil { + return err + } + return nil + }, + }, &cli.StringFlag{ Name: "history", Aliases: []string{"H"}, diff --git a/config/config.go b/config/config.go index edb4b54..d1b3a85 100644 --- a/config/config.go +++ b/config/config.go @@ -18,7 +18,6 @@ var ( CONFIG_DIR = path.Join(home, ".config", "aicli") CONFIG_FILE = path.Join(CONFIG_DIR, "config.ini") LOG_FILE = path.Join(CONFIG_DIR, "log") - HISTORY_FILE = path.Join(CONFIG_DIR, "history.json") HISTORY_CONTENT = "{ \"default\": [] }" CONFIG_INI *ini.File CONFIG_EXEMPLE = ` @@ -58,13 +57,6 @@ func InitConfig() error { fmt.Printf("Log file created at %s\n", LOG_FILE) } - if !utils.FileExist(HISTORY_FILE) { - if err := os.WriteFile(HISTORY_FILE, []byte(HISTORY_CONTENT), 0644); err != nil { - return err - } - fmt.Printf("History file created at %s\n", HISTORY_FILE) - } - os.Setenv("LOG_FILE", LOG_FILE) return nil diff --git a/lang/en.go b/lang/en.go index 08b49ea..087dbc1 100644 --- a/lang/en.go +++ b/lang/en.go @@ -12,6 +12,7 @@ var EN_STRINGS = LangString{ "unknown-sdk": "Unknown sdk \"%s\"", "sdk-model-usage": "Select a model", "text-usage": "Generate text from a prompt", + "text-sdk-usage": "Select a sdk", "text-temp-usage": "Set temperature", "text-system-usage": "Instruction with role system (use \"-\" for stdin)", "text-history-usage": "Select a history", diff --git a/lang/fr.go b/lang/fr.go index d2a84a3..25173d0 100644 --- a/lang/fr.go +++ b/lang/fr.go @@ -12,6 +12,7 @@ var FR_STRINGS = LangString{ "unknown-sdk": "Sdk inconnu \"%s\"", "sdk-model-usage": "Sélectionner un modèle", "text-usage": "Générer du texte à partir d'un prompt", + "text-sdk-usage": "Sélectionner un sdk", "text-temp-usage": "Définir la température", "text-system-usage": "Instruction avec rôle système (utilisez \"-\" pour stdin)", "text-history-usage": "Sélectionner un historique", diff --git a/sdk/claude.go b/sdk/claude.go index 0f97ce4..3538689 100644 --- a/sdk/claude.go +++ b/sdk/claude.go @@ -27,21 +27,27 @@ type ClaudeBody struct { type ClaudeText struct { Sdk SdkText + TextHistory } // Initialize ClaudeText struct, inheriting from Sdk and SdkText func NewClaudeText(apiKey, model string, temp float64) (*ClaudeText, error) { + history, err := NewTextHistory("claude") + if err != nil { + return nil, err + } + sdkService := &ClaudeText{ Sdk: Sdk{ + Name: "claude", ApiUrl: "https://api.anthropic.com/v1/messages", ApiKey: apiKey, Model: "claude-3-5-sonnet-20240620", }, SdkText: SdkText{ - History: make(map[string][]Message), - SelectedHistory: "default", - Temp: 0.7, + Temp: 0.7, }, + TextHistory: *history, } if model != "" { diff --git a/sdk/history.go b/sdk/history.go new file mode 100644 index 0000000..1e63b17 --- /dev/null +++ b/sdk/history.go @@ -0,0 +1,123 @@ +package sdk + +import ( + "encoding/json" + "os" + "path" + + "github.com/LordPax/aicli/config" + "github.com/LordPax/aicli/utils" +) + +type ITextHistory interface { + AppendHistory(role string, text ...string) Message + SaveHistory() error + LoadHistory() error + GetHistory() []Message + SetSelectedHistory(name string) + GetSelectedHistory() string + ClearHistory() +} + +type TextHistory struct { + History map[string][]Message + SelectedHistory string + HistoryFile string +} + +func NewTextHistory(sdk string) (*TextHistory, error) { + historyFile := path.Join(config.CONFIG_DIR, sdk+"-history.json") + log, err := utils.GetLog() + if err != nil { + return nil, err + } + + if !utils.FileExist(historyFile) { + if err := os.WriteFile(historyFile, []byte(config.HISTORY_CONTENT), 0644); err != nil { + return nil, err + } + log.Logf("History file created at %s\n", historyFile) + } + + history := &TextHistory{ + History: make(map[string][]Message), + SelectedHistory: "default", + HistoryFile: historyFile, + } + + return history, nil +} + +func (t *TextHistory) SetSelectedHistory(name string) { + t.SelectedHistory = name +} + +func (t *TextHistory) GetSelectedHistory() string { + return t.SelectedHistory +} + +func (t *TextHistory) AppendHistory(role string, text ...string) Message { + var content []Content + + for _, t := range text { + content = append(content, Content{ + Type: "text", + Text: t, + }) + } + + name := t.SelectedHistory + message := Message{ + Role: role, + Content: content, + } + t.History[name] = append(t.History[name], message) + + return message +} + +func (t *TextHistory) SaveHistory() error { + f, err := os.Create(t.HistoryFile) + if err != nil { + return err + } + defer f.Close() + + jsonHistory, err := json.Marshal(t.History) + if err != nil { + return err + } + + if _, err := f.Write(jsonHistory); err != nil { + return err + } + + return nil +} + +func (t *TextHistory) LoadHistory() error { + f, err := os.ReadFile(t.HistoryFile) + if err != nil { + return err + } + + if len(f) == 0 { + return nil + } + + if err := json.Unmarshal(f, &t.History); err != nil { + return err + } + + return nil +} + +func (t *TextHistory) ClearHistory() { + name := t.SelectedHistory + t.History[name] = []Message{} +} + +func (t *TextHistory) GetHistory() []Message { + name := t.SelectedHistory + return t.History[name] +} diff --git a/sdk/openai.go b/sdk/openai.go index 2920262..2014553 100644 --- a/sdk/openai.go +++ b/sdk/openai.go @@ -35,21 +35,27 @@ type OpenaiBody struct { type OpenaiText struct { Sdk SdkText + TextHistory } // Initialize OpenaiText struct, inheriting from Sdk and SdkText func NewOpenaiText(apiKey, model string, temp float64) (*OpenaiText, error) { + history, err := NewTextHistory("openai") + if err != nil { + return nil, err + } + sdkService := &OpenaiText{ Sdk: Sdk{ + Name: "openai", ApiUrl: "https://api.openai.com/v1/chat/completions", ApiKey: apiKey, Model: "gpt-4", }, SdkText: SdkText{ - History: make(map[string][]Message), - SelectedHistory: "default", - Temp: 0.7, + Temp: 0.7, }, + TextHistory: *history, } if model != "" { diff --git a/sdk/sdk.go b/sdk/sdk.go index b7cc138..bd17175 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -14,14 +14,20 @@ type ISdk interface { SendRequest(text string) (Message, error) SetModel(model string) GetModel() string + GetName() string } type Sdk struct { + Name string ApiUrl string ApiKey string Model string } +func (s *Sdk) GetName() string { + return s.Name +} + func (s *Sdk) SetModel(model string) { s.Model = model } @@ -30,11 +36,11 @@ func (s *Sdk) GetModel() string { return s.Model } -func InitSdkText() error { +func InitSdkText(sdk string) error { var err error l := lang.GetLocalize() - sdkType, apiKey, model, temp, err := getConfigText() + sdkType, apiKey, model, temp, err := getConfigText(sdk) if err != nil { return err } @@ -55,13 +61,15 @@ func InitSdkText() error { return nil } -func getConfigText() (string, string, string, float64, error) { +func getConfigText(sdkType string) (string, string, string, float64, error) { l := lang.GetLocalize() confText := config.CONFIG_INI.Section("text") - sdkType := confText.Key("type").String() if sdkType == "" { - return "", "", "", 0, errors.New(l.Get("type-required")) + sdkType = confText.Key("type").String() + if sdkType == "" { + return "", "", "", 0, errors.New(l.Get("type-required")) + } } apiKey := confText.Key("apiKey").String() @@ -86,7 +94,7 @@ func getConfigText() (string, string, string, float64, error) { } func InitSdk() error { - if err := InitSdkText(); err != nil { + if err := InitSdkText(""); err != nil { return err } @@ -98,3 +106,7 @@ func InitSdk() error { func GetSdkText() ITextService { return sdkTextInstance } + +func SetSdkText(s ITextService) { + sdkTextInstance = s +} diff --git a/sdk/text.go b/sdk/text.go index e8da4dd..e90abd8 100644 --- a/sdk/text.go +++ b/sdk/text.go @@ -1,12 +1,5 @@ package sdk -import ( - "encoding/json" - "os" - - "github.com/LordPax/aicli/config" -) - type Content struct { Type string `json:"type"` Text string `json:"text"` @@ -35,32 +28,16 @@ type ErrorMsg struct { type ITextService interface { ISdk ISdkText + ITextHistory } type ISdkText interface { SetTemp(temp float64) GetTemp() float64 - AppendHistory(role string, text ...string) Message - SaveHistory() error - LoadHistory() error - GetHistory() []Message - SetSelectedHistory(name string) - GetSelectedHistory() string - ClearHistory() } type SdkText struct { - History map[string][]Message - SelectedHistory string - Temp float64 -} - -func (s *SdkText) SetSelectedHistory(name string) { - s.SelectedHistory = name -} - -func (s *SdkText) GetSelectedHistory() string { - return s.SelectedHistory + Temp float64 } func (s *SdkText) SetTemp(temp float64) { @@ -70,69 +47,3 @@ func (s *SdkText) SetTemp(temp float64) { func (s *SdkText) GetTemp() float64 { return s.Temp } - -func (s *SdkText) AppendHistory(role string, text ...string) Message { - var content []Content - - for _, t := range text { - content = append(content, Content{ - Type: "text", - Text: t, - }) - } - - name := s.SelectedHistory - message := Message{ - Role: role, - Content: content, - } - s.History[name] = append(s.History[name], message) - - return message -} - -func (s *SdkText) SaveHistory() error { - f, err := os.Create(config.HISTORY_FILE) - if err != nil { - return err - } - defer f.Close() - - jsonHistory, err := json.Marshal(s.History) - if err != nil { - return err - } - - if _, err := f.Write(jsonHistory); err != nil { - return err - } - - return nil -} - -func (s *SdkText) LoadHistory() error { - f, err := os.ReadFile(config.HISTORY_FILE) - if err != nil { - return err - } - - if len(f) == 0 { - return nil - } - - if err := json.Unmarshal(f, &s.History); err != nil { - return err - } - - return nil -} - -func (s *SdkText) ClearHistory() { - name := s.SelectedHistory - s.History[name] = []Message{} -} - -func (s *SdkText) GetHistory() []Message { - name := s.SelectedHistory - return s.History[name] -} diff --git a/utils/log.go b/utils/log.go index 4f2e875..3e49ddc 100644 --- a/utils/log.go +++ b/utils/log.go @@ -83,6 +83,15 @@ func (l *Log) PrintfErr(format string, a ...any) { } } +func (l *Log) Logf(format string, a ...any) { + text := fmt.Sprintf(format, a...) + + if err := l.WriteLog(text); err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + os.Exit(1) + } +} + func (l *Log) Close() error { return l.file.Close() }