diff --git a/go.mod b/go.mod index ae88f30..309d26b 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.0 github.com/gorilla/mux v1.8.0 github.com/gorilla/sessions v1.2.1 + github.com/hupe1980/go-huggingface v0.0.8 github.com/labstack/echo/v4 v4.11.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 diff --git a/go.sum b/go.sum index aca12a8..a0cc40e 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,8 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/hupe1980/go-huggingface v0.0.8 h1:9WsQqzzjIwi9DpPHU3sCaQoThcDcSvoRReG+kVhMewg= +github.com/hupe1980/go-huggingface v0.0.8/go.mod h1:IRvsik3+b9BJyw9hCfw1arI6gDObcVto1UA8f3kt8mM= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= @@ -40,7 +42,7 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= diff --git a/vendor/github.com/hupe1980/go-huggingface/.gitignore b/vendor/github.com/hupe1980/go-huggingface/.gitignore new file mode 100644 index 0000000..2dd5137 --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/.gitignore @@ -0,0 +1,23 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +.env diff --git a/vendor/github.com/hupe1980/go-huggingface/.golangci.yml b/vendor/github.com/hupe1980/go-huggingface/.golangci.yml new file mode 100644 index 0000000..0ade7ff --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/.golangci.yml @@ -0,0 +1,57 @@ +linters-settings: + errcheck: + check-type-assertions: true + goconst: + min-len: 2 + min-occurrences: 3 + gocritic: + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + govet: + check-shadowing: true + nolintlint: + require-explanation: true + require-specific: true + +linters: + disable-all: true + enable: + - bodyclose + #- depguard + - dogsled + #- dupl + - errcheck + - exportloopref + - exhaustive + #- goconst TODO + - gofmt + - goimports + #- gomnd + - gocyclo + - gosec + - gosimple + - govet + - ineffassign + - misspell + #- nolintlint + - nakedret + - prealloc + - predeclared + #- revive TODO + - staticcheck + - stylecheck + - thelper + - tparallel + - typecheck + - unconvert + - unparam + - unused + - whitespace + - wsl + +run: + issues-exit-code: 1 \ No newline at end of file diff --git a/vendor/github.com/hupe1980/go-huggingface/.goreleaser.yml b/vendor/github.com/hupe1980/go-huggingface/.goreleaser.yml new file mode 100644 index 0000000..10b9449 --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/.goreleaser.yml @@ -0,0 +1,2 @@ +builds: +- skip: true \ No newline at end of file diff --git a/vendor/github.com/hupe1980/go-huggingface/LICENSE b/vendor/github.com/hupe1980/go-huggingface/LICENSE new file mode 100644 index 0000000..2f58d40 --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Frank Hübner + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/hupe1980/go-huggingface/Makefile b/vendor/github.com/hupe1980/go-huggingface/Makefile new file mode 100644 index 0000000..d3f71bf --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/Makefile @@ -0,0 +1,29 @@ +PROJECTNAME=$(shell basename "$(PWD)") + +# Go related variables. +# Make is verbose in Linux. Make it silent. +MAKEFLAGS += --silent + +.PHONY: setup +## setup: Setup installes dependencies +setup: + @go mod tidy + +.PHONY: lint +## test: Runs the linter +lint: + golangci-lint run --color=always --sort-results ./... + +.PHONY: test +## test: Runs go test with default values +test: + @go test -v -race -count=1 ./... + +.PHONY: help +## help: Prints this help message +help: Makefile + @echo + @echo " Choose a command run in "$(PROJECTNAME)":" + @echo + @sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /' + @echo \ No newline at end of file diff --git a/vendor/github.com/hupe1980/go-huggingface/README.md b/vendor/github.com/hupe1980/go-huggingface/README.md new file mode 100644 index 0000000..c410366 --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/README.md @@ -0,0 +1,52 @@ +# 🤗 go-huggingface +![Build Status](https://github.com/hupe1980/go-huggingface/workflows/build/badge.svg) +[![Go Reference](https://pkg.go.dev/badge/github.com/hupe1980/go-huggingface.svg)](https://pkg.go.dev/github.com/hupe1980/go-huggingface) +> The Hugging Face Inference Client in Golang is a modul designed to interact with the Hugging Face model repository and perform inference tasks using state-of-the-art natural language processing models. Developed in Golang, it provides a seamless and efficient way to integrate Hugging Face models into your Golang applications. + +## Installation +``` +go get github.com/hupe1980/go-huggingface +``` + +## How to use +```golang +package main + +import ( + "context" + "fmt" + "log" + "os" + + huggingface "github.com/hupe1980/go-huggingface" +) + +func main() { + ic := huggingface.NewInferenceClient(os.Getenv("HUGGINGFACEHUB_API_TOKEN")) + + res, err := ic.ZeroShotClassification(context.Background(), &huggingface.ZeroShotClassificationRequest{ + Inputs: []string{"Hi, I recently bought a device from your company but it is not working as advertised and I would like to get reimbursed!"}, + Parameters: huggingface.ZeroShotClassificationParameters{ + CandidateLabels: []string{"refund", "faq", "legal"}, + }, + }) + if err != nil { + log.Fatal(err) + } + + fmt.Println(res[0].Sequence) + fmt.Println("Labels:", res[0].Labels) + fmt.Println("Scores:", res[0].Scores) +} +``` +Output: +```text +Hi, I recently bought a device from your company but it is not working as advertised and I would like to get reimbursed! +Labels: [refund faq legal] +Scores: [0.8777876496315002 0.10522633790969849 0.016985949128866196] +``` + +For more example usage, see [_examples](./_examples). + +## License +[MIT](LICENCE) \ No newline at end of file diff --git a/vendor/github.com/hupe1980/go-huggingface/conversational.go b/vendor/github.com/hupe1980/go-huggingface/conversational.go new file mode 100644 index 0000000..c742ff2 --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/conversational.go @@ -0,0 +1,99 @@ +package gohuggingface + +import ( + "context" + "encoding/json" + "errors" +) + +// Used with ConversationalRequest +type ConversationalParameters struct { + // (Default: None). Integer to define the minimum length in tokens of the output summary. + MinLength *int `json:"min_length,omitempty"` + + // (Default: None). Integer to define the maximum length in tokens of the output summary. + MaxLength *int `json:"max_length,omitempty"` + + // (Default: None). Integer to define the top tokens considered within the sample operation to create + // new text. + TopK *int `json:"top_k,omitempty"` + + // (Default: None). Float to define the tokens that are within the sample` operation of text generation. + // Add tokens in the sample for more probable to least probable until the sum of the probabilities is + // greater than top_p. + TopP *float64 `json:"top_p,omitempty"` + + // (Default: 1.0). Float (0.0-100.0). The temperature of the sampling operation. 1 means regular sampling, + // 0 mens top_k=1, 100.0 is getting closer to uniform probability. + Temperature *float64 `json:"temperature,omitempty"` + + // (Default: None). Float (0.0-100.0). The more a token is used within generation the more it is penalized + // to not be picked in successive generation passes. + RepetitionPenalty *float64 `json:"repetitionpenalty,omitempty"` + + // (Default: None). Float (0-120.0). The amount of time in seconds that the query should take maximum. + // Network can cause some overhead so it will be a soft limit. + MaxTime *float64 `json:"maxtime,omitempty"` +} + +// Used with ConversationalRequest +type ConverstationalInputs struct { + // (Required) The last input from the user in the conversation. + Text string `json:"text"` + + // A list of strings corresponding to the earlier replies from the model. + GeneratedResponses []string `json:"generated_responses,omitempty"` + + // A list of strings corresponding to the earlier replies from the user. + // Should be of the same length of GeneratedResponses. + PastUserInputs []string `json:"past_user_inputs,omitempty"` +} + +// Request structure for the conversational endpoint +type ConversationalRequest struct { + // (Required) + Inputs ConverstationalInputs `json:"inputs,omitempty"` + + Parameters ConversationalParameters `json:"parameters,omitempty"` + Options Options `json:"options,omitempty"` + Model string `json:"-"` +} + +// Used with ConversationalResponse +type Conversation struct { + // The last outputs from the model in the conversation, after the model has run. + GeneratedResponses []string `json:"generated_responses,omitempty"` + + // The last inputs from the user in the conversation, after the model has run. + PastUserInputs []string `json:"past_user_inputs,omitempty"` +} + +// Response structure for the conversational endpoint +type ConversationalResponse struct { + // The answer of the model + GeneratedText string `json:"generated_text,omitempty"` + + // A facility dictionary to send back for the next input (with the new user input addition). + Conversation Conversation `json:"conversation,omitempty"` +} + +// Conversational performs conversational AI using the specified model. +// It sends a POST request to the Hugging Face inference endpoint with the provided conversational inputs. +// The response contains the generated conversational response or an error if the request fails. +func (ic *InferenceClient) Conversational(ctx context.Context, req *ConversationalRequest) (*ConversationalResponse, error) { + if len(req.Inputs.Text) == 0 { + return nil, errors.New("text is required") + } + + body, err := ic.post(ctx, req.Model, "conversational", req) + if err != nil { + return nil, err + } + + conversationalResponse := ConversationalResponse{} + if err := json.Unmarshal(body, &conversationalResponse); err != nil { + return nil, err + } + + return &conversationalResponse, nil +} diff --git a/vendor/github.com/hupe1980/go-huggingface/error.go b/vendor/github.com/hupe1980/go-huggingface/error.go new file mode 100644 index 0000000..ff931bc --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/error.go @@ -0,0 +1,5 @@ +package gohuggingface + +type ErrorResponse struct { + Error string `json:"error"` +} diff --git a/vendor/github.com/hupe1980/go-huggingface/feature_extraction.go b/vendor/github.com/hupe1980/go-huggingface/feature_extraction.go new file mode 100644 index 0000000..a9bda35 --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/feature_extraction.go @@ -0,0 +1,42 @@ +package gohuggingface + +import ( + "context" + "encoding/json" + "errors" + "fmt" +) + +// Request structure for the feature extraction endpoint +type FeatureExtractionRequest struct { + // String to get the features from + Inputs []string `json:"inputs"` + Options Options `json:"options,omitempty"` + Model string `json:"-"` +} + +// Response structure for the feature extraction endpoint +type FeatureExtractionResponse [][][][]float64 + +// FeatureExtraction performs feature extraction using the specified model. +// It sends a POST request to the Hugging Face inference endpoint with the provided input data. +// The response contains the extracted features or an error if the request fails. +func (ic *InferenceClient) FeatureExtraction(ctx context.Context, req *FeatureExtractionRequest) (FeatureExtractionResponse, error) { + if len(req.Inputs) == 0 { + return nil, errors.New("inputs are required") + } + + body, err := ic.post(ctx, req.Model, "feature-extraction", req) + if err != nil { + return nil, err + } + + fmt.Println(string(body)) + + featureExtractionResponse := FeatureExtractionResponse{} + if err := json.Unmarshal(body, &featureExtractionResponse); err != nil { + return nil, err + } + + return featureExtractionResponse, nil +} diff --git a/vendor/github.com/hupe1980/go-huggingface/fill_mask.go b/vendor/github.com/hupe1980/go-huggingface/fill_mask.go new file mode 100644 index 0000000..ad6ea3a --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/fill_mask.go @@ -0,0 +1,51 @@ +package gohuggingface + +import ( + "context" + "encoding/json" + "errors" +) + +// Request structure for the Fill Mask endpoint +type FillMaskRequest struct { + // (Required) a string to be filled from, must contain the [MASK] token (check model card for exact name of the mask) + Inputs []string `json:"inputs"` + Options Options `json:"options,omitempty"` + Model string `json:"-"` +} + +// Response structure for the Fill Mask endpoint +type FillMaskResponse []struct { + // The actual sequence of tokens that ran against the model (may contain special tokens) + Sequence string `json:"sequence,omitempty"` + + // The probability for this token. + Score float64 `json:"score,omitempty"` + + // The id of the token + TokenID int `json:"token,omitempty"` + + // The string representation of the token + TokenStr string `json:"token_str,omitempty"` +} + +// FillMask performs masked language modeling using the specified model. +// It sends a POST request to the Hugging Face inference endpoint with the provided inputs. +// The response contains the generated text with the masked tokens filled or an error if the request fails. +func (ic *InferenceClient) FillMask(ctx context.Context, req *FillMaskRequest) (FillMaskResponse, error) { + if len(req.Inputs) == 0 { + return nil, errors.New("inputs are required") + } + + body, err := ic.post(ctx, req.Model, "fill-mask", req) + if err != nil { + return nil, err + } + + fillMaskResponse := FillMaskResponse{} + if err := json.Unmarshal(body, &fillMaskResponse); err != nil { + return nil, err + } + + return fillMaskResponse, nil +} diff --git a/vendor/github.com/hupe1980/go-huggingface/huggingface.go b/vendor/github.com/hupe1980/go-huggingface/huggingface.go new file mode 100644 index 0000000..0582d5c --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/huggingface.go @@ -0,0 +1,205 @@ +package gohuggingface + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" +) + +var ( + // recommendedModels stores the recommended models for each task. + recommendedModels map[string]string +) + +// HTTPClient is an interface representing an HTTP client. +type HTTPClient interface { + Do(req *http.Request) (*http.Response, error) +} + +// InferenceClientOptions represents options for the InferenceClient. +type InferenceClientOptions struct { + Model string + Endpoint string + InferenceEndpoint string + HTTPClient HTTPClient +} + +// InferenceClient is a client for performing inference using Hugging Face models. +type InferenceClient struct { + httpClient HTTPClient + token string + opts InferenceClientOptions +} + +// NewInferenceClient creates a new InferenceClient instance with the specified token. +func NewInferenceClient(token string, optFns ...func(o *InferenceClientOptions)) *InferenceClient { + opts := InferenceClientOptions{ + Endpoint: "https://huggingface.co", + InferenceEndpoint: "https://api-inference.huggingface.co", + } + + for _, fn := range optFns { + fn(&opts) + } + + if opts.HTTPClient == nil { + opts.HTTPClient = http.DefaultClient + } + + return &InferenceClient{ + httpClient: opts.HTTPClient, + token: token, + opts: opts, + } +} + +func (ic *InferenceClient) SetModel(model string) { + ic.opts.Model = model +} + +// post sends a POST request to the specified model and task with the provided payload. +// It returns the response body or an error if the request fails. +func (ic *InferenceClient) post(ctx context.Context, model, task string, payload any) ([]byte, error) { + url, err := ic.resolveURL(ctx, model, task) + if err != nil { + return nil, err + } + + body, err := json.Marshal(payload) + if err != nil { + return nil, err + } + + httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body)) + if err != nil { + return nil, err + } + + httpReq.Header.Set("Content-Type", "application/json") + httpReq.Header.Set("Accept", "application/json") + + if ic.token != "" { + httpReq.Header.Set("Authorization", fmt.Sprintf("Bearer %s", ic.token)) + } + + res, err := ic.httpClient.Do(httpReq) + if err != nil { + return nil, err + } + + defer res.Body.Close() + + resBody, err := io.ReadAll(res.Body) + if err != nil { + return nil, err + } + + if res.StatusCode != http.StatusOK { + errResp := ErrorResponse{} + if err := json.Unmarshal(resBody, &errResp); err != nil { + return nil, fmt.Errorf("huggingfaces error: %s", resBody) + } + + return nil, fmt.Errorf("huggingfaces error: %s", errResp.Error) + } + + return resBody, nil +} + +// resolveURL resolves the URL for the specified model and task. +// It returns the resolved URL or an error if resolution fails. +func (ic *InferenceClient) resolveURL(ctx context.Context, model, task string) (string, error) { + if model == "" { + model = ic.opts.Model + } + + // If model is already a URL, ignore `task` and return directly + if model != "" && (strings.HasPrefix(model, "http://") || strings.HasPrefix(model, "https://")) { + return model, nil + } + + if model == "" { + var err error + + model, err = ic.getRecommendedModel(ctx, task) + if err != nil { + return "", err + } + } + + // Feature-extraction and sentence-similarity are the only cases where models support multiple tasks + if contains([]string{"feature-extraction", "sentence-similarity"}, task) { + return fmt.Sprintf("%s/pipeline/%s/%s", ic.opts.InferenceEndpoint, task, model), nil + } + + return fmt.Sprintf("%s/models/%s", ic.opts.InferenceEndpoint, model), nil +} + +// getRecommendedModel retrieves the recommended model for the specified task. +// It returns the recommended model or an error if retrieval fails. +func (ic *InferenceClient) getRecommendedModel(ctx context.Context, task string) (string, error) { + rModels, err := ic.fetchRecommendedModels(ctx) + if err != nil { + return "", err + } + + model, ok := rModels[task] + if !ok { + return "", fmt.Errorf("task %s has no recommended model", task) + } + + return model, nil +} + +// fetchRecommendedModels retrieves the recommended models for all available tasks. +// It returns a map of task names to recommended models or an error if retrieval fails. +func (ic *InferenceClient) fetchRecommendedModels(ctx context.Context) (map[string]string, error) { + if recommendedModels == nil { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/api/tasks", ic.opts.Endpoint), nil) + if err != nil { + return nil, err + } + + res, err := ic.httpClient.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + + var jsonResponse map[string]interface{} + + err = json.NewDecoder(res.Body).Decode(&jsonResponse) + if err != nil { + return nil, err + } + + recommendedModels = make(map[string]string) + + for task, details := range jsonResponse { + widgetModels, ok := details.(map[string]interface{})["widgetModels"].([]interface{}) + if !ok || len(widgetModels) == 0 { + recommendedModels[task] = "" + } else { + firstModel, _ := widgetModels[0].(string) + recommendedModels[task] = firstModel + } + } + } + + return recommendedModels, nil +} + +// Contains checks if the given element is present in the collection. +func contains[T comparable](collection []T, element T) bool { + for _, item := range collection { + if item == element { + return true + } + } + + return false +} diff --git a/vendor/github.com/hupe1980/go-huggingface/options.go b/vendor/github.com/hupe1980/go-huggingface/options.go new file mode 100644 index 0000000..acbc382 --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/options.go @@ -0,0 +1,16 @@ +package gohuggingface + +type Options struct { + // (Default: true). There is a cache layer on the inference API to speedup + // requests we have already seen. Most models can use those results as is + // as models are deterministic (meaning the results will be the same anyway). + // However if you use a non deterministic model, you can set this parameter + // to prevent the caching mechanism from being used resulting in a real new query. + UseCache *bool `json:"use_cache,omitempty"` + + // (Default: false) If the model is not ready, wait for it instead of receiving 503. + // It limits the number of requests required to get your inference done. It is advised + // to only set this flag to true after receiving a 503 error as it will limit hanging + // in your application to known places. + WaitForModel *bool `json:"wait_for_model,omitempty"` +} diff --git a/vendor/github.com/hupe1980/go-huggingface/question_answering.go b/vendor/github.com/hupe1980/go-huggingface/question_answering.go new file mode 100644 index 0000000..5517c7c --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/question_answering.go @@ -0,0 +1,63 @@ +package gohuggingface + +import ( + "context" + "encoding/json" + "errors" +) + +type QuestionAnsweringInputs struct { + // (Required) The question as a string that has an answer within Context. + Question string `json:"question"` + + // (Required) A string that contains the answer to the question + Context string `json:"context"` +} + +// Request structure for question answering model +type QuestionAnsweringRequest struct { + // (Required) + Inputs QuestionAnsweringInputs `json:"inputs,omitempty"` + Options Options `json:"options,omitempty"` + Model string `json:"-"` +} + +// Response structure for question answering model +type QuestionAnsweringResponse struct { + // A string that’s the answer within the Context text. + Answer string `json:"answer,omitempty"` + + // A float that represents how likely that the answer is correct. + Score float64 `json:"score,omitempty"` + + // The string index of the start of the answer within Context. + Start int `json:"start,omitempty"` + + // The string index of the stop of the answer within Context. + End int `json:"end,omitempty"` +} + +// QuestionAnswering performs question answering using the specified model. +// It sends a POST request to the Hugging Face inference endpoint with the provided question and context inputs. +// The response contains the answer or an error if the request fails. +func (ic *InferenceClient) QuestionAnswering(ctx context.Context, req *QuestionAnsweringRequest) (*QuestionAnsweringResponse, error) { + if req.Inputs.Question == "" { + return nil, errors.New("question is required") + } + + if req.Inputs.Context == "" { + return nil, errors.New("context is required") + } + + body, err := ic.post(ctx, req.Model, "question-answering", req) + if err != nil { + return nil, err + } + + questionAnsweringResponse := QuestionAnsweringResponse{} + if err := json.Unmarshal(body, &questionAnsweringResponse); err != nil { + return nil, err + } + + return &questionAnsweringResponse, nil +} diff --git a/vendor/github.com/hupe1980/go-huggingface/summarization.go b/vendor/github.com/hupe1980/go-huggingface/summarization.go new file mode 100644 index 0000000..0b73fbd --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/summarization.go @@ -0,0 +1,70 @@ +package gohuggingface + +import ( + "context" + "encoding/json" + "errors" +) + +type SummarizationParameters struct { + // (Default: None). Integer to define the minimum length in tokens of the output summary. + MinLength *int `json:"min_length,omitempty"` + + // (Default: None). Integer to define the maximum length in tokens of the output summary. + MaxLength *int `json:"max_length,omitempty"` + + // (Default: None). Integer to define the top tokens considered within the sample operation to create + // new text. + TopK *int `json:"top_k,omitempty"` + + // (Default: None). Float to define the tokens that are within the sample` operation of text generation. + // Add tokens in the sample for more probable to least probable until the sum of the probabilities is + // greater than top_p. + TopP *float64 `json:"top_p,omitempty"` + + // (Default: 1.0). Float (0.0-100.0). The temperature of the sampling operation. 1 means regular sampling, + // 0 mens top_k=1, 100.0 is getting closer to uniform probability. + Temperature *float64 `json:"temperature,omitempty"` + + // (Default: None). Float (0.0-100.0). The more a token is used within generation the more it is penalized + // to not be picked in successive generation passes. + RepetitionPenalty *float64 `json:"repetitionpenalty,omitempty"` + + // (Default: None). Float (0-120.0). The amount of time in seconds that the query should take maximum. + // Network can cause some overhead so it will be a soft limit. + MaxTime *float64 `json:"maxtime,omitempty"` +} + +type SummarizationRequest struct { + // String to be summarized + Inputs []string `json:"inputs"` + Parameters SummarizationParameters `json:"parameters,omitempty"` + Options Options `json:"options,omitempty"` + Model string `json:"-"` +} + +type SummarizationResponse []struct { + // The summarized input string + SummaryText string `json:"summary_text,omitempty"` +} + +// Summarization performs text summarization using the specified model. +// It sends a POST request to the Hugging Face inference endpoint with the provided inputs. +// The response contains the generated summary or an error if the request fails. +func (ic *InferenceClient) Summarization(ctx context.Context, req *SummarizationRequest) (SummarizationResponse, error) { + if len(req.Inputs) == 0 { + return nil, errors.New("inputs are required") + } + + body, err := ic.post(ctx, req.Model, "summarization", req) + if err != nil { + return nil, err + } + + summarizationResponse := SummarizationResponse{} + if err := json.Unmarshal(body, &summarizationResponse); err != nil { + return nil, err + } + + return summarizationResponse, nil +} diff --git a/vendor/github.com/hupe1980/go-huggingface/table_question_answering.go b/vendor/github.com/hupe1980/go-huggingface/table_question_answering.go new file mode 100644 index 0000000..0e07fb8 --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/table_question_answering.go @@ -0,0 +1,64 @@ +package gohuggingface + +import ( + "context" + "encoding/json" + "errors" +) + +// Request structure for table question answering model +type TableQuestionAnsweringRequest struct { + Inputs TableQuestionAnsweringInputs `json:"inputs"` + Options Options `json:"options,omitempty"` + Model string `json:"-"` +} + +type TableQuestionAnsweringInputs struct { + // (Required) The query in plain text that you want to ask the table + Query string `json:"query"` + + // (Required) A table of data represented as a dict of list where entries + // are headers and the lists are all the values, all lists must + // have the same size. + Table map[string][]string `json:"table"` +} + +// Response structure for table question answering model +type TableQuestionAnsweringResponse struct { + // The plaintext answer + Answer string `json:"answer,omitempty"` + + // A list of coordinates of the cells references in the answer + Coordinates [][]int `json:"coordinates,omitempty"` + + // A list of coordinates of the cells contents + Cells []string `json:"cells,omitempty"` + + // The aggregator used to get the answer + Aggregator string `json:"aggregator,omitempty"` +} + +// TableQuestionAnswering performs table-based question answering using the specified model. +// It sends a POST request to the Hugging Face inference endpoint with the provided inputs. +// The response contains the answer or an error if the request fails. +func (ic *InferenceClient) TableQuestionAnswering(ctx context.Context, req *TableQuestionAnsweringRequest) (*TableQuestionAnsweringResponse, error) { + if req.Inputs.Query == "" { + return nil, errors.New("query is required") + } + + if req.Inputs.Table == nil { + return nil, errors.New("table is required") + } + + body, err := ic.post(ctx, req.Model, "table-question-answering", req) + if err != nil { + return nil, err + } + + tablequestionAnsweringResponse := TableQuestionAnsweringResponse{} + if err := json.Unmarshal(body, &tablequestionAnsweringResponse); err != nil { + return nil, err + } + + return &tablequestionAnsweringResponse, nil +} diff --git a/vendor/github.com/hupe1980/go-huggingface/text2text_generation.go b/vendor/github.com/hupe1980/go-huggingface/text2text_generation.go new file mode 100644 index 0000000..0fdd787 --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/text2text_generation.go @@ -0,0 +1,75 @@ +package gohuggingface + +import ( + "context" + "encoding/json" + "errors" +) + +type Text2TextGenerationParameters struct { + // (Default: None). Integer to define the top tokens considered within the sample operation to create new text. + TopK *int `json:"top_k,omitempty"` + + // (Default: None). Float to define the tokens that are within the sample` operation of text generation. Add + // tokens in the sample for more probable to least probable until the sum of the probabilities is greater + // than top_p. + TopP *float64 `json:"top_p,omitempty"` + + // (Default: 1.0). Float (0.0-100.0). The temperature of the sampling operation. 1 means regular sampling, + // 0 means top_k=1, 100.0 is getting closer to uniform probability. + Temperature *float64 `json:"temperature,omitempty"` + + // (Default: None). Float (0.0-100.0). The more a token is used within generation the more it is penalized + // to not be picked in successive generation passes. + RepetitionPenalty *float64 `json:"repetition_penalty,omitempty"` + + // (Default: None). Int (0-250). The amount of new tokens to be generated, this does not include the input + // length it is a estimate of the size of generated text you want. Each new tokens slows down the request, + // so look for balance between response times and length of text generated. + MaxNewTokens *int `json:"max_new_tokens,omitempty"` + + // (Default: None). Float (0-120.0). The amount of time in seconds that the query should take maximum. + // Network can cause some overhead so it will be a soft limit. Use that in combination with max_new_tokens + // for best results. + MaxTime *float64 `json:"max_time,omitempty"` + + // (Default: True). Bool. If set to False, the return results will not contain the original query making it + // easier for prompting. + ReturnFullText *bool `json:"return_full_text,omitempty"` + + // (Default: 1). Integer. The number of proposition you want to be returned. + NumReturnSequences *int `json:"num_return_sequences,omitempty"` +} + +type Text2TextGenerationRequest struct { + // String to generated from + Inputs string `json:"inputs"` + Parameters Text2TextGenerationParameters `json:"parameters,omitempty"` + Options Options `json:"options,omitempty"` + Model string `json:"-"` +} + +type Text2TextGenerationResponse []struct { + GeneratedText string `json:"generated_text,omitempty"` +} + +// Text2TextGeneration performs text-to-text generation using the specified model. +// It sends a POST request to the Hugging Face inference endpoint with the provided inputs. +// The response contains the generated text or an error if the request fails. +func (ic *InferenceClient) Text2TextGeneration(ctx context.Context, req *Text2TextGenerationRequest) (Text2TextGenerationResponse, error) { + if req.Inputs == "" { + return nil, errors.New("inputs are required") + } + + body, err := ic.post(ctx, req.Model, "text2text-generation", req) + if err != nil { + return nil, err + } + + text2TextGenerationResponse := Text2TextGenerationResponse{} + if err := json.Unmarshal(body, &text2TextGenerationResponse); err != nil { + return nil, err + } + + return text2TextGenerationResponse, nil +} diff --git a/vendor/github.com/hupe1980/go-huggingface/text_generation.go b/vendor/github.com/hupe1980/go-huggingface/text_generation.go new file mode 100644 index 0000000..58469de --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/text_generation.go @@ -0,0 +1,77 @@ +package gohuggingface + +import ( + "context" + "encoding/json" + "errors" +) + +type TextGenerationParameters struct { + // (Default: None). Integer to define the top tokens considered within the sample operation to create new text. + TopK *int `json:"top_k,omitempty"` + + // (Default: None). Float to define the tokens that are within the sample` operation of text generation. Add + // tokens in the sample for more probable to least probable until the sum of the probabilities is greater + // than top_p. + TopP *float64 `json:"top_p,omitempty"` + + // (Default: 1.0). Float (0.0-100.0). The temperature of the sampling operation. 1 means regular sampling, + // 0 means top_k=1, 100.0 is getting closer to uniform probability. + Temperature *float64 `json:"temperature,omitempty"` + + // (Default: None). Float (0.0-100.0). The more a token is used within generation the more it is penalized + // to not be picked in successive generation passes. + RepetitionPenalty *float64 `json:"repetition_penalty,omitempty"` + + // (Default: None). Int (0-250). The amount of new tokens to be generated, this does not include the input + // length it is a estimate of the size of generated text you want. Each new tokens slows down the request, + // so look for balance between response times and length of text generated. + MaxNewTokens *int `json:"max_new_tokens,omitempty"` + + // (Default: None). Float (0-120.0). The amount of time in seconds that the query should take maximum. + // Network can cause some overhead so it will be a soft limit. Use that in combination with max_new_tokens + // for best results. + MaxTime *float64 `json:"max_time,omitempty"` + + // (Default: True). Bool. If set to False, the return results will not contain the original query making it + // easier for prompting. + ReturnFullText *bool `json:"return_full_text,omitempty"` + + // (Default: 1). Integer. The number of proposition you want to be returned. + NumReturnSequences *int `json:"num_return_sequences,omitempty"` +} + +type TextGenerationRequest struct { + // String to generated from + Inputs string `json:"inputs"` + Parameters TextGenerationParameters `json:"parameters,omitempty"` + Options Options `json:"options,omitempty"` + Model string `json:"-"` +} + +// A list of generated texts. The length of this list is the value of +// NumReturnSequences in the request. +type TextGenerationResponse []struct { + GeneratedText string `json:"generated_text,omitempty"` +} + +// TextGeneration performs text generation using the specified model. +// It sends a POST request to the Hugging Face inference endpoint with the provided inputs. +// The response contains the generated text or an error if the request fails. +func (ic *InferenceClient) TextGeneration(ctx context.Context, req *TextGenerationRequest) (TextGenerationResponse, error) { + if req.Inputs == "" { + return nil, errors.New("inputs are required") + } + + body, err := ic.post(ctx, req.Model, "text-generation", req) + if err != nil { + return nil, err + } + + textGenerationResponse := TextGenerationResponse{} + if err := json.Unmarshal(body, &textGenerationResponse); err != nil { + return nil, err + } + + return textGenerationResponse, nil +} diff --git a/vendor/github.com/hupe1980/go-huggingface/zero_shot_classification.go b/vendor/github.com/hupe1980/go-huggingface/zero_shot_classification.go new file mode 100644 index 0000000..71109f9 --- /dev/null +++ b/vendor/github.com/hupe1980/go-huggingface/zero_shot_classification.go @@ -0,0 +1,64 @@ +package gohuggingface + +import ( + "context" + "encoding/json" + "errors" +) + +type ZeroShotClassificationParameters struct { + // (Required) A list of strings that are potential classes for inputs. Max 10 candidate_labels, + // for more, simply run multiple requests, results are going to be misleading if using + // too many candidate_labels anyway. If you want to keep the exact same, you can + // simply run multi_label=True and do the scaling on your end. + CandidateLabels []string `json:"candidate_labels"` + + // (Default: false) Boolean that is set to True if classes can overlap + MultiLabel *bool `json:"multi_label,omitempty"` +} + +type ZeroShotClassificationRequest struct { + // (Required) Input or Inputs are required request fields + Inputs []string `json:"inputs"` + // (Required) + Parameters ZeroShotClassificationParameters `json:"parameters,omitempty"` + Options Options `json:"options,omitempty"` + Model string `json:"-"` +} + +type ZeroShotClassificationResponse []struct { + // The string sent as an input + Sequence string `json:"sequence,omitempty"` + + // The list of labels sent in the request, sorted in descending order + // by probability that the input corresponds to the to the label. + Labels []string `json:"labels,omitempty"` + + // a list of floats that correspond the the probability of label, in the same order as labels. + Scores []float64 `json:"scores,omitempty"` +} + +// ZeroShotClassification performs zero-shot classification using the specified model. +// It sends a POST request to the Hugging Face inference endpoint with the provided inputs. +// The response contains the classification results or an error if the request fails. +func (ic *InferenceClient) ZeroShotClassification(ctx context.Context, req *ZeroShotClassificationRequest) (ZeroShotClassificationResponse, error) { + if len(req.Inputs) == 0 { + return nil, errors.New("inputs are required") + } + + if len(req.Parameters.CandidateLabels) == 0 { + return nil, errors.New("canidateLabels are required") + } + + body, err := ic.post(ctx, req.Model, "zero-shot-classification", req) + if err != nil { + return nil, err + } + + zeroShotClassificationResponse := ZeroShotClassificationResponse{} + if err := json.Unmarshal(body, &zeroShotClassificationResponse); err != nil { + return nil, err + } + + return zeroShotClassificationResponse, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index f8b9452..c0b4ef6 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -13,6 +13,9 @@ github.com/gorilla/securecookie # github.com/gorilla/sessions v1.2.1 ## explicit github.com/gorilla/sessions +# github.com/hupe1980/go-huggingface v0.0.8 +## explicit; go 1.20 +github.com/hupe1980/go-huggingface # github.com/inconshreveable/mousetrap v1.1.0 ## explicit; go 1.18 github.com/inconshreveable/mousetrap