From 439e3b1f4bd35dfff01c05a9b225622c6a60d383 Mon Sep 17 00:00:00 2001 From: "@k33g" Date: Sat, 8 Feb 2025 11:57:50 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Improve=20structure=20/=20format?= =?UTF-8?q?=20of=20the=20code:=20add=20ModelNotFoundError?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LAST_RELEASE.md | 43 +++++++++++++++++++-- completion/chat-completion.go | 52 +++++++++++++++++++++++--- examples/04-chat-stream/main.go | 21 +++++++---- examples/66-structured-outputs/.env | 2 +- examples/66-structured-outputs/main.go | 9 ++++- 5 files changed, 107 insertions(+), 20 deletions(-) diff --git a/LAST_RELEASE.md b/LAST_RELEASE.md index 999c428..2f7411b 100644 --- a/LAST_RELEASE.md +++ b/LAST_RELEASE.md @@ -5,10 +5,45 @@ ## v0.2.4 🥮 [mooncake] > Release in progress 🚧 -- Improving the RAG example with Elasticsearch: `40-rag-with-elastic-markdown` -- New examples: - - Structured output: `66-structured-outputs` - - Experiments with Hypothetical Document Embeddings (HyDE): `65-hyde` (🚧 this is a work in progress) +### RAG + +Improving the RAG example with Elasticsearch: `40-rag-with-elastic-markdown` (🙏 Thank you [@codefromthecrypt](https://github.com/codefromthecrypt)) + +### New examples: + +- Structured output: `66-structured-outputs` +- Experiments with Hypothetical Document Embeddings (HyDE): `65-hyde` (🚧 this is a work in progress) + +### Error management + +#### ModelNotFoundError + +```golang +// package completion +type ModelNotFoundError struct { + Code int + Message string + Model string +} +``` + +**Usage**: +```golang +answer, err := completion.Chat(ollamaUrl, query) +if err != nil { + // test if the model is not found + if modelErr, ok := err.(*completion.ModelNotFoundError); ok { + fmt.Printf("💥 Got Model Not Found error: %s\n", modelErr.Message) + fmt.Printf("😡 Error code: %d\n", modelErr.Code) + fmt.Printf("🧠 Expected Model: %s\n", modelErr.Model) + } else { + log.Fatal("😡:", err) + } +} +``` +> See these examples: `04-chat-stream` and `66-structured-outputs` + +### MCP ## v0.2.3 🥧 [pie] diff --git a/completion/chat-completion.go b/completion/chat-completion.go index e3ce668..fce97a8 100644 --- a/completion/chat-completion.go +++ b/completion/chat-completion.go @@ -8,18 +8,33 @@ import ( "fmt" "io" "net/http" + "strings" "github.com/parakeet-nest/parakeet/llm" ) +type ModelNotFoundError struct { + Code int + Message string + Model string +} + +func (e *ModelNotFoundError) Error() string { + return fmt.Sprintf("Code: %d, Message: %s, Model: %s", e.Code, e.Message, e.Model) +} + +type CompletionError struct { + Error string +} + func Chat(url string, query llm.Query) (llm.Answer, error) { kindOfCompletion := "chat" /* - var outputSchema = "" - if query.Format != "" && query.Format != "json" { - outputSchema = query.Format - } + var outputSchema = "" + if query.Format != "" && query.Format != "json" { + outputSchema = query.Format + } */ query.Stream = false @@ -39,8 +54,6 @@ func Chat(url string, query llm.Query) (llm.Answer, error) { return llm.Answer{}, err } - //fmt.Println("🔴 jsonQuery", string(jsonQuery)) - req, err := http.NewRequest(http.MethodPost, url+"/api/"+kindOfCompletion, bytes.NewBuffer(jsonQuery)) if err != nil { return llm.Answer{}, err @@ -67,7 +80,24 @@ func Chat(url string, query llm.Query) (llm.Answer, error) { // we need to create a new error because // because, even if the status is not ok (ex 401 Unauthorized) // the error == nil + + if resp.StatusCode == http.StatusNotFound { + var completionError CompletionError + var modelNotFound ModelNotFoundError + err = json.Unmarshal(body, &completionError) + if err != nil { + return llm.Answer{}, err + } + if strings.HasPrefix(completionError.Error, "model") && strings.HasSuffix(completionError.Error, "not found, try pulling it first") { + modelNotFound.Code = resp.StatusCode + modelNotFound.Message = completionError.Error + modelNotFound.Model = query.Model + } + return llm.Answer{}, &modelNotFound + } + return llm.Answer{}, errors.New("Error: status code: " + resp.Status + "\n" + string(body)) + } var answer llm.Answer @@ -175,6 +205,16 @@ func ChatStream(url string, query llm.Query, onChunk func(llm.Answer) error) (ll } if resp.StatusCode != http.StatusOK { + if resp.StatusCode == http.StatusNotFound { + var modelNotFound ModelNotFoundError + + modelNotFound.Code = resp.StatusCode + modelNotFound.Message = "model " + query.Model + " not found, try pulling it first" + modelNotFound.Model = query.Model + + return llm.Answer{}, &modelNotFound + } + return llm.Answer{}, errors.New("Error: status code: " + resp.Status) } else { return fullAnswer, nil diff --git a/examples/04-chat-stream/main.go b/examples/04-chat-stream/main.go index 3939da6..4f59170 100644 --- a/examples/04-chat-stream/main.go +++ b/examples/04-chat-stream/main.go @@ -11,9 +11,8 @@ import ( "log" "github.com/parakeet-nest/parakeet/completion" - "github.com/parakeet-nest/parakeet/llm" "github.com/parakeet-nest/parakeet/enums/option" - + "github.com/parakeet-nest/parakeet/llm" ) func main() { @@ -31,13 +30,12 @@ func main() { And, please, be structured with bullet points` options := llm.SetOptions(map[string]interface{}{ - option.Temperature: 0.5, - option.RepeatLastN: 2, + option.Temperature: 0.5, + option.RepeatLastN: 2, option.RepeatPenalty: 3.0, - option.Verbose: true, + option.Verbose: false, }) - query := llm.Query{ Model: model, Messages: []llm.Message{ @@ -52,12 +50,19 @@ func main() { fmt.Print(answer.Message.Content) return nil }) - + fmt.Println("📝 Full answer:") fmt.Println(fullAnswer.Message.Role) fmt.Println(fullAnswer.Message.Content) if err != nil { - log.Fatal("😡:", err) + // test if the model is not found + if modelErr, ok := err.(*completion.ModelNotFoundError); ok { + fmt.Printf("💥 Got Model Not Found error: %s\n", modelErr.Message) + fmt.Printf("😡 Error code: %d\n", modelErr.Code) + fmt.Printf("🧠 Expected Model: %s\n", modelErr.Model) + } else { + log.Fatal("😡:", err) + } } } diff --git a/examples/66-structured-outputs/.env b/examples/66-structured-outputs/.env index b71722e..4fba000 100644 --- a/examples/66-structured-outputs/.env +++ b/examples/66-structured-outputs/.env @@ -1,5 +1,5 @@ # if working from a container #OLLAMA_HOST=http://host.docker.internal:11434 OLLAMA_HOST=http://localhost:11434 -LLM=qwen2.5:1.5b +LLM_CHAT=qwen2.5:1.5b diff --git a/examples/66-structured-outputs/main.go b/examples/66-structured-outputs/main.go index 3263dd3..2f8bd0a 100644 --- a/examples/66-structured-outputs/main.go +++ b/examples/66-structured-outputs/main.go @@ -72,7 +72,14 @@ func main() { answer, err := completion.Chat(ollamaUrl, query) if err != nil { - log.Fatal("😡:", err) + // test if the model is not found + if modelErr, ok := err.(*completion.ModelNotFoundError); ok { + fmt.Printf("💥 Got Model Not Found error: %s\n", modelErr.Message) + fmt.Printf("😡 Error code: %d\n", modelErr.Code) + fmt.Printf("🧠 Expected Model: %s\n", modelErr.Model) + } else { + log.Fatal("😡:", err) + } } fmt.Println(answer.Message.Content)