[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-73247":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":15,"forks30d":15,"starsTrendScore":19,"compositeScore":20,"rankGlobal":9,"rankLanguage":9,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":24,"hasPages":22,"topics":25,"createdAt":9,"pushedAt":9,"updatedAt":26,"readmeContent":27,"aiSummary":28,"trendingCount":15,"starSnapshotCount":15,"syncStatus":29,"lastSyncTime":30,"discoverSource":31},73247,"openai-go","openai\u002Fopenai-go","openai","The official Go library for the OpenAI API",null,"Go",3289,325,32,96,0,3,18,69,9,29.54,"Apache License 2.0",false,"main",true,[],"2026-06-12 02:03:10","# OpenAI Go API Library\n\n\u003C!-- x-release-please-start-version -->\n\n\u003Ca href=\"https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fopenai\u002Fopenai-go\u002Fv3\">\u003Cimg src=\"https:\u002F\u002Fpkg.go.dev\u002Fbadge\u002Fgithub.com\u002Fopenai\u002Fopenai-go.svg\" alt=\"Go Reference\">\u003C\u002Fa>\n\n\u003C!-- x-release-please-end -->\n\nThe OpenAI Go library provides convenient access to the [OpenAI REST API](https:\u002F\u002Fplatform.openai.com\u002Fdocs)\nfrom applications written in Go.\n\n> [!WARNING]\n> The latest version of this package has small and limited breaking changes.\n> See the [changelog](CHANGELOG.md) for details.\n\n## Installation\n\n\u003C!-- x-release-please-start-version -->\n\n```go\nimport (\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\" \u002F\u002F imported as openai\n)\n```\n\n\u003C!-- x-release-please-end -->\n\nOr to pin the version:\n\n\u003C!-- x-release-please-start-version -->\n\n```sh\ngo get -u 'github.com\u002Fopenai\u002Fopenai-go\u002Fv3@v3.36.0'\n```\n\n\u003C!-- x-release-please-end -->\n\n## Requirements\n\nThis library requires Go 1.22+.\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\nThe primary API for interacting with OpenAI models is the [Responses API](https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fapi-reference\u002Fresponses). You can generate text from the model with the code below.\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\"\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\u002Foption\"\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\u002Fresponses\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\tclient := openai.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"), \u002F\u002F defaults to os.LookupEnv(\"OPENAI_API_KEY\")\n\t)\n\n\tquestion := \"Write me a haiku about computers\"\n\n\tresp, err := client.Responses.New(ctx, responses.ResponseNewParams{\n\t\tInput: responses.ResponseNewParamsInputUnion{OfString: openai.String(question)},\n\t\tModel: openai.ChatModelGPT5_2,\n\t})\n\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tprintln(resp.OutputText())\n}\n```\n\n\u003Cdetails>\n\u003Csummary>Multi-turn Responses\u003C\u002Fsummary>\n\n```go\nresponse, err := client.Responses.New(ctx, responses.ResponseNewParams{\n\tModel: openai.ChatModelGPT5_2,\n\tInput: responses.ResponseNewParamsInputUnion{\n\t\tOfString: openai.String(\"What is the capital of France?\"),\n\t},\n})\nif err != nil {\n\tpanic(err)\n}\nfmt.Println(\"First response:\", response.OutputText())\n\n\u002F\u002F Use PreviousResponseID to continue the conversation\nresponse, err = client.Responses.New(ctx, responses.ResponseNewParams{\n\tModel:              openai.ChatModelGPT5_2,\n\tPreviousResponseID: openai.String(response.ID),\n\tInput: responses.ResponseNewParamsInputUnion{\n\t\tOfString: openai.String(\"And what is the population of that city?\"),\n\t},\n})\nif err != nil {\n\tpanic(err)\n}\nfmt.Println(\"Second response:\", response.OutputText())\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Conversations\u003C\u002Fsummary>\n\n```go\nconv, err := client.Conversations.New(ctx, conversations.ConversationNewParams{})\nif err != nil {\n\tpanic(err)\n}\nfmt.Println(\"Created conversation:\", conv.ID)\n\nresponse, err := client.Responses.New(ctx, responses.ResponseNewParams{\n\tModel: openai.ChatModelGPT5_2,\n\tInput: responses.ResponseNewParamsInputUnion{\n\t\tOfString: openai.String(\"Hello! Remember that my favorite color is blue.\"),\n\t},\n\tConversation: responses.ResponseNewParamsConversationUnion{\n\t\tOfConversationObject: &responses.ResponseConversationParam{\n\t\t\tID: conv.ID,\n\t\t},\n\t},\n})\nif err != nil {\n\tpanic(err)\n}\nfmt.Println(\"First response:\", response.OutputText())\n\n\u002F\u002F Continue the conversation\nresponse, err = client.Responses.New(ctx, responses.ResponseNewParams{\n\tModel: openai.ChatModelGPT5_2,\n\tInput: responses.ResponseNewParamsInputUnion{\n\t\tOfString: openai.String(\"What is my favorite color?\"),\n\t},\n\tConversation: responses.ResponseNewParamsConversationUnion{\n\t\tOfConversationObject: &responses.ResponseConversationParam{\n\t\t\tID: conv.ID,\n\t\t},\n\t},\n})\nif err != nil {\n\tpanic(err)\n}\nfmt.Println(\"Second response:\", response.OutputText())\n\nitems, err := client.Conversations.Items.List(ctx, conv.ID, conversations.ItemListParams{})\nif err != nil {\n\tpanic(err)\n}\nfmt.Println(\"Conversation has\", len(items.Data), \"items\")\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Streaming responses\u003C\u002Fsummary>\n\n```go\nctx := context.Background()\n\nstream := client.Responses.NewStreaming(ctx, responses.ResponseNewParams{\n\tModel: openai.ChatModelGPT5_2,\n\tInput: responses.ResponseNewParamsInputUnion{\n\t\tOfString: openai.String(\"Write a haiku about programming\"),\n\t},\n})\n\nfor stream.Next() {\n\tevent := stream.Current()\n\tprint(event.Delta)\n}\n\nif stream.Err() != nil {\n\tpanic(stream.Err())\n}\n```\n\n> See the [full streaming example](.\u002Fexamples\u002Fresponses-streaming\u002Fmain.go)\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Tool calling\u003C\u002Fsummary>\n\n```go\nctx := context.Background()\n\nparams := responses.ResponseNewParams{\n\tModel: openai.ChatModelGPT5_2,\n\tInput: responses.ResponseNewParamsInputUnion{\n\t\tOfString: openai.String(\"What is the weather in New York City?\"),\n\t},\n\tTools: []responses.ToolUnionParam{{\n\t\tOfFunction: &responses.FunctionToolParam{\n\t\t\tName:        \"get_weather\",\n\t\t\tDescription: openai.String(\"Get weather at the given location\"),\n\t\t\tParameters: map[string]any{\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": map[string]any{\n\t\t\t\t\t\"location\": map[string]string{\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"required\": []string{\"location\"},\n\t\t\t},\n\t\t},\n\t}},\n}\n\nresponse, _ := client.Responses.New(ctx, params)\n\n\u002F\u002F Check for function calls in the response output\nfor _, item := range response.Output {\n\tif item.Type == \"function_call\" {\n\t\ttoolCall := item.AsFunctionCall()\n\t\tif toolCall.Name == \"get_weather\" {\n\t\t\t\u002F\u002F Extract arguments and call your function\n\t\t\tvar args map[string]any\n\t\t\tjson.Unmarshal([]byte(toolCall.Arguments), &args)\n\t\t\tlocation := args[\"location\"].(string)\n\n\t\t\t\u002F\u002F Simulate getting weather data\n\t\t\tweatherData := getWeather(location)\n\t\t\tfmt.Printf(\"Weather in %s: %s\\n\", location, weatherData)\n\n\t\t\t\u002F\u002F Continue conversation with function result\n\t\t\tresponse, _ = client.Responses.New(ctx, responses.ResponseNewParams{\n\t\t\t\tModel:              openai.ChatModelGPT5_2,\n\t\t\t\tPreviousResponseID: openai.String(response.ID),\n\t\t\t\tInput: responses.ResponseNewParamsInputUnion{\n\t\t\t\t\tOfInputItemList: []responses.ResponseInputItemUnionParam{{\n\t\t\t\t\t\tOfFunctionCallOutput: &responses.ResponseInputItemFunctionCallOutputParam{\n\t\t\t\t\t\t\tCallID: toolCall.CallID,\n\t\t\t\t\t\t\tOutput: responses.ResponseInputItemFunctionCallOutputOutputUnionParam{\n\t\t\t\t\t\t\t\tOfString: openai.String(weatherData),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}},\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}\n}\n```\n\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Structured outputs\u003C\u002Fsummary>\n\n```go\nimport (\n\t\"encoding\u002Fjson\"\n\t\"github.com\u002Finvopop\u002Fjsonschema\"\n\t\u002F\u002F ...\n)\n\n\u002F\u002F A struct that will be converted to a Structured Outputs response schema\ntype HistoricalComputer struct {\n\tOrigin       Origin   `json:\"origin\" jsonschema_description:\"The origin of the computer\"`\n\tName         string   `json:\"full_name\" jsonschema_description:\"The name of the device model\"`\n\tLegacy       string   `json:\"legacy\" jsonschema:\"enum=positive,enum=neutral,enum=negative\" jsonschema_description:\"Its influence on the field of computing\"`\n\tNotableFacts []string `json:\"notable_facts\" jsonschema_description:\"A few key facts about the computer\"`\n}\n\ntype Origin struct {\n\tYearBuilt    int64  `json:\"year_of_construction\" jsonschema_description:\"The year it was made\"`\n\tOrganization string `json:\"organization\" jsonschema_description:\"The organization that was in charge of its development\"`\n}\n\n\u002F\u002F Structured Outputs uses a subset of JSON schema\n\u002F\u002F These flags are necessary to comply with the subset\nfunc GenerateSchema[T any]() map[string]any {\n\treflector := jsonschema.Reflector{\n\t\tAllowAdditionalProperties: false,\n\t\tDoNotReference:            true,\n\t}\n\tvar v T\n\tschema := reflector.Reflect(v)\n\n\tdata, _ := json.Marshal(schema)\n\tvar result map[string]any\n\tjson.Unmarshal(data, &result)\n\treturn result\n}\n\n\u002F\u002F Generate the JSON schema at initialization time\nvar HistoricalComputerSchema = GenerateSchema[HistoricalComputer]()\n\nfunc main() {\n\tclient := openai.NewClient()\n\tctx := context.Background()\n\n\tresponse, err := client.Responses.New(ctx, responses.ResponseNewParams{\n\t\tModel: openai.ChatModelGPT5_2,\n\t\tInput: responses.ResponseNewParamsInputUnion{\n\t\t\tOfString: openai.String(\"What computer ran the first neural network?\"),\n\t\t},\n\t\tText: responses.ResponseTextConfigParam{\n\t\t\tFormat: responses.ResponseFormatTextConfigParamOfJSONSchema(\n\t\t\t\t\"historical_computer\",\n\t\t\t\tHistoricalComputerSchema,\n\t\t\t),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t\u002F\u002F extract into a well-typed struct\n\tvar historicalComputer HistoricalComputer\n\t_ = json.Unmarshal([]byte(response.OutputText()), &historicalComputer)\n\n\thistoricalComputer.Name\n\thistoricalComputer.Origin.YearBuilt\n\thistoricalComputer.Origin.Organization\n\tfor i, fact := range historicalComputer.NotableFacts {\n\t\t\u002F\u002F ...\n\t}\n}\n```\n\n> See the [full structured outputs example](.\u002Fexamples\u002Fresponses-structured-outputs\u002Fmain.go)\n\n\u003C\u002Fdetails>\n\n### Chat Completions API\n\nThe previous standard (supported indefinitely) for generating text is the [Chat Completions API](https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fapi-reference\u002Fchat). You can use that API to generate text from the model with the code below.\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\"\n)\n\nfunc main() {\n\tclient := openai.NewClient()\n\n\tchatCompletion, err := client.Chat.Completions.New(context.TODO(), openai.ChatCompletionNewParams{\n\t\tMessages: []openai.ChatCompletionMessageParamUnion{\n\t\t\topenai.DeveloperMessage(\"You are a coding assistant that talks like a pirate.\"),\n\t\t\topenai.UserMessage(\"How do I check if a slice is empty in Go?\"),\n\t\t},\n\t\tModel: openai.ChatModelGPT5_2,\n\t})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tprintln(chatCompletion.Choices[0].Message.Content)\n}\n```\n\n### Request fields\n\nThe openai library uses the [`omitzero`](https:\u002F\u002Ftip.golang.org\u002Fdoc\u002Fgo1.24#encodingjsonpkgencodingjson)\nsemantics from the Go 1.24+ `encoding\u002Fjson` release for request fields.\n\nRequired primitive fields (`int64`, `string`, etc.) feature the tag \u003Ccode>\\`api:\"required\"\\`\u003C\u002Fcode>. These\nfields are always serialized, even their zero values.\n\nOptional primitive types are wrapped in a `param.Opt[T]`. These fields can be set with the provided constructors, `openai.String(string)`, `openai.Int(int64)`, etc.\n\nAny `param.Opt[T]`, map, slice, struct or string enum uses the\ntag \u003Ccode>\\`json:\"...,omitzero\"\\`\u003C\u002Fcode>. Its zero value is considered omitted.\n\nThe `param.IsOmitted(any)` function can confirm the presence of any `omitzero` field.\n\n```go\np := openai.ExampleParams{\n\tID:   \"id_xxx\",             \u002F\u002F required property\n\tName: openai.String(\"...\"), \u002F\u002F optional property\n\n\tPoint: openai.Point{\n\t\tX: 0,             \u002F\u002F required field will serialize as 0\n\t\tY: openai.Int(1), \u002F\u002F optional field will serialize as 1\n\t\t\u002F\u002F ... omitted non-required fields will not be serialized\n\t},\n\n\tOrigin: openai.Origin{}, \u002F\u002F the zero value of [Origin] is considered omitted\n}\n```\n\nTo send `null` instead of a `param.Opt[T]`, use `param.Null[T]()`.\nTo send `null` instead of a struct `T`, use `param.NullStruct[T]()`.\n\n```go\np.Name = param.Null[string]()       \u002F\u002F 'null' instead of string\np.Point = param.NullStruct[Point]() \u002F\u002F 'null' instead of struct\n\nparam.IsNull(p.Name)  \u002F\u002F true\nparam.IsNull(p.Point) \u002F\u002F true\n```\n\nRequest structs contain a `.SetExtraFields(map[string]any)` method which can send non-conforming\nfields in the request body. Extra fields overwrite any struct fields with a matching\nkey. For security reasons, only use `SetExtraFields` with trusted data.\n\nTo send a custom value instead of a struct, use `param.Override[T](value)`.\n\n```go\n\u002F\u002F In cases where the API specifies a given type,\n\u002F\u002F but you want to send something else, use [SetExtraFields]:\np.SetExtraFields(map[string]any{\n\t\"x\": 0.01, \u002F\u002F send \"x\" as a float instead of int\n})\n\n\u002F\u002F Send a number instead of an object\ncustom := param.Override[openai.FooParams](12)\n```\n\n### Request unions\n\nUnions are represented as a struct with fields prefixed by \"Of\" for each of its variants,\nonly one field can be non-zero. The non-zero field will be serialized.\n\nSub-properties of the union can be accessed via methods on the union struct.\nThese methods return a mutable pointer to the underlying data, if present.\n\n```go\n\u002F\u002F Only one field can be non-zero, use param.IsOmitted() to check if a field is set\ntype AnimalUnionParam struct {\n\tOfCat *Cat `json:\",omitzero,inline`\n\tOfDog *Dog `json:\",omitzero,inline`\n}\n\nanimal := AnimalUnionParam{\n\tOfCat: &Cat{\n\t\tName: \"Whiskers\",\n\t\tOwner: PersonParam{\n\t\t\tAddress: AddressParam{Street: \"3333 Coyote Hill Rd\", Zip: 0},\n\t\t},\n\t},\n}\n\n\u002F\u002F Mutating a field\nif address := animal.GetOwner().GetAddress(); address != nil {\n\taddress.ZipCode = 94304\n}\n```\n\n### Response objects\n\nAll fields in response structs are ordinary value types (not pointers or wrappers).\nResponse structs also include a special `JSON` field containing metadata about\neach property.\n\n```go\ntype Animal struct {\n\tName   string `json:\"name,nullable\"`\n\tOwners int    `json:\"owners\"`\n\tAge    int    `json:\"age\"`\n\tJSON   struct {\n\t\tName        respjson.Field\n\t\tOwner       respjson.Field\n\t\tAge         respjson.Field\n\t\tExtraFields map[string]respjson.Field\n\t} `json:\"-\"`\n}\n```\n\nTo handle optional data, use the `.Valid()` method on the JSON field.\n`.Valid()` returns true if a field is not `null`, not present, or couldn't be marshaled.\n\nIf `.Valid()` is false, the corresponding field will simply be its zero value.\n\n```go\nraw := `{\"owners\": 1, \"name\": null}`\n\nvar res Animal\njson.Unmarshal([]byte(raw), &res)\n\n\u002F\u002F Accessing regular fields\n\nres.Owners \u002F\u002F 1\nres.Name   \u002F\u002F \"\"\nres.Age    \u002F\u002F 0\n\n\u002F\u002F Optional field checks\n\nres.JSON.Owners.Valid() \u002F\u002F true\nres.JSON.Name.Valid()   \u002F\u002F false\nres.JSON.Age.Valid()    \u002F\u002F false\n\n\u002F\u002F Raw JSON values\n\nres.JSON.Owners.Raw()                  \u002F\u002F \"1\"\nres.JSON.Name.Raw() == \"null\"          \u002F\u002F true\nres.JSON.Name.Raw() == respjson.Null   \u002F\u002F true\nres.JSON.Age.Raw() == \"\"               \u002F\u002F true\nres.JSON.Age.Raw() == respjson.Omitted \u002F\u002F true\n```\n\nThese `.JSON` structs also include an `ExtraFields` map containing\nany properties in the json response that were not specified\nin the struct. This can be useful for API features not yet\npresent in the SDK.\n\n```go\nbody := res.JSON.ExtraFields[\"my_unexpected_field\"].Raw()\n```\n\n### Response Unions\n\nIn responses, unions are represented by a flattened struct containing all possible fields from each of the\nobject variants.\nTo convert it to a variant use the `.AsFooVariant()` method or the `.AsAny()` method if present.\n\nIf a response value union contains primitive values, primitive fields will be alongside\nthe properties but prefixed with `Of` and feature the tag `json:\"...,inline\"`.\n\n```go\ntype AnimalUnion struct {\n\t\u002F\u002F From variants [Dog], [Cat]\n\tOwner Person `json:\"owner\"`\n\t\u002F\u002F From variant [Dog]\n\tDogBreed string `json:\"dog_breed\"`\n\t\u002F\u002F From variant [Cat]\n\tCatBreed string `json:\"cat_breed\"`\n\t\u002F\u002F ...\n\n\tJSON struct {\n\t\tOwner respjson.Field\n\t\t\u002F\u002F ...\n\t} `json:\"-\"`\n}\n\n\u002F\u002F If animal variant\nif animal.Owner.Address.ZipCode == \"\" {\n\tpanic(\"missing zip code\")\n}\n\n\u002F\u002F Switch on the variant\nswitch variant := animal.AsAny().(type) {\ncase Dog:\ncase Cat:\ndefault:\n\tpanic(\"unexpected type\")\n}\n```\n\n### RequestOptions\n\nThis library uses the functional options pattern. Functions defined in the\n`option` package return a `RequestOption`, which is a closure that mutates a\n`RequestConfig`. These options can be supplied to the client or at individual\nrequests. For example:\n\n```go\nclient := openai.NewClient(\n\t\u002F\u002F Adds a header to every request made by the client\n\toption.WithHeader(\"X-Some-Header\", \"custom_header_info\"),\n)\n\nclient.Responses.New(context.TODO(), responses.ResponseNewParams{...},\n\t\u002F\u002F Override the header\n\toption.WithHeader(\"X-Some-Header\", \"some_other_custom_header_info\"),\n\t\u002F\u002F Add an undocumented field to the request body, using sjson syntax\n\toption.WithJSONSet(\"some.json.path\", map[string]string{\"my\": \"object\"}),\n)\n```\n\nThe request option `option.WithDebugLog(nil)` may be helpful while debugging.\n\nSee the [full list of request options](https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fopenai\u002Fopenai-go\u002Foption).\n\n### Pagination\n\nThis library provides some conveniences for working with paginated list endpoints.\n\nYou can use `.ListAutoPaging()` methods to iterate through items across all pages:\n\n```go\niter := client.FineTuning.Jobs.ListAutoPaging(context.TODO(), openai.FineTuningJobListParams{\n\tLimit: openai.Int(20),\n})\n\u002F\u002F Automatically fetches more pages as needed.\nfor iter.Next() {\n\tfineTuningJob := iter.Current()\n\tfmt.Printf(\"%+v\\n\", fineTuningJob)\n}\nif err := iter.Err(); err != nil {\n\tpanic(err.Error())\n}\n```\n\nOr you can use simple `.List()` methods to fetch a single page and receive a standard response object\nwith additional helper methods like `.GetNextPage()`, e.g.:\n\n```go\npage, err := client.FineTuning.Jobs.List(context.TODO(), openai.FineTuningJobListParams{\n\tLimit: openai.Int(20),\n})\nfor page != nil {\n\tfor _, job := range page.Data {\n\t\tfmt.Printf(\"%+v\\n\", job)\n\t}\n\tpage, err = page.GetNextPage()\n}\nif err != nil {\n\tpanic(err.Error())\n}\n```\n\n### Errors\n\nWhen the API returns a non-success status code, we return an error with type\n`*openai.Error`. This contains the `StatusCode`, `*http.Request`, and\n`*http.Response` values of the request, as well as the JSON of the error body\n(much like other response objects in the SDK).\n\nTo handle errors, we recommend that you use the `errors.As` pattern:\n\n```go\n_, err := client.FineTuning.Jobs.New(context.TODO(), openai.FineTuningJobNewParams{\n\tModel:        openai.FineTuningJobNewParamsModel(\"gpt-4o\"),\n\tTrainingFile: \"file-abc123\",\n})\nif err != nil {\n\tvar apierr *openai.Error\n\tif errors.As(err, &apierr) {\n\t\tprintln(string(apierr.DumpRequest(true)))  \u002F\u002F Prints the serialized HTTP request\n\t\tprintln(string(apierr.DumpResponse(true))) \u002F\u002F Prints the serialized HTTP response\n\t}\n\tpanic(err.Error()) \u002F\u002F GET \"\u002Ffine_tuning\u002Fjobs\": 400 Bad Request { ... }\n}\n```\n\nWhen other errors occur, they are returned unwrapped; for example,\nif HTTP transport fails, you might receive `*url.Error` wrapping `*net.OpError`.\n\n### Timeouts\n\nRequests do not time out by default; use context to configure a timeout for a request lifecycle.\n\nNote that if a request is [retried](#retries), the context timeout does not start over.\nTo set a per-retry timeout, use `option.WithRequestTimeout()`.\n\n```go\n\u002F\u002F This sets the timeout for the request, including all the retries.\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)\ndefer cancel()\nclient.Responses.New(\n\tctx,\n\tresponses.ResponseNewParams{\n\t\tModel: openai.ChatModelGPT5_2,\n\t\tInput: responses.ResponseNewParamsInputUnion{\n\t\t\tOfString: openai.String(\"How can I list all files in a directory using Python?\"),\n\t\t},\n\t},\n\t\u002F\u002F This sets the per-retry timeout\n\toption.WithRequestTimeout(20*time.Second),\n)\n```\n\n### File uploads\n\nRequest parameters that correspond to file uploads in multipart requests are typed as\n`io.Reader`. The contents of the `io.Reader` will by default be sent as a multipart form\npart with the file name of \"anonymous_file\" and content-type of \"application\u002Foctet-stream\".\n\nThe file name and content-type can be customized by implementing `Name() string` or `ContentType()\nstring` on the run-time type of `io.Reader`. Note that `os.File` implements `Name() string`, so a\nfile returned by `os.Open` will be sent with the file name on disk.\n\nWe also provide a helper `openai.File(reader io.Reader, filename string, contentType string)`\nwhich can be used to wrap any `io.Reader` with the appropriate file name and content type.\n\n```go\n\u002F\u002F A file from the file system\nfile, err := os.Open(\"input.jsonl\")\nopenai.FileNewParams{\n\tFile:    file,\n\tPurpose: openai.FilePurposeFineTune,\n}\n\n\u002F\u002F A file from a string\nopenai.FileNewParams{\n\tFile:    strings.NewReader(\"my file contents\"),\n\tPurpose: openai.FilePurposeFineTune,\n}\n\n\u002F\u002F With a custom filename and contentType\nopenai.FileNewParams{\n\tFile:    openai.File(strings.NewReader(`{\"hello\": \"foo\"}`), \"file.go\", \"application\u002Fjson\"),\n\tPurpose: openai.FilePurposeFineTune,\n}\n```\n\n## Webhook Verification\n\nVerifying webhook signatures is _optional but encouraged_.\n\nFor more information about webhooks, see [the API docs](https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fguides\u002Fwebhooks).\n\n### Parsing webhook payloads\n\nFor most use cases, you will likely want to verify the webhook and parse the payload at the same time. To achieve this, we provide the method `client.Webhooks.Unwrap()`, which parses a webhook request and verifies that it was sent by OpenAI. This method will return an error if the signature is invalid.\n\nNote that the `body` parameter should be the raw JSON bytes sent from the server (do not parse it first). The `Unwrap()` method will parse this JSON for you into an event object after verifying the webhook was sent from OpenAI.\n\n```go\npackage main\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"net\u002Fhttp\"\n\t\"os\"\n\n\t\"github.com\u002Fgin-gonic\u002Fgin\"\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\"\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\u002Foption\"\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\u002Fwebhooks\"\n)\n\nfunc main() {\n\tclient := openai.NewClient(\n\t\toption.WithWebhookSecret(os.Getenv(\"OPENAI_WEBHOOK_SECRET\")), \u002F\u002F env var used by default; explicit here.\n\t)\n\n\tr := gin.Default()\n\n\tr.POST(\"\u002Fwebhook\", func(c *gin.Context) {\n\t\tbody, err := io.ReadAll(c.Request.Body)\n\t\tif err != nil {\n\t\t\tc.JSON(http.StatusInternalServerError, gin.H{\"error\": \"Error reading request body\"})\n\t\t\treturn\n\t\t}\n\t\tdefer c.Request.Body.Close()\n\n\t\twebhookEvent, err := client.Webhooks.Unwrap(body, c.Request.Header)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Invalid webhook signature: %v\", err)\n\t\t\tc.JSON(http.StatusBadRequest, gin.H{\"error\": \"invalid signature\"})\n\t\t\treturn\n\t\t}\n\n\t\tswitch event := webhookEvent.AsAny().(type) {\n\t\tcase webhooks.ResponseCompletedWebhookEvent:\n\t\t\tlog.Printf(\"Response completed: %+v\", event.Data)\n\t\tcase webhooks.ResponseFailedWebhookEvent:\n\t\t\tlog.Printf(\"Response failed: %+v\", event.Data)\n\t\tdefault:\n\t\t\tlog.Printf(\"Unhandled event type: %T\", event)\n\t\t}\n\n\t\tc.JSON(http.StatusOK, gin.H{\"message\": \"ok\"})\n\t})\n\n\tr.Run(\":8000\")\n}\n```\n\n### Verifying webhook payloads directly\n\nIn some cases, you may want to verify the webhook separately from parsing the payload. If you prefer to handle these steps separately, we provide the method `client.Webhooks.VerifySignature()` to _only verify_ the signature of a webhook request. Like `Unwrap()`, this method will return an error if the signature is invalid.\n\nNote that the `body` parameter should be the raw JSON bytes sent from the server (do not parse it first). You will then need to parse the body after verifying the signature.\n\n```go\npackage main\n\nimport (\n\t\"encoding\u002Fjson\"\n\t\"io\"\n\t\"log\"\n\t\"net\u002Fhttp\"\n\t\"os\"\n\n\t\"github.com\u002Fgin-gonic\u002Fgin\"\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\"\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\u002Foption\"\n)\n\nfunc main() {\n\tclient := openai.NewClient(\n\t\toption.WithWebhookSecret(os.Getenv(\"OPENAI_WEBHOOK_SECRET\")), \u002F\u002F env var used by default; explicit here.\n\t)\n\n\tr := gin.Default()\n\n\tr.POST(\"\u002Fwebhook\", func(c *gin.Context) {\n\t\tbody, err := io.ReadAll(c.Request.Body)\n\t\tif err != nil {\n\t\t\tc.JSON(http.StatusInternalServerError, gin.H{\"error\": \"Error reading request body\"})\n\t\t\treturn\n\t\t}\n\t\tdefer c.Request.Body.Close()\n\n\t\terr = client.Webhooks.VerifySignature(body, c.Request.Header)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Invalid webhook signature: %v\", err)\n\t\t\tc.JSON(http.StatusBadRequest, gin.H{\"error\": \"invalid signature\"})\n\t\t\treturn\n\t\t}\n\n\t\tc.JSON(http.StatusOK, gin.H{\"message\": \"ok\"})\n\t})\n\n\tr.Run(\":8000\")\n}\n```\n\n### Retries\n\nCertain errors will be automatically retried 2 times by default, with a short exponential backoff.\nWe retry by default all connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit,\nand >=500 Internal errors.\n\nYou can use the `WithMaxRetries` option to configure or disable this:\n\n```go\n\u002F\u002F Configure the default for all requests:\nclient := openai.NewClient(\n\toption.WithMaxRetries(0), \u002F\u002F default is 2\n)\n\n\u002F\u002F Override per-request:\nclient.Responses.New(\n\tcontext.TODO(),\n\tresponses.ResponseNewParams{\n\t\tModel: openai.ChatModelGPT5_2,\n\t\tInput: responses.ResponseNewParamsInputUnion{\n\t\t\tOfString: openai.String(\"How can I get the name of the current day in JavaScript?\"),\n\t\t},\n\t},\n\toption.WithMaxRetries(5),\n)\n```\n\n### Accessing raw response data (e.g. response headers)\n\nYou can access the raw HTTP response data by using the `option.WithResponseInto()` request option. This is useful when\nyou need to examine response headers, status codes, or other details.\n\n```go\n\u002F\u002F Create a variable to store the HTTP response\nvar httpResp *http.Response\nresponse, err := client.Responses.New(\n\tcontext.TODO(),\n\tresponses.ResponseNewParams{\n\t\tModel: openai.ChatModelGPT5_2,\n\t\tInput: responses.ResponseNewParamsInputUnion{\n\t\t\tOfString: openai.String(\"Say this is a test\"),\n\t\t},\n\t},\n\toption.WithResponseInto(&httpResp),\n)\nif err != nil {\n\t\u002F\u002F handle error\n}\nfmt.Printf(\"%+v\\n\", response)\n\nfmt.Printf(\"Status Code: %d\\n\", httpResp.StatusCode)\nfmt.Printf(\"Headers: %+#v\\n\", httpResp.Header)\n```\n\n### Making custom\u002Fundocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.Get`, `client.Post`, and other HTTP verbs.\n`RequestOptions` on the client, such as retries, will be respected when making these requests.\n\n```go\nvar (\n    \u002F\u002F params can be an io.Reader, a []byte, an encoding\u002Fjson serializable object,\n    \u002F\u002F or a \"…Params\" struct defined in this library.\n    params map[string]any\n\n    \u002F\u002F result can be an []byte, *http.Response, a encoding\u002Fjson deserializable object,\n    \u002F\u002F or a model defined in this library.\n    result *http.Response\n)\nerr := client.Post(context.Background(), \"\u002Funspecified\", params, &result)\nif err != nil {\n    …\n}\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use either the `option.WithQuerySet()`\nor the `option.WithJSONSet()` methods.\n\n```go\nparams := FooNewParams{\n    ID:   \"id_xxxx\",\n    Data: FooNewParamsData{\n        FirstName: openai.String(\"John\"),\n    },\n}\nclient.Foo.New(context.Background(), params, option.WithJSONSet(\"data.last_name\", \"Doe\"))\n```\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may either access the raw JSON of the response as a string\nwith `result.JSON.RawJSON()`, or get the raw JSON of a particular field on the result with\n`result.JSON.Foo.Raw()`.\n\nAny fields that are not present on the response struct will be saved and can be accessed by `result.JSON.ExtraFields()` which returns the extra fields as a `map[string]Field`.\n\n### Middleware\n\nWe provide `option.WithMiddleware` which applies the given\nmiddleware to requests.\n\n```go\nfunc Logger(req *http.Request, next option.MiddlewareNext) (res *http.Response, err error) {\n\t\u002F\u002F Before the request\n\tstart := time.Now()\n\tLogReq(req)\n\n\t\u002F\u002F Forward the request to the next handler\n\tres, err = next(req)\n\n\t\u002F\u002F Handle stuff after the request\n\tend := time.Now()\n\tLogRes(res, err, start - end)\n\n    return res, err\n}\n\nclient := openai.NewClient(\n\toption.WithMiddleware(Logger),\n)\n```\n\nWhen multiple middlewares are provided as variadic arguments, the middlewares\nare applied left to right. If `option.WithMiddleware` is given\nmultiple times, for example first in the client then the method, the\nmiddleware in the client will run first and the middleware given in the method\nwill run next.\n\nYou may also replace the default `http.Client` with\n`option.WithHTTPClient(client)`. Only one http client is\naccepted (this overwrites any previous client) and receives requests after any\nmiddleware has been applied.\n\n## Workload Identity Authentication\n\nFor cloud workloads (Kubernetes, Azure, Google Cloud Platform), you can use workload identity authentication instead of API keys. This provides short-lived tokens that are automatically refreshed.\n\n### Kubernetes\n\n```go\nimport (\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\"\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\u002Fauth\"\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\u002Foption\"\n)\n\nclient := openai.NewClient(\n\toption.WithWorkloadIdentity(auth.WorkloadIdentity{\n\t\tIdentityProviderID: \"idp-123\",\n\t\tServiceAccountID:   \"sa-456\",\n\t\tProvider:           auth.K8sServiceAccountTokenProvider(\"\"),\n\t}),\n)\n```\n\n### Azure Managed Identity\n\n```go\nclient := openai.NewClient(\n\toption.WithWorkloadIdentity(auth.WorkloadIdentity{\n\t\tIdentityProviderID: \"idp-123\",\n\t\tServiceAccountID:   \"sa-456\",\n\t\tProvider:           auth.AzureManagedIdentityTokenProvider(nil),\n\t}),\n)\n```\n\n### Google Cloud Compute Engine\n\n```go\nclient := openai.NewClient(\n\toption.WithWorkloadIdentity(auth.WorkloadIdentity{\n\t\tIdentityProviderID: \"idp-123\",\n\t\tServiceAccountID:   \"sa-456\",\n\t\tProvider:           auth.GCPIDTokenProvider(nil),\n\t}),\n)\n```\n\n### Custom Subject Token Provider\n\nYou can implement your own subject token provider:\n\n```go\nimport (\n\t\"context\"\n\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\"\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\u002Fauth\"\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\u002Foption\"\n)\n\ntype customTokenProvider struct{}\n\nfunc (p *customTokenProvider) TokenType() auth.SubjectTokenType {\n\treturn auth.SubjectTokenTypeJWT\n}\n\nfunc (p *customTokenProvider) GetToken(ctx context.Context, httpClient auth.HTTPDoer) (string, error) {\n\treturn \"your-token\", nil\n}\n\nclient := openai.NewClient(\n\toption.WithWorkloadIdentity(auth.WorkloadIdentity{\n\t\tIdentityProviderID: \"idp-123\",\n\t\tServiceAccountID:   \"sa-456\",\n\t\tProvider:           &customTokenProvider{},\n\t}),\n)\n```\n\n### Customizing Refresh Buffer\n\nBy default, tokens are refreshed 20 minutes (1200 seconds) before expiry. You can customize this:\n\n```go\nclient := openai.NewClient(\n\toption.WithWorkloadIdentity(auth.WorkloadIdentity{\n\t\tIdentityProviderID:   \"idp-123\",\n\t\tServiceAccountID:     \"sa-456\",\n\t\tProvider:             auth.K8sServiceAccountTokenProvider(\"\"),\n\t\tRefreshBufferSeconds: 600,\n\t}),\n)\n```\n\n## Microsoft Azure OpenAI\n\nTo use this library with [Azure OpenAI]https:\u002F\u002Flearn.microsoft.com\u002Fazure\u002Fai-services\u002Fopenai\u002Foverview),\nuse the option.RequestOption functions in the `azure` package.\n\n```go\npackage main\n\nimport (\n\t\"github.com\u002FAzure\u002Fazure-sdk-for-go\u002Fsdk\u002Fazidentity\"\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\"\n\t\"github.com\u002Fopenai\u002Fopenai-go\u002Fv3\u002Fazure\"\n)\n\nfunc main() {\n\tconst azureOpenAIEndpoint = \"https:\u002F\u002F\u003Cazure-openai-resource>.openai.azure.com\"\n\n\t\u002F\u002F The latest API versions, including previews, can be found here:\n\t\u002F\u002F https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fai-services\u002Fopenai\u002Freference#rest-api-versionng\n\tconst azureOpenAIAPIVersion = \"2024-06-01\"\n\n\ttokenCredential, err := azidentity.NewDefaultAzureCredential(nil)\n\n\tif err != nil {\n\t\tfmt.Printf(\"Failed to create the DefaultAzureCredential: %s\", err)\n\t\tos.Exit(1)\n\t}\n\n\tclient := openai.NewClient(\n\t\tazure.WithEndpoint(azureOpenAIEndpoint, azureOpenAIAPIVersion),\n\n\t\t\u002F\u002F Choose between authenticating using a TokenCredential or an API Key\n\t\tazure.WithTokenCredential(tokenCredential),\n\t\t\u002F\u002F or azure.WithAPIKey(azureOpenAIAPIKey),\n\t)\n}\n```\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https:\u002F\u002Fsemver.org\u002Fspec\u002Fv2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https:\u002F\u002Fwww.github.com\u002Fopenai\u002Fopenai-go\u002Fissues) with questions, bugs, or suggestions.\n\n## Contributing\n\nSee [the contributing documentation](.\u002FCONTRIBUTING.md).\n","openai-go 是官方提供的用于访问 OpenAI API 的 Go 语言库。它允许开发者通过简单的 Go 代码调用 OpenAI 的各种模型，如生成文本、多轮对话等，支持最新的 GPT 系列模型。该库具有良好的封装性，使得用户可以轻松地集成到现有的 Go 项目中，并且提供了详细的文档和示例代码来帮助快速上手。适用于需要在后端服务或其他 Go 应用程序中利用 AI 功能的场景，例如构建聊天机器人、内容生成工具或进行自然语言处理任务。",2,"2026-06-11 03:44:41","high_star"]