[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"tool-sashabaranov--go-openai":3,"similar-sashabaranov--go-openai":197},{"id":4,"github_repo":5,"name":6,"description_en":7,"description_zh":8,"ai_summary_zh":9,"readme_en":10,"readme_zh":11,"quickstart_zh":12,"use_case_zh":13,"hero_image_url":14,"owner_login":15,"owner_name":16,"owner_avatar_url":17,"owner_bio":18,"owner_company":19,"owner_location":20,"owner_email":21,"owner_twitter":21,"owner_website":21,"owner_url":22,"languages":23,"stars":28,"forks":29,"last_commit_at":30,"license":31,"difficulty_score":32,"env_os":33,"env_gpu":34,"env_ram":34,"env_deps":35,"category_tags":40,"github_topics":44,"view_count":56,"oss_zip_url":21,"oss_zip_packed_at":21,"status":57,"created_at":58,"updated_at":59,"faqs":60,"releases":96},7649,"sashabaranov\u002Fgo-openai","go-openai","OpenAI ChatGPT, GPT-5, GPT-Image-1, Whisper API clients for Go","go-openai 是一款专为 Go 语言开发者打造的非官方 OpenAI API 客户端库。它旨在简化 Go 应用与 OpenAI 强大人工智能模型的集成过程，让开发者无需从零构建复杂的 HTTP 请求和响应解析逻辑，即可轻松调用各类前沿 AI 能力。\n\n该工具全面支持 ChatGPT（包括 GPT-4o、o1 等最新模型）、GPT-3.5\u002F4、DALL·E 2\u002F3、GPT Image 1 以及 Whisper 语音识别等核心接口。无论是需要实现智能对话机器人、生成创意图像，还是进行语音转文字处理，go-openai 都能提供稳定且类型安全的代码支持。其独特的技术亮点在于对流式输出（Streaming）的完善支持，允许应用实时接收并展示模型生成的内容，显著提升用户交互体验；同时，它紧跟 Go 语言特性，要求 Go 1.18 及以上版本，确保了代码的现代性与执行效率。\n\ngo-openai 非常适合熟悉或正在使用 Go 语言的软件工程师、后端开发人员以及 AI 应用研究者。如果你希望在 Go 项目中快速接入 OpenAI 生态，构建高效、可靠的智能应用，这款轻量级且社区活跃的库将是你的","go-openai 是一款专为 Go 语言开发者打造的非官方 OpenAI API 客户端库。它旨在简化 Go 应用与 OpenAI 强大人工智能模型的集成过程，让开发者无需从零构建复杂的 HTTP 请求和响应解析逻辑，即可轻松调用各类前沿 AI 能力。\n\n该工具全面支持 ChatGPT（包括 GPT-4o、o1 等最新模型）、GPT-3.5\u002F4、DALL·E 2\u002F3、GPT Image 1 以及 Whisper 语音识别等核心接口。无论是需要实现智能对话机器人、生成创意图像，还是进行语音转文字处理，go-openai 都能提供稳定且类型安全的代码支持。其独特的技术亮点在于对流式输出（Streaming）的完善支持，允许应用实时接收并展示模型生成的内容，显著提升用户交互体验；同时，它紧跟 Go 语言特性，要求 Go 1.18 及以上版本，确保了代码的现代性与执行效率。\n\ngo-openai 非常适合熟悉或正在使用 Go 语言的软件工程师、后端开发人员以及 AI 应用研究者。如果你希望在 Go 项目中快速接入 OpenAI 生态，构建高效、可靠的智能应用，这款轻量级且社区活跃的库将是你的理想选择。通过简单的安装和直观的 API 设计，它能帮助你专注于业务逻辑创新，而非底层通信细节。","# Go OpenAI\n[![Go Reference](https:\u002F\u002Fpkg.go.dev\u002Fbadge\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai.svg)](https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai)\n[![Go Report Card](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fsashabaranov_go-openai_readme_2b4a70945b89.png)](https:\u002F\u002Fgoreportcard.com\u002Freport\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai)\n[![codecov](https:\u002F\u002Fcodecov.io\u002Fgh\u002Fsashabaranov\u002Fgo-openai\u002Fbranch\u002Fmaster\u002Fgraph\u002Fbadge.svg?token=bCbIfHLIsW)](https:\u002F\u002Fcodecov.io\u002Fgh\u002Fsashabaranov\u002Fgo-openai)\n\nThis library provides unofficial Go clients for [OpenAI API](https:\u002F\u002Fplatform.openai.com\u002F). We support: \n\n* ChatGPT 4o, o1\n* GPT-3, GPT-4\n* DALL·E 2, DALL·E 3, GPT Image 1\n* Whisper\n\n## Installation\n\n```\ngo get github.com\u002Fsashabaranov\u002Fgo-openai\n```\nCurrently, go-openai requires Go version 1.18 or greater.\n\n\n## Usage\n\n### ChatGPT example usage:\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tclient := openai.NewClient(\"your token\")\n\tresp, err := client.CreateChatCompletion(\n\t\tcontext.Background(),\n\t\topenai.ChatCompletionRequest{\n\t\t\tModel: openai.GPT3Dot5Turbo,\n\t\t\tMessages: []openai.ChatCompletionMessage{\n\t\t\t\t{\n\t\t\t\t\tRole:    openai.ChatMessageRoleUser,\n\t\t\t\t\tContent: \"Hello!\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t)\n\n\tif err != nil {\n\t\tfmt.Printf(\"ChatCompletion error: %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Println(resp.Choices[0].Message.Content)\n}\n\n```\n\n### Getting an OpenAI API Key:\n\n1. Visit the OpenAI website at [https:\u002F\u002Fplatform.openai.com\u002Faccount\u002Fapi-keys](https:\u002F\u002Fplatform.openai.com\u002Faccount\u002Fapi-keys).\n2. If you don't have an account, click on \"Sign Up\" to create one. If you do, click \"Log In\".\n3. Once logged in, navigate to your API key management page.\n4. Click on \"Create new secret key\".\n5. Enter a name for your new key, then click \"Create secret key\".\n6. Your new API key will be displayed. Use this key to interact with the OpenAI API.\n\n**Note:** Your API key is sensitive information. Do not share it with anyone.\n\n### Other examples:\n\n\u003Cdetails>\n\u003Csummary>ChatGPT streaming completion\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tc := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\treq := openai.ChatCompletionRequest{\n\t\tModel:     openai.GPT3Dot5Turbo,\n\t\tMaxTokens: 20,\n\t\tMessages: []openai.ChatCompletionMessage{\n\t\t\t{\n\t\t\t\tRole:    openai.ChatMessageRoleUser,\n\t\t\t\tContent: \"Lorem ipsum\",\n\t\t\t},\n\t\t},\n\t\tStream: true,\n\t}\n\tstream, err := c.CreateChatCompletionStream(ctx, req)\n\tif err != nil {\n\t\tfmt.Printf(\"ChatCompletionStream error: %v\\n\", err)\n\t\treturn\n\t}\n\tdefer stream.Close()\n\n\tfmt.Printf(\"Stream response: \")\n\tfor {\n\t\tresponse, err := stream.Recv()\n\t\tif errors.Is(err, io.EOF) {\n\t\t\tfmt.Println(\"\\nStream finished\")\n\t\t\treturn\n\t\t}\n\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"\\nStream error: %v\\n\", err)\n\t\t\treturn\n\t\t}\n\n\t\tfmt.Printf(response.Choices[0].Delta.Content)\n\t}\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>GPT-3 completion\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tc := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\treq := openai.CompletionRequest{\n\t\tModel:     openai.GPT3Babbage002,\n\t\tMaxTokens: 5,\n\t\tPrompt:    \"Lorem ipsum\",\n\t}\n\tresp, err := c.CreateCompletion(ctx, req)\n\tif err != nil {\n\t\tfmt.Printf(\"Completion error: %v\\n\", err)\n\t\treturn\n\t}\n\tfmt.Println(resp.Choices[0].Text)\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>GPT-3 streaming completion\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"errors\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tc := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\treq := openai.CompletionRequest{\n\t\tModel:     openai.GPT3Babbage002,\n\t\tMaxTokens: 5,\n\t\tPrompt:    \"Lorem ipsum\",\n\t\tStream:    true,\n\t}\n\tstream, err := c.CreateCompletionStream(ctx, req)\n\tif err != nil {\n\t\tfmt.Printf(\"CompletionStream error: %v\\n\", err)\n\t\treturn\n\t}\n\tdefer stream.Close()\n\n\tfor {\n\t\tresponse, err := stream.Recv()\n\t\tif errors.Is(err, io.EOF) {\n\t\t\tfmt.Println(\"Stream finished\")\n\t\t\treturn\n\t\t}\n\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"Stream error: %v\\n\", err)\n\t\t\treturn\n\t\t}\n\n\n\t\tfmt.Printf(\"Stream response: %v\\n\", response)\n\t}\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Audio Speech-To-Text\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tc := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\treq := openai.AudioRequest{\n\t\tModel:    openai.Whisper1,\n\t\tFilePath: \"recording.mp3\",\n\t}\n\tresp, err := c.CreateTranscription(ctx, req)\n\tif err != nil {\n\t\tfmt.Printf(\"Transcription error: %v\\n\", err)\n\t\treturn\n\t}\n\tfmt.Println(resp.Text)\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Audio Captions\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tc := openai.NewClient(os.Getenv(\"OPENAI_KEY\"))\n\n\treq := openai.AudioRequest{\n\t\tModel:    openai.Whisper1,\n\t\tFilePath: os.Args[1],\n\t\tFormat:   openai.AudioResponseFormatSRT,\n\t}\n\tresp, err := c.CreateTranscription(context.Background(), req)\n\tif err != nil {\n\t\tfmt.Printf(\"Transcription error: %v\\n\", err)\n\t\treturn\n\t}\n\tf, err := os.Create(os.Args[1] + \".srt\")\n\tif err != nil {\n\t\tfmt.Printf(\"Could not open file: %v\\n\", err)\n\t\treturn\n\t}\n\tdefer f.Close()\n\tif _, err := f.WriteString(resp.Text); err != nil {\n\t\tfmt.Printf(\"Error writing to file: %v\\n\", err)\n\t\treturn\n\t}\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>DALL-E 2 image generation\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding\u002Fbase64\"\n\t\"fmt\"\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n\t\"image\u002Fpng\"\n\t\"os\"\n)\n\nfunc main() {\n\tc := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\t\u002F\u002F Sample image by link\n\treqUrl := openai.ImageRequest{\n\t\tPrompt:         \"Parrot on a skateboard performs a trick, cartoon style, natural light, high detail\",\n\t\tSize:           openai.CreateImageSize256x256,\n\t\tResponseFormat: openai.CreateImageResponseFormatURL,\n\t\tN:              1,\n\t}\n\n\trespUrl, err := c.CreateImage(ctx, reqUrl)\n\tif err != nil {\n\t\tfmt.Printf(\"Image creation error: %v\\n\", err)\n\t\treturn\n\t}\n\tfmt.Println(respUrl.Data[0].URL)\n\n\t\u002F\u002F Example image as base64\n\treqBase64 := openai.ImageRequest{\n\t\tPrompt:         \"Portrait of a humanoid parrot in a classic costume, high detail, realistic light, unreal engine\",\n\t\tSize:           openai.CreateImageSize256x256,\n\t\tResponseFormat: openai.CreateImageResponseFormatB64JSON,\n\t\tN:              1,\n\t}\n\n\trespBase64, err := c.CreateImage(ctx, reqBase64)\n\tif err != nil {\n\t\tfmt.Printf(\"Image creation error: %v\\n\", err)\n\t\treturn\n\t}\n\n\timgBytes, err := base64.StdEncoding.DecodeString(respBase64.Data[0].B64JSON)\n\tif err != nil {\n\t\tfmt.Printf(\"Base64 decode error: %v\\n\", err)\n\t\treturn\n\t}\n\n\tr := bytes.NewReader(imgBytes)\n\timgData, err := png.Decode(r)\n\tif err != nil {\n\t\tfmt.Printf(\"PNG decode error: %v\\n\", err)\n\t\treturn\n\t}\n\n\tfile, err := os.Create(\"example.png\")\n\tif err != nil {\n\t\tfmt.Printf(\"File creation error: %v\\n\", err)\n\t\treturn\n\t}\n\tdefer file.Close()\n\n\tif err := png.Encode(file, imgData); err != nil {\n\t\tfmt.Printf(\"PNG encode error: %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Println(\"The image was saved as example.png\")\n}\n\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>GPT Image 1 image generation\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"encoding\u002Fbase64\"\n\t\"fmt\"\n\t\"os\"\n\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tc := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\treq := openai.ImageRequest{\n\t\tPrompt:            \"Parrot on a skateboard performing a trick. Large bold text \\\"SKATE MASTER\\\" banner at the bottom of the image. Cartoon style, natural light, high detail, 1:1 aspect ratio.\",\n\t\tBackground:        openai.CreateImageBackgroundOpaque,\n\t\tModel:             openai.CreateImageModelGptImage1,\n\t\tSize:              openai.CreateImageSize1024x1024,\n\t\tN:                 1,\n\t\tQuality:           openai.CreateImageQualityLow,\n\t\tOutputCompression: 100,\n\t\tOutputFormat:      openai.CreateImageOutputFormatJPEG,\n\t\t\u002F\u002F Moderation: \t\t openai.CreateImageModerationLow,\n\t\t\u002F\u002F User: \t\t\t\t\t \"\",\n\t}\n\n\tresp, err := c.CreateImage(ctx, req)\n\tif err != nil {\n\t\tfmt.Printf(\"Image creation Image generation with GPT Image 1error: %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Println(\"Image Base64:\", resp.Data[0].B64JSON)\n\n\t\u002F\u002F Decode the base64 data\n\timgBytes, err := base64.StdEncoding.DecodeString(resp.Data[0].B64JSON)\n\tif err != nil {\n\t\tfmt.Printf(\"Base64 decode error: %v\\n\", err)\n\t\treturn\n\t}\n\n\t\u002F\u002F Write image to file\n\toutputPath := \"generated_image.jpg\"\n\terr = os.WriteFile(outputPath, imgBytes, 0644)\n\tif err != nil {\n\t\tfmt.Printf(\"Failed to write image file: %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"The image was saved as %s\\n\", outputPath)\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Configuring proxy\u003C\u002Fsummary>\n\n```go\nconfig := openai.DefaultConfig(\"token\")\nproxyUrl, err := url.Parse(\"http:\u002F\u002Flocalhost:{port}\")\nif err != nil {\n\tpanic(err)\n}\ntransport := &http.Transport{\n\tProxy: http.ProxyURL(proxyUrl),\n}\nconfig.HTTPClient = &http.Client{\n\tTransport: transport,\n}\n\nc := openai.NewClientWithConfig(config)\n```\n\nSee also: https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai#ClientConfig\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>ChatGPT support context\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tclient := openai.NewClient(\"your token\")\n\tmessages := make([]openai.ChatCompletionMessage, 0)\n\treader := bufio.NewReader(os.Stdin)\n\tfmt.Println(\"Conversation\")\n\tfmt.Println(\"---------------------\")\n\n\tfor {\n\t\tfmt.Print(\"-> \")\n\t\ttext, _ := reader.ReadString('\\n')\n\t\t\u002F\u002F convert CRLF to LF\n\t\ttext = strings.Replace(text, \"\\n\", \"\", -1)\n\t\tmessages = append(messages, openai.ChatCompletionMessage{\n\t\t\tRole:    openai.ChatMessageRoleUser,\n\t\t\tContent: text,\n\t\t})\n\n\t\tresp, err := client.CreateChatCompletion(\n\t\t\tcontext.Background(),\n\t\t\topenai.ChatCompletionRequest{\n\t\t\t\tModel:    openai.GPT3Dot5Turbo,\n\t\t\t\tMessages: messages,\n\t\t\t},\n\t\t)\n\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"ChatCompletion error: %v\\n\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tcontent := resp.Choices[0].Message.Content\n\t\tmessages = append(messages, openai.ChatCompletionMessage{\n\t\t\tRole:    openai.ChatMessageRoleAssistant,\n\t\t\tContent: content,\n\t\t})\n\t\tfmt.Println(content)\n\t}\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Azure OpenAI ChatGPT\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tconfig := openai.DefaultAzureConfig(\"your Azure OpenAI Key\", \"https:\u002F\u002Fyour Azure OpenAI Endpoint\")\n\t\u002F\u002F If you use a deployment name different from the model name, you can customize the AzureModelMapperFunc function\n\t\u002F\u002F config.AzureModelMapperFunc = func(model string) string {\n\t\u002F\u002F \tazureModelMapping := map[string]string{\n\t\u002F\u002F \t\t\"gpt-3.5-turbo\": \"your gpt-3.5-turbo deployment name\",\n\t\u002F\u002F \t}\n\t\u002F\u002F \treturn azureModelMapping[model]\n\t\u002F\u002F }\n\n\tclient := openai.NewClientWithConfig(config)\n\tresp, err := client.CreateChatCompletion(\n\t\tcontext.Background(),\n\t\topenai.ChatCompletionRequest{\n\t\t\tModel: openai.GPT3Dot5Turbo,\n\t\t\tMessages: []openai.ChatCompletionMessage{\n\t\t\t\t{\n\t\t\t\t\tRole:    openai.ChatMessageRoleUser,\n\t\t\t\t\tContent: \"Hello Azure OpenAI!\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t)\n\tif err != nil {\n\t\tfmt.Printf(\"ChatCompletion error: %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Println(resp.Choices[0].Message.Content)\n}\n\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Embedding Semantic Similarity\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"log\"\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n\n)\n\nfunc main() {\n\tclient := openai.NewClient(\"your-token\")\n\n\t\u002F\u002F Create an EmbeddingRequest for the user query\n\tqueryReq := openai.EmbeddingRequest{\n\t\tInput: []string{\"How many chucks would a woodchuck chuck\"},\n\t\tModel: openai.AdaEmbeddingV2,\n\t}\n\n\t\u002F\u002F Create an embedding for the user query\n\tqueryResponse, err := client.CreateEmbeddings(context.Background(), queryReq)\n\tif err != nil {\n\t\tlog.Fatal(\"Error creating query embedding:\", err)\n\t}\n\n\t\u002F\u002F Create an EmbeddingRequest for the target text\n\ttargetReq := openai.EmbeddingRequest{\n\t\tInput: []string{\"How many chucks would a woodchuck chuck if the woodchuck could chuck wood\"},\n\t\tModel: openai.AdaEmbeddingV2,\n\t}\n\n\t\u002F\u002F Create an embedding for the target text\n\ttargetResponse, err := client.CreateEmbeddings(context.Background(), targetReq)\n\tif err != nil {\n\t\tlog.Fatal(\"Error creating target embedding:\", err)\n\t}\n\n\t\u002F\u002F Now that we have the embeddings for the user query and the target text, we\n\t\u002F\u002F can calculate their similarity.\n\tqueryEmbedding := queryResponse.Data[0]\n\ttargetEmbedding := targetResponse.Data[0]\n\n\tsimilarity, err := queryEmbedding.DotProduct(&targetEmbedding)\n\tif err != nil {\n\t\tlog.Fatal(\"Error calculating dot product:\", err)\n\t}\n\n\tlog.Printf(\"The similarity score between the query and the target is %f\", similarity)\n}\n\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Azure OpenAI Embeddings\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\n\tconfig := openai.DefaultAzureConfig(\"your Azure OpenAI Key\", \"https:\u002F\u002Fyour Azure OpenAI Endpoint\")\n\tconfig.APIVersion = \"2023-05-15\" \u002F\u002F optional update to latest API version\n\n\t\u002F\u002FIf you use a deployment name different from the model name, you can customize the AzureModelMapperFunc function\n\t\u002F\u002Fconfig.AzureModelMapperFunc = func(model string) string {\n\t\u002F\u002F    azureModelMapping := map[string]string{\n\t\u002F\u002F        \"gpt-3.5-turbo\":\"your gpt-3.5-turbo deployment name\",\n\t\u002F\u002F    }\n\t\u002F\u002F    return azureModelMapping[model]\n\t\u002F\u002F}\n\n\tinput := \"Text to vectorize\"\n\n\tclient := openai.NewClientWithConfig(config)\n\tresp, err := client.CreateEmbeddings(\n\t\tcontext.Background(),\n\t\topenai.EmbeddingRequest{\n\t\t\tInput: []string{input},\n\t\t\tModel: openai.AdaEmbeddingV2,\n\t\t})\n\n\tif err != nil {\n\t\tfmt.Printf(\"CreateEmbeddings error: %v\\n\", err)\n\t\treturn\n\t}\n\n\tvectors := resp.Data[0].Embedding \u002F\u002F []float32 with 1536 dimensions\n\n\tfmt.Println(vectors[:10], \"...\", vectors[len(vectors)-10:])\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>JSON Schema for function calling\u003C\u002Fsummary>\n\nIt is now possible for chat completion to choose to call a function for more information ([see developer docs here](https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fguides\u002Fgpt\u002Ffunction-calling)).\n\nIn 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.\n\nThe developer documents give this JSON schema definition as an example:\n\n```json\n{\n  \"name\":\"get_current_weather\",\n  \"description\":\"Get the current weather in a given location\",\n  \"parameters\":{\n    \"type\":\"object\",\n    \"properties\":{\n        \"location\":{\n          \"type\":\"string\",\n          \"description\":\"The city and state, e.g. San Francisco, CA\"\n        },\n        \"unit\":{\n          \"type\":\"string\",\n          \"enum\":[\n              \"celsius\",\n              \"fahrenheit\"\n          ]\n        }\n    },\n    \"required\":[\n        \"location\"\n    ]\n  }\n}\n```\n\nUsing the `jsonschema` package, this schema could be created using structs as such:\n\n```go\nFunctionDefinition{\n  Name: \"get_current_weather\",\n  Parameters: jsonschema.Definition{\n    Type: jsonschema.Object,\n    Properties: map[string]jsonschema.Definition{\n      \"location\": {\n        Type: jsonschema.String,\n        Description: \"The city and state, e.g. San Francisco, CA\",\n      },\n      \"unit\": {\n        Type: jsonschema.String,\n        Enum: []string{\"celsius\", \"fahrenheit\"},\n      },\n    },\n    Required: []string{\"location\"},\n  },\n}\n```\n\nThe `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).\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Error handling\u003C\u002Fsummary>\n\nOpen-AI maintains clear documentation on how to [handle API errors](https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fguides\u002Ferror-codes\u002Fapi-errors)\n\nexample:\n```\ne := &openai.APIError{}\nif errors.As(err, &e) {\n  switch e.HTTPStatusCode {\n    case 401:\n      \u002F\u002F invalid auth or key (do not retry)\n    case 429:\n      \u002F\u002F rate limiting or engine overload (wait and retry) \n    case 500:\n      \u002F\u002F openai server error (retry)\n    default:\n      \u002F\u002F unhandled\n  }\n}\n\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Fine Tune Model\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tclient := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\t\u002F\u002F create a .jsonl file with your training data for conversational model\n\t\u002F\u002F {\"prompt\": \"\u003Cprompt text>\", \"completion\": \"\u003Cideal generated text>\"}\n\t\u002F\u002F {\"prompt\": \"\u003Cprompt text>\", \"completion\": \"\u003Cideal generated text>\"}\n\t\u002F\u002F {\"prompt\": \"\u003Cprompt text>\", \"completion\": \"\u003Cideal generated text>\"}\n\n\t\u002F\u002F chat models are trained using the following file format:\n\t\u002F\u002F {\"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.\"}]}\n\t\u002F\u002F {\"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?\"}]}\n\t\u002F\u002F {\"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.\"}]}\n\n\t\u002F\u002F you can use openai cli tool to validate the data\n\t\u002F\u002F For more info - https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fguides\u002Ffine-tuning\n\n\tfile, err := client.CreateFile(ctx, openai.FileRequest{\n\t\tFilePath: \"training_prepared.jsonl\",\n\t\tPurpose:  \"fine-tune\",\n\t})\n\tif err != nil {\n\t\tfmt.Printf(\"Upload JSONL file error: %v\\n\", err)\n\t\treturn\n\t}\n\n\t\u002F\u002F create a fine tuning job\n\t\u002F\u002F 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)\n\t\u002F\u002F use below get method to know the status of your model\n\tfineTuningJob, err := client.CreateFineTuningJob(ctx, openai.FineTuningJobRequest{\n\t\tTrainingFile: file.ID,\n\t\tModel:        \"davinci-002\", \u002F\u002F gpt-3.5-turbo-0613, babbage-002.\n\t})\n\tif err != nil {\n\t\tfmt.Printf(\"Creating new fine tune model error: %v\\n\", err)\n\t\treturn\n\t}\n\n\tfineTuningJob, err = client.RetrieveFineTuningJob(ctx, fineTuningJob.ID)\n\tif err != nil {\n\t\tfmt.Printf(\"Getting fine tune model error: %v\\n\", err)\n\t\treturn\n\t}\n\tfmt.Println(fineTuningJob.FineTunedModel)\n\n\t\u002F\u002F once the status of fineTuningJob is `succeeded`, you can use your fine tune model in Completion Request or Chat Completion Request\n\n\t\u002F\u002F resp, err := client.CreateCompletion(ctx, openai.CompletionRequest{\n\t\u002F\u002F\t Model:  fineTuningJob.FineTunedModel,\n\t\u002F\u002F\t Prompt: \"your prompt\",\n\t\u002F\u002F })\n\t\u002F\u002F if err != nil {\n\t\u002F\u002F\t fmt.Printf(\"Create completion error %v\\n\", err)\n\t\u002F\u002F\t return\n\t\u002F\u002F }\n\t\u002F\u002F\n\t\u002F\u002F fmt.Println(resp.Choices[0].Text)\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Structured Outputs\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com\u002Fsashabaranov\u002Fgo-openai\"\n\t\"github.com\u002Fsashabaranov\u002Fgo-openai\u002Fjsonschema\"\n)\n\nfunc main() {\n\tclient := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\ttype Result struct {\n\t\tSteps []struct {\n\t\t\tExplanation string `json:\"explanation\"`\n\t\t\tOutput      string `json:\"output\"`\n\t\t} `json:\"steps\"`\n\t\tFinalAnswer string `json:\"final_answer\"`\n\t}\n\tvar result Result\n\tschema, err := jsonschema.GenerateSchemaForType(result)\n\tif err != nil {\n\t\tlog.Fatalf(\"GenerateSchemaForType error: %v\", err)\n\t}\n\tresp, err := client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{\n\t\tModel: openai.GPT4oMini,\n\t\tMessages: []openai.ChatCompletionMessage{\n\t\t\t{\n\t\t\t\tRole:    openai.ChatMessageRoleSystem,\n\t\t\t\tContent: \"You are a helpful math tutor. Guide the user through the solution step by step.\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tRole:    openai.ChatMessageRoleUser,\n\t\t\t\tContent: \"how can I solve 8x + 7 = -23\",\n\t\t\t},\n\t\t},\n\t\tResponseFormat: &openai.ChatCompletionResponseFormat{\n\t\t\tType: openai.ChatCompletionResponseFormatTypeJSONSchema,\n\t\t\tJSONSchema: &openai.ChatCompletionResponseFormatJSONSchema{\n\t\t\t\tName:   \"math_reasoning\",\n\t\t\t\tSchema: schema,\n\t\t\t\tStrict: true,\n\t\t\t},\n\t\t},\n\t})\n\tif err != nil {\n\t\tlog.Fatalf(\"CreateChatCompletion error: %v\", err)\n\t}\n\terr = schema.Unmarshal(resp.Choices[0].Message.Content, &result)\n\tif err != nil {\n\t\tlog.Fatalf(\"Unmarshal schema error: %v\", err)\n\t}\n\tfmt.Println(result)\n}\n```\n\u003C\u002Fdetails>\nSee the `examples\u002F` folder for more.\n\n## Frequently Asked Questions\n\n### Why don't we get the same answer when specifying a temperature field of 0 and asking the same question?\n\nEven when specifying a temperature field of 0, it doesn't guarantee that you'll always get the same response. Several factors come into play.\n\n1. 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.\n2. Token Count for Input\u002FOutput: 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.\n\nDue to the factors mentioned above, different answers may be returned even for the same question.\n\n**Workarounds:**\n1. As of November 2023, use [the new `seed` parameter](https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fguides\u002Ftext-generation\u002Freproducible-outputs) in conjunction with the `system_fingerprint` response field, alongside Temperature management.\n2. 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.\n3. 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.\n\nBy adopting these strategies, you can expect more consistent results.\n\n**Related Issues:**  \n[omitempty option of request struct will generate incorrect request when parameter is 0.](https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fissues\u002F9)\n\n### Does Go OpenAI provide a method to count tokens?\n\nNo, 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.\n\nFor counting tokens, you might find the following links helpful:  \n- [Counting Tokens For Chat API Calls](https:\u002F\u002Fgithub.com\u002Fpkoukk\u002Ftiktoken-go#counting-tokens-for-chat-api-calls)\n- [How to count tokens with tiktoken](https:\u002F\u002Fgithub.com\u002Fopenai\u002Fopenai-cookbook\u002Fblob\u002Fmain\u002Fexamples\u002FHow_to_count_tokens_with_tiktoken.ipynb)\n\n**Related Issues:**  \n[Is it possible to join the implementation of GPT3 Tokenizer](https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fissues\u002F62)\n\n## Contributing\n\nBy following [Contributing Guidelines](https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fblob\u002Fmaster\u002FCONTRIBUTING.md), we hope to ensure that your contributions are made smoothly and efficiently.\n\n## Thank you\n\nWe want to take a moment to express our deepest gratitude to the [contributors](https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fgraphs\u002Fcontributors) and sponsors of this project:\n- [Carson Kahn](https:\u002F\u002Fcarsonkahn.com) of [Spindle AI](https:\u002F\u002Fspindleai.com)\n\nTo 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!\n","# Go OpenAI\n[![Go Reference](https:\u002F\u002Fpkg.go.dev\u002Fbadge\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai.svg)](https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai)\n[![Go Report Card](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fsashabaranov_go-openai_readme_2b4a70945b89.png)](https:\u002F\u002Fgoreportcard.com\u002Freport\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai)\n[![codecov](https:\u002F\u002Fcodecov.io\u002Fgh\u002Fsashabaranov\u002Fgo-openai\u002Fbranch\u002Fmaster\u002Fgraph\u002Fbadge.svg?token=bCbIfHLIsW)](https:\u002F\u002Fcodecov.io\u002Fgh\u002Fsashabaranov\u002Fgo-openai)\n\n本库为 [OpenAI API](https:\u002F\u002Fplatform.openai.com\u002F) 提供非官方的 Go 客户端。我们支持以下功能：\n\n* ChatGPT 4o、o1\n* GPT-3、GPT-4\n* DALL·E 2、DALL·E 3、GPT Image 1\n* Whisper\n\n## 安装\n\n```\ngo get github.com\u002Fsashabaranov\u002Fgo-openai\n```\n目前，go-openai 需要 Go 1.18 或更高版本。\n\n\n## 使用方法\n\n### ChatGPT 示例用法：\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tclient := openai.NewClient(\"your token\")\n\tresp, err := client.CreateChatCompletion(\n\t\tcontext.Background(),\n\t\topenai.ChatCompletionRequest{\n\t\t\tModel: openai.GPT3Dot5Turbo,\n\t\t\tMessages: []openai.ChatCompletionMessage{\n\t\t\t\t{\n\t\t\t\t\tRole:    openai.ChatMessageRoleUser,\n\t\t\t\t\tContent: \"Hello!\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t)\n\n\tif err != nil {\n\t\tfmt.Printf(\"ChatCompletion error: %v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Println(resp.Choices[0].Message.Content)\n}\n```\n\n### 获取 OpenAI API 密钥：\n\n1. 访问 OpenAI 官网：[https:\u002F\u002Fplatform.openai.com\u002Faccount\u002Fapi-keys](https:\u002F\u002Fplatform.openai.com\u002Faccount\u002Fapi-keys)。\n2. 如果您还没有账号，请点击“Sign Up”创建一个；如果您已有账号，请点击“Log In”登录。\n3. 登录后，进入您的 API 密钥管理页面。\n4. 点击“Create new secret key”。\n5. 为您的新密钥命名，然后点击“Create secret key”。\n6. 您的新 API 密钥将会显示出来。请使用此密钥与 OpenAI API 进行交互。\n\n**注意：** 您的 API 密钥属于敏感信息，请勿将其分享给任何人。\n\n### 其他示例：\n\n\u003Cdetails>\n\u003Csummary>ChatGPT 流式完成\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tc := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\treq := openai.ChatCompletionRequest{\n\t\tModel:     openai.GPT3Dot5Turbo,\n\t\tMaxTokens: 20,\n\t\tMessages: []openai.ChatCompletionMessage{\n\t\t\t{\n\t\t\t\tRole:    openai.ChatMessageRoleUser,\n\t\t\t\tContent: \"Lorem ipsum\",\n\t\t\t},\n\t\t},\n\t\tStream: true,\n\t}\n\tstream, err := c.CreateChatCompletionStream(ctx, req)\n\tif err != nil {\n\t\tfmt.Printf(\"ChatCompletionStream error: %v\\n\", err)\n\t\treturn\n\t}\n\tdefer stream.Close()\n\n\tfmt.Printf(\"流式响应：\")\n\tfor {\n\t\tresponse, err := stream.Recv()\n\t\tif errors.Is(err, io.EOF) {\n\t\t\tfmt.Println(\"\\n流式结束\")\n\t\t\treturn\n\t\t}\n\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"\\n流式错误：%v\\n\", err)\n\t\t\treturn\n\t\t}\n\n\t\tfmt.Printf(response.Choices[0].Delta.Content)\n\t}\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>GPT-3 完成\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tc := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\treq := openai.CompletionRequest{\n\t\tModel:     openai.GPT3Babbage002,\n\t\tMaxTokens: 5,\n\t\tPrompt:    \"Lorem ipsum\",\n\t}\n\tresp, err := c.CreateCompletion(ctx, req)\n\tif err != nil {\n\t\tfmt.Printf(\"Completion error: %v\\n\", err)\n\t\treturn\n\t}\n\tfmt.Println(resp.Choices[0].Text)\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>GPT-3 流式完成\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"errors\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tc := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\treq := openai.CompletionRequest{\n\t\tModel:     openai.GPT3Babbage002,\n\t\tMaxTokens: 5,\n\t\tPrompt:    \"Lorem ipsum\",\n\t\tStream:    true,\n\t}\n\tstream, err := c.CreateCompletionStream(ctx, req)\n\tif err != nil {\n\t\tfmt.Printf(\"CompletionStream error: %v\\n\", err)\n\t\treturn\n\t}\n\tdefer stream.Close()\n\n\tfor {\n\t\tresponse, err := stream.Recv()\n\t\tif errors.Is(err, io.EOF) {\n\t\t\tfmt.Println(\"流式结束\")\n\t\t\treturn\n\t\t}\n\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"流式错误：%v\\n\", err)\n\t\t\treturn\n\t\t}\n\n\t\tfmt.Printf(\"流式响应：\\n%s\\n\", response)\n\t}\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>音频转文字\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tc := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\treq := openai.AudioRequest{\n\t\tModel:    openai.Whisper1,\n\t\tFilePath: \"recording.mp3\",\n\t}\n\tresp, err := c.CreateTranscription(ctx, req)\n\tif err != nil {\n\t\tfmt.Printf(\"转录错误：%v\\n\", err)\n\t\treturn\n\t}\n\tfmt.Println(resp.Text)\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>音频字幕生成\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\n\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tc := openai.NewClient(os.Getenv(\"OPENAI_KEY\"))\n\n\treq := openai.AudioRequest{\n\t\tModel:    openai.Whisper1,\n\t\tFilePath: os.Args[1],\n\t\tFormat:   openai.AudioResponseFormatSRT,\n\t}\n\tresp, err := c.CreateTranscription(context.Background(), req)\n\tif err != nil {\n\t\tfmt.Printf(\"转录错误：%v\\n\", err)\n\t\treturn\n\t}\n\tf, err := os.Create(os.Args[1] + \".srt\")\n\tif err != nil {\n\t\tfmt.Printf(\"无法打开文件：%v\\n\", err)\n\t\treturn\n\t}\n\tdefer f.Close()\n\tif _, err := f.WriteString(resp.Text); err != nil {\n\t\tfmt.Printf(\"写入文件时出错：%v\\n\", err)\n\t\treturn\n\t}\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>DALL-E 2 图像生成\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding\u002Fbase64\"\n\t\"fmt\"\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n\t\"image\u002Fpng\"\n\t\"os\"\n)\n\nfunc main() {\n\tc := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\t\u002F\u002F 通过链接生成示例图像\n\treqUrl := openai.ImageRequest{\n\t\tPrompt:         \"一只鹦鹉在滑板上表演技巧，卡通风格，自然光，高细节\",\n\t\tSize:           openai.CreateImageSize256x256,\n\t\tResponseFormat: openai.CreateImageResponseFormatURL,\n\t\tN:              1,\n\t}\n\n\trespUrl, err := c.CreateImage(ctx, reqUrl)\n\tif err != nil {\n\t\tfmt.Printf(\"图像生成错误：%v\\n\", err)\n\t\treturn\n\t}\n\tfmt.Println(respUrl.Data[0].URL)\n\n\t\u002F\u002F 示例图像以 base64 格式\n\treqBase64 := openai.ImageRequest{\n\t\tPrompt:         \"一个人形鹦鹉穿着经典服装的肖像，高细节，逼真的光线，虚幻引擎效果\",\n\t\tSize:           openai.CreateImageSize256x256,\n\t\tResponseFormat: openai.CreateImageResponseFormatB64JSON,\n\t\tN:              1,\n\t}\n\n\trespBase64, err := c.CreateImage(ctx, reqBase64)\n\tif err != nil {\n\t\tfmt.Printf(\"图像生成错误：%v\\n\", err)\n\t\treturn\n\t}\n\n\timgBytes, err := base64.StdEncoding.DecodeString(respBase64.Data[0].B64JSON)\n\tif err != nil {\n\t\tfmt.Printf(\"Base64 解码错误：%v\\n\", err)\n\t\treturn\n\t}\n\n\tr := bytes.NewReader(imgBytes)\n\timgData, err := png.Decode(r)\n\tif err != nil {\n\t\tfmt.Printf(\"PNG 解码错误：%v\\n\", err)\n\t\treturn\n\t}\n\n文件, err := os.Create(\"example.png\")\n\tif err != nil {\n\t\tfmt.Printf(\"创建文件错误：：%v\\n\", err)\n\t\treturn\n\t}\n\tdefer file.Close()\n\n\tif err := png.Encode(file, imgData); err != nil {\n\t\tfmt.Printf(\"PNG编码错误：：%v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Println(\"图像已保存为example.png\")\n}\n\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>GPT Image 1 图像生成\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"encoding\u002Fbase64\"\n\t\"fmt\"\n\t\"os\"\n\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tc := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\treq := openai.ImageRequest{\n\t\tPrompt:            \"一只鹦鹉在滑板上表演特技。图片底部有一条醒目的横幅，上面写着‘SKATE MASTER’。卡通风格，自然光，高细节，1:1长宽比。\",\n\t\tBackground:        openai.CreateImageBackgroundOpaque,\n\t\tModel:             openai.CreateImageModelGptImage1,\n\t\tSize:              openai.CreateImageSize1024x1024,\n\t\tN:                 1,\n\t\tQuality:           openai.CreateImageQualityLow,\n\t\tOutputCompression: 100,\n\t\tOutputFormat:      openai.CreateImageOutputFormatJPEG,\n\t\t\u002F\u002F Moderation: \t\t openai.CreateImageModerationLow,\n\t\t\u002F\u002F User: \t\t\t\t\t \"\",\n\t}\n\n\tresp, err := c.CreateImage(ctx, req)\n\tif err != nil {\n\t\tfmt.Printf(\"图像生成错误：：%v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Println(\"图像Base64:\", resp.Data[0].B64JSON)\n\n\t\u002F\u002F 解码Base64数据\n\timgBytes, err := base64.StdEncoding.DecodeString(resp.Data[0].B64JSON)\n\tif err != nil {\n\t\tfmt.Printf(\"Base64解码错误：：%v\\n\", err)\n\t\treturn\n\t}\n\n\t\u002F\u002F 将图像写入文件\n\toutputPath := \"generated_image.jpg\"\n\terr = os.WriteFile(outputPath, imgBytes, 0644)\n\tif err != nil {\n\t\tfmt.Printf(\"写入图像文件失败：：%v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"图像已保存为%s\\n\", outputPath)\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>配置代理\u003C\u002Fsummary>\n\n```go\nconfig := openai.DefaultConfig(\"token\")\nproxyUrl, err := url.Parse(\"http:\u002F\u002Flocalhost:{port}\")\nif err != nil {\n\tpanic(err)\n}\ntransport := &http.Transport{\n\tProxy: http.ProxyURL(proxyUrl),\n}\nconfig.HTTPClient = &http.Client{\n\tTransport: transport,\n}\n\nc := openai.NewClientWithConfig(config)\n```\n\n参见：https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai#ClientConfig\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>ChatGPT支持上下文\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tclient := openai.NewClient(\"your token\")\n\tmessages := make([]openai.ChatCompletionMessage, 0)\n\treader := bufio.NewReader(os.Stdin)\n\tfmt.Println(\"对话\")\n\tfmt.Println(\"---------------------\")\n\n\tfor {\n\t\tfmt.Print(\"-> \")\n\t\ttext, _ := reader.ReadString('\\n')\n\t\t\u002F\u002F 将CRLF转换为LF\n\t\ttext = strings.Replace(text, \"\\n\", \"\", -1)\n\t\tmessages = append(messages, openai.ChatCompletionMessage{\n\t\t\tRole:    openai.ChatMessageRoleUser,\n\t\t\tContent: text,\n\t\t})\n\n\t\tresp, err := client.CreateChatCompletion(\n\t\t\tcontext.Background(),\n\t\t\topenai.ChatCompletionRequest{\n\t\t\t\tModel:    openai.GPT3Dot5Turbo,\n\t\t\t\tMessages: messages,\n\t\t\t},\n\t\t)\n\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"ChatCompletion错误：：%v\\n\", err)\n\t\t\tcontinue\n\t\t}\n\n\t\tcontent := resp.Choices[0].Message.Content\n\t\tmessages = append(messages, openai.ChatCompletionMessage{\n\t\t\tRole:    openai.ChatMessageRoleAssistant,\n\t\t\tContent: content,\n\t\t})\n\t\tfmt.Println(content)\n\t}\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Azure OpenAI ChatGPT\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tconfig := openai.DefaultAzureConfig(\"your Azure OpenAI Key\", \"https:\u002F\u002Fyour Azure OpenAI Endpoint\")\n\t\u002F\u002F 如果你使用的部署名称与模型名称不同，可以自定义AzureModelMapperFunc函数\n\t\u002F\u002F config.AzureModelMapperFunc = func(model string) string {\n\t\u002F\u002F \tazureModelMapping := map[string]string{\n\t\u002F\u002F \t\t\"gpt-3.5-turbo\": \"your gpt-3.5-turbo部署名称\",\n\t\u002F\u002F \t}\n\t\u002F\u002F \treturn azureModelMapping[model]\n\t\u002F\u002F }\n\n\tclient := openai.NewClientWithConfig(config)\n\tresp, err := client.CreateChatCompletion(\n\t\tcontext.Background(),\n\t\topenai.ChatCompletionRequest{\n\t\t\tModel: openai.GPT3Dot5Turbo,\n\t\t\tMessages: []openai.ChatCompletionMessage{\n\t\t\t\t{\n\t\t\t\t\tRole:    openai.ChatMessageRoleUser,\n\t\t\t\t\tContent: \"Hello Azure OpenAI!\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t)\n\tif err != nil {\n\t\tfmt.Printf(\"ChatCompletion错误：：%v\\n\", err)\n\t\treturn\n\t}\n\n\tfmt.Println(resp.Choices[0].Message.Content)\n}\n\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>嵌入语义相似度\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"log\"\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n\n)\n\nfunc main() {\n\tclient := openai.NewClient(\"your-token\")\n\n\t\u002F\u002F 为用户查询创建一个EmbeddingRequest\n\tqueryReq := openai.EmbeddingRequest{\n\t\tInput: []string{\"一只土拨鼠能刨多少土？\"},\n\t\tModel: openai.AdaEmbeddingV2,\n\t}\n\n\t\u002F\u002F 为用户查询创建嵌入向量\nqueryResponse, err := client.CreateEmbeddings(context.Background(), queryReq)\nif err != nil {\n\tlog.Fatal(\"创建查询嵌入向量时出错：\", err)\n}\n\n\t\u002F\u002F 为目标文本创建一个EmbeddingRequest\ntargetReq := openai.EmbeddingRequest{\n\t Input: []string{\"如果土拨鼠真的会刨土，它能刨多少土呢？\"},\n\t Model: openai.AdaEmbeddingV2,\n}\n\n\t\u002F\u002F 为目标文本创建嵌入向量\ntargetResponse, err := client.CreateEmbeddings(context.Background(), targetReq)\nif err != nil {\n\tlog.Fatal(\"创建目标嵌入向量时出错：\", err)\n}\n\n\t\u002F\u002F 现在我们已经有了用户查询和目标文本的嵌入向量，就可以计算它们之间的相似度了。\nqueryEmbedding := queryResponse.Data[0]\ntargetEmbedding := targetResponse.Data[0]\n\nsimilarity, err := queryEmbedding.DotProduct(&targetEmbedding)\nif err != nil {\n\tlog.Fatal(\"计算点积时出错：\", err)\n}\n\nlog.Printf(\"查询和目标文本之间的相似度分数为%f\", similarity)\n}\n\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>Azure OpenAI嵌入\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\n\tconfig := openai.DefaultAzureConfig(\"your Azure OpenAI Key\", \"https:\u002F\u002Fyour Azure OpenAI Endpoint\")\n\tconfig.APIVersion = \"2023-05-15\" \u002F\u002F 可选地更新到最新API版本\n\n\t\u002F\u002F 如果你使用的部署名称与模型名称不同，可以自定义AzureModelMapperFunc函数\n\t\u002F\u002Fconfig.AzureModelMapperFunc = func(model string) string {\n\t\u002F\u002F    azureModelMapping := map[string]string{\n\t\u002F\u002F        \"gpt-3.5-turbo\":\"your gpt-3.5-turbo部署名称\",\n\t\u002F\u002F    }\n\t\u002F\u002F    return azureModelMapping[model]\n\t\u002F\u002F}\n\ninput := \"需要向量化处理的文本\"\n\nclient := openai.NewClientWithConfig(config)\nresp, err := client.CreateEmbeddings(\n\tcontext.Background(),\n\topenai.EmbeddingRequest{\n\t\tInput: []string{input},\n\t\tModel: openai.AdaEmbeddingV2,\n\t},\n)\nif err != nil {\n\tfmt.Printf(\"CreateEmbeddings错误：：%v\\n\", err)\n\treturn\n}\n\n向量 := resp.Data[0].Embedding \u002F\u002F 一个包含1536维浮点数的数组\n\nfmt.Println(vectors[:10], \"...\", vectors[len(vectors)-10:])\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>用于函数调用的 JSON Schema\u003C\u002Fsummary>\n\n现在，聊天补全功能可以选择调用函数以获取更多信息（[请参阅此处的开发者文档](https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fguides\u002Fgpt\u002Ffunction-calling)）。\n\n为了描述可调用函数的类型，必须提供一个 JSON Schema。虽然有许多比本库所能提供的更为先进的 JSON Schema 库，但我们仍包含了一个简单的 `jsonschema` 包，供希望使用此功能而无需自行格式化 JSON Schema 负载的人士使用。\n\n开发者文档中给出了如下 JSON Schema 定义作为示例：\n\n```json\n{\n  \"name\":\"get_current_weather\",\n  \"description\":\"获取给定地点的当前天气\",\n  \"parameters\":{\n    \"type\":\"object\",\n    \"properties\":{\n        \"location\":{\n          \"type\":\"string\",\n          \"description\":\"城市和州，例如旧金山，加州\"\n        },\n        \"unit\":{\n          \"type\":\"string\",\n          \"enum\":[\n              \"celsius\",\n              \"fahrenheit\"\n          ]\n        }\n    },\n    \"required\":[\n        \"location\"\n    ]\n  }\n}\n```\n\n使用 `jsonschema` 包，可以通过结构体创建该 Schema，如下所示：\n\n```go\nFunctionDefinition{\n  Name: \"get_current_weather\",\n  Parameters: jsonschema.Definition{\n    Type: jsonschema.Object,\n    Properties: map[string]jsonschema.Definition{\n      \"location\": {\n        Type: jsonschema.String,\n        Description: \"城市和州，例如旧金山，加州\",\n      },\n      \"unit\": {\n        Type: jsonschema.String,\n        Enum: []string{\"celsius\", \"fahrenheit\"},\n      },\n    },\n    Required: []string{\"location\"},\n  },\n}\n```\n\n`FunctionDefinition` 的 `Parameters` 字段可以接受上述任一格式，甚至可以接受来自其他库的嵌套结构体（只要能够被序列化为 JSON 即可）。\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>错误处理\u003C\u002Fsummary>\n\nOpenAI 维护了清晰的文档，说明如何 [处理 API 错误](https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fguides\u002Ferror-codes\u002Fapi-errors)。\n\n示例：\n```\ne := &openai.APIError{}\nif errors.As(err, &e) {\n  switch e.HTTPStatusCode {\n    case 401:\n      \u002F\u002F 认证或密钥无效（不要重试）\n    case 429:\n      \u002F\u002F 速率限制或引擎过载（等待后重试）\n    case 500:\n      \u002F\u002F OpenAI 服务器错误（重试）\n    default:\n      \u002F\u002F 未处理的情况\n  }\n}\n\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>微调模型\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\tclient := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\t\u002F\u002F 创建一个包含对话模型训练数据的 .jsonl 文件\n\t\u002F\u002F {\"prompt\": \"\u003C提示文本>\", \"completion\": \"\u003C理想生成文本>\"}\n\t\u002F\u002F {\"prompt\": \"\u003C提示文本>\", \"completion\": \"\u003C理想生成文本>\"}\n\t\u002F\u002F {\"prompt\": \"\u003C提示文本>\", \"completion\": \"\u003C理想生成文本>\"}\n\n\t\u002F\u002F 对话模型使用以下文件格式进行训练：\n\t\u002F\u002F {\"messages\": [{\"role\": \"system\", \"content\": \"Marv 是一个既基于事实又带讽刺意味的聊天机器人。\"}, {\"role\": \"user\", \"content\": \"法国的首都是哪里？\"}, {\"role\": \"assistant\", \"content\": \"巴黎，好像大家都知道似的。\"}]}\n\t\u002F\u002F {\"messages\": [{\"role\": \"system\", \"content\": \"Marv 是一个既基于事实又带讽刺意味的聊天机器人。\"}, {\"role\": \"user\", \"content\": \"《罗密欧与朱丽叶》是谁写的？\"}, {\"role\": \"assistant\", \"content\": \"哦，就是那个叫威廉·莎士比亚的人呗。你听说过他吗？\"}]}\n\t\u002F\u002F {\"messages\": [{\"role\": \"system\", \"content\": \"Marv 是一个既基于事实又带讽刺意味的聊天机器人。\"}, {\"role\": \"user\", \"content\": \"月球离地球有多远？\"}, {\"role\": \"assistant\", \"content\": \"大约 384,400 公里吧。多一点少一点也没啥关系，反正谁在乎呢。\"}]}\n\n\t\u002F\u002F 可以使用 OpenAI CLI 工具来验证数据。\n\t\u002F\u002F 更多信息请参阅：https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fguides\u002Ffine-tuning\n\n\tfile, err := client.CreateFile(ctx, openai.FileRequest{\n\t\tFilePath: \"training_prepared.jsonl\",\n\t\tPurpose:  \"fine-tune\",\n\t})\n\tif err != nil {\n\t\tfmt.Printf(\"上传 JSONL 文件时出错：%v\\n\", err)\n\t\treturn\n\t}\n\n\t\u002F\u002F 创建微调任务\n\t\u002F\u002F 流式传输事件直到任务完成（这通常需要几分钟，但如果队列中有许多任务或您的数据集很大，则可能需要数小时）。\n\t\u002F\u002F 使用下面的方法来了解模型的状态。\n\tfineTuningJob, err := client.CreateFineTuningJob(ctx, openai.FineTuningJobRequest{\n\t\tTrainingFile: file.ID,\n\t\tModel:        \"davinci-002\", \u002F\u002F gpt-3.5-turbo-0613、babbage-002。\n\t})\n\tif err != nil {\n\t\tfmt.Printf(\"创建新的微调模型时出错：%v\\n\", err)\n\t\treturn\n\t}\n\n\tfineTuningJob, err = client.RetrieveFineTuningJob(ctx, fineTuningJob.ID)\n\tif err != nil {\n\t\tfmt.Printf(\"获取微调模型时出错：%v\\n\", err)\n\t\treturn\n\t}\n\tfmt.Println(fineTuningJob.FineTunedModel)\n\n\t\u002F\u002F 一旦 fineTuningJob 的状态变为 `succeeded`，您就可以在 Completion Request 或 Chat Completion Request 中使用您的微调模型。\n\n\t\u002F\u002F resp, err := client.CreateCompletion(ctx, openai.CompletionRequest{\n\t\u002F\u002F\t Model:  fineTuningJob.FineTunedModel,\n\t\u002F\u002F\t Prompt: \"your prompt\",\n\t\u002F\u002F })\n\t\u002F\u002F if err != nil {\n\t\u002F\u002F\t fmt.Printf(\"创建完成请求时出错：%v\\n\", err)\n\t\u002F\u002F\t return\n\t\u002F\u002F }\n\t\u002F\u002F\n\t\u002F\u002F fmt.Println(resp.Choices[0].Text)\n}\n```\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>结构化输出\u003C\u002Fsummary>\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com\u002Fsashabaranov\u002Fgo-openai\"\n\t\"github.com\u002Fsashabaranov\u002Fgo-openai\u002Fjsonschema\"\n)\n\nfunc main() {\n\tclient := openai.NewClient(\"your token\")\n\tctx := context.Background()\n\n\ttype Result struct {\n\t\tSteps []struct {\n\t\t\tExplanation string `json:\"explanation\"`\n\t\t\tOutput      string `json:\"output\"`\n\t\t} `json:\"steps\"`\n\t\tFinalAnswer string `json:\"final_answer\"`\n\t}\n\tvar result Result\n\tschema, err := jsonschema.GenerateSchemaForType(result)\n\tif err != nil {\n\t\tlog.Fatalf(\"GenerateSchemaForType 出错：%v\", err)\n\t}\n\tresp, err := client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{\n\t\tModel: openai.GPT4oMini,\n\t\tMessages: []openai.ChatCompletionMessage{\n\t\t\t{\n\t\t\t\tRole:    openai.ChatMessageRoleSystem,\n\t\t\t\tContent: \"你是一位乐于助人的数学家教。请逐步引导用户解决问题。\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tRole:    openai.ChatMessageRoleUser,\n\t\t\t\tContent: \"我该如何解方程 8x + 7 = -23\",\n\t\t\t},\n\t\t},\n\t\tResponseFormat: &openai.ChatCompletionResponseFormat{\n\t\t\tType: openai.ChatCompletionResponseFormatTypeJSONSchema,\n\t\t\tJSONSchema: &openai.ChatCompletionResponseFormatJSONSchema{\n\t\t\t\tName:   \"math_reasoning\",\n\t\t\t\tSchema: schema,\n\t\t\t\tStrict: true,\n\t\t\t},\n\t\t},\n\t})\n\tif err != nil {\n\t\tlog.Fatalf(\"CreateChatCompletion 出错：%v\", err)\n\t}\n\terr = schema.Unmarshal(resp.Choices[0].Message.Content, &result)\n\tif err != nil {\n\t\tlog.Fatalf(\"Unmarshal schema 出错：%v\", err)\n\t}\n\tfmt.Println(result)\n}\n```\n\u003C\u002Fdetails>\n更多内容请参阅 `examples\u002F` 文件夹。\n\n\n\n## 常见问题解答\n\n### 为什么在指定温度字段为0并提出相同问题时，我们得不到相同的答案？\n\n即使将温度字段设置为0，也不能保证每次都会得到完全一致的响应。这背后涉及多个因素。\n\n1. Go OpenAI 的行为：当您在 Go OpenAI 中将温度字段设置为0时，由于使用了 `omitempty` 标签，该字段会被从请求中移除。因此，OpenAI API 会采用默认值1。\n2. 输入\u002F输出的 token 数量：如果输入和输出中的 token 数量较多，即便将温度设置为0，仍可能出现非确定性行为。尤其是在使用约32,000个 token 时，即使温度为0，非确定性行为的发生概率也会达到最高。\n\n由于上述原因，即使是相同的问题，也可能返回不同的答案。\n\n**解决方法：**\n1. 截至2023年11月，可以结合使用 [新的 `seed` 参数](https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fguides\u002Ftext-generation\u002Freproducible-outputs) 和 `system_fingerprint` 响应字段，同时合理管理温度参数。\n2. 使用 `math.SmallestNonzeroFloat32`：将温度字段设置为 `math.SmallestNonzeroFloat32` 而不是0，可以模拟将温度设为0的效果。\n3. 限制 token 数量：通过限制输入和输出中的 token 数量，尤其是避免接近32,000 token 的大请求，可以降低非确定性行为的风险。\n\n采取这些策略后，您可以期待更一致的结果。\n\n**相关问题：**\n[请求结构体的 `omitempty` 选项在参数为0时会生成错误的请求。](https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fissues\u002F9)\n\n### Go OpenAI 是否提供 token 计数功能？\n\n目前，Go OpenAI 并未提供 token 计数功能，未来也没有计划加入此功能。不过，如果有无需依赖其他库即可实现 token 计数的方法，或许可以将其合并到 Go OpenAI 中。否则，更适合将其单独实现在一个专用的库或仓库中。\n\n关于 token 计数，您可以参考以下链接：\n- [用于聊天 API 调用的 token 计数](https:\u002F\u002Fgithub.com\u002Fpkoukk\u002Ftiktoken-go#counting-tokens-for-chat-api-calls)\n- [如何使用 tiktoken 进行 token 计数](https:\u002F\u002Fgithub.com\u002Fopenai\u002Fopenai-cookbook\u002Fblob\u002Fmain\u002Fexamples\u002FHow_to_count_tokens_with_tiktoken.ipynb)\n\n**相关问题：**\n[是否可以集成 GPT-3 Tokenizer 的实现？](https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fissues\u002F62)\n\n## 参与贡献\n\n请遵循 [贡献指南](https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fblob\u002Fmaster\u002FCONTRIBUTING.md)，以确保您的贡献能够顺利且高效地完成。\n\n## 感谢\n\n在此，我们想向本项目的 [贡献者](https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fgraphs\u002Fcontributors) 和赞助者致以最诚挚的谢意：\n- Spindle AI 的 Carson Kahn (https:\u002F\u002Fcarsonkahn.com)\n\n感谢每一位！是你们的帮助让我们取得了远超预期的成果。期待我们携手迈向更加辉煌的未来！","# go-openai 快速上手指南\n\n`go-openai` 是一个非官方的 Go 语言客户端库，用于便捷地调用 OpenAI API。它支持 ChatGPT (4o, o1)、GPT-3\u002F4、DALL·E 2\u002F3、GPT Image 1 以及 Whisper 等主流模型。\n\n## 环境准备\n\n在开始之前，请确保您的开发环境满足以下要求：\n\n*   **Go 版本**：需要 Go 1.18 或更高版本。\n*   **API Key**：您需要拥有一个有效的 OpenAI API Key。\n    *   获取地址：[https:\u002F\u002Fplatform.openai.com\u002Faccount\u002Fapi-keys](https:\u002F\u002Fplatform.openai.com\u002Faccount\u002Fapi-keys)\n    *   **注意**：API Key 属于敏感信息，请勿泄露或在代码中硬编码提交到公共仓库。建议通过环境变量读取。\n\n## 安装步骤\n\n使用 Go 模块命令安装该库：\n\n```bash\ngo get github.com\u002Fsashabaranov\u002Fgo-openai\n```\n\n> **国内开发者提示**：如果下载速度较慢，可配置国内 Go 代理加速：\n> ```bash\n> export GOPROXY=https:\u002F\u002Fgoproxy.cn,direct\n> go get github.com\u002Fsashabaranov\u002Fgo-openai\n> ```\n\n## 基本使用\n\n以下是最简单的 ChatGPT 对话示例。将 `\"your token\"` 替换为您的实际 API Key 即可运行。\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\topenai \"github.com\u002Fsashabaranov\u002Fgo-openai\"\n)\n\nfunc main() {\n\t\u002F\u002F 初始化客户端\n\tclient := openai.NewClient(\"your token\")\n\n\t\u002F\u002F 创建聊天完成请求\n\tresp, err := client.CreateChatCompletion(\n\t\tcontext.Background(),\n\t\topenai.ChatCompletionRequest{\n\t\t\tModel: openai.GPT3Dot5Turbo,\n\t\t\tMessages: []openai.ChatCompletionMessage{\n\t\t\t\t{\n\t\t\t\t\tRole:    openai.ChatMessageRoleUser,\n\t\t\t\t\tContent: \"Hello!\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t)\n\n\tif err != nil {\n\t\tfmt.Printf(\"ChatCompletion error: %v\\n\", err)\n\t\treturn\n\t}\n\n\t\u002F\u002F 输出模型回复\n\tfmt.Println(resp.Choices[0].Message.Content)\n}\n```\n\n### 核心功能简述\n除了基础对话，该库还支持以下高级用法（参考官方文档获取更多细节）：\n*   **流式输出**：使用 `CreateChatCompletionStream` 实现打字机效果。\n*   **语音转文字**：使用 `CreateTranscription` 调用 Whisper 模型。\n*   **图像生成**：支持 DALL·E 2\u002F3 及 GPT Image 1 生成图片。\n*   **Azure 集成**：通过 `DefaultAzureConfig` 轻松连接 Azure OpenAI 服务。\n*   **上下文记忆**：通过在 `Messages` 切片中累积历史对话实现多轮对话。","某电商平台的后端团队正在用 Go 语言重构其智能客服系统，需要快速集成大模型能力以自动回答用户关于订单状态和退货政策的咨询。\n\n### 没有 go-openai 时\n- 开发人员必须手动封装复杂的 HTTP 请求，逐行处理鉴权头、JSON 序列化及错误码映射，代码冗余且极易出错。\n- 实现流式回复（Streaming）功能极其困难，需底层处理 SSE 协议解析，导致用户等待首字响应时间过长，体验卡顿。\n- 切换不同模型（如从 GPT-3.5 升级至 GPT-4o）或尝试 Whisper 语音转文字时，需要重写大量接口适配逻辑，维护成本高昂。\n- 缺乏统一的类型定义，团队成员对 API 参数结构理解不一致，导致联调阶段频繁出现格式错误。\n\n### 使用 go-openai 后\n- 仅需几行代码即可初始化客户端并调用 `CreateChatCompletion`，库内部自动处理所有 HTTP 细节与错误重试，开发效率提升数倍。\n- 直接调用 `CreateChatCompletionStream` 接口即可轻松实现打字机效果的流式输出，显著降低用户感知延迟，交互更流畅。\n- 通过简单的常量替换（如 `openai.GPT4o`）即可无缝切换模型，或一键启用 Whisper 接口处理用户上传的语音投诉，扩展性极强。\n- 利用库中预定义的强类型结构体（如 `ChatCompletionRequest`），编译器能自动检查参数合法性，大幅减少运行时异常。\n\ngo-openai 将繁琐的 API 对接工作转化为标准的 Go 函数调用，让团队能专注于业务逻辑而非底层通信协议。","https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fsashabaranov_go-openai_3878b3e4.png","sashabaranov","Alex Baranov","https:\u002F\u002Foss.gittoolsai.com\u002Favatars\u002Fsashabaranov_9a3ff643.jpg","VP of Engineering @unreallabsai\r\n\r\nPreviously: \r\nSamaya AI, Headspace, Sayana (YC W20),\r\nCERN, Yandex","@unreallabsai","London, United Kingdom",null,"https:\u002F\u002Fgithub.com\u002Fsashabaranov",[24],{"name":25,"color":26,"percentage":27},"Go","#00ADD8",100,10617,1687,"2026-04-14T13:39:23","Apache-2.0",1,"Linux, macOS, Windows","未说明",{"notes":36,"python":37,"dependencies":38},"这是一个 Go 语言客户端库，用于调用 OpenAI API，本身不运行 AI 模型，因此无需本地 GPU 或大内存。运行需安装 Go 1.18 及以上版本，并配置有效的 OpenAI API Key。支持通过代理配置访问网络。","不适用 (Go 语言库)",[39],"Go >= 1.18",[41,42,43],"插件","语言模型","音频",[45,46,47,48,49,50,51,52,53,54,55],"go","openai","golang","streaming-api","dall-e","chatgpt","chatgpt-api","openai-whisper","gpt-4","gpt-5","gpt-5-api",2,"ready","2026-03-27T02:49:30.150509","2026-04-15T11:26:17.278792",[61,66,71,76,81,86,91],{"id":62,"question_zh":63,"answer_zh":64,"source_url":65},34264,"遇到 'invalid character '\u003C' looking for beginning of value' 错误怎么办？","这通常是因为 baseURL 设置不正确，缺少了后缀 '\u002Fv1'。请确保您的 baseURL 格式为 'http:\u002F\u002FYOUR_DOMAIN:YOUR_PORT\u002Fv1'。检查是否忘记包含 'v1' 路径。","https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fissues\u002F233",{"id":67,"question_zh":68,"answer_zh":69,"source_url":70},34265,"在使用 go-openai 时遇到网络连接错误（如 connection refused），但 Python 包可以正常使用，如何解决？","这通常是由于网络代理问题导致的。您需要在 Go 客户端中显式配置 HTTP 代理。示例代码如下：\n\nconst (\n    ApiKey    = \"sk-xxxxxxxxxxxxxxxxxxx\"\n    ProxyHost = \"http:\u002F\u002F127.0.0.1:10809\"\n)\n\nproxyUri, err := url.Parse(ProxyHost)\nif err != nil {\n    return\n}\nhClient := &http.Client{\n    Transport: &http.Transport{\n        Proxy: http.ProxyURL(proxyUri),\n    },\n    Timeout: 60 * time.Second,\n}\ndefaultConfig := openai.DefaultConfig(ApiKey)\ndefaultConfig.HTTPClient = hClient\nclient := openai.NewClientWithConfig(defaultConfig)","https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fissues\u002F604",{"id":72,"question_zh":73,"answer_zh":74,"source_url":75},34266,"如何在发送请求前统计 Token 数量以控制成本？","该库本身不直接包含 Token 计数功能，但可以使用第三方库 'tiktoken-go' 来解决此问题。通过集成 tiktoken-go，您可以在发送请求前准确计算输入内容的 Token 数，从而正确调整 MaxToken 参数。","https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fissues\u002F200",{"id":77,"question_zh":78,"answer_zh":79,"source_url":80},34267,"流式输出（Stream）中的空白字符被去除导致格式混乱，如何处理？","这不是 go-openai 库本身的问题，而是前端实现或数据处理逻辑的问题。库输出的流内容本身是正常的，建议检查前端渲染逻辑或后端对流出数据的处理代码，确保没有意外去除空白字符。","https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fissues\u002F276",{"id":82,"question_zh":83,"answer_zh":84,"source_url":85},34268,"如何在不消耗 OpenAI 额度的情况下进行测试？","可以使用库中提供的 Mock Server 功能进行单元测试。该项目已经实现了针对所有 OpenAI API 端点的 Mock 测试服务器（参见 PR #356），它可以模拟服务器响应并验证客户端发送的值，从而避免在开发测试阶段消耗真实的 API 额度。","https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fissues\u002F30",{"id":87,"question_zh":88,"answer_zh":89,"source_url":90},34269,"函数调用（Function Calling）和新模型（如 *-0613）支持吗？","是的，这些功能已经在 v1.11.3 及更高版本中实现。对于函数调用的参数类型，已更新为 'any' 类型以支持更灵活的定义。请升级到您的项目中使用最新版本，并参考相关测试用例了解具体用法。","https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fissues\u002F360",{"id":92,"question_zh":93,"answer_zh":94,"source_url":95},34270,"为什么有很多重复或未关闭的 Issue，应该如何提问？","维护者建议将纯“提问”类的内容发布到 GitHub Discussions 或 Stack Overflow，而不是作为 Issue 提交。Issue  tracker 应主要用于报告 Bug 和提出功能增强请求。这有助于保持 Issue 列表的清晰，方便维护者追踪实际问题。","https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fissues\u002F415",[97,102,107,112,117,122,127,132,137,142,147,152,157,162,167,172,177,182,187,192],{"id":98,"version":99,"summary_zh":100,"released_at":101},264132,"v1.41.2","## 变更内容\n* 由 @azdaev 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1064 中为聊天完成请求添加了 Verbose 参数\n\n## 新贡献者\n* @azdaev 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1064 中完成了首次贡献\n\n**完整变更日志**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.41.1...v1.41.2","2025-09-12T09:44:28",{"id":103,"version":104,"summary_zh":105,"released_at":106},264133,"v1.41.1","## 变更内容\n* 功能新增：@liushuangls 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1066 中添加了 `safety_identifier` 参数\n\n\n**完整变更日志**：https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.41.0...v1.41.1","2025-08-12T10:05:47",{"id":108,"version":109,"summary_zh":110,"released_at":111},264134,"v1.41.0","## 变更内容\n* 由 @sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1040 中提升 jsonschema 的测试覆盖率\n* 由 @sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1041 中提高 files.go 的测试覆盖率\n* 由 @sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1042 中启用 Go 1.18 兼容性检查\n* 由 @AyushSawant18588 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F906 中为 embeddings API 添加 extra_body 参数支持\n* 由 @sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1043 中进一步提升 jsonschema 的测试覆盖率\n* 由 @sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1044 中为内部工具函数添加测试\n* 由 @AyushSawant18588 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1034 中将 GuidedChoice 添加到 ChatCompletionRequest 中\n* fix(chat): 缩短注释以通过 linter 检查，由 @sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1050 中完成\n* 由 @behzadsp 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1062 中添加 GPT-5 模型常量及推理验证逻辑\n\n## 新贡献者\n* @behzadsp 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1062 中完成了首次贡献\n\n**完整变更日志**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.40.5...v1.41.0","2025-08-11T09:18:54",{"id":113,"version":114,"summary_zh":115,"released_at":116},264135,"v1.40.5","## 变更内容\n* 通过 @eiixy 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1030 中实现了对 JSON Schema 中 $ref 和 $defs 的支持\n* 由 @sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1032 中提升了单元测试覆盖率\n* 由 @eiixy 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1033 中移除了 GenerateSchemaForType 中的根级 $ref\n* 由 @sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1036 中进一步提高测试覆盖率\n* 由 @sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1038 中配置 Codecov 忽略示例和测试辅助文件\n* 由 @sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1039 中将 image.go 的测试覆盖率提升至 100%\n\n\n**完整变更日志**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.40.4...v1.40.5","2025-07-11T15:19:46",{"id":118,"version":119,"summary_zh":120,"released_at":121},264136,"v1.40.4","## 变更内容\n* 修复：在 ChatCompletionResponseFormatJSONSchema.schema 中正确地反序列化 JSON 模式，由 @eiixy 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1028 中完成\n* 添加对聊天完成服务层级的支持，由 @mathewtinsley 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1023 中完成\n\n## 新贡献者\n* @mathewtinsley 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1023 中完成了首次贡献\n\n**完整变更日志**：https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.40.3...v1.40.4","2025-07-08T11:25:25",{"id":123,"version":124,"summary_zh":125,"released_at":126},264137,"v1.40.3","## 变更内容\n* 测试：增强错误累加器和表单构建器的测试，并由 @Whitea029 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F999 中添加了 marshaller 测试。\n* 修复：移除每次流式响应块中的 usage 字段。由 @Hritik003 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1022 中完成。\n\n## 新贡献者\n* @Whitea029 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F999 中完成了首次贡献。\n* @Hritik003 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1022 中完成了首次贡献。\n\n**完整变更日志**：https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.40.2...v1.40.3","2025-06-25T10:07:22",{"id":128,"version":129,"summary_zh":130,"released_at":131},264138,"v1.40.2","## 变更内容\n* 由 @Axb12 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1017 中修复了图像 API 缺少文件名的 bug\n\n\n**完整变更日志**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.40.1...v1.40.2","2025-06-16T19:09:28",{"id":133,"version":134,"summary_zh":135,"released_at":136},264139,"v1.40.1","## 变更内容\n* 将图片 API 中的 `*os.File` 更新为 `io.Reader`，由 @Axb12 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F994 中完成\n* 跳过 JSON 字段，由 @jtarchie 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F1009 中完成\n\n## 新贡献者\n* @Axb12 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F994 中完成了首次贡献\n\n**完整变更日志**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.40.0...v1.40.1","2025-05-29T11:11:46",{"id":138,"version":139,"summary_zh":140,"released_at":141},264140,"v1.40.0","## 变更内容\n* 由 @sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F987 中修复 Codecov\n* 由 @sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F996 中移除 golangci-lint 备份文件\n* 功能：由 @PChaparro 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F971 中添加对 `gpt-image-1` 图像生成的支持\n* 向 ChatCompletionRequest 添加 ChatTemplateKwargs，由 @justa-cai 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F980 中完成\n* 由 @sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F998 中修复 linter 问题\n\n## 新贡献者\n* @PChaparro 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F971 中完成了首次贡献\n* @justa-cai 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F980 中完成了首次贡献\n\n**完整变更日志**：https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.39.1...v1.40.0","2025-05-13T16:46:45",{"id":143,"version":144,"summary_zh":145,"released_at":146},264141,"v1.39.1","## 变更内容\n* 修复：@bakatz 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F981 中修正了 o4-mini 模型名称中的拼写错误，并修复了端点映射。\n* 提升单元测试覆盖率：@sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F984 中完成。\n* 将 golangci-lint 升级至 2.1.5：@sashabaranov 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F986 中完成。\n\n## 新贡献者\n* @bakatz 在 https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F981 中完成了首次贡献。\n\n**完整变更日志**：https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.39.0...v1.39.1","2025-05-03T21:41:10",{"id":148,"version":149,"summary_zh":150,"released_at":151},264142,"v1.39.0","## What's Changed\r\n* Add support for reasoning_content field in chat completion messages for DeepSeek R1 by @goodenough227 in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F925\r\n* Adapt different stream data prefix, with or without space by @panzhongxian in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F945\r\n* Add support for `o4-mini` and `o3` by @rorymalcolm in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F968\r\n* Add CompletionRequest.StreamOptions by @stmcginnis in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F959\r\n* Remove redundant typecheck linter by @alexandear in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F955\r\n* Add Prediction field by @danielpeng2 in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F970\r\n\r\n## New Contributors\r\n* @goodenough227 made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F925\r\n* @panzhongxian made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F945\r\n* @stmcginnis made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F959\r\n* @danielpeng2 made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F970\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.38.3...v1.39.0","2025-04-29T13:40:20",{"id":153,"version":154,"summary_zh":155,"released_at":156},264143,"v1.38.3","## What's Changed\r\n* feat: add new GPT-4.1 model variants to completion.go by @iktakahiro in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F966\r\n* feat: Add missing TTS models and voices by @netr in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F958\r\n\r\n## New Contributors\r\n* @netr made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F958\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.38.2...v1.38.3","2025-04-27T19:50:05",{"id":158,"version":159,"summary_zh":160,"released_at":161},264144,"v1.38.2","## What's Changed\r\n* add enum tag to jsonschema by @jtarchie in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F962\r\n\r\n## New Contributors\r\n* @jtarchie made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F962\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.38.1...v1.38.2","2025-04-17T08:46:50",{"id":163,"version":164,"summary_zh":165,"released_at":166},264145,"v1.38.1","## What's Changed\r\n* feat: add gpt-4.5-preview models by @liushuangls in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F947\r\n\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.38.0...v1.38.1","2025-03-20T19:13:33",{"id":168,"version":169,"summary_zh":170,"released_at":171},264146,"v1.38.0","## What's Changed\r\n* ref: add image url support to messages by @mazyaryousefinia in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F933\r\n* feat: add developer role by @liushuangls in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F936\r\n* fix: remove validateO1Specific by @liushuangls in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F939\r\n* feat: add Anthropic API support with custom version header by @danackerson in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F934\r\n* Fix linter by @sashabaranov in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F943\r\n\r\n## New Contributors\r\n* @mazyaryousefinia made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F933\r\n* @danackerson made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F934\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.37.0...v1.38.0","2025-02-25T17:23:05",{"id":173,"version":174,"summary_zh":175,"released_at":176},264147,"v1.37.0","## What's Changed\r\n* Simplify tests with T.TempDir by @alexandear in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F929\r\n* Chat Completion API: add ReasoningEffort and new o1 models by @trevorcreech in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F928\r\n* Make \"Content\" field in \"ChatCompletionMessage\" omitempty by @saileshd1402 in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F926\r\n* Add support for O3-mini by @rorymalcolm in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F930\r\n\r\n## New Contributors\r\n* @alexandear made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F929\r\n* @trevorcreech made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F928\r\n* @saileshd1402 made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F926\r\n* @rorymalcolm made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F930\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.36.1...v1.37.0","2025-02-06T14:54:15",{"id":178,"version":179,"summary_zh":180,"released_at":181},264148,"v1.36.1","## What's Changed\r\n* Fix ID field to be optional by @TimMisiak in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F911\r\n* Ignore test.mp3 by @sashabaranov in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F913\r\n* Added additional_messages by @sabuhigr in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F914\r\n\r\n## New Contributors\r\n* @TimMisiak made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F911\r\n* @sabuhigr made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F914\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.36.0...v1.36.1","2024-12-27T10:27:39",{"id":183,"version":184,"summary_zh":185,"released_at":186},264149,"v1.36.0","## What's Changed\r\n* Make user field optional in embedding request by @nagar-ajay in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F899\r\n* feat: add gpt-4o-2024-11-20 model by @liushuangls in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F905\r\n* feat: add RecvRaw by @WqyJh in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F896\r\n\r\n## New Contributors\r\n* @nagar-ajay made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F899\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.35.7...v1.36.0","2024-11-30T10:36:27",{"id":188,"version":189,"summary_zh":190,"released_at":191},264150,"v1.35.7","## What's Changed\r\n* Updated client_test to solve lint error by @AyushSawant18588 in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F900\r\n* o1 model support stream by @ldnvnbl and @handsomefox in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F904 and https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F902\r\n\r\n## New Contributors\r\n* @ldnvnbl made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F904\r\n* @handsomefox made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F902\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.35.6...v1.35.7","2024-11-20T20:37:24",{"id":193,"version":194,"summary_zh":195,"released_at":196},264151,"v1.35.6","## What's Changed\r\n* Added Vector Store File List properties that allow for pagination by @MattDavisRV in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F891\r\n* Support Attachments in MessageRequest by @kodernubie in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F890\r\n\r\n## New Contributors\r\n* @MattDavisRV made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F891\r\n* @kodernubie made their first contribution in https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fpull\u002F890\r\n\r\n**Full Changelog**: https:\u002F\u002Fgithub.com\u002Fsashabaranov\u002Fgo-openai\u002Fcompare\u002Fv1.32.5...v1.35.6","2024-11-08T13:54:45",[198,208,217,225,234,242],{"id":199,"name":200,"github_repo":201,"description_zh":202,"stars":203,"difficulty_score":56,"last_commit_at":204,"category_tags":205,"status":57},1381,"everything-claude-code","affaan-m\u002Feverything-claude-code","everything-claude-code 是一套专为 AI 编程助手（如 Claude Code、Codex、Cursor 等）打造的高性能优化系统。它不仅仅是一组配置文件，而是一个经过长期实战打磨的完整框架，旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。\n\n通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能，everything-claude-code 能显著提升 AI 在复杂任务中的表现，帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略，使得模型响应更快、成本更低，同时有效防御潜在的攻击向量。\n\n这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库，还是需要 AI 协助进行安全审计与自动化测试，everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目，它融合了多语言支持与丰富的实战钩子（hooks），让 AI 真正成长为懂上",156033,"2026-04-14T23:32:00",[206,207,42],"开发框架","Agent",{"id":209,"name":210,"github_repo":211,"description_zh":212,"stars":213,"difficulty_score":56,"last_commit_at":214,"category_tags":215,"status":57},6121,"gemini-cli","google-gemini\u002Fgemini-cli","gemini-cli 是一款由谷歌推出的开源 AI 命令行工具，它将强大的 Gemini 大模型能力直接集成到用户的终端环境中。对于习惯在命令行工作的开发者而言，它提供了一条从输入提示词到获取模型响应的最短路径，无需切换窗口即可享受智能辅助。\n\n这款工具主要解决了开发过程中频繁上下文切换的痛点，让用户能在熟悉的终端界面内直接完成代码理解、生成、调试以及自动化运维任务。无论是查询大型代码库、根据草图生成应用，还是执行复杂的 Git 操作，gemini-cli 都能通过自然语言指令高效处理。\n\n它特别适合广大软件工程师、DevOps 人员及技术研究人员使用。其核心亮点包括支持高达 100 万 token 的超长上下文窗口，具备出色的逻辑推理能力；内置 Google 搜索、文件操作及 Shell 命令执行等实用工具；更独特的是，它支持 MCP（模型上下文协议），允许用户灵活扩展自定义集成，连接如图像生成等外部能力。此外，个人谷歌账号即可享受免费的额度支持，且项目基于 Apache 2.0 协议完全开源，是提升终端工作效率的理想助手。",100752,"2026-04-10T01:20:03",[41,207,216,206],"图像",{"id":218,"name":219,"github_repo":220,"description_zh":221,"stars":222,"difficulty_score":56,"last_commit_at":223,"category_tags":224,"status":57},4721,"markitdown","microsoft\u002Fmarkitdown","MarkItDown 是一款由微软 AutoGen 团队打造的轻量级 Python 工具，专为将各类文件高效转换为 Markdown 格式而设计。它支持 PDF、Word、Excel、PPT、图片（含 OCR）、音频（含语音转录）、HTML 乃至 YouTube 链接等多种格式的解析，能够精准提取文档中的标题、列表、表格和链接等关键结构信息。\n\n在人工智能应用日益普及的今天，大语言模型（LLM）虽擅长处理文本，却难以直接读取复杂的二进制办公文档。MarkItDown 恰好解决了这一痛点，它将非结构化或半结构化的文件转化为模型“原生理解”且 Token 效率极高的 Markdown 格式，成为连接本地文件与 AI 分析 pipeline 的理想桥梁。此外，它还提供了 MCP（模型上下文协议）服务器，可无缝集成到 Claude Desktop 等 LLM 应用中。\n\n这款工具特别适合开发者、数据科学家及 AI 研究人员使用，尤其是那些需要构建文档检索增强生成（RAG）系统、进行批量文本分析或希望让 AI 助手直接“阅读”本地文件的用户。虽然生成的内容也具备一定可读性，但其核心优势在于为机器",93400,"2026-04-06T19:52:38",[41,206],{"id":226,"name":227,"github_repo":228,"description_zh":229,"stars":230,"difficulty_score":231,"last_commit_at":232,"category_tags":233,"status":57},4487,"LLMs-from-scratch","rasbt\u002FLLMs-from-scratch","LLMs-from-scratch 是一个基于 PyTorch 的开源教育项目，旨在引导用户从零开始一步步构建一个类似 ChatGPT 的大型语言模型（LLM）。它不仅是同名技术著作的官方代码库，更提供了一套完整的实践方案，涵盖模型开发、预训练及微调的全过程。\n\n该项目主要解决了大模型领域“黑盒化”的学习痛点。许多开发者虽能调用现成模型，却难以深入理解其内部架构与训练机制。通过亲手编写每一行核心代码，用户能够透彻掌握 Transformer 架构、注意力机制等关键原理，从而真正理解大模型是如何“思考”的。此外，项目还包含了加载大型预训练权重进行微调的代码，帮助用户将理论知识延伸至实际应用。\n\nLLMs-from-scratch 特别适合希望深入底层原理的 AI 开发者、研究人员以及计算机专业的学生。对于不满足于仅使用 API，而是渴望探究模型构建细节的技术人员而言，这是极佳的学习资源。其独特的技术亮点在于“循序渐进”的教学设计：将复杂的系统工程拆解为清晰的步骤，配合详细的图表与示例，让构建一个虽小但功能完备的大模型变得触手可及。无论你是想夯实理论基础，还是为未来研发更大规模的模型做准备",90106,3,"2026-04-06T11:19:32",[42,216,207,206],{"id":235,"name":236,"github_repo":237,"description_zh":238,"stars":239,"difficulty_score":56,"last_commit_at":240,"category_tags":241,"status":57},3704,"NextChat","ChatGPTNextWeb\u002FNextChat","NextChat 是一款轻量且极速的 AI 助手，旨在为用户提供流畅、跨平台的大模型交互体验。它完美解决了用户在多设备间切换时难以保持对话连续性，以及面对众多 AI 模型不知如何统一管理的痛点。无论是日常办公、学习辅助还是创意激发，NextChat 都能让用户随时随地通过网页、iOS、Android、Windows、MacOS 或 Linux 端无缝接入智能服务。\n\n这款工具非常适合普通用户、学生、职场人士以及需要私有化部署的企业团队使用。对于开发者而言，它也提供了便捷的自托管方案，支持一键部署到 Vercel 或 Zeabur 等平台。\n\nNextChat 的核心亮点在于其广泛的模型兼容性，原生支持 Claude、DeepSeek、GPT-4 及 Gemini Pro 等主流大模型，让用户在一个界面即可自由切换不同 AI 能力。此外，它还率先支持 MCP（Model Context Protocol）协议，增强了上下文处理能力。针对企业用户，NextChat 提供专业版解决方案，具备品牌定制、细粒度权限控制、内部知识库整合及安全审计等功能，满足公司对数据隐私和个性化管理的高标准要求。",87618,"2026-04-05T07:20:52",[206,42],{"id":243,"name":244,"github_repo":245,"description_zh":246,"stars":247,"difficulty_score":56,"last_commit_at":248,"category_tags":249,"status":57},2268,"ML-For-Beginners","microsoft\u002FML-For-Beginners","ML-For-Beginners 是由微软推出的一套系统化机器学习入门课程，旨在帮助零基础用户轻松掌握经典机器学习知识。这套课程将学习路径规划为 12 周，包含 26 节精炼课程和 52 道配套测验，内容涵盖从基础概念到实际应用的完整流程，有效解决了初学者面对庞大知识体系时无从下手、缺乏结构化指导的痛点。\n\n无论是希望转型的开发者、需要补充算法背景的研究人员，还是对人工智能充满好奇的普通爱好者，都能从中受益。课程不仅提供了清晰的理论讲解，还强调动手实践，让用户在循序渐进中建立扎实的技能基础。其独特的亮点在于强大的多语言支持，通过自动化机制提供了包括简体中文在内的 50 多种语言版本，极大地降低了全球不同背景用户的学习门槛。此外，项目采用开源协作模式，社区活跃且内容持续更新，确保学习者能获取前沿且准确的技术资讯。如果你正寻找一条清晰、友好且专业的机器学习入门之路，ML-For-Beginners 将是理想的起点。",85092,"2026-04-10T11:13:16",[216,250,251,41,207,252,42,206,43],"数据工具","视频","其他"]