Coder Social home page Coder Social logo

sashabaranov / go-openai Goto Github PK

View Code? Open in Web Editor NEW
8.5K 71.0 1.3K 560 KB

OpenAI ChatGPT, GPT-3, GPT-4, DALL·E, Whisper API wrapper for Go

License: Apache License 2.0

Go 99.56% Makefile 0.44%
go gpt-3 openai golang streaming-api dall-e chatgpt chatgpt-api openai-whisper gpt-4

go-openai's Introduction

Go OpenAI

Go Reference Go Report Card codecov

This library provides unofficial Go clients for OpenAI API. We support:

  • ChatGPT
  • GPT-3, GPT-4
  • DALL·E 2, DALL·E 3
  • Whisper

Installation

go get github.com/sashabaranov/go-openai

Currently, go-openai requires Go version 1.18 or greater.

Usage

ChatGPT example usage:

package main

import (
	"context"
	"fmt"
	openai "github.com/sashabaranov/go-openai"
)

func main() {
	client := openai.NewClient("your token")
	resp, err := client.CreateChatCompletion(
		context.Background(),
		openai.ChatCompletionRequest{
			Model: openai.GPT3Dot5Turbo,
			Messages: []openai.ChatCompletionMessage{
				{
					Role:    openai.ChatMessageRoleUser,
					Content: "Hello!",
				},
			},
		},
	)

	if err != nil {
		fmt.Printf("ChatCompletion error: %v\n", err)
		return
	}

	fmt.Println(resp.Choices[0].Message.Content)
}

Getting an OpenAI API Key:

  1. Visit the OpenAI website at https://platform.openai.com/account/api-keys.
  2. If you don't have an account, click on "Sign Up" to create one. If you do, click "Log In".
  3. Once logged in, navigate to your API key management page.
  4. Click on "Create new secret key".
  5. Enter a name for your new key, then click "Create secret key".
  6. Your new API key will be displayed. Use this key to interact with the OpenAI API.

Note: Your API key is sensitive information. Do not share it with anyone.

Other examples:

ChatGPT streaming completion
package main

import (
	"context"
	"errors"
	"fmt"
	"io"
	openai "github.com/sashabaranov/go-openai"
)

func main() {
	c := openai.NewClient("your token")
	ctx := context.Background()

	req := openai.ChatCompletionRequest{
		Model:     openai.GPT3Dot5Turbo,
		MaxTokens: 20,
		Messages: []openai.ChatCompletionMessage{
			{
				Role:    openai.ChatMessageRoleUser,
				Content: "Lorem ipsum",
			},
		},
		Stream: true,
	}
	stream, err := c.CreateChatCompletionStream(ctx, req)
	if err != nil {
		fmt.Printf("ChatCompletionStream error: %v\n", err)
		return
	}
	defer stream.Close()

	fmt.Printf("Stream response: ")
	for {
		response, err := stream.Recv()
		if errors.Is(err, io.EOF) {
			fmt.Println("\nStream finished")
			return
		}

		if err != nil {
			fmt.Printf("\nStream error: %v\n", err)
			return
		}

		fmt.Printf(response.Choices[0].Delta.Content)
	}
}
GPT-3 completion
package main

import (
	"context"
	"fmt"
	openai "github.com/sashabaranov/go-openai"
)

func main() {
	c := openai.NewClient("your token")
	ctx := context.Background()

	req := openai.CompletionRequest{
		Model:     openai.GPT3Ada,
		MaxTokens: 5,
		Prompt:    "Lorem ipsum",
	}
	resp, err := c.CreateCompletion(ctx, req)
	if err != nil {
		fmt.Printf("Completion error: %v\n", err)
		return
	}
	fmt.Println(resp.Choices[0].Text)
}
GPT-3 streaming completion
package main

import (
	"errors"
	"context"
	"fmt"
	"io"
	openai "github.com/sashabaranov/go-openai"
)

func main() {
	c := openai.NewClient("your token")
	ctx := context.Background()

	req := openai.CompletionRequest{
		Model:     openai.GPT3Ada,
		MaxTokens: 5,
		Prompt:    "Lorem ipsum",
		Stream:    true,
	}
	stream, err := c.CreateCompletionStream(ctx, req)
	if err != nil {
		fmt.Printf("CompletionStream error: %v\n", err)
		return
	}
	defer stream.Close()

	for {
		response, err := stream.Recv()
		if errors.Is(err, io.EOF) {
			fmt.Println("Stream finished")
			return
		}

		if err != nil {
			fmt.Printf("Stream error: %v\n", err)
			return
		}


		fmt.Printf("Stream response: %v\n", response)
	}
}
Audio Speech-To-Text
package main

import (
	"context"
	"fmt"

	openai "github.com/sashabaranov/go-openai"
)

func main() {
	c := openai.NewClient("your token")
	ctx := context.Background()

	req := openai.AudioRequest{
		Model:    openai.Whisper1,
		FilePath: "recording.mp3",
	}
	resp, err := c.CreateTranscription(ctx, req)
	if err != nil {
		fmt.Printf("Transcription error: %v\n", err)
		return
	}
	fmt.Println(resp.Text)
}
Audio Captions
package main

import (
	"context"
	"fmt"
	"os"

	openai "github.com/sashabaranov/go-openai"
)

func main() {
	c := openai.NewClient(os.Getenv("OPENAI_KEY"))

	req := openai.AudioRequest{
		Model:    openai.Whisper1,
		FilePath: os.Args[1],
		Format:   openai.AudioResponseFormatSRT,
	}
	resp, err := c.CreateTranscription(context.Background(), req)
	if err != nil {
		fmt.Printf("Transcription error: %v\n", err)
		return
	}
	f, err := os.Create(os.Args[1] + ".srt")
	if err != nil {
		fmt.Printf("Could not open file: %v\n", err)
		return
	}
	defer f.Close()
	if _, err := f.WriteString(resp.Text); err != nil {
		fmt.Printf("Error writing to file: %v\n", err)
		return
	}
}
DALL-E 2 image generation
package main

import (
	"bytes"
	"context"
	"encoding/base64"
	"fmt"
	openai "github.com/sashabaranov/go-openai"
	"image/png"
	"os"
)

func main() {
	c := openai.NewClient("your token")
	ctx := context.Background()

	// Sample image by link
	reqUrl := openai.ImageRequest{
		Prompt:         "Parrot on a skateboard performs a trick, cartoon style, natural light, high detail",
		Size:           openai.CreateImageSize256x256,
		ResponseFormat: openai.CreateImageResponseFormatURL,
		N:              1,
	}

	respUrl, err := c.CreateImage(ctx, reqUrl)
	if err != nil {
		fmt.Printf("Image creation error: %v\n", err)
		return
	}
	fmt.Println(respUrl.Data[0].URL)

	// Example image as base64
	reqBase64 := openai.ImageRequest{
		Prompt:         "Portrait of a humanoid parrot in a classic costume, high detail, realistic light, unreal engine",
		Size:           openai.CreateImageSize256x256,
		ResponseFormat: openai.CreateImageResponseFormatB64JSON,
		N:              1,
	}

	respBase64, err := c.CreateImage(ctx, reqBase64)
	if err != nil {
		fmt.Printf("Image creation error: %v\n", err)
		return
	}

	imgBytes, err := base64.StdEncoding.DecodeString(respBase64.Data[0].B64JSON)
	if err != nil {
		fmt.Printf("Base64 decode error: %v\n", err)
		return
	}

	r := bytes.NewReader(imgBytes)
	imgData, err := png.Decode(r)
	if err != nil {
		fmt.Printf("PNG decode error: %v\n", err)
		return
	}

	file, err := os.Create("example.png")
	if err != nil {
		fmt.Printf("File creation error: %v\n", err)
		return
	}
	defer file.Close()

	if err := png.Encode(file, imgData); err != nil {
		fmt.Printf("PNG encode error: %v\n", err)
		return
	}

	fmt.Println("The image was saved as example.png")
}
Configuring proxy
config := openai.DefaultConfig("token")
proxyUrl, err := url.Parse("http://localhost:{port}")
if err != nil {
	panic(err)
}
transport := &http.Transport{
	Proxy: http.ProxyURL(proxyUrl),
}
config.HTTPClient = &http.Client{
	Transport: transport,
}

c := openai.NewClientWithConfig(config)

See also: https://pkg.go.dev/github.com/sashabaranov/go-openai#ClientConfig

ChatGPT support context
package main

import (
	"bufio"
	"context"
	"fmt"
	"os"
	"strings"

	"github.com/sashabaranov/go-openai"
)

func main() {
	client := openai.NewClient("your token")
	messages := make([]openai.ChatCompletionMessage, 0)
	reader := bufio.NewReader(os.Stdin)
	fmt.Println("Conversation")
	fmt.Println("---------------------")

	for {
		fmt.Print("-> ")
		text, _ := reader.ReadString('\n')
		// convert CRLF to LF
		text = strings.Replace(text, "\n", "", -1)
		messages = append(messages, openai.ChatCompletionMessage{
			Role:    openai.ChatMessageRoleUser,
			Content: text,
		})

		resp, err := client.CreateChatCompletion(
			context.Background(),
			openai.ChatCompletionRequest{
				Model:    openai.GPT3Dot5Turbo,
				Messages: messages,
			},
		)

		if err != nil {
			fmt.Printf("ChatCompletion error: %v\n", err)
			continue
		}

		content := resp.Choices[0].Message.Content
		messages = append(messages, openai.ChatCompletionMessage{
			Role:    openai.ChatMessageRoleAssistant,
			Content: content,
		})
		fmt.Println(content)
	}
}
Azure OpenAI ChatGPT
package main

import (
	"context"
	"fmt"

	openai "github.com/sashabaranov/go-openai"
)

func main() {
	config := openai.DefaultAzureConfig("your Azure OpenAI Key", "https://your Azure OpenAI Endpoint")
	// If you use a deployment name different from the model name, you can customize the AzureModelMapperFunc function
	// config.AzureModelMapperFunc = func(model string) string {
	// 	azureModelMapping := map[string]string{
	// 		"gpt-3.5-turbo": "your gpt-3.5-turbo deployment name",
	// 	}
	// 	return azureModelMapping[model]
	// }

	client := openai.NewClientWithConfig(config)
	resp, err := client.CreateChatCompletion(
		context.Background(),
		openai.ChatCompletionRequest{
			Model: openai.GPT3Dot5Turbo,
			Messages: []openai.ChatCompletionMessage{
				{
					Role:    openai.ChatMessageRoleUser,
					Content: "Hello Azure OpenAI!",
				},
			},
		},
	)
	if err != nil {
		fmt.Printf("ChatCompletion error: %v\n", err)
		return
	}

	fmt.Println(resp.Choices[0].Message.Content)
}
Embedding Semantic Similarity
package main

import (
	"context"
	"log"
	openai "github.com/sashabaranov/go-openai"

)

func main() {
	client := openai.NewClient("your-token")

	// Create an EmbeddingRequest for the user query
	queryReq := openai.EmbeddingRequest{
		Input: []string{"How many chucks would a woodchuck chuck"},
		Model: openai.AdaEmbeddingV2,
	}

	// Create an embedding for the user query
	queryResponse, err := client.CreateEmbeddings(context.Background(), queryReq)
	if err != nil {
		log.Fatal("Error creating query embedding:", err)
	}

	// Create an EmbeddingRequest for the target text
	targetReq := openai.EmbeddingRequest{
		Input: []string{"How many chucks would a woodchuck chuck if the woodchuck could chuck wood"},
		Model: openai.AdaEmbeddingV2,
	}

	// Create an embedding for the target text
	targetResponse, err := client.CreateEmbeddings(context.Background(), targetReq)
	if err != nil {
		log.Fatal("Error creating target embedding:", err)
	}

	// Now that we have the embeddings for the user query and the target text, we
	// can calculate their similarity.
	queryEmbedding := queryResponse.Data[0]
	targetEmbedding := targetResponse.Data[0]

	similarity, err := queryEmbedding.DotProduct(&targetEmbedding)
	if err != nil {
		log.Fatal("Error calculating dot product:", err)
	}

	log.Printf("The similarity score between the query and the target is %f", similarity)
}
Azure OpenAI Embeddings
package main

import (
	"context"
	"fmt"

	openai "github.com/sashabaranov/go-openai"
)

func main() {

	config := openai.DefaultAzureConfig("your Azure OpenAI Key", "https://your Azure OpenAI Endpoint")
	config.APIVersion = "2023-05-15" // optional update to latest API version

	//If you use a deployment name different from the model name, you can customize the AzureModelMapperFunc function
	//config.AzureModelMapperFunc = func(model string) string {
	//    azureModelMapping := map[string]string{
	//        "gpt-3.5-turbo":"your gpt-3.5-turbo deployment name",
	//    }
	//    return azureModelMapping[model]
	//}

	input := "Text to vectorize"

	client := openai.NewClientWithConfig(config)
	resp, err := client.CreateEmbeddings(
		context.Background(),
		openai.EmbeddingRequest{
			Input: []string{input},
			Model: openai.AdaEmbeddingV2,
		})

	if err != nil {
		fmt.Printf("CreateEmbeddings error: %v\n", err)
		return
	}

	vectors := resp.Data[0].Embedding // []float32 with 1536 dimensions

	fmt.Println(vectors[:10], "...", vectors[len(vectors)-10:])
}
JSON Schema for function calling

It is now possible for chat completion to choose to call a function for more information (see developer docs here).

In order to describe the type of functions that can be called, a JSON schema must be provided. Many JSON schema libraries exist and are more advanced than what we can offer in this library, however we have included a simple jsonschema package for those who want to use this feature without formatting their own JSON schema payload.

The developer documents give this JSON schema definition as an example:

{
  "name":"get_current_weather",
  "description":"Get the current weather in a given location",
  "parameters":{
    "type":"object",
    "properties":{
        "location":{
          "type":"string",
          "description":"The city and state, e.g. San Francisco, CA"
        },
        "unit":{
          "type":"string",
          "enum":[
              "celsius",
              "fahrenheit"
          ]
        }
    },
    "required":[
        "location"
    ]
  }
}

Using the jsonschema package, this schema could be created using structs as such:

FunctionDefinition{
  Name: "get_current_weather",
  Parameters: jsonschema.Definition{
    Type: jsonschema.Object,
    Properties: map[string]jsonschema.Definition{
      "location": {
        Type: jsonschema.String,
        Description: "The city and state, e.g. San Francisco, CA",
      },
      "unit": {
        Type: jsonschema.String,
        Enum: []string{"celsius", "fahrenheit"},
      },
    },
    Required: []string{"location"},
  },
}

The Parameters field of a FunctionDefinition can accept either of the above styles, or even a nested struct from another library (as long as it can be marshalled into JSON).

Error handling

Open-AI maintains clear documentation on how to handle API errors

example:

e := &openai.APIError{}
if errors.As(err, &e) {
  switch e.HTTPStatusCode {
    case 401:
      // invalid auth or key (do not retry)
    case 429:
      // rate limiting or engine overload (wait and retry) 
    case 500:
      // openai server error (retry)
    default:
      // unhandled
  }
}

Fine Tune Model
package main

import (
	"context"
	"fmt"
	"github.com/sashabaranov/go-openai"
)

func main() {
	client := openai.NewClient("your token")
	ctx := context.Background()

	// create a .jsonl file with your training data for conversational model
	// {"prompt": "<prompt text>", "completion": "<ideal generated text>"}
	// {"prompt": "<prompt text>", "completion": "<ideal generated text>"}
	// {"prompt": "<prompt text>", "completion": "<ideal generated text>"}

	// chat models are trained using the following file format:
	// {"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already."}]}
	// {"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?"}]}
	// {"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "How far is the Moon from Earth?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters."}]}

	// you can use openai cli tool to validate the data
	// For more info - https://platform.openai.com/docs/guides/fine-tuning

	file, err := client.CreateFile(ctx, openai.FileRequest{
		FilePath: "training_prepared.jsonl",
		Purpose:  "fine-tune",
	})
	if err != nil {
		fmt.Printf("Upload JSONL file error: %v\n", err)
		return
	}

	// create a fine tuning job
	// Streams events until the job is done (this often takes minutes, but can take hours if there are many jobs in the queue or your dataset is large)
	// use below get method to know the status of your model
	fineTuningJob, err := client.CreateFineTuningJob(ctx, openai.FineTuningJobRequest{
		TrainingFile: file.ID,
		Model:        "davinci-002", // gpt-3.5-turbo-0613, babbage-002.
	})
	if err != nil {
		fmt.Printf("Creating new fine tune model error: %v\n", err)
		return
	}

	fineTuningJob, err = client.RetrieveFineTuningJob(ctx, fineTuningJob.ID)
	if err != nil {
		fmt.Printf("Getting fine tune model error: %v\n", err)
		return
	}
	fmt.Println(fineTuningJob.FineTunedModel)

	// once the status of fineTuningJob is `succeeded`, you can use your fine tune model in Completion Request or Chat Completion Request

	// resp, err := client.CreateCompletion(ctx, openai.CompletionRequest{
	//	 Model:  fineTuningJob.FineTunedModel,
	//	 Prompt: "your prompt",
	// })
	// if err != nil {
	//	 fmt.Printf("Create completion error %v\n", err)
	//	 return
	// }
	//
	// fmt.Println(resp.Choices[0].Text)
}
See the `examples/` folder for more.

Frequently Asked Questions

Why don't we get the same answer when specifying a temperature field of 0 and asking the same question?

Even when specifying a temperature field of 0, it doesn't guarantee that you'll always get the same response. Several factors come into play.

  1. Go OpenAI Behavior: When you specify a temperature field of 0 in Go OpenAI, the omitempty tag causes that field to be removed from the request. Consequently, the OpenAI API applies the default value of 1.
  2. Token Count for Input/Output: If there's a large number of tokens in the input and output, setting the temperature to 0 can still result in non-deterministic behavior. In particular, when using around 32k tokens, the likelihood of non-deterministic behavior becomes highest even with a temperature of 0.

Due to the factors mentioned above, different answers may be returned even for the same question.

Workarounds:

  1. As of November 2023, use the new seed parameter in conjunction with the system_fingerprint response field, alongside Temperature management.
  2. Try using math.SmallestNonzeroFloat32: By specifying math.SmallestNonzeroFloat32 in the temperature field instead of 0, you can mimic the behavior of setting it to 0.
  3. Limiting Token Count: By limiting the number of tokens in the input and output and especially avoiding large requests close to 32k tokens, you can reduce the risk of non-deterministic behavior.

By adopting these strategies, you can expect more consistent results.

Related Issues:
omitempty option of request struct will generate incorrect request when parameter is 0.

Does Go OpenAI provide a method to count tokens?

No, Go OpenAI does not offer a feature to count tokens, and there are no plans to provide such a feature in the future. However, if there's a way to implement a token counting feature with zero dependencies, it might be possible to merge that feature into Go OpenAI. Otherwise, it would be more appropriate to implement it in a dedicated library or repository.

For counting tokens, you might find the following links helpful:

Related Issues:
Is it possible to join the implementation of GPT3 Tokenizer

Contributing

By following Contributing Guidelines, we hope to ensure that your contributions are made smoothly and efficiently.

Thank you

We want to take a moment to express our deepest gratitude to the contributors and sponsors of this project:

To all of you: thank you. You've helped us achieve more than we ever imagined possible. Can't wait to see where we go next, together!

go-openai's People

Contributors

aceld avatar adaynu avatar agcom avatar albertpurnama avatar bestgopher avatar blfletcher avatar bnwlkr avatar chrbsg avatar coggsfl avatar coggsflod avatar deining avatar henomis avatar hoani avatar itegel avatar jooyyy avatar liushuangls avatar mtrefilek avatar nasa1024 avatar nicexai avatar qhenkart avatar rexposadas avatar sashabaranov avatar shadowpigy avatar simonklee avatar urjitbhatia avatar vvatanabe avatar wqyjh avatar yukibobier avatar zerodeng01 avatar zjy282 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-openai's Issues

Fix the example usage

I'm trying to get started with the example from the readme file. I'm pretty sure that I'm providing the correct API key but it gives me the following error:

2023/01/12 02:32:32 error, status code: 401
exit status 1

The command below with the same API key gives me the status 200 OK.

curl https://api.openai.com/v1/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"model": "text-davinci-003", "prompt": "Say this is a test", "temperature": 0, "max_tokens": 7}'

Http Client Transport Support

For some reason, the API is banned in some countries.

After added the following codes, it works:

        config := gogpt.DefaultConfig("token")
	// 创建一个 HTTP Transport 对象,并设置代理服务器
	proxyUrl, err := url.Parse("http://localhost:{port}")
	if err != nil {
		panic(err)
	}
	transport := &http.Transport{
		Proxy: http.ProxyURL(proxyUrl),
	}
	// 创建一个 HTTP 客户端,并将 Transport 对象设置为其 Transport 字段
	config.HTTPClient = &http.Client{
		Transport: transport,
	}

	c := gogpt.NewClientWithConfig(config)

emptyMessagesLimit and Stream error

Hi,

Thanks for your excellent work.

Yesterday, doing calls to CreateCompletionStream() function I started getting the following error:
Stream error: stream has sent too many empty messages

Requests were like this:

{
  "model": "text-davinci-003",
  "prompt": "В чем смысл жизни?",
  "max_tokens": 512,
  "temperature": 0.7,
  "stream": true
}

Seems like it's related to
emptyMessagesLimit = 100 in stream.go.

My code:

	stream, err := c.CreateCompletionStream(context.Background(), params)
	if err != nil {
		return
	}
	defer stream.Close()

	for {
		response, err := stream.Recv()
		if errors.Is(err, io.EOF) {
			return
		}

		if err != nil {
			fmt.Printf("Stream error: %v\n", err)
			return
		}

		choices := response.Choices
		if len(choices) > 0 {
			fmt.Printf("%s", choices[0].Text)
		}
	}

I copied it from your example. Before yesterday it worked fine. Today this error seems to persist.

Could you please check it or make the variable configurable?

Thanks again.

Expose APIError required

At present, I don't know how to get the original error message.
I need to make conditional judgments based on the original error code to do different things.

Please let me know if you have a solution, thanks

when the apikey is use out money it return EOF?

maybe then you use out money ,it should return error ,like
You exceeded your current quota, please check your plan and billing details.

this is a apikey for test : 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

API support for beta version

Hi Team,

I have tried to use the codex model, but there is no support for the beta version API. Do you guys think we should add support for the beta version API? I would be happy to help with this.

`omitempty` option of request struct will generate incorrect request when parameter is 0.

The 'omitempty' option of the request structs should be removed. This is because it generates an incorrect request when a parameter is 0. For example, a request with the temperate field set to '0' will actually return a response as if the field had been set to one. This is because the go JSON parser does not differentiate between a 0 value and no value for float32, so Openai will receive a request without a temperate field which then defaults to a temperature value of 1.

Support multiple prompts in CompletionRequest

Hi 👋 Thanks for developing a great library!

Openai create-prompt documentation says the prompt field is supported encoded as a string, array of strings, array of tokens, or array of token arrays. but this library seems to be supported only encoded as a string.

openai-js implemented type for that like this: https://github.com/threepointone/openai-js/blob/eaade749f2ead531d2ac9a2015184f7b6418a581/api.ts#L475

So I want to ask the question, How can I send a completion request with an array of string?

Thanks

Use the new API URLs and deprecate the old endpoints

OpenAI's API has recently changed so API calls are made to endpoints such as /v1/completions for completions instead of /v1/engines/${engineID}/completions.

I'm currently migrating to using go-gpt3 instead of my own client, and would like to incorporate a mock server for simulating responses. This would be incredibly helpful to avoid handling the old API.

Add Coverage Data

We should track code coverage of the go-gpt3 client with a tool such as codecov.

Demo code not working

Please forgive me if I am asking an insanely stupid question. I got the go-gpt3 code, then copied verbatim the example usage, and when I try to run the example code I get no response.

I did not download anything else besides go-gpt3, therefore, here is the (potentially insanely stupid question): Do I need to download something else. e.g., the openai API in Python or in .js?

I don't like Python or JS, I would rather use pure Go if possible, but if there is no other choice and I have to get the Python or the JS version, which one would be the better choice?

Thanks you

Does this library support streaming?

I can see that the CompletionRequest takes a Stream bool, but I don't see anything in the code that would indicate streaming support or functionality. I could very easily be missing something though, so wanted to check with you. Thanks.

Mark search API as deprecated

I am creating this issue to introduce myself as well. I am using go-gpt3 as the underlying library for my tool geppetto, and would like to provide an easy to use CLI tool for all openai APIs. As I was going through, I noticed that the search API was deprecated (and in fact, not even reachable from the doc page).

Should we mark it as deprecated in the library as well?

Embeddings upgrade

Current embeddings API might use an improvement:

  • Use float32 instead of float64 (I highly doubt that OpenAI uses 64-bit floats in their LLM)
  • Add some basic operations between embeddings, like cosine similarity (which is equal to dot product due to embeddings being normalized to length 1)

the stream always return EOF

func test1(key, input string, callback func(message string)) {

config := gogpt.DefaultConfig(key)
config.EmptyMessagesLimit = 10000
c := gogpt.NewClientWithConfig(config)
ctx := context.Background()

req := gogpt.CompletionRequest{
	Model:     gogpt.GPT3TextDavinci003,
	MaxTokens: 5,
	Prompt:    input,
	Stream:    true,
}

stream, err := c.CreateCompletionStream(ctx, req)

if err != nil {
	return
}
defer stream.Close()
i := 0
for {
	i++
	response, err := stream.Recv()
	if errors.Is(err, io.EOF) {
		fmt.Println(err.Error())
		fmt.Println("Stream finished")
		return
	}
	if err != nil {
		fmt.Printf("Stream error: %v\n", err)
		return
	}
	var txt string
	if len(response.Choices) > 0 {
		txt = response.Choices[0].Text
	}
	callback(txt)
	//fmt.Printf("Stream response: %v\n", response.Choices[0])
}

}

the version is v1.2.0
thanks

Introducing generics in a future version

Are you considering introducing generics in future releases?

If we introduce a generics:
Pros: sdk implementation will potentially become more elegant.
Cons: only support go1.8.0 or above, compatibility becomes worse.

Add a Mocked Server for Testing

Based on a request from #27, we should introduce a mocked server which tests that values are correctly sent by go-gpt3 and received by the server, as well as the ability for the client to receive data from the server.

This can help us to quickly iterate on tests without spending any OpenAI credits.

We need the following to complete this task

  • Create a mocked OpenAI API server
  • Write endpoint handlers and tests for the mocked server:
    • Completions
    • Edits
    • Moderation
    • Search
    • Embeddings
    • Answers
    • Files
    • Classifications

Inconsistent results from GPT with temperature = 0

I am getting a wide variety of results from GPT, but my temperature is 0. I'm using a custom-trained model. I contacted GPT/openai, but their customer support seems to be inadequate.

req := gogpt.CompletionRequest{
	Model:       "davinci:ft-text-friday-2022-10-02-03-58-57",
	MaxTokens:   100, // 16 is default
	Prompt:      prompt,
	Temperature: 0,
	//TopP:             1,
	//FrequencyPenalty: 0,
	//PresencePenalty:  0,
	Stop: []string{" ->", ">>>"},
}

Example 1

 TRC Respond in JSON. I want to buy water. ->
8:02AM TRC GPT 5
8:02AM TRC GPT 6
8:02AM TRC GPT 6.a
8:02AM TRC returned: null
We'll update the last message sent to match the reply, and we'll update the request.id to say:
{ 'Store': 'water', 'Category': 'latest', 'Message': 'I want to buy water', 'Date': '2016-09-21T10:52:13', 'RequestId': '20', 'Reply': 'null', 'ArrivalDate': '2016-09-21T10:52:13'}

Example 2, sent seconds later

8:02AM TRC Respond in JSON. I want to buy water. ->
8:02AM TRC GPT 5
8:02AM TRC GPT 6
8:02AM TRC GPT 6.a
8:02AM TRC returned: {'Function': 'contact_support', 'Noun': 'water', 'Adjectives': [], 'Category': '', 'ClothingType': '', 'Quantity': 0, 'ArrivalDate': '', 'Store': '', 'MinPrice': 0, 'MaxPrice': 0, 'Multiple': False}

The New Moderation Endpoint

They said:

In the future, we will deprecate content-filter-alpha in favor of the moderation endpoint. For now, we recommend that users begin transitioning to the new endpoint for testing.

Personally, I actively use the content-filter-alpha as this is required if your apps were already approved by OpenAI.
This is also required if one wants to pass the app review's Standard safety requirements.

Would love to see this being supported soon~

Here are some details about the moderation endpoint:

How to keep the context in the conversation

How to keep the context in the conversation

I'm trying to do a continuous question and answer session, but each time it's a new context and he can't analyze the question I asked earlier.

I think there should be an attribute like session_id, but there isn't, so how should I do it?



// CompletionRequest represents a request structure for completion API.
type CompletionRequest struct {
	Model            string         `json:"model"`
	Prompt           string         `json:"prompt,omitempty"`
	Suffix           string         `json:"suffix,omitempty"`
	MaxTokens        int            `json:"max_tokens,omitempty"`
	Temperature      float32        `json:"temperature,omitempty"`
	TopP             float32        `json:"top_p,omitempty"`
	N                int            `json:"n,omitempty"`
	Stream           bool           `json:"stream,omitempty"`
	LogProbs         int            `json:"logprobs,omitempty"`
	Echo             bool           `json:"echo,omitempty"`
	Stop             []string       `json:"stop,omitempty"`
	PresencePenalty  float32        `json:"presence_penalty,omitempty"`
	FrequencyPenalty float32        `json:"frequency_penalty,omitempty"`
	BestOf           int            `json:"best_of,omitempty"`
	LogitBias        map[string]int `json:"logit_bias,omitempty"`
	User             string         `json:"user,omitempty"`
}

This request body, none of which identifies the session attributes

stream mode,can 't detect answer is over

the code is bellow :

for {
		response, err := stream.Recv()
		if errors.Is(err, io.EOF) {
			fmt.Println("Stream finished")
			return
		}

		if err != nil {
			fmt.Printf("Stream error: %v\n", err)
			return
		}

		fmt.Printf("%v\n", err)
		fmt.Printf("%T\n", response.Choices[0].Text)
		//fmt.Printf("%s", response.Choices[0].Text)
	}

this is echo :

<nil>
string
<nil>
string
<nil>
string
<nil>
string
<nil>
string
<nil>
string
<nil>
string
<nil>
string
<nil>
string
<nil>
string
<nil>
string
<nil>
string
<nil>
string
<nil>
string
<nil>
panic: runtime error: index out of range [0] with length 0

goroutine 1 [running]:
main.main()
        /home/ly/Desktop/chatgpt/mydemo2/main.go:42 +0x545

then answer is over err is not equal io.EOF

		if errors.Is(err, io.EOF) {
			fmt.Println("Stream finished")
			return
		}

the chat stream api should check return error message.

https://github.com/sashabaranov/go-gpt3/blob/575c4e4adbf3e12dea780c735fa9c19062440e11/chat_stream.go#L40

In the recv method is that it does not check the response status code, and it returns an empty message instead of an error message when the status is not 200.

To fix this issue, the recv method should check the status code of the response and return an error message if the status code is not 200. The error message should be of type ErrorResponse with an APIError field containing the appropriate error information.

type APIError struct {
	Code       *string `json:"code,omitempty"`
	Message    string  `json:"message"`
	Param      *string `json:"param,omitempty"`
	Type       string  `json:"type"`
	StatusCode int     `json:"-"`
}
type ErrorResponse struct {
	Error *APIError `json:"error,omitempty"`
}

gpt3dot5trurbo error

when i change model to gpt3dot5truo api return error msg like this :

error, status code: 404, message: This is a chat model and not supported in the v1/completions endpoint. Did you mean to use v1/chat/completions?

Support new chat API (POST /chat/completions)

OpenAI announced support for a new chat API like chatGPT. This has a similar request and response model to the completions endpoint but with slight variations.

POST: https://api.openai.com/v1/chat/completions

Request:

{
  "model": "gpt-3.5-turbo",
  "messages": [{"role": "user", "content": "Hello!"}]
}

Response:

{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1677652288,
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "\n\nHello there, how may I assist you today?",
    },
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 12,
    "total_tokens": 21
  }
}

Further details can be found here: https://platform.openai.com/docs/guides/chat

GPT3Dot5Turbo0301 model always return EOF

I have upgraded to the latest version but it always return EOF, and the previous version was normal

func test1(key, input string, callback func(message string)) {
	config := gogpt.DefaultConfig(key)
	config.EmptyMessagesLimit = 10000
	c := gogpt.NewClientWithConfig(config)
	ctx := context.Background()

	req := gogpt.CompletionRequest{
		Model:     gogpt.GPT3Dot5Turbo0301,
		MaxTokens: 100,
		Prompt:    input,
		Stream:    true,
	}
	stream, err := c.CreateCompletionStream(ctx, req)
	if err != nil {
		return
	}
	defer stream.Close()
	i := 0
	for {
		i++
		response, err := stream.Recv()
		if errors.Is(err, io.EOF) {
			fmt.Println(err.Error())
			fmt.Println("Stream finished")
			return
		}

		if err != nil {
			fmt.Printf("Stream error: %v\n", err)
			return
		}
		var txt string
		if len(response.Choices) > 0 {
			txt = response.Choices[0].Text
		}
		callback(txt)
		//fmt.Printf("Stream response: %v\n", response.Choices[0])
	}
}
key := "sk-Z5vCOAEQ3IINgZ0KpzDkT3BlbkFJ******7BQtM"
test1(key, "hello", func(message string) {
		fmt.Print(message)
	})

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.