mirror of
https://github.com/woodchen-ink/Oapi-Feishu.git
synced 2025-07-18 05:42:08 +08:00
298 lines
6.7 KiB
Go
298 lines
6.7 KiB
Go
package openai
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"image"
|
|
"image/jpeg"
|
|
"image/png"
|
|
"io"
|
|
"mime/multipart"
|
|
"os"
|
|
)
|
|
|
|
type ImageGenerationRequestBody struct {
|
|
Prompt string `json:"prompt"`
|
|
N int `json:"n"`
|
|
Size string `json:"size"`
|
|
ResponseFormat string `json:"response_format"`
|
|
}
|
|
|
|
type ImageResponseBody struct {
|
|
Created int64 `json:"created"`
|
|
Data []struct {
|
|
Base64Json string `json:"b64_json"`
|
|
} `json:"data"`
|
|
}
|
|
|
|
type ImageVariantRequestBody struct {
|
|
Image string `json:"image"`
|
|
N int `json:"n"`
|
|
Size string `json:"size"`
|
|
ResponseFormat string `json:"response_format"`
|
|
}
|
|
|
|
func (gpt *ChatGPT) GenerateImage(prompt string, size string,
|
|
n int) ([]string, error) {
|
|
requestBody := ImageGenerationRequestBody{
|
|
Prompt: prompt,
|
|
N: n,
|
|
Size: size,
|
|
ResponseFormat: "b64_json",
|
|
}
|
|
|
|
imageResponseBody := &ImageResponseBody{}
|
|
err := gpt.sendRequestWithBodyType(gpt.ApiUrl+"/v1/images/generations",
|
|
"POST", jsonBody, requestBody, imageResponseBody)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var b64Pool []string
|
|
for _, data := range imageResponseBody.Data {
|
|
b64Pool = append(b64Pool, data.Base64Json)
|
|
}
|
|
return b64Pool, nil
|
|
}
|
|
|
|
func (gpt *ChatGPT) GenerateOneImage(prompt string,
|
|
size string) (string, error) {
|
|
b64s, err := gpt.GenerateImage(prompt, size, 1)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return b64s[0], nil
|
|
}
|
|
|
|
func (gpt *ChatGPT) GenerateOneImageWithDefaultSize(
|
|
prompt string) (string, error) {
|
|
return gpt.GenerateOneImage(prompt, "512x512")
|
|
}
|
|
|
|
func (gpt *ChatGPT) GenerateImageVariation(images string,
|
|
size string, n int) ([]string, error) {
|
|
requestBody := ImageVariantRequestBody{
|
|
Image: images,
|
|
N: n,
|
|
Size: size,
|
|
ResponseFormat: "b64_json",
|
|
}
|
|
|
|
imageResponseBody := &ImageResponseBody{}
|
|
err := gpt.sendRequestWithBodyType(gpt.ApiUrl+"/v1/images/variations",
|
|
"POST", formPictureDataBody, requestBody, imageResponseBody)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var b64Pool []string
|
|
for _, data := range imageResponseBody.Data {
|
|
b64Pool = append(b64Pool, data.Base64Json)
|
|
}
|
|
return b64Pool, nil
|
|
}
|
|
|
|
func (gpt *ChatGPT) GenerateOneImageVariation(images string,
|
|
size string) (string, error) {
|
|
b64s, err := gpt.GenerateImageVariation(images, size, 1)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return b64s[0], nil
|
|
}
|
|
|
|
func pictureMultipartForm(request ImageVariantRequestBody,
|
|
w *multipart.Writer) error {
|
|
|
|
f, err := os.Open(request.Image)
|
|
if err != nil {
|
|
return fmt.Errorf("opening audio file: %w", err)
|
|
}
|
|
fw, err := w.CreateFormFile("image", f.Name())
|
|
if err != nil {
|
|
return fmt.Errorf("creating form file: %w", err)
|
|
}
|
|
if _, err = io.Copy(fw, f); err != nil {
|
|
return fmt.Errorf("reading from opened audio file: %w", err)
|
|
}
|
|
|
|
err = w.WriteField("size", request.Size)
|
|
if err != nil {
|
|
return fmt.Errorf("writing size: %w", err)
|
|
}
|
|
|
|
err = w.WriteField("n", fmt.Sprintf("%d", request.N))
|
|
if err != nil {
|
|
return fmt.Errorf("writing n: %w", err)
|
|
}
|
|
|
|
err = w.WriteField("response_format", request.ResponseFormat)
|
|
if err != nil {
|
|
return fmt.Errorf("writing response_format: %w", err)
|
|
}
|
|
|
|
//err = w.WriteField("user", "user123456")
|
|
|
|
//fw, err = w.CreateFormField("model")
|
|
//if err != nil {
|
|
// return fmt.Errorf("creating form field: %w", err)
|
|
//}
|
|
//modelName := bytes.NewReader([]byte(request.Model))
|
|
//if _, err = io.Copy(fw, modelName); err != nil {
|
|
// return fmt.Errorf("writing model name: %w", err)
|
|
//}
|
|
|
|
//fmt.Printf("w.FormDataContentType(): %s ", w.FormDataContentType())
|
|
|
|
w.Close()
|
|
|
|
return nil
|
|
}
|
|
|
|
func VerifyPngs(pngPaths []string) error {
|
|
foundPng := false
|
|
var expectedWidth, expectedHeight int
|
|
|
|
for _, pngPath := range pngPaths {
|
|
f, err := os.Open(pngPath)
|
|
if err != nil {
|
|
return fmt.Errorf("os.Open: %v", err)
|
|
}
|
|
|
|
fi, err := f.Stat()
|
|
if err != nil {
|
|
return fmt.Errorf("f.Stat: %v", err)
|
|
}
|
|
if fi.Size() > 4*1024*1024 {
|
|
return fmt.Errorf("image size too large, "+
|
|
"must be under %d MB", 4)
|
|
}
|
|
|
|
image, err := png.Decode(f)
|
|
if err != nil {
|
|
return fmt.Errorf("image must be valid png, got error: %v", err)
|
|
}
|
|
width := image.Bounds().Dx()
|
|
height := image.Bounds().Dy()
|
|
if width != height {
|
|
return fmt.Errorf("found non-square image with dimensions %dx%d", width, height)
|
|
}
|
|
|
|
if !foundPng {
|
|
foundPng = true
|
|
expectedWidth = width
|
|
expectedHeight = height
|
|
} else {
|
|
if width != expectedWidth || height != expectedHeight {
|
|
return fmt.Errorf("dimensions of all images must match, got both (%dx%d) and (%dx%d)", width, height, expectedWidth, expectedHeight)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func ConvertToRGBA(inputFilePath string, outputFilePath string) error {
|
|
// 打开输入文件
|
|
inputFile, err := os.Open(inputFilePath)
|
|
if err != nil {
|
|
return fmt.Errorf("打开文件时出错:%w", err)
|
|
}
|
|
defer inputFile.Close()
|
|
|
|
// 解码图像
|
|
img, _, err := image.Decode(inputFile)
|
|
if err != nil {
|
|
return fmt.Errorf("解码图像时出错:%w", err)
|
|
}
|
|
|
|
// 将图像转换为RGBA模式
|
|
rgba := image.NewRGBA(img.Bounds())
|
|
for x := 0; x < img.Bounds().Max.X; x++ {
|
|
for y := 0; y < img.Bounds().Max.Y; y++ {
|
|
rgba.Set(x, y, img.At(x, y))
|
|
}
|
|
}
|
|
|
|
// 创建输出文件
|
|
outputFile, err := os.Create(outputFilePath)
|
|
if err != nil {
|
|
return fmt.Errorf("创建输出文件时出错:%w", err)
|
|
}
|
|
defer outputFile.Close()
|
|
|
|
// 编码图像为 PNG 格式并写入输出文件
|
|
if err := png.Encode(outputFile, rgba); err != nil {
|
|
return fmt.Errorf("编码图像时出错:%w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func ConvertJpegToPNG(jpgPath string) error {
|
|
// Open the JPEG file for reading
|
|
f, err := os.Open(jpgPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
// Check if the file is a JPEG image
|
|
_, err = jpeg.Decode(f)
|
|
if err != nil {
|
|
// The file is not a JPEG image, no need to convert it
|
|
return fmt.Errorf("file %s is not a JPEG image", jpgPath)
|
|
}
|
|
|
|
// Reset the file pointer to the beginning of the file
|
|
_, err = f.Seek(0, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Create a new PNG file for writing
|
|
pngPath := jpgPath[:len(jpgPath)-4] + ".png" // replace .jpg extension with .png
|
|
out, err := os.Create(pngPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer out.Close()
|
|
|
|
// Decode the JPEG image and encode it as PNG
|
|
img, err := jpeg.Decode(f)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = png.Encode(out, img)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func GetImageCompressionType(path string) (string, error) {
|
|
// 打开文件
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer file.Close()
|
|
|
|
// 创建 bufio.Reader
|
|
reader := bufio.NewReader(file)
|
|
|
|
// 解码图像
|
|
_, format, err := image.DecodeConfig(reader)
|
|
if err != nil {
|
|
fmt.Println("err: ", err)
|
|
return "", err
|
|
}
|
|
|
|
fmt.Println("format: ", format)
|
|
// 返回压缩类型
|
|
return format, nil
|
|
}
|