Repository: sashabaranov/go-openai
Pull request #150 (2023-03-13 10:25:18)

fix issue #149
fix issue #149


Patch:
diff --git a/image.go b/image.go
index b9fde5a..8f04572 100644
--- a/image.go
+++ b/image.go
@@ -86,20 +86,64 @@ func (c *Client) CreateEditImage(ctx context.Context, request ImageEditRequest)
 		return
 	}
 
-	// mask
-	mask, err := writer.CreateFormFile("mask", request.Mask.Name())
+	// mask, it is optional
+	if request.Mask != nil {
+		mask, err2 := writer.CreateFormFile("mask", request.Mask.Name())
+		if err2 != nil {
+			return
+		}
+		_, err = io.Copy(mask, request.Mask)
+		if err != nil {
+			return
+		}
+	}
+
+	err = writer.WriteField("prompt", request.Prompt)
+	if err != nil {
+		return
+	}
+	err = writer.WriteField("n", strconv.Itoa(request.N))
+	if err != nil {
+		return
+	}
+	err = writer.WriteField("size", request.Size)
 	if err != nil {
 		return
 	}
-	_, err = io.Copy(mask, request.Mask)
+	writer.Close()
+	urlSuffix := "/images/edits"
+	req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.fullURL(urlSuffix), body)
 	if err != nil {
 		return
 	}
 
-	err = writer.WriteField("prompt", request.Prompt)
+	req.Header.Set("Content-Type", writer.FormDataContentType())
+	err = c.sendRequest(req, &response)
+	return
+}
+
+// ImageVariationRequest represents the request structure for the image API.
+type ImageVariationRequest struct {
+	Image *os.File `json:"image,omitempty"`
+	N     int      `json:"n,omitempty"`
+	Size  string   `json:"size,omitempty"`
+}
+
+// ImageVariationRequest - API call to create an image variation. This is the main endpoint of the DALL-E API.
+func (c *Client) CreateVariateImage(ctx context.Context, request ImageVariationRequest) (response ImageResponse, err error) {
+	body := &bytes.Buffer{}
+	writer := multipart.NewWriter(body)
+
+	// image
+	image, err := writer.CreateFormFile("image", request.Image.Name())
+	if err != nil {
+		return
+	}
+	_, err = io.Copy(image, request.Image)
 	if err != nil {
 		return
 	}
+
 	err = writer.WriteField("n", strconv.Itoa(request.N))
 	if err != nil {
 		return


Test patch:
diff --git a/image_test.go b/image_test.go
index db558e0..95dded8 100644
--- a/image_test.go
+++ b/image_test.go
@@ -132,6 +132,43 @@ func TestImageEdit(t *testing.T) {
 	}
 }
 
+func TestImageEditWithoutMask(t *testing.T) {
+	server := test.NewTestServer()
+	server.RegisterHandler("/v1/images/edits", handleEditImageEndpoint)
+	// create the test server
+	var err error
+	ts := server.OpenAITestServer()
+	ts.Start()
+	defer ts.Close()
+
+	config := DefaultConfig(test.GetTestToken())
+	config.BaseURL = ts.URL + "/v1"
+	client := NewClientWithConfig(config)
+	ctx := context.Background()
+
+	origin, err := os.Create("image.png")
+	if err != nil {
+		t.Error("open origin file error")
+		return
+	}
+
+	defer func() {
+		origin.Close()
+		os.Remove("image.png")
+	}()
+
+	req := ImageEditRequest{
+		Image:  origin,
+		Prompt: "There is a turtle in the pool",
+		N:      3,
+		Size:   CreateImageSize1024x1024,
+	}
+	_, err = client.CreateEditImage(ctx, req)
+	if err != nil {
+		t.Fatalf("CreateImage error: %v", err)
+	}
+}
+
 // handleEditImageEndpoint Handles the images endpoint by the test server.
 func handleEditImageEndpoint(w http.ResponseWriter, r *http.Request) {
 	var resBytes []byte
@@ -162,3 +199,71 @@ func handleEditImageEndpoint(w http.ResponseWriter, r *http.Request) {
 	resBytes, _ = json.Marshal(responses)
 	fmt.Fprintln(w, string(resBytes))
 }
+
+
+func TestImageVariation(t *testing.T) {
+	server := test.NewTestServer()
+	server.RegisterHandler("/v1/images/edits", handleVariateImageEndpoint)
+	// create the test server
+	var err error
+	ts := server.OpenAITestServer()
+	ts.Start()
+	defer ts.Close()
+
+	config := DefaultConfig(test.GetTestToken())
+	config.BaseURL = ts.URL + "/v1"
+	client := NewClientWithConfig(config)
+	ctx := context.Background()
+
+	origin, err := os.Create("image.png")
+	if err != nil {
+		t.Error("open origin file error")
+		return
+	}
+
+	defer func() {
+		origin.Close()
+		os.Remove("image.png")
+	}()
+
+	req := ImageVariationRequest{
+		Image:  origin,
+		N:      3,
+		Size:   CreateImageSize1024x1024,
+	}
+	_, err = client.CreateVariateImage(ctx, req)
+	if err != nil {
+		t.Fatalf("CreateImage error: %v", err)
+	}
+}
+
+// handleVariateImageEndpoint Handles the images endpoint by the test server.
+func handleVariateImageEndpoint(w http.ResponseWriter, r *http.Request) {
+	var resBytes []byte
+
+	// imagess only accepts POST requests
+	if r.Method != "POST" {
+		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+	}
+
+	responses := ImageResponse{
+		Created: time.Now().Unix(),
+		Data: []ImageResponseDataInner{
+			{
+				URL:     "test-url1",
+				B64JSON: "",
+			},
+			{
+				URL:     "test-url2",
+				B64JSON: "",
+			},
+			{
+				URL:     "test-url3",
+				B64JSON: "",
+			},
+		},
+	}
+
+	resBytes, _ = json.Marshal(responses)
+	fmt.Fprintln(w, string(resBytes))
+}