Skip to content

Commit

Permalink
feat(text) : add sdk for claude
Browse files Browse the repository at this point in the history
  • Loading branch information
LordPax committed Sep 18, 2024
1 parent 08d0556 commit 3f23c1c
Show file tree
Hide file tree
Showing 11 changed files with 369 additions and 92 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

### Added

* Add interactive mode for text command
* Add parameter `history`, `model`, `temp`, `system` for text command
* Add history with name for text command
* Add sdk claude for text command
* Add sdk openai for text command
* Add localized for `en` and `fr`
* Read config.ini file
65 changes: 47 additions & 18 deletions commands/text.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package commands

import (
"errors"
"fmt"
"io"
"os"
"strconv"
Expand Down Expand Up @@ -60,27 +60,45 @@ func TextFlags() []cli.Flag {
return nil
},
},
&cli.StringFlag{
&cli.StringSliceFlag{
Name: "system",
Aliases: []string{"s"},
Usage: l.Get("text-system-usage"),
Action: func(c *cli.Context, value string) error {
if value == "-" {
stdin, err := io.ReadAll(os.Stdin)
Action: func(c *cli.Context, values []string) error {
for _, value := range values {
if value == "-" {
stdin, err := io.ReadAll(os.Stdin)
if err != nil {
return err
}

value = string(stdin)
}

textSdk.AppendHistory("system", value)
}

return nil
},
},
&cli.StringSliceFlag{
Name: "file",
Aliases: []string{"f"},
Usage: l.Get("text-file-usage"),
Action: func(c *cli.Context, files []string) error {
for _, file := range files {
f, err := os.ReadFile(file)
if err != nil {
return err
}

value = string(stdin)
}
if len(f) == 0 {
return fmt.Errorf(l.Get("empty-file"), file)
}

message := sdk.Message{
Role: "system",
Content: value,
textSdk.AppendHistory("system", string(f))
}

textSdk.AppendHistory(message)

return nil
},
},
Expand All @@ -97,19 +115,30 @@ func TextFlags() []cli.Flag {
return nil
},
},
&cli.BoolFlag{
Name: "list-history",
Aliases: []string{"l"},
Usage: l.Get("text-list-history-usage"),
Action: func(c *cli.Context, value bool) error {
if err := service.ListHistory(true, true); err != nil {
return err
}
os.Exit(0)
return nil
},
},
}
}

func textAction(c *cli.Context) error {
l := lang.GetLocalize()

if c.NArg() == 0 {
return errors.New(l.Get("no-args"))
if err := service.InteractiveMode(); err != nil {
return err
}
return nil
}

prompt := c.Args().First()

if err := service.SendTextRequest(prompt); err != nil {
if err := service.SendTextRequest(c.Args().First()); err != nil {
return err
}

Expand Down
19 changes: 10 additions & 9 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ import (
var home, _ = os.UserHomeDir()

var (
NAME = "aicli"
VERSION = "1.0.0"
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")
CONFIG_INI *ini.File
CONFIG_EXEMPLE = `
NAME = "aicli"
VERSION = "1.0.0"
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 = `
[text]
type=openai
model=gpt-4
Expand Down Expand Up @@ -58,7 +59,7 @@ func InitConfig() error {
}

if !utils.FileExist(HISTORY_FILE) {
if _, err := os.Create(HISTORY_FILE); err != nil {
if err := os.WriteFile(HISTORY_FILE, []byte(HISTORY_CONTENT), 0644); err != nil {
return err
}
fmt.Printf("History file created at %s\n", HISTORY_FILE)
Expand Down
37 changes: 22 additions & 15 deletions lang/en.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
package lang

import "github.com/LordPax/aicli/utils"

var EN_STRINGS = LangString{
"usage": "CLI toot to use ai model",
"output-desc": "Output directory",
"output-dir-empty": "Output directory is empty",
"silent": "Disable printing log to stdout",
"no-args": "No arguments provided",
"no-command": "No command provided",
"unknown-sdk": "Unknown sdk \"%s\"",
"sdk-model-usage": "Select a model",
"text-usage": "Generate text from a prompt",
"text-temp-usage": "Set temperature",
"text-system-usage": "Instruction with role system (use \"-\" for stdin)",
"text-history-usage": "Select a history",
"text-clear-usage": "Clear history",
"type-required": "Type is required",
"apiKey-required": "API key is required",
"usage": "CLI toot to use ai model",
"output-desc": "Output directory",
"output-dir-empty": "Output directory is empty",
"silent": "Disable printing log to stdout",
"no-args": "No arguments provided",
"no-command": "No command provided",
"unknown-sdk": "Unknown sdk \"%s\"",
"sdk-model-usage": "Select a model",
"text-usage": "Generate text from a prompt",
"text-temp-usage": "Set temperature",
"text-system-usage": "Instruction with role system (use \"-\" for stdin)",
"text-history-usage": "Select a history",
"text-clear-usage": "Clear history",
"text-file-usage": "Text file to use",
"text-input": "(\"exit\" to quit) " + utils.Blue + "user> " + utils.Reset,
"text-list-history-usage": "List history",
"type-required": "Type is required",
"apiKey-required": "API key is required",
"empty-file": "File \"%s\" is empty",
"empty-history": "History \"%s\" is empty\n",
}
37 changes: 22 additions & 15 deletions lang/fr.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
package lang

import "github.com/LordPax/aicli/utils"

var FR_STRINGS = LangString{
"usage": "CLI pour utiliser des modèles d'IA",
"output-desc": "Répertoire de sortie",
"output-dir-empty": "Le répertoire de sortie est vide",
"silent": "Désactiver l'impression du journal sur stdout",
"no-args": "Aucun argument fourni",
"no-command": "Aucune commande fournie",
"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-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",
"text-clear-usage": "Effacer l'historique",
"type-required": "Le type est requis",
"apiKey-required": "La clé API est requise",
"usage": "CLI pour utiliser des modèles d'IA",
"output-desc": "Répertoire de sortie",
"output-dir-empty": "Le répertoire de sortie est vide",
"silent": "Désactiver l'impression du journal sur stdout",
"no-args": "Aucun argument fourni",
"no-command": "Aucune commande fournie",
"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-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",
"text-clear-usage": "Effacer l'historique",
"text-file-usage": "Fichier texte à utiliser",
"text-input": "(\"exit\" pour quitter) " + utils.Blue + "user> " + utils.Reset,
"text-list-history-usage": "Lister l'historique",
"type-required": "Le type est requis",
"apiKey-required": "La clé API est requise",
"empty-file": "Le fichier est vide",
"empty-history": "L'historique \"%s\" est vide\n",
}
100 changes: 100 additions & 0 deletions sdk/claude.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package sdk

import (
"encoding/json"
"errors"
"io"
"net/http"

"github.com/LordPax/aicli/utils"
)

type ClaudeResponse struct {
Role string `json:"role"`
Content []Content `json:"content"`
}

type ClaudeText struct {
Sdk
SdkText
}

// Initialize ClaudeText struct, inheriting from Sdk and SdkText
func NewClaudeText(apiKey, model string, temp float64) (*ClaudeText, error) {
sdkService := &ClaudeText{
Sdk: Sdk{
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,
},
}

if model != "" {
sdkService.Model = model
}

if temp != 0 {
sdkService.Temp = temp
}

if err := sdkService.LoadHistory(); err != nil {
return nil, err
}

return sdkService, nil
}

func (c *ClaudeText) SendRequest(text string) (Message, error) {
var textResponse ClaudeResponse

c.AppendHistory("user", text)

jsonBody, err := json.Marshal(TextBody{
Model: c.Model,
// MaxTokens: 1024,
Messages: c.GetHistory(),
})
if err != nil {
return Message{}, err
}

resp, err := utils.PostRequest(c.ApiUrl, jsonBody, map[string]string{
"Content-Type": "application/json",
"anthropic-version": "2023-06-01",
"x-api-key": c.ApiKey,
})
if err != nil {
return Message{}, err
}
defer resp.Body.Close()

respBody, err := io.ReadAll(resp.Body)
if err != nil {
return Message{}, err
}

if resp.StatusCode != http.StatusOK {
var errorMsg ErrorMsg
if err := json.Unmarshal(respBody, &errorMsg); err != nil {
return Message{}, err
}
return Message{}, errors.New(errorMsg.Error.Message)
}

if err := json.Unmarshal(respBody, &textResponse); err != nil {
return Message{}, err
}

respMessage := c.AppendHistory(textResponse.Role, textResponse.Content[0].Text)

if err := c.SaveHistory(); err != nil {
return Message{}, err
}

return respMessage, nil
}
31 changes: 16 additions & 15 deletions sdk/openai-text.go → sdk/openai.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@ package sdk
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"

"github.com/LordPax/aicli/utils"
)

type OpenaiResponse struct {
Choices Choices `json:"choices"`
}

type Choices []struct {
Index int64 `json:"index"`
Message Message `json:"message"`
}

type OpenaiText struct {
Sdk
SdkText
Expand Down Expand Up @@ -46,28 +54,21 @@ func NewOpenaiText(apiKey, model string, temp float64) (*OpenaiText, error) {
}

func (o *OpenaiText) SendRequest(text string) (Message, error) {
var textResponse TextResponse
var textResponse OpenaiResponse

message := Message{
Role: "user",
Content: text,
}
o.AppendHistory("user", text)

o.AppendHistory(message)

body := TextBody{
jsonBody, err := json.Marshal(TextBody{
Model: o.Model,
Messages: o.GetHistory(),
}

jsonBody, err := json.Marshal(body)
})
if err != nil {
return Message{}, err
}

resp, err := utils.PostRequest(o.ApiUrl, jsonBody, map[string]string{
"Content-Type": "application/json",
"Authorization": fmt.Sprintf("Bearer %s", o.ApiKey),
"Authorization": "Bearer " + o.ApiKey,
})
if err != nil {
return Message{}, err
Expand All @@ -91,8 +92,8 @@ func (o *OpenaiText) SendRequest(text string) (Message, error) {
return Message{}, err
}

respMessage := textResponse.Choices[0].Message
o.AppendHistory(respMessage)
msg := textResponse.Choices[0].Message
respMessage := o.AppendHistory(msg.Role, msg.Content)

if err := o.SaveHistory(); err != nil {
return Message{}, err
Expand Down
Loading

0 comments on commit 3f23c1c

Please sign in to comment.