Initialize module and dependencies
This commit is contained in:
31
go.mod
Normal file
31
go.mod
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
module github.com/chimerical-llc/odidere
|
||||||
|
|
||||||
|
go 1.25.5
|
||||||
|
|
||||||
|
tool (
|
||||||
|
golang.org/x/tools/cmd/deadcode
|
||||||
|
golang.org/x/tools/cmd/goimports
|
||||||
|
golang.org/x/vuln/cmd/govulncheck
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
|
github.com/sashabaranov/go-openai v1.41.2
|
||||||
|
golang.org/x/sync v0.19.0
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
golang.org/x/mod v0.32.0 // indirect
|
||||||
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
|
golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2 // indirect
|
||||||
|
golang.org/x/tools v0.41.0 // indirect
|
||||||
|
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated // indirect
|
||||||
|
golang.org/x/vuln v1.1.4 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
tool (
|
||||||
|
golang.org/x/tools/cmd/deadcode
|
||||||
|
golang.org/x/tools/cmd/goimports
|
||||||
|
golang.org/x/vuln/cmd/govulncheck
|
||||||
|
)
|
||||||
30
go.sum
Normal file
30
go.sum
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU=
|
||||||
|
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/sashabaranov/go-openai v1.41.2 h1:vfPRBZNMpnqu8ELsclWcAvF19lDNgh1t6TVfFFOPiSM=
|
||||||
|
github.com/sashabaranov/go-openai v1.41.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||||
|
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
|
||||||
|
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
|
||||||
|
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||||
|
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
|
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||||
|
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
|
golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2 h1:O1cMQHRfwNpDfDJerqRoE2oD+AFlyid87D40L/OkkJo=
|
||||||
|
golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8=
|
||||||
|
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
|
||||||
|
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
|
||||||
|
golang.org/x/tools/go/expect v0.1.0-deprecated h1:jY2C5HGYR5lqex3gEniOQL0r7Dq5+VGVgY1nudX5lXY=
|
||||||
|
golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
|
||||||
|
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
|
||||||
|
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8=
|
||||||
|
golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=
|
||||||
|
golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
41
vendor/github.com/google/uuid/CHANGELOG.md
generated
vendored
Normal file
41
vendor/github.com/google/uuid/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06))
|
||||||
|
* Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6))
|
||||||
|
|
||||||
|
## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29))
|
||||||
|
|
||||||
|
## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4))
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior)
|
||||||
|
|
||||||
|
## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0))
|
||||||
|
|
||||||
|
## Changelog
|
||||||
26
vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
Normal file
26
vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# How to contribute
|
||||||
|
|
||||||
|
We definitely welcome patches and contribution to this project!
|
||||||
|
|
||||||
|
### Tips
|
||||||
|
|
||||||
|
Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org).
|
||||||
|
|
||||||
|
Always try to include a test case! If it is not possible or not necessary,
|
||||||
|
please explain why in the pull request description.
|
||||||
|
|
||||||
|
### Releasing
|
||||||
|
|
||||||
|
Commits that would precipitate a SemVer change, as described in the Conventional
|
||||||
|
Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action)
|
||||||
|
to create a release candidate pull request. Once submitted, `release-please`
|
||||||
|
will create a release.
|
||||||
|
|
||||||
|
For tips on how to work with `release-please`, see its documentation.
|
||||||
|
|
||||||
|
### Legal requirements
|
||||||
|
|
||||||
|
In order to protect both you and ourselves, you will need to sign the
|
||||||
|
[Contributor License Agreement](https://cla.developers.google.com/clas).
|
||||||
|
|
||||||
|
You may have already signed it for other Google projects.
|
||||||
9
vendor/github.com/google/uuid/CONTRIBUTORS
generated
vendored
Normal file
9
vendor/github.com/google/uuid/CONTRIBUTORS
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Paul Borman <borman@google.com>
|
||||||
|
bmatsuo
|
||||||
|
shawnps
|
||||||
|
theory
|
||||||
|
jboverfelt
|
||||||
|
dsymonds
|
||||||
|
cd1
|
||||||
|
wallclockbuilder
|
||||||
|
dansouza
|
||||||
27
vendor/github.com/google/uuid/LICENSE
generated
vendored
Normal file
27
vendor/github.com/google/uuid/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2009,2014 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
21
vendor/github.com/google/uuid/README.md
generated
vendored
Normal file
21
vendor/github.com/google/uuid/README.md
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# uuid
|
||||||
|
The uuid package generates and inspects UUIDs based on
|
||||||
|
[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122)
|
||||||
|
and DCE 1.1: Authentication and Security Services.
|
||||||
|
|
||||||
|
This package is based on the github.com/pborman/uuid package (previously named
|
||||||
|
code.google.com/p/go-uuid). It differs from these earlier packages in that
|
||||||
|
a UUID is a 16 byte array rather than a byte slice. One loss due to this
|
||||||
|
change is the ability to represent an invalid UUID (vs a NIL UUID).
|
||||||
|
|
||||||
|
###### Install
|
||||||
|
```sh
|
||||||
|
go get github.com/google/uuid
|
||||||
|
```
|
||||||
|
|
||||||
|
###### Documentation
|
||||||
|
[](https://pkg.go.dev/github.com/google/uuid)
|
||||||
|
|
||||||
|
Full `go doc` style documentation for the package can be viewed online without
|
||||||
|
installing this package by using the GoDoc site here:
|
||||||
|
http://pkg.go.dev/github.com/google/uuid
|
||||||
80
vendor/github.com/google/uuid/dce.go
generated
vendored
Normal file
80
vendor/github.com/google/uuid/dce.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Domain represents a Version 2 domain
|
||||||
|
type Domain byte
|
||||||
|
|
||||||
|
// Domain constants for DCE Security (Version 2) UUIDs.
|
||||||
|
const (
|
||||||
|
Person = Domain(0)
|
||||||
|
Group = Domain(1)
|
||||||
|
Org = Domain(2)
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewDCESecurity returns a DCE Security (Version 2) UUID.
|
||||||
|
//
|
||||||
|
// The domain should be one of Person, Group or Org.
|
||||||
|
// On a POSIX system the id should be the users UID for the Person
|
||||||
|
// domain and the users GID for the Group. The meaning of id for
|
||||||
|
// the domain Org or on non-POSIX systems is site defined.
|
||||||
|
//
|
||||||
|
// For a given domain/id pair the same token may be returned for up to
|
||||||
|
// 7 minutes and 10 seconds.
|
||||||
|
func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
|
||||||
|
uuid, err := NewUUID()
|
||||||
|
if err == nil {
|
||||||
|
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
|
||||||
|
uuid[9] = byte(domain)
|
||||||
|
binary.BigEndian.PutUint32(uuid[0:], id)
|
||||||
|
}
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
|
||||||
|
// domain with the id returned by os.Getuid.
|
||||||
|
//
|
||||||
|
// NewDCESecurity(Person, uint32(os.Getuid()))
|
||||||
|
func NewDCEPerson() (UUID, error) {
|
||||||
|
return NewDCESecurity(Person, uint32(os.Getuid()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
|
||||||
|
// domain with the id returned by os.Getgid.
|
||||||
|
//
|
||||||
|
// NewDCESecurity(Group, uint32(os.Getgid()))
|
||||||
|
func NewDCEGroup() (UUID, error) {
|
||||||
|
return NewDCESecurity(Group, uint32(os.Getgid()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Domain returns the domain for a Version 2 UUID. Domains are only defined
|
||||||
|
// for Version 2 UUIDs.
|
||||||
|
func (uuid UUID) Domain() Domain {
|
||||||
|
return Domain(uuid[9])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2
|
||||||
|
// UUIDs.
|
||||||
|
func (uuid UUID) ID() uint32 {
|
||||||
|
return binary.BigEndian.Uint32(uuid[0:4])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Domain) String() string {
|
||||||
|
switch d {
|
||||||
|
case Person:
|
||||||
|
return "Person"
|
||||||
|
case Group:
|
||||||
|
return "Group"
|
||||||
|
case Org:
|
||||||
|
return "Org"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Domain%d", int(d))
|
||||||
|
}
|
||||||
12
vendor/github.com/google/uuid/doc.go
generated
vendored
Normal file
12
vendor/github.com/google/uuid/doc.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package uuid generates and inspects UUIDs.
|
||||||
|
//
|
||||||
|
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
|
||||||
|
// Services.
|
||||||
|
//
|
||||||
|
// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to
|
||||||
|
// maps or compared directly.
|
||||||
|
package uuid
|
||||||
59
vendor/github.com/google/uuid/hash.go
generated
vendored
Normal file
59
vendor/github.com/google/uuid/hash.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/sha1"
|
||||||
|
"hash"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Well known namespace IDs and UUIDs
|
||||||
|
var (
|
||||||
|
NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
Nil UUID // empty UUID, all zeros
|
||||||
|
|
||||||
|
// The Max UUID is special form of UUID that is specified to have all 128 bits set to 1.
|
||||||
|
Max = UUID{
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewHash returns a new UUID derived from the hash of space concatenated with
|
||||||
|
// data generated by h. The hash should be at least 16 byte in length. The
|
||||||
|
// first 16 bytes of the hash are used to form the UUID. The version of the
|
||||||
|
// UUID will be the lower 4 bits of version. NewHash is used to implement
|
||||||
|
// NewMD5 and NewSHA1.
|
||||||
|
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
||||||
|
h.Reset()
|
||||||
|
h.Write(space[:]) //nolint:errcheck
|
||||||
|
h.Write(data) //nolint:errcheck
|
||||||
|
s := h.Sum(nil)
|
||||||
|
var uuid UUID
|
||||||
|
copy(uuid[:], s)
|
||||||
|
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
|
||||||
|
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMD5 returns a new MD5 (Version 3) UUID based on the
|
||||||
|
// supplied name space and data. It is the same as calling:
|
||||||
|
//
|
||||||
|
// NewHash(md5.New(), space, data, 3)
|
||||||
|
func NewMD5(space UUID, data []byte) UUID {
|
||||||
|
return NewHash(md5.New(), space, data, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
|
||||||
|
// supplied name space and data. It is the same as calling:
|
||||||
|
//
|
||||||
|
// NewHash(sha1.New(), space, data, 5)
|
||||||
|
func NewSHA1(space UUID, data []byte) UUID {
|
||||||
|
return NewHash(sha1.New(), space, data, 5)
|
||||||
|
}
|
||||||
38
vendor/github.com/google/uuid/marshal.go
generated
vendored
Normal file
38
vendor/github.com/google/uuid/marshal.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// MarshalText implements encoding.TextMarshaler.
|
||||||
|
func (uuid UUID) MarshalText() ([]byte, error) {
|
||||||
|
var js [36]byte
|
||||||
|
encodeHex(js[:], uuid)
|
||||||
|
return js[:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
|
func (uuid *UUID) UnmarshalText(data []byte) error {
|
||||||
|
id, err := ParseBytes(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*uuid = id
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||||
|
func (uuid UUID) MarshalBinary() ([]byte, error) {
|
||||||
|
return uuid[:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||||
|
func (uuid *UUID) UnmarshalBinary(data []byte) error {
|
||||||
|
if len(data) != 16 {
|
||||||
|
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||||
|
}
|
||||||
|
copy(uuid[:], data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
90
vendor/github.com/google/uuid/node.go
generated
vendored
Normal file
90
vendor/github.com/google/uuid/node.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
nodeMu sync.Mutex
|
||||||
|
ifname string // name of interface being used
|
||||||
|
nodeID [6]byte // hardware for version 1 UUIDs
|
||||||
|
zeroID [6]byte // nodeID with only 0's
|
||||||
|
)
|
||||||
|
|
||||||
|
// NodeInterface returns the name of the interface from which the NodeID was
|
||||||
|
// derived. The interface "user" is returned if the NodeID was set by
|
||||||
|
// SetNodeID.
|
||||||
|
func NodeInterface() string {
|
||||||
|
defer nodeMu.Unlock()
|
||||||
|
nodeMu.Lock()
|
||||||
|
return ifname
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
|
||||||
|
// If name is "" then the first usable interface found will be used or a random
|
||||||
|
// Node ID will be generated. If a named interface cannot be found then false
|
||||||
|
// is returned.
|
||||||
|
//
|
||||||
|
// SetNodeInterface never fails when name is "".
|
||||||
|
func SetNodeInterface(name string) bool {
|
||||||
|
defer nodeMu.Unlock()
|
||||||
|
nodeMu.Lock()
|
||||||
|
return setNodeInterface(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setNodeInterface(name string) bool {
|
||||||
|
iname, addr := getHardwareInterface(name) // null implementation for js
|
||||||
|
if iname != "" && addr != nil {
|
||||||
|
ifname = iname
|
||||||
|
copy(nodeID[:], addr)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// We found no interfaces with a valid hardware address. If name
|
||||||
|
// does not specify a specific interface generate a random Node ID
|
||||||
|
// (section 4.1.6)
|
||||||
|
if name == "" {
|
||||||
|
ifname = "random"
|
||||||
|
randomBits(nodeID[:])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
|
||||||
|
// if not already set.
|
||||||
|
func NodeID() []byte {
|
||||||
|
defer nodeMu.Unlock()
|
||||||
|
nodeMu.Lock()
|
||||||
|
if nodeID == zeroID {
|
||||||
|
setNodeInterface("")
|
||||||
|
}
|
||||||
|
nid := nodeID
|
||||||
|
return nid[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
|
||||||
|
// of id are used. If id is less than 6 bytes then false is returned and the
|
||||||
|
// Node ID is not set.
|
||||||
|
func SetNodeID(id []byte) bool {
|
||||||
|
if len(id) < 6 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer nodeMu.Unlock()
|
||||||
|
nodeMu.Lock()
|
||||||
|
copy(nodeID[:], id)
|
||||||
|
ifname = "user"
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
|
||||||
|
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
|
||||||
|
func (uuid UUID) NodeID() []byte {
|
||||||
|
var node [6]byte
|
||||||
|
copy(node[:], uuid[10:])
|
||||||
|
return node[:]
|
||||||
|
}
|
||||||
12
vendor/github.com/google/uuid/node_js.go
generated
vendored
Normal file
12
vendor/github.com/google/uuid/node_js.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build js
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
// getHardwareInterface returns nil values for the JS version of the code.
|
||||||
|
// This removes the "net" dependency, because it is not used in the browser.
|
||||||
|
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
|
||||||
|
func getHardwareInterface(name string) (string, []byte) { return "", nil }
|
||||||
33
vendor/github.com/google/uuid/node_net.go
generated
vendored
Normal file
33
vendor/github.com/google/uuid/node_net.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !js
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
var interfaces []net.Interface // cached list of interfaces
|
||||||
|
|
||||||
|
// getHardwareInterface returns the name and hardware address of interface name.
|
||||||
|
// If name is "" then the name and hardware address of one of the system's
|
||||||
|
// interfaces is returned. If no interfaces are found (name does not exist or
|
||||||
|
// there are no interfaces) then "", nil is returned.
|
||||||
|
//
|
||||||
|
// Only addresses of at least 6 bytes are returned.
|
||||||
|
func getHardwareInterface(name string) (string, []byte) {
|
||||||
|
if interfaces == nil {
|
||||||
|
var err error
|
||||||
|
interfaces, err = net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, ifs := range interfaces {
|
||||||
|
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
|
||||||
|
return ifs.Name, ifs.HardwareAddr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
118
vendor/github.com/google/uuid/null.go
generated
vendored
Normal file
118
vendor/github.com/google/uuid/null.go
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
// Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"database/sql/driver"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var jsonNull = []byte("null")
|
||||||
|
|
||||||
|
// NullUUID represents a UUID that may be null.
|
||||||
|
// NullUUID implements the SQL driver.Scanner interface so
|
||||||
|
// it can be used as a scan destination:
|
||||||
|
//
|
||||||
|
// var u uuid.NullUUID
|
||||||
|
// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u)
|
||||||
|
// ...
|
||||||
|
// if u.Valid {
|
||||||
|
// // use u.UUID
|
||||||
|
// } else {
|
||||||
|
// // NULL value
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
type NullUUID struct {
|
||||||
|
UUID UUID
|
||||||
|
Valid bool // Valid is true if UUID is not NULL
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the SQL driver.Scanner interface.
|
||||||
|
func (nu *NullUUID) Scan(value interface{}) error {
|
||||||
|
if value == nil {
|
||||||
|
nu.UUID, nu.Valid = Nil, false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := nu.UUID.Scan(value)
|
||||||
|
if err != nil {
|
||||||
|
nu.Valid = false
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nu.Valid = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver Valuer interface.
|
||||||
|
func (nu NullUUID) Value() (driver.Value, error) {
|
||||||
|
if !nu.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
// Delegate to UUID Value function
|
||||||
|
return nu.UUID.Value()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||||
|
func (nu NullUUID) MarshalBinary() ([]byte, error) {
|
||||||
|
if nu.Valid {
|
||||||
|
return nu.UUID[:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||||
|
func (nu *NullUUID) UnmarshalBinary(data []byte) error {
|
||||||
|
if len(data) != 16 {
|
||||||
|
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||||
|
}
|
||||||
|
copy(nu.UUID[:], data)
|
||||||
|
nu.Valid = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements encoding.TextMarshaler.
|
||||||
|
func (nu NullUUID) MarshalText() ([]byte, error) {
|
||||||
|
if nu.Valid {
|
||||||
|
return nu.UUID.MarshalText()
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonNull, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
|
func (nu *NullUUID) UnmarshalText(data []byte) error {
|
||||||
|
id, err := ParseBytes(data)
|
||||||
|
if err != nil {
|
||||||
|
nu.Valid = false
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nu.UUID = id
|
||||||
|
nu.Valid = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
|
func (nu NullUUID) MarshalJSON() ([]byte, error) {
|
||||||
|
if nu.Valid {
|
||||||
|
return json.Marshal(nu.UUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonNull, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
|
func (nu *NullUUID) UnmarshalJSON(data []byte) error {
|
||||||
|
if bytes.Equal(data, jsonNull) {
|
||||||
|
*nu = NullUUID{}
|
||||||
|
return nil // valid null UUID
|
||||||
|
}
|
||||||
|
err := json.Unmarshal(data, &nu.UUID)
|
||||||
|
nu.Valid = err == nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
59
vendor/github.com/google/uuid/sql.go
generated
vendored
Normal file
59
vendor/github.com/google/uuid/sql.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Scan implements sql.Scanner so UUIDs can be read from databases transparently.
|
||||||
|
// Currently, database types that map to string and []byte are supported. Please
|
||||||
|
// consult database-specific driver documentation for matching types.
|
||||||
|
func (uuid *UUID) Scan(src interface{}) error {
|
||||||
|
switch src := src.(type) {
|
||||||
|
case nil:
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case string:
|
||||||
|
// if an empty UUID comes from a table, we return a null UUID
|
||||||
|
if src == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// see Parse for required string format
|
||||||
|
u, err := Parse(src)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Scan: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
*uuid = u
|
||||||
|
|
||||||
|
case []byte:
|
||||||
|
// if an empty UUID comes from a table, we return a null UUID
|
||||||
|
if len(src) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// assumes a simple slice of bytes if 16 bytes
|
||||||
|
// otherwise attempts to parse
|
||||||
|
if len(src) != 16 {
|
||||||
|
return uuid.Scan(string(src))
|
||||||
|
}
|
||||||
|
copy((*uuid)[:], src)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements sql.Valuer so that UUIDs can be written to databases
|
||||||
|
// transparently. Currently, UUIDs map to strings. Please consult
|
||||||
|
// database-specific driver documentation for matching types.
|
||||||
|
func (uuid UUID) Value() (driver.Value, error) {
|
||||||
|
return uuid.String(), nil
|
||||||
|
}
|
||||||
134
vendor/github.com/google/uuid/time.go
generated
vendored
Normal file
134
vendor/github.com/google/uuid/time.go
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
|
||||||
|
// 1582.
|
||||||
|
type Time int64
|
||||||
|
|
||||||
|
const (
|
||||||
|
lillian = 2299160 // Julian day of 15 Oct 1582
|
||||||
|
unix = 2440587 // Julian day of 1 Jan 1970
|
||||||
|
epoch = unix - lillian // Days between epochs
|
||||||
|
g1582 = epoch * 86400 // seconds between epochs
|
||||||
|
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
timeMu sync.Mutex
|
||||||
|
lasttime uint64 // last time we returned
|
||||||
|
clockSeq uint16 // clock sequence for this run
|
||||||
|
|
||||||
|
timeNow = time.Now // for testing
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnixTime converts t the number of seconds and nanoseconds using the Unix
|
||||||
|
// epoch of 1 Jan 1970.
|
||||||
|
func (t Time) UnixTime() (sec, nsec int64) {
|
||||||
|
sec = int64(t - g1582ns100)
|
||||||
|
nsec = (sec % 10000000) * 100
|
||||||
|
sec /= 10000000
|
||||||
|
return sec, nsec
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
|
||||||
|
// clock sequence as well as adjusting the clock sequence as needed. An error
|
||||||
|
// is returned if the current time cannot be determined.
|
||||||
|
func GetTime() (Time, uint16, error) {
|
||||||
|
defer timeMu.Unlock()
|
||||||
|
timeMu.Lock()
|
||||||
|
return getTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTime() (Time, uint16, error) {
|
||||||
|
t := timeNow()
|
||||||
|
|
||||||
|
// If we don't have a clock sequence already, set one.
|
||||||
|
if clockSeq == 0 {
|
||||||
|
setClockSequence(-1)
|
||||||
|
}
|
||||||
|
now := uint64(t.UnixNano()/100) + g1582ns100
|
||||||
|
|
||||||
|
// If time has gone backwards with this clock sequence then we
|
||||||
|
// increment the clock sequence
|
||||||
|
if now <= lasttime {
|
||||||
|
clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000
|
||||||
|
}
|
||||||
|
lasttime = now
|
||||||
|
return Time(now), clockSeq, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClockSequence returns the current clock sequence, generating one if not
|
||||||
|
// already set. The clock sequence is only used for Version 1 UUIDs.
|
||||||
|
//
|
||||||
|
// The uuid package does not use global static storage for the clock sequence or
|
||||||
|
// the last time a UUID was generated. Unless SetClockSequence is used, a new
|
||||||
|
// random clock sequence is generated the first time a clock sequence is
|
||||||
|
// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1)
|
||||||
|
func ClockSequence() int {
|
||||||
|
defer timeMu.Unlock()
|
||||||
|
timeMu.Lock()
|
||||||
|
return clockSequence()
|
||||||
|
}
|
||||||
|
|
||||||
|
func clockSequence() int {
|
||||||
|
if clockSeq == 0 {
|
||||||
|
setClockSequence(-1)
|
||||||
|
}
|
||||||
|
return int(clockSeq & 0x3fff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
|
||||||
|
// -1 causes a new sequence to be generated.
|
||||||
|
func SetClockSequence(seq int) {
|
||||||
|
defer timeMu.Unlock()
|
||||||
|
timeMu.Lock()
|
||||||
|
setClockSequence(seq)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setClockSequence(seq int) {
|
||||||
|
if seq == -1 {
|
||||||
|
var b [2]byte
|
||||||
|
randomBits(b[:]) // clock sequence
|
||||||
|
seq = int(b[0])<<8 | int(b[1])
|
||||||
|
}
|
||||||
|
oldSeq := clockSeq
|
||||||
|
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
|
||||||
|
if oldSeq != clockSeq {
|
||||||
|
lasttime = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
|
||||||
|
// uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs.
|
||||||
|
func (uuid UUID) Time() Time {
|
||||||
|
var t Time
|
||||||
|
switch uuid.Version() {
|
||||||
|
case 6:
|
||||||
|
time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110
|
||||||
|
t = Time(time)
|
||||||
|
case 7:
|
||||||
|
time := binary.BigEndian.Uint64(uuid[:8])
|
||||||
|
t = Time((time>>16)*10000 + g1582ns100)
|
||||||
|
default: // forward compatible
|
||||||
|
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
|
||||||
|
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
|
||||||
|
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
|
||||||
|
t = Time(time)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClockSequence returns the clock sequence encoded in uuid.
|
||||||
|
// The clock sequence is only well defined for version 1 and 2 UUIDs.
|
||||||
|
func (uuid UUID) ClockSequence() int {
|
||||||
|
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff
|
||||||
|
}
|
||||||
43
vendor/github.com/google/uuid/util.go
generated
vendored
Normal file
43
vendor/github.com/google/uuid/util.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// randomBits completely fills slice b with random data.
|
||||||
|
func randomBits(b []byte) {
|
||||||
|
if _, err := io.ReadFull(rander, b); err != nil {
|
||||||
|
panic(err.Error()) // rand should never fail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// xvalues returns the value of a byte as a hexadecimal digit or 255.
|
||||||
|
var xvalues = [256]byte{
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
}
|
||||||
|
|
||||||
|
// xtob converts hex characters x1 and x2 into a byte.
|
||||||
|
func xtob(x1, x2 byte) (byte, bool) {
|
||||||
|
b1 := xvalues[x1]
|
||||||
|
b2 := xvalues[x2]
|
||||||
|
return (b1 << 4) | b2, b1 != 255 && b2 != 255
|
||||||
|
}
|
||||||
365
vendor/github.com/google/uuid/uuid.go
generated
vendored
Normal file
365
vendor/github.com/google/uuid/uuid.go
generated
vendored
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
// Copyright 2018 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
||||||
|
// 4122.
|
||||||
|
type UUID [16]byte
|
||||||
|
|
||||||
|
// A Version represents a UUID's version.
|
||||||
|
type Version byte
|
||||||
|
|
||||||
|
// A Variant represents a UUID's variant.
|
||||||
|
type Variant byte
|
||||||
|
|
||||||
|
// Constants returned by Variant.
|
||||||
|
const (
|
||||||
|
Invalid = Variant(iota) // Invalid UUID
|
||||||
|
RFC4122 // The variant specified in RFC4122
|
||||||
|
Reserved // Reserved, NCS backward compatibility.
|
||||||
|
Microsoft // Reserved, Microsoft Corporation backward compatibility.
|
||||||
|
Future // Reserved for future definition.
|
||||||
|
)
|
||||||
|
|
||||||
|
const randPoolSize = 16 * 16
|
||||||
|
|
||||||
|
var (
|
||||||
|
rander = rand.Reader // random function
|
||||||
|
poolEnabled = false
|
||||||
|
poolMu sync.Mutex
|
||||||
|
poolPos = randPoolSize // protected with poolMu
|
||||||
|
pool [randPoolSize]byte // protected with poolMu
|
||||||
|
)
|
||||||
|
|
||||||
|
type invalidLengthError struct{ len int }
|
||||||
|
|
||||||
|
func (err invalidLengthError) Error() string {
|
||||||
|
return fmt.Sprintf("invalid UUID length: %d", err.len)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInvalidLengthError is matcher function for custom error invalidLengthError
|
||||||
|
func IsInvalidLengthError(err error) bool {
|
||||||
|
_, ok := err.(invalidLengthError)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse decodes s into a UUID or returns an error if it cannot be parsed. Both
|
||||||
|
// the standard UUID forms defined in RFC 4122
|
||||||
|
// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||||
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition,
|
||||||
|
// Parse accepts non-standard strings such as the raw hex encoding
|
||||||
|
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings,
|
||||||
|
// e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are
|
||||||
|
// examined in the latter case. Parse should not be used to validate strings as
|
||||||
|
// it parses non-standard encodings as indicated above.
|
||||||
|
func Parse(s string) (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
switch len(s) {
|
||||||
|
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
case 36:
|
||||||
|
|
||||||
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
case 36 + 9:
|
||||||
|
if !strings.EqualFold(s[:9], "urn:uuid:") {
|
||||||
|
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||||
|
}
|
||||||
|
s = s[9:]
|
||||||
|
|
||||||
|
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||||
|
case 36 + 2:
|
||||||
|
s = s[1:]
|
||||||
|
|
||||||
|
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
case 32:
|
||||||
|
var ok bool
|
||||||
|
for i := range uuid {
|
||||||
|
uuid[i], ok = xtob(s[i*2], s[i*2+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
default:
|
||||||
|
return uuid, invalidLengthError{len(s)}
|
||||||
|
}
|
||||||
|
// s is now at least 36 bytes long
|
||||||
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
for i, x := range [16]int{
|
||||||
|
0, 2, 4, 6,
|
||||||
|
9, 11,
|
||||||
|
14, 16,
|
||||||
|
19, 21,
|
||||||
|
24, 26, 28, 30, 32, 34,
|
||||||
|
} {
|
||||||
|
v, ok := xtob(s[x], s[x+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
uuid[i] = v
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
|
||||||
|
func ParseBytes(b []byte) (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
switch len(b) {
|
||||||
|
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) {
|
||||||
|
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
|
||||||
|
}
|
||||||
|
b = b[9:]
|
||||||
|
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||||
|
b = b[1:]
|
||||||
|
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
var ok bool
|
||||||
|
for i := 0; i < 32; i += 2 {
|
||||||
|
uuid[i/2], ok = xtob(b[i], b[i+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
default:
|
||||||
|
return uuid, invalidLengthError{len(b)}
|
||||||
|
}
|
||||||
|
// s is now at least 36 bytes long
|
||||||
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
for i, x := range [16]int{
|
||||||
|
0, 2, 4, 6,
|
||||||
|
9, 11,
|
||||||
|
14, 16,
|
||||||
|
19, 21,
|
||||||
|
24, 26, 28, 30, 32, 34,
|
||||||
|
} {
|
||||||
|
v, ok := xtob(b[x], b[x+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
uuid[i] = v
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustParse is like Parse but panics if the string cannot be parsed.
|
||||||
|
// It simplifies safe initialization of global variables holding compiled UUIDs.
|
||||||
|
func MustParse(s string) UUID {
|
||||||
|
uuid, err := Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(`uuid: Parse(` + s + `): ` + err.Error())
|
||||||
|
}
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
|
||||||
|
// does not have a length of 16. The bytes are copied from the slice.
|
||||||
|
func FromBytes(b []byte) (uuid UUID, err error) {
|
||||||
|
err = uuid.UnmarshalBinary(b)
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must returns uuid if err is nil and panics otherwise.
|
||||||
|
func Must(uuid UUID, err error) UUID {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate returns an error if s is not a properly formatted UUID in one of the following formats:
|
||||||
|
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||||
|
// It returns an error if the format is invalid, otherwise nil.
|
||||||
|
func Validate(s string) error {
|
||||||
|
switch len(s) {
|
||||||
|
// Standard UUID format
|
||||||
|
case 36:
|
||||||
|
|
||||||
|
// UUID with "urn:uuid:" prefix
|
||||||
|
case 36 + 9:
|
||||||
|
if !strings.EqualFold(s[:9], "urn:uuid:") {
|
||||||
|
return fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||||
|
}
|
||||||
|
s = s[9:]
|
||||||
|
|
||||||
|
// UUID enclosed in braces
|
||||||
|
case 36 + 2:
|
||||||
|
if s[0] != '{' || s[len(s)-1] != '}' {
|
||||||
|
return fmt.Errorf("invalid bracketed UUID format")
|
||||||
|
}
|
||||||
|
s = s[1 : len(s)-1]
|
||||||
|
|
||||||
|
// UUID without hyphens
|
||||||
|
case 32:
|
||||||
|
for i := 0; i < len(s); i += 2 {
|
||||||
|
_, ok := xtob(s[i], s[i+1])
|
||||||
|
if !ok {
|
||||||
|
return errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return invalidLengthError{len(s)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for standard UUID format
|
||||||
|
if len(s) == 36 {
|
||||||
|
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||||
|
return errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} {
|
||||||
|
if _, ok := xtob(s[x], s[x+1]); !ok {
|
||||||
|
return errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
// , or "" if uuid is invalid.
|
||||||
|
func (uuid UUID) String() string {
|
||||||
|
var buf [36]byte
|
||||||
|
encodeHex(buf[:], uuid)
|
||||||
|
return string(buf[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// URN returns the RFC 2141 URN form of uuid,
|
||||||
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
|
||||||
|
func (uuid UUID) URN() string {
|
||||||
|
var buf [36 + 9]byte
|
||||||
|
copy(buf[:], "urn:uuid:")
|
||||||
|
encodeHex(buf[9:], uuid)
|
||||||
|
return string(buf[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeHex(dst []byte, uuid UUID) {
|
||||||
|
hex.Encode(dst, uuid[:4])
|
||||||
|
dst[8] = '-'
|
||||||
|
hex.Encode(dst[9:13], uuid[4:6])
|
||||||
|
dst[13] = '-'
|
||||||
|
hex.Encode(dst[14:18], uuid[6:8])
|
||||||
|
dst[18] = '-'
|
||||||
|
hex.Encode(dst[19:23], uuid[8:10])
|
||||||
|
dst[23] = '-'
|
||||||
|
hex.Encode(dst[24:], uuid[10:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variant returns the variant encoded in uuid.
|
||||||
|
func (uuid UUID) Variant() Variant {
|
||||||
|
switch {
|
||||||
|
case (uuid[8] & 0xc0) == 0x80:
|
||||||
|
return RFC4122
|
||||||
|
case (uuid[8] & 0xe0) == 0xc0:
|
||||||
|
return Microsoft
|
||||||
|
case (uuid[8] & 0xe0) == 0xe0:
|
||||||
|
return Future
|
||||||
|
default:
|
||||||
|
return Reserved
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version returns the version of uuid.
|
||||||
|
func (uuid UUID) Version() Version {
|
||||||
|
return Version(uuid[6] >> 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Version) String() string {
|
||||||
|
if v > 15 {
|
||||||
|
return fmt.Sprintf("BAD_VERSION_%d", v)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("VERSION_%d", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Variant) String() string {
|
||||||
|
switch v {
|
||||||
|
case RFC4122:
|
||||||
|
return "RFC4122"
|
||||||
|
case Reserved:
|
||||||
|
return "Reserved"
|
||||||
|
case Microsoft:
|
||||||
|
return "Microsoft"
|
||||||
|
case Future:
|
||||||
|
return "Future"
|
||||||
|
case Invalid:
|
||||||
|
return "Invalid"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("BadVariant%d", int(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRand sets the random number generator to r, which implements io.Reader.
|
||||||
|
// If r.Read returns an error when the package requests random data then
|
||||||
|
// a panic will be issued.
|
||||||
|
//
|
||||||
|
// Calling SetRand with nil sets the random number generator to the default
|
||||||
|
// generator.
|
||||||
|
func SetRand(r io.Reader) {
|
||||||
|
if r == nil {
|
||||||
|
rander = rand.Reader
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rander = r
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableRandPool enables internal randomness pool used for Random
|
||||||
|
// (Version 4) UUID generation. The pool contains random bytes read from
|
||||||
|
// the random number generator on demand in batches. Enabling the pool
|
||||||
|
// may improve the UUID generation throughput significantly.
|
||||||
|
//
|
||||||
|
// Since the pool is stored on the Go heap, this feature may be a bad fit
|
||||||
|
// for security sensitive applications.
|
||||||
|
//
|
||||||
|
// Both EnableRandPool and DisableRandPool are not thread-safe and should
|
||||||
|
// only be called when there is no possibility that New or any other
|
||||||
|
// UUID Version 4 generation function will be called concurrently.
|
||||||
|
func EnableRandPool() {
|
||||||
|
poolEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableRandPool disables the randomness pool if it was previously
|
||||||
|
// enabled with EnableRandPool.
|
||||||
|
//
|
||||||
|
// Both EnableRandPool and DisableRandPool are not thread-safe and should
|
||||||
|
// only be called when there is no possibility that New or any other
|
||||||
|
// UUID Version 4 generation function will be called concurrently.
|
||||||
|
func DisableRandPool() {
|
||||||
|
poolEnabled = false
|
||||||
|
defer poolMu.Unlock()
|
||||||
|
poolMu.Lock()
|
||||||
|
poolPos = randPoolSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// UUIDs is a slice of UUID types.
|
||||||
|
type UUIDs []UUID
|
||||||
|
|
||||||
|
// Strings returns a string slice containing the string form of each UUID in uuids.
|
||||||
|
func (uuids UUIDs) Strings() []string {
|
||||||
|
var uuidStrs = make([]string, len(uuids))
|
||||||
|
for i, uuid := range uuids {
|
||||||
|
uuidStrs[i] = uuid.String()
|
||||||
|
}
|
||||||
|
return uuidStrs
|
||||||
|
}
|
||||||
44
vendor/github.com/google/uuid/version1.go
generated
vendored
Normal file
44
vendor/github.com/google/uuid/version1.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
|
||||||
|
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||||
|
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||||
|
// be set NewUUID returns nil. If clock sequence has not been set by
|
||||||
|
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||||
|
// return the current NewUUID returns nil and an error.
|
||||||
|
//
|
||||||
|
// In most cases, New should be used.
|
||||||
|
func NewUUID() (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
now, seq, err := GetTime()
|
||||||
|
if err != nil {
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
timeLow := uint32(now & 0xffffffff)
|
||||||
|
timeMid := uint16((now >> 32) & 0xffff)
|
||||||
|
timeHi := uint16((now >> 48) & 0x0fff)
|
||||||
|
timeHi |= 0x1000 // Version 1
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint32(uuid[0:], timeLow)
|
||||||
|
binary.BigEndian.PutUint16(uuid[4:], timeMid)
|
||||||
|
binary.BigEndian.PutUint16(uuid[6:], timeHi)
|
||||||
|
binary.BigEndian.PutUint16(uuid[8:], seq)
|
||||||
|
|
||||||
|
nodeMu.Lock()
|
||||||
|
if nodeID == zeroID {
|
||||||
|
setNodeInterface("")
|
||||||
|
}
|
||||||
|
copy(uuid[10:], nodeID[:])
|
||||||
|
nodeMu.Unlock()
|
||||||
|
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
76
vendor/github.com/google/uuid/version4.go
generated
vendored
Normal file
76
vendor/github.com/google/uuid/version4.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
// New creates a new random UUID or panics. New is equivalent to
|
||||||
|
// the expression
|
||||||
|
//
|
||||||
|
// uuid.Must(uuid.NewRandom())
|
||||||
|
func New() UUID {
|
||||||
|
return Must(NewRandom())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewString creates a new random UUID and returns it as a string or panics.
|
||||||
|
// NewString is equivalent to the expression
|
||||||
|
//
|
||||||
|
// uuid.New().String()
|
||||||
|
func NewString() string {
|
||||||
|
return Must(NewRandom()).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRandom returns a Random (Version 4) UUID.
|
||||||
|
//
|
||||||
|
// The strength of the UUIDs is based on the strength of the crypto/rand
|
||||||
|
// package.
|
||||||
|
//
|
||||||
|
// Uses the randomness pool if it was enabled with EnableRandPool.
|
||||||
|
//
|
||||||
|
// A note about uniqueness derived from the UUID Wikipedia entry:
|
||||||
|
//
|
||||||
|
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||||
|
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
||||||
|
// means the probability is about 0.00000000006 (6 × 10−11),
|
||||||
|
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||||
|
// year and having one duplicate.
|
||||||
|
func NewRandom() (UUID, error) {
|
||||||
|
if !poolEnabled {
|
||||||
|
return NewRandomFromReader(rander)
|
||||||
|
}
|
||||||
|
return newRandomFromPool()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader.
|
||||||
|
func NewRandomFromReader(r io.Reader) (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
_, err := io.ReadFull(r, uuid[:])
|
||||||
|
if err != nil {
|
||||||
|
return Nil, err
|
||||||
|
}
|
||||||
|
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||||
|
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRandomFromPool() (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
poolMu.Lock()
|
||||||
|
if poolPos == randPoolSize {
|
||||||
|
_, err := io.ReadFull(rander, pool[:])
|
||||||
|
if err != nil {
|
||||||
|
poolMu.Unlock()
|
||||||
|
return Nil, err
|
||||||
|
}
|
||||||
|
poolPos = 0
|
||||||
|
}
|
||||||
|
copy(uuid[:], pool[poolPos:(poolPos+16)])
|
||||||
|
poolPos += 16
|
||||||
|
poolMu.Unlock()
|
||||||
|
|
||||||
|
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||||
|
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
56
vendor/github.com/google/uuid/version6.go
generated
vendored
Normal file
56
vendor/github.com/google/uuid/version6.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright 2023 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import "encoding/binary"
|
||||||
|
|
||||||
|
// UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality.
|
||||||
|
// It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs.
|
||||||
|
// Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead.
|
||||||
|
//
|
||||||
|
// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6
|
||||||
|
//
|
||||||
|
// NewV6 returns a Version 6 UUID based on the current NodeID and clock
|
||||||
|
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||||
|
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||||
|
// be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by
|
||||||
|
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||||
|
// return the current NewV6 returns Nil and an error.
|
||||||
|
func NewV6() (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
now, seq, err := GetTime()
|
||||||
|
if err != nil {
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
0 1 2 3
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| time_high |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| time_mid | time_low_and_version |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|clk_seq_hi_res | clk_seq_low | node (0-1) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| node (2-5) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
*/
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint64(uuid[0:], uint64(now))
|
||||||
|
binary.BigEndian.PutUint16(uuid[8:], seq)
|
||||||
|
|
||||||
|
uuid[6] = 0x60 | (uuid[6] & 0x0F)
|
||||||
|
uuid[8] = 0x80 | (uuid[8] & 0x3F)
|
||||||
|
|
||||||
|
nodeMu.Lock()
|
||||||
|
if nodeID == zeroID {
|
||||||
|
setNodeInterface("")
|
||||||
|
}
|
||||||
|
copy(uuid[10:], nodeID[:])
|
||||||
|
nodeMu.Unlock()
|
||||||
|
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
104
vendor/github.com/google/uuid/version7.go
generated
vendored
Normal file
104
vendor/github.com/google/uuid/version7.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
// Copyright 2023 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UUID version 7 features a time-ordered value field derived from the widely
|
||||||
|
// implemented and well known Unix Epoch timestamp source,
|
||||||
|
// the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded.
|
||||||
|
// As well as improved entropy characteristics over versions 1 or 6.
|
||||||
|
//
|
||||||
|
// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7
|
||||||
|
//
|
||||||
|
// Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible.
|
||||||
|
//
|
||||||
|
// NewV7 returns a Version 7 UUID based on the current time(Unix Epoch).
|
||||||
|
// Uses the randomness pool if it was enabled with EnableRandPool.
|
||||||
|
// On error, NewV7 returns Nil and an error
|
||||||
|
func NewV7() (UUID, error) {
|
||||||
|
uuid, err := NewRandom()
|
||||||
|
if err != nil {
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
makeV7(uuid[:])
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch).
|
||||||
|
// it use NewRandomFromReader fill random bits.
|
||||||
|
// On error, NewV7FromReader returns Nil and an error.
|
||||||
|
func NewV7FromReader(r io.Reader) (UUID, error) {
|
||||||
|
uuid, err := NewRandomFromReader(r)
|
||||||
|
if err != nil {
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
makeV7(uuid[:])
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6])
|
||||||
|
// uuid[8] already has the right version number (Variant is 10)
|
||||||
|
// see function NewV7 and NewV7FromReader
|
||||||
|
func makeV7(uuid []byte) {
|
||||||
|
/*
|
||||||
|
0 1 2 3
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| unix_ts_ms |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| unix_ts_ms | ver | rand_a (12 bit seq) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|var| rand_b |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| rand_b |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
*/
|
||||||
|
_ = uuid[15] // bounds check
|
||||||
|
|
||||||
|
t, s := getV7Time()
|
||||||
|
|
||||||
|
uuid[0] = byte(t >> 40)
|
||||||
|
uuid[1] = byte(t >> 32)
|
||||||
|
uuid[2] = byte(t >> 24)
|
||||||
|
uuid[3] = byte(t >> 16)
|
||||||
|
uuid[4] = byte(t >> 8)
|
||||||
|
uuid[5] = byte(t)
|
||||||
|
|
||||||
|
uuid[6] = 0x70 | (0x0F & byte(s>>8))
|
||||||
|
uuid[7] = byte(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// lastV7time is the last time we returned stored as:
|
||||||
|
//
|
||||||
|
// 52 bits of time in milliseconds since epoch
|
||||||
|
// 12 bits of (fractional nanoseconds) >> 8
|
||||||
|
var lastV7time int64
|
||||||
|
|
||||||
|
const nanoPerMilli = 1000000
|
||||||
|
|
||||||
|
// getV7Time returns the time in milliseconds and nanoseconds / 256.
|
||||||
|
// The returned (milli << 12 + seq) is guarenteed to be greater than
|
||||||
|
// (milli << 12 + seq) returned by any previous call to getV7Time.
|
||||||
|
func getV7Time() (milli, seq int64) {
|
||||||
|
timeMu.Lock()
|
||||||
|
defer timeMu.Unlock()
|
||||||
|
|
||||||
|
nano := timeNow().UnixNano()
|
||||||
|
milli = nano / nanoPerMilli
|
||||||
|
// Sequence number is between 0 and 3906 (nanoPerMilli>>8)
|
||||||
|
seq = (nano - milli*nanoPerMilli) >> 8
|
||||||
|
now := milli<<12 + seq
|
||||||
|
if now <= lastV7time {
|
||||||
|
now = lastV7time + 1
|
||||||
|
milli = now >> 12
|
||||||
|
seq = now & 0xfff
|
||||||
|
}
|
||||||
|
lastV7time = now
|
||||||
|
return milli, seq
|
||||||
|
}
|
||||||
4
vendor/github.com/sashabaranov/go-openai/.codecov.yml
generated
vendored
Normal file
4
vendor/github.com/sashabaranov/go-openai/.codecov.yml
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
coverage:
|
||||||
|
ignore:
|
||||||
|
- "examples/**"
|
||||||
|
- "internal/test/**"
|
||||||
22
vendor/github.com/sashabaranov/go-openai/.gitignore
generated
vendored
Normal file
22
vendor/github.com/sashabaranov/go-openai/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, built with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Dependency directories (remove the comment below to include it)
|
||||||
|
# vendor/
|
||||||
|
|
||||||
|
# Auth token for tests
|
||||||
|
.openai-token
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Generated by tests
|
||||||
|
test.mp3
|
||||||
168
vendor/github.com/sashabaranov/go-openai/.golangci.yml
generated
vendored
Normal file
168
vendor/github.com/sashabaranov/go-openai/.golangci.yml
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
version: "2"
|
||||||
|
linters:
|
||||||
|
default: none
|
||||||
|
enable:
|
||||||
|
- asciicheck
|
||||||
|
- bidichk
|
||||||
|
- bodyclose
|
||||||
|
- contextcheck
|
||||||
|
- cyclop
|
||||||
|
- dupl
|
||||||
|
- durationcheck
|
||||||
|
- errcheck
|
||||||
|
- errname
|
||||||
|
- errorlint
|
||||||
|
- exhaustive
|
||||||
|
- forbidigo
|
||||||
|
- funlen
|
||||||
|
- gochecknoinits
|
||||||
|
- gocognit
|
||||||
|
- goconst
|
||||||
|
- gocritic
|
||||||
|
- gocyclo
|
||||||
|
- godot
|
||||||
|
- gomoddirectives
|
||||||
|
- gomodguard
|
||||||
|
- goprintffuncname
|
||||||
|
- gosec
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- lll
|
||||||
|
- makezero
|
||||||
|
- mnd
|
||||||
|
- nestif
|
||||||
|
- nilerr
|
||||||
|
- nilnil
|
||||||
|
- nolintlint
|
||||||
|
- nosprintfhostport
|
||||||
|
- predeclared
|
||||||
|
- promlinter
|
||||||
|
- revive
|
||||||
|
- rowserrcheck
|
||||||
|
- sqlclosecheck
|
||||||
|
- staticcheck
|
||||||
|
- testpackage
|
||||||
|
- tparallel
|
||||||
|
- unconvert
|
||||||
|
- unparam
|
||||||
|
- unused
|
||||||
|
- usetesting
|
||||||
|
- wastedassign
|
||||||
|
- whitespace
|
||||||
|
settings:
|
||||||
|
cyclop:
|
||||||
|
max-complexity: 30
|
||||||
|
package-average: 10
|
||||||
|
errcheck:
|
||||||
|
check-type-assertions: true
|
||||||
|
funlen:
|
||||||
|
lines: 100
|
||||||
|
statements: 50
|
||||||
|
gocognit:
|
||||||
|
min-complexity: 20
|
||||||
|
gocritic:
|
||||||
|
settings:
|
||||||
|
captLocal:
|
||||||
|
paramsOnly: false
|
||||||
|
underef:
|
||||||
|
skipRecvDeref: false
|
||||||
|
gomodguard:
|
||||||
|
blocked:
|
||||||
|
modules:
|
||||||
|
- github.com/golang/protobuf:
|
||||||
|
recommendations:
|
||||||
|
- google.golang.org/protobuf
|
||||||
|
reason: see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules
|
||||||
|
- github.com/satori/go.uuid:
|
||||||
|
recommendations:
|
||||||
|
- github.com/google/uuid
|
||||||
|
reason: satori's package is not maintained
|
||||||
|
- github.com/gofrs/uuid:
|
||||||
|
recommendations:
|
||||||
|
- github.com/google/uuid
|
||||||
|
reason: 'see recommendation from dev-infra team: https://confluence.gtforge.com/x/gQI6Aw'
|
||||||
|
govet:
|
||||||
|
disable:
|
||||||
|
- fieldalignment
|
||||||
|
enable-all: true
|
||||||
|
settings:
|
||||||
|
shadow:
|
||||||
|
strict: true
|
||||||
|
mnd:
|
||||||
|
ignored-functions:
|
||||||
|
- os.Chmod
|
||||||
|
- os.Mkdir
|
||||||
|
- os.MkdirAll
|
||||||
|
- os.OpenFile
|
||||||
|
- os.WriteFile
|
||||||
|
- prometheus.ExponentialBuckets
|
||||||
|
- prometheus.ExponentialBucketsRange
|
||||||
|
- prometheus.LinearBuckets
|
||||||
|
- strconv.FormatFloat
|
||||||
|
- strconv.FormatInt
|
||||||
|
- strconv.FormatUint
|
||||||
|
- strconv.ParseFloat
|
||||||
|
- strconv.ParseInt
|
||||||
|
- strconv.ParseUint
|
||||||
|
nakedret:
|
||||||
|
max-func-lines: 0
|
||||||
|
nolintlint:
|
||||||
|
require-explanation: true
|
||||||
|
require-specific: true
|
||||||
|
allow-no-explanation:
|
||||||
|
- funlen
|
||||||
|
- gocognit
|
||||||
|
- lll
|
||||||
|
rowserrcheck:
|
||||||
|
packages:
|
||||||
|
- github.com/jmoiron/sqlx
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
presets:
|
||||||
|
- comments
|
||||||
|
- common-false-positives
|
||||||
|
- legacy
|
||||||
|
- std-error-handling
|
||||||
|
rules:
|
||||||
|
- linters:
|
||||||
|
- forbidigo
|
||||||
|
- mnd
|
||||||
|
- revive
|
||||||
|
path : ^examples/.*\.go$
|
||||||
|
- linters:
|
||||||
|
- lll
|
||||||
|
source: ^//\s*go:generate\s
|
||||||
|
- linters:
|
||||||
|
- godot
|
||||||
|
source: (noinspection|TODO)
|
||||||
|
- linters:
|
||||||
|
- gocritic
|
||||||
|
source: //noinspection
|
||||||
|
- linters:
|
||||||
|
- errorlint
|
||||||
|
source: ^\s+if _, ok := err\.\([^.]+\.InternalError\); ok {
|
||||||
|
- linters:
|
||||||
|
- bodyclose
|
||||||
|
- dupl
|
||||||
|
- funlen
|
||||||
|
- goconst
|
||||||
|
- gosec
|
||||||
|
- noctx
|
||||||
|
- wrapcheck
|
||||||
|
- staticcheck
|
||||||
|
path: _test\.go
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
issues:
|
||||||
|
max-same-issues: 50
|
||||||
|
formatters:
|
||||||
|
enable:
|
||||||
|
- goimports
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
88
vendor/github.com/sashabaranov/go-openai/CONTRIBUTING.md
generated
vendored
Normal file
88
vendor/github.com/sashabaranov/go-openai/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
# Contributing Guidelines
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
Thank you for your interest in contributing to the "Go OpenAI" project! By following this guideline, we hope to ensure that your contributions are made smoothly and efficiently. The Go OpenAI project is licensed under the [Apache 2.0 License](https://github.com/sashabaranov/go-openai/blob/master/LICENSE), and we welcome contributions through GitHub pull requests.
|
||||||
|
|
||||||
|
## Reporting Bugs
|
||||||
|
If you discover a bug, first check the [GitHub Issues page](https://github.com/sashabaranov/go-openai/issues) to see if the issue has already been reported. If you're reporting a new issue, please use the "Bug report" template and provide detailed information about the problem, including steps to reproduce it.
|
||||||
|
|
||||||
|
## Suggesting Features
|
||||||
|
If you want to suggest a new feature or improvement, first check the [GitHub Issues page](https://github.com/sashabaranov/go-openai/issues) to ensure a similar suggestion hasn't already been made. Use the "Feature request" template to provide a detailed description of your suggestion.
|
||||||
|
|
||||||
|
## Reporting Vulnerabilities
|
||||||
|
If you identify a security concern, please use the "Report a security vulnerability" template on the [GitHub Issues page](https://github.com/sashabaranov/go-openai/issues) to share the details. This report will only be viewable to repository maintainers. You will be credited if the advisory is published.
|
||||||
|
|
||||||
|
## Questions for Users
|
||||||
|
If you have questions, please utilize [StackOverflow](https://stackoverflow.com/) or the [GitHub Discussions page](https://github.com/sashabaranov/go-openai/discussions).
|
||||||
|
|
||||||
|
## Contributing Code
|
||||||
|
There might already be a similar pull requests submitted! Please search for [pull requests](https://github.com/sashabaranov/go-openai/pulls) before creating one.
|
||||||
|
|
||||||
|
### Requirements for Merging a Pull Request
|
||||||
|
|
||||||
|
The requirements to accept a pull request are as follows:
|
||||||
|
|
||||||
|
- Features not provided by the OpenAI API will not be accepted.
|
||||||
|
- The functionality of the feature must match that of the official OpenAI API.
|
||||||
|
- All pull requests should be written in Go according to common conventions, formatted with `goimports`, and free of warnings from tools like `golangci-lint`.
|
||||||
|
- Include tests and ensure all tests pass.
|
||||||
|
- Maintain test coverage without any reduction.
|
||||||
|
- All pull requests require approval from at least one Go OpenAI maintainer.
|
||||||
|
|
||||||
|
**Note:**
|
||||||
|
The merging method for pull requests in this repository is squash merge.
|
||||||
|
|
||||||
|
### Creating a Pull Request
|
||||||
|
- Fork the repository.
|
||||||
|
- Create a new branch and commit your changes.
|
||||||
|
- Push that branch to GitHub.
|
||||||
|
- Start a new Pull Request on GitHub. (Please use the pull request template to provide detailed information.)
|
||||||
|
|
||||||
|
**Note:**
|
||||||
|
If your changes introduce breaking changes, please prefix your pull request title with "[BREAKING_CHANGES]".
|
||||||
|
|
||||||
|
### Code Style
|
||||||
|
In this project, we adhere to the standard coding style of Go. Your code should maintain consistency with the rest of the codebase. To achieve this, please format your code using tools like `goimports` and resolve any syntax or style issues with `golangci-lint`.
|
||||||
|
|
||||||
|
**Run goimports:**
|
||||||
|
```
|
||||||
|
go install golang.org/x/tools/cmd/goimports@latest
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
goimports -w .
|
||||||
|
```
|
||||||
|
|
||||||
|
**Run golangci-lint:**
|
||||||
|
```
|
||||||
|
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
golangci-lint run --out-format=github-actions
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unit Test
|
||||||
|
Please create or update tests relevant to your changes. Ensure all tests run successfully to verify that your modifications do not adversely affect other functionalities.
|
||||||
|
|
||||||
|
**Run test:**
|
||||||
|
```
|
||||||
|
go test -v ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integration Test
|
||||||
|
Integration tests are requested against the production version of the OpenAI API. These tests will verify that the library is properly coded against the actual behavior of the API, and will fail upon any incompatible change in the API.
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
These tests send real network traffic to the OpenAI API and may reach rate limits. Temporary network problems may also cause the test to fail.
|
||||||
|
|
||||||
|
**Run integration test:**
|
||||||
|
```
|
||||||
|
OPENAI_TOKEN=XXX go test -v -tags=integration ./api_integration_test.go
|
||||||
|
```
|
||||||
|
|
||||||
|
If the `OPENAI_TOKEN` environment variable is not available, integration tests will be skipped.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
We wholeheartedly welcome your active participation. Let's build an amazing project together!
|
||||||
201
vendor/github.com/sashabaranov/go-openai/LICENSE
generated
vendored
Normal file
201
vendor/github.com/sashabaranov/go-openai/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
913
vendor/github.com/sashabaranov/go-openai/README.md
generated
vendored
Normal file
913
vendor/github.com/sashabaranov/go-openai/README.md
generated
vendored
Normal file
@@ -0,0 +1,913 @@
|
|||||||
|
# Go OpenAI
|
||||||
|
[](https://pkg.go.dev/github.com/sashabaranov/go-openai)
|
||||||
|
[](https://goreportcard.com/report/github.com/sashabaranov/go-openai)
|
||||||
|
[](https://codecov.io/gh/sashabaranov/go-openai)
|
||||||
|
|
||||||
|
This library provides unofficial Go clients for [OpenAI API](https://platform.openai.com/). We support:
|
||||||
|
|
||||||
|
* ChatGPT 4o, o1
|
||||||
|
* GPT-3, GPT-4
|
||||||
|
* DALL·E 2, DALL·E 3, GPT Image 1
|
||||||
|
* Whisper
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
go get github.com/sashabaranov/go-openai
|
||||||
|
```
|
||||||
|
Currently, go-openai requires Go version 1.18 or greater.
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### ChatGPT example usage:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
openai "github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
client := openai.NewClient("your token")
|
||||||
|
resp, err := client.CreateChatCompletion(
|
||||||
|
context.Background(),
|
||||||
|
openai.ChatCompletionRequest{
|
||||||
|
Model: openai.GPT3Dot5Turbo,
|
||||||
|
Messages: []openai.ChatCompletionMessage{
|
||||||
|
{
|
||||||
|
Role: openai.ChatMessageRoleUser,
|
||||||
|
Content: "Hello!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ChatCompletion error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(resp.Choices[0].Message.Content)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Getting an OpenAI API Key:
|
||||||
|
|
||||||
|
1. Visit the OpenAI website at [https://platform.openai.com/account/api-keys](https://platform.openai.com/account/api-keys).
|
||||||
|
2. If you don't have an account, click on "Sign Up" to create one. If you do, click "Log In".
|
||||||
|
3. Once logged in, navigate to your API key management page.
|
||||||
|
4. Click on "Create new secret key".
|
||||||
|
5. Enter a name for your new key, then click "Create secret key".
|
||||||
|
6. Your new API key will be displayed. Use this key to interact with the OpenAI API.
|
||||||
|
|
||||||
|
**Note:** Your API key is sensitive information. Do not share it with anyone.
|
||||||
|
|
||||||
|
### Other examples:
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>ChatGPT streaming completion</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
openai "github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := openai.NewClient("your token")
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
req := openai.ChatCompletionRequest{
|
||||||
|
Model: openai.GPT3Dot5Turbo,
|
||||||
|
MaxTokens: 20,
|
||||||
|
Messages: []openai.ChatCompletionMessage{
|
||||||
|
{
|
||||||
|
Role: openai.ChatMessageRoleUser,
|
||||||
|
Content: "Lorem ipsum",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Stream: true,
|
||||||
|
}
|
||||||
|
stream, err := c.CreateChatCompletionStream(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ChatCompletionStream error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer stream.Close()
|
||||||
|
|
||||||
|
fmt.Printf("Stream response: ")
|
||||||
|
for {
|
||||||
|
response, err := stream.Recv()
|
||||||
|
if errors.Is(err, io.EOF) {
|
||||||
|
fmt.Println("\nStream finished")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("\nStream error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(response.Choices[0].Delta.Content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>GPT-3 completion</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
openai "github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := openai.NewClient("your token")
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
req := openai.CompletionRequest{
|
||||||
|
Model: openai.GPT3Babbage002,
|
||||||
|
MaxTokens: 5,
|
||||||
|
Prompt: "Lorem ipsum",
|
||||||
|
}
|
||||||
|
resp, err := c.CreateCompletion(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Completion error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(resp.Choices[0].Text)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>GPT-3 streaming completion</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
openai "github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := openai.NewClient("your token")
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
req := openai.CompletionRequest{
|
||||||
|
Model: openai.GPT3Babbage002,
|
||||||
|
MaxTokens: 5,
|
||||||
|
Prompt: "Lorem ipsum",
|
||||||
|
Stream: true,
|
||||||
|
}
|
||||||
|
stream, err := c.CreateCompletionStream(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("CompletionStream error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer stream.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
response, err := stream.Recv()
|
||||||
|
if errors.Is(err, io.EOF) {
|
||||||
|
fmt.Println("Stream finished")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Stream error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fmt.Printf("Stream response: %v\n", response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Audio Speech-To-Text</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
openai "github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := openai.NewClient("your token")
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
req := openai.AudioRequest{
|
||||||
|
Model: openai.Whisper1,
|
||||||
|
FilePath: "recording.mp3",
|
||||||
|
}
|
||||||
|
resp, err := c.CreateTranscription(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Transcription error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(resp.Text)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Audio Captions</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
openai "github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := openai.NewClient(os.Getenv("OPENAI_KEY"))
|
||||||
|
|
||||||
|
req := openai.AudioRequest{
|
||||||
|
Model: openai.Whisper1,
|
||||||
|
FilePath: os.Args[1],
|
||||||
|
Format: openai.AudioResponseFormatSRT,
|
||||||
|
}
|
||||||
|
resp, err := c.CreateTranscription(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Transcription error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f, err := os.Create(os.Args[1] + ".srt")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Could not open file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
if _, err := f.WriteString(resp.Text); err != nil {
|
||||||
|
fmt.Printf("Error writing to file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>DALL-E 2 image generation</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
openai "github.com/sashabaranov/go-openai"
|
||||||
|
"image/png"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := openai.NewClient("your token")
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// Sample image by link
|
||||||
|
reqUrl := openai.ImageRequest{
|
||||||
|
Prompt: "Parrot on a skateboard performs a trick, cartoon style, natural light, high detail",
|
||||||
|
Size: openai.CreateImageSize256x256,
|
||||||
|
ResponseFormat: openai.CreateImageResponseFormatURL,
|
||||||
|
N: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
respUrl, err := c.CreateImage(ctx, reqUrl)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Image creation error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(respUrl.Data[0].URL)
|
||||||
|
|
||||||
|
// Example image as base64
|
||||||
|
reqBase64 := openai.ImageRequest{
|
||||||
|
Prompt: "Portrait of a humanoid parrot in a classic costume, high detail, realistic light, unreal engine",
|
||||||
|
Size: openai.CreateImageSize256x256,
|
||||||
|
ResponseFormat: openai.CreateImageResponseFormatB64JSON,
|
||||||
|
N: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
respBase64, err := c.CreateImage(ctx, reqBase64)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Image creation error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
imgBytes, err := base64.StdEncoding.DecodeString(respBase64.Data[0].B64JSON)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Base64 decode error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r := bytes.NewReader(imgBytes)
|
||||||
|
imgData, err := png.Decode(r)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("PNG decode error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Create("example.png")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("File creation error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
if err := png.Encode(file, imgData); err != nil {
|
||||||
|
fmt.Printf("PNG encode error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("The image was saved as example.png")
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>GPT Image 1 image generation</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
openai "github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := openai.NewClient("your token")
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
req := openai.ImageRequest{
|
||||||
|
Prompt: "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.",
|
||||||
|
Background: openai.CreateImageBackgroundOpaque,
|
||||||
|
Model: openai.CreateImageModelGptImage1,
|
||||||
|
Size: openai.CreateImageSize1024x1024,
|
||||||
|
N: 1,
|
||||||
|
Quality: openai.CreateImageQualityLow,
|
||||||
|
OutputCompression: 100,
|
||||||
|
OutputFormat: openai.CreateImageOutputFormatJPEG,
|
||||||
|
// Moderation: openai.CreateImageModerationLow,
|
||||||
|
// User: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.CreateImage(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Image creation Image generation with GPT Image 1error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Image Base64:", resp.Data[0].B64JSON)
|
||||||
|
|
||||||
|
// Decode the base64 data
|
||||||
|
imgBytes, err := base64.StdEncoding.DecodeString(resp.Data[0].B64JSON)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Base64 decode error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write image to file
|
||||||
|
outputPath := "generated_image.jpg"
|
||||||
|
err = os.WriteFile(outputPath, imgBytes, 0644)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to write image file: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("The image was saved as %s\n", outputPath)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Configuring proxy</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
config := openai.DefaultConfig("token")
|
||||||
|
proxyUrl, err := url.Parse("http://localhost:{port}")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
transport := &http.Transport{
|
||||||
|
Proxy: http.ProxyURL(proxyUrl),
|
||||||
|
}
|
||||||
|
config.HTTPClient = &http.Client{
|
||||||
|
Transport: transport,
|
||||||
|
}
|
||||||
|
|
||||||
|
c := openai.NewClientWithConfig(config)
|
||||||
|
```
|
||||||
|
|
||||||
|
See also: https://pkg.go.dev/github.com/sashabaranov/go-openai#ClientConfig
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>ChatGPT support context</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
client := openai.NewClient("your token")
|
||||||
|
messages := make([]openai.ChatCompletionMessage, 0)
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
fmt.Println("Conversation")
|
||||||
|
fmt.Println("---------------------")
|
||||||
|
|
||||||
|
for {
|
||||||
|
fmt.Print("-> ")
|
||||||
|
text, _ := reader.ReadString('\n')
|
||||||
|
// convert CRLF to LF
|
||||||
|
text = strings.Replace(text, "\n", "", -1)
|
||||||
|
messages = append(messages, openai.ChatCompletionMessage{
|
||||||
|
Role: openai.ChatMessageRoleUser,
|
||||||
|
Content: text,
|
||||||
|
})
|
||||||
|
|
||||||
|
resp, err := client.CreateChatCompletion(
|
||||||
|
context.Background(),
|
||||||
|
openai.ChatCompletionRequest{
|
||||||
|
Model: openai.GPT3Dot5Turbo,
|
||||||
|
Messages: messages,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ChatCompletion error: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
content := resp.Choices[0].Message.Content
|
||||||
|
messages = append(messages, openai.ChatCompletionMessage{
|
||||||
|
Role: openai.ChatMessageRoleAssistant,
|
||||||
|
Content: content,
|
||||||
|
})
|
||||||
|
fmt.Println(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Azure OpenAI ChatGPT</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
openai "github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
config := openai.DefaultAzureConfig("your Azure OpenAI Key", "https://your Azure OpenAI Endpoint")
|
||||||
|
// If you use a deployment name different from the model name, you can customize the AzureModelMapperFunc function
|
||||||
|
// config.AzureModelMapperFunc = func(model string) string {
|
||||||
|
// azureModelMapping := map[string]string{
|
||||||
|
// "gpt-3.5-turbo": "your gpt-3.5-turbo deployment name",
|
||||||
|
// }
|
||||||
|
// return azureModelMapping[model]
|
||||||
|
// }
|
||||||
|
|
||||||
|
client := openai.NewClientWithConfig(config)
|
||||||
|
resp, err := client.CreateChatCompletion(
|
||||||
|
context.Background(),
|
||||||
|
openai.ChatCompletionRequest{
|
||||||
|
Model: openai.GPT3Dot5Turbo,
|
||||||
|
Messages: []openai.ChatCompletionMessage{
|
||||||
|
{
|
||||||
|
Role: openai.ChatMessageRoleUser,
|
||||||
|
Content: "Hello Azure OpenAI!",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ChatCompletion error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(resp.Choices[0].Message.Content)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Embedding Semantic Similarity</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
openai "github.com/sashabaranov/go-openai"
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
client := openai.NewClient("your-token")
|
||||||
|
|
||||||
|
// Create an EmbeddingRequest for the user query
|
||||||
|
queryReq := openai.EmbeddingRequest{
|
||||||
|
Input: []string{"How many chucks would a woodchuck chuck"},
|
||||||
|
Model: openai.AdaEmbeddingV2,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an embedding for the user query
|
||||||
|
queryResponse, err := client.CreateEmbeddings(context.Background(), queryReq)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error creating query embedding:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an EmbeddingRequest for the target text
|
||||||
|
targetReq := openai.EmbeddingRequest{
|
||||||
|
Input: []string{"How many chucks would a woodchuck chuck if the woodchuck could chuck wood"},
|
||||||
|
Model: openai.AdaEmbeddingV2,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an embedding for the target text
|
||||||
|
targetResponse, err := client.CreateEmbeddings(context.Background(), targetReq)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error creating target embedding:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we have the embeddings for the user query and the target text, we
|
||||||
|
// can calculate their similarity.
|
||||||
|
queryEmbedding := queryResponse.Data[0]
|
||||||
|
targetEmbedding := targetResponse.Data[0]
|
||||||
|
|
||||||
|
similarity, err := queryEmbedding.DotProduct(&targetEmbedding)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error calculating dot product:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("The similarity score between the query and the target is %f", similarity)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Azure OpenAI Embeddings</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
openai "github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
config := openai.DefaultAzureConfig("your Azure OpenAI Key", "https://your Azure OpenAI Endpoint")
|
||||||
|
config.APIVersion = "2023-05-15" // optional update to latest API version
|
||||||
|
|
||||||
|
//If you use a deployment name different from the model name, you can customize the AzureModelMapperFunc function
|
||||||
|
//config.AzureModelMapperFunc = func(model string) string {
|
||||||
|
// azureModelMapping := map[string]string{
|
||||||
|
// "gpt-3.5-turbo":"your gpt-3.5-turbo deployment name",
|
||||||
|
// }
|
||||||
|
// return azureModelMapping[model]
|
||||||
|
//}
|
||||||
|
|
||||||
|
input := "Text to vectorize"
|
||||||
|
|
||||||
|
client := openai.NewClientWithConfig(config)
|
||||||
|
resp, err := client.CreateEmbeddings(
|
||||||
|
context.Background(),
|
||||||
|
openai.EmbeddingRequest{
|
||||||
|
Input: []string{input},
|
||||||
|
Model: openai.AdaEmbeddingV2,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("CreateEmbeddings error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vectors := resp.Data[0].Embedding // []float32 with 1536 dimensions
|
||||||
|
|
||||||
|
fmt.Println(vectors[:10], "...", vectors[len(vectors)-10:])
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>JSON Schema for function calling</summary>
|
||||||
|
|
||||||
|
It is now possible for chat completion to choose to call a function for more information ([see developer docs here](https://platform.openai.com/docs/guides/gpt/function-calling)).
|
||||||
|
|
||||||
|
In order to describe the type of functions that can be called, a JSON schema must be provided. Many JSON schema libraries exist and are more advanced than what we can offer in this library, however we have included a simple `jsonschema` package for those who want to use this feature without formatting their own JSON schema payload.
|
||||||
|
|
||||||
|
The developer documents give this JSON schema definition as an example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name":"get_current_weather",
|
||||||
|
"description":"Get the current weather in a given location",
|
||||||
|
"parameters":{
|
||||||
|
"type":"object",
|
||||||
|
"properties":{
|
||||||
|
"location":{
|
||||||
|
"type":"string",
|
||||||
|
"description":"The city and state, e.g. San Francisco, CA"
|
||||||
|
},
|
||||||
|
"unit":{
|
||||||
|
"type":"string",
|
||||||
|
"enum":[
|
||||||
|
"celsius",
|
||||||
|
"fahrenheit"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required":[
|
||||||
|
"location"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Using the `jsonschema` package, this schema could be created using structs as such:
|
||||||
|
|
||||||
|
```go
|
||||||
|
FunctionDefinition{
|
||||||
|
Name: "get_current_weather",
|
||||||
|
Parameters: jsonschema.Definition{
|
||||||
|
Type: jsonschema.Object,
|
||||||
|
Properties: map[string]jsonschema.Definition{
|
||||||
|
"location": {
|
||||||
|
Type: jsonschema.String,
|
||||||
|
Description: "The city and state, e.g. San Francisco, CA",
|
||||||
|
},
|
||||||
|
"unit": {
|
||||||
|
Type: jsonschema.String,
|
||||||
|
Enum: []string{"celsius", "fahrenheit"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Required: []string{"location"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Parameters` field of a `FunctionDefinition` can accept either of the above styles, or even a nested struct from another library (as long as it can be marshalled into JSON).
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Error handling</summary>
|
||||||
|
|
||||||
|
Open-AI maintains clear documentation on how to [handle API errors](https://platform.openai.com/docs/guides/error-codes/api-errors)
|
||||||
|
|
||||||
|
example:
|
||||||
|
```
|
||||||
|
e := &openai.APIError{}
|
||||||
|
if errors.As(err, &e) {
|
||||||
|
switch e.HTTPStatusCode {
|
||||||
|
case 401:
|
||||||
|
// invalid auth or key (do not retry)
|
||||||
|
case 429:
|
||||||
|
// rate limiting or engine overload (wait and retry)
|
||||||
|
case 500:
|
||||||
|
// openai server error (retry)
|
||||||
|
default:
|
||||||
|
// unhandled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Fine Tune Model</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/sashabaranov/go-openai"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
client := openai.NewClient("your token")
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// create a .jsonl file with your training data for conversational model
|
||||||
|
// {"prompt": "<prompt text>", "completion": "<ideal generated text>"}
|
||||||
|
// {"prompt": "<prompt text>", "completion": "<ideal generated text>"}
|
||||||
|
// {"prompt": "<prompt text>", "completion": "<ideal generated text>"}
|
||||||
|
|
||||||
|
// chat models are trained using the following file format:
|
||||||
|
// {"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already."}]}
|
||||||
|
// {"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?"}]}
|
||||||
|
// {"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "How far is the Moon from Earth?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters."}]}
|
||||||
|
|
||||||
|
// you can use openai cli tool to validate the data
|
||||||
|
// For more info - https://platform.openai.com/docs/guides/fine-tuning
|
||||||
|
|
||||||
|
file, err := client.CreateFile(ctx, openai.FileRequest{
|
||||||
|
FilePath: "training_prepared.jsonl",
|
||||||
|
Purpose: "fine-tune",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Upload JSONL file error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a fine tuning job
|
||||||
|
// Streams events until the job is done (this often takes minutes, but can take hours if there are many jobs in the queue or your dataset is large)
|
||||||
|
// use below get method to know the status of your model
|
||||||
|
fineTuningJob, err := client.CreateFineTuningJob(ctx, openai.FineTuningJobRequest{
|
||||||
|
TrainingFile: file.ID,
|
||||||
|
Model: "davinci-002", // gpt-3.5-turbo-0613, babbage-002.
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Creating new fine tune model error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fineTuningJob, err = client.RetrieveFineTuningJob(ctx, fineTuningJob.ID)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Getting fine tune model error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(fineTuningJob.FineTunedModel)
|
||||||
|
|
||||||
|
// once the status of fineTuningJob is `succeeded`, you can use your fine tune model in Completion Request or Chat Completion Request
|
||||||
|
|
||||||
|
// resp, err := client.CreateCompletion(ctx, openai.CompletionRequest{
|
||||||
|
// Model: fineTuningJob.FineTunedModel,
|
||||||
|
// Prompt: "your prompt",
|
||||||
|
// })
|
||||||
|
// if err != nil {
|
||||||
|
// fmt.Printf("Create completion error %v\n", err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fmt.Println(resp.Choices[0].Text)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Structured Outputs</summary>
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/sashabaranov/go-openai"
|
||||||
|
"github.com/sashabaranov/go-openai/jsonschema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
client := openai.NewClient("your token")
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
Steps []struct {
|
||||||
|
Explanation string `json:"explanation"`
|
||||||
|
Output string `json:"output"`
|
||||||
|
} `json:"steps"`
|
||||||
|
FinalAnswer string `json:"final_answer"`
|
||||||
|
}
|
||||||
|
var result Result
|
||||||
|
schema, err := jsonschema.GenerateSchemaForType(result)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("GenerateSchemaForType error: %v", err)
|
||||||
|
}
|
||||||
|
resp, err := client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{
|
||||||
|
Model: openai.GPT4oMini,
|
||||||
|
Messages: []openai.ChatCompletionMessage{
|
||||||
|
{
|
||||||
|
Role: openai.ChatMessageRoleSystem,
|
||||||
|
Content: "You are a helpful math tutor. Guide the user through the solution step by step.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Role: openai.ChatMessageRoleUser,
|
||||||
|
Content: "how can I solve 8x + 7 = -23",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ResponseFormat: &openai.ChatCompletionResponseFormat{
|
||||||
|
Type: openai.ChatCompletionResponseFormatTypeJSONSchema,
|
||||||
|
JSONSchema: &openai.ChatCompletionResponseFormatJSONSchema{
|
||||||
|
Name: "math_reasoning",
|
||||||
|
Schema: schema,
|
||||||
|
Strict: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("CreateChatCompletion error: %v", err)
|
||||||
|
}
|
||||||
|
err = schema.Unmarshal(resp.Choices[0].Message.Content, &result)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unmarshal schema error: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println(result)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
See the `examples/` folder for more.
|
||||||
|
|
||||||
|
## Frequently Asked Questions
|
||||||
|
|
||||||
|
### Why don't we get the same answer when specifying a temperature field of 0 and asking the same question?
|
||||||
|
|
||||||
|
Even when specifying a temperature field of 0, it doesn't guarantee that you'll always get the same response. Several factors come into play.
|
||||||
|
|
||||||
|
1. Go OpenAI Behavior: When you specify a temperature field of 0 in Go OpenAI, the omitempty tag causes that field to be removed from the request. Consequently, the OpenAI API applies the default value of 1.
|
||||||
|
2. Token Count for Input/Output: If there's a large number of tokens in the input and output, setting the temperature to 0 can still result in non-deterministic behavior. In particular, when using around 32k tokens, the likelihood of non-deterministic behavior becomes highest even with a temperature of 0.
|
||||||
|
|
||||||
|
Due to the factors mentioned above, different answers may be returned even for the same question.
|
||||||
|
|
||||||
|
**Workarounds:**
|
||||||
|
1. As of November 2023, use [the new `seed` parameter](https://platform.openai.com/docs/guides/text-generation/reproducible-outputs) in conjunction with the `system_fingerprint` response field, alongside Temperature management.
|
||||||
|
2. Try using `math.SmallestNonzeroFloat32`: By specifying `math.SmallestNonzeroFloat32` in the temperature field instead of 0, you can mimic the behavior of setting it to 0.
|
||||||
|
3. Limiting Token Count: By limiting the number of tokens in the input and output and especially avoiding large requests close to 32k tokens, you can reduce the risk of non-deterministic behavior.
|
||||||
|
|
||||||
|
By adopting these strategies, you can expect more consistent results.
|
||||||
|
|
||||||
|
**Related Issues:**
|
||||||
|
[omitempty option of request struct will generate incorrect request when parameter is 0.](https://github.com/sashabaranov/go-openai/issues/9)
|
||||||
|
|
||||||
|
### Does Go OpenAI provide a method to count tokens?
|
||||||
|
|
||||||
|
No, Go OpenAI does not offer a feature to count tokens, and there are no plans to provide such a feature in the future. However, if there's a way to implement a token counting feature with zero dependencies, it might be possible to merge that feature into Go OpenAI. Otherwise, it would be more appropriate to implement it in a dedicated library or repository.
|
||||||
|
|
||||||
|
For counting tokens, you might find the following links helpful:
|
||||||
|
- [Counting Tokens For Chat API Calls](https://github.com/pkoukk/tiktoken-go#counting-tokens-for-chat-api-calls)
|
||||||
|
- [How to count tokens with tiktoken](https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb)
|
||||||
|
|
||||||
|
**Related Issues:**
|
||||||
|
[Is it possible to join the implementation of GPT3 Tokenizer](https://github.com/sashabaranov/go-openai/issues/62)
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
By following [Contributing Guidelines](https://github.com/sashabaranov/go-openai/blob/master/CONTRIBUTING.md), we hope to ensure that your contributions are made smoothly and efficiently.
|
||||||
|
|
||||||
|
## Thank you
|
||||||
|
|
||||||
|
We want to take a moment to express our deepest gratitude to the [contributors](https://github.com/sashabaranov/go-openai/graphs/contributors) and sponsors of this project:
|
||||||
|
- [Carson Kahn](https://carsonkahn.com) of [Spindle AI](https://spindleai.com)
|
||||||
|
|
||||||
|
To all of you: thank you. You've helped us achieve more than we ever imagined possible. Can't wait to see where we go next, together!
|
||||||
325
vendor/github.com/sashabaranov/go-openai/assistant.go
generated
vendored
Normal file
325
vendor/github.com/sashabaranov/go-openai/assistant.go
generated
vendored
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
assistantsSuffix = "/assistants"
|
||||||
|
assistantsFilesSuffix = "/files"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Assistant struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
Instructions *string `json:"instructions,omitempty"`
|
||||||
|
Tools []AssistantTool `json:"tools"`
|
||||||
|
ToolResources *AssistantToolResource `json:"tool_resources,omitempty"`
|
||||||
|
FileIDs []string `json:"file_ids,omitempty"` // Deprecated in v2
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty"`
|
||||||
|
Temperature *float32 `json:"temperature,omitempty"`
|
||||||
|
TopP *float32 `json:"top_p,omitempty"`
|
||||||
|
ResponseFormat any `json:"response_format,omitempty"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssistantToolType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AssistantToolTypeCodeInterpreter AssistantToolType = "code_interpreter"
|
||||||
|
AssistantToolTypeRetrieval AssistantToolType = "retrieval"
|
||||||
|
AssistantToolTypeFunction AssistantToolType = "function"
|
||||||
|
AssistantToolTypeFileSearch AssistantToolType = "file_search"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AssistantTool struct {
|
||||||
|
Type AssistantToolType `json:"type"`
|
||||||
|
Function *FunctionDefinition `json:"function,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssistantToolFileSearch struct {
|
||||||
|
VectorStoreIDs []string `json:"vector_store_ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssistantToolCodeInterpreter struct {
|
||||||
|
FileIDs []string `json:"file_ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssistantToolResource struct {
|
||||||
|
FileSearch *AssistantToolFileSearch `json:"file_search,omitempty"`
|
||||||
|
CodeInterpreter *AssistantToolCodeInterpreter `json:"code_interpreter,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssistantRequest provides the assistant request parameters.
|
||||||
|
// When modifying the tools the API functions as the following:
|
||||||
|
// If Tools is undefined, no changes are made to the Assistant's tools.
|
||||||
|
// If Tools is empty slice it will effectively delete all of the Assistant's tools.
|
||||||
|
// If Tools is populated, it will replace all of the existing Assistant's tools with the provided tools.
|
||||||
|
type AssistantRequest struct {
|
||||||
|
Model string `json:"model"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
Instructions *string `json:"instructions,omitempty"`
|
||||||
|
Tools []AssistantTool `json:"-"`
|
||||||
|
FileIDs []string `json:"file_ids,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty"`
|
||||||
|
ToolResources *AssistantToolResource `json:"tool_resources,omitempty"`
|
||||||
|
ResponseFormat any `json:"response_format,omitempty"`
|
||||||
|
Temperature *float32 `json:"temperature,omitempty"`
|
||||||
|
TopP *float32 `json:"top_p,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON provides a custom marshaller for the assistant request to handle the API use cases
|
||||||
|
// If Tools is nil, the field is omitted from the JSON.
|
||||||
|
// If Tools is an empty slice, it's included in the JSON as an empty array ([]).
|
||||||
|
// If Tools is populated, it's included in the JSON with the elements.
|
||||||
|
func (a AssistantRequest) MarshalJSON() ([]byte, error) {
|
||||||
|
type Alias AssistantRequest
|
||||||
|
assistantAlias := &struct {
|
||||||
|
Tools *[]AssistantTool `json:"tools,omitempty"`
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
Alias: (*Alias)(&a),
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Tools != nil {
|
||||||
|
assistantAlias.Tools = &a.Tools
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(assistantAlias)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssistantsList is a list of assistants.
|
||||||
|
type AssistantsList struct {
|
||||||
|
Assistants []Assistant `json:"data"`
|
||||||
|
LastID *string `json:"last_id"`
|
||||||
|
FirstID *string `json:"first_id"`
|
||||||
|
HasMore bool `json:"has_more"`
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssistantDeleteResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
Deleted bool `json:"deleted"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssistantFile struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
AssistantID string `json:"assistant_id"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssistantFileRequest struct {
|
||||||
|
FileID string `json:"file_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssistantFilesList struct {
|
||||||
|
AssistantFiles []AssistantFile `json:"data"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAssistant creates a new assistant.
|
||||||
|
func (c *Client) CreateAssistant(ctx context.Context, request AssistantRequest) (response Assistant, err error) {
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(assistantsSuffix), withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveAssistant retrieves an assistant.
|
||||||
|
func (c *Client) RetrieveAssistant(
|
||||||
|
ctx context.Context,
|
||||||
|
assistantID string,
|
||||||
|
) (response Assistant, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s", assistantsSuffix, assistantID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyAssistant modifies an assistant.
|
||||||
|
func (c *Client) ModifyAssistant(
|
||||||
|
ctx context.Context,
|
||||||
|
assistantID string,
|
||||||
|
request AssistantRequest,
|
||||||
|
) (response Assistant, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s", assistantsSuffix, assistantID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix), withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAssistant deletes an assistant.
|
||||||
|
func (c *Client) DeleteAssistant(
|
||||||
|
ctx context.Context,
|
||||||
|
assistantID string,
|
||||||
|
) (response AssistantDeleteResponse, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s", assistantsSuffix, assistantID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodDelete, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAssistants Lists the currently available assistants.
|
||||||
|
func (c *Client) ListAssistants(
|
||||||
|
ctx context.Context,
|
||||||
|
limit *int,
|
||||||
|
order *string,
|
||||||
|
after *string,
|
||||||
|
before *string,
|
||||||
|
) (response AssistantsList, err error) {
|
||||||
|
urlValues := url.Values{}
|
||||||
|
if limit != nil {
|
||||||
|
urlValues.Add("limit", fmt.Sprintf("%d", *limit))
|
||||||
|
}
|
||||||
|
if order != nil {
|
||||||
|
urlValues.Add("order", *order)
|
||||||
|
}
|
||||||
|
if after != nil {
|
||||||
|
urlValues.Add("after", *after)
|
||||||
|
}
|
||||||
|
if before != nil {
|
||||||
|
urlValues.Add("before", *before)
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedValues := ""
|
||||||
|
if len(urlValues) > 0 {
|
||||||
|
encodedValues = "?" + urlValues.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
urlSuffix := fmt.Sprintf("%s%s", assistantsSuffix, encodedValues)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAssistantFile creates a new assistant file.
|
||||||
|
func (c *Client) CreateAssistantFile(
|
||||||
|
ctx context.Context,
|
||||||
|
assistantID string,
|
||||||
|
request AssistantFileRequest,
|
||||||
|
) (response AssistantFile, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s%s", assistantsSuffix, assistantID, assistantsFilesSuffix)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix),
|
||||||
|
withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveAssistantFile retrieves an assistant file.
|
||||||
|
func (c *Client) RetrieveAssistantFile(
|
||||||
|
ctx context.Context,
|
||||||
|
assistantID string,
|
||||||
|
fileID string,
|
||||||
|
) (response AssistantFile, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s%s/%s", assistantsSuffix, assistantID, assistantsFilesSuffix, fileID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAssistantFile deletes an existing file.
|
||||||
|
func (c *Client) DeleteAssistantFile(
|
||||||
|
ctx context.Context,
|
||||||
|
assistantID string,
|
||||||
|
fileID string,
|
||||||
|
) (err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s%s/%s", assistantsSuffix, assistantID, assistantsFilesSuffix, fileID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodDelete, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAssistantFiles Lists the currently available files for an assistant.
|
||||||
|
func (c *Client) ListAssistantFiles(
|
||||||
|
ctx context.Context,
|
||||||
|
assistantID string,
|
||||||
|
limit *int,
|
||||||
|
order *string,
|
||||||
|
after *string,
|
||||||
|
before *string,
|
||||||
|
) (response AssistantFilesList, err error) {
|
||||||
|
urlValues := url.Values{}
|
||||||
|
if limit != nil {
|
||||||
|
urlValues.Add("limit", fmt.Sprintf("%d", *limit))
|
||||||
|
}
|
||||||
|
if order != nil {
|
||||||
|
urlValues.Add("order", *order)
|
||||||
|
}
|
||||||
|
if after != nil {
|
||||||
|
urlValues.Add("after", *after)
|
||||||
|
}
|
||||||
|
if before != nil {
|
||||||
|
urlValues.Add("before", *before)
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedValues := ""
|
||||||
|
if len(urlValues) > 0 {
|
||||||
|
encodedValues = "?" + urlValues.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s%s%s", assistantsSuffix, assistantID, assistantsFilesSuffix, encodedValues)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
234
vendor/github.com/sashabaranov/go-openai/audio.go
generated
vendored
Normal file
234
vendor/github.com/sashabaranov/go-openai/audio.go
generated
vendored
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
utils "github.com/sashabaranov/go-openai/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Whisper Defines the models provided by OpenAI to use when processing audio with OpenAI.
|
||||||
|
const (
|
||||||
|
Whisper1 = "whisper-1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Response formats; Whisper uses AudioResponseFormatJSON by default.
|
||||||
|
type AudioResponseFormat string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AudioResponseFormatJSON AudioResponseFormat = "json"
|
||||||
|
AudioResponseFormatText AudioResponseFormat = "text"
|
||||||
|
AudioResponseFormatSRT AudioResponseFormat = "srt"
|
||||||
|
AudioResponseFormatVerboseJSON AudioResponseFormat = "verbose_json"
|
||||||
|
AudioResponseFormatVTT AudioResponseFormat = "vtt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TranscriptionTimestampGranularity string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TranscriptionTimestampGranularityWord TranscriptionTimestampGranularity = "word"
|
||||||
|
TranscriptionTimestampGranularitySegment TranscriptionTimestampGranularity = "segment"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AudioRequest represents a request structure for audio API.
|
||||||
|
type AudioRequest struct {
|
||||||
|
Model string
|
||||||
|
|
||||||
|
// FilePath is either an existing file in your filesystem or a filename representing the contents of Reader.
|
||||||
|
FilePath string
|
||||||
|
|
||||||
|
// Reader is an optional io.Reader when you do not want to use an existing file.
|
||||||
|
Reader io.Reader
|
||||||
|
|
||||||
|
Prompt string
|
||||||
|
Temperature float32
|
||||||
|
Language string // Only for transcription.
|
||||||
|
Format AudioResponseFormat
|
||||||
|
TimestampGranularities []TranscriptionTimestampGranularity // Only for transcription.
|
||||||
|
}
|
||||||
|
|
||||||
|
// AudioResponse represents a response structure for audio API.
|
||||||
|
type AudioResponse struct {
|
||||||
|
Task string `json:"task"`
|
||||||
|
Language string `json:"language"`
|
||||||
|
Duration float64 `json:"duration"`
|
||||||
|
Segments []struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Seek int `json:"seek"`
|
||||||
|
Start float64 `json:"start"`
|
||||||
|
End float64 `json:"end"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
Tokens []int `json:"tokens"`
|
||||||
|
Temperature float64 `json:"temperature"`
|
||||||
|
AvgLogprob float64 `json:"avg_logprob"`
|
||||||
|
CompressionRatio float64 `json:"compression_ratio"`
|
||||||
|
NoSpeechProb float64 `json:"no_speech_prob"`
|
||||||
|
Transient bool `json:"transient"`
|
||||||
|
} `json:"segments"`
|
||||||
|
Words []struct {
|
||||||
|
Word string `json:"word"`
|
||||||
|
Start float64 `json:"start"`
|
||||||
|
End float64 `json:"end"`
|
||||||
|
} `json:"words"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type audioTextResponse struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *audioTextResponse) ToAudioResponse() AudioResponse {
|
||||||
|
return AudioResponse{
|
||||||
|
Text: r.Text,
|
||||||
|
httpHeader: r.httpHeader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTranscription — API call to create a transcription. Returns transcribed text.
|
||||||
|
func (c *Client) CreateTranscription(
|
||||||
|
ctx context.Context,
|
||||||
|
request AudioRequest,
|
||||||
|
) (response AudioResponse, err error) {
|
||||||
|
return c.callAudioAPI(ctx, request, "transcriptions")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTranslation — API call to translate audio into English.
|
||||||
|
func (c *Client) CreateTranslation(
|
||||||
|
ctx context.Context,
|
||||||
|
request AudioRequest,
|
||||||
|
) (response AudioResponse, err error) {
|
||||||
|
return c.callAudioAPI(ctx, request, "translations")
|
||||||
|
}
|
||||||
|
|
||||||
|
// callAudioAPI — API call to an audio endpoint.
|
||||||
|
func (c *Client) callAudioAPI(
|
||||||
|
ctx context.Context,
|
||||||
|
request AudioRequest,
|
||||||
|
endpointSuffix string,
|
||||||
|
) (response AudioResponse, err error) {
|
||||||
|
var formBody bytes.Buffer
|
||||||
|
builder := c.createFormBuilder(&formBody)
|
||||||
|
|
||||||
|
if err = audioMultipartForm(request, builder); err != nil {
|
||||||
|
return AudioResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
urlSuffix := fmt.Sprintf("/audio/%s", endpointSuffix)
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL(urlSuffix, withModel(request.Model)),
|
||||||
|
withBody(&formBody),
|
||||||
|
withContentType(builder.FormDataContentType()),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return AudioResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.HasJSONResponse() {
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
} else {
|
||||||
|
var textResponse audioTextResponse
|
||||||
|
err = c.sendRequest(req, &textResponse)
|
||||||
|
response = textResponse.ToAudioResponse()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return AudioResponse{}, err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasJSONResponse returns true if the response format is JSON.
|
||||||
|
func (r AudioRequest) HasJSONResponse() bool {
|
||||||
|
return r.Format == "" || r.Format == AudioResponseFormatJSON || r.Format == AudioResponseFormatVerboseJSON
|
||||||
|
}
|
||||||
|
|
||||||
|
// audioMultipartForm creates a form with audio file contents and the name of the model to use for
|
||||||
|
// audio processing.
|
||||||
|
func audioMultipartForm(request AudioRequest, b utils.FormBuilder) error {
|
||||||
|
err := createFileField(request, b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = b.WriteField("model", request.Model)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("writing model name: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a form field for the prompt (if provided)
|
||||||
|
if request.Prompt != "" {
|
||||||
|
err = b.WriteField("prompt", request.Prompt)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("writing prompt: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a form field for the format (if provided)
|
||||||
|
if request.Format != "" {
|
||||||
|
err = b.WriteField("response_format", string(request.Format))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("writing format: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a form field for the temperature (if provided)
|
||||||
|
if request.Temperature != 0 {
|
||||||
|
err = b.WriteField("temperature", fmt.Sprintf("%.2f", request.Temperature))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("writing temperature: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a form field for the language (if provided)
|
||||||
|
if request.Language != "" {
|
||||||
|
err = b.WriteField("language", request.Language)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("writing language: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(request.TimestampGranularities) > 0 {
|
||||||
|
for _, tg := range request.TimestampGranularities {
|
||||||
|
err = b.WriteField("timestamp_granularities[]", string(tg))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("writing timestamp_granularities[]: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the multipart writer
|
||||||
|
return b.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// createFileField creates the "file" form field from either an existing file or by using the reader.
|
||||||
|
func createFileField(request AudioRequest, b utils.FormBuilder) error {
|
||||||
|
if request.Reader != nil {
|
||||||
|
err := b.CreateFormFileReader("file", request.Reader, request.FilePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("creating form using reader: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(request.FilePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("opening audio file: %w", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
err = b.CreateFormFile("file", f)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("creating form file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
271
vendor/github.com/sashabaranov/go-openai/batch.go
generated
vendored
Normal file
271
vendor/github.com/sashabaranov/go-openai/batch.go
generated
vendored
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
const batchesSuffix = "/batches"
|
||||||
|
|
||||||
|
type BatchEndpoint string
|
||||||
|
|
||||||
|
const (
|
||||||
|
BatchEndpointChatCompletions BatchEndpoint = "/v1/chat/completions"
|
||||||
|
BatchEndpointCompletions BatchEndpoint = "/v1/completions"
|
||||||
|
BatchEndpointEmbeddings BatchEndpoint = "/v1/embeddings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BatchLineItem interface {
|
||||||
|
MarshalBatchLineItem() []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type BatchChatCompletionRequest struct {
|
||||||
|
CustomID string `json:"custom_id"`
|
||||||
|
Body ChatCompletionRequest `json:"body"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
URL BatchEndpoint `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r BatchChatCompletionRequest) MarshalBatchLineItem() []byte {
|
||||||
|
marshal, _ := json.Marshal(r)
|
||||||
|
return marshal
|
||||||
|
}
|
||||||
|
|
||||||
|
type BatchCompletionRequest struct {
|
||||||
|
CustomID string `json:"custom_id"`
|
||||||
|
Body CompletionRequest `json:"body"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
URL BatchEndpoint `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r BatchCompletionRequest) MarshalBatchLineItem() []byte {
|
||||||
|
marshal, _ := json.Marshal(r)
|
||||||
|
return marshal
|
||||||
|
}
|
||||||
|
|
||||||
|
type BatchEmbeddingRequest struct {
|
||||||
|
CustomID string `json:"custom_id"`
|
||||||
|
Body EmbeddingRequest `json:"body"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
URL BatchEndpoint `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r BatchEmbeddingRequest) MarshalBatchLineItem() []byte {
|
||||||
|
marshal, _ := json.Marshal(r)
|
||||||
|
return marshal
|
||||||
|
}
|
||||||
|
|
||||||
|
type Batch struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
Endpoint BatchEndpoint `json:"endpoint"`
|
||||||
|
Errors *struct {
|
||||||
|
Object string `json:"object,omitempty"`
|
||||||
|
Data []struct {
|
||||||
|
Code string `json:"code,omitempty"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
Param *string `json:"param,omitempty"`
|
||||||
|
Line *int `json:"line,omitempty"`
|
||||||
|
} `json:"data"`
|
||||||
|
} `json:"errors"`
|
||||||
|
InputFileID string `json:"input_file_id"`
|
||||||
|
CompletionWindow string `json:"completion_window"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
OutputFileID *string `json:"output_file_id"`
|
||||||
|
ErrorFileID *string `json:"error_file_id"`
|
||||||
|
CreatedAt int `json:"created_at"`
|
||||||
|
InProgressAt *int `json:"in_progress_at"`
|
||||||
|
ExpiresAt *int `json:"expires_at"`
|
||||||
|
FinalizingAt *int `json:"finalizing_at"`
|
||||||
|
CompletedAt *int `json:"completed_at"`
|
||||||
|
FailedAt *int `json:"failed_at"`
|
||||||
|
ExpiredAt *int `json:"expired_at"`
|
||||||
|
CancellingAt *int `json:"cancelling_at"`
|
||||||
|
CancelledAt *int `json:"cancelled_at"`
|
||||||
|
RequestCounts BatchRequestCounts `json:"request_counts"`
|
||||||
|
Metadata map[string]any `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BatchRequestCounts struct {
|
||||||
|
Total int `json:"total"`
|
||||||
|
Completed int `json:"completed"`
|
||||||
|
Failed int `json:"failed"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateBatchRequest struct {
|
||||||
|
InputFileID string `json:"input_file_id"`
|
||||||
|
Endpoint BatchEndpoint `json:"endpoint"`
|
||||||
|
CompletionWindow string `json:"completion_window"`
|
||||||
|
Metadata map[string]any `json:"metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BatchResponse struct {
|
||||||
|
httpHeader
|
||||||
|
Batch
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateBatch — API call to Create batch.
|
||||||
|
func (c *Client) CreateBatch(
|
||||||
|
ctx context.Context,
|
||||||
|
request CreateBatchRequest,
|
||||||
|
) (response BatchResponse, err error) {
|
||||||
|
if request.CompletionWindow == "" {
|
||||||
|
request.CompletionWindow = "24h"
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(batchesSuffix), withBody(request))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploadBatchFileRequest struct {
|
||||||
|
FileName string
|
||||||
|
Lines []BatchLineItem
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *UploadBatchFileRequest) MarshalJSONL() []byte {
|
||||||
|
buff := bytes.Buffer{}
|
||||||
|
for i, line := range r.Lines {
|
||||||
|
if i != 0 {
|
||||||
|
buff.Write([]byte("\n"))
|
||||||
|
}
|
||||||
|
buff.Write(line.MarshalBatchLineItem())
|
||||||
|
}
|
||||||
|
return buff.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *UploadBatchFileRequest) AddChatCompletion(customerID string, body ChatCompletionRequest) {
|
||||||
|
r.Lines = append(r.Lines, BatchChatCompletionRequest{
|
||||||
|
CustomID: customerID,
|
||||||
|
Body: body,
|
||||||
|
Method: "POST",
|
||||||
|
URL: BatchEndpointChatCompletions,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *UploadBatchFileRequest) AddCompletion(customerID string, body CompletionRequest) {
|
||||||
|
r.Lines = append(r.Lines, BatchCompletionRequest{
|
||||||
|
CustomID: customerID,
|
||||||
|
Body: body,
|
||||||
|
Method: "POST",
|
||||||
|
URL: BatchEndpointCompletions,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *UploadBatchFileRequest) AddEmbedding(customerID string, body EmbeddingRequest) {
|
||||||
|
r.Lines = append(r.Lines, BatchEmbeddingRequest{
|
||||||
|
CustomID: customerID,
|
||||||
|
Body: body,
|
||||||
|
Method: "POST",
|
||||||
|
URL: BatchEndpointEmbeddings,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadBatchFile — upload batch file.
|
||||||
|
func (c *Client) UploadBatchFile(ctx context.Context, request UploadBatchFileRequest) (File, error) {
|
||||||
|
if request.FileName == "" {
|
||||||
|
request.FileName = "@batchinput.jsonl"
|
||||||
|
}
|
||||||
|
return c.CreateFileBytes(ctx, FileBytesRequest{
|
||||||
|
Name: request.FileName,
|
||||||
|
Bytes: request.MarshalJSONL(),
|
||||||
|
Purpose: PurposeBatch,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateBatchWithUploadFileRequest struct {
|
||||||
|
Endpoint BatchEndpoint `json:"endpoint"`
|
||||||
|
CompletionWindow string `json:"completion_window"`
|
||||||
|
Metadata map[string]any `json:"metadata"`
|
||||||
|
UploadBatchFileRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateBatchWithUploadFile — API call to Create batch with upload file.
|
||||||
|
func (c *Client) CreateBatchWithUploadFile(
|
||||||
|
ctx context.Context,
|
||||||
|
request CreateBatchWithUploadFileRequest,
|
||||||
|
) (response BatchResponse, err error) {
|
||||||
|
var file File
|
||||||
|
file, err = c.UploadBatchFile(ctx, UploadBatchFileRequest{
|
||||||
|
FileName: request.FileName,
|
||||||
|
Lines: request.Lines,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return c.CreateBatch(ctx, CreateBatchRequest{
|
||||||
|
InputFileID: file.ID,
|
||||||
|
Endpoint: request.Endpoint,
|
||||||
|
CompletionWindow: request.CompletionWindow,
|
||||||
|
Metadata: request.Metadata,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveBatch — API call to Retrieve batch.
|
||||||
|
func (c *Client) RetrieveBatch(
|
||||||
|
ctx context.Context,
|
||||||
|
batchID string,
|
||||||
|
) (response BatchResponse, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s", batchesSuffix, batchID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelBatch — API call to Cancel batch.
|
||||||
|
func (c *Client) CancelBatch(
|
||||||
|
ctx context.Context,
|
||||||
|
batchID string,
|
||||||
|
) (response BatchResponse, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s/cancel", batchesSuffix, batchID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListBatchResponse struct {
|
||||||
|
httpHeader
|
||||||
|
Object string `json:"object"`
|
||||||
|
Data []Batch `json:"data"`
|
||||||
|
FirstID string `json:"first_id"`
|
||||||
|
LastID string `json:"last_id"`
|
||||||
|
HasMore bool `json:"has_more"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListBatch API call to List batch.
|
||||||
|
func (c *Client) ListBatch(ctx context.Context, after *string, limit *int) (response ListBatchResponse, err error) {
|
||||||
|
urlValues := url.Values{}
|
||||||
|
if limit != nil {
|
||||||
|
urlValues.Add("limit", fmt.Sprintf("%d", *limit))
|
||||||
|
}
|
||||||
|
if after != nil {
|
||||||
|
urlValues.Add("after", *after)
|
||||||
|
}
|
||||||
|
encodedValues := ""
|
||||||
|
if len(urlValues) > 0 {
|
||||||
|
encodedValues = "?" + urlValues.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
urlSuffix := fmt.Sprintf("%s%s", batchesSuffix, encodedValues)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
498
vendor/github.com/sashabaranov/go-openai/chat.go
generated
vendored
Normal file
498
vendor/github.com/sashabaranov/go-openai/chat.go
generated
vendored
Normal file
@@ -0,0 +1,498 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/sashabaranov/go-openai/jsonschema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Chat message role defined by the OpenAI API.
|
||||||
|
const (
|
||||||
|
ChatMessageRoleSystem = "system"
|
||||||
|
ChatMessageRoleUser = "user"
|
||||||
|
ChatMessageRoleAssistant = "assistant"
|
||||||
|
ChatMessageRoleFunction = "function"
|
||||||
|
ChatMessageRoleTool = "tool"
|
||||||
|
ChatMessageRoleDeveloper = "developer"
|
||||||
|
)
|
||||||
|
|
||||||
|
const chatCompletionsSuffix = "/chat/completions"
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrChatCompletionInvalidModel = errors.New("this model is not supported with this method, please use CreateCompletion client method instead") //nolint:lll
|
||||||
|
ErrChatCompletionStreamNotSupported = errors.New("streaming is not supported with this method, please use CreateChatCompletionStream") //nolint:lll
|
||||||
|
ErrContentFieldsMisused = errors.New("can't use both Content and MultiContent properties simultaneously")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Hate struct {
|
||||||
|
Filtered bool `json:"filtered"`
|
||||||
|
Severity string `json:"severity,omitempty"`
|
||||||
|
}
|
||||||
|
type SelfHarm struct {
|
||||||
|
Filtered bool `json:"filtered"`
|
||||||
|
Severity string `json:"severity,omitempty"`
|
||||||
|
}
|
||||||
|
type Sexual struct {
|
||||||
|
Filtered bool `json:"filtered"`
|
||||||
|
Severity string `json:"severity,omitempty"`
|
||||||
|
}
|
||||||
|
type Violence struct {
|
||||||
|
Filtered bool `json:"filtered"`
|
||||||
|
Severity string `json:"severity,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JailBreak struct {
|
||||||
|
Filtered bool `json:"filtered"`
|
||||||
|
Detected bool `json:"detected"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Profanity struct {
|
||||||
|
Filtered bool `json:"filtered"`
|
||||||
|
Detected bool `json:"detected"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContentFilterResults struct {
|
||||||
|
Hate Hate `json:"hate,omitempty"`
|
||||||
|
SelfHarm SelfHarm `json:"self_harm,omitempty"`
|
||||||
|
Sexual Sexual `json:"sexual,omitempty"`
|
||||||
|
Violence Violence `json:"violence,omitempty"`
|
||||||
|
JailBreak JailBreak `json:"jailbreak,omitempty"`
|
||||||
|
Profanity Profanity `json:"profanity,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PromptAnnotation struct {
|
||||||
|
PromptIndex int `json:"prompt_index,omitempty"`
|
||||||
|
ContentFilterResults ContentFilterResults `json:"content_filter_results,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageURLDetail string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ImageURLDetailHigh ImageURLDetail = "high"
|
||||||
|
ImageURLDetailLow ImageURLDetail = "low"
|
||||||
|
ImageURLDetailAuto ImageURLDetail = "auto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChatMessageImageURL struct {
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
|
Detail ImageURLDetail `json:"detail,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatMessagePartType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ChatMessagePartTypeText ChatMessagePartType = "text"
|
||||||
|
ChatMessagePartTypeImageURL ChatMessagePartType = "image_url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChatMessagePart struct {
|
||||||
|
Type ChatMessagePartType `json:"type,omitempty"`
|
||||||
|
Text string `json:"text,omitempty"`
|
||||||
|
ImageURL *ChatMessageImageURL `json:"image_url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatCompletionMessage struct {
|
||||||
|
Role string `json:"role"`
|
||||||
|
Content string `json:"content,omitempty"`
|
||||||
|
Refusal string `json:"refusal,omitempty"`
|
||||||
|
MultiContent []ChatMessagePart
|
||||||
|
|
||||||
|
// This property isn't in the official documentation, but it's in
|
||||||
|
// the documentation for the official library for python:
|
||||||
|
// - https://github.com/openai/openai-python/blob/main/chatml.md
|
||||||
|
// - https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
|
||||||
|
// This property is used for the "reasoning" feature supported by deepseek-reasoner
|
||||||
|
// which is not in the official documentation.
|
||||||
|
// the doc from deepseek:
|
||||||
|
// - https://api-docs.deepseek.com/api/create-chat-completion#responses
|
||||||
|
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||||
|
|
||||||
|
FunctionCall *FunctionCall `json:"function_call,omitempty"`
|
||||||
|
|
||||||
|
// For Role=assistant prompts this may be set to the tool calls generated by the model, such as function calls.
|
||||||
|
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||||
|
|
||||||
|
// For Role=tool prompts this should be set to the ID given in the assistant's prior request to call a tool.
|
||||||
|
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m ChatCompletionMessage) MarshalJSON() ([]byte, error) {
|
||||||
|
if m.Content != "" && m.MultiContent != nil {
|
||||||
|
return nil, ErrContentFieldsMisused
|
||||||
|
}
|
||||||
|
if len(m.MultiContent) > 0 {
|
||||||
|
msg := struct {
|
||||||
|
Role string `json:"role"`
|
||||||
|
Content string `json:"-"`
|
||||||
|
Refusal string `json:"refusal,omitempty"`
|
||||||
|
MultiContent []ChatMessagePart `json:"content,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||||
|
FunctionCall *FunctionCall `json:"function_call,omitempty"`
|
||||||
|
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||||
|
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||||
|
}(m)
|
||||||
|
return json.Marshal(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := struct {
|
||||||
|
Role string `json:"role"`
|
||||||
|
Content string `json:"content,omitempty"`
|
||||||
|
Refusal string `json:"refusal,omitempty"`
|
||||||
|
MultiContent []ChatMessagePart `json:"-"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||||
|
FunctionCall *FunctionCall `json:"function_call,omitempty"`
|
||||||
|
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||||
|
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||||
|
}(m)
|
||||||
|
return json.Marshal(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ChatCompletionMessage) UnmarshalJSON(bs []byte) error {
|
||||||
|
msg := struct {
|
||||||
|
Role string `json:"role"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Refusal string `json:"refusal,omitempty"`
|
||||||
|
MultiContent []ChatMessagePart
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||||
|
FunctionCall *FunctionCall `json:"function_call,omitempty"`
|
||||||
|
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||||
|
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(bs, &msg); err == nil {
|
||||||
|
*m = ChatCompletionMessage(msg)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
multiMsg := struct {
|
||||||
|
Role string `json:"role"`
|
||||||
|
Content string
|
||||||
|
Refusal string `json:"refusal,omitempty"`
|
||||||
|
MultiContent []ChatMessagePart `json:"content"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||||
|
FunctionCall *FunctionCall `json:"function_call,omitempty"`
|
||||||
|
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||||
|
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||||
|
}{}
|
||||||
|
if err := json.Unmarshal(bs, &multiMsg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*m = ChatCompletionMessage(multiMsg)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToolCall struct {
|
||||||
|
// Index is not nil only in chat completion chunk object
|
||||||
|
Index *int `json:"index,omitempty"`
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Type ToolType `json:"type"`
|
||||||
|
Function FunctionCall `json:"function"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FunctionCall struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
// call function with arguments in JSON format
|
||||||
|
Arguments string `json:"arguments,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatCompletionResponseFormatType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ChatCompletionResponseFormatTypeJSONObject ChatCompletionResponseFormatType = "json_object"
|
||||||
|
ChatCompletionResponseFormatTypeJSONSchema ChatCompletionResponseFormatType = "json_schema"
|
||||||
|
ChatCompletionResponseFormatTypeText ChatCompletionResponseFormatType = "text"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChatCompletionResponseFormat struct {
|
||||||
|
Type ChatCompletionResponseFormatType `json:"type,omitempty"`
|
||||||
|
JSONSchema *ChatCompletionResponseFormatJSONSchema `json:"json_schema,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatCompletionResponseFormatJSONSchema struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Schema json.Marshaler `json:"schema"`
|
||||||
|
Strict bool `json:"strict"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ChatCompletionResponseFormatJSONSchema) UnmarshalJSON(data []byte) error {
|
||||||
|
type rawJSONSchema struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Schema json.RawMessage `json:"schema"`
|
||||||
|
Strict bool `json:"strict"`
|
||||||
|
}
|
||||||
|
var raw rawJSONSchema
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.Name = raw.Name
|
||||||
|
r.Description = raw.Description
|
||||||
|
r.Strict = raw.Strict
|
||||||
|
if len(raw.Schema) > 0 && string(raw.Schema) != "null" {
|
||||||
|
var d jsonschema.Definition
|
||||||
|
err := json.Unmarshal(raw.Schema, &d)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.Schema = &d
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChatCompletionRequestExtensions contains third-party OpenAI API extensions
|
||||||
|
// (e.g., vendor-specific implementations like vLLM).
|
||||||
|
type ChatCompletionRequestExtensions struct {
|
||||||
|
// GuidedChoice is a vLLM-specific extension that restricts the model's output
|
||||||
|
// to one of the predefined string choices provided in this field. This feature
|
||||||
|
// is used to constrain the model's responses to a controlled set of options,
|
||||||
|
// ensuring predictable and consistent outputs in scenarios where specific
|
||||||
|
// choices are required.
|
||||||
|
GuidedChoice []string `json:"guided_choice,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChatCompletionRequest represents a request structure for chat completion API.
|
||||||
|
type ChatCompletionRequest struct {
|
||||||
|
Model string `json:"model"`
|
||||||
|
Messages []ChatCompletionMessage `json:"messages"`
|
||||||
|
// MaxTokens The maximum number of tokens that can be generated in the chat completion.
|
||||||
|
// This value can be used to control costs for text generated via API.
|
||||||
|
// Deprecated: use MaxCompletionTokens. Not compatible with o1-series models.
|
||||||
|
// refs: https://platform.openai.com/docs/api-reference/chat/create#chat-create-max_tokens
|
||||||
|
MaxTokens int `json:"max_tokens,omitempty"`
|
||||||
|
// MaxCompletionTokens An upper bound for the number of tokens that can be generated for a completion,
|
||||||
|
// including visible output tokens and reasoning tokens https://platform.openai.com/docs/guides/reasoning
|
||||||
|
MaxCompletionTokens int `json:"max_completion_tokens,omitempty"`
|
||||||
|
Temperature float32 `json:"temperature,omitempty"`
|
||||||
|
TopP float32 `json:"top_p,omitempty"`
|
||||||
|
N int `json:"n,omitempty"`
|
||||||
|
Stream bool `json:"stream,omitempty"`
|
||||||
|
Stop []string `json:"stop,omitempty"`
|
||||||
|
PresencePenalty float32 `json:"presence_penalty,omitempty"`
|
||||||
|
ResponseFormat *ChatCompletionResponseFormat `json:"response_format,omitempty"`
|
||||||
|
Seed *int `json:"seed,omitempty"`
|
||||||
|
FrequencyPenalty float32 `json:"frequency_penalty,omitempty"`
|
||||||
|
// LogitBias is must be a token id string (specified by their token ID in the tokenizer), not a word string.
|
||||||
|
// incorrect: `"logit_bias":{"You": 6}`, correct: `"logit_bias":{"1639": 6}`
|
||||||
|
// refs: https://platform.openai.com/docs/api-reference/chat/create#chat/create-logit_bias
|
||||||
|
LogitBias map[string]int `json:"logit_bias,omitempty"`
|
||||||
|
// LogProbs indicates whether to return log probabilities of the output tokens or not.
|
||||||
|
// If true, returns the log probabilities of each output token returned in the content of message.
|
||||||
|
// This option is currently not available on the gpt-4-vision-preview model.
|
||||||
|
LogProbs bool `json:"logprobs,omitempty"`
|
||||||
|
// TopLogProbs is an integer between 0 and 5 specifying the number of most likely tokens to return at each
|
||||||
|
// token position, each with an associated log probability.
|
||||||
|
// logprobs must be set to true if this parameter is used.
|
||||||
|
TopLogProbs int `json:"top_logprobs,omitempty"`
|
||||||
|
User string `json:"user,omitempty"`
|
||||||
|
// Deprecated: use Tools instead.
|
||||||
|
Functions []FunctionDefinition `json:"functions,omitempty"`
|
||||||
|
// Deprecated: use ToolChoice instead.
|
||||||
|
FunctionCall any `json:"function_call,omitempty"`
|
||||||
|
Tools []Tool `json:"tools,omitempty"`
|
||||||
|
// This can be either a string or an ToolChoice object.
|
||||||
|
ToolChoice any `json:"tool_choice,omitempty"`
|
||||||
|
// Options for streaming response. Only set this when you set stream: true.
|
||||||
|
StreamOptions *StreamOptions `json:"stream_options,omitempty"`
|
||||||
|
// Disable the default behavior of parallel tool calls by setting it: false.
|
||||||
|
ParallelToolCalls any `json:"parallel_tool_calls,omitempty"`
|
||||||
|
// Store can be set to true to store the output of this completion request for use in distillations and evals.
|
||||||
|
// https://platform.openai.com/docs/api-reference/chat/create#chat-create-store
|
||||||
|
Store bool `json:"store,omitempty"`
|
||||||
|
// Controls effort on reasoning for reasoning models. It can be set to "low", "medium", or "high".
|
||||||
|
ReasoningEffort string `json:"reasoning_effort,omitempty"`
|
||||||
|
// Metadata to store with the completion.
|
||||||
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
|
// Configuration for a predicted output.
|
||||||
|
Prediction *Prediction `json:"prediction,omitempty"`
|
||||||
|
// ChatTemplateKwargs provides a way to add non-standard parameters to the request body.
|
||||||
|
// Additional kwargs to pass to the template renderer. Will be accessible by the chat template.
|
||||||
|
// Such as think mode for qwen3. "chat_template_kwargs": {"enable_thinking": false}
|
||||||
|
// https://qwen.readthedocs.io/en/latest/deployment/vllm.html#thinking-non-thinking-modes
|
||||||
|
ChatTemplateKwargs map[string]any `json:"chat_template_kwargs,omitempty"`
|
||||||
|
// Specifies the latency tier to use for processing the request.
|
||||||
|
ServiceTier ServiceTier `json:"service_tier,omitempty"`
|
||||||
|
// Verbosity determines how many output tokens are generated. Lowering the number of
|
||||||
|
// tokens reduces overall latency. It can be set to "low", "medium", or "high".
|
||||||
|
// Note: This field is only confirmed to work with gpt-5, gpt-5-mini and gpt-5-nano.
|
||||||
|
// Also, it is not in the API reference of chat completion at the time of writing,
|
||||||
|
// though it is supported by the API.
|
||||||
|
Verbosity string `json:"verbosity,omitempty"`
|
||||||
|
// A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies.
|
||||||
|
// The IDs should be a string that uniquely identifies each user.
|
||||||
|
// We recommend hashing their username or email address, in order to avoid sending us any identifying information.
|
||||||
|
// https://platform.openai.com/docs/api-reference/chat/create#chat_create-safety_identifier
|
||||||
|
SafetyIdentifier string `json:"safety_identifier,omitempty"`
|
||||||
|
// Embedded struct for non-OpenAI extensions
|
||||||
|
ChatCompletionRequestExtensions
|
||||||
|
}
|
||||||
|
|
||||||
|
type StreamOptions struct {
|
||||||
|
// If set, an additional chunk will be streamed before the data: [DONE] message.
|
||||||
|
// The usage field on this chunk shows the token usage statistics for the entire request,
|
||||||
|
// and the choices field will always be an empty array.
|
||||||
|
// All other chunks will also include a usage field, but with a null value.
|
||||||
|
IncludeUsage bool `json:"include_usage,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToolType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ToolTypeFunction ToolType = "function"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Tool struct {
|
||||||
|
Type ToolType `json:"type"`
|
||||||
|
Function *FunctionDefinition `json:"function,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToolChoice struct {
|
||||||
|
Type ToolType `json:"type"`
|
||||||
|
Function ToolFunction `json:"function,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToolFunction struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FunctionDefinition struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Strict bool `json:"strict,omitempty"`
|
||||||
|
// Parameters is an object describing the function.
|
||||||
|
// You can pass json.RawMessage to describe the schema,
|
||||||
|
// or you can pass in a struct which serializes to the proper JSON schema.
|
||||||
|
// The jsonschema package is provided for convenience, but you should
|
||||||
|
// consider another specialized library if you require more complex schemas.
|
||||||
|
Parameters any `json:"parameters"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: use FunctionDefinition instead.
|
||||||
|
type FunctionDefine = FunctionDefinition
|
||||||
|
|
||||||
|
type TopLogProbs struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
LogProb float64 `json:"logprob"`
|
||||||
|
Bytes []byte `json:"bytes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogProb represents the probability information for a token.
|
||||||
|
type LogProb struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
LogProb float64 `json:"logprob"`
|
||||||
|
Bytes []byte `json:"bytes,omitempty"` // Omitting the field if it is null
|
||||||
|
// TopLogProbs is a list of the most likely tokens and their log probability, at this token position.
|
||||||
|
// In rare cases, there may be fewer than the number of requested top_logprobs returned.
|
||||||
|
TopLogProbs []TopLogProbs `json:"top_logprobs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogProbs is the top-level structure containing the log probability information.
|
||||||
|
type LogProbs struct {
|
||||||
|
// Content is a list of message content tokens with log probability information.
|
||||||
|
Content []LogProb `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Prediction struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FinishReason string
|
||||||
|
|
||||||
|
const (
|
||||||
|
FinishReasonStop FinishReason = "stop"
|
||||||
|
FinishReasonLength FinishReason = "length"
|
||||||
|
FinishReasonFunctionCall FinishReason = "function_call"
|
||||||
|
FinishReasonToolCalls FinishReason = "tool_calls"
|
||||||
|
FinishReasonContentFilter FinishReason = "content_filter"
|
||||||
|
FinishReasonNull FinishReason = "null"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceTier string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ServiceTierAuto ServiceTier = "auto"
|
||||||
|
ServiceTierDefault ServiceTier = "default"
|
||||||
|
ServiceTierFlex ServiceTier = "flex"
|
||||||
|
ServiceTierPriority ServiceTier = "priority"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r FinishReason) MarshalJSON() ([]byte, error) {
|
||||||
|
if r == FinishReasonNull || r == "" {
|
||||||
|
return []byte("null"), nil
|
||||||
|
}
|
||||||
|
return []byte(`"` + string(r) + `"`), nil // best effort to not break future API changes
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatCompletionChoice struct {
|
||||||
|
Index int `json:"index"`
|
||||||
|
Message ChatCompletionMessage `json:"message"`
|
||||||
|
// FinishReason
|
||||||
|
// stop: API returned complete message,
|
||||||
|
// or a message terminated by one of the stop sequences provided via the stop parameter
|
||||||
|
// length: Incomplete model output due to max_tokens parameter or token limit
|
||||||
|
// function_call: The model decided to call a function
|
||||||
|
// content_filter: Omitted content due to a flag from our content filters
|
||||||
|
// null: API response still in progress or incomplete
|
||||||
|
FinishReason FinishReason `json:"finish_reason"`
|
||||||
|
LogProbs *LogProbs `json:"logprobs,omitempty"`
|
||||||
|
ContentFilterResults ContentFilterResults `json:"content_filter_results,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChatCompletionResponse represents a response structure for chat completion API.
|
||||||
|
type ChatCompletionResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
Created int64 `json:"created"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
Choices []ChatCompletionChoice `json:"choices"`
|
||||||
|
Usage Usage `json:"usage"`
|
||||||
|
SystemFingerprint string `json:"system_fingerprint"`
|
||||||
|
PromptFilterResults []PromptFilterResult `json:"prompt_filter_results,omitempty"`
|
||||||
|
ServiceTier ServiceTier `json:"service_tier,omitempty"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateChatCompletion — API call to Create a completion for the chat message.
|
||||||
|
func (c *Client) CreateChatCompletion(
|
||||||
|
ctx context.Context,
|
||||||
|
request ChatCompletionRequest,
|
||||||
|
) (response ChatCompletionResponse, err error) {
|
||||||
|
if request.Stream {
|
||||||
|
err = ErrChatCompletionStreamNotSupported
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
urlSuffix := chatCompletionsSuffix
|
||||||
|
if !checkEndpointSupportsModel(urlSuffix, request.Model) {
|
||||||
|
err = ErrChatCompletionInvalidModel
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reasoningValidator := NewReasoningValidator()
|
||||||
|
if err = reasoningValidator.Validate(request); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL(urlSuffix, withModel(request.Model)),
|
||||||
|
withBody(request),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
112
vendor/github.com/sashabaranov/go-openai/chat_stream.go
generated
vendored
Normal file
112
vendor/github.com/sashabaranov/go-openai/chat_stream.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ChatCompletionStreamChoiceDelta struct {
|
||||||
|
Content string `json:"content,omitempty"`
|
||||||
|
Role string `json:"role,omitempty"`
|
||||||
|
FunctionCall *FunctionCall `json:"function_call,omitempty"`
|
||||||
|
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||||
|
Refusal string `json:"refusal,omitempty"`
|
||||||
|
|
||||||
|
// This property is used for the "reasoning" feature supported by deepseek-reasoner
|
||||||
|
// which is not in the official documentation.
|
||||||
|
// the doc from deepseek:
|
||||||
|
// - https://api-docs.deepseek.com/api/create-chat-completion#responses
|
||||||
|
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatCompletionStreamChoiceLogprobs struct {
|
||||||
|
Content []ChatCompletionTokenLogprob `json:"content,omitempty"`
|
||||||
|
Refusal []ChatCompletionTokenLogprob `json:"refusal,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatCompletionTokenLogprob struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
Bytes []int64 `json:"bytes,omitempty"`
|
||||||
|
Logprob float64 `json:"logprob,omitempty"`
|
||||||
|
TopLogprobs []ChatCompletionTokenLogprobTopLogprob `json:"top_logprobs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatCompletionTokenLogprobTopLogprob struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
Bytes []int64 `json:"bytes"`
|
||||||
|
Logprob float64 `json:"logprob"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatCompletionStreamChoice struct {
|
||||||
|
Index int `json:"index"`
|
||||||
|
Delta ChatCompletionStreamChoiceDelta `json:"delta"`
|
||||||
|
Logprobs *ChatCompletionStreamChoiceLogprobs `json:"logprobs,omitempty"`
|
||||||
|
FinishReason FinishReason `json:"finish_reason"`
|
||||||
|
ContentFilterResults ContentFilterResults `json:"content_filter_results,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PromptFilterResult struct {
|
||||||
|
Index int `json:"index"`
|
||||||
|
ContentFilterResults ContentFilterResults `json:"content_filter_results,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatCompletionStreamResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
Created int64 `json:"created"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
Choices []ChatCompletionStreamChoice `json:"choices"`
|
||||||
|
SystemFingerprint string `json:"system_fingerprint"`
|
||||||
|
PromptAnnotations []PromptAnnotation `json:"prompt_annotations,omitempty"`
|
||||||
|
PromptFilterResults []PromptFilterResult `json:"prompt_filter_results,omitempty"`
|
||||||
|
// An optional field that will only be present when you set stream_options: {"include_usage": true} in your request.
|
||||||
|
// When present, it contains a null value except for the last chunk which contains the token usage statistics
|
||||||
|
// for the entire request.
|
||||||
|
Usage *Usage `json:"usage,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChatCompletionStream
|
||||||
|
// Note: Perhaps it is more elegant to abstract Stream using generics.
|
||||||
|
type ChatCompletionStream struct {
|
||||||
|
*streamReader[ChatCompletionStreamResponse]
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateChatCompletionStream — API call to create a chat completion w/ streaming
|
||||||
|
// support. It sets whether to stream back partial progress. If set, tokens will be
|
||||||
|
// sent as data-only server-sent events as they become available, with the
|
||||||
|
// stream terminated by a data: [DONE] message.
|
||||||
|
func (c *Client) CreateChatCompletionStream(
|
||||||
|
ctx context.Context,
|
||||||
|
request ChatCompletionRequest,
|
||||||
|
) (stream *ChatCompletionStream, err error) {
|
||||||
|
urlSuffix := chatCompletionsSuffix
|
||||||
|
if !checkEndpointSupportsModel(urlSuffix, request.Model) {
|
||||||
|
err = ErrChatCompletionInvalidModel
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Stream = true
|
||||||
|
reasoningValidator := NewReasoningValidator()
|
||||||
|
if err = reasoningValidator.Validate(request); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL(urlSuffix, withModel(request.Model)),
|
||||||
|
withBody(request),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := sendRequestStream[ChatCompletionStreamResponse](c, req)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
stream = &ChatCompletionStream{
|
||||||
|
streamReader: resp,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
341
vendor/github.com/sashabaranov/go-openai/client.go
generated
vendored
Normal file
341
vendor/github.com/sashabaranov/go-openai/client.go
generated
vendored
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
utils "github.com/sashabaranov/go-openai/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client is OpenAI GPT-3 API client.
|
||||||
|
type Client struct {
|
||||||
|
config ClientConfig
|
||||||
|
|
||||||
|
requestBuilder utils.RequestBuilder
|
||||||
|
createFormBuilder func(io.Writer) utils.FormBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response interface {
|
||||||
|
SetHeader(http.Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
type httpHeader http.Header
|
||||||
|
|
||||||
|
func (h *httpHeader) SetHeader(header http.Header) {
|
||||||
|
*h = httpHeader(header)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpHeader) Header() http.Header {
|
||||||
|
return http.Header(*h)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *httpHeader) GetRateLimitHeaders() RateLimitHeaders {
|
||||||
|
return newRateLimitHeaders(h.Header())
|
||||||
|
}
|
||||||
|
|
||||||
|
type RawResponse struct {
|
||||||
|
io.ReadCloser
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient creates new OpenAI API client.
|
||||||
|
func NewClient(authToken string) *Client {
|
||||||
|
config := DefaultConfig(authToken)
|
||||||
|
return NewClientWithConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClientWithConfig creates new OpenAI API client for specified config.
|
||||||
|
func NewClientWithConfig(config ClientConfig) *Client {
|
||||||
|
return &Client{
|
||||||
|
config: config,
|
||||||
|
requestBuilder: utils.NewRequestBuilder(),
|
||||||
|
createFormBuilder: func(body io.Writer) utils.FormBuilder {
|
||||||
|
return utils.NewFormBuilder(body)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOrgClient creates new OpenAI API client for specified Organization ID.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use NewClientWithConfig.
|
||||||
|
func NewOrgClient(authToken, org string) *Client {
|
||||||
|
config := DefaultConfig(authToken)
|
||||||
|
config.OrgID = org
|
||||||
|
return NewClientWithConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
type requestOptions struct {
|
||||||
|
body any
|
||||||
|
header http.Header
|
||||||
|
}
|
||||||
|
|
||||||
|
type requestOption func(*requestOptions)
|
||||||
|
|
||||||
|
func withBody(body any) requestOption {
|
||||||
|
return func(args *requestOptions) {
|
||||||
|
args.body = body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func withExtraBody(extraBody map[string]any) requestOption {
|
||||||
|
return func(args *requestOptions) {
|
||||||
|
// Assert that args.body is a map[string]any.
|
||||||
|
bodyMap, ok := args.body.(map[string]any)
|
||||||
|
if ok {
|
||||||
|
// If it's a map[string]any then only add extraBody
|
||||||
|
// fields to args.body otherwise keep only fields in request struct.
|
||||||
|
for key, value := range extraBody {
|
||||||
|
bodyMap[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func withContentType(contentType string) requestOption {
|
||||||
|
return func(args *requestOptions) {
|
||||||
|
args.header.Set("Content-Type", contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func withBetaAssistantVersion(version string) requestOption {
|
||||||
|
return func(args *requestOptions) {
|
||||||
|
args.header.Set("OpenAI-Beta", fmt.Sprintf("assistants=%s", version))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) newRequest(ctx context.Context, method, url string, setters ...requestOption) (*http.Request, error) {
|
||||||
|
// Default Options
|
||||||
|
args := &requestOptions{
|
||||||
|
body: nil,
|
||||||
|
header: make(http.Header),
|
||||||
|
}
|
||||||
|
for _, setter := range setters {
|
||||||
|
setter(args)
|
||||||
|
}
|
||||||
|
req, err := c.requestBuilder.Build(ctx, method, url, args.body, args.header)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.setCommonHeaders(req)
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) sendRequest(req *http.Request, v Response) error {
|
||||||
|
req.Header.Set("Accept", "application/json")
|
||||||
|
|
||||||
|
// Check whether Content-Type is already set, Upload Files API requires
|
||||||
|
// Content-Type == multipart/form-data
|
||||||
|
contentType := req.Header.Get("Content-Type")
|
||||||
|
if contentType == "" {
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := c.config.HTTPClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
if v != nil {
|
||||||
|
v.SetHeader(res.Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isFailureStatusCode(res) {
|
||||||
|
return c.handleErrorResp(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
return decodeResponse(res.Body, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) sendRequestRaw(req *http.Request) (response RawResponse, err error) {
|
||||||
|
resp, err := c.config.HTTPClient.Do(req) //nolint:bodyclose // body should be closed by outer function
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if isFailureStatusCode(resp) {
|
||||||
|
err = c.handleErrorResp(resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.SetHeader(resp.Header)
|
||||||
|
response.ReadCloser = resp.Body
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendRequestStream[T streamable](client *Client, req *http.Request) (*streamReader[T], error) {
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("Accept", "text/event-stream")
|
||||||
|
req.Header.Set("Cache-Control", "no-cache")
|
||||||
|
req.Header.Set("Connection", "keep-alive")
|
||||||
|
|
||||||
|
resp, err := client.config.HTTPClient.Do(req) //nolint:bodyclose // body is closed in stream.Close()
|
||||||
|
if err != nil {
|
||||||
|
return new(streamReader[T]), err
|
||||||
|
}
|
||||||
|
if isFailureStatusCode(resp) {
|
||||||
|
return new(streamReader[T]), client.handleErrorResp(resp)
|
||||||
|
}
|
||||||
|
return &streamReader[T]{
|
||||||
|
emptyMessagesLimit: client.config.EmptyMessagesLimit,
|
||||||
|
reader: bufio.NewReader(resp.Body),
|
||||||
|
response: resp,
|
||||||
|
errAccumulator: utils.NewErrorAccumulator(),
|
||||||
|
unmarshaler: &utils.JSONUnmarshaler{},
|
||||||
|
httpHeader: httpHeader(resp.Header),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) setCommonHeaders(req *http.Request) {
|
||||||
|
// https://learn.microsoft.com/en-us/azure/cognitive-services/openai/reference#authentication
|
||||||
|
switch c.config.APIType {
|
||||||
|
case APITypeAzure, APITypeCloudflareAzure:
|
||||||
|
// Azure API Key authentication
|
||||||
|
req.Header.Set(AzureAPIKeyHeader, c.config.authToken)
|
||||||
|
case APITypeAnthropic:
|
||||||
|
// https://docs.anthropic.com/en/api/versioning
|
||||||
|
req.Header.Set("anthropic-version", c.config.APIVersion)
|
||||||
|
case APITypeOpenAI, APITypeAzureAD:
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
if c.config.authToken != "" {
|
||||||
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.config.authToken))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.config.OrgID != "" {
|
||||||
|
req.Header.Set("OpenAI-Organization", c.config.OrgID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isFailureStatusCode(resp *http.Response) bool {
|
||||||
|
return resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeResponse(body io.Reader, v any) error {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch o := v.(type) {
|
||||||
|
case *string:
|
||||||
|
return decodeString(body, o)
|
||||||
|
case *audioTextResponse:
|
||||||
|
return decodeString(body, &o.Text)
|
||||||
|
default:
|
||||||
|
return json.NewDecoder(body).Decode(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeString(body io.Reader, output *string) error {
|
||||||
|
b, err := io.ReadAll(body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*output = string(b)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type fullURLOptions struct {
|
||||||
|
model string
|
||||||
|
}
|
||||||
|
|
||||||
|
type fullURLOption func(*fullURLOptions)
|
||||||
|
|
||||||
|
func withModel(model string) fullURLOption {
|
||||||
|
return func(args *fullURLOptions) {
|
||||||
|
args.model = model
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var azureDeploymentsEndpoints = []string{
|
||||||
|
"/completions",
|
||||||
|
"/embeddings",
|
||||||
|
"/chat/completions",
|
||||||
|
"/audio/transcriptions",
|
||||||
|
"/audio/translations",
|
||||||
|
"/audio/speech",
|
||||||
|
"/images/generations",
|
||||||
|
}
|
||||||
|
|
||||||
|
// fullURL returns full URL for request.
|
||||||
|
func (c *Client) fullURL(suffix string, setters ...fullURLOption) string {
|
||||||
|
baseURL := strings.TrimRight(c.config.BaseURL, "/")
|
||||||
|
args := fullURLOptions{}
|
||||||
|
for _, setter := range setters {
|
||||||
|
setter(&args)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.config.APIType == APITypeAzure || c.config.APIType == APITypeAzureAD {
|
||||||
|
baseURL = c.baseURLWithAzureDeployment(baseURL, suffix, args.model)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.config.APIVersion != "" {
|
||||||
|
suffix = c.suffixWithAPIVersion(suffix)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s%s", baseURL, suffix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) suffixWithAPIVersion(suffix string) string {
|
||||||
|
parsedSuffix, err := url.Parse(suffix)
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to parse url suffix")
|
||||||
|
}
|
||||||
|
query := parsedSuffix.Query()
|
||||||
|
query.Add("api-version", c.config.APIVersion)
|
||||||
|
return fmt.Sprintf("%s?%s", parsedSuffix.Path, query.Encode())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) baseURLWithAzureDeployment(baseURL, suffix, model string) (newBaseURL string) {
|
||||||
|
baseURL = fmt.Sprintf("%s/%s", strings.TrimRight(baseURL, "/"), azureAPIPrefix)
|
||||||
|
if containsSubstr(azureDeploymentsEndpoints, suffix) {
|
||||||
|
azureDeploymentName := c.config.GetAzureDeploymentByModel(model)
|
||||||
|
if azureDeploymentName == "" {
|
||||||
|
azureDeploymentName = "UNKNOWN"
|
||||||
|
}
|
||||||
|
baseURL = fmt.Sprintf("%s/%s/%s", baseURL, azureDeploymentsPrefix, azureDeploymentName)
|
||||||
|
}
|
||||||
|
return baseURL
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) handleErrorResp(resp *http.Response) error {
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error, reading response body: %w", err)
|
||||||
|
}
|
||||||
|
var errRes ErrorResponse
|
||||||
|
err = json.Unmarshal(body, &errRes)
|
||||||
|
if err != nil || errRes.Error == nil {
|
||||||
|
reqErr := &RequestError{
|
||||||
|
HTTPStatus: resp.Status,
|
||||||
|
HTTPStatusCode: resp.StatusCode,
|
||||||
|
Err: err,
|
||||||
|
Body: body,
|
||||||
|
}
|
||||||
|
if errRes.Error != nil {
|
||||||
|
reqErr.Err = errRes.Error
|
||||||
|
}
|
||||||
|
return reqErr
|
||||||
|
}
|
||||||
|
|
||||||
|
errRes.Error.HTTPStatus = resp.Status
|
||||||
|
errRes.Error.HTTPStatusCode = resp.StatusCode
|
||||||
|
return errRes.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsSubstr(s []string, e string) bool {
|
||||||
|
for _, v := range s {
|
||||||
|
if strings.Contains(e, v) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
26
vendor/github.com/sashabaranov/go-openai/common.go
generated
vendored
Normal file
26
vendor/github.com/sashabaranov/go-openai/common.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
// common.go defines common types used throughout the OpenAI API.
|
||||||
|
|
||||||
|
// Usage Represents the total token usage per request to OpenAI.
|
||||||
|
type Usage struct {
|
||||||
|
PromptTokens int `json:"prompt_tokens"`
|
||||||
|
CompletionTokens int `json:"completion_tokens"`
|
||||||
|
TotalTokens int `json:"total_tokens"`
|
||||||
|
PromptTokensDetails *PromptTokensDetails `json:"prompt_tokens_details"`
|
||||||
|
CompletionTokensDetails *CompletionTokensDetails `json:"completion_tokens_details"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompletionTokensDetails Breakdown of tokens used in a completion.
|
||||||
|
type CompletionTokensDetails struct {
|
||||||
|
AudioTokens int `json:"audio_tokens"`
|
||||||
|
ReasoningTokens int `json:"reasoning_tokens"`
|
||||||
|
AcceptedPredictionTokens int `json:"accepted_prediction_tokens"`
|
||||||
|
RejectedPredictionTokens int `json:"rejected_prediction_tokens"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PromptTokensDetails Breakdown of tokens used in the prompt.
|
||||||
|
type PromptTokensDetails struct {
|
||||||
|
AudioTokens int `json:"audio_tokens"`
|
||||||
|
CachedTokens int `json:"cached_tokens"`
|
||||||
|
}
|
||||||
295
vendor/github.com/sashabaranov/go-openai/completion.go
generated
vendored
Normal file
295
vendor/github.com/sashabaranov/go-openai/completion.go
generated
vendored
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GPT3 Defines the models provided by OpenAI to use when generating
|
||||||
|
// completions from OpenAI.
|
||||||
|
// GPT3 Models are designed for text-based tasks. For code-specific
|
||||||
|
// tasks, please refer to the Codex series of models.
|
||||||
|
const (
|
||||||
|
O1Mini = "o1-mini"
|
||||||
|
O1Mini20240912 = "o1-mini-2024-09-12"
|
||||||
|
O1Preview = "o1-preview"
|
||||||
|
O1Preview20240912 = "o1-preview-2024-09-12"
|
||||||
|
O1 = "o1"
|
||||||
|
O120241217 = "o1-2024-12-17"
|
||||||
|
O3 = "o3"
|
||||||
|
O320250416 = "o3-2025-04-16"
|
||||||
|
O3Mini = "o3-mini"
|
||||||
|
O3Mini20250131 = "o3-mini-2025-01-31"
|
||||||
|
O4Mini = "o4-mini"
|
||||||
|
O4Mini20250416 = "o4-mini-2025-04-16"
|
||||||
|
GPT432K0613 = "gpt-4-32k-0613"
|
||||||
|
GPT432K0314 = "gpt-4-32k-0314"
|
||||||
|
GPT432K = "gpt-4-32k"
|
||||||
|
GPT40613 = "gpt-4-0613"
|
||||||
|
GPT40314 = "gpt-4-0314"
|
||||||
|
GPT4o = "gpt-4o"
|
||||||
|
GPT4o20240513 = "gpt-4o-2024-05-13"
|
||||||
|
GPT4o20240806 = "gpt-4o-2024-08-06"
|
||||||
|
GPT4o20241120 = "gpt-4o-2024-11-20"
|
||||||
|
GPT4oLatest = "chatgpt-4o-latest"
|
||||||
|
GPT4oMini = "gpt-4o-mini"
|
||||||
|
GPT4oMini20240718 = "gpt-4o-mini-2024-07-18"
|
||||||
|
GPT4Turbo = "gpt-4-turbo"
|
||||||
|
GPT4Turbo20240409 = "gpt-4-turbo-2024-04-09"
|
||||||
|
GPT4Turbo0125 = "gpt-4-0125-preview"
|
||||||
|
GPT4Turbo1106 = "gpt-4-1106-preview"
|
||||||
|
GPT4TurboPreview = "gpt-4-turbo-preview"
|
||||||
|
GPT4VisionPreview = "gpt-4-vision-preview"
|
||||||
|
GPT4 = "gpt-4"
|
||||||
|
GPT4Dot1 = "gpt-4.1"
|
||||||
|
GPT4Dot120250414 = "gpt-4.1-2025-04-14"
|
||||||
|
GPT4Dot1Mini = "gpt-4.1-mini"
|
||||||
|
GPT4Dot1Mini20250414 = "gpt-4.1-mini-2025-04-14"
|
||||||
|
GPT4Dot1Nano = "gpt-4.1-nano"
|
||||||
|
GPT4Dot1Nano20250414 = "gpt-4.1-nano-2025-04-14"
|
||||||
|
GPT4Dot5Preview = "gpt-4.5-preview"
|
||||||
|
GPT4Dot5Preview20250227 = "gpt-4.5-preview-2025-02-27"
|
||||||
|
GPT5 = "gpt-5"
|
||||||
|
GPT5Mini = "gpt-5-mini"
|
||||||
|
GPT5Nano = "gpt-5-nano"
|
||||||
|
GPT5ChatLatest = "gpt-5-chat-latest"
|
||||||
|
GPT3Dot5Turbo0125 = "gpt-3.5-turbo-0125"
|
||||||
|
GPT3Dot5Turbo1106 = "gpt-3.5-turbo-1106"
|
||||||
|
GPT3Dot5Turbo0613 = "gpt-3.5-turbo-0613"
|
||||||
|
GPT3Dot5Turbo0301 = "gpt-3.5-turbo-0301"
|
||||||
|
GPT3Dot5Turbo16K = "gpt-3.5-turbo-16k"
|
||||||
|
GPT3Dot5Turbo16K0613 = "gpt-3.5-turbo-16k-0613"
|
||||||
|
GPT3Dot5Turbo = "gpt-3.5-turbo"
|
||||||
|
GPT3Dot5TurboInstruct = "gpt-3.5-turbo-instruct"
|
||||||
|
// Deprecated: Model is shutdown. Use gpt-3.5-turbo-instruct instead.
|
||||||
|
GPT3TextDavinci003 = "text-davinci-003"
|
||||||
|
// Deprecated: Model is shutdown. Use gpt-3.5-turbo-instruct instead.
|
||||||
|
GPT3TextDavinci002 = "text-davinci-002"
|
||||||
|
// Deprecated: Model is shutdown. Use gpt-3.5-turbo-instruct instead.
|
||||||
|
GPT3TextCurie001 = "text-curie-001"
|
||||||
|
// Deprecated: Model is shutdown. Use gpt-3.5-turbo-instruct instead.
|
||||||
|
GPT3TextBabbage001 = "text-babbage-001"
|
||||||
|
// Deprecated: Model is shutdown. Use gpt-3.5-turbo-instruct instead.
|
||||||
|
GPT3TextAda001 = "text-ada-001"
|
||||||
|
// Deprecated: Model is shutdown. Use gpt-3.5-turbo-instruct instead.
|
||||||
|
GPT3TextDavinci001 = "text-davinci-001"
|
||||||
|
// Deprecated: Model is shutdown. Use gpt-3.5-turbo-instruct instead.
|
||||||
|
GPT3DavinciInstructBeta = "davinci-instruct-beta"
|
||||||
|
// Deprecated: Model is shutdown. Use davinci-002 instead.
|
||||||
|
GPT3Davinci = "davinci"
|
||||||
|
GPT3Davinci002 = "davinci-002"
|
||||||
|
// Deprecated: Model is shutdown. Use gpt-3.5-turbo-instruct instead.
|
||||||
|
GPT3CurieInstructBeta = "curie-instruct-beta"
|
||||||
|
GPT3Curie = "curie"
|
||||||
|
GPT3Curie002 = "curie-002"
|
||||||
|
// Deprecated: Model is shutdown. Use babbage-002 instead.
|
||||||
|
GPT3Ada = "ada"
|
||||||
|
GPT3Ada002 = "ada-002"
|
||||||
|
// Deprecated: Model is shutdown. Use babbage-002 instead.
|
||||||
|
GPT3Babbage = "babbage"
|
||||||
|
GPT3Babbage002 = "babbage-002"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Codex Defines the models provided by OpenAI.
|
||||||
|
// These models are designed for code-specific tasks, and use
|
||||||
|
// a different tokenizer which optimizes for whitespace.
|
||||||
|
const (
|
||||||
|
CodexCodeDavinci002 = "code-davinci-002"
|
||||||
|
CodexCodeCushman001 = "code-cushman-001"
|
||||||
|
CodexCodeDavinci001 = "code-davinci-001"
|
||||||
|
)
|
||||||
|
|
||||||
|
var disabledModelsForEndpoints = map[string]map[string]bool{
|
||||||
|
"/completions": {
|
||||||
|
O1Mini: true,
|
||||||
|
O1Mini20240912: true,
|
||||||
|
O1Preview: true,
|
||||||
|
O1Preview20240912: true,
|
||||||
|
O3Mini: true,
|
||||||
|
O3Mini20250131: true,
|
||||||
|
O4Mini: true,
|
||||||
|
O4Mini20250416: true,
|
||||||
|
O3: true,
|
||||||
|
O320250416: true,
|
||||||
|
GPT3Dot5Turbo: true,
|
||||||
|
GPT3Dot5Turbo0301: true,
|
||||||
|
GPT3Dot5Turbo0613: true,
|
||||||
|
GPT3Dot5Turbo1106: true,
|
||||||
|
GPT3Dot5Turbo0125: true,
|
||||||
|
GPT3Dot5Turbo16K: true,
|
||||||
|
GPT3Dot5Turbo16K0613: true,
|
||||||
|
GPT4: true,
|
||||||
|
GPT4Dot5Preview: true,
|
||||||
|
GPT4Dot5Preview20250227: true,
|
||||||
|
GPT4o: true,
|
||||||
|
GPT4o20240513: true,
|
||||||
|
GPT4o20240806: true,
|
||||||
|
GPT4o20241120: true,
|
||||||
|
GPT4oLatest: true,
|
||||||
|
GPT4oMini: true,
|
||||||
|
GPT4oMini20240718: true,
|
||||||
|
GPT4TurboPreview: true,
|
||||||
|
GPT4VisionPreview: true,
|
||||||
|
GPT4Turbo1106: true,
|
||||||
|
GPT4Turbo0125: true,
|
||||||
|
GPT4Turbo: true,
|
||||||
|
GPT4Turbo20240409: true,
|
||||||
|
GPT40314: true,
|
||||||
|
GPT40613: true,
|
||||||
|
GPT432K: true,
|
||||||
|
GPT432K0314: true,
|
||||||
|
GPT432K0613: true,
|
||||||
|
O1: true,
|
||||||
|
GPT4Dot1: true,
|
||||||
|
GPT4Dot120250414: true,
|
||||||
|
GPT4Dot1Mini: true,
|
||||||
|
GPT4Dot1Mini20250414: true,
|
||||||
|
GPT4Dot1Nano: true,
|
||||||
|
GPT4Dot1Nano20250414: true,
|
||||||
|
GPT5: true,
|
||||||
|
GPT5Mini: true,
|
||||||
|
GPT5Nano: true,
|
||||||
|
GPT5ChatLatest: true,
|
||||||
|
},
|
||||||
|
chatCompletionsSuffix: {
|
||||||
|
CodexCodeDavinci002: true,
|
||||||
|
CodexCodeCushman001: true,
|
||||||
|
CodexCodeDavinci001: true,
|
||||||
|
GPT3TextDavinci003: true,
|
||||||
|
GPT3TextDavinci002: true,
|
||||||
|
GPT3TextCurie001: true,
|
||||||
|
GPT3TextBabbage001: true,
|
||||||
|
GPT3TextAda001: true,
|
||||||
|
GPT3TextDavinci001: true,
|
||||||
|
GPT3DavinciInstructBeta: true,
|
||||||
|
GPT3Davinci: true,
|
||||||
|
GPT3CurieInstructBeta: true,
|
||||||
|
GPT3Curie: true,
|
||||||
|
GPT3Ada: true,
|
||||||
|
GPT3Babbage: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkEndpointSupportsModel(endpoint, model string) bool {
|
||||||
|
return !disabledModelsForEndpoints[endpoint][model]
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPromptType(prompt any) bool {
|
||||||
|
_, isString := prompt.(string)
|
||||||
|
_, isStringSlice := prompt.([]string)
|
||||||
|
if isString || isStringSlice {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if it is prompt is []string hidden under []any
|
||||||
|
slice, isSlice := prompt.([]any)
|
||||||
|
if !isSlice {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range slice {
|
||||||
|
_, itemIsString := item.(string)
|
||||||
|
if !itemIsString {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true // all items in the slice are string, so it is []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompletionRequest represents a request structure for completion API.
|
||||||
|
type CompletionRequest struct {
|
||||||
|
Model string `json:"model"`
|
||||||
|
Prompt any `json:"prompt,omitempty"`
|
||||||
|
BestOf int `json:"best_of,omitempty"`
|
||||||
|
Echo bool `json:"echo,omitempty"`
|
||||||
|
FrequencyPenalty float32 `json:"frequency_penalty,omitempty"`
|
||||||
|
// LogitBias is must be a token id string (specified by their token ID in the tokenizer), not a word string.
|
||||||
|
// incorrect: `"logit_bias":{"You": 6}`, correct: `"logit_bias":{"1639": 6}`
|
||||||
|
// refs: https://platform.openai.com/docs/api-reference/completions/create#completions/create-logit_bias
|
||||||
|
LogitBias map[string]int `json:"logit_bias,omitempty"`
|
||||||
|
// Store can be set to true to store the output of this completion request for use in distillations and evals.
|
||||||
|
// https://platform.openai.com/docs/api-reference/chat/create#chat-create-store
|
||||||
|
Store bool `json:"store,omitempty"`
|
||||||
|
// Metadata to store with the completion.
|
||||||
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
|
LogProbs int `json:"logprobs,omitempty"`
|
||||||
|
MaxTokens int `json:"max_tokens,omitempty"`
|
||||||
|
N int `json:"n,omitempty"`
|
||||||
|
PresencePenalty float32 `json:"presence_penalty,omitempty"`
|
||||||
|
Seed *int `json:"seed,omitempty"`
|
||||||
|
Stop []string `json:"stop,omitempty"`
|
||||||
|
Stream bool `json:"stream,omitempty"`
|
||||||
|
Suffix string `json:"suffix,omitempty"`
|
||||||
|
Temperature float32 `json:"temperature,omitempty"`
|
||||||
|
TopP float32 `json:"top_p,omitempty"`
|
||||||
|
User string `json:"user,omitempty"`
|
||||||
|
// Options for streaming response. Only set this when you set stream: true.
|
||||||
|
StreamOptions *StreamOptions `json:"stream_options,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompletionChoice represents one of possible completions.
|
||||||
|
type CompletionChoice struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
Index int `json:"index"`
|
||||||
|
FinishReason string `json:"finish_reason"`
|
||||||
|
LogProbs LogprobResult `json:"logprobs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogprobResult represents logprob result of Choice.
|
||||||
|
type LogprobResult struct {
|
||||||
|
Tokens []string `json:"tokens"`
|
||||||
|
TokenLogprobs []float32 `json:"token_logprobs"`
|
||||||
|
TopLogprobs []map[string]float32 `json:"top_logprobs"`
|
||||||
|
TextOffset []int `json:"text_offset"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompletionResponse represents a response structure for completion API.
|
||||||
|
type CompletionResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
Created int64 `json:"created"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
Choices []CompletionChoice `json:"choices"`
|
||||||
|
Usage *Usage `json:"usage,omitempty"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateCompletion — API call to create a completion. This is the main endpoint of the API. Returns new text as well
|
||||||
|
// as, if requested, the probabilities over each alternative token at each position.
|
||||||
|
//
|
||||||
|
// If using a fine-tuned model, simply provide the model's ID in the CompletionRequest object,
|
||||||
|
// and the server will use the model's parameters to generate the completion.
|
||||||
|
func (c *Client) CreateCompletion(
|
||||||
|
ctx context.Context,
|
||||||
|
request CompletionRequest,
|
||||||
|
) (response CompletionResponse, err error) {
|
||||||
|
if request.Stream {
|
||||||
|
err = ErrCompletionStreamNotSupported
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
urlSuffix := "/completions"
|
||||||
|
if !checkEndpointSupportsModel(urlSuffix, request.Model) {
|
||||||
|
err = ErrCompletionUnsupportedModel
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !checkPromptType(request.Prompt) {
|
||||||
|
err = ErrCompletionRequestPromptTypeNotSupported
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL(urlSuffix, withModel(request.Model)),
|
||||||
|
withBody(request),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
109
vendor/github.com/sashabaranov/go-openai/config.go
generated
vendored
Normal file
109
vendor/github.com/sashabaranov/go-openai/config.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
openaiAPIURLv1 = "https://api.openai.com/v1"
|
||||||
|
defaultEmptyMessagesLimit uint = 300
|
||||||
|
|
||||||
|
azureAPIPrefix = "openai"
|
||||||
|
azureDeploymentsPrefix = "deployments"
|
||||||
|
|
||||||
|
AnthropicAPIVersion = "2023-06-01"
|
||||||
|
)
|
||||||
|
|
||||||
|
type APIType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
APITypeOpenAI APIType = "OPEN_AI"
|
||||||
|
APITypeAzure APIType = "AZURE"
|
||||||
|
APITypeAzureAD APIType = "AZURE_AD"
|
||||||
|
APITypeCloudflareAzure APIType = "CLOUDFLARE_AZURE"
|
||||||
|
APITypeAnthropic APIType = "ANTHROPIC"
|
||||||
|
)
|
||||||
|
|
||||||
|
const AzureAPIKeyHeader = "api-key"
|
||||||
|
|
||||||
|
const defaultAssistantVersion = "v2" // upgrade to v2 to support vector store
|
||||||
|
|
||||||
|
type HTTPDoer interface {
|
||||||
|
Do(req *http.Request) (*http.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientConfig is a configuration of a client.
|
||||||
|
type ClientConfig struct {
|
||||||
|
authToken string
|
||||||
|
|
||||||
|
BaseURL string
|
||||||
|
OrgID string
|
||||||
|
APIType APIType
|
||||||
|
APIVersion string // required when APIType is APITypeAzure or APITypeAzureAD or APITypeAnthropic
|
||||||
|
AssistantVersion string
|
||||||
|
AzureModelMapperFunc func(model string) string // replace model to azure deployment name func
|
||||||
|
HTTPClient HTTPDoer
|
||||||
|
|
||||||
|
EmptyMessagesLimit uint
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultConfig(authToken string) ClientConfig {
|
||||||
|
return ClientConfig{
|
||||||
|
authToken: authToken,
|
||||||
|
BaseURL: openaiAPIURLv1,
|
||||||
|
APIType: APITypeOpenAI,
|
||||||
|
AssistantVersion: defaultAssistantVersion,
|
||||||
|
OrgID: "",
|
||||||
|
|
||||||
|
HTTPClient: &http.Client{},
|
||||||
|
|
||||||
|
EmptyMessagesLimit: defaultEmptyMessagesLimit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultAzureConfig(apiKey, baseURL string) ClientConfig {
|
||||||
|
return ClientConfig{
|
||||||
|
authToken: apiKey,
|
||||||
|
BaseURL: baseURL,
|
||||||
|
OrgID: "",
|
||||||
|
APIType: APITypeAzure,
|
||||||
|
APIVersion: "2023-05-15",
|
||||||
|
AzureModelMapperFunc: func(model string) string {
|
||||||
|
return regexp.MustCompile(`[.:]`).ReplaceAllString(model, "")
|
||||||
|
},
|
||||||
|
|
||||||
|
HTTPClient: &http.Client{},
|
||||||
|
|
||||||
|
EmptyMessagesLimit: defaultEmptyMessagesLimit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultAnthropicConfig(apiKey, baseURL string) ClientConfig {
|
||||||
|
if baseURL == "" {
|
||||||
|
baseURL = "https://api.anthropic.com/v1"
|
||||||
|
}
|
||||||
|
return ClientConfig{
|
||||||
|
authToken: apiKey,
|
||||||
|
BaseURL: baseURL,
|
||||||
|
OrgID: "",
|
||||||
|
APIType: APITypeAnthropic,
|
||||||
|
APIVersion: AnthropicAPIVersion,
|
||||||
|
|
||||||
|
HTTPClient: &http.Client{},
|
||||||
|
|
||||||
|
EmptyMessagesLimit: defaultEmptyMessagesLimit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ClientConfig) String() string {
|
||||||
|
return "<OpenAI API ClientConfig>"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClientConfig) GetAzureDeploymentByModel(model string) string {
|
||||||
|
if c.AzureModelMapperFunc != nil {
|
||||||
|
return c.AzureModelMapperFunc(model)
|
||||||
|
}
|
||||||
|
|
||||||
|
return model
|
||||||
|
}
|
||||||
53
vendor/github.com/sashabaranov/go-openai/edits.go
generated
vendored
Normal file
53
vendor/github.com/sashabaranov/go-openai/edits.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EditsRequest represents a request structure for Edits API.
|
||||||
|
type EditsRequest struct {
|
||||||
|
Model *string `json:"model,omitempty"`
|
||||||
|
Input string `json:"input,omitempty"`
|
||||||
|
Instruction string `json:"instruction,omitempty"`
|
||||||
|
N int `json:"n,omitempty"`
|
||||||
|
Temperature float32 `json:"temperature,omitempty"`
|
||||||
|
TopP float32 `json:"top_p,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditsChoice represents one of possible edits.
|
||||||
|
type EditsChoice struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
Index int `json:"index"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditsResponse represents a response structure for Edits API.
|
||||||
|
type EditsResponse struct {
|
||||||
|
Object string `json:"object"`
|
||||||
|
Created int64 `json:"created"`
|
||||||
|
Usage Usage `json:"usage"`
|
||||||
|
Choices []EditsChoice `json:"choices"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edits Perform an API call to the Edits endpoint.
|
||||||
|
/* Deprecated: Users of the Edits API and its associated models (e.g., text-davinci-edit-001 or code-davinci-edit-001)
|
||||||
|
will need to migrate to GPT-3.5 Turbo by January 4, 2024.
|
||||||
|
You can use CreateChatCompletion or CreateChatCompletionStream instead.
|
||||||
|
*/
|
||||||
|
func (c *Client) Edits(ctx context.Context, request EditsRequest) (response EditsResponse, err error) {
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL("/edits", withModel(fmt.Sprint(request.Model))),
|
||||||
|
withBody(request),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
297
vendor/github.com/sashabaranov/go-openai/embeddings.go
generated
vendored
Normal file
297
vendor/github.com/sashabaranov/go-openai/embeddings.go
generated
vendored
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"math"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrVectorLengthMismatch = errors.New("vector length mismatch")
|
||||||
|
|
||||||
|
// EmbeddingModel enumerates the models which can be used
|
||||||
|
// to generate Embedding vectors.
|
||||||
|
type EmbeddingModel string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Deprecated: The following block is shut down. Use text-embedding-ada-002 instead.
|
||||||
|
AdaSimilarity EmbeddingModel = "text-similarity-ada-001"
|
||||||
|
BabbageSimilarity EmbeddingModel = "text-similarity-babbage-001"
|
||||||
|
CurieSimilarity EmbeddingModel = "text-similarity-curie-001"
|
||||||
|
DavinciSimilarity EmbeddingModel = "text-similarity-davinci-001"
|
||||||
|
AdaSearchDocument EmbeddingModel = "text-search-ada-doc-001"
|
||||||
|
AdaSearchQuery EmbeddingModel = "text-search-ada-query-001"
|
||||||
|
BabbageSearchDocument EmbeddingModel = "text-search-babbage-doc-001"
|
||||||
|
BabbageSearchQuery EmbeddingModel = "text-search-babbage-query-001"
|
||||||
|
CurieSearchDocument EmbeddingModel = "text-search-curie-doc-001"
|
||||||
|
CurieSearchQuery EmbeddingModel = "text-search-curie-query-001"
|
||||||
|
DavinciSearchDocument EmbeddingModel = "text-search-davinci-doc-001"
|
||||||
|
DavinciSearchQuery EmbeddingModel = "text-search-davinci-query-001"
|
||||||
|
AdaCodeSearchCode EmbeddingModel = "code-search-ada-code-001"
|
||||||
|
AdaCodeSearchText EmbeddingModel = "code-search-ada-text-001"
|
||||||
|
BabbageCodeSearchCode EmbeddingModel = "code-search-babbage-code-001"
|
||||||
|
BabbageCodeSearchText EmbeddingModel = "code-search-babbage-text-001"
|
||||||
|
|
||||||
|
AdaEmbeddingV2 EmbeddingModel = "text-embedding-ada-002"
|
||||||
|
SmallEmbedding3 EmbeddingModel = "text-embedding-3-small"
|
||||||
|
LargeEmbedding3 EmbeddingModel = "text-embedding-3-large"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Embedding is a special format of data representation that can be easily utilized by machine
|
||||||
|
// learning models and algorithms. The embedding is an information dense representation of the
|
||||||
|
// semantic meaning of a piece of text. Each embedding is a vector of floating point numbers,
|
||||||
|
// such that the distance between two embeddings in the vector space is correlated with semantic similarity
|
||||||
|
// between two inputs in the original format. For example, if two texts are similar,
|
||||||
|
// then their vector representations should also be similar.
|
||||||
|
type Embedding struct {
|
||||||
|
Object string `json:"object"`
|
||||||
|
Embedding []float32 `json:"embedding"`
|
||||||
|
Index int `json:"index"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DotProduct calculates the dot product of the embedding vector with another
|
||||||
|
// embedding vector. Both vectors must have the same length; otherwise, an
|
||||||
|
// ErrVectorLengthMismatch is returned. The method returns the calculated dot
|
||||||
|
// product as a float32 value.
|
||||||
|
func (e *Embedding) DotProduct(other *Embedding) (float32, error) {
|
||||||
|
if len(e.Embedding) != len(other.Embedding) {
|
||||||
|
return 0, ErrVectorLengthMismatch
|
||||||
|
}
|
||||||
|
|
||||||
|
var dotProduct float32
|
||||||
|
for i := range e.Embedding {
|
||||||
|
dotProduct += e.Embedding[i] * other.Embedding[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return dotProduct, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmbeddingResponse is the response from a Create embeddings request.
|
||||||
|
type EmbeddingResponse struct {
|
||||||
|
Object string `json:"object"`
|
||||||
|
Data []Embedding `json:"data"`
|
||||||
|
Model EmbeddingModel `json:"model"`
|
||||||
|
Usage Usage `json:"usage"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type base64String string
|
||||||
|
|
||||||
|
func (b base64String) Decode() ([]float32, error) {
|
||||||
|
decodedData, err := base64.StdEncoding.DecodeString(string(b))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const sizeOfFloat32 = 4
|
||||||
|
floats := make([]float32, len(decodedData)/sizeOfFloat32)
|
||||||
|
for i := 0; i < len(floats); i++ {
|
||||||
|
floats[i] = math.Float32frombits(binary.LittleEndian.Uint32(decodedData[i*4 : (i+1)*4]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return floats, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base64Embedding is a container for base64 encoded embeddings.
|
||||||
|
type Base64Embedding struct {
|
||||||
|
Object string `json:"object"`
|
||||||
|
Embedding base64String `json:"embedding"`
|
||||||
|
Index int `json:"index"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmbeddingResponseBase64 is the response from a Create embeddings request with base64 encoding format.
|
||||||
|
type EmbeddingResponseBase64 struct {
|
||||||
|
Object string `json:"object"`
|
||||||
|
Data []Base64Embedding `json:"data"`
|
||||||
|
Model EmbeddingModel `json:"model"`
|
||||||
|
Usage Usage `json:"usage"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToEmbeddingResponse converts an embeddingResponseBase64 to an EmbeddingResponse.
|
||||||
|
func (r *EmbeddingResponseBase64) ToEmbeddingResponse() (EmbeddingResponse, error) {
|
||||||
|
data := make([]Embedding, len(r.Data))
|
||||||
|
|
||||||
|
for i, base64Embedding := range r.Data {
|
||||||
|
embedding, err := base64Embedding.Embedding.Decode()
|
||||||
|
if err != nil {
|
||||||
|
return EmbeddingResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
data[i] = Embedding{
|
||||||
|
Object: base64Embedding.Object,
|
||||||
|
Embedding: embedding,
|
||||||
|
Index: base64Embedding.Index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EmbeddingResponse{
|
||||||
|
Object: r.Object,
|
||||||
|
Model: r.Model,
|
||||||
|
Data: data,
|
||||||
|
Usage: r.Usage,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmbeddingRequestConverter interface {
|
||||||
|
// Needs to be of type EmbeddingRequestStrings or EmbeddingRequestTokens
|
||||||
|
Convert() EmbeddingRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmbeddingEncodingFormat is the format of the embeddings data.
|
||||||
|
// Currently, only "float" and "base64" are supported, however, "base64" is not officially documented.
|
||||||
|
// If not specified OpenAI will use "float".
|
||||||
|
type EmbeddingEncodingFormat string
|
||||||
|
|
||||||
|
const (
|
||||||
|
EmbeddingEncodingFormatFloat EmbeddingEncodingFormat = "float"
|
||||||
|
EmbeddingEncodingFormatBase64 EmbeddingEncodingFormat = "base64"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EmbeddingRequest struct {
|
||||||
|
Input any `json:"input"`
|
||||||
|
Model EmbeddingModel `json:"model"`
|
||||||
|
User string `json:"user,omitempty"`
|
||||||
|
EncodingFormat EmbeddingEncodingFormat `json:"encoding_format,omitempty"`
|
||||||
|
// Dimensions The number of dimensions the resulting output embeddings should have.
|
||||||
|
// Only supported in text-embedding-3 and later models.
|
||||||
|
Dimensions int `json:"dimensions,omitempty"`
|
||||||
|
// The ExtraBody field allows for the inclusion of arbitrary key-value pairs
|
||||||
|
// in the request body that may not be explicitly defined in this struct.
|
||||||
|
ExtraBody map[string]any `json:"extra_body,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r EmbeddingRequest) Convert() EmbeddingRequest {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmbeddingRequestStrings is the input to a create embeddings request with a slice of strings.
|
||||||
|
type EmbeddingRequestStrings struct {
|
||||||
|
// Input is a slice of strings for which you want to generate an Embedding vector.
|
||||||
|
// Each input must not exceed 8192 tokens in length.
|
||||||
|
// OpenAPI suggests replacing newlines (\n) in your input with a single space, as they
|
||||||
|
// have observed inferior results when newlines are present.
|
||||||
|
// E.g.
|
||||||
|
// "The food was delicious and the waiter..."
|
||||||
|
Input []string `json:"input"`
|
||||||
|
// ID of the model to use. You can use the List models API to see all of your available models,
|
||||||
|
// or see our Model overview for descriptions of them.
|
||||||
|
Model EmbeddingModel `json:"model"`
|
||||||
|
// A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
|
||||||
|
User string `json:"user"`
|
||||||
|
// EmbeddingEncodingFormat is the format of the embeddings data.
|
||||||
|
// Currently, only "float" and "base64" are supported, however, "base64" is not officially documented.
|
||||||
|
// If not specified OpenAI will use "float".
|
||||||
|
EncodingFormat EmbeddingEncodingFormat `json:"encoding_format,omitempty"`
|
||||||
|
// Dimensions The number of dimensions the resulting output embeddings should have.
|
||||||
|
// Only supported in text-embedding-3 and later models.
|
||||||
|
Dimensions int `json:"dimensions,omitempty"`
|
||||||
|
// The ExtraBody field allows for the inclusion of arbitrary key-value pairs
|
||||||
|
// in the request body that may not be explicitly defined in this struct.
|
||||||
|
ExtraBody map[string]any `json:"extra_body,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r EmbeddingRequestStrings) Convert() EmbeddingRequest {
|
||||||
|
return EmbeddingRequest{
|
||||||
|
Input: r.Input,
|
||||||
|
Model: r.Model,
|
||||||
|
User: r.User,
|
||||||
|
EncodingFormat: r.EncodingFormat,
|
||||||
|
Dimensions: r.Dimensions,
|
||||||
|
ExtraBody: r.ExtraBody,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmbeddingRequestTokens struct {
|
||||||
|
// Input is a slice of slices of ints ([][]int) for which you want to generate an Embedding vector.
|
||||||
|
// Each input must not exceed 8192 tokens in length.
|
||||||
|
// OpenAPI suggests replacing newlines (\n) in your input with a single space, as they
|
||||||
|
// have observed inferior results when newlines are present.
|
||||||
|
// E.g.
|
||||||
|
// "The food was delicious and the waiter..."
|
||||||
|
Input [][]int `json:"input"`
|
||||||
|
// ID of the model to use. You can use the List models API to see all of your available models,
|
||||||
|
// or see our Model overview for descriptions of them.
|
||||||
|
Model EmbeddingModel `json:"model"`
|
||||||
|
// A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
|
||||||
|
User string `json:"user"`
|
||||||
|
// EmbeddingEncodingFormat is the format of the embeddings data.
|
||||||
|
// Currently, only "float" and "base64" are supported, however, "base64" is not officially documented.
|
||||||
|
// If not specified OpenAI will use "float".
|
||||||
|
EncodingFormat EmbeddingEncodingFormat `json:"encoding_format,omitempty"`
|
||||||
|
// Dimensions The number of dimensions the resulting output embeddings should have.
|
||||||
|
// Only supported in text-embedding-3 and later models.
|
||||||
|
Dimensions int `json:"dimensions,omitempty"`
|
||||||
|
// The ExtraBody field allows for the inclusion of arbitrary key-value pairs
|
||||||
|
// in the request body that may not be explicitly defined in this struct.
|
||||||
|
ExtraBody map[string]any `json:"extra_body,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r EmbeddingRequestTokens) Convert() EmbeddingRequest {
|
||||||
|
return EmbeddingRequest{
|
||||||
|
Input: r.Input,
|
||||||
|
Model: r.Model,
|
||||||
|
User: r.User,
|
||||||
|
EncodingFormat: r.EncodingFormat,
|
||||||
|
Dimensions: r.Dimensions,
|
||||||
|
ExtraBody: r.ExtraBody,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEmbeddings returns an EmbeddingResponse which will contain an Embedding for every item in |body.Input|.
|
||||||
|
// https://beta.openai.com/docs/api-reference/embeddings/create
|
||||||
|
//
|
||||||
|
// Body should be of type EmbeddingRequestStrings for embedding strings or EmbeddingRequestTokens
|
||||||
|
// for embedding groups of text already converted to tokens.
|
||||||
|
func (c *Client) CreateEmbeddings(
|
||||||
|
ctx context.Context,
|
||||||
|
conv EmbeddingRequestConverter,
|
||||||
|
) (res EmbeddingResponse, err error) {
|
||||||
|
baseReq := conv.Convert()
|
||||||
|
|
||||||
|
// The body map is used to dynamically construct the request payload for the embedding API.
|
||||||
|
// Instead of relying on a fixed struct, the body map allows for flexible inclusion of fields
|
||||||
|
// based on their presence, avoiding unnecessary or empty fields in the request.
|
||||||
|
extraBody := baseReq.ExtraBody
|
||||||
|
baseReq.ExtraBody = nil
|
||||||
|
|
||||||
|
// Serialize baseReq to JSON
|
||||||
|
jsonData, err := json.Marshal(baseReq)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize JSON to map[string]any
|
||||||
|
var body map[string]any
|
||||||
|
_ = json.Unmarshal(jsonData, &body)
|
||||||
|
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL("/embeddings", withModel(string(baseReq.Model))),
|
||||||
|
withBody(body), // Main request body.
|
||||||
|
withExtraBody(extraBody), // Merge ExtraBody fields.
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if baseReq.EncodingFormat != EmbeddingEncodingFormatBase64 {
|
||||||
|
err = c.sendRequest(req, &res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
base64Response := &EmbeddingResponseBase64{}
|
||||||
|
err = c.sendRequest(req, base64Response)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err = base64Response.ToEmbeddingResponse()
|
||||||
|
return
|
||||||
|
}
|
||||||
52
vendor/github.com/sashabaranov/go-openai/engines.go
generated
vendored
Normal file
52
vendor/github.com/sashabaranov/go-openai/engines.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Engine struct represents engine from OpenAPI API.
|
||||||
|
type Engine struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
Owner string `json:"owner"`
|
||||||
|
Ready bool `json:"ready"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnginesList is a list of engines.
|
||||||
|
type EnginesList struct {
|
||||||
|
Engines []Engine `json:"data"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEngines Lists the currently available engines, and provides basic
|
||||||
|
// information about each option such as the owner and availability.
|
||||||
|
func (c *Client) ListEngines(ctx context.Context) (engines EnginesList, err error) {
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL("/engines"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &engines)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEngine Retrieves an engine instance, providing basic information about
|
||||||
|
// the engine such as the owner and availability.
|
||||||
|
func (c *Client) GetEngine(
|
||||||
|
ctx context.Context,
|
||||||
|
engineID string,
|
||||||
|
) (engine Engine, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/engines/%s", engineID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &engine)
|
||||||
|
return
|
||||||
|
}
|
||||||
115
vendor/github.com/sashabaranov/go-openai/error.go
generated
vendored
Normal file
115
vendor/github.com/sashabaranov/go-openai/error.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// APIError provides error information returned by the OpenAI API.
|
||||||
|
// InnerError struct is only valid for Azure OpenAI Service.
|
||||||
|
type APIError struct {
|
||||||
|
Code any `json:"code,omitempty"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Param *string `json:"param,omitempty"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
HTTPStatus string `json:"-"`
|
||||||
|
HTTPStatusCode int `json:"-"`
|
||||||
|
InnerError *InnerError `json:"innererror,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InnerError Azure Content filtering. Only valid for Azure OpenAI Service.
|
||||||
|
type InnerError struct {
|
||||||
|
Code string `json:"code,omitempty"`
|
||||||
|
ContentFilterResults ContentFilterResults `json:"content_filter_result,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestError provides information about generic request errors.
|
||||||
|
type RequestError struct {
|
||||||
|
HTTPStatus string
|
||||||
|
HTTPStatusCode int
|
||||||
|
Err error
|
||||||
|
Body []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorResponse struct {
|
||||||
|
Error *APIError `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *APIError) Error() string {
|
||||||
|
if e.HTTPStatusCode > 0 {
|
||||||
|
return fmt.Sprintf("error, status code: %d, status: %s, message: %s", e.HTTPStatusCode, e.HTTPStatus, e.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *APIError) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
var rawMap map[string]json.RawMessage
|
||||||
|
err = json.Unmarshal(data, &rawMap)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(rawMap["message"], &e.Message)
|
||||||
|
if err != nil {
|
||||||
|
// If the parameter field of a function call is invalid as a JSON schema
|
||||||
|
// refs: https://github.com/sashabaranov/go-openai/issues/381
|
||||||
|
var messages []string
|
||||||
|
err = json.Unmarshal(rawMap["message"], &messages)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e.Message = strings.Join(messages, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional fields for azure openai
|
||||||
|
// refs: https://github.com/sashabaranov/go-openai/issues/343
|
||||||
|
if _, ok := rawMap["type"]; ok {
|
||||||
|
err = json.Unmarshal(rawMap["type"], &e.Type)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := rawMap["innererror"]; ok {
|
||||||
|
err = json.Unmarshal(rawMap["innererror"], &e.InnerError)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional fields
|
||||||
|
if _, ok := rawMap["param"]; ok {
|
||||||
|
err = json.Unmarshal(rawMap["param"], &e.Param)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := rawMap["code"]; !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the api returned a number, we need to force an integer
|
||||||
|
// since the json package defaults to float64
|
||||||
|
var intCode int
|
||||||
|
err = json.Unmarshal(rawMap["code"], &intCode)
|
||||||
|
if err == nil {
|
||||||
|
e.Code = intCode
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Unmarshal(rawMap["code"], &e.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RequestError) Error() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"error, status code: %d, status: %s, message: %s, body: %s",
|
||||||
|
e.HTTPStatusCode, e.HTTPStatus, e.Err, e.Body,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RequestError) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
171
vendor/github.com/sashabaranov/go-openai/files.go
generated
vendored
Normal file
171
vendor/github.com/sashabaranov/go-openai/files.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileRequest struct {
|
||||||
|
FileName string `json:"file"`
|
||||||
|
FilePath string `json:"-"`
|
||||||
|
Purpose string `json:"purpose"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PurposeType represents the purpose of the file when uploading.
|
||||||
|
type PurposeType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PurposeFineTune PurposeType = "fine-tune"
|
||||||
|
PurposeFineTuneResults PurposeType = "fine-tune-results"
|
||||||
|
PurposeAssistants PurposeType = "assistants"
|
||||||
|
PurposeAssistantsOutput PurposeType = "assistants_output"
|
||||||
|
PurposeBatch PurposeType = "batch"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FileBytesRequest represents a file upload request.
|
||||||
|
type FileBytesRequest struct {
|
||||||
|
// the name of the uploaded file in OpenAI
|
||||||
|
Name string
|
||||||
|
// the bytes of the file
|
||||||
|
Bytes []byte
|
||||||
|
// the purpose of the file
|
||||||
|
Purpose PurposeType
|
||||||
|
}
|
||||||
|
|
||||||
|
// File struct represents an OpenAPI file.
|
||||||
|
type File struct {
|
||||||
|
Bytes int `json:"bytes"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
FileName string `json:"filename"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Purpose string `json:"purpose"`
|
||||||
|
StatusDetails string `json:"status_details"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilesList is a list of files that belong to the user or organization.
|
||||||
|
type FilesList struct {
|
||||||
|
Files []File `json:"data"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateFileBytes uploads bytes directly to OpenAI without requiring a local file.
|
||||||
|
func (c *Client) CreateFileBytes(ctx context.Context, request FileBytesRequest) (file File, err error) {
|
||||||
|
var b bytes.Buffer
|
||||||
|
reader := bytes.NewReader(request.Bytes)
|
||||||
|
builder := c.createFormBuilder(&b)
|
||||||
|
|
||||||
|
err = builder.WriteField("purpose", string(request.Purpose))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = builder.CreateFormFileReader("file", reader, request.Name)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = builder.Close()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/files"),
|
||||||
|
withBody(&b), withContentType(builder.FormDataContentType()))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &file)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateFile uploads a jsonl file to GPT3
|
||||||
|
// FilePath must be a local file path.
|
||||||
|
func (c *Client) CreateFile(ctx context.Context, request FileRequest) (file File, err error) {
|
||||||
|
var b bytes.Buffer
|
||||||
|
builder := c.createFormBuilder(&b)
|
||||||
|
|
||||||
|
err = builder.WriteField("purpose", request.Purpose)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fileData, err := os.Open(request.FilePath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer fileData.Close()
|
||||||
|
|
||||||
|
err = builder.CreateFormFile("file", fileData)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = builder.Close()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/files"),
|
||||||
|
withBody(&b), withContentType(builder.FormDataContentType()))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &file)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteFile deletes an existing file.
|
||||||
|
func (c *Client) DeleteFile(ctx context.Context, fileID string) (err error) {
|
||||||
|
req, err := c.newRequest(ctx, http.MethodDelete, c.fullURL("/files/"+fileID))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListFiles Lists the currently available files,
|
||||||
|
// and provides basic information about each file such as the file name and purpose.
|
||||||
|
func (c *Client) ListFiles(ctx context.Context) (files FilesList, err error) {
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL("/files"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &files)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFile Retrieves a file instance, providing basic information about the file
|
||||||
|
// such as the file name and purpose.
|
||||||
|
func (c *Client) GetFile(ctx context.Context, fileID string) (file File, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/files/%s", fileID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &file)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetFileContent(ctx context.Context, fileID string) (content RawResponse, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/files/%s/content", fileID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.sendRequestRaw(req)
|
||||||
|
}
|
||||||
178
vendor/github.com/sashabaranov/go-openai/fine_tunes.go
generated
vendored
Normal file
178
vendor/github.com/sashabaranov/go-openai/fine_tunes.go
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
// This API will be officially deprecated on January 4th, 2024.
|
||||||
|
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||||
|
type FineTuneRequest struct {
|
||||||
|
TrainingFile string `json:"training_file"`
|
||||||
|
ValidationFile string `json:"validation_file,omitempty"`
|
||||||
|
Model string `json:"model,omitempty"`
|
||||||
|
Epochs int `json:"n_epochs,omitempty"`
|
||||||
|
BatchSize int `json:"batch_size,omitempty"`
|
||||||
|
LearningRateMultiplier float32 `json:"learning_rate_multiplier,omitempty"`
|
||||||
|
PromptLossRate float32 `json:"prompt_loss_rate,omitempty"`
|
||||||
|
ComputeClassificationMetrics bool `json:"compute_classification_metrics,omitempty"`
|
||||||
|
ClassificationClasses int `json:"classification_n_classes,omitempty"`
|
||||||
|
ClassificationPositiveClass string `json:"classification_positive_class,omitempty"`
|
||||||
|
ClassificationBetas []float32 `json:"classification_betas,omitempty"`
|
||||||
|
Suffix string `json:"suffix,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
// This API will be officially deprecated on January 4th, 2024.
|
||||||
|
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||||
|
type FineTune struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
FineTuneEventList []FineTuneEvent `json:"events,omitempty"`
|
||||||
|
FineTunedModel string `json:"fine_tuned_model"`
|
||||||
|
HyperParams FineTuneHyperParams `json:"hyperparams"`
|
||||||
|
OrganizationID string `json:"organization_id"`
|
||||||
|
ResultFiles []File `json:"result_files"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
ValidationFiles []File `json:"validation_files"`
|
||||||
|
TrainingFiles []File `json:"training_files"`
|
||||||
|
UpdatedAt int64 `json:"updated_at"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
// This API will be officially deprecated on January 4th, 2024.
|
||||||
|
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||||
|
type FineTuneEvent struct {
|
||||||
|
Object string `json:"object"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
Level string `json:"level"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
// This API will be officially deprecated on January 4th, 2024.
|
||||||
|
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||||
|
type FineTuneHyperParams struct {
|
||||||
|
BatchSize int `json:"batch_size"`
|
||||||
|
LearningRateMultiplier float64 `json:"learning_rate_multiplier"`
|
||||||
|
Epochs int `json:"n_epochs"`
|
||||||
|
PromptLossWeight float64 `json:"prompt_loss_weight"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
// This API will be officially deprecated on January 4th, 2024.
|
||||||
|
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||||
|
type FineTuneList struct {
|
||||||
|
Object string `json:"object"`
|
||||||
|
Data []FineTune `json:"data"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
// This API will be officially deprecated on January 4th, 2024.
|
||||||
|
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||||
|
type FineTuneEventList struct {
|
||||||
|
Object string `json:"object"`
|
||||||
|
Data []FineTuneEvent `json:"data"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
// This API will be officially deprecated on January 4th, 2024.
|
||||||
|
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||||
|
type FineTuneDeleteResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
Deleted bool `json:"deleted"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
// This API will be officially deprecated on January 4th, 2024.
|
||||||
|
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||||
|
func (c *Client) CreateFineTune(ctx context.Context, request FineTuneRequest) (response FineTune, err error) {
|
||||||
|
urlSuffix := "/fine-tunes"
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix), withBody(request))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelFineTune cancel a fine-tune job.
|
||||||
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
// This API will be officially deprecated on January 4th, 2024.
|
||||||
|
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||||
|
func (c *Client) CancelFineTune(ctx context.Context, fineTuneID string) (response FineTune, err error) {
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/fine-tunes/"+fineTuneID+"/cancel")) //nolint:lll //this method is deprecated
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
// This API will be officially deprecated on January 4th, 2024.
|
||||||
|
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||||
|
func (c *Client) ListFineTunes(ctx context.Context) (response FineTuneList, err error) {
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL("/fine-tunes"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
// This API will be officially deprecated on January 4th, 2024.
|
||||||
|
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||||
|
func (c *Client) GetFineTune(ctx context.Context, fineTuneID string) (response FineTune, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/fine-tunes/%s", fineTuneID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
// This API will be officially deprecated on January 4th, 2024.
|
||||||
|
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||||
|
func (c *Client) DeleteFineTune(ctx context.Context, fineTuneID string) (response FineTuneDeleteResponse, err error) {
|
||||||
|
req, err := c.newRequest(ctx, http.MethodDelete, c.fullURL("/fine-tunes/"+fineTuneID))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: On August 22nd, 2023, OpenAI announced the deprecation of the /v1/fine-tunes API.
|
||||||
|
// This API will be officially deprecated on January 4th, 2024.
|
||||||
|
// OpenAI recommends to migrate to the new fine tuning API implemented in fine_tuning_job.go.
|
||||||
|
func (c *Client) ListFineTuneEvents(ctx context.Context, fineTuneID string) (response FineTuneEventList, err error) {
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL("/fine-tunes/"+fineTuneID+"/events"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
159
vendor/github.com/sashabaranov/go-openai/fine_tuning_job.go
generated
vendored
Normal file
159
vendor/github.com/sashabaranov/go-openai/fine_tuning_job.go
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FineTuningJob struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
FinishedAt int64 `json:"finished_at"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
FineTunedModel string `json:"fine_tuned_model,omitempty"`
|
||||||
|
OrganizationID string `json:"organization_id"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Hyperparameters Hyperparameters `json:"hyperparameters"`
|
||||||
|
TrainingFile string `json:"training_file"`
|
||||||
|
ValidationFile string `json:"validation_file,omitempty"`
|
||||||
|
ResultFiles []string `json:"result_files"`
|
||||||
|
TrainedTokens int `json:"trained_tokens"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type Hyperparameters struct {
|
||||||
|
Epochs any `json:"n_epochs,omitempty"`
|
||||||
|
LearningRateMultiplier any `json:"learning_rate_multiplier,omitempty"`
|
||||||
|
BatchSize any `json:"batch_size,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FineTuningJobRequest struct {
|
||||||
|
TrainingFile string `json:"training_file"`
|
||||||
|
ValidationFile string `json:"validation_file,omitempty"`
|
||||||
|
Model string `json:"model,omitempty"`
|
||||||
|
Hyperparameters *Hyperparameters `json:"hyperparameters,omitempty"`
|
||||||
|
Suffix string `json:"suffix,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FineTuningJobEventList struct {
|
||||||
|
Object string `json:"object"`
|
||||||
|
Data []FineTuneEvent `json:"data"`
|
||||||
|
HasMore bool `json:"has_more"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type FineTuningJobEvent struct {
|
||||||
|
Object string `json:"object"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
CreatedAt int `json:"created_at"`
|
||||||
|
Level string `json:"level"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data any `json:"data"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateFineTuningJob create a fine tuning job.
|
||||||
|
func (c *Client) CreateFineTuningJob(
|
||||||
|
ctx context.Context,
|
||||||
|
request FineTuningJobRequest,
|
||||||
|
) (response FineTuningJob, err error) {
|
||||||
|
urlSuffix := "/fine_tuning/jobs"
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix), withBody(request))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelFineTuningJob cancel a fine tuning job.
|
||||||
|
func (c *Client) CancelFineTuningJob(ctx context.Context, fineTuningJobID string) (response FineTuningJob, err error) {
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL("/fine_tuning/jobs/"+fineTuningJobID+"/cancel"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveFineTuningJob retrieve a fine tuning job.
|
||||||
|
func (c *Client) RetrieveFineTuningJob(
|
||||||
|
ctx context.Context,
|
||||||
|
fineTuningJobID string,
|
||||||
|
) (response FineTuningJob, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/fine_tuning/jobs/%s", fineTuningJobID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type listFineTuningJobEventsParameters struct {
|
||||||
|
after *string
|
||||||
|
limit *int
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListFineTuningJobEventsParameter func(*listFineTuningJobEventsParameters)
|
||||||
|
|
||||||
|
func ListFineTuningJobEventsWithAfter(after string) ListFineTuningJobEventsParameter {
|
||||||
|
return func(args *listFineTuningJobEventsParameters) {
|
||||||
|
args.after = &after
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListFineTuningJobEventsWithLimit(limit int) ListFineTuningJobEventsParameter {
|
||||||
|
return func(args *listFineTuningJobEventsParameters) {
|
||||||
|
args.limit = &limit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListFineTuningJobs list fine tuning jobs events.
|
||||||
|
func (c *Client) ListFineTuningJobEvents(
|
||||||
|
ctx context.Context,
|
||||||
|
fineTuningJobID string,
|
||||||
|
setters ...ListFineTuningJobEventsParameter,
|
||||||
|
) (response FineTuningJobEventList, err error) {
|
||||||
|
parameters := &listFineTuningJobEventsParameters{
|
||||||
|
after: nil,
|
||||||
|
limit: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, setter := range setters {
|
||||||
|
setter(parameters)
|
||||||
|
}
|
||||||
|
|
||||||
|
urlValues := url.Values{}
|
||||||
|
if parameters.after != nil {
|
||||||
|
urlValues.Add("after", *parameters.after)
|
||||||
|
}
|
||||||
|
if parameters.limit != nil {
|
||||||
|
urlValues.Add("limit", fmt.Sprintf("%d", *parameters.limit))
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedValues := ""
|
||||||
|
if len(urlValues) > 0 {
|
||||||
|
encodedValues = "?" + urlValues.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodGet,
|
||||||
|
c.fullURL("/fine_tuning/jobs/"+fineTuningJobID+"/events"+encodedValues),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
289
vendor/github.com/sashabaranov/go-openai/image.go
generated
vendored
Normal file
289
vendor/github.com/sashabaranov/go-openai/image.go
generated
vendored
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Image sizes defined by the OpenAI API.
|
||||||
|
const (
|
||||||
|
CreateImageSize256x256 = "256x256"
|
||||||
|
CreateImageSize512x512 = "512x512"
|
||||||
|
CreateImageSize1024x1024 = "1024x1024"
|
||||||
|
|
||||||
|
// dall-e-3 supported only.
|
||||||
|
CreateImageSize1792x1024 = "1792x1024"
|
||||||
|
CreateImageSize1024x1792 = "1024x1792"
|
||||||
|
|
||||||
|
// gpt-image-1 supported only.
|
||||||
|
CreateImageSize1536x1024 = "1536x1024" // Landscape
|
||||||
|
CreateImageSize1024x1536 = "1024x1536" // Portrait
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// dall-e-2 and dall-e-3 only.
|
||||||
|
CreateImageResponseFormatB64JSON = "b64_json"
|
||||||
|
CreateImageResponseFormatURL = "url"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CreateImageModelDallE2 = "dall-e-2"
|
||||||
|
CreateImageModelDallE3 = "dall-e-3"
|
||||||
|
CreateImageModelGptImage1 = "gpt-image-1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CreateImageQualityHD = "hd"
|
||||||
|
CreateImageQualityStandard = "standard"
|
||||||
|
|
||||||
|
// gpt-image-1 only.
|
||||||
|
CreateImageQualityHigh = "high"
|
||||||
|
CreateImageQualityMedium = "medium"
|
||||||
|
CreateImageQualityLow = "low"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// dall-e-3 only.
|
||||||
|
CreateImageStyleVivid = "vivid"
|
||||||
|
CreateImageStyleNatural = "natural"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// gpt-image-1 only.
|
||||||
|
CreateImageBackgroundTransparent = "transparent"
|
||||||
|
CreateImageBackgroundOpaque = "opaque"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// gpt-image-1 only.
|
||||||
|
CreateImageModerationLow = "low"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// gpt-image-1 only.
|
||||||
|
CreateImageOutputFormatPNG = "png"
|
||||||
|
CreateImageOutputFormatJPEG = "jpeg"
|
||||||
|
CreateImageOutputFormatWEBP = "webp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImageRequest represents the request structure for the image API.
|
||||||
|
type ImageRequest struct {
|
||||||
|
Prompt string `json:"prompt,omitempty"`
|
||||||
|
Model string `json:"model,omitempty"`
|
||||||
|
N int `json:"n,omitempty"`
|
||||||
|
Quality string `json:"quality,omitempty"`
|
||||||
|
Size string `json:"size,omitempty"`
|
||||||
|
Style string `json:"style,omitempty"`
|
||||||
|
ResponseFormat string `json:"response_format,omitempty"`
|
||||||
|
User string `json:"user,omitempty"`
|
||||||
|
Background string `json:"background,omitempty"`
|
||||||
|
Moderation string `json:"moderation,omitempty"`
|
||||||
|
OutputCompression int `json:"output_compression,omitempty"`
|
||||||
|
OutputFormat string `json:"output_format,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageResponse represents a response structure for image API.
|
||||||
|
type ImageResponse struct {
|
||||||
|
Created int64 `json:"created,omitempty"`
|
||||||
|
Data []ImageResponseDataInner `json:"data,omitempty"`
|
||||||
|
Usage ImageResponseUsage `json:"usage,omitempty"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageResponseInputTokensDetails represents the token breakdown for input tokens.
|
||||||
|
type ImageResponseInputTokensDetails struct {
|
||||||
|
TextTokens int `json:"text_tokens,omitempty"`
|
||||||
|
ImageTokens int `json:"image_tokens,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageResponseUsage represents the token usage information for image API.
|
||||||
|
type ImageResponseUsage struct {
|
||||||
|
TotalTokens int `json:"total_tokens,omitempty"`
|
||||||
|
InputTokens int `json:"input_tokens,omitempty"`
|
||||||
|
OutputTokens int `json:"output_tokens,omitempty"`
|
||||||
|
InputTokensDetails ImageResponseInputTokensDetails `json:"input_tokens_details,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageResponseDataInner represents a response data structure for image API.
|
||||||
|
type ImageResponseDataInner struct {
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
|
B64JSON string `json:"b64_json,omitempty"`
|
||||||
|
RevisedPrompt string `json:"revised_prompt,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateImage - API call to create an image. This is the main endpoint of the DALL-E API.
|
||||||
|
func (c *Client) CreateImage(ctx context.Context, request ImageRequest) (response ImageResponse, err error) {
|
||||||
|
urlSuffix := "/images/generations"
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL(urlSuffix, withModel(request.Model)),
|
||||||
|
withBody(request),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapReader wraps an io.Reader with filename and Content-type.
|
||||||
|
func WrapReader(rdr io.Reader, filename string, contentType string) io.Reader {
|
||||||
|
return file{rdr, filename, contentType}
|
||||||
|
}
|
||||||
|
|
||||||
|
type file struct {
|
||||||
|
io.Reader
|
||||||
|
name string
|
||||||
|
contentType string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f file) Name() string {
|
||||||
|
if f.name != "" {
|
||||||
|
return f.name
|
||||||
|
} else if named, ok := f.Reader.(interface{ Name() string }); ok {
|
||||||
|
return named.Name()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f file) ContentType() string {
|
||||||
|
return f.contentType
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageEditRequest represents the request structure for the image API.
|
||||||
|
// Use WrapReader to wrap an io.Reader with filename and Content-type.
|
||||||
|
type ImageEditRequest struct {
|
||||||
|
Image io.Reader `json:"image,omitempty"`
|
||||||
|
Mask io.Reader `json:"mask,omitempty"`
|
||||||
|
Prompt string `json:"prompt,omitempty"`
|
||||||
|
Model string `json:"model,omitempty"`
|
||||||
|
N int `json:"n,omitempty"`
|
||||||
|
Size string `json:"size,omitempty"`
|
||||||
|
ResponseFormat string `json:"response_format,omitempty"`
|
||||||
|
Quality string `json:"quality,omitempty"`
|
||||||
|
User string `json:"user,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEditImage - API call to create an image. This is the main endpoint of the DALL-E API.
|
||||||
|
func (c *Client) CreateEditImage(ctx context.Context, request ImageEditRequest) (response ImageResponse, err error) {
|
||||||
|
body := &bytes.Buffer{}
|
||||||
|
builder := c.createFormBuilder(body)
|
||||||
|
|
||||||
|
// image, filename verification can be postponed
|
||||||
|
err = builder.CreateFormFileReader("image", request.Image, "")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// mask, it is optional
|
||||||
|
if request.Mask != nil {
|
||||||
|
// filename verification can be postponed
|
||||||
|
err = builder.CreateFormFileReader("mask", request.Mask, "")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = builder.WriteField("prompt", request.Prompt)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = builder.WriteField("n", strconv.Itoa(request.N))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = builder.WriteField("size", request.Size)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = builder.WriteField("response_format", request.ResponseFormat)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = builder.Close()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL("/images/edits", withModel(request.Model)),
|
||||||
|
withBody(body),
|
||||||
|
withContentType(builder.FormDataContentType()),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageVariRequest represents the request structure for the image API.
|
||||||
|
// Use WrapReader to wrap an io.Reader with filename and Content-type.
|
||||||
|
type ImageVariRequest struct {
|
||||||
|
Image io.Reader `json:"image,omitempty"`
|
||||||
|
Model string `json:"model,omitempty"`
|
||||||
|
N int `json:"n,omitempty"`
|
||||||
|
Size string `json:"size,omitempty"`
|
||||||
|
ResponseFormat string `json:"response_format,omitempty"`
|
||||||
|
User string `json:"user,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateVariImage - API call to create an image variation. This is the main endpoint of the DALL-E API.
|
||||||
|
// Use abbreviations(vari for variation) because ci-lint has a single-line length limit ...
|
||||||
|
func (c *Client) CreateVariImage(ctx context.Context, request ImageVariRequest) (response ImageResponse, err error) {
|
||||||
|
body := &bytes.Buffer{}
|
||||||
|
builder := c.createFormBuilder(body)
|
||||||
|
|
||||||
|
// image, filename verification can be postponed
|
||||||
|
err = builder.CreateFormFileReader("image", request.Image, "")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = builder.WriteField("n", strconv.Itoa(request.N))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = builder.WriteField("size", request.Size)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = builder.WriteField("response_format", request.ResponseFormat)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = builder.Close()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL("/images/variations", withModel(request.Model)),
|
||||||
|
withBody(body),
|
||||||
|
withContentType(builder.FormDataContentType()),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
44
vendor/github.com/sashabaranov/go-openai/internal/error_accumulator.go
generated
vendored
Normal file
44
vendor/github.com/sashabaranov/go-openai/internal/error_accumulator.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrorAccumulator interface {
|
||||||
|
Write(p []byte) error
|
||||||
|
Bytes() []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type errorBuffer interface {
|
||||||
|
io.Writer
|
||||||
|
Len() int
|
||||||
|
Bytes() []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultErrorAccumulator struct {
|
||||||
|
Buffer errorBuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewErrorAccumulator() ErrorAccumulator {
|
||||||
|
return &DefaultErrorAccumulator{
|
||||||
|
Buffer: &bytes.Buffer{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DefaultErrorAccumulator) Write(p []byte) error {
|
||||||
|
_, err := e.Buffer.Write(p)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error accumulator write error, %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DefaultErrorAccumulator) Bytes() (errBytes []byte) {
|
||||||
|
if e.Buffer.Len() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errBytes = e.Buffer.Bytes()
|
||||||
|
return
|
||||||
|
}
|
||||||
112
vendor/github.com/sashabaranov/go-openai/internal/form_builder.go
generated
vendored
Normal file
112
vendor/github.com/sashabaranov/go-openai/internal/form_builder.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/textproto"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FormBuilder interface {
|
||||||
|
CreateFormFile(fieldname string, file *os.File) error
|
||||||
|
CreateFormFileReader(fieldname string, r io.Reader, filename string) error
|
||||||
|
WriteField(fieldname, value string) error
|
||||||
|
Close() error
|
||||||
|
FormDataContentType() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultFormBuilder struct {
|
||||||
|
writer *multipart.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFormBuilder(body io.Writer) *DefaultFormBuilder {
|
||||||
|
return &DefaultFormBuilder{
|
||||||
|
writer: multipart.NewWriter(body),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fb *DefaultFormBuilder) CreateFormFile(fieldname string, file *os.File) error {
|
||||||
|
return fb.createFormFile(fieldname, file, file.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
|
||||||
|
|
||||||
|
func escapeQuotes(s string) string {
|
||||||
|
return quoteEscaper.Replace(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateFormFileReader creates a form field with a file reader.
|
||||||
|
// The filename in Content-Disposition is required.
|
||||||
|
func (fb *DefaultFormBuilder) CreateFormFileReader(fieldname string, r io.Reader, filename string) error {
|
||||||
|
if filename == "" {
|
||||||
|
if f, ok := r.(interface{ Name() string }); ok {
|
||||||
|
filename = f.Name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var contentType string
|
||||||
|
if f, ok := r.(interface{ ContentType() string }); ok {
|
||||||
|
contentType = f.ContentType()
|
||||||
|
}
|
||||||
|
|
||||||
|
h := make(textproto.MIMEHeader)
|
||||||
|
h.Set(
|
||||||
|
"Content-Disposition",
|
||||||
|
fmt.Sprintf(
|
||||||
|
`form-data; name="%s"; filename="%s"`,
|
||||||
|
escapeQuotes(fieldname),
|
||||||
|
escapeQuotes(filepath.Base(filename)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// content type is optional, but it can be set
|
||||||
|
if contentType != "" {
|
||||||
|
h.Set("Content-Type", contentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldWriter, err := fb.writer.CreatePart(h)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(fieldWriter, r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fb *DefaultFormBuilder) createFormFile(fieldname string, r io.Reader, filename string) error {
|
||||||
|
if filename == "" {
|
||||||
|
return fmt.Errorf("filename cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldWriter, err := fb.writer.CreateFormFile(fieldname, filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(fieldWriter, r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fb *DefaultFormBuilder) WriteField(fieldname, value string) error {
|
||||||
|
if fieldname == "" {
|
||||||
|
return fmt.Errorf("fieldname cannot be empty")
|
||||||
|
}
|
||||||
|
return fb.writer.WriteField(fieldname, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fb *DefaultFormBuilder) Close() error {
|
||||||
|
return fb.writer.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fb *DefaultFormBuilder) FormDataContentType() string {
|
||||||
|
return fb.writer.FormDataContentType()
|
||||||
|
}
|
||||||
15
vendor/github.com/sashabaranov/go-openai/internal/marshaller.go
generated
vendored
Normal file
15
vendor/github.com/sashabaranov/go-openai/internal/marshaller.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Marshaller interface {
|
||||||
|
Marshal(value any) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type JSONMarshaller struct{}
|
||||||
|
|
||||||
|
func (jm *JSONMarshaller) Marshal(value any) ([]byte, error) {
|
||||||
|
return json.Marshal(value)
|
||||||
|
}
|
||||||
52
vendor/github.com/sashabaranov/go-openai/internal/request_builder.go
generated
vendored
Normal file
52
vendor/github.com/sashabaranov/go-openai/internal/request_builder.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RequestBuilder interface {
|
||||||
|
Build(ctx context.Context, method, url string, body any, header http.Header) (*http.Request, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type HTTPRequestBuilder struct {
|
||||||
|
marshaller Marshaller
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRequestBuilder() *HTTPRequestBuilder {
|
||||||
|
return &HTTPRequestBuilder{
|
||||||
|
marshaller: &JSONMarshaller{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *HTTPRequestBuilder) Build(
|
||||||
|
ctx context.Context,
|
||||||
|
method string,
|
||||||
|
url string,
|
||||||
|
body any,
|
||||||
|
header http.Header,
|
||||||
|
) (req *http.Request, err error) {
|
||||||
|
var bodyReader io.Reader
|
||||||
|
if body != nil {
|
||||||
|
if v, ok := body.(io.Reader); ok {
|
||||||
|
bodyReader = v
|
||||||
|
} else {
|
||||||
|
var reqBytes []byte
|
||||||
|
reqBytes, err = b.marshaller.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bodyReader = bytes.NewBuffer(reqBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req, err = http.NewRequestWithContext(ctx, method, url, bodyReader)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if header != nil {
|
||||||
|
req.Header = header
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
15
vendor/github.com/sashabaranov/go-openai/internal/unmarshaler.go
generated
vendored
Normal file
15
vendor/github.com/sashabaranov/go-openai/internal/unmarshaler.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Unmarshaler interface {
|
||||||
|
Unmarshal(data []byte, v any) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type JSONUnmarshaler struct{}
|
||||||
|
|
||||||
|
func (jm *JSONUnmarshaler) Unmarshal(data []byte, v any) error {
|
||||||
|
return json.Unmarshal(data, v)
|
||||||
|
}
|
||||||
235
vendor/github.com/sashabaranov/go-openai/jsonschema/json.go
generated
vendored
Normal file
235
vendor/github.com/sashabaranov/go-openai/jsonschema/json.go
generated
vendored
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
// Package jsonschema provides very simple functionality for representing a JSON schema as a
|
||||||
|
// (nested) struct. This struct can be used with the chat completion "function call" feature.
|
||||||
|
// For more complicated schemas, it is recommended to use a dedicated JSON schema library
|
||||||
|
// and/or pass in the schema in []byte format.
|
||||||
|
package jsonschema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DataType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
Object DataType = "object"
|
||||||
|
Number DataType = "number"
|
||||||
|
Integer DataType = "integer"
|
||||||
|
String DataType = "string"
|
||||||
|
Array DataType = "array"
|
||||||
|
Null DataType = "null"
|
||||||
|
Boolean DataType = "boolean"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Definition is a struct for describing a JSON Schema.
|
||||||
|
// It is fairly limited, and you may have better luck using a third-party library.
|
||||||
|
type Definition struct {
|
||||||
|
// Type specifies the data type of the schema.
|
||||||
|
Type DataType `json:"type,omitempty"`
|
||||||
|
// Description is the description of the schema.
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
// Enum is used to restrict a value to a fixed set of values. It must be an array with at least
|
||||||
|
// one element, where each element is unique. You will probably only use this with strings.
|
||||||
|
Enum []string `json:"enum,omitempty"`
|
||||||
|
// Properties describes the properties of an object, if the schema type is Object.
|
||||||
|
Properties map[string]Definition `json:"properties,omitempty"`
|
||||||
|
// Required specifies which properties are required, if the schema type is Object.
|
||||||
|
Required []string `json:"required,omitempty"`
|
||||||
|
// Items specifies which data type an array contains, if the schema type is Array.
|
||||||
|
Items *Definition `json:"items,omitempty"`
|
||||||
|
// AdditionalProperties is used to control the handling of properties in an object
|
||||||
|
// that are not explicitly defined in the properties section of the schema. example:
|
||||||
|
// additionalProperties: true
|
||||||
|
// additionalProperties: false
|
||||||
|
// additionalProperties: jsonschema.Definition{Type: jsonschema.String}
|
||||||
|
AdditionalProperties any `json:"additionalProperties,omitempty"`
|
||||||
|
// Whether the schema is nullable or not.
|
||||||
|
Nullable bool `json:"nullable,omitempty"`
|
||||||
|
|
||||||
|
// Ref Reference to a definition in $defs or external schema.
|
||||||
|
Ref string `json:"$ref,omitempty"`
|
||||||
|
// Defs A map of reusable schema definitions.
|
||||||
|
Defs map[string]Definition `json:"$defs,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Definition) MarshalJSON() ([]byte, error) {
|
||||||
|
if d.Properties == nil {
|
||||||
|
d.Properties = make(map[string]Definition)
|
||||||
|
}
|
||||||
|
type Alias Definition
|
||||||
|
return json.Marshal(struct {
|
||||||
|
Alias
|
||||||
|
}{
|
||||||
|
Alias: (Alias)(*d),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Definition) Unmarshal(content string, v any) error {
|
||||||
|
return VerifySchemaAndUnmarshal(*d, []byte(content), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateSchemaForType(v any) (*Definition, error) {
|
||||||
|
var defs = make(map[string]Definition)
|
||||||
|
def, err := reflectSchema(reflect.TypeOf(v), defs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// If the schema has a root $ref, resolve it by:
|
||||||
|
// 1. Extracting the key from the $ref.
|
||||||
|
// 2. Detaching the referenced definition from $defs.
|
||||||
|
// 3. Checking for self-references in the detached definition.
|
||||||
|
// - If a self-reference is found, restore the original $defs structure.
|
||||||
|
// 4. Flattening the referenced definition into the root schema.
|
||||||
|
// 5. Clearing the $ref field in the root schema.
|
||||||
|
if def.Ref != "" {
|
||||||
|
origRef := def.Ref
|
||||||
|
key := strings.TrimPrefix(origRef, "#/$defs/")
|
||||||
|
if root, ok := defs[key]; ok {
|
||||||
|
delete(defs, key)
|
||||||
|
root.Defs = defs
|
||||||
|
if containsRef(root, origRef) {
|
||||||
|
root.Defs = nil
|
||||||
|
defs[key] = root
|
||||||
|
}
|
||||||
|
*def = root
|
||||||
|
}
|
||||||
|
def.Ref = ""
|
||||||
|
}
|
||||||
|
def.Defs = defs
|
||||||
|
return def, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectSchema(t reflect.Type, defs map[string]Definition) (*Definition, error) {
|
||||||
|
var d Definition
|
||||||
|
switch t.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
d.Type = String
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||||
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
d.Type = Integer
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
d.Type = Number
|
||||||
|
case reflect.Bool:
|
||||||
|
d.Type = Boolean
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
d.Type = Array
|
||||||
|
items, err := reflectSchema(t.Elem(), defs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
d.Items = items
|
||||||
|
case reflect.Struct:
|
||||||
|
if t.Name() != "" {
|
||||||
|
if _, ok := defs[t.Name()]; !ok {
|
||||||
|
defs[t.Name()] = Definition{}
|
||||||
|
object, err := reflectSchemaObject(t, defs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defs[t.Name()] = *object
|
||||||
|
}
|
||||||
|
return &Definition{Ref: "#/$defs/" + t.Name()}, nil
|
||||||
|
}
|
||||||
|
d.Type = Object
|
||||||
|
d.AdditionalProperties = false
|
||||||
|
object, err := reflectSchemaObject(t, defs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
d = *object
|
||||||
|
case reflect.Ptr:
|
||||||
|
definition, err := reflectSchema(t.Elem(), defs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
d = *definition
|
||||||
|
case reflect.Invalid, reflect.Uintptr, reflect.Complex64, reflect.Complex128,
|
||||||
|
reflect.Chan, reflect.Func, reflect.Interface, reflect.Map,
|
||||||
|
reflect.UnsafePointer:
|
||||||
|
return nil, fmt.Errorf("unsupported type: %s", t.Kind().String())
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return &d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func reflectSchemaObject(t reflect.Type, defs map[string]Definition) (*Definition, error) {
|
||||||
|
var d = Definition{
|
||||||
|
Type: Object,
|
||||||
|
AdditionalProperties: false,
|
||||||
|
}
|
||||||
|
properties := make(map[string]Definition)
|
||||||
|
var requiredFields []string
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
field := t.Field(i)
|
||||||
|
if !field.IsExported() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
jsonTag := field.Tag.Get("json")
|
||||||
|
var required = true
|
||||||
|
switch {
|
||||||
|
case jsonTag == "-":
|
||||||
|
continue
|
||||||
|
case jsonTag == "":
|
||||||
|
jsonTag = field.Name
|
||||||
|
case strings.HasSuffix(jsonTag, ",omitempty"):
|
||||||
|
jsonTag = strings.TrimSuffix(jsonTag, ",omitempty")
|
||||||
|
required = false
|
||||||
|
}
|
||||||
|
|
||||||
|
item, err := reflectSchema(field.Type, defs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
description := field.Tag.Get("description")
|
||||||
|
if description != "" {
|
||||||
|
item.Description = description
|
||||||
|
}
|
||||||
|
enum := field.Tag.Get("enum")
|
||||||
|
if enum != "" {
|
||||||
|
item.Enum = strings.Split(enum, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
if n := field.Tag.Get("nullable"); n != "" {
|
||||||
|
nullable, _ := strconv.ParseBool(n)
|
||||||
|
item.Nullable = nullable
|
||||||
|
}
|
||||||
|
|
||||||
|
properties[jsonTag] = *item
|
||||||
|
|
||||||
|
if s := field.Tag.Get("required"); s != "" {
|
||||||
|
required, _ = strconv.ParseBool(s)
|
||||||
|
}
|
||||||
|
if required {
|
||||||
|
requiredFields = append(requiredFields, jsonTag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.Required = requiredFields
|
||||||
|
d.Properties = properties
|
||||||
|
return &d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsRef(def Definition, targetRef string) bool {
|
||||||
|
if def.Ref == targetRef {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, d := range def.Defs {
|
||||||
|
if containsRef(d, targetRef) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, prop := range def.Properties {
|
||||||
|
if containsRef(prop, targetRef) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if def.Items != nil && containsRef(*def.Items, targetRef) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
140
vendor/github.com/sashabaranov/go-openai/jsonschema/validate.go
generated
vendored
Normal file
140
vendor/github.com/sashabaranov/go-openai/jsonschema/validate.go
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
package jsonschema
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CollectDefs(def Definition) map[string]Definition {
|
||||||
|
result := make(map[string]Definition)
|
||||||
|
collectDefsRecursive(def, result, "#")
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectDefsRecursive(def Definition, result map[string]Definition, prefix string) {
|
||||||
|
for k, v := range def.Defs {
|
||||||
|
path := prefix + "/$defs/" + k
|
||||||
|
result[path] = v
|
||||||
|
collectDefsRecursive(v, result, path)
|
||||||
|
}
|
||||||
|
for k, sub := range def.Properties {
|
||||||
|
collectDefsRecursive(sub, result, prefix+"/properties/"+k)
|
||||||
|
}
|
||||||
|
if def.Items != nil {
|
||||||
|
collectDefsRecursive(*def.Items, result, prefix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifySchemaAndUnmarshal(schema Definition, content []byte, v any) error {
|
||||||
|
var data any
|
||||||
|
err := json.Unmarshal(content, &data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !Validate(schema, data, WithDefs(CollectDefs(schema))) {
|
||||||
|
return errors.New("data validation failed against the provided schema")
|
||||||
|
}
|
||||||
|
return json.Unmarshal(content, &v)
|
||||||
|
}
|
||||||
|
|
||||||
|
type validateArgs struct {
|
||||||
|
Defs map[string]Definition
|
||||||
|
}
|
||||||
|
|
||||||
|
type ValidateOption func(*validateArgs)
|
||||||
|
|
||||||
|
func WithDefs(defs map[string]Definition) ValidateOption {
|
||||||
|
return func(option *validateArgs) {
|
||||||
|
option.Defs = defs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Validate(schema Definition, data any, opts ...ValidateOption) bool {
|
||||||
|
args := validateArgs{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&args)
|
||||||
|
}
|
||||||
|
if len(opts) == 0 {
|
||||||
|
args.Defs = CollectDefs(schema)
|
||||||
|
}
|
||||||
|
switch schema.Type {
|
||||||
|
case Object:
|
||||||
|
return validateObject(schema, data, args.Defs)
|
||||||
|
case Array:
|
||||||
|
return validateArray(schema, data, args.Defs)
|
||||||
|
case String:
|
||||||
|
v, ok := data.(string)
|
||||||
|
if ok && len(schema.Enum) > 0 {
|
||||||
|
return contains(schema.Enum, v)
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
case Number: // float64 and int
|
||||||
|
_, ok := data.(float64)
|
||||||
|
if !ok {
|
||||||
|
_, ok = data.(int)
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
case Boolean:
|
||||||
|
_, ok := data.(bool)
|
||||||
|
return ok
|
||||||
|
case Integer:
|
||||||
|
// Golang unmarshals all numbers as float64, so we need to check if the float64 is an integer
|
||||||
|
if num, ok := data.(float64); ok {
|
||||||
|
return num == float64(int64(num))
|
||||||
|
}
|
||||||
|
_, ok := data.(int)
|
||||||
|
return ok
|
||||||
|
case Null:
|
||||||
|
return data == nil
|
||||||
|
default:
|
||||||
|
if schema.Ref != "" && args.Defs != nil {
|
||||||
|
if v, ok := args.Defs[schema.Ref]; ok {
|
||||||
|
return Validate(v, data, WithDefs(args.Defs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateObject(schema Definition, data any, defs map[string]Definition) bool {
|
||||||
|
dataMap, ok := data.(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, field := range schema.Required {
|
||||||
|
if _, exists := dataMap[field]; !exists {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for key, valueSchema := range schema.Properties {
|
||||||
|
value, exists := dataMap[key]
|
||||||
|
if exists && !Validate(valueSchema, value, WithDefs(defs)) {
|
||||||
|
return false
|
||||||
|
} else if !exists && contains(schema.Required, key) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateArray(schema Definition, data any, defs map[string]Definition) bool {
|
||||||
|
dataArray, ok := data.([]any)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, item := range dataArray {
|
||||||
|
if !Validate(*schema.Items, item, WithDefs(defs)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func contains[S ~[]E, E comparable](s S, v E) bool {
|
||||||
|
for i := range s {
|
||||||
|
if v == s[i] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
224
vendor/github.com/sashabaranov/go-openai/messages.go
generated
vendored
Normal file
224
vendor/github.com/sashabaranov/go-openai/messages.go
generated
vendored
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
messagesSuffix = "messages"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
CreatedAt int `json:"created_at"`
|
||||||
|
ThreadID string `json:"thread_id"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
Content []MessageContent `json:"content"`
|
||||||
|
FileIds []string `json:"file_ids"` //nolint:revive //backwards-compatibility
|
||||||
|
AssistantID *string `json:"assistant_id,omitempty"`
|
||||||
|
RunID *string `json:"run_id,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessagesList struct {
|
||||||
|
Messages []Message `json:"data"`
|
||||||
|
|
||||||
|
Object string `json:"object"`
|
||||||
|
FirstID *string `json:"first_id"`
|
||||||
|
LastID *string `json:"last_id"`
|
||||||
|
HasMore bool `json:"has_more"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageContent struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Text *MessageText `json:"text,omitempty"`
|
||||||
|
ImageFile *ImageFile `json:"image_file,omitempty"`
|
||||||
|
ImageURL *ImageURL `json:"image_url,omitempty"`
|
||||||
|
}
|
||||||
|
type MessageText struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
Annotations []any `json:"annotations"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageFile struct {
|
||||||
|
FileID string `json:"file_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageURL struct {
|
||||||
|
URL string `json:"url"`
|
||||||
|
Detail string `json:"detail"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageRequest struct {
|
||||||
|
Role string `json:"role"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
FileIds []string `json:"file_ids,omitempty"` //nolint:revive // backwards-compatibility
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty"`
|
||||||
|
Attachments []ThreadAttachment `json:"attachments,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageFile struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
CreatedAt int `json:"created_at"`
|
||||||
|
MessageID string `json:"message_id"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageFilesList struct {
|
||||||
|
MessageFiles []MessageFile `json:"data"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageDeletionStatus struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
Deleted bool `json:"deleted"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateMessage creates a new message.
|
||||||
|
func (c *Client) CreateMessage(ctx context.Context, threadID string, request MessageRequest) (msg Message, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/%s", threadID, messagesSuffix)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix), withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListMessage fetches all messages in the thread.
|
||||||
|
func (c *Client) ListMessage(ctx context.Context, threadID string,
|
||||||
|
limit *int,
|
||||||
|
order *string,
|
||||||
|
after *string,
|
||||||
|
before *string,
|
||||||
|
runID *string,
|
||||||
|
) (messages MessagesList, err error) {
|
||||||
|
urlValues := url.Values{}
|
||||||
|
if limit != nil {
|
||||||
|
urlValues.Add("limit", fmt.Sprintf("%d", *limit))
|
||||||
|
}
|
||||||
|
if order != nil {
|
||||||
|
urlValues.Add("order", *order)
|
||||||
|
}
|
||||||
|
if after != nil {
|
||||||
|
urlValues.Add("after", *after)
|
||||||
|
}
|
||||||
|
if before != nil {
|
||||||
|
urlValues.Add("before", *before)
|
||||||
|
}
|
||||||
|
if runID != nil {
|
||||||
|
urlValues.Add("run_id", *runID)
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedValues := ""
|
||||||
|
if len(urlValues) > 0 {
|
||||||
|
encodedValues = "?" + urlValues.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/%s%s", threadID, messagesSuffix, encodedValues)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &messages)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveMessage retrieves a Message.
|
||||||
|
func (c *Client) RetrieveMessage(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID, messageID string,
|
||||||
|
) (msg Message, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/%s/%s", threadID, messagesSuffix, messageID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyMessage modifies a message.
|
||||||
|
func (c *Client) ModifyMessage(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID, messageID string,
|
||||||
|
metadata map[string]string,
|
||||||
|
) (msg Message, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/%s/%s", threadID, messagesSuffix, messageID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix),
|
||||||
|
withBody(map[string]any{"metadata": metadata}), withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveMessageFile fetches a message file.
|
||||||
|
func (c *Client) RetrieveMessageFile(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID, messageID, fileID string,
|
||||||
|
) (file MessageFile, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/%s/%s/files/%s", threadID, messagesSuffix, messageID, fileID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &file)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListMessageFiles fetches all files attached to a message.
|
||||||
|
func (c *Client) ListMessageFiles(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID, messageID string,
|
||||||
|
) (files MessageFilesList, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/%s/%s/files", threadID, messagesSuffix, messageID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &files)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMessage deletes a message..
|
||||||
|
func (c *Client) DeleteMessage(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID, messageID string,
|
||||||
|
) (status MessageDeletionStatus, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/%s/%s", threadID, messagesSuffix, messageID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodDelete, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &status)
|
||||||
|
return
|
||||||
|
}
|
||||||
90
vendor/github.com/sashabaranov/go-openai/models.go
generated
vendored
Normal file
90
vendor/github.com/sashabaranov/go-openai/models.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Model struct represents an OpenAPI model.
|
||||||
|
type Model struct {
|
||||||
|
CreatedAt int64 `json:"created"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
OwnedBy string `json:"owned_by"`
|
||||||
|
Permission []Permission `json:"permission"`
|
||||||
|
Root string `json:"root"`
|
||||||
|
Parent string `json:"parent"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permission struct represents an OpenAPI permission.
|
||||||
|
type Permission struct {
|
||||||
|
CreatedAt int64 `json:"created"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
AllowCreateEngine bool `json:"allow_create_engine"`
|
||||||
|
AllowSampling bool `json:"allow_sampling"`
|
||||||
|
AllowLogprobs bool `json:"allow_logprobs"`
|
||||||
|
AllowSearchIndices bool `json:"allow_search_indices"`
|
||||||
|
AllowView bool `json:"allow_view"`
|
||||||
|
AllowFineTuning bool `json:"allow_fine_tuning"`
|
||||||
|
Organization string `json:"organization"`
|
||||||
|
Group interface{} `json:"group"`
|
||||||
|
IsBlocking bool `json:"is_blocking"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FineTuneModelDeleteResponse represents the deletion status of a fine-tuned model.
|
||||||
|
type FineTuneModelDeleteResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
Deleted bool `json:"deleted"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModelsList is a list of models, including those that belong to the user or organization.
|
||||||
|
type ModelsList struct {
|
||||||
|
Models []Model `json:"data"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListModels Lists the currently available models,
|
||||||
|
// and provides basic information about each model such as the model id and parent.
|
||||||
|
func (c *Client) ListModels(ctx context.Context) (models ModelsList, err error) {
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL("/models"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &models)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetModel Retrieves a model instance, providing basic information about
|
||||||
|
// the model such as the owner and permissioning.
|
||||||
|
func (c *Client) GetModel(ctx context.Context, modelID string) (model Model, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/models/%s", modelID)
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &model)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteFineTuneModel Deletes a fine-tune model. You must have the Owner
|
||||||
|
// role in your organization to delete a model.
|
||||||
|
func (c *Client) DeleteFineTuneModel(ctx context.Context, modelID string) (
|
||||||
|
response FineTuneModelDeleteResponse, err error) {
|
||||||
|
req, err := c.newRequest(ctx, http.MethodDelete, c.fullURL("/models/"+modelID))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
107
vendor/github.com/sashabaranov/go-openai/moderation.go
generated
vendored
Normal file
107
vendor/github.com/sashabaranov/go-openai/moderation.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The moderation endpoint is a tool you can use to check whether content complies with OpenAI's usage policies.
|
||||||
|
// Developers can thus identify content that our usage policies prohibits and take action, for instance by filtering it.
|
||||||
|
|
||||||
|
// The default is text-moderation-latest which will be automatically upgraded over time.
|
||||||
|
// This ensures you are always using our most accurate model.
|
||||||
|
// If you use text-moderation-stable, we will provide advanced notice before updating the model.
|
||||||
|
// Accuracy of text-moderation-stable may be slightly lower than for text-moderation-latest.
|
||||||
|
const (
|
||||||
|
ModerationOmniLatest = "omni-moderation-latest"
|
||||||
|
ModerationOmni20240926 = "omni-moderation-2024-09-26"
|
||||||
|
ModerationTextStable = "text-moderation-stable"
|
||||||
|
ModerationTextLatest = "text-moderation-latest"
|
||||||
|
// Deprecated: use ModerationTextStable and ModerationTextLatest instead.
|
||||||
|
ModerationText001 = "text-moderation-001"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrModerationInvalidModel = errors.New("this model is not supported with moderation, please use text-moderation-stable or text-moderation-latest instead") //nolint:lll
|
||||||
|
)
|
||||||
|
|
||||||
|
var validModerationModel = map[string]struct{}{
|
||||||
|
ModerationOmniLatest: {},
|
||||||
|
ModerationOmni20240926: {},
|
||||||
|
ModerationTextStable: {},
|
||||||
|
ModerationTextLatest: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModerationRequest represents a request structure for moderation API.
|
||||||
|
type ModerationRequest struct {
|
||||||
|
Input string `json:"input,omitempty"`
|
||||||
|
Model string `json:"model,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result represents one of possible moderation results.
|
||||||
|
type Result struct {
|
||||||
|
Categories ResultCategories `json:"categories"`
|
||||||
|
CategoryScores ResultCategoryScores `json:"category_scores"`
|
||||||
|
Flagged bool `json:"flagged"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResultCategories represents Categories of Result.
|
||||||
|
type ResultCategories struct {
|
||||||
|
Hate bool `json:"hate"`
|
||||||
|
HateThreatening bool `json:"hate/threatening"`
|
||||||
|
Harassment bool `json:"harassment"`
|
||||||
|
HarassmentThreatening bool `json:"harassment/threatening"`
|
||||||
|
SelfHarm bool `json:"self-harm"`
|
||||||
|
SelfHarmIntent bool `json:"self-harm/intent"`
|
||||||
|
SelfHarmInstructions bool `json:"self-harm/instructions"`
|
||||||
|
Sexual bool `json:"sexual"`
|
||||||
|
SexualMinors bool `json:"sexual/minors"`
|
||||||
|
Violence bool `json:"violence"`
|
||||||
|
ViolenceGraphic bool `json:"violence/graphic"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResultCategoryScores represents CategoryScores of Result.
|
||||||
|
type ResultCategoryScores struct {
|
||||||
|
Hate float32 `json:"hate"`
|
||||||
|
HateThreatening float32 `json:"hate/threatening"`
|
||||||
|
Harassment float32 `json:"harassment"`
|
||||||
|
HarassmentThreatening float32 `json:"harassment/threatening"`
|
||||||
|
SelfHarm float32 `json:"self-harm"`
|
||||||
|
SelfHarmIntent float32 `json:"self-harm/intent"`
|
||||||
|
SelfHarmInstructions float32 `json:"self-harm/instructions"`
|
||||||
|
Sexual float32 `json:"sexual"`
|
||||||
|
SexualMinors float32 `json:"sexual/minors"`
|
||||||
|
Violence float32 `json:"violence"`
|
||||||
|
ViolenceGraphic float32 `json:"violence/graphic"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModerationResponse represents a response structure for moderation API.
|
||||||
|
type ModerationResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
Results []Result `json:"results"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// Moderations — perform a moderation api call over a string.
|
||||||
|
// Input can be an array or slice but a string will reduce the complexity.
|
||||||
|
func (c *Client) Moderations(ctx context.Context, request ModerationRequest) (response ModerationResponse, err error) {
|
||||||
|
if _, ok := validModerationModel[request.Model]; len(request.Model) > 0 && !ok {
|
||||||
|
err = ErrModerationInvalidModel
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL("/moderations", withModel(request.Model)),
|
||||||
|
withBody(&request),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
43
vendor/github.com/sashabaranov/go-openai/ratelimit.go
generated
vendored
Normal file
43
vendor/github.com/sashabaranov/go-openai/ratelimit.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RateLimitHeaders struct represents Openai rate limits headers.
|
||||||
|
type RateLimitHeaders struct {
|
||||||
|
LimitRequests int `json:"x-ratelimit-limit-requests"`
|
||||||
|
LimitTokens int `json:"x-ratelimit-limit-tokens"`
|
||||||
|
RemainingRequests int `json:"x-ratelimit-remaining-requests"`
|
||||||
|
RemainingTokens int `json:"x-ratelimit-remaining-tokens"`
|
||||||
|
ResetRequests ResetTime `json:"x-ratelimit-reset-requests"`
|
||||||
|
ResetTokens ResetTime `json:"x-ratelimit-reset-tokens"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResetTime string
|
||||||
|
|
||||||
|
func (r ResetTime) String() string {
|
||||||
|
return string(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ResetTime) Time() time.Time {
|
||||||
|
d, _ := time.ParseDuration(string(r))
|
||||||
|
return time.Now().Add(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRateLimitHeaders(h http.Header) RateLimitHeaders {
|
||||||
|
limitReq, _ := strconv.Atoi(h.Get("x-ratelimit-limit-requests"))
|
||||||
|
limitTokens, _ := strconv.Atoi(h.Get("x-ratelimit-limit-tokens"))
|
||||||
|
remainingReq, _ := strconv.Atoi(h.Get("x-ratelimit-remaining-requests"))
|
||||||
|
remainingTokens, _ := strconv.Atoi(h.Get("x-ratelimit-remaining-tokens"))
|
||||||
|
return RateLimitHeaders{
|
||||||
|
LimitRequests: limitReq,
|
||||||
|
LimitTokens: limitTokens,
|
||||||
|
RemainingRequests: remainingReq,
|
||||||
|
RemainingTokens: remainingTokens,
|
||||||
|
ResetRequests: ResetTime(h.Get("x-ratelimit-reset-requests")),
|
||||||
|
ResetTokens: ResetTime(h.Get("x-ratelimit-reset-tokens")),
|
||||||
|
}
|
||||||
|
}
|
||||||
82
vendor/github.com/sashabaranov/go-openai/reasoning_validator.go
generated
vendored
Normal file
82
vendor/github.com/sashabaranov/go-openai/reasoning_validator.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Deprecated: use ErrReasoningModelMaxTokensDeprecated instead.
|
||||||
|
ErrO1MaxTokensDeprecated = errors.New("this model is not supported MaxTokens, please use MaxCompletionTokens") //nolint:lll
|
||||||
|
ErrCompletionUnsupportedModel = errors.New("this model is not supported with this method, please use CreateChatCompletion client method instead") //nolint:lll
|
||||||
|
ErrCompletionStreamNotSupported = errors.New("streaming is not supported with this method, please use CreateCompletionStream") //nolint:lll
|
||||||
|
ErrCompletionRequestPromptTypeNotSupported = errors.New("the type of CompletionRequest.Prompt only supports string and []string") //nolint:lll
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrO1BetaLimitationsMessageTypes = errors.New("this model has beta-limitations, user and assistant messages only, system messages are not supported") //nolint:lll
|
||||||
|
ErrO1BetaLimitationsTools = errors.New("this model has beta-limitations, tools, function calling, and response format parameters are not supported") //nolint:lll
|
||||||
|
// Deprecated: use ErrReasoningModelLimitations* instead.
|
||||||
|
ErrO1BetaLimitationsLogprobs = errors.New("this model has beta-limitations, logprobs not supported") //nolint:lll
|
||||||
|
ErrO1BetaLimitationsOther = errors.New("this model has beta-limitations, temperature, top_p and n are fixed at 1, while presence_penalty and frequency_penalty are fixed at 0") //nolint:lll
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//nolint:lll
|
||||||
|
ErrReasoningModelMaxTokensDeprecated = errors.New("this model is not supported MaxTokens, please use MaxCompletionTokens")
|
||||||
|
ErrReasoningModelLimitationsLogprobs = errors.New("this model has beta-limitations, logprobs not supported") //nolint:lll
|
||||||
|
ErrReasoningModelLimitationsOther = errors.New("this model has beta-limitations, temperature, top_p and n are fixed at 1, while presence_penalty and frequency_penalty are fixed at 0") //nolint:lll
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReasoningValidator handles validation for reasoning model requests.
|
||||||
|
type ReasoningValidator struct{}
|
||||||
|
|
||||||
|
// NewReasoningValidator creates a new validator for reasoning models.
|
||||||
|
func NewReasoningValidator() *ReasoningValidator {
|
||||||
|
return &ReasoningValidator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate performs all validation checks for reasoning models.
|
||||||
|
func (v *ReasoningValidator) Validate(request ChatCompletionRequest) error {
|
||||||
|
o1Series := strings.HasPrefix(request.Model, "o1")
|
||||||
|
o3Series := strings.HasPrefix(request.Model, "o3")
|
||||||
|
o4Series := strings.HasPrefix(request.Model, "o4")
|
||||||
|
gpt5Series := strings.HasPrefix(request.Model, "gpt-5")
|
||||||
|
|
||||||
|
if !o1Series && !o3Series && !o4Series && !gpt5Series {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := v.validateReasoningModelParams(request); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateReasoningModelParams checks reasoning model parameters.
|
||||||
|
func (v *ReasoningValidator) validateReasoningModelParams(request ChatCompletionRequest) error {
|
||||||
|
if request.MaxTokens > 0 {
|
||||||
|
return ErrReasoningModelMaxTokensDeprecated
|
||||||
|
}
|
||||||
|
if request.LogProbs {
|
||||||
|
return ErrReasoningModelLimitationsLogprobs
|
||||||
|
}
|
||||||
|
if request.Temperature > 0 && request.Temperature != 1 {
|
||||||
|
return ErrReasoningModelLimitationsOther
|
||||||
|
}
|
||||||
|
if request.TopP > 0 && request.TopP != 1 {
|
||||||
|
return ErrReasoningModelLimitationsOther
|
||||||
|
}
|
||||||
|
if request.N > 0 && request.N != 1 {
|
||||||
|
return ErrReasoningModelLimitationsOther
|
||||||
|
}
|
||||||
|
if request.PresencePenalty > 0 {
|
||||||
|
return ErrReasoningModelLimitationsOther
|
||||||
|
}
|
||||||
|
if request.FrequencyPenalty > 0 {
|
||||||
|
return ErrReasoningModelLimitationsOther
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
454
vendor/github.com/sashabaranov/go-openai/run.go
generated
vendored
Normal file
454
vendor/github.com/sashabaranov/go-openai/run.go
generated
vendored
Normal file
@@ -0,0 +1,454 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Run struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
ThreadID string `json:"thread_id"`
|
||||||
|
AssistantID string `json:"assistant_id"`
|
||||||
|
Status RunStatus `json:"status"`
|
||||||
|
RequiredAction *RunRequiredAction `json:"required_action,omitempty"`
|
||||||
|
LastError *RunLastError `json:"last_error,omitempty"`
|
||||||
|
ExpiresAt int64 `json:"expires_at"`
|
||||||
|
StartedAt *int64 `json:"started_at,omitempty"`
|
||||||
|
CancelledAt *int64 `json:"cancelled_at,omitempty"`
|
||||||
|
FailedAt *int64 `json:"failed_at,omitempty"`
|
||||||
|
CompletedAt *int64 `json:"completed_at,omitempty"`
|
||||||
|
Model string `json:"model"`
|
||||||
|
Instructions string `json:"instructions,omitempty"`
|
||||||
|
Tools []Tool `json:"tools"`
|
||||||
|
FileIDS []string `json:"file_ids"` //nolint:revive // backwards-compatibility
|
||||||
|
Metadata map[string]any `json:"metadata"`
|
||||||
|
Usage Usage `json:"usage,omitempty"`
|
||||||
|
|
||||||
|
Temperature *float32 `json:"temperature,omitempty"`
|
||||||
|
// The maximum number of prompt tokens that may be used over the course of the run.
|
||||||
|
// If the run exceeds the number of prompt tokens specified, the run will end with status 'incomplete'.
|
||||||
|
MaxPromptTokens int `json:"max_prompt_tokens,omitempty"`
|
||||||
|
// The maximum number of completion tokens that may be used over the course of the run.
|
||||||
|
// If the run exceeds the number of completion tokens specified, the run will end with status 'incomplete'.
|
||||||
|
MaxCompletionTokens int `json:"max_completion_tokens,omitempty"`
|
||||||
|
// ThreadTruncationStrategy defines the truncation strategy to use for the thread.
|
||||||
|
TruncationStrategy *ThreadTruncationStrategy `json:"truncation_strategy,omitempty"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type RunStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RunStatusQueued RunStatus = "queued"
|
||||||
|
RunStatusInProgress RunStatus = "in_progress"
|
||||||
|
RunStatusRequiresAction RunStatus = "requires_action"
|
||||||
|
RunStatusCancelling RunStatus = "cancelling"
|
||||||
|
RunStatusFailed RunStatus = "failed"
|
||||||
|
RunStatusCompleted RunStatus = "completed"
|
||||||
|
RunStatusIncomplete RunStatus = "incomplete"
|
||||||
|
RunStatusExpired RunStatus = "expired"
|
||||||
|
RunStatusCancelled RunStatus = "cancelled"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RunRequiredAction struct {
|
||||||
|
Type RequiredActionType `json:"type"`
|
||||||
|
SubmitToolOutputs *SubmitToolOutputs `json:"submit_tool_outputs,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RequiredActionType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RequiredActionTypeSubmitToolOutputs RequiredActionType = "submit_tool_outputs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SubmitToolOutputs struct {
|
||||||
|
ToolCalls []ToolCall `json:"tool_calls"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RunLastError struct {
|
||||||
|
Code RunError `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RunError string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RunErrorServerError RunError = "server_error"
|
||||||
|
RunErrorRateLimitExceeded RunError = "rate_limit_exceeded"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RunRequest struct {
|
||||||
|
AssistantID string `json:"assistant_id"`
|
||||||
|
Model string `json:"model,omitempty"`
|
||||||
|
Instructions string `json:"instructions,omitempty"`
|
||||||
|
AdditionalInstructions string `json:"additional_instructions,omitempty"`
|
||||||
|
AdditionalMessages []ThreadMessage `json:"additional_messages,omitempty"`
|
||||||
|
Tools []Tool `json:"tools,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty"`
|
||||||
|
|
||||||
|
// Sampling temperature between 0 and 2. Higher values like 0.8 are more random.
|
||||||
|
// lower values are more focused and deterministic.
|
||||||
|
Temperature *float32 `json:"temperature,omitempty"`
|
||||||
|
TopP *float32 `json:"top_p,omitempty"`
|
||||||
|
|
||||||
|
// The maximum number of prompt tokens that may be used over the course of the run.
|
||||||
|
// If the run exceeds the number of prompt tokens specified, the run will end with status 'incomplete'.
|
||||||
|
MaxPromptTokens int `json:"max_prompt_tokens,omitempty"`
|
||||||
|
|
||||||
|
// The maximum number of completion tokens that may be used over the course of the run.
|
||||||
|
// If the run exceeds the number of completion tokens specified, the run will end with status 'incomplete'.
|
||||||
|
MaxCompletionTokens int `json:"max_completion_tokens,omitempty"`
|
||||||
|
|
||||||
|
// ThreadTruncationStrategy defines the truncation strategy to use for the thread.
|
||||||
|
TruncationStrategy *ThreadTruncationStrategy `json:"truncation_strategy,omitempty"`
|
||||||
|
|
||||||
|
// This can be either a string or a ToolChoice object.
|
||||||
|
ToolChoice any `json:"tool_choice,omitempty"`
|
||||||
|
// This can be either a string or a ResponseFormat object.
|
||||||
|
ResponseFormat any `json:"response_format,omitempty"`
|
||||||
|
// Disable the default behavior of parallel tool calls by setting it: false.
|
||||||
|
ParallelToolCalls any `json:"parallel_tool_calls,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ThreadTruncationStrategy defines the truncation strategy to use for the thread.
|
||||||
|
// https://platform.openai.com/docs/assistants/how-it-works/truncation-strategy.
|
||||||
|
type ThreadTruncationStrategy struct {
|
||||||
|
// default 'auto'.
|
||||||
|
Type TruncationStrategy `json:"type,omitempty"`
|
||||||
|
// this field should be set if the truncation strategy is set to LastMessages.
|
||||||
|
LastMessages *int `json:"last_messages,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TruncationStrategy defines the existing truncation strategies existing for thread management in an assistant.
|
||||||
|
type TruncationStrategy string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TruncationStrategyAuto messages in the middle of the thread will be dropped to fit the context length of the model.
|
||||||
|
TruncationStrategyAuto = TruncationStrategy("auto")
|
||||||
|
// TruncationStrategyLastMessages the thread will be truncated to the n most recent messages in the thread.
|
||||||
|
TruncationStrategyLastMessages = TruncationStrategy("last_messages")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReponseFormat specifies the format the model must output.
|
||||||
|
// https://platform.openai.com/docs/api-reference/runs/createRun#runs-createrun-response_format.
|
||||||
|
// Type can either be text or json_object.
|
||||||
|
type ReponseFormat struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RunModifyRequest struct {
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunList is a list of runs.
|
||||||
|
type RunList struct {
|
||||||
|
Runs []Run `json:"data"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type SubmitToolOutputsRequest struct {
|
||||||
|
ToolOutputs []ToolOutput `json:"tool_outputs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToolOutput struct {
|
||||||
|
ToolCallID string `json:"tool_call_id"`
|
||||||
|
Output any `json:"output"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateThreadAndRunRequest struct {
|
||||||
|
RunRequest
|
||||||
|
Thread ThreadRequest `json:"thread"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RunStep struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
AssistantID string `json:"assistant_id"`
|
||||||
|
ThreadID string `json:"thread_id"`
|
||||||
|
RunID string `json:"run_id"`
|
||||||
|
Type RunStepType `json:"type"`
|
||||||
|
Status RunStepStatus `json:"status"`
|
||||||
|
StepDetails StepDetails `json:"step_details"`
|
||||||
|
LastError *RunLastError `json:"last_error,omitempty"`
|
||||||
|
ExpiredAt *int64 `json:"expired_at,omitempty"`
|
||||||
|
CancelledAt *int64 `json:"cancelled_at,omitempty"`
|
||||||
|
FailedAt *int64 `json:"failed_at,omitempty"`
|
||||||
|
CompletedAt *int64 `json:"completed_at,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type RunStepStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RunStepStatusInProgress RunStepStatus = "in_progress"
|
||||||
|
RunStepStatusCancelling RunStepStatus = "cancelled"
|
||||||
|
RunStepStatusFailed RunStepStatus = "failed"
|
||||||
|
RunStepStatusCompleted RunStepStatus = "completed"
|
||||||
|
RunStepStatusExpired RunStepStatus = "expired"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RunStepType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RunStepTypeMessageCreation RunStepType = "message_creation"
|
||||||
|
RunStepTypeToolCalls RunStepType = "tool_calls"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepDetails struct {
|
||||||
|
Type RunStepType `json:"type"`
|
||||||
|
MessageCreation *StepDetailsMessageCreation `json:"message_creation,omitempty"`
|
||||||
|
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StepDetailsMessageCreation struct {
|
||||||
|
MessageID string `json:"message_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunStepList is a list of steps.
|
||||||
|
type RunStepList struct {
|
||||||
|
RunSteps []RunStep `json:"data"`
|
||||||
|
|
||||||
|
FirstID string `json:"first_id"`
|
||||||
|
LastID string `json:"last_id"`
|
||||||
|
HasMore bool `json:"has_more"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pagination struct {
|
||||||
|
Limit *int
|
||||||
|
Order *string
|
||||||
|
After *string
|
||||||
|
Before *string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRun creates a new run.
|
||||||
|
func (c *Client) CreateRun(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID string,
|
||||||
|
request RunRequest,
|
||||||
|
) (response Run, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/runs", threadID)
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL(urlSuffix),
|
||||||
|
withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveRun retrieves a run.
|
||||||
|
func (c *Client) RetrieveRun(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID string,
|
||||||
|
runID string,
|
||||||
|
) (response Run, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/runs/%s", threadID, runID)
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodGet,
|
||||||
|
c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyRun modifies a run.
|
||||||
|
func (c *Client) ModifyRun(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID string,
|
||||||
|
runID string,
|
||||||
|
request RunModifyRequest,
|
||||||
|
) (response Run, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/runs/%s", threadID, runID)
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL(urlSuffix),
|
||||||
|
withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRuns lists runs.
|
||||||
|
func (c *Client) ListRuns(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID string,
|
||||||
|
pagination Pagination,
|
||||||
|
) (response RunList, err error) {
|
||||||
|
urlValues := url.Values{}
|
||||||
|
if pagination.Limit != nil {
|
||||||
|
urlValues.Add("limit", fmt.Sprintf("%d", *pagination.Limit))
|
||||||
|
}
|
||||||
|
if pagination.Order != nil {
|
||||||
|
urlValues.Add("order", *pagination.Order)
|
||||||
|
}
|
||||||
|
if pagination.After != nil {
|
||||||
|
urlValues.Add("after", *pagination.After)
|
||||||
|
}
|
||||||
|
if pagination.Before != nil {
|
||||||
|
urlValues.Add("before", *pagination.Before)
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedValues := ""
|
||||||
|
if len(urlValues) > 0 {
|
||||||
|
encodedValues = "?" + urlValues.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/runs%s", threadID, encodedValues)
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodGet,
|
||||||
|
c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmitToolOutputs submits tool outputs.
|
||||||
|
func (c *Client) SubmitToolOutputs(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID string,
|
||||||
|
runID string,
|
||||||
|
request SubmitToolOutputsRequest) (response Run, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/runs/%s/submit_tool_outputs", threadID, runID)
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL(urlSuffix),
|
||||||
|
withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelRun cancels a run.
|
||||||
|
func (c *Client) CancelRun(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID string,
|
||||||
|
runID string) (response Run, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/runs/%s/cancel", threadID, runID)
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateThreadAndRun submits tool outputs.
|
||||||
|
func (c *Client) CreateThreadAndRun(
|
||||||
|
ctx context.Context,
|
||||||
|
request CreateThreadAndRunRequest) (response Run, err error) {
|
||||||
|
urlSuffix := "/threads/runs"
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL(urlSuffix),
|
||||||
|
withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveRunStep retrieves a run step.
|
||||||
|
func (c *Client) RetrieveRunStep(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID string,
|
||||||
|
runID string,
|
||||||
|
stepID string,
|
||||||
|
) (response RunStep, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/runs/%s/steps/%s", threadID, runID, stepID)
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodGet,
|
||||||
|
c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRunSteps lists run steps.
|
||||||
|
func (c *Client) ListRunSteps(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID string,
|
||||||
|
runID string,
|
||||||
|
pagination Pagination,
|
||||||
|
) (response RunStepList, err error) {
|
||||||
|
urlValues := url.Values{}
|
||||||
|
if pagination.Limit != nil {
|
||||||
|
urlValues.Add("limit", fmt.Sprintf("%d", *pagination.Limit))
|
||||||
|
}
|
||||||
|
if pagination.Order != nil {
|
||||||
|
urlValues.Add("order", *pagination.Order)
|
||||||
|
}
|
||||||
|
if pagination.After != nil {
|
||||||
|
urlValues.Add("after", *pagination.After)
|
||||||
|
}
|
||||||
|
if pagination.Before != nil {
|
||||||
|
urlValues.Add("before", *pagination.Before)
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedValues := ""
|
||||||
|
if len(urlValues) > 0 {
|
||||||
|
encodedValues = "?" + urlValues.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
urlSuffix := fmt.Sprintf("/threads/%s/runs/%s/steps%s", threadID, runID, encodedValues)
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodGet,
|
||||||
|
c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
65
vendor/github.com/sashabaranov/go-openai/speech.go
generated
vendored
Normal file
65
vendor/github.com/sashabaranov/go-openai/speech.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SpeechModel string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TTSModel1 SpeechModel = "tts-1"
|
||||||
|
TTSModel1HD SpeechModel = "tts-1-hd"
|
||||||
|
TTSModelCanary SpeechModel = "canary-tts"
|
||||||
|
TTSModelGPT4oMini SpeechModel = "gpt-4o-mini-tts"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SpeechVoice string
|
||||||
|
|
||||||
|
const (
|
||||||
|
VoiceAlloy SpeechVoice = "alloy"
|
||||||
|
VoiceAsh SpeechVoice = "ash"
|
||||||
|
VoiceBallad SpeechVoice = "ballad"
|
||||||
|
VoiceCoral SpeechVoice = "coral"
|
||||||
|
VoiceEcho SpeechVoice = "echo"
|
||||||
|
VoiceFable SpeechVoice = "fable"
|
||||||
|
VoiceOnyx SpeechVoice = "onyx"
|
||||||
|
VoiceNova SpeechVoice = "nova"
|
||||||
|
VoiceShimmer SpeechVoice = "shimmer"
|
||||||
|
VoiceVerse SpeechVoice = "verse"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SpeechResponseFormat string
|
||||||
|
|
||||||
|
const (
|
||||||
|
SpeechResponseFormatMp3 SpeechResponseFormat = "mp3"
|
||||||
|
SpeechResponseFormatOpus SpeechResponseFormat = "opus"
|
||||||
|
SpeechResponseFormatAac SpeechResponseFormat = "aac"
|
||||||
|
SpeechResponseFormatFlac SpeechResponseFormat = "flac"
|
||||||
|
SpeechResponseFormatWav SpeechResponseFormat = "wav"
|
||||||
|
SpeechResponseFormatPcm SpeechResponseFormat = "pcm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateSpeechRequest struct {
|
||||||
|
Model SpeechModel `json:"model"`
|
||||||
|
Input string `json:"input"`
|
||||||
|
Voice SpeechVoice `json:"voice"`
|
||||||
|
Instructions string `json:"instructions,omitempty"` // Optional, Doesnt work with tts-1 or tts-1-hd.
|
||||||
|
ResponseFormat SpeechResponseFormat `json:"response_format,omitempty"` // Optional, default to mp3
|
||||||
|
Speed float64 `json:"speed,omitempty"` // Optional, default to 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CreateSpeech(ctx context.Context, request CreateSpeechRequest) (response RawResponse, err error) {
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL("/audio/speech", withModel(string(request.Model))),
|
||||||
|
withBody(request),
|
||||||
|
withContentType("application/json"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.sendRequestRaw(req)
|
||||||
|
}
|
||||||
55
vendor/github.com/sashabaranov/go-openai/stream.go
generated
vendored
Normal file
55
vendor/github.com/sashabaranov/go-openai/stream.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrTooManyEmptyStreamMessages = errors.New("stream has sent too many empty messages")
|
||||||
|
)
|
||||||
|
|
||||||
|
type CompletionStream struct {
|
||||||
|
*streamReader[CompletionResponse]
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateCompletionStream — API call to create a completion w/ streaming
|
||||||
|
// support. It sets whether to stream back partial progress. If set, tokens will be
|
||||||
|
// sent as data-only server-sent events as they become available, with the
|
||||||
|
// stream terminated by a data: [DONE] message.
|
||||||
|
func (c *Client) CreateCompletionStream(
|
||||||
|
ctx context.Context,
|
||||||
|
request CompletionRequest,
|
||||||
|
) (stream *CompletionStream, err error) {
|
||||||
|
urlSuffix := "/completions"
|
||||||
|
if !checkEndpointSupportsModel(urlSuffix, request.Model) {
|
||||||
|
err = ErrCompletionUnsupportedModel
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !checkPromptType(request.Prompt) {
|
||||||
|
err = ErrCompletionRequestPromptTypeNotSupported
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Stream = true
|
||||||
|
req, err := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL(urlSuffix, withModel(request.Model)),
|
||||||
|
withBody(request),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := sendRequestStream[CompletionResponse](c, req)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
stream = &CompletionStream{
|
||||||
|
streamReader: resp,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
119
vendor/github.com/sashabaranov/go-openai/stream_reader.go
generated
vendored
Normal file
119
vendor/github.com/sashabaranov/go-openai/stream_reader.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
utils "github.com/sashabaranov/go-openai/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
headerData = regexp.MustCompile(`^data:\s*`)
|
||||||
|
errorPrefix = regexp.MustCompile(`^data:\s*{"error":`)
|
||||||
|
)
|
||||||
|
|
||||||
|
type streamable interface {
|
||||||
|
ChatCompletionStreamResponse | CompletionResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
type streamReader[T streamable] struct {
|
||||||
|
emptyMessagesLimit uint
|
||||||
|
isFinished bool
|
||||||
|
|
||||||
|
reader *bufio.Reader
|
||||||
|
response *http.Response
|
||||||
|
errAccumulator utils.ErrorAccumulator
|
||||||
|
unmarshaler utils.Unmarshaler
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stream *streamReader[T]) Recv() (response T, err error) {
|
||||||
|
rawLine, err := stream.RecvRaw()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = stream.unmarshaler.Unmarshal(rawLine, &response)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stream *streamReader[T]) RecvRaw() ([]byte, error) {
|
||||||
|
if stream.isFinished {
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream.processLines()
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:gocognit
|
||||||
|
func (stream *streamReader[T]) processLines() ([]byte, error) {
|
||||||
|
var (
|
||||||
|
emptyMessagesCount uint
|
||||||
|
hasErrorPrefix bool
|
||||||
|
)
|
||||||
|
|
||||||
|
for {
|
||||||
|
rawLine, readErr := stream.reader.ReadBytes('\n')
|
||||||
|
if readErr != nil || hasErrorPrefix {
|
||||||
|
respErr := stream.unmarshalError()
|
||||||
|
if respErr != nil {
|
||||||
|
return nil, fmt.Errorf("error, %w", respErr.Error)
|
||||||
|
}
|
||||||
|
return nil, readErr
|
||||||
|
}
|
||||||
|
|
||||||
|
noSpaceLine := bytes.TrimSpace(rawLine)
|
||||||
|
if errorPrefix.Match(noSpaceLine) {
|
||||||
|
hasErrorPrefix = true
|
||||||
|
}
|
||||||
|
if !headerData.Match(noSpaceLine) || hasErrorPrefix {
|
||||||
|
if hasErrorPrefix {
|
||||||
|
noSpaceLine = headerData.ReplaceAll(noSpaceLine, nil)
|
||||||
|
}
|
||||||
|
writeErr := stream.errAccumulator.Write(noSpaceLine)
|
||||||
|
if writeErr != nil {
|
||||||
|
return nil, writeErr
|
||||||
|
}
|
||||||
|
emptyMessagesCount++
|
||||||
|
if emptyMessagesCount > stream.emptyMessagesLimit {
|
||||||
|
return nil, ErrTooManyEmptyStreamMessages
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
noPrefixLine := headerData.ReplaceAll(noSpaceLine, nil)
|
||||||
|
if string(noPrefixLine) == "[DONE]" {
|
||||||
|
stream.isFinished = true
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
return noPrefixLine, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stream *streamReader[T]) unmarshalError() (errResp *ErrorResponse) {
|
||||||
|
errBytes := stream.errAccumulator.Bytes()
|
||||||
|
if len(errBytes) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := stream.unmarshaler.Unmarshal(errBytes, &errResp)
|
||||||
|
if err != nil {
|
||||||
|
errResp = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stream *streamReader[T]) Close() error {
|
||||||
|
return stream.response.Body.Close()
|
||||||
|
}
|
||||||
171
vendor/github.com/sashabaranov/go-openai/thread.go
generated
vendored
Normal file
171
vendor/github.com/sashabaranov/go-openai/thread.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
threadsSuffix = "/threads"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Thread struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
Metadata map[string]any `json:"metadata"`
|
||||||
|
ToolResources ToolResources `json:"tool_resources,omitempty"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type ThreadRequest struct {
|
||||||
|
Messages []ThreadMessage `json:"messages,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty"`
|
||||||
|
ToolResources *ToolResourcesRequest `json:"tool_resources,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToolResources struct {
|
||||||
|
CodeInterpreter *CodeInterpreterToolResources `json:"code_interpreter,omitempty"`
|
||||||
|
FileSearch *FileSearchToolResources `json:"file_search,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CodeInterpreterToolResources struct {
|
||||||
|
FileIDs []string `json:"file_ids,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileSearchToolResources struct {
|
||||||
|
VectorStoreIDs []string `json:"vector_store_ids,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToolResourcesRequest struct {
|
||||||
|
CodeInterpreter *CodeInterpreterToolResourcesRequest `json:"code_interpreter,omitempty"`
|
||||||
|
FileSearch *FileSearchToolResourcesRequest `json:"file_search,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CodeInterpreterToolResourcesRequest struct {
|
||||||
|
FileIDs []string `json:"file_ids,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileSearchToolResourcesRequest struct {
|
||||||
|
VectorStoreIDs []string `json:"vector_store_ids,omitempty"`
|
||||||
|
VectorStores []VectorStoreToolResources `json:"vector_stores,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type VectorStoreToolResources struct {
|
||||||
|
FileIDs []string `json:"file_ids,omitempty"`
|
||||||
|
ChunkingStrategy *ChunkingStrategy `json:"chunking_strategy,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChunkingStrategy struct {
|
||||||
|
Type ChunkingStrategyType `json:"type"`
|
||||||
|
Static *StaticChunkingStrategy `json:"static,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StaticChunkingStrategy struct {
|
||||||
|
MaxChunkSizeTokens int `json:"max_chunk_size_tokens"`
|
||||||
|
ChunkOverlapTokens int `json:"chunk_overlap_tokens"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChunkingStrategyType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ChunkingStrategyTypeAuto ChunkingStrategyType = "auto"
|
||||||
|
ChunkingStrategyTypeStatic ChunkingStrategyType = "static"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ModifyThreadRequest struct {
|
||||||
|
Metadata map[string]any `json:"metadata"`
|
||||||
|
ToolResources *ToolResources `json:"tool_resources,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ThreadMessageRole string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ThreadMessageRoleAssistant ThreadMessageRole = "assistant"
|
||||||
|
ThreadMessageRoleUser ThreadMessageRole = "user"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ThreadMessage struct {
|
||||||
|
Role ThreadMessageRole `json:"role"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
FileIDs []string `json:"file_ids,omitempty"`
|
||||||
|
Attachments []ThreadAttachment `json:"attachments,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ThreadAttachment struct {
|
||||||
|
FileID string `json:"file_id"`
|
||||||
|
Tools []ThreadAttachmentTool `json:"tools"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ThreadAttachmentTool struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ThreadDeleteResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
Deleted bool `json:"deleted"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateThread creates a new thread.
|
||||||
|
func (c *Client) CreateThread(ctx context.Context, request ThreadRequest) (response Thread, err error) {
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(threadsSuffix), withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveThread retrieves a thread.
|
||||||
|
func (c *Client) RetrieveThread(ctx context.Context, threadID string) (response Thread, err error) {
|
||||||
|
urlSuffix := threadsSuffix + "/" + threadID
|
||||||
|
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyThread modifies a thread.
|
||||||
|
func (c *Client) ModifyThread(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID string,
|
||||||
|
request ModifyThreadRequest,
|
||||||
|
) (response Thread, err error) {
|
||||||
|
urlSuffix := threadsSuffix + "/" + threadID
|
||||||
|
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix), withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteThread deletes a thread.
|
||||||
|
func (c *Client) DeleteThread(
|
||||||
|
ctx context.Context,
|
||||||
|
threadID string,
|
||||||
|
) (response ThreadDeleteResponse, err error) {
|
||||||
|
urlSuffix := threadsSuffix + "/" + threadID
|
||||||
|
req, err := c.newRequest(ctx, http.MethodDelete, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
348
vendor/github.com/sashabaranov/go-openai/vector_store.go
generated
vendored
Normal file
348
vendor/github.com/sashabaranov/go-openai/vector_store.go
generated
vendored
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
package openai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
vectorStoresSuffix = "/vector_stores"
|
||||||
|
vectorStoresFilesSuffix = "/files"
|
||||||
|
vectorStoresFileBatchesSuffix = "/file_batches"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VectorStoreFileCount struct {
|
||||||
|
InProgress int `json:"in_progress"`
|
||||||
|
Completed int `json:"completed"`
|
||||||
|
Failed int `json:"failed"`
|
||||||
|
Cancelled int `json:"cancelled"`
|
||||||
|
Total int `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type VectorStore struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
UsageBytes int `json:"usage_bytes"`
|
||||||
|
FileCounts VectorStoreFileCount `json:"file_counts"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
ExpiresAfter *VectorStoreExpires `json:"expires_after"`
|
||||||
|
ExpiresAt *int `json:"expires_at"`
|
||||||
|
Metadata map[string]any `json:"metadata"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type VectorStoreExpires struct {
|
||||||
|
Anchor string `json:"anchor"`
|
||||||
|
Days int `json:"days"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VectorStoreRequest provides the vector store request parameters.
|
||||||
|
type VectorStoreRequest struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
FileIDs []string `json:"file_ids,omitempty"`
|
||||||
|
ExpiresAfter *VectorStoreExpires `json:"expires_after,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VectorStoresList is a list of vector store.
|
||||||
|
type VectorStoresList struct {
|
||||||
|
VectorStores []VectorStore `json:"data"`
|
||||||
|
LastID *string `json:"last_id"`
|
||||||
|
FirstID *string `json:"first_id"`
|
||||||
|
HasMore bool `json:"has_more"`
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type VectorStoreDeleteResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
Deleted bool `json:"deleted"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type VectorStoreFile struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
VectorStoreID string `json:"vector_store_id"`
|
||||||
|
UsageBytes int `json:"usage_bytes"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type VectorStoreFileRequest struct {
|
||||||
|
FileID string `json:"file_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type VectorStoreFilesList struct {
|
||||||
|
VectorStoreFiles []VectorStoreFile `json:"data"`
|
||||||
|
FirstID *string `json:"first_id"`
|
||||||
|
LastID *string `json:"last_id"`
|
||||||
|
HasMore bool `json:"has_more"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type VectorStoreFileBatch struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Object string `json:"object"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
VectorStoreID string `json:"vector_store_id"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
FileCounts VectorStoreFileCount `json:"file_counts"`
|
||||||
|
|
||||||
|
httpHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
type VectorStoreFileBatchRequest struct {
|
||||||
|
FileIDs []string `json:"file_ids"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateVectorStore creates a new vector store.
|
||||||
|
func (c *Client) CreateVectorStore(ctx context.Context, request VectorStoreRequest) (response VectorStore, err error) {
|
||||||
|
req, _ := c.newRequest(
|
||||||
|
ctx,
|
||||||
|
http.MethodPost,
|
||||||
|
c.fullURL(vectorStoresSuffix),
|
||||||
|
withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion),
|
||||||
|
)
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveVectorStore retrieves an vector store.
|
||||||
|
func (c *Client) RetrieveVectorStore(
|
||||||
|
ctx context.Context,
|
||||||
|
vectorStoreID string,
|
||||||
|
) (response VectorStore, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s", vectorStoresSuffix, vectorStoreID)
|
||||||
|
req, _ := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyVectorStore modifies a vector store.
|
||||||
|
func (c *Client) ModifyVectorStore(
|
||||||
|
ctx context.Context,
|
||||||
|
vectorStoreID string,
|
||||||
|
request VectorStoreRequest,
|
||||||
|
) (response VectorStore, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s", vectorStoresSuffix, vectorStoreID)
|
||||||
|
req, _ := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix), withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteVectorStore deletes an vector store.
|
||||||
|
func (c *Client) DeleteVectorStore(
|
||||||
|
ctx context.Context,
|
||||||
|
vectorStoreID string,
|
||||||
|
) (response VectorStoreDeleteResponse, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s", vectorStoresSuffix, vectorStoreID)
|
||||||
|
req, _ := c.newRequest(ctx, http.MethodDelete, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListVectorStores Lists the currently available vector store.
|
||||||
|
func (c *Client) ListVectorStores(
|
||||||
|
ctx context.Context,
|
||||||
|
pagination Pagination,
|
||||||
|
) (response VectorStoresList, err error) {
|
||||||
|
urlValues := url.Values{}
|
||||||
|
|
||||||
|
if pagination.After != nil {
|
||||||
|
urlValues.Add("after", *pagination.After)
|
||||||
|
}
|
||||||
|
if pagination.Order != nil {
|
||||||
|
urlValues.Add("order", *pagination.Order)
|
||||||
|
}
|
||||||
|
if pagination.Limit != nil {
|
||||||
|
urlValues.Add("limit", fmt.Sprintf("%d", *pagination.Limit))
|
||||||
|
}
|
||||||
|
if pagination.Before != nil {
|
||||||
|
urlValues.Add("before", *pagination.Before)
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedValues := ""
|
||||||
|
if len(urlValues) > 0 {
|
||||||
|
encodedValues = "?" + urlValues.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
urlSuffix := fmt.Sprintf("%s%s", vectorStoresSuffix, encodedValues)
|
||||||
|
req, _ := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateVectorStoreFile creates a new vector store file.
|
||||||
|
func (c *Client) CreateVectorStoreFile(
|
||||||
|
ctx context.Context,
|
||||||
|
vectorStoreID string,
|
||||||
|
request VectorStoreFileRequest,
|
||||||
|
) (response VectorStoreFile, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s%s", vectorStoresSuffix, vectorStoreID, vectorStoresFilesSuffix)
|
||||||
|
req, _ := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix),
|
||||||
|
withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveVectorStoreFile retrieves a vector store file.
|
||||||
|
func (c *Client) RetrieveVectorStoreFile(
|
||||||
|
ctx context.Context,
|
||||||
|
vectorStoreID string,
|
||||||
|
fileID string,
|
||||||
|
) (response VectorStoreFile, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s%s/%s", vectorStoresSuffix, vectorStoreID, vectorStoresFilesSuffix, fileID)
|
||||||
|
req, _ := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteVectorStoreFile deletes an existing file.
|
||||||
|
func (c *Client) DeleteVectorStoreFile(
|
||||||
|
ctx context.Context,
|
||||||
|
vectorStoreID string,
|
||||||
|
fileID string,
|
||||||
|
) (err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s%s/%s", vectorStoresSuffix, vectorStoreID, vectorStoresFilesSuffix, fileID)
|
||||||
|
req, _ := c.newRequest(ctx, http.MethodDelete, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
|
||||||
|
err = c.sendRequest(req, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListVectorStoreFiles Lists the currently available files for a vector store.
|
||||||
|
func (c *Client) ListVectorStoreFiles(
|
||||||
|
ctx context.Context,
|
||||||
|
vectorStoreID string,
|
||||||
|
pagination Pagination,
|
||||||
|
) (response VectorStoreFilesList, err error) {
|
||||||
|
urlValues := url.Values{}
|
||||||
|
if pagination.After != nil {
|
||||||
|
urlValues.Add("after", *pagination.After)
|
||||||
|
}
|
||||||
|
if pagination.Limit != nil {
|
||||||
|
urlValues.Add("limit", fmt.Sprintf("%d", *pagination.Limit))
|
||||||
|
}
|
||||||
|
if pagination.Before != nil {
|
||||||
|
urlValues.Add("before", *pagination.Before)
|
||||||
|
}
|
||||||
|
if pagination.Order != nil {
|
||||||
|
urlValues.Add("order", *pagination.Order)
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedValues := ""
|
||||||
|
if len(urlValues) > 0 {
|
||||||
|
encodedValues = "?" + urlValues.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s%s%s", vectorStoresSuffix, vectorStoreID, vectorStoresFilesSuffix, encodedValues)
|
||||||
|
req, _ := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateVectorStoreFileBatch creates a new vector store file batch.
|
||||||
|
func (c *Client) CreateVectorStoreFileBatch(
|
||||||
|
ctx context.Context,
|
||||||
|
vectorStoreID string,
|
||||||
|
request VectorStoreFileBatchRequest,
|
||||||
|
) (response VectorStoreFileBatch, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s%s", vectorStoresSuffix, vectorStoreID, vectorStoresFileBatchesSuffix)
|
||||||
|
req, _ := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix),
|
||||||
|
withBody(request),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveVectorStoreFileBatch retrieves a vector store file batch.
|
||||||
|
func (c *Client) RetrieveVectorStoreFileBatch(
|
||||||
|
ctx context.Context,
|
||||||
|
vectorStoreID string,
|
||||||
|
batchID string,
|
||||||
|
) (response VectorStoreFileBatch, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s%s/%s", vectorStoresSuffix, vectorStoreID, vectorStoresFileBatchesSuffix, batchID)
|
||||||
|
req, _ := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelVectorStoreFileBatch cancel a new vector store file batch.
|
||||||
|
func (c *Client) CancelVectorStoreFileBatch(
|
||||||
|
ctx context.Context,
|
||||||
|
vectorStoreID string,
|
||||||
|
batchID string,
|
||||||
|
) (response VectorStoreFileBatch, err error) {
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s%s/%s%s", vectorStoresSuffix,
|
||||||
|
vectorStoreID, vectorStoresFileBatchesSuffix, batchID, "/cancel")
|
||||||
|
req, _ := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListVectorStoreFiles Lists the currently available files for a vector store.
|
||||||
|
func (c *Client) ListVectorStoreFilesInBatch(
|
||||||
|
ctx context.Context,
|
||||||
|
vectorStoreID string,
|
||||||
|
batchID string,
|
||||||
|
pagination Pagination,
|
||||||
|
) (response VectorStoreFilesList, err error) {
|
||||||
|
urlValues := url.Values{}
|
||||||
|
if pagination.After != nil {
|
||||||
|
urlValues.Add("after", *pagination.After)
|
||||||
|
}
|
||||||
|
if pagination.Limit != nil {
|
||||||
|
urlValues.Add("limit", fmt.Sprintf("%d", *pagination.Limit))
|
||||||
|
}
|
||||||
|
if pagination.Before != nil {
|
||||||
|
urlValues.Add("before", *pagination.Before)
|
||||||
|
}
|
||||||
|
if pagination.Order != nil {
|
||||||
|
urlValues.Add("order", *pagination.Order)
|
||||||
|
}
|
||||||
|
|
||||||
|
encodedValues := ""
|
||||||
|
if len(urlValues) > 0 {
|
||||||
|
encodedValues = "?" + urlValues.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
urlSuffix := fmt.Sprintf("%s/%s%s/%s%s%s", vectorStoresSuffix,
|
||||||
|
vectorStoreID, vectorStoresFileBatchesSuffix, batchID, "/files", encodedValues)
|
||||||
|
req, _ := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix),
|
||||||
|
withBetaAssistantVersion(c.config.AssistantVersion))
|
||||||
|
|
||||||
|
err = c.sendRequest(req, &response)
|
||||||
|
return
|
||||||
|
}
|
||||||
27
vendor/golang.org/x/mod/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/mod/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
Copyright 2009 The Go Authors.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google LLC nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
22
vendor/golang.org/x/mod/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/mod/PATENTS
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
|
"This implementation" means the copyrightable works distributed by
|
||||||
|
Google as part of the Go project.
|
||||||
|
|
||||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||||
|
patent license to make, have made, use, offer to sell, sell, import,
|
||||||
|
transfer and otherwise run, modify and propagate the contents of this
|
||||||
|
implementation of Go, where such license applies only to those patent
|
||||||
|
claims, both currently owned or controlled by Google and acquired in
|
||||||
|
the future, licensable by Google that are necessarily infringed by this
|
||||||
|
implementation of Go. This grant does not include claims that would be
|
||||||
|
infringed only as a consequence of further modification of this
|
||||||
|
implementation. If you or your agent or exclusive licensee institute or
|
||||||
|
order or agree to the institution of patent litigation against any
|
||||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that this implementation of Go or any code incorporated within this
|
||||||
|
implementation of Go constitutes direct or contributory patent
|
||||||
|
infringement, or inducement of patent infringement, then any patent
|
||||||
|
rights granted to you under this License for this implementation of Go
|
||||||
|
shall terminate as of the date such litigation is filed.
|
||||||
78
vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go
generated
vendored
Normal file
78
vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package lazyregexp is a thin wrapper over regexp, allowing the use of global
|
||||||
|
// regexp variables without forcing them to be compiled at init.
|
||||||
|
package lazyregexp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Regexp is a wrapper around [regexp.Regexp], where the underlying regexp will be
|
||||||
|
// compiled the first time it is needed.
|
||||||
|
type Regexp struct {
|
||||||
|
str string
|
||||||
|
once sync.Once
|
||||||
|
rx *regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Regexp) re() *regexp.Regexp {
|
||||||
|
r.once.Do(r.build)
|
||||||
|
return r.rx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Regexp) build() {
|
||||||
|
r.rx = regexp.MustCompile(r.str)
|
||||||
|
r.str = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Regexp) FindSubmatch(s []byte) [][]byte {
|
||||||
|
return r.re().FindSubmatch(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Regexp) FindStringSubmatch(s string) []string {
|
||||||
|
return r.re().FindStringSubmatch(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Regexp) FindStringSubmatchIndex(s string) []int {
|
||||||
|
return r.re().FindStringSubmatchIndex(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Regexp) ReplaceAllString(src, repl string) string {
|
||||||
|
return r.re().ReplaceAllString(src, repl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Regexp) FindString(s string) string {
|
||||||
|
return r.re().FindString(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Regexp) FindAllString(s string, n int) []string {
|
||||||
|
return r.re().FindAllString(s, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Regexp) MatchString(s string) bool {
|
||||||
|
return r.re().MatchString(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Regexp) SubexpNames() []string {
|
||||||
|
return r.re().SubexpNames()
|
||||||
|
}
|
||||||
|
|
||||||
|
var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test")
|
||||||
|
|
||||||
|
// New creates a new lazy regexp, delaying the compiling work until it is first
|
||||||
|
// needed. If the code is being run as part of tests, the regexp compiling will
|
||||||
|
// happen immediately.
|
||||||
|
func New(str string) *Regexp {
|
||||||
|
lr := &Regexp{str: str}
|
||||||
|
if inTest {
|
||||||
|
// In tests, always compile the regexps early.
|
||||||
|
lr.re()
|
||||||
|
}
|
||||||
|
return lr
|
||||||
|
}
|
||||||
840
vendor/golang.org/x/mod/module/module.go
generated
vendored
Normal file
840
vendor/golang.org/x/mod/module/module.go
generated
vendored
Normal file
@@ -0,0 +1,840 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package module defines the module.Version type along with support code.
|
||||||
|
//
|
||||||
|
// The [module.Version] type is a simple Path, Version pair:
|
||||||
|
//
|
||||||
|
// type Version struct {
|
||||||
|
// Path string
|
||||||
|
// Version string
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// There are no restrictions imposed directly by use of this structure,
|
||||||
|
// but additional checking functions, most notably [Check], verify that
|
||||||
|
// a particular path, version pair is valid.
|
||||||
|
//
|
||||||
|
// # Escaped Paths
|
||||||
|
//
|
||||||
|
// Module paths appear as substrings of file system paths
|
||||||
|
// (in the download cache) and of web server URLs in the proxy protocol.
|
||||||
|
// In general we cannot rely on file systems to be case-sensitive,
|
||||||
|
// nor can we rely on web servers, since they read from file systems.
|
||||||
|
// That is, we cannot rely on the file system to keep rsc.io/QUOTE
|
||||||
|
// and rsc.io/quote separate. Windows and macOS don't.
|
||||||
|
// Instead, we must never require two different casings of a file path.
|
||||||
|
// Because we want the download cache to match the proxy protocol,
|
||||||
|
// and because we want the proxy protocol to be possible to serve
|
||||||
|
// from a tree of static files (which might be stored on a case-insensitive
|
||||||
|
// file system), the proxy protocol must never require two different casings
|
||||||
|
// of a URL path either.
|
||||||
|
//
|
||||||
|
// One possibility would be to make the escaped form be the lowercase
|
||||||
|
// hexadecimal encoding of the actual path bytes. This would avoid ever
|
||||||
|
// needing different casings of a file path, but it would be fairly illegible
|
||||||
|
// to most programmers when those paths appeared in the file system
|
||||||
|
// (including in file paths in compiler errors and stack traces)
|
||||||
|
// in web server logs, and so on. Instead, we want a safe escaped form that
|
||||||
|
// leaves most paths unaltered.
|
||||||
|
//
|
||||||
|
// The safe escaped form is to replace every uppercase letter
|
||||||
|
// with an exclamation mark followed by the letter's lowercase equivalent.
|
||||||
|
//
|
||||||
|
// For example,
|
||||||
|
//
|
||||||
|
// github.com/Azure/azure-sdk-for-go -> github.com/!azure/azure-sdk-for-go.
|
||||||
|
// github.com/GoogleCloudPlatform/cloudsql-proxy -> github.com/!google!cloud!platform/cloudsql-proxy
|
||||||
|
// github.com/Sirupsen/logrus -> github.com/!sirupsen/logrus.
|
||||||
|
//
|
||||||
|
// Import paths that avoid upper-case letters are left unchanged.
|
||||||
|
// Note that because import paths are ASCII-only and avoid various
|
||||||
|
// problematic punctuation (like : < and >), the escaped form is also ASCII-only
|
||||||
|
// and avoids the same problematic punctuation.
|
||||||
|
//
|
||||||
|
// Import paths have never allowed exclamation marks, so there is no
|
||||||
|
// need to define how to escape a literal !.
|
||||||
|
//
|
||||||
|
// # Unicode Restrictions
|
||||||
|
//
|
||||||
|
// Today, paths are disallowed from using Unicode.
|
||||||
|
//
|
||||||
|
// Although paths are currently disallowed from using Unicode,
|
||||||
|
// we would like at some point to allow Unicode letters as well, to assume that
|
||||||
|
// file systems and URLs are Unicode-safe (storing UTF-8), and apply
|
||||||
|
// the !-for-uppercase convention for escaping them in the file system.
|
||||||
|
// But there are at least two subtle considerations.
|
||||||
|
//
|
||||||
|
// First, note that not all case-fold equivalent distinct runes
|
||||||
|
// form an upper/lower pair.
|
||||||
|
// For example, U+004B ('K'), U+006B ('k'), and U+212A ('K' for Kelvin)
|
||||||
|
// are three distinct runes that case-fold to each other.
|
||||||
|
// When we do add Unicode letters, we must not assume that upper/lower
|
||||||
|
// are the only case-equivalent pairs.
|
||||||
|
// Perhaps the Kelvin symbol would be disallowed entirely, for example.
|
||||||
|
// Or perhaps it would escape as "!!k", or perhaps as "(212A)".
|
||||||
|
//
|
||||||
|
// Second, it would be nice to allow Unicode marks as well as letters,
|
||||||
|
// but marks include combining marks, and then we must deal not
|
||||||
|
// only with case folding but also normalization: both U+00E9 ('é')
|
||||||
|
// and U+0065 U+0301 ('e' followed by combining acute accent)
|
||||||
|
// look the same on the page and are treated by some file systems
|
||||||
|
// as the same path. If we do allow Unicode marks in paths, there
|
||||||
|
// must be some kind of normalization to allow only one canonical
|
||||||
|
// encoding of any character used in an import path.
|
||||||
|
package module
|
||||||
|
|
||||||
|
// IMPORTANT NOTE
|
||||||
|
//
|
||||||
|
// This file essentially defines the set of valid import paths for the go command.
|
||||||
|
// There are many subtle considerations, including Unicode ambiguity,
|
||||||
|
// security, network, and file system representations.
|
||||||
|
//
|
||||||
|
// This file also defines the set of valid module path and version combinations,
|
||||||
|
// another topic with many subtle considerations.
|
||||||
|
//
|
||||||
|
// Changes to the semantics in this file require approval from rsc.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmp"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"path"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"golang.org/x/mod/semver"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Version (for clients, a module.Version) is defined by a module path and version pair.
|
||||||
|
// These are stored in their plain (unescaped) form.
|
||||||
|
type Version struct {
|
||||||
|
// Path is a module path, like "golang.org/x/text" or "rsc.io/quote/v2".
|
||||||
|
Path string
|
||||||
|
|
||||||
|
// Version is usually a semantic version in canonical form.
|
||||||
|
// There are three exceptions to this general rule.
|
||||||
|
// First, the top-level target of a build has no specific version
|
||||||
|
// and uses Version = "".
|
||||||
|
// Second, during MVS calculations the version "none" is used
|
||||||
|
// to represent the decision to take no version of a given module.
|
||||||
|
// Third, filesystem paths found in "replace" directives are
|
||||||
|
// represented by a path with an empty version.
|
||||||
|
Version string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a representation of the Version suitable for logging
|
||||||
|
// (Path@Version, or just Path if Version is empty).
|
||||||
|
func (m Version) String() string {
|
||||||
|
if m.Version == "" {
|
||||||
|
return m.Path
|
||||||
|
}
|
||||||
|
return m.Path + "@" + m.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
// A ModuleError indicates an error specific to a module.
|
||||||
|
type ModuleError struct {
|
||||||
|
Path string
|
||||||
|
Version string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// VersionError returns a [ModuleError] derived from a [Version] and error,
|
||||||
|
// or err itself if it is already such an error.
|
||||||
|
func VersionError(v Version, err error) error {
|
||||||
|
var mErr *ModuleError
|
||||||
|
if errors.As(err, &mErr) && mErr.Path == v.Path && mErr.Version == v.Version {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return &ModuleError{
|
||||||
|
Path: v.Path,
|
||||||
|
Version: v.Version,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ModuleError) Error() string {
|
||||||
|
if v, ok := e.Err.(*InvalidVersionError); ok {
|
||||||
|
return fmt.Sprintf("%s@%s: invalid %s: %v", e.Path, v.Version, v.noun(), v.Err)
|
||||||
|
}
|
||||||
|
if e.Version != "" {
|
||||||
|
return fmt.Sprintf("%s@%s: %v", e.Path, e.Version, e.Err)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("module %s: %v", e.Path, e.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ModuleError) Unwrap() error { return e.Err }
|
||||||
|
|
||||||
|
// An InvalidVersionError indicates an error specific to a version, with the
|
||||||
|
// module path unknown or specified externally.
|
||||||
|
//
|
||||||
|
// A [ModuleError] may wrap an InvalidVersionError, but an InvalidVersionError
|
||||||
|
// must not wrap a ModuleError.
|
||||||
|
type InvalidVersionError struct {
|
||||||
|
Version string
|
||||||
|
Pseudo bool
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// noun returns either "version" or "pseudo-version", depending on whether
|
||||||
|
// e.Version is a pseudo-version.
|
||||||
|
func (e *InvalidVersionError) noun() string {
|
||||||
|
if e.Pseudo {
|
||||||
|
return "pseudo-version"
|
||||||
|
}
|
||||||
|
return "version"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidVersionError) Error() string {
|
||||||
|
return fmt.Sprintf("%s %q invalid: %s", e.noun(), e.Version, e.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidVersionError) Unwrap() error { return e.Err }
|
||||||
|
|
||||||
|
// An InvalidPathError indicates a module, import, or file path doesn't
|
||||||
|
// satisfy all naming constraints. See [CheckPath], [CheckImportPath],
|
||||||
|
// and [CheckFilePath] for specific restrictions.
|
||||||
|
type InvalidPathError struct {
|
||||||
|
Kind string // "module", "import", or "file"
|
||||||
|
Path string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidPathError) Error() string {
|
||||||
|
return fmt.Sprintf("malformed %s path %q: %v", e.Kind, e.Path, e.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InvalidPathError) Unwrap() error { return e.Err }
|
||||||
|
|
||||||
|
// Check checks that a given module path, version pair is valid.
|
||||||
|
// In addition to the path being a valid module path
|
||||||
|
// and the version being a valid semantic version,
|
||||||
|
// the two must correspond.
|
||||||
|
// For example, the path "yaml/v2" only corresponds to
|
||||||
|
// semantic versions beginning with "v2.".
|
||||||
|
func Check(path, version string) error {
|
||||||
|
if err := CheckPath(path); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !semver.IsValid(version) {
|
||||||
|
return &ModuleError{
|
||||||
|
Path: path,
|
||||||
|
Err: &InvalidVersionError{Version: version, Err: errors.New("not a semantic version")},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, pathMajor, _ := SplitPathVersion(path)
|
||||||
|
if err := CheckPathMajor(version, pathMajor); err != nil {
|
||||||
|
return &ModuleError{Path: path, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// firstPathOK reports whether r can appear in the first element of a module path.
|
||||||
|
// The first element of the path must be an LDH domain name, at least for now.
|
||||||
|
// To avoid case ambiguity, the domain name must be entirely lower case.
|
||||||
|
func firstPathOK(r rune) bool {
|
||||||
|
return r == '-' || r == '.' ||
|
||||||
|
'0' <= r && r <= '9' ||
|
||||||
|
'a' <= r && r <= 'z'
|
||||||
|
}
|
||||||
|
|
||||||
|
// modPathOK reports whether r can appear in a module path element.
|
||||||
|
// Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~.
|
||||||
|
//
|
||||||
|
// This matches what "go get" has historically recognized in import paths,
|
||||||
|
// and avoids confusing sequences like '%20' or '+' that would change meaning
|
||||||
|
// if used in a URL.
|
||||||
|
//
|
||||||
|
// TODO(rsc): We would like to allow Unicode letters, but that requires additional
|
||||||
|
// care in the safe encoding (see "escaped paths" above).
|
||||||
|
func modPathOK(r rune) bool {
|
||||||
|
if r < utf8.RuneSelf {
|
||||||
|
return r == '-' || r == '.' || r == '_' || r == '~' ||
|
||||||
|
'0' <= r && r <= '9' ||
|
||||||
|
'A' <= r && r <= 'Z' ||
|
||||||
|
'a' <= r && r <= 'z'
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// importPathOK reports whether r can appear in a package import path element.
|
||||||
|
//
|
||||||
|
// Import paths are intermediate between module paths and file paths: we
|
||||||
|
// disallow characters that would be confusing or ambiguous as arguments to
|
||||||
|
// 'go get' (such as '@' and ' ' ), but allow certain characters that are
|
||||||
|
// otherwise-unambiguous on the command line and historically used for some
|
||||||
|
// binary names (such as '++' as a suffix for compiler binaries and wrappers).
|
||||||
|
func importPathOK(r rune) bool {
|
||||||
|
return modPathOK(r) || r == '+'
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileNameOK reports whether r can appear in a file name.
|
||||||
|
// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters.
|
||||||
|
// If we expand the set of allowed characters here, we have to
|
||||||
|
// work harder at detecting potential case-folding and normalization collisions.
|
||||||
|
// See note about "escaped paths" above.
|
||||||
|
func fileNameOK(r rune) bool {
|
||||||
|
if r < utf8.RuneSelf {
|
||||||
|
// Entire set of ASCII punctuation, from which we remove characters:
|
||||||
|
// ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
|
||||||
|
// We disallow some shell special characters: " ' * < > ? ` |
|
||||||
|
// (Note that some of those are disallowed by the Windows file system as well.)
|
||||||
|
// We also disallow path separators / : and \ (fileNameOK is only called on path element characters).
|
||||||
|
// We allow spaces (U+0020) in file names.
|
||||||
|
const allowed = "!#$%&()+,-.=@[]^_{}~ "
|
||||||
|
if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return strings.ContainsRune(allowed, r)
|
||||||
|
}
|
||||||
|
// It may be OK to add more ASCII punctuation here, but only carefully.
|
||||||
|
// For example Windows disallows < > \, and macOS disallows :, so we must not allow those.
|
||||||
|
return unicode.IsLetter(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckPath checks that a module path is valid.
|
||||||
|
// A valid module path is a valid import path, as checked by [CheckImportPath],
|
||||||
|
// with three additional constraints.
|
||||||
|
// First, the leading path element (up to the first slash, if any),
|
||||||
|
// by convention a domain name, must contain only lower-case ASCII letters,
|
||||||
|
// ASCII digits, dots (U+002E), and dashes (U+002D);
|
||||||
|
// it must contain at least one dot and cannot start with a dash.
|
||||||
|
// Second, for a final path element of the form /vN, where N looks numeric
|
||||||
|
// (ASCII digits and dots) must not begin with a leading zero, must not be /v1,
|
||||||
|
// and must not contain any dots. For paths beginning with "gopkg.in/",
|
||||||
|
// this second requirement is replaced by a requirement that the path
|
||||||
|
// follow the gopkg.in server's conventions.
|
||||||
|
// Third, no path element may begin with a dot.
|
||||||
|
func CheckPath(path string) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
err = &InvalidPathError{Kind: "module", Path: path, Err: err}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := checkPath(path, modulePath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i := strings.Index(path, "/")
|
||||||
|
if i < 0 {
|
||||||
|
i = len(path)
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
return fmt.Errorf("leading slash")
|
||||||
|
}
|
||||||
|
if !strings.Contains(path[:i], ".") {
|
||||||
|
return fmt.Errorf("missing dot in first path element")
|
||||||
|
}
|
||||||
|
if path[0] == '-' {
|
||||||
|
return fmt.Errorf("leading dash in first path element")
|
||||||
|
}
|
||||||
|
for _, r := range path[:i] {
|
||||||
|
if !firstPathOK(r) {
|
||||||
|
return fmt.Errorf("invalid char %q in first path element", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, _, ok := SplitPathVersion(path); !ok {
|
||||||
|
return fmt.Errorf("invalid version")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckImportPath checks that an import path is valid.
|
||||||
|
//
|
||||||
|
// A valid import path consists of one or more valid path elements
|
||||||
|
// separated by slashes (U+002F). (It must not begin with nor end in a slash.)
|
||||||
|
//
|
||||||
|
// A valid path element is a non-empty string made up of
|
||||||
|
// ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~.
|
||||||
|
// It must not end with a dot (U+002E), nor contain two dots in a row.
|
||||||
|
//
|
||||||
|
// The element prefix up to the first dot must not be a reserved file name
|
||||||
|
// on Windows, regardless of case (CON, com1, NuL, and so on). The element
|
||||||
|
// must not have a suffix of a tilde followed by one or more ASCII digits
|
||||||
|
// (to exclude paths elements that look like Windows short-names).
|
||||||
|
//
|
||||||
|
// CheckImportPath may be less restrictive in the future, but see the
|
||||||
|
// top-level package documentation for additional information about
|
||||||
|
// subtleties of Unicode.
|
||||||
|
func CheckImportPath(path string) error {
|
||||||
|
if err := checkPath(path, importPath); err != nil {
|
||||||
|
return &InvalidPathError{Kind: "import", Path: path, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// pathKind indicates what kind of path we're checking. Module paths,
|
||||||
|
// import paths, and file paths have different restrictions.
|
||||||
|
type pathKind int
|
||||||
|
|
||||||
|
const (
|
||||||
|
modulePath pathKind = iota
|
||||||
|
importPath
|
||||||
|
filePath
|
||||||
|
)
|
||||||
|
|
||||||
|
// checkPath checks that a general path is valid. kind indicates what
|
||||||
|
// specific constraints should be applied.
|
||||||
|
//
|
||||||
|
// checkPath returns an error describing why the path is not valid.
|
||||||
|
// Because these checks apply to module, import, and file paths,
|
||||||
|
// and because other checks may be applied, the caller is expected to wrap
|
||||||
|
// this error with [InvalidPathError].
|
||||||
|
func checkPath(path string, kind pathKind) error {
|
||||||
|
if !utf8.ValidString(path) {
|
||||||
|
return fmt.Errorf("invalid UTF-8")
|
||||||
|
}
|
||||||
|
if path == "" {
|
||||||
|
return fmt.Errorf("empty string")
|
||||||
|
}
|
||||||
|
if path[0] == '-' && kind != filePath {
|
||||||
|
return fmt.Errorf("leading dash")
|
||||||
|
}
|
||||||
|
if strings.Contains(path, "//") {
|
||||||
|
return fmt.Errorf("double slash")
|
||||||
|
}
|
||||||
|
if path[len(path)-1] == '/' {
|
||||||
|
return fmt.Errorf("trailing slash")
|
||||||
|
}
|
||||||
|
elemStart := 0
|
||||||
|
for i, r := range path {
|
||||||
|
if r == '/' {
|
||||||
|
if err := checkElem(path[elemStart:i], kind); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
elemStart = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := checkElem(path[elemStart:], kind); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkElem checks whether an individual path element is valid.
|
||||||
|
func checkElem(elem string, kind pathKind) error {
|
||||||
|
if elem == "" {
|
||||||
|
return fmt.Errorf("empty path element")
|
||||||
|
}
|
||||||
|
if strings.Count(elem, ".") == len(elem) {
|
||||||
|
return fmt.Errorf("invalid path element %q", elem)
|
||||||
|
}
|
||||||
|
if elem[0] == '.' && kind == modulePath {
|
||||||
|
return fmt.Errorf("leading dot in path element")
|
||||||
|
}
|
||||||
|
if elem[len(elem)-1] == '.' {
|
||||||
|
return fmt.Errorf("trailing dot in path element")
|
||||||
|
}
|
||||||
|
for _, r := range elem {
|
||||||
|
ok := false
|
||||||
|
switch kind {
|
||||||
|
case modulePath:
|
||||||
|
ok = modPathOK(r)
|
||||||
|
case importPath:
|
||||||
|
ok = importPathOK(r)
|
||||||
|
case filePath:
|
||||||
|
ok = fileNameOK(r)
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("internal error: invalid kind %v", kind))
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("invalid char %q", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Windows disallows a bunch of path elements, sadly.
|
||||||
|
// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
|
||||||
|
short := elem
|
||||||
|
if i := strings.Index(short, "."); i >= 0 {
|
||||||
|
short = short[:i]
|
||||||
|
}
|
||||||
|
for _, bad := range badWindowsNames {
|
||||||
|
if strings.EqualFold(bad, short) {
|
||||||
|
return fmt.Errorf("%q disallowed as path element component on Windows", short)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if kind == filePath {
|
||||||
|
// don't check for Windows short-names in file names. They're
|
||||||
|
// only an issue for import paths.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject path components that look like Windows short-names.
|
||||||
|
// Those usually end in a tilde followed by one or more ASCII digits.
|
||||||
|
if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 {
|
||||||
|
suffix := short[tilde+1:]
|
||||||
|
suffixIsDigits := true
|
||||||
|
for _, r := range suffix {
|
||||||
|
if r < '0' || r > '9' {
|
||||||
|
suffixIsDigits = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if suffixIsDigits {
|
||||||
|
return fmt.Errorf("trailing tilde and digits in path element")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckFilePath checks that a slash-separated file path is valid.
|
||||||
|
// The definition of a valid file path is the same as the definition
|
||||||
|
// of a valid import path except that the set of allowed characters is larger:
|
||||||
|
// all Unicode letters, ASCII digits, the ASCII space character (U+0020),
|
||||||
|
// and the ASCII punctuation characters
|
||||||
|
// “!#$%&()+,-.=@[]^_{}~”.
|
||||||
|
// (The excluded punctuation characters, " * < > ? ` ' | / \ and :,
|
||||||
|
// have special meanings in certain shells or operating systems.)
|
||||||
|
//
|
||||||
|
// CheckFilePath may be less restrictive in the future, but see the
|
||||||
|
// top-level package documentation for additional information about
|
||||||
|
// subtleties of Unicode.
|
||||||
|
func CheckFilePath(path string) error {
|
||||||
|
if err := checkPath(path, filePath); err != nil {
|
||||||
|
return &InvalidPathError{Kind: "file", Path: path, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// badWindowsNames are the reserved file path elements on Windows.
|
||||||
|
// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
|
||||||
|
var badWindowsNames = []string{
|
||||||
|
"CON",
|
||||||
|
"PRN",
|
||||||
|
"AUX",
|
||||||
|
"NUL",
|
||||||
|
"COM1",
|
||||||
|
"COM2",
|
||||||
|
"COM3",
|
||||||
|
"COM4",
|
||||||
|
"COM5",
|
||||||
|
"COM6",
|
||||||
|
"COM7",
|
||||||
|
"COM8",
|
||||||
|
"COM9",
|
||||||
|
"LPT1",
|
||||||
|
"LPT2",
|
||||||
|
"LPT3",
|
||||||
|
"LPT4",
|
||||||
|
"LPT5",
|
||||||
|
"LPT6",
|
||||||
|
"LPT7",
|
||||||
|
"LPT8",
|
||||||
|
"LPT9",
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitPathVersion returns prefix and major version such that prefix+pathMajor == path
|
||||||
|
// and version is either empty or "/vN" for N >= 2.
|
||||||
|
// As a special case, gopkg.in paths are recognized directly;
|
||||||
|
// they require ".vN" instead of "/vN", and for all N, not just N >= 2.
|
||||||
|
// SplitPathVersion returns with ok = false when presented with
|
||||||
|
// a path whose last path element does not satisfy the constraints
|
||||||
|
// applied by [CheckPath], such as "example.com/pkg/v1" or "example.com/pkg/v1.2".
|
||||||
|
func SplitPathVersion(path string) (prefix, pathMajor string, ok bool) {
|
||||||
|
if strings.HasPrefix(path, "gopkg.in/") {
|
||||||
|
return splitGopkgIn(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
i := len(path)
|
||||||
|
dot := false
|
||||||
|
for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9' || path[i-1] == '.') {
|
||||||
|
if path[i-1] == '.' {
|
||||||
|
dot = true
|
||||||
|
}
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
if i <= 1 || i == len(path) || path[i-1] != 'v' || path[i-2] != '/' {
|
||||||
|
return path, "", true
|
||||||
|
}
|
||||||
|
prefix, pathMajor = path[:i-2], path[i-2:]
|
||||||
|
if dot || len(pathMajor) <= 2 || pathMajor[2] == '0' || pathMajor == "/v1" {
|
||||||
|
return path, "", false
|
||||||
|
}
|
||||||
|
return prefix, pathMajor, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitGopkgIn is like SplitPathVersion but only for gopkg.in paths.
|
||||||
|
func splitGopkgIn(path string) (prefix, pathMajor string, ok bool) {
|
||||||
|
if !strings.HasPrefix(path, "gopkg.in/") {
|
||||||
|
return path, "", false
|
||||||
|
}
|
||||||
|
i := len(path)
|
||||||
|
if strings.HasSuffix(path, "-unstable") {
|
||||||
|
i -= len("-unstable")
|
||||||
|
}
|
||||||
|
for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9') {
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
if i <= 1 || path[i-1] != 'v' || path[i-2] != '.' {
|
||||||
|
// All gopkg.in paths must end in vN for some N.
|
||||||
|
return path, "", false
|
||||||
|
}
|
||||||
|
prefix, pathMajor = path[:i-2], path[i-2:]
|
||||||
|
if len(pathMajor) <= 2 || pathMajor[2] == '0' && pathMajor != ".v0" {
|
||||||
|
return path, "", false
|
||||||
|
}
|
||||||
|
return prefix, pathMajor, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchPathMajor reports whether the semantic version v
|
||||||
|
// matches the path major version pathMajor.
|
||||||
|
//
|
||||||
|
// MatchPathMajor returns true if and only if [CheckPathMajor] returns nil.
|
||||||
|
func MatchPathMajor(v, pathMajor string) bool {
|
||||||
|
return CheckPathMajor(v, pathMajor) == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckPathMajor returns a non-nil error if the semantic version v
|
||||||
|
// does not match the path major version pathMajor.
|
||||||
|
func CheckPathMajor(v, pathMajor string) error {
|
||||||
|
// TODO(jayconrod): return errors or panic for invalid inputs. This function
|
||||||
|
// (and others) was covered by integration tests for cmd/go, and surrounding
|
||||||
|
// code protected against invalid inputs like non-canonical versions.
|
||||||
|
if strings.HasPrefix(pathMajor, ".v") && strings.HasSuffix(pathMajor, "-unstable") {
|
||||||
|
pathMajor = strings.TrimSuffix(pathMajor, "-unstable")
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(v, "v0.0.0-") && pathMajor == ".v1" {
|
||||||
|
// Allow old bug in pseudo-versions that generated v0.0.0- pseudoversion for gopkg .v1.
|
||||||
|
// For example, gopkg.in/yaml.v2@v2.2.1's go.mod requires gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
m := semver.Major(v)
|
||||||
|
if pathMajor == "" {
|
||||||
|
if m == "v0" || m == "v1" || semver.Build(v) == "+incompatible" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
pathMajor = "v0 or v1"
|
||||||
|
} else if pathMajor[0] == '/' || pathMajor[0] == '.' {
|
||||||
|
if m == pathMajor[1:] {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
pathMajor = pathMajor[1:]
|
||||||
|
}
|
||||||
|
return &InvalidVersionError{
|
||||||
|
Version: v,
|
||||||
|
Err: fmt.Errorf("should be %s, not %s", pathMajor, semver.Major(v)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PathMajorPrefix returns the major-version tag prefix implied by pathMajor.
|
||||||
|
// An empty PathMajorPrefix allows either v0 or v1.
|
||||||
|
//
|
||||||
|
// Note that [MatchPathMajor] may accept some versions that do not actually begin
|
||||||
|
// with this prefix: namely, it accepts a 'v0.0.0-' prefix for a '.v1'
|
||||||
|
// pathMajor, even though that pathMajor implies 'v1' tagging.
|
||||||
|
func PathMajorPrefix(pathMajor string) string {
|
||||||
|
if pathMajor == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if pathMajor[0] != '/' && pathMajor[0] != '.' {
|
||||||
|
panic("pathMajor suffix " + pathMajor + " passed to PathMajorPrefix lacks separator")
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(pathMajor, ".v") && strings.HasSuffix(pathMajor, "-unstable") {
|
||||||
|
pathMajor = strings.TrimSuffix(pathMajor, "-unstable")
|
||||||
|
}
|
||||||
|
m := pathMajor[1:]
|
||||||
|
if m != semver.Major(m) {
|
||||||
|
panic("pathMajor suffix " + pathMajor + "passed to PathMajorPrefix is not a valid major version")
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanonicalVersion returns the canonical form of the version string v.
|
||||||
|
// It is the same as [semver.Canonical] except that it preserves the special build suffix "+incompatible".
|
||||||
|
func CanonicalVersion(v string) string {
|
||||||
|
cv := semver.Canonical(v)
|
||||||
|
if semver.Build(v) == "+incompatible" {
|
||||||
|
cv += "+incompatible"
|
||||||
|
}
|
||||||
|
return cv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort sorts the list by Path, breaking ties by comparing [Version] fields.
|
||||||
|
// The Version fields are interpreted as semantic versions (using [semver.Compare])
|
||||||
|
// optionally followed by a tie-breaking suffix introduced by a slash character,
|
||||||
|
// like in "v0.0.1/go.mod".
|
||||||
|
func Sort(list []Version) {
|
||||||
|
slices.SortFunc(list, func(i, j Version) int {
|
||||||
|
if i.Path != j.Path {
|
||||||
|
return strings.Compare(i.Path, j.Path)
|
||||||
|
}
|
||||||
|
// To help go.sum formatting, allow version/file.
|
||||||
|
// Compare semver prefix by semver rules,
|
||||||
|
// file by string order.
|
||||||
|
vi := i.Version
|
||||||
|
vj := j.Version
|
||||||
|
var fi, fj string
|
||||||
|
if k := strings.Index(vi, "/"); k >= 0 {
|
||||||
|
vi, fi = vi[:k], vi[k:]
|
||||||
|
}
|
||||||
|
if k := strings.Index(vj, "/"); k >= 0 {
|
||||||
|
vj, fj = vj[:k], vj[k:]
|
||||||
|
}
|
||||||
|
if vi != vj {
|
||||||
|
return semver.Compare(vi, vj)
|
||||||
|
}
|
||||||
|
return cmp.Compare(fi, fj)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// EscapePath returns the escaped form of the given module path.
|
||||||
|
// It fails if the module path is invalid.
|
||||||
|
func EscapePath(path string) (escaped string, err error) {
|
||||||
|
if err := CheckPath(path); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return escapeString(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EscapeVersion returns the escaped form of the given module version.
|
||||||
|
// Versions are allowed to be in non-semver form but must be valid file names
|
||||||
|
// and not contain exclamation marks.
|
||||||
|
func EscapeVersion(v string) (escaped string, err error) {
|
||||||
|
if err := checkElem(v, filePath); err != nil || strings.Contains(v, "!") {
|
||||||
|
return "", &InvalidVersionError{
|
||||||
|
Version: v,
|
||||||
|
Err: fmt.Errorf("disallowed version string"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return escapeString(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func escapeString(s string) (escaped string, err error) {
|
||||||
|
haveUpper := false
|
||||||
|
for _, r := range s {
|
||||||
|
if r == '!' || r >= utf8.RuneSelf {
|
||||||
|
// This should be disallowed by CheckPath, but diagnose anyway.
|
||||||
|
// The correctness of the escaping loop below depends on it.
|
||||||
|
return "", fmt.Errorf("internal error: inconsistency in EscapePath")
|
||||||
|
}
|
||||||
|
if 'A' <= r && r <= 'Z' {
|
||||||
|
haveUpper = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !haveUpper {
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf []byte
|
||||||
|
for _, r := range s {
|
||||||
|
if 'A' <= r && r <= 'Z' {
|
||||||
|
buf = append(buf, '!', byte(r+'a'-'A'))
|
||||||
|
} else {
|
||||||
|
buf = append(buf, byte(r))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(buf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnescapePath returns the module path for the given escaped path.
|
||||||
|
// It fails if the escaped path is invalid or describes an invalid path.
|
||||||
|
func UnescapePath(escaped string) (path string, err error) {
|
||||||
|
path, ok := unescapeString(escaped)
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("invalid escaped module path %q", escaped)
|
||||||
|
}
|
||||||
|
if err := CheckPath(path); err != nil {
|
||||||
|
return "", fmt.Errorf("invalid escaped module path %q: %v", escaped, err)
|
||||||
|
}
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnescapeVersion returns the version string for the given escaped version.
|
||||||
|
// It fails if the escaped form is invalid or describes an invalid version.
|
||||||
|
// Versions are allowed to be in non-semver form but must be valid file names
|
||||||
|
// and not contain exclamation marks.
|
||||||
|
func UnescapeVersion(escaped string) (v string, err error) {
|
||||||
|
v, ok := unescapeString(escaped)
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("invalid escaped version %q", escaped)
|
||||||
|
}
|
||||||
|
if err := checkElem(v, filePath); err != nil {
|
||||||
|
return "", fmt.Errorf("invalid escaped version %q: %v", v, err)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unescapeString(escaped string) (string, bool) {
|
||||||
|
var buf []byte
|
||||||
|
|
||||||
|
bang := false
|
||||||
|
for _, r := range escaped {
|
||||||
|
if r >= utf8.RuneSelf {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
if bang {
|
||||||
|
bang = false
|
||||||
|
if r < 'a' || 'z' < r {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
buf = append(buf, byte(r+'A'-'a'))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r == '!' {
|
||||||
|
bang = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if 'A' <= r && r <= 'Z' {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
buf = append(buf, byte(r))
|
||||||
|
}
|
||||||
|
if bang {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return string(buf), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchPrefixPatterns reports whether any path prefix of target matches one of
|
||||||
|
// the glob patterns (as defined by [path.Match]) in the comma-separated globs
|
||||||
|
// list. This implements the algorithm used when matching a module path to the
|
||||||
|
// GOPRIVATE environment variable, as described by 'go help module-private'.
|
||||||
|
//
|
||||||
|
// It ignores any empty or malformed patterns in the list.
|
||||||
|
// Trailing slashes on patterns are ignored.
|
||||||
|
func MatchPrefixPatterns(globs, target string) bool {
|
||||||
|
for globs != "" {
|
||||||
|
// Extract next non-empty glob in comma-separated list.
|
||||||
|
var glob string
|
||||||
|
if before, after, ok := strings.Cut(globs, ","); ok {
|
||||||
|
glob, globs = before, after
|
||||||
|
} else {
|
||||||
|
glob, globs = globs, ""
|
||||||
|
}
|
||||||
|
glob = strings.TrimSuffix(glob, "/")
|
||||||
|
if glob == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// A glob with N+1 path elements (N slashes) needs to be matched
|
||||||
|
// against the first N+1 path elements of target,
|
||||||
|
// which end just before the N+1'th slash.
|
||||||
|
n := strings.Count(glob, "/")
|
||||||
|
prefix := target
|
||||||
|
// Walk target, counting slashes, truncating at the N+1'th slash.
|
||||||
|
for i := 0; i < len(target); i++ {
|
||||||
|
if target[i] == '/' {
|
||||||
|
if n == 0 {
|
||||||
|
prefix = target[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
n--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
// Not enough prefix elements.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
matched, _ := path.Match(glob, prefix)
|
||||||
|
if matched {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
250
vendor/golang.org/x/mod/module/pseudo.go
generated
vendored
Normal file
250
vendor/golang.org/x/mod/module/pseudo.go
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Pseudo-versions
|
||||||
|
//
|
||||||
|
// Code authors are expected to tag the revisions they want users to use,
|
||||||
|
// including prereleases. However, not all authors tag versions at all,
|
||||||
|
// and not all commits a user might want to try will have tags.
|
||||||
|
// A pseudo-version is a version with a special form that allows us to
|
||||||
|
// address an untagged commit and order that version with respect to
|
||||||
|
// other versions we might encounter.
|
||||||
|
//
|
||||||
|
// A pseudo-version takes one of the general forms:
|
||||||
|
//
|
||||||
|
// (1) vX.0.0-yyyymmddhhmmss-abcdef123456
|
||||||
|
// (2) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456
|
||||||
|
// (3) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456+incompatible
|
||||||
|
// (4) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456
|
||||||
|
// (5) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456+incompatible
|
||||||
|
//
|
||||||
|
// If there is no recently tagged version with the right major version vX,
|
||||||
|
// then form (1) is used, creating a space of pseudo-versions at the bottom
|
||||||
|
// of the vX version range, less than any tagged version, including the unlikely v0.0.0.
|
||||||
|
//
|
||||||
|
// If the most recent tagged version before the target commit is vX.Y.Z or vX.Y.Z+incompatible,
|
||||||
|
// then the pseudo-version uses form (2) or (3), making it a prerelease for the next
|
||||||
|
// possible semantic version after vX.Y.Z. The leading 0 segment in the prerelease string
|
||||||
|
// ensures that the pseudo-version compares less than possible future explicit prereleases
|
||||||
|
// like vX.Y.(Z+1)-rc1 or vX.Y.(Z+1)-1.
|
||||||
|
//
|
||||||
|
// If the most recent tagged version before the target commit is vX.Y.Z-pre or vX.Y.Z-pre+incompatible,
|
||||||
|
// then the pseudo-version uses form (4) or (5), making it a slightly later prerelease.
|
||||||
|
|
||||||
|
package module
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/mod/internal/lazyregexp"
|
||||||
|
"golang.org/x/mod/semver"
|
||||||
|
)
|
||||||
|
|
||||||
|
var pseudoVersionRE = lazyregexp.New(`^v[0-9]+\.(0\.0-|\d+\.\d+-([^+]*\.)?0\.)\d{14}-[A-Za-z0-9]+(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$`)
|
||||||
|
|
||||||
|
const PseudoVersionTimestampFormat = "20060102150405"
|
||||||
|
|
||||||
|
// PseudoVersion returns a pseudo-version for the given major version ("v1")
|
||||||
|
// preexisting older tagged version ("" or "v1.2.3" or "v1.2.3-pre"), revision time,
|
||||||
|
// and revision identifier (usually a 12-byte commit hash prefix).
|
||||||
|
func PseudoVersion(major, older string, t time.Time, rev string) string {
|
||||||
|
if major == "" {
|
||||||
|
major = "v0"
|
||||||
|
}
|
||||||
|
segment := fmt.Sprintf("%s-%s", t.UTC().Format(PseudoVersionTimestampFormat), rev)
|
||||||
|
build := semver.Build(older)
|
||||||
|
older = semver.Canonical(older)
|
||||||
|
if older == "" {
|
||||||
|
return major + ".0.0-" + segment // form (1)
|
||||||
|
}
|
||||||
|
if semver.Prerelease(older) != "" {
|
||||||
|
return older + ".0." + segment + build // form (4), (5)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Form (2), (3).
|
||||||
|
// Extract patch from vMAJOR.MINOR.PATCH
|
||||||
|
i := strings.LastIndex(older, ".") + 1
|
||||||
|
v, patch := older[:i], older[i:]
|
||||||
|
|
||||||
|
// Reassemble.
|
||||||
|
return v + incDecimal(patch) + "-0." + segment + build
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZeroPseudoVersion returns a pseudo-version with a zero timestamp and
|
||||||
|
// revision, which may be used as a placeholder.
|
||||||
|
func ZeroPseudoVersion(major string) string {
|
||||||
|
return PseudoVersion(major, "", time.Time{}, "000000000000")
|
||||||
|
}
|
||||||
|
|
||||||
|
// incDecimal returns the decimal string incremented by 1.
|
||||||
|
func incDecimal(decimal string) string {
|
||||||
|
// Scan right to left turning 9s to 0s until you find a digit to increment.
|
||||||
|
digits := []byte(decimal)
|
||||||
|
i := len(digits) - 1
|
||||||
|
for ; i >= 0 && digits[i] == '9'; i-- {
|
||||||
|
digits[i] = '0'
|
||||||
|
}
|
||||||
|
if i >= 0 {
|
||||||
|
digits[i]++
|
||||||
|
} else {
|
||||||
|
// digits is all zeros
|
||||||
|
digits[0] = '1'
|
||||||
|
digits = append(digits, '0')
|
||||||
|
}
|
||||||
|
return string(digits)
|
||||||
|
}
|
||||||
|
|
||||||
|
// decDecimal returns the decimal string decremented by 1, or the empty string
|
||||||
|
// if the decimal is all zeroes.
|
||||||
|
func decDecimal(decimal string) string {
|
||||||
|
// Scan right to left turning 0s to 9s until you find a digit to decrement.
|
||||||
|
digits := []byte(decimal)
|
||||||
|
i := len(digits) - 1
|
||||||
|
for ; i >= 0 && digits[i] == '0'; i-- {
|
||||||
|
digits[i] = '9'
|
||||||
|
}
|
||||||
|
if i < 0 {
|
||||||
|
// decimal is all zeros
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if i == 0 && digits[i] == '1' && len(digits) > 1 {
|
||||||
|
digits = digits[1:]
|
||||||
|
} else {
|
||||||
|
digits[i]--
|
||||||
|
}
|
||||||
|
return string(digits)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPseudoVersion reports whether v is a pseudo-version.
|
||||||
|
func IsPseudoVersion(v string) bool {
|
||||||
|
return strings.Count(v, "-") >= 2 && semver.IsValid(v) && pseudoVersionRE.MatchString(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZeroPseudoVersion returns whether v is a pseudo-version with a zero base,
|
||||||
|
// timestamp, and revision, as returned by [ZeroPseudoVersion].
|
||||||
|
func IsZeroPseudoVersion(v string) bool {
|
||||||
|
return v == ZeroPseudoVersion(semver.Major(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PseudoVersionTime returns the time stamp of the pseudo-version v.
|
||||||
|
// It returns an error if v is not a pseudo-version or if the time stamp
|
||||||
|
// embedded in the pseudo-version is not a valid time.
|
||||||
|
func PseudoVersionTime(v string) (time.Time, error) {
|
||||||
|
_, timestamp, _, _, err := parsePseudoVersion(v)
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
t, err := time.Parse("20060102150405", timestamp)
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, &InvalidVersionError{
|
||||||
|
Version: v,
|
||||||
|
Pseudo: true,
|
||||||
|
Err: fmt.Errorf("malformed time %q", timestamp),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PseudoVersionRev returns the revision identifier of the pseudo-version v.
|
||||||
|
// It returns an error if v is not a pseudo-version.
|
||||||
|
func PseudoVersionRev(v string) (rev string, err error) {
|
||||||
|
_, _, rev, _, err = parsePseudoVersion(v)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// PseudoVersionBase returns the canonical parent version, if any, upon which
|
||||||
|
// the pseudo-version v is based.
|
||||||
|
//
|
||||||
|
// If v has no parent version (that is, if it is "vX.0.0-[…]"),
|
||||||
|
// PseudoVersionBase returns the empty string and a nil error.
|
||||||
|
func PseudoVersionBase(v string) (string, error) {
|
||||||
|
base, _, _, build, err := parsePseudoVersion(v)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch pre := semver.Prerelease(base); pre {
|
||||||
|
case "":
|
||||||
|
// vX.0.0-yyyymmddhhmmss-abcdef123456 → ""
|
||||||
|
if build != "" {
|
||||||
|
// Pseudo-versions of the form vX.0.0-yyyymmddhhmmss-abcdef123456+incompatible
|
||||||
|
// are nonsensical: the "vX.0.0-" prefix implies that there is no parent tag,
|
||||||
|
// but the "+incompatible" suffix implies that the major version of
|
||||||
|
// the parent tag is not compatible with the module's import path.
|
||||||
|
//
|
||||||
|
// There are a few such entries in the index generated by proxy.golang.org,
|
||||||
|
// but we believe those entries were generated by the proxy itself.
|
||||||
|
return "", &InvalidVersionError{
|
||||||
|
Version: v,
|
||||||
|
Pseudo: true,
|
||||||
|
Err: fmt.Errorf("lacks base version, but has build metadata %q", build),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
|
||||||
|
case "-0":
|
||||||
|
// vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456 → vX.Y.Z
|
||||||
|
// vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456+incompatible → vX.Y.Z+incompatible
|
||||||
|
base = strings.TrimSuffix(base, pre)
|
||||||
|
i := strings.LastIndexByte(base, '.')
|
||||||
|
if i < 0 {
|
||||||
|
panic("base from parsePseudoVersion missing patch number: " + base)
|
||||||
|
}
|
||||||
|
patch := decDecimal(base[i+1:])
|
||||||
|
if patch == "" {
|
||||||
|
// vX.0.0-0 is invalid, but has been observed in the wild in the index
|
||||||
|
// generated by requests to proxy.golang.org.
|
||||||
|
//
|
||||||
|
// NOTE(bcmills): I cannot find a historical bug that accounts for
|
||||||
|
// pseudo-versions of this form, nor have I seen such versions in any
|
||||||
|
// actual go.mod files. If we find actual examples of this form and a
|
||||||
|
// reasonable theory of how they came into existence, it seems fine to
|
||||||
|
// treat them as equivalent to vX.0.0 (especially since the invalid
|
||||||
|
// pseudo-versions have lower precedence than the real ones). For now, we
|
||||||
|
// reject them.
|
||||||
|
return "", &InvalidVersionError{
|
||||||
|
Version: v,
|
||||||
|
Pseudo: true,
|
||||||
|
Err: fmt.Errorf("version before %s would have negative patch number", base),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base[:i+1] + patch + build, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
// vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456 → vX.Y.Z-pre
|
||||||
|
// vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456+incompatible → vX.Y.Z-pre+incompatible
|
||||||
|
if !strings.HasSuffix(base, ".0") {
|
||||||
|
panic(`base from parsePseudoVersion missing ".0" before date: ` + base)
|
||||||
|
}
|
||||||
|
return strings.TrimSuffix(base, ".0") + build, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var errPseudoSyntax = errors.New("syntax error")
|
||||||
|
|
||||||
|
func parsePseudoVersion(v string) (base, timestamp, rev, build string, err error) {
|
||||||
|
if !IsPseudoVersion(v) {
|
||||||
|
return "", "", "", "", &InvalidVersionError{
|
||||||
|
Version: v,
|
||||||
|
Pseudo: true,
|
||||||
|
Err: errPseudoSyntax,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
build = semver.Build(v)
|
||||||
|
v = strings.TrimSuffix(v, build)
|
||||||
|
j := strings.LastIndex(v, "-")
|
||||||
|
v, rev = v[:j], v[j+1:]
|
||||||
|
i := strings.LastIndex(v, "-")
|
||||||
|
if j := strings.LastIndex(v, "."); j > i {
|
||||||
|
base = v[:j] // "vX.Y.Z-pre.0" or "vX.Y.(Z+1)-0"
|
||||||
|
timestamp = v[j+1:]
|
||||||
|
} else {
|
||||||
|
base = v[:i] // "vX.0.0"
|
||||||
|
timestamp = v[i+1:]
|
||||||
|
}
|
||||||
|
return base, timestamp, rev, build, nil
|
||||||
|
}
|
||||||
407
vendor/golang.org/x/mod/semver/semver.go
generated
vendored
Normal file
407
vendor/golang.org/x/mod/semver/semver.go
generated
vendored
Normal file
@@ -0,0 +1,407 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package semver implements comparison of semantic version strings.
|
||||||
|
// In this package, semantic version strings must begin with a leading "v",
|
||||||
|
// as in "v1.0.0".
|
||||||
|
//
|
||||||
|
// The general form of a semantic version string accepted by this package is
|
||||||
|
//
|
||||||
|
// vMAJOR[.MINOR[.PATCH[-PRERELEASE][+BUILD]]]
|
||||||
|
//
|
||||||
|
// where square brackets indicate optional parts of the syntax;
|
||||||
|
// MAJOR, MINOR, and PATCH are decimal integers without extra leading zeros;
|
||||||
|
// PRERELEASE and BUILD are each a series of non-empty dot-separated identifiers
|
||||||
|
// using only alphanumeric characters and hyphens; and
|
||||||
|
// all-numeric PRERELEASE identifiers must not have leading zeros.
|
||||||
|
//
|
||||||
|
// This package follows Semantic Versioning 2.0.0 (see semver.org)
|
||||||
|
// with two exceptions. First, it requires the "v" prefix. Second, it recognizes
|
||||||
|
// vMAJOR and vMAJOR.MINOR (with no prerelease or build suffixes)
|
||||||
|
// as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0.
|
||||||
|
package semver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// parsed returns the parsed form of a semantic version string.
|
||||||
|
type parsed struct {
|
||||||
|
major string
|
||||||
|
minor string
|
||||||
|
patch string
|
||||||
|
short string
|
||||||
|
prerelease string
|
||||||
|
build string
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid reports whether v is a valid semantic version string.
|
||||||
|
func IsValid(v string) bool {
|
||||||
|
_, ok := parse(v)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Canonical returns the canonical formatting of the semantic version v.
|
||||||
|
// It fills in any missing .MINOR or .PATCH and discards build metadata.
|
||||||
|
// Two semantic versions compare equal only if their canonical formatting
|
||||||
|
// is an identical string.
|
||||||
|
// The canonical invalid semantic version is the empty string.
|
||||||
|
func Canonical(v string) string {
|
||||||
|
p, ok := parse(v)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if p.build != "" {
|
||||||
|
return v[:len(v)-len(p.build)]
|
||||||
|
}
|
||||||
|
if p.short != "" {
|
||||||
|
return v + p.short
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Major returns the major version prefix of the semantic version v.
|
||||||
|
// For example, Major("v2.1.0") == "v2".
|
||||||
|
// If v is an invalid semantic version string, Major returns the empty string.
|
||||||
|
func Major(v string) string {
|
||||||
|
pv, ok := parse(v)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return v[:1+len(pv.major)]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MajorMinor returns the major.minor version prefix of the semantic version v.
|
||||||
|
// For example, MajorMinor("v2.1.0") == "v2.1".
|
||||||
|
// If v is an invalid semantic version string, MajorMinor returns the empty string.
|
||||||
|
func MajorMinor(v string) string {
|
||||||
|
pv, ok := parse(v)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
i := 1 + len(pv.major)
|
||||||
|
if j := i + 1 + len(pv.minor); j <= len(v) && v[i] == '.' && v[i+1:j] == pv.minor {
|
||||||
|
return v[:j]
|
||||||
|
}
|
||||||
|
return v[:i] + "." + pv.minor
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prerelease returns the prerelease suffix of the semantic version v.
|
||||||
|
// For example, Prerelease("v2.1.0-pre+meta") == "-pre".
|
||||||
|
// If v is an invalid semantic version string, Prerelease returns the empty string.
|
||||||
|
func Prerelease(v string) string {
|
||||||
|
pv, ok := parse(v)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return pv.prerelease
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build returns the build suffix of the semantic version v.
|
||||||
|
// For example, Build("v2.1.0+meta") == "+meta".
|
||||||
|
// If v is an invalid semantic version string, Build returns the empty string.
|
||||||
|
func Build(v string) string {
|
||||||
|
pv, ok := parse(v)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return pv.build
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare returns an integer comparing two versions according to
|
||||||
|
// semantic version precedence.
|
||||||
|
// The result will be 0 if v == w, -1 if v < w, or +1 if v > w.
|
||||||
|
//
|
||||||
|
// An invalid semantic version string is considered less than a valid one.
|
||||||
|
// All invalid semantic version strings compare equal to each other.
|
||||||
|
func Compare(v, w string) int {
|
||||||
|
pv, ok1 := parse(v)
|
||||||
|
pw, ok2 := parse(w)
|
||||||
|
if !ok1 && !ok2 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if !ok1 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if !ok2 {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
if c := compareInt(pv.major, pw.major); c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
if c := compareInt(pv.minor, pw.minor); c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
if c := compareInt(pv.patch, pw.patch); c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return comparePrerelease(pv.prerelease, pw.prerelease)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max canonicalizes its arguments and then returns the version string
|
||||||
|
// that compares greater.
|
||||||
|
//
|
||||||
|
// Deprecated: use [Compare] instead. In most cases, returning a canonicalized
|
||||||
|
// version is not expected or desired.
|
||||||
|
func Max(v, w string) string {
|
||||||
|
v = Canonical(v)
|
||||||
|
w = Canonical(w)
|
||||||
|
if Compare(v, w) > 0 {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByVersion implements [sort.Interface] for sorting semantic version strings.
|
||||||
|
type ByVersion []string
|
||||||
|
|
||||||
|
func (vs ByVersion) Len() int { return len(vs) }
|
||||||
|
func (vs ByVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] }
|
||||||
|
func (vs ByVersion) Less(i, j int) bool { return compareVersion(vs[i], vs[j]) < 0 }
|
||||||
|
|
||||||
|
// Sort sorts a list of semantic version strings using [Compare] and falls back
|
||||||
|
// to use [strings.Compare] if both versions are considered equal.
|
||||||
|
func Sort(list []string) {
|
||||||
|
slices.SortFunc(list, compareVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareVersion(a, b string) int {
|
||||||
|
cmp := Compare(a, b)
|
||||||
|
if cmp != 0 {
|
||||||
|
return cmp
|
||||||
|
}
|
||||||
|
return strings.Compare(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parse(v string) (p parsed, ok bool) {
|
||||||
|
if v == "" || v[0] != 'v' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.major, v, ok = parseInt(v[1:])
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v == "" {
|
||||||
|
p.minor = "0"
|
||||||
|
p.patch = "0"
|
||||||
|
p.short = ".0.0"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v[0] != '.' {
|
||||||
|
ok = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.minor, v, ok = parseInt(v[1:])
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v == "" {
|
||||||
|
p.patch = "0"
|
||||||
|
p.short = ".0"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v[0] != '.' {
|
||||||
|
ok = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.patch, v, ok = parseInt(v[1:])
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(v) > 0 && v[0] == '-' {
|
||||||
|
p.prerelease, v, ok = parsePrerelease(v)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(v) > 0 && v[0] == '+' {
|
||||||
|
p.build, v, ok = parseBuild(v)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v != "" {
|
||||||
|
ok = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInt(v string) (t, rest string, ok bool) {
|
||||||
|
if v == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v[0] < '0' || '9' < v[0] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i := 1
|
||||||
|
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if v[0] == '0' && i != 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return v[:i], v[i:], true
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsePrerelease(v string) (t, rest string, ok bool) {
|
||||||
|
// "A pre-release version MAY be denoted by appending a hyphen and
|
||||||
|
// a series of dot separated identifiers immediately following the patch version.
|
||||||
|
// Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-].
|
||||||
|
// Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes."
|
||||||
|
if v == "" || v[0] != '-' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i := 1
|
||||||
|
start := 1
|
||||||
|
for i < len(v) && v[i] != '+' {
|
||||||
|
if !isIdentChar(v[i]) && v[i] != '.' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v[i] == '.' {
|
||||||
|
if start == i || isBadNum(v[start:i]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
start = i + 1
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if start == i || isBadNum(v[start:i]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return v[:i], v[i:], true
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseBuild(v string) (t, rest string, ok bool) {
|
||||||
|
if v == "" || v[0] != '+' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i := 1
|
||||||
|
start := 1
|
||||||
|
for i < len(v) {
|
||||||
|
if !isIdentChar(v[i]) && v[i] != '.' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if v[i] == '.' {
|
||||||
|
if start == i {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
start = i + 1
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if start == i {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return v[:i], v[i:], true
|
||||||
|
}
|
||||||
|
|
||||||
|
func isIdentChar(c byte) bool {
|
||||||
|
return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isBadNum(v string) bool {
|
||||||
|
i := 0
|
||||||
|
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return i == len(v) && i > 1 && v[0] == '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNum(v string) bool {
|
||||||
|
i := 0
|
||||||
|
for i < len(v) && '0' <= v[i] && v[i] <= '9' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return i == len(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareInt(x, y string) int {
|
||||||
|
if x == y {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if len(x) < len(y) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if len(x) > len(y) {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
if x < y {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func comparePrerelease(x, y string) int {
|
||||||
|
// "When major, minor, and patch are equal, a pre-release version has
|
||||||
|
// lower precedence than a normal version.
|
||||||
|
// Example: 1.0.0-alpha < 1.0.0.
|
||||||
|
// Precedence for two pre-release versions with the same major, minor,
|
||||||
|
// and patch version MUST be determined by comparing each dot separated
|
||||||
|
// identifier from left to right until a difference is found as follows:
|
||||||
|
// identifiers consisting of only digits are compared numerically and
|
||||||
|
// identifiers with letters or hyphens are compared lexically in ASCII
|
||||||
|
// sort order. Numeric identifiers always have lower precedence than
|
||||||
|
// non-numeric identifiers. A larger set of pre-release fields has a
|
||||||
|
// higher precedence than a smaller set, if all of the preceding
|
||||||
|
// identifiers are equal.
|
||||||
|
// Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta <
|
||||||
|
// 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0."
|
||||||
|
if x == y {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if x == "" {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
if y == "" {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
for x != "" && y != "" {
|
||||||
|
x = x[1:] // skip - or .
|
||||||
|
y = y[1:] // skip - or .
|
||||||
|
var dx, dy string
|
||||||
|
dx, x = nextIdent(x)
|
||||||
|
dy, y = nextIdent(y)
|
||||||
|
if dx != dy {
|
||||||
|
ix := isNum(dx)
|
||||||
|
iy := isNum(dy)
|
||||||
|
if ix != iy {
|
||||||
|
if ix {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ix {
|
||||||
|
if len(dx) < len(dy) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if len(dx) > len(dy) {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dx < dy {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if x == "" {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return +1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func nextIdent(x string) (dx, rest string) {
|
||||||
|
i := 0
|
||||||
|
for i < len(x) && x[i] != '.' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return x[:i], x[i:]
|
||||||
|
}
|
||||||
27
vendor/golang.org/x/sync/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/sync/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
Copyright 2009 The Go Authors.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google LLC nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
22
vendor/golang.org/x/sync/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/sync/PATENTS
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
|
"This implementation" means the copyrightable works distributed by
|
||||||
|
Google as part of the Go project.
|
||||||
|
|
||||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||||
|
patent license to make, have made, use, offer to sell, sell, import,
|
||||||
|
transfer and otherwise run, modify and propagate the contents of this
|
||||||
|
implementation of Go, where such license applies only to those patent
|
||||||
|
claims, both currently owned or controlled by Google and acquired in
|
||||||
|
the future, licensable by Google that are necessarily infringed by this
|
||||||
|
implementation of Go. This grant does not include claims that would be
|
||||||
|
infringed only as a consequence of further modification of this
|
||||||
|
implementation. If you or your agent or exclusive licensee institute or
|
||||||
|
order or agree to the institution of patent litigation against any
|
||||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that this implementation of Go or any code incorporated within this
|
||||||
|
implementation of Go constitutes direct or contributory patent
|
||||||
|
infringement, or inducement of patent infringement, then any patent
|
||||||
|
rights granted to you under this License for this implementation of Go
|
||||||
|
shall terminate as of the date such litigation is filed.
|
||||||
151
vendor/golang.org/x/sync/errgroup/errgroup.go
generated
vendored
Normal file
151
vendor/golang.org/x/sync/errgroup/errgroup.go
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package errgroup provides synchronization, error propagation, and Context
|
||||||
|
// cancellation for groups of goroutines working on subtasks of a common task.
|
||||||
|
//
|
||||||
|
// [errgroup.Group] is related to [sync.WaitGroup] but adds handling of tasks
|
||||||
|
// returning errors.
|
||||||
|
package errgroup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type token struct{}
|
||||||
|
|
||||||
|
// A Group is a collection of goroutines working on subtasks that are part of
|
||||||
|
// the same overall task. A Group should not be reused for different tasks.
|
||||||
|
//
|
||||||
|
// A zero Group is valid, has no limit on the number of active goroutines,
|
||||||
|
// and does not cancel on error.
|
||||||
|
type Group struct {
|
||||||
|
cancel func(error)
|
||||||
|
|
||||||
|
wg sync.WaitGroup
|
||||||
|
|
||||||
|
sem chan token
|
||||||
|
|
||||||
|
errOnce sync.Once
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Group) done() {
|
||||||
|
if g.sem != nil {
|
||||||
|
<-g.sem
|
||||||
|
}
|
||||||
|
g.wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithContext returns a new Group and an associated Context derived from ctx.
|
||||||
|
//
|
||||||
|
// The derived Context is canceled the first time a function passed to Go
|
||||||
|
// returns a non-nil error or the first time Wait returns, whichever occurs
|
||||||
|
// first.
|
||||||
|
func WithContext(ctx context.Context) (*Group, context.Context) {
|
||||||
|
ctx, cancel := context.WithCancelCause(ctx)
|
||||||
|
return &Group{cancel: cancel}, ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait blocks until all function calls from the Go method have returned, then
|
||||||
|
// returns the first non-nil error (if any) from them.
|
||||||
|
func (g *Group) Wait() error {
|
||||||
|
g.wg.Wait()
|
||||||
|
if g.cancel != nil {
|
||||||
|
g.cancel(g.err)
|
||||||
|
}
|
||||||
|
return g.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go calls the given function in a new goroutine.
|
||||||
|
//
|
||||||
|
// The first call to Go must happen before a Wait.
|
||||||
|
// It blocks until the new goroutine can be added without the number of
|
||||||
|
// goroutines in the group exceeding the configured limit.
|
||||||
|
//
|
||||||
|
// The first goroutine in the group that returns a non-nil error will
|
||||||
|
// cancel the associated Context, if any. The error will be returned
|
||||||
|
// by Wait.
|
||||||
|
func (g *Group) Go(f func() error) {
|
||||||
|
if g.sem != nil {
|
||||||
|
g.sem <- token{}
|
||||||
|
}
|
||||||
|
|
||||||
|
g.wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer g.done()
|
||||||
|
|
||||||
|
// It is tempting to propagate panics from f()
|
||||||
|
// up to the goroutine that calls Wait, but
|
||||||
|
// it creates more problems than it solves:
|
||||||
|
// - it delays panics arbitrarily,
|
||||||
|
// making bugs harder to detect;
|
||||||
|
// - it turns f's panic stack into a mere value,
|
||||||
|
// hiding it from crash-monitoring tools;
|
||||||
|
// - it risks deadlocks that hide the panic entirely,
|
||||||
|
// if f's panic leaves the program in a state
|
||||||
|
// that prevents the Wait call from being reached.
|
||||||
|
// See #53757, #74275, #74304, #74306.
|
||||||
|
|
||||||
|
if err := f(); err != nil {
|
||||||
|
g.errOnce.Do(func() {
|
||||||
|
g.err = err
|
||||||
|
if g.cancel != nil {
|
||||||
|
g.cancel(g.err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TryGo calls the given function in a new goroutine only if the number of
|
||||||
|
// active goroutines in the group is currently below the configured limit.
|
||||||
|
//
|
||||||
|
// The return value reports whether the goroutine was started.
|
||||||
|
func (g *Group) TryGo(f func() error) bool {
|
||||||
|
if g.sem != nil {
|
||||||
|
select {
|
||||||
|
case g.sem <- token{}:
|
||||||
|
// Note: this allows barging iff channels in general allow barging.
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g.wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer g.done()
|
||||||
|
|
||||||
|
if err := f(); err != nil {
|
||||||
|
g.errOnce.Do(func() {
|
||||||
|
g.err = err
|
||||||
|
if g.cancel != nil {
|
||||||
|
g.cancel(g.err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLimit limits the number of active goroutines in this group to at most n.
|
||||||
|
// A negative value indicates no limit.
|
||||||
|
// A limit of zero will prevent any new goroutines from being added.
|
||||||
|
//
|
||||||
|
// Any subsequent call to the Go method will block until it can add an active
|
||||||
|
// goroutine without exceeding the configured limit.
|
||||||
|
//
|
||||||
|
// The limit must not be modified while any goroutines in the group are active.
|
||||||
|
func (g *Group) SetLimit(n int) {
|
||||||
|
if n < 0 {
|
||||||
|
g.sem = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if active := len(g.sem); active != 0 {
|
||||||
|
panic(fmt.Errorf("errgroup: modify limit while %v goroutines in the group are still active", active))
|
||||||
|
}
|
||||||
|
g.sem = make(chan token, n)
|
||||||
|
}
|
||||||
160
vendor/golang.org/x/sync/semaphore/semaphore.go
generated
vendored
Normal file
160
vendor/golang.org/x/sync/semaphore/semaphore.go
generated
vendored
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package semaphore provides a weighted semaphore implementation.
|
||||||
|
package semaphore // import "golang.org/x/sync/semaphore"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type waiter struct {
|
||||||
|
n int64
|
||||||
|
ready chan<- struct{} // Closed when semaphore acquired.
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWeighted creates a new weighted semaphore with the given
|
||||||
|
// maximum combined weight for concurrent access.
|
||||||
|
func NewWeighted(n int64) *Weighted {
|
||||||
|
w := &Weighted{size: n}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
// Weighted provides a way to bound concurrent access to a resource.
|
||||||
|
// The callers can request access with a given weight.
|
||||||
|
type Weighted struct {
|
||||||
|
size int64
|
||||||
|
cur int64
|
||||||
|
mu sync.Mutex
|
||||||
|
waiters list.List
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire acquires the semaphore with a weight of n, blocking until resources
|
||||||
|
// are available or ctx is done. On success, returns nil. On failure, returns
|
||||||
|
// ctx.Err() and leaves the semaphore unchanged.
|
||||||
|
func (s *Weighted) Acquire(ctx context.Context, n int64) error {
|
||||||
|
done := ctx.Done()
|
||||||
|
|
||||||
|
s.mu.Lock()
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
// ctx becoming done has "happened before" acquiring the semaphore,
|
||||||
|
// whether it became done before the call began or while we were
|
||||||
|
// waiting for the mutex. We prefer to fail even if we could acquire
|
||||||
|
// the mutex without blocking.
|
||||||
|
s.mu.Unlock()
|
||||||
|
return ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if s.size-s.cur >= n && s.waiters.Len() == 0 {
|
||||||
|
// Since we hold s.mu and haven't synchronized since checking done, if
|
||||||
|
// ctx becomes done before we return here, it becoming done must have
|
||||||
|
// "happened concurrently" with this call - it cannot "happen before"
|
||||||
|
// we return in this branch. So, we're ok to always acquire here.
|
||||||
|
s.cur += n
|
||||||
|
s.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if n > s.size {
|
||||||
|
// Don't make other Acquire calls block on one that's doomed to fail.
|
||||||
|
s.mu.Unlock()
|
||||||
|
<-done
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
ready := make(chan struct{})
|
||||||
|
w := waiter{n: n, ready: ready}
|
||||||
|
elem := s.waiters.PushBack(w)
|
||||||
|
s.mu.Unlock()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
s.mu.Lock()
|
||||||
|
select {
|
||||||
|
case <-ready:
|
||||||
|
// Acquired the semaphore after we were canceled.
|
||||||
|
// Pretend we didn't and put the tokens back.
|
||||||
|
s.cur -= n
|
||||||
|
s.notifyWaiters()
|
||||||
|
default:
|
||||||
|
isFront := s.waiters.Front() == elem
|
||||||
|
s.waiters.Remove(elem)
|
||||||
|
// If we're at the front and there're extra tokens left, notify other waiters.
|
||||||
|
if isFront && s.size > s.cur {
|
||||||
|
s.notifyWaiters()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.mu.Unlock()
|
||||||
|
return ctx.Err()
|
||||||
|
|
||||||
|
case <-ready:
|
||||||
|
// Acquired the semaphore. Check that ctx isn't already done.
|
||||||
|
// We check the done channel instead of calling ctx.Err because we
|
||||||
|
// already have the channel, and ctx.Err is O(n) with the nesting
|
||||||
|
// depth of ctx.
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
s.Release(n)
|
||||||
|
return ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TryAcquire acquires the semaphore with a weight of n without blocking.
|
||||||
|
// On success, returns true. On failure, returns false and leaves the semaphore unchanged.
|
||||||
|
func (s *Weighted) TryAcquire(n int64) bool {
|
||||||
|
s.mu.Lock()
|
||||||
|
success := s.size-s.cur >= n && s.waiters.Len() == 0
|
||||||
|
if success {
|
||||||
|
s.cur += n
|
||||||
|
}
|
||||||
|
s.mu.Unlock()
|
||||||
|
return success
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release releases the semaphore with a weight of n.
|
||||||
|
func (s *Weighted) Release(n int64) {
|
||||||
|
s.mu.Lock()
|
||||||
|
s.cur -= n
|
||||||
|
if s.cur < 0 {
|
||||||
|
s.mu.Unlock()
|
||||||
|
panic("semaphore: released more than held")
|
||||||
|
}
|
||||||
|
s.notifyWaiters()
|
||||||
|
s.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Weighted) notifyWaiters() {
|
||||||
|
for {
|
||||||
|
next := s.waiters.Front()
|
||||||
|
if next == nil {
|
||||||
|
break // No more waiters blocked.
|
||||||
|
}
|
||||||
|
|
||||||
|
w := next.Value.(waiter)
|
||||||
|
if s.size-s.cur < w.n {
|
||||||
|
// Not enough tokens for the next waiter. We could keep going (to try to
|
||||||
|
// find a waiter with a smaller request), but under load that could cause
|
||||||
|
// starvation for large requests; instead, we leave all remaining waiters
|
||||||
|
// blocked.
|
||||||
|
//
|
||||||
|
// Consider a semaphore used as a read-write lock, with N tokens, N
|
||||||
|
// readers, and one writer. Each reader can Acquire(1) to obtain a read
|
||||||
|
// lock. The writer can Acquire(N) to obtain a write lock, excluding all
|
||||||
|
// of the readers. If we allow the readers to jump ahead in the queue,
|
||||||
|
// the writer will starve — there is always one token available for every
|
||||||
|
// reader.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
s.cur += w.n
|
||||||
|
s.waiters.Remove(next)
|
||||||
|
close(w.ready)
|
||||||
|
}
|
||||||
|
}
|
||||||
27
vendor/golang.org/x/sys/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/sys/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
Copyright 2009 The Go Authors.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google LLC nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
22
vendor/golang.org/x/sys/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/sys/PATENTS
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
|
"This implementation" means the copyrightable works distributed by
|
||||||
|
Google as part of the Go project.
|
||||||
|
|
||||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||||
|
patent license to make, have made, use, offer to sell, sell, import,
|
||||||
|
transfer and otherwise run, modify and propagate the contents of this
|
||||||
|
implementation of Go, where such license applies only to those patent
|
||||||
|
claims, both currently owned or controlled by Google and acquired in
|
||||||
|
the future, licensable by Google that are necessarily infringed by this
|
||||||
|
implementation of Go. This grant does not include claims that would be
|
||||||
|
infringed only as a consequence of further modification of this
|
||||||
|
implementation. If you or your agent or exclusive licensee institute or
|
||||||
|
order or agree to the institution of patent litigation against any
|
||||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that this implementation of Go or any code incorporated within this
|
||||||
|
implementation of Go constitutes direct or contributory patent
|
||||||
|
infringement, or inducement of patent infringement, then any patent
|
||||||
|
rights granted to you under this License for this implementation of Go
|
||||||
|
shall terminate as of the date such litigation is filed.
|
||||||
12
vendor/golang.org/x/sys/windows/aliases.go
generated
vendored
Normal file
12
vendor/golang.org/x/sys/windows/aliases.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
type Errno = syscall.Errno
|
||||||
|
type SysProcAttr = syscall.SysProcAttr
|
||||||
415
vendor/golang.org/x/sys/windows/dll_windows.go
generated
vendored
Normal file
415
vendor/golang.org/x/sys/windows/dll_windows.go
generated
vendored
Normal file
@@ -0,0 +1,415 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// We need to use LoadLibrary and GetProcAddress from the Go runtime, because
|
||||||
|
// the these symbols are loaded by the system linker and are required to
|
||||||
|
// dynamically load additional symbols. Note that in the Go runtime, these
|
||||||
|
// return syscall.Handle and syscall.Errno, but these are the same, in fact,
|
||||||
|
// as windows.Handle and windows.Errno, and we intend to keep these the same.
|
||||||
|
|
||||||
|
//go:linkname syscall_loadlibrary syscall.loadlibrary
|
||||||
|
func syscall_loadlibrary(filename *uint16) (handle Handle, err Errno)
|
||||||
|
|
||||||
|
//go:linkname syscall_getprocaddress syscall.getprocaddress
|
||||||
|
func syscall_getprocaddress(handle Handle, procname *uint8) (proc uintptr, err Errno)
|
||||||
|
|
||||||
|
// DLLError describes reasons for DLL load failures.
|
||||||
|
type DLLError struct {
|
||||||
|
Err error
|
||||||
|
ObjName string
|
||||||
|
Msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DLLError) Error() string { return e.Msg }
|
||||||
|
|
||||||
|
func (e *DLLError) Unwrap() error { return e.Err }
|
||||||
|
|
||||||
|
// A DLL implements access to a single DLL.
|
||||||
|
type DLL struct {
|
||||||
|
Name string
|
||||||
|
Handle Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadDLL loads DLL file into memory.
|
||||||
|
//
|
||||||
|
// Warning: using LoadDLL without an absolute path name is subject to
|
||||||
|
// DLL preloading attacks. To safely load a system DLL, use [NewLazySystemDLL],
|
||||||
|
// or use [LoadLibraryEx] directly.
|
||||||
|
func LoadDLL(name string) (dll *DLL, err error) {
|
||||||
|
namep, err := UTF16PtrFromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
h, e := syscall_loadlibrary(namep)
|
||||||
|
if e != 0 {
|
||||||
|
return nil, &DLLError{
|
||||||
|
Err: e,
|
||||||
|
ObjName: name,
|
||||||
|
Msg: "Failed to load " + name + ": " + e.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d := &DLL{
|
||||||
|
Name: name,
|
||||||
|
Handle: h,
|
||||||
|
}
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustLoadDLL is like LoadDLL but panics if load operation fails.
|
||||||
|
func MustLoadDLL(name string) *DLL {
|
||||||
|
d, e := LoadDLL(name)
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindProc searches DLL d for procedure named name and returns *Proc
|
||||||
|
// if found. It returns an error if search fails.
|
||||||
|
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
|
||||||
|
namep, err := BytePtrFromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
a, e := syscall_getprocaddress(d.Handle, namep)
|
||||||
|
if e != 0 {
|
||||||
|
return nil, &DLLError{
|
||||||
|
Err: e,
|
||||||
|
ObjName: name,
|
||||||
|
Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p := &Proc{
|
||||||
|
Dll: d,
|
||||||
|
Name: name,
|
||||||
|
addr: a,
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustFindProc is like FindProc but panics if search fails.
|
||||||
|
func (d *DLL) MustFindProc(name string) *Proc {
|
||||||
|
p, e := d.FindProc(name)
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindProcByOrdinal searches DLL d for procedure by ordinal and returns *Proc
|
||||||
|
// if found. It returns an error if search fails.
|
||||||
|
func (d *DLL) FindProcByOrdinal(ordinal uintptr) (proc *Proc, err error) {
|
||||||
|
a, e := GetProcAddressByOrdinal(d.Handle, ordinal)
|
||||||
|
name := "#" + itoa(int(ordinal))
|
||||||
|
if e != nil {
|
||||||
|
return nil, &DLLError{
|
||||||
|
Err: e,
|
||||||
|
ObjName: name,
|
||||||
|
Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p := &Proc{
|
||||||
|
Dll: d,
|
||||||
|
Name: name,
|
||||||
|
addr: a,
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustFindProcByOrdinal is like FindProcByOrdinal but panics if search fails.
|
||||||
|
func (d *DLL) MustFindProcByOrdinal(ordinal uintptr) *Proc {
|
||||||
|
p, e := d.FindProcByOrdinal(ordinal)
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release unloads DLL d from memory.
|
||||||
|
func (d *DLL) Release() (err error) {
|
||||||
|
return FreeLibrary(d.Handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Proc implements access to a procedure inside a DLL.
|
||||||
|
type Proc struct {
|
||||||
|
Dll *DLL
|
||||||
|
Name string
|
||||||
|
addr uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Addr returns the address of the procedure represented by p.
|
||||||
|
// The return value can be passed to Syscall to run the procedure.
|
||||||
|
func (p *Proc) Addr() uintptr {
|
||||||
|
return p.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:uintptrescapes
|
||||||
|
|
||||||
|
// Call executes procedure p with arguments a. It will panic, if more than 15 arguments
|
||||||
|
// are supplied.
|
||||||
|
//
|
||||||
|
// The returned error is always non-nil, constructed from the result of GetLastError.
|
||||||
|
// Callers must inspect the primary return value to decide whether an error occurred
|
||||||
|
// (according to the semantics of the specific function being called) before consulting
|
||||||
|
// the error. The error will be guaranteed to contain windows.Errno.
|
||||||
|
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||||
|
switch len(a) {
|
||||||
|
case 0:
|
||||||
|
return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
|
||||||
|
case 1:
|
||||||
|
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
|
||||||
|
case 2:
|
||||||
|
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
|
||||||
|
case 3:
|
||||||
|
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
|
||||||
|
case 4:
|
||||||
|
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
|
||||||
|
case 5:
|
||||||
|
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
|
||||||
|
case 6:
|
||||||
|
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
|
||||||
|
case 7:
|
||||||
|
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
|
||||||
|
case 8:
|
||||||
|
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
|
||||||
|
case 9:
|
||||||
|
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
|
||||||
|
case 10:
|
||||||
|
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
|
||||||
|
case 11:
|
||||||
|
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
|
||||||
|
case 12:
|
||||||
|
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
|
||||||
|
case 13:
|
||||||
|
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
|
||||||
|
case 14:
|
||||||
|
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
|
||||||
|
case 15:
|
||||||
|
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
|
||||||
|
default:
|
||||||
|
panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A LazyDLL implements access to a single DLL.
|
||||||
|
// It will delay the load of the DLL until the first
|
||||||
|
// call to its Handle method or to one of its
|
||||||
|
// LazyProc's Addr method.
|
||||||
|
type LazyDLL struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// System determines whether the DLL must be loaded from the
|
||||||
|
// Windows System directory, bypassing the normal DLL search
|
||||||
|
// path.
|
||||||
|
System bool
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
dll *DLL // non nil once DLL is loaded
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load loads DLL file d.Name into memory. It returns an error if fails.
|
||||||
|
// Load will not try to load DLL, if it is already loaded into memory.
|
||||||
|
func (d *LazyDLL) Load() error {
|
||||||
|
// Non-racy version of:
|
||||||
|
// if d.dll != nil {
|
||||||
|
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
if d.dll != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// kernel32.dll is special, since it's where LoadLibraryEx comes from.
|
||||||
|
// The kernel already special-cases its name, so it's always
|
||||||
|
// loaded from system32.
|
||||||
|
var dll *DLL
|
||||||
|
var err error
|
||||||
|
if d.Name == "kernel32.dll" {
|
||||||
|
dll, err = LoadDLL(d.Name)
|
||||||
|
} else {
|
||||||
|
dll, err = loadLibraryEx(d.Name, d.System)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-racy version of:
|
||||||
|
// d.dll = dll
|
||||||
|
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// mustLoad is like Load but panics if search fails.
|
||||||
|
func (d *LazyDLL) mustLoad() {
|
||||||
|
e := d.Load()
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle returns d's module handle.
|
||||||
|
func (d *LazyDLL) Handle() uintptr {
|
||||||
|
d.mustLoad()
|
||||||
|
return uintptr(d.dll.Handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
|
||||||
|
func (d *LazyDLL) NewProc(name string) *LazyProc {
|
||||||
|
return &LazyProc{l: d, Name: name}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLazyDLL creates new LazyDLL associated with DLL file.
|
||||||
|
//
|
||||||
|
// Warning: using NewLazyDLL without an absolute path name is subject to
|
||||||
|
// DLL preloading attacks. To safely load a system DLL, use [NewLazySystemDLL].
|
||||||
|
func NewLazyDLL(name string) *LazyDLL {
|
||||||
|
return &LazyDLL{Name: name}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLazySystemDLL is like NewLazyDLL, but will only
|
||||||
|
// search Windows System directory for the DLL if name is
|
||||||
|
// a base name (like "advapi32.dll").
|
||||||
|
func NewLazySystemDLL(name string) *LazyDLL {
|
||||||
|
return &LazyDLL{Name: name, System: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A LazyProc implements access to a procedure inside a LazyDLL.
|
||||||
|
// It delays the lookup until the Addr method is called.
|
||||||
|
type LazyProc struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
l *LazyDLL
|
||||||
|
proc *Proc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find searches DLL for procedure named p.Name. It returns
|
||||||
|
// an error if search fails. Find will not search procedure,
|
||||||
|
// if it is already found and loaded into memory.
|
||||||
|
func (p *LazyProc) Find() error {
|
||||||
|
// Non-racy version of:
|
||||||
|
// if p.proc == nil {
|
||||||
|
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
if p.proc == nil {
|
||||||
|
e := p.l.Load()
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
proc, e := p.l.dll.FindProc(p.Name)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
// Non-racy version of:
|
||||||
|
// p.proc = proc
|
||||||
|
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// mustFind is like Find but panics if search fails.
|
||||||
|
func (p *LazyProc) mustFind() {
|
||||||
|
e := p.Find()
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Addr returns the address of the procedure represented by p.
|
||||||
|
// The return value can be passed to Syscall to run the procedure.
|
||||||
|
// It will panic if the procedure cannot be found.
|
||||||
|
func (p *LazyProc) Addr() uintptr {
|
||||||
|
p.mustFind()
|
||||||
|
return p.proc.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:uintptrescapes
|
||||||
|
|
||||||
|
// Call executes procedure p with arguments a. It will panic, if more than 15 arguments
|
||||||
|
// are supplied. It will also panic if the procedure cannot be found.
|
||||||
|
//
|
||||||
|
// The returned error is always non-nil, constructed from the result of GetLastError.
|
||||||
|
// Callers must inspect the primary return value to decide whether an error occurred
|
||||||
|
// (according to the semantics of the specific function being called) before consulting
|
||||||
|
// the error. The error will be guaranteed to contain windows.Errno.
|
||||||
|
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
|
||||||
|
p.mustFind()
|
||||||
|
return p.proc.Call(a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
var canDoSearchSystem32Once struct {
|
||||||
|
sync.Once
|
||||||
|
v bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func initCanDoSearchSystem32() {
|
||||||
|
// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
|
||||||
|
// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
|
||||||
|
// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
|
||||||
|
// systems that have KB2533623 installed. To determine whether the
|
||||||
|
// flags are available, use GetProcAddress to get the address of the
|
||||||
|
// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
|
||||||
|
// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
|
||||||
|
// flags can be used with LoadLibraryEx."
|
||||||
|
canDoSearchSystem32Once.v = (modkernel32.NewProc("AddDllDirectory").Find() == nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func canDoSearchSystem32() bool {
|
||||||
|
canDoSearchSystem32Once.Do(initCanDoSearchSystem32)
|
||||||
|
return canDoSearchSystem32Once.v
|
||||||
|
}
|
||||||
|
|
||||||
|
func isBaseName(name string) bool {
|
||||||
|
for _, c := range name {
|
||||||
|
if c == ':' || c == '/' || c == '\\' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadLibraryEx wraps the Windows LoadLibraryEx function.
|
||||||
|
//
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
|
||||||
|
//
|
||||||
|
// If name is not an absolute path, LoadLibraryEx searches for the DLL
|
||||||
|
// in a variety of automatic locations unless constrained by flags.
|
||||||
|
// See: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx
|
||||||
|
func loadLibraryEx(name string, system bool) (*DLL, error) {
|
||||||
|
loadDLL := name
|
||||||
|
var flags uintptr
|
||||||
|
if system {
|
||||||
|
if canDoSearchSystem32() {
|
||||||
|
flags = LOAD_LIBRARY_SEARCH_SYSTEM32
|
||||||
|
} else if isBaseName(name) {
|
||||||
|
// WindowsXP or unpatched Windows machine
|
||||||
|
// trying to load "foo.dll" out of the system
|
||||||
|
// folder, but LoadLibraryEx doesn't support
|
||||||
|
// that yet on their system, so emulate it.
|
||||||
|
systemdir, err := GetSystemDirectory()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
loadDLL = systemdir + "\\" + name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h, err := LoadLibraryEx(loadDLL, 0, flags)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &DLL{Name: name, Handle: h}, nil
|
||||||
|
}
|
||||||
57
vendor/golang.org/x/sys/windows/env_windows.go
generated
vendored
Normal file
57
vendor/golang.org/x/sys/windows/env_windows.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Windows environment variables.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Getenv(key string) (value string, found bool) {
|
||||||
|
return syscall.Getenv(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Setenv(key, value string) error {
|
||||||
|
return syscall.Setenv(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Clearenv() {
|
||||||
|
syscall.Clearenv()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Environ() []string {
|
||||||
|
return syscall.Environ()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a default environment associated with the token, rather than the current
|
||||||
|
// process. If inheritExisting is true, then this environment also inherits the
|
||||||
|
// environment of the current process.
|
||||||
|
func (token Token) Environ(inheritExisting bool) (env []string, err error) {
|
||||||
|
var block *uint16
|
||||||
|
err = CreateEnvironmentBlock(&block, token, inheritExisting)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer DestroyEnvironmentBlock(block)
|
||||||
|
size := unsafe.Sizeof(*block)
|
||||||
|
for *block != 0 {
|
||||||
|
// find NUL terminator
|
||||||
|
end := unsafe.Pointer(block)
|
||||||
|
for *(*uint16)(end) != 0 {
|
||||||
|
end = unsafe.Add(end, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
entry := unsafe.Slice(block, (uintptr(end)-uintptr(unsafe.Pointer(block)))/size)
|
||||||
|
env = append(env, UTF16ToString(entry))
|
||||||
|
block = (*uint16)(unsafe.Add(end, size))
|
||||||
|
}
|
||||||
|
return env, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Unsetenv(key string) error {
|
||||||
|
return syscall.Unsetenv(key)
|
||||||
|
}
|
||||||
20
vendor/golang.org/x/sys/windows/eventlog.go
generated
vendored
Normal file
20
vendor/golang.org/x/sys/windows/eventlog.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
const (
|
||||||
|
EVENTLOG_SUCCESS = 0
|
||||||
|
EVENTLOG_ERROR_TYPE = 1
|
||||||
|
EVENTLOG_WARNING_TYPE = 2
|
||||||
|
EVENTLOG_INFORMATION_TYPE = 4
|
||||||
|
EVENTLOG_AUDIT_SUCCESS = 8
|
||||||
|
EVENTLOG_AUDIT_FAILURE = 16
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) [failretval==0] = advapi32.RegisterEventSourceW
|
||||||
|
//sys DeregisterEventSource(handle Handle) (err error) = advapi32.DeregisterEventSource
|
||||||
|
//sys ReportEvent(log Handle, etype uint16, category uint16, eventId uint32, usrSId uintptr, numStrings uint16, dataSize uint32, strings **uint16, rawData *byte) (err error) = advapi32.ReportEventW
|
||||||
248
vendor/golang.org/x/sys/windows/exec_windows.go
generated
vendored
Normal file
248
vendor/golang.org/x/sys/windows/exec_windows.go
generated
vendored
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Fork, exec, wait, etc.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
errorspkg "errors"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EscapeArg rewrites command line argument s as prescribed
|
||||||
|
// in http://msdn.microsoft.com/en-us/library/ms880421.
|
||||||
|
// This function returns "" (2 double quotes) if s is empty.
|
||||||
|
// Alternatively, these transformations are done:
|
||||||
|
// - every back slash (\) is doubled, but only if immediately
|
||||||
|
// followed by double quote (");
|
||||||
|
// - every double quote (") is escaped by back slash (\);
|
||||||
|
// - finally, s is wrapped with double quotes (arg -> "arg"),
|
||||||
|
// but only if there is space or tab inside s.
|
||||||
|
func EscapeArg(s string) string {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return `""`
|
||||||
|
}
|
||||||
|
n := len(s)
|
||||||
|
hasSpace := false
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
switch s[i] {
|
||||||
|
case '"', '\\':
|
||||||
|
n++
|
||||||
|
case ' ', '\t':
|
||||||
|
hasSpace = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hasSpace {
|
||||||
|
n += 2 // Reserve space for quotes.
|
||||||
|
}
|
||||||
|
if n == len(s) {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
qs := make([]byte, n)
|
||||||
|
j := 0
|
||||||
|
if hasSpace {
|
||||||
|
qs[j] = '"'
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
slashes := 0
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
switch s[i] {
|
||||||
|
default:
|
||||||
|
slashes = 0
|
||||||
|
qs[j] = s[i]
|
||||||
|
case '\\':
|
||||||
|
slashes++
|
||||||
|
qs[j] = s[i]
|
||||||
|
case '"':
|
||||||
|
for ; slashes > 0; slashes-- {
|
||||||
|
qs[j] = '\\'
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
qs[j] = '\\'
|
||||||
|
j++
|
||||||
|
qs[j] = s[i]
|
||||||
|
}
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
if hasSpace {
|
||||||
|
for ; slashes > 0; slashes-- {
|
||||||
|
qs[j] = '\\'
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
qs[j] = '"'
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
return string(qs[:j])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComposeCommandLine escapes and joins the given arguments suitable for use as a Windows command line,
|
||||||
|
// in CreateProcess's CommandLine argument, CreateService/ChangeServiceConfig's BinaryPathName argument,
|
||||||
|
// or any program that uses CommandLineToArgv.
|
||||||
|
func ComposeCommandLine(args []string) string {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Per https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw:
|
||||||
|
// “This function accepts command lines that contain a program name; the
|
||||||
|
// program name can be enclosed in quotation marks or not.”
|
||||||
|
//
|
||||||
|
// Unfortunately, it provides no means of escaping interior quotation marks
|
||||||
|
// within that program name, and we have no way to report them here.
|
||||||
|
prog := args[0]
|
||||||
|
mustQuote := len(prog) == 0
|
||||||
|
for i := 0; i < len(prog); i++ {
|
||||||
|
c := prog[i]
|
||||||
|
if c <= ' ' || (c == '"' && i == 0) {
|
||||||
|
// Force quotes for not only the ASCII space and tab as described in the
|
||||||
|
// MSDN article, but also ASCII control characters.
|
||||||
|
// The documentation for CommandLineToArgvW doesn't say what happens when
|
||||||
|
// the first argument is not a valid program name, but it empirically
|
||||||
|
// seems to drop unquoted control characters.
|
||||||
|
mustQuote = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var commandLine []byte
|
||||||
|
if mustQuote {
|
||||||
|
commandLine = make([]byte, 0, len(prog)+2)
|
||||||
|
commandLine = append(commandLine, '"')
|
||||||
|
for i := 0; i < len(prog); i++ {
|
||||||
|
c := prog[i]
|
||||||
|
if c == '"' {
|
||||||
|
// This quote would interfere with our surrounding quotes.
|
||||||
|
// We have no way to report an error, so just strip out
|
||||||
|
// the offending character instead.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
commandLine = append(commandLine, c)
|
||||||
|
}
|
||||||
|
commandLine = append(commandLine, '"')
|
||||||
|
} else {
|
||||||
|
if len(args) == 1 {
|
||||||
|
// args[0] is a valid command line representing itself.
|
||||||
|
// No need to allocate a new slice or string for it.
|
||||||
|
return prog
|
||||||
|
}
|
||||||
|
commandLine = []byte(prog)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, arg := range args[1:] {
|
||||||
|
commandLine = append(commandLine, ' ')
|
||||||
|
// TODO(bcmills): since we're already appending to a slice, it would be nice
|
||||||
|
// to avoid the intermediate allocations of EscapeArg.
|
||||||
|
// Perhaps we can factor out an appendEscapedArg function.
|
||||||
|
commandLine = append(commandLine, EscapeArg(arg)...)
|
||||||
|
}
|
||||||
|
return string(commandLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecomposeCommandLine breaks apart its argument command line into unescaped parts using CommandLineToArgv,
|
||||||
|
// as gathered from GetCommandLine, QUERY_SERVICE_CONFIG's BinaryPathName argument, or elsewhere that
|
||||||
|
// command lines are passed around.
|
||||||
|
// DecomposeCommandLine returns an error if commandLine contains NUL.
|
||||||
|
func DecomposeCommandLine(commandLine string) ([]string, error) {
|
||||||
|
if len(commandLine) == 0 {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
utf16CommandLine, err := UTF16FromString(commandLine)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errorspkg.New("string with NUL passed to DecomposeCommandLine")
|
||||||
|
}
|
||||||
|
var argc int32
|
||||||
|
argv, err := commandLineToArgv(&utf16CommandLine[0], &argc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer LocalFree(Handle(unsafe.Pointer(argv)))
|
||||||
|
|
||||||
|
var args []string
|
||||||
|
for _, p := range unsafe.Slice(argv, argc) {
|
||||||
|
args = append(args, UTF16PtrToString(p))
|
||||||
|
}
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandLineToArgv parses a Unicode command line string and sets
|
||||||
|
// argc to the number of parsed arguments.
|
||||||
|
//
|
||||||
|
// The returned memory should be freed using a single call to LocalFree.
|
||||||
|
//
|
||||||
|
// Note that although the return type of CommandLineToArgv indicates 8192
|
||||||
|
// entries of up to 8192 characters each, the actual count of parsed arguments
|
||||||
|
// may exceed 8192, and the documentation for CommandLineToArgvW does not mention
|
||||||
|
// any bound on the lengths of the individual argument strings.
|
||||||
|
// (See https://go.dev/issue/63236.)
|
||||||
|
func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) {
|
||||||
|
argp, err := commandLineToArgv(cmd, argc)
|
||||||
|
argv = (*[8192]*[8192]uint16)(unsafe.Pointer(argp))
|
||||||
|
return argv, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func CloseOnExec(fd Handle) {
|
||||||
|
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FullPath retrieves the full path of the specified file.
|
||||||
|
func FullPath(name string) (path string, err error) {
|
||||||
|
p, err := UTF16PtrFromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
n := uint32(100)
|
||||||
|
for {
|
||||||
|
buf := make([]uint16, n)
|
||||||
|
n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if n <= uint32(len(buf)) {
|
||||||
|
return UTF16ToString(buf[:n]), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProcThreadAttributeList allocates a new ProcThreadAttributeListContainer, with the requested maximum number of attributes.
|
||||||
|
func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeListContainer, error) {
|
||||||
|
var size uintptr
|
||||||
|
err := initializeProcThreadAttributeList(nil, maxAttrCount, 0, &size)
|
||||||
|
if err != ERROR_INSUFFICIENT_BUFFER {
|
||||||
|
if err == nil {
|
||||||
|
return nil, errorspkg.New("unable to query buffer size from InitializeProcThreadAttributeList")
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
alloc, err := LocalAlloc(LMEM_FIXED, uint32(size))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// size is guaranteed to be ≥1 by InitializeProcThreadAttributeList.
|
||||||
|
al := &ProcThreadAttributeListContainer{data: (*ProcThreadAttributeList)(unsafe.Pointer(alloc))}
|
||||||
|
err = initializeProcThreadAttributeList(al.data, maxAttrCount, 0, &size)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return al, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update modifies the ProcThreadAttributeList using UpdateProcThreadAttribute.
|
||||||
|
func (al *ProcThreadAttributeListContainer) Update(attribute uintptr, value unsafe.Pointer, size uintptr) error {
|
||||||
|
al.pointers = append(al.pointers, value)
|
||||||
|
return updateProcThreadAttribute(al.data, 0, attribute, value, size, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete frees ProcThreadAttributeList's resources.
|
||||||
|
func (al *ProcThreadAttributeListContainer) Delete() {
|
||||||
|
deleteProcThreadAttributeList(al.data)
|
||||||
|
LocalFree(Handle(unsafe.Pointer(al.data)))
|
||||||
|
al.data = nil
|
||||||
|
al.pointers = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns the actual ProcThreadAttributeList to be passed to StartupInfoEx.
|
||||||
|
func (al *ProcThreadAttributeListContainer) List() *ProcThreadAttributeList {
|
||||||
|
return al.data
|
||||||
|
}
|
||||||
48
vendor/golang.org/x/sys/windows/memory_windows.go
generated
vendored
Normal file
48
vendor/golang.org/x/sys/windows/memory_windows.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
const (
|
||||||
|
MEM_COMMIT = 0x00001000
|
||||||
|
MEM_RESERVE = 0x00002000
|
||||||
|
MEM_DECOMMIT = 0x00004000
|
||||||
|
MEM_RELEASE = 0x00008000
|
||||||
|
MEM_RESET = 0x00080000
|
||||||
|
MEM_TOP_DOWN = 0x00100000
|
||||||
|
MEM_WRITE_WATCH = 0x00200000
|
||||||
|
MEM_PHYSICAL = 0x00400000
|
||||||
|
MEM_RESET_UNDO = 0x01000000
|
||||||
|
MEM_LARGE_PAGES = 0x20000000
|
||||||
|
|
||||||
|
PAGE_NOACCESS = 0x00000001
|
||||||
|
PAGE_READONLY = 0x00000002
|
||||||
|
PAGE_READWRITE = 0x00000004
|
||||||
|
PAGE_WRITECOPY = 0x00000008
|
||||||
|
PAGE_EXECUTE = 0x00000010
|
||||||
|
PAGE_EXECUTE_READ = 0x00000020
|
||||||
|
PAGE_EXECUTE_READWRITE = 0x00000040
|
||||||
|
PAGE_EXECUTE_WRITECOPY = 0x00000080
|
||||||
|
PAGE_GUARD = 0x00000100
|
||||||
|
PAGE_NOCACHE = 0x00000200
|
||||||
|
PAGE_WRITECOMBINE = 0x00000400
|
||||||
|
PAGE_TARGETS_INVALID = 0x40000000
|
||||||
|
PAGE_TARGETS_NO_UPDATE = 0x40000000
|
||||||
|
|
||||||
|
QUOTA_LIMITS_HARDWS_MIN_DISABLE = 0x00000002
|
||||||
|
QUOTA_LIMITS_HARDWS_MIN_ENABLE = 0x00000001
|
||||||
|
QUOTA_LIMITS_HARDWS_MAX_DISABLE = 0x00000008
|
||||||
|
QUOTA_LIMITS_HARDWS_MAX_ENABLE = 0x00000004
|
||||||
|
)
|
||||||
|
|
||||||
|
type MemoryBasicInformation struct {
|
||||||
|
BaseAddress uintptr
|
||||||
|
AllocationBase uintptr
|
||||||
|
AllocationProtect uint32
|
||||||
|
PartitionId uint16
|
||||||
|
RegionSize uintptr
|
||||||
|
State uint32
|
||||||
|
Protect uint32
|
||||||
|
Type uint32
|
||||||
|
}
|
||||||
70
vendor/golang.org/x/sys/windows/mkerrors.bash
generated
vendored
Normal file
70
vendor/golang.org/x/sys/windows/mkerrors.bash
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
|
winerror="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/shared/winerror.h | sort -Vr | head -n 1)"
|
||||||
|
[[ -n $winerror ]] || { echo "Unable to find winerror.h" >&2; exit 1; }
|
||||||
|
ntstatus="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/shared/ntstatus.h | sort -Vr | head -n 1)"
|
||||||
|
[[ -n $ntstatus ]] || { echo "Unable to find ntstatus.h" >&2; exit 1; }
|
||||||
|
|
||||||
|
declare -A errors
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "// Code generated by 'mkerrors.bash'; DO NOT EDIT."
|
||||||
|
echo
|
||||||
|
echo "package windows"
|
||||||
|
echo "import \"syscall\""
|
||||||
|
echo "const ("
|
||||||
|
|
||||||
|
while read -r line; do
|
||||||
|
unset vtype
|
||||||
|
if [[ $line =~ ^#define\ +([A-Z0-9_]+k?)\ +([A-Z0-9_]+\()?([A-Z][A-Z0-9_]+k?)\)? ]]; then
|
||||||
|
key="${BASH_REMATCH[1]}"
|
||||||
|
value="${BASH_REMATCH[3]}"
|
||||||
|
elif [[ $line =~ ^#define\ +([A-Z0-9_]+k?)\ +([A-Z0-9_]+\()?((0x)?[0-9A-Fa-f]+)L?\)? ]]; then
|
||||||
|
key="${BASH_REMATCH[1]}"
|
||||||
|
value="${BASH_REMATCH[3]}"
|
||||||
|
vtype="${BASH_REMATCH[2]}"
|
||||||
|
elif [[ $line =~ ^#define\ +([A-Z0-9_]+k?)\ +\(\(([A-Z]+)\)((0x)?[0-9A-Fa-f]+)L?\) ]]; then
|
||||||
|
key="${BASH_REMATCH[1]}"
|
||||||
|
value="${BASH_REMATCH[3]}"
|
||||||
|
vtype="${BASH_REMATCH[2]}"
|
||||||
|
else
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
[[ -n $key && -n $value ]] || continue
|
||||||
|
[[ -z ${errors["$key"]} ]] || continue
|
||||||
|
errors["$key"]="$value"
|
||||||
|
if [[ -v vtype ]]; then
|
||||||
|
if [[ $key == FACILITY_* || $key == NO_ERROR ]]; then
|
||||||
|
vtype=""
|
||||||
|
elif [[ $vtype == *HANDLE* || $vtype == *HRESULT* ]]; then
|
||||||
|
vtype="Handle"
|
||||||
|
else
|
||||||
|
vtype="syscall.Errno"
|
||||||
|
fi
|
||||||
|
last_vtype="$vtype"
|
||||||
|
else
|
||||||
|
vtype=""
|
||||||
|
if [[ $last_vtype == Handle && $value == NO_ERROR ]]; then
|
||||||
|
value="S_OK"
|
||||||
|
elif [[ $last_vtype == syscall.Errno && $value == NO_ERROR ]]; then
|
||||||
|
value="ERROR_SUCCESS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$key $vtype = $value"
|
||||||
|
done < "$winerror"
|
||||||
|
|
||||||
|
while read -r line; do
|
||||||
|
[[ $line =~ ^#define\ (STATUS_[^\s]+)\ +\(\(NTSTATUS\)((0x)?[0-9a-fA-F]+)L?\) ]] || continue
|
||||||
|
echo "${BASH_REMATCH[1]} NTStatus = ${BASH_REMATCH[2]}"
|
||||||
|
done < "$ntstatus"
|
||||||
|
|
||||||
|
echo ")"
|
||||||
|
} | gofmt > "zerrors_windows.go"
|
||||||
27
vendor/golang.org/x/sys/windows/mkknownfolderids.bash
generated
vendored
Normal file
27
vendor/golang.org/x/sys/windows/mkknownfolderids.bash
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
|
knownfolders="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/um/KnownFolders.h | sort -Vr | head -n 1)"
|
||||||
|
[[ -n $knownfolders ]] || { echo "Unable to find KnownFolders.h" >&2; exit 1; }
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "// Code generated by 'mkknownfolderids.bash'; DO NOT EDIT."
|
||||||
|
echo
|
||||||
|
echo "package windows"
|
||||||
|
echo "type KNOWNFOLDERID GUID"
|
||||||
|
echo "var ("
|
||||||
|
while read -r line; do
|
||||||
|
[[ $line =~ DEFINE_KNOWN_FOLDER\((FOLDERID_[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+)\) ]] || continue
|
||||||
|
printf "%s = &KNOWNFOLDERID{0x%08x, 0x%04x, 0x%04x, [8]byte{0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}}\n" \
|
||||||
|
"${BASH_REMATCH[1]}" $(( "${BASH_REMATCH[2]}" )) $(( "${BASH_REMATCH[3]}" )) $(( "${BASH_REMATCH[4]}" )) \
|
||||||
|
$(( "${BASH_REMATCH[5]}" )) $(( "${BASH_REMATCH[6]}" )) $(( "${BASH_REMATCH[7]}" )) $(( "${BASH_REMATCH[8]}" )) \
|
||||||
|
$(( "${BASH_REMATCH[9]}" )) $(( "${BASH_REMATCH[10]}" )) $(( "${BASH_REMATCH[11]}" )) $(( "${BASH_REMATCH[12]}" ))
|
||||||
|
done < "$knownfolders"
|
||||||
|
echo ")"
|
||||||
|
} | gofmt > "zknownfolderids_windows.go"
|
||||||
9
vendor/golang.org/x/sys/windows/mksyscall.go
generated
vendored
Normal file
9
vendor/golang.org/x/sys/windows/mksyscall.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build generate
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go setupapi_windows.go
|
||||||
30
vendor/golang.org/x/sys/windows/race.go
generated
vendored
Normal file
30
vendor/golang.org/x/sys/windows/race.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build windows && race
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const raceenabled = true
|
||||||
|
|
||||||
|
func raceAcquire(addr unsafe.Pointer) {
|
||||||
|
runtime.RaceAcquire(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func raceReleaseMerge(addr unsafe.Pointer) {
|
||||||
|
runtime.RaceReleaseMerge(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func raceReadRange(addr unsafe.Pointer, len int) {
|
||||||
|
runtime.RaceReadRange(addr, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
func raceWriteRange(addr unsafe.Pointer, len int) {
|
||||||
|
runtime.RaceWriteRange(addr, len)
|
||||||
|
}
|
||||||
25
vendor/golang.org/x/sys/windows/race0.go
generated
vendored
Normal file
25
vendor/golang.org/x/sys/windows/race0.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build windows && !race
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const raceenabled = false
|
||||||
|
|
||||||
|
func raceAcquire(addr unsafe.Pointer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func raceReleaseMerge(addr unsafe.Pointer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func raceReadRange(addr unsafe.Pointer, len int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func raceWriteRange(addr unsafe.Pointer, len int) {
|
||||||
|
}
|
||||||
1497
vendor/golang.org/x/sys/windows/security_windows.go
generated
vendored
Normal file
1497
vendor/golang.org/x/sys/windows/security_windows.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
257
vendor/golang.org/x/sys/windows/service.go
generated
vendored
Normal file
257
vendor/golang.org/x/sys/windows/service.go
generated
vendored
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
const (
|
||||||
|
SC_MANAGER_CONNECT = 1
|
||||||
|
SC_MANAGER_CREATE_SERVICE = 2
|
||||||
|
SC_MANAGER_ENUMERATE_SERVICE = 4
|
||||||
|
SC_MANAGER_LOCK = 8
|
||||||
|
SC_MANAGER_QUERY_LOCK_STATUS = 16
|
||||||
|
SC_MANAGER_MODIFY_BOOT_CONFIG = 32
|
||||||
|
SC_MANAGER_ALL_ACCESS = 0xf003f
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SERVICE_KERNEL_DRIVER = 1
|
||||||
|
SERVICE_FILE_SYSTEM_DRIVER = 2
|
||||||
|
SERVICE_ADAPTER = 4
|
||||||
|
SERVICE_RECOGNIZER_DRIVER = 8
|
||||||
|
SERVICE_WIN32_OWN_PROCESS = 16
|
||||||
|
SERVICE_WIN32_SHARE_PROCESS = 32
|
||||||
|
SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS
|
||||||
|
SERVICE_INTERACTIVE_PROCESS = 256
|
||||||
|
SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER
|
||||||
|
SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS
|
||||||
|
|
||||||
|
SERVICE_BOOT_START = 0
|
||||||
|
SERVICE_SYSTEM_START = 1
|
||||||
|
SERVICE_AUTO_START = 2
|
||||||
|
SERVICE_DEMAND_START = 3
|
||||||
|
SERVICE_DISABLED = 4
|
||||||
|
|
||||||
|
SERVICE_ERROR_IGNORE = 0
|
||||||
|
SERVICE_ERROR_NORMAL = 1
|
||||||
|
SERVICE_ERROR_SEVERE = 2
|
||||||
|
SERVICE_ERROR_CRITICAL = 3
|
||||||
|
|
||||||
|
SC_STATUS_PROCESS_INFO = 0
|
||||||
|
|
||||||
|
SC_ACTION_NONE = 0
|
||||||
|
SC_ACTION_RESTART = 1
|
||||||
|
SC_ACTION_REBOOT = 2
|
||||||
|
SC_ACTION_RUN_COMMAND = 3
|
||||||
|
|
||||||
|
SERVICE_STOPPED = 1
|
||||||
|
SERVICE_START_PENDING = 2
|
||||||
|
SERVICE_STOP_PENDING = 3
|
||||||
|
SERVICE_RUNNING = 4
|
||||||
|
SERVICE_CONTINUE_PENDING = 5
|
||||||
|
SERVICE_PAUSE_PENDING = 6
|
||||||
|
SERVICE_PAUSED = 7
|
||||||
|
SERVICE_NO_CHANGE = 0xffffffff
|
||||||
|
|
||||||
|
SERVICE_ACCEPT_STOP = 1
|
||||||
|
SERVICE_ACCEPT_PAUSE_CONTINUE = 2
|
||||||
|
SERVICE_ACCEPT_SHUTDOWN = 4
|
||||||
|
SERVICE_ACCEPT_PARAMCHANGE = 8
|
||||||
|
SERVICE_ACCEPT_NETBINDCHANGE = 16
|
||||||
|
SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 32
|
||||||
|
SERVICE_ACCEPT_POWEREVENT = 64
|
||||||
|
SERVICE_ACCEPT_SESSIONCHANGE = 128
|
||||||
|
SERVICE_ACCEPT_PRESHUTDOWN = 256
|
||||||
|
|
||||||
|
SERVICE_CONTROL_STOP = 1
|
||||||
|
SERVICE_CONTROL_PAUSE = 2
|
||||||
|
SERVICE_CONTROL_CONTINUE = 3
|
||||||
|
SERVICE_CONTROL_INTERROGATE = 4
|
||||||
|
SERVICE_CONTROL_SHUTDOWN = 5
|
||||||
|
SERVICE_CONTROL_PARAMCHANGE = 6
|
||||||
|
SERVICE_CONTROL_NETBINDADD = 7
|
||||||
|
SERVICE_CONTROL_NETBINDREMOVE = 8
|
||||||
|
SERVICE_CONTROL_NETBINDENABLE = 9
|
||||||
|
SERVICE_CONTROL_NETBINDDISABLE = 10
|
||||||
|
SERVICE_CONTROL_DEVICEEVENT = 11
|
||||||
|
SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12
|
||||||
|
SERVICE_CONTROL_POWEREVENT = 13
|
||||||
|
SERVICE_CONTROL_SESSIONCHANGE = 14
|
||||||
|
SERVICE_CONTROL_PRESHUTDOWN = 15
|
||||||
|
|
||||||
|
SERVICE_ACTIVE = 1
|
||||||
|
SERVICE_INACTIVE = 2
|
||||||
|
SERVICE_STATE_ALL = 3
|
||||||
|
|
||||||
|
SERVICE_QUERY_CONFIG = 1
|
||||||
|
SERVICE_CHANGE_CONFIG = 2
|
||||||
|
SERVICE_QUERY_STATUS = 4
|
||||||
|
SERVICE_ENUMERATE_DEPENDENTS = 8
|
||||||
|
SERVICE_START = 16
|
||||||
|
SERVICE_STOP = 32
|
||||||
|
SERVICE_PAUSE_CONTINUE = 64
|
||||||
|
SERVICE_INTERROGATE = 128
|
||||||
|
SERVICE_USER_DEFINED_CONTROL = 256
|
||||||
|
SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL
|
||||||
|
|
||||||
|
SERVICE_RUNS_IN_SYSTEM_PROCESS = 1
|
||||||
|
|
||||||
|
SERVICE_CONFIG_DESCRIPTION = 1
|
||||||
|
SERVICE_CONFIG_FAILURE_ACTIONS = 2
|
||||||
|
SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3
|
||||||
|
SERVICE_CONFIG_FAILURE_ACTIONS_FLAG = 4
|
||||||
|
SERVICE_CONFIG_SERVICE_SID_INFO = 5
|
||||||
|
SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO = 6
|
||||||
|
SERVICE_CONFIG_PRESHUTDOWN_INFO = 7
|
||||||
|
SERVICE_CONFIG_TRIGGER_INFO = 8
|
||||||
|
SERVICE_CONFIG_PREFERRED_NODE = 9
|
||||||
|
SERVICE_CONFIG_LAUNCH_PROTECTED = 12
|
||||||
|
|
||||||
|
SERVICE_SID_TYPE_NONE = 0
|
||||||
|
SERVICE_SID_TYPE_UNRESTRICTED = 1
|
||||||
|
SERVICE_SID_TYPE_RESTRICTED = 2 | SERVICE_SID_TYPE_UNRESTRICTED
|
||||||
|
|
||||||
|
SC_ENUM_PROCESS_INFO = 0
|
||||||
|
|
||||||
|
SERVICE_NOTIFY_STATUS_CHANGE = 2
|
||||||
|
SERVICE_NOTIFY_STOPPED = 0x00000001
|
||||||
|
SERVICE_NOTIFY_START_PENDING = 0x00000002
|
||||||
|
SERVICE_NOTIFY_STOP_PENDING = 0x00000004
|
||||||
|
SERVICE_NOTIFY_RUNNING = 0x00000008
|
||||||
|
SERVICE_NOTIFY_CONTINUE_PENDING = 0x00000010
|
||||||
|
SERVICE_NOTIFY_PAUSE_PENDING = 0x00000020
|
||||||
|
SERVICE_NOTIFY_PAUSED = 0x00000040
|
||||||
|
SERVICE_NOTIFY_CREATED = 0x00000080
|
||||||
|
SERVICE_NOTIFY_DELETED = 0x00000100
|
||||||
|
SERVICE_NOTIFY_DELETE_PENDING = 0x00000200
|
||||||
|
|
||||||
|
SC_EVENT_DATABASE_CHANGE = 0
|
||||||
|
SC_EVENT_PROPERTY_CHANGE = 1
|
||||||
|
SC_EVENT_STATUS_CHANGE = 2
|
||||||
|
|
||||||
|
SERVICE_START_REASON_DEMAND = 0x00000001
|
||||||
|
SERVICE_START_REASON_AUTO = 0x00000002
|
||||||
|
SERVICE_START_REASON_TRIGGER = 0x00000004
|
||||||
|
SERVICE_START_REASON_RESTART_ON_FAILURE = 0x00000008
|
||||||
|
SERVICE_START_REASON_DELAYEDAUTO = 0x00000010
|
||||||
|
|
||||||
|
SERVICE_DYNAMIC_INFORMATION_LEVEL_START_REASON = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
type ENUM_SERVICE_STATUS struct {
|
||||||
|
ServiceName *uint16
|
||||||
|
DisplayName *uint16
|
||||||
|
ServiceStatus SERVICE_STATUS
|
||||||
|
}
|
||||||
|
|
||||||
|
type SERVICE_STATUS struct {
|
||||||
|
ServiceType uint32
|
||||||
|
CurrentState uint32
|
||||||
|
ControlsAccepted uint32
|
||||||
|
Win32ExitCode uint32
|
||||||
|
ServiceSpecificExitCode uint32
|
||||||
|
CheckPoint uint32
|
||||||
|
WaitHint uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type SERVICE_TABLE_ENTRY struct {
|
||||||
|
ServiceName *uint16
|
||||||
|
ServiceProc uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
type QUERY_SERVICE_CONFIG struct {
|
||||||
|
ServiceType uint32
|
||||||
|
StartType uint32
|
||||||
|
ErrorControl uint32
|
||||||
|
BinaryPathName *uint16
|
||||||
|
LoadOrderGroup *uint16
|
||||||
|
TagId uint32
|
||||||
|
Dependencies *uint16
|
||||||
|
ServiceStartName *uint16
|
||||||
|
DisplayName *uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type SERVICE_DESCRIPTION struct {
|
||||||
|
Description *uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type SERVICE_DELAYED_AUTO_START_INFO struct {
|
||||||
|
IsDelayedAutoStartUp uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type SERVICE_STATUS_PROCESS struct {
|
||||||
|
ServiceType uint32
|
||||||
|
CurrentState uint32
|
||||||
|
ControlsAccepted uint32
|
||||||
|
Win32ExitCode uint32
|
||||||
|
ServiceSpecificExitCode uint32
|
||||||
|
CheckPoint uint32
|
||||||
|
WaitHint uint32
|
||||||
|
ProcessId uint32
|
||||||
|
ServiceFlags uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type ENUM_SERVICE_STATUS_PROCESS struct {
|
||||||
|
ServiceName *uint16
|
||||||
|
DisplayName *uint16
|
||||||
|
ServiceStatusProcess SERVICE_STATUS_PROCESS
|
||||||
|
}
|
||||||
|
|
||||||
|
type SERVICE_NOTIFY struct {
|
||||||
|
Version uint32
|
||||||
|
NotifyCallback uintptr
|
||||||
|
Context uintptr
|
||||||
|
NotificationStatus uint32
|
||||||
|
ServiceStatus SERVICE_STATUS_PROCESS
|
||||||
|
NotificationTriggered uint32
|
||||||
|
ServiceNames *uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type SERVICE_FAILURE_ACTIONS struct {
|
||||||
|
ResetPeriod uint32
|
||||||
|
RebootMsg *uint16
|
||||||
|
Command *uint16
|
||||||
|
ActionsCount uint32
|
||||||
|
Actions *SC_ACTION
|
||||||
|
}
|
||||||
|
|
||||||
|
type SERVICE_FAILURE_ACTIONS_FLAG struct {
|
||||||
|
FailureActionsOnNonCrashFailures int32
|
||||||
|
}
|
||||||
|
|
||||||
|
type SC_ACTION struct {
|
||||||
|
Type uint32
|
||||||
|
Delay uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type QUERY_SERVICE_LOCK_STATUS struct {
|
||||||
|
IsLocked uint32
|
||||||
|
LockOwner *uint16
|
||||||
|
LockDuration uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenSCManagerW
|
||||||
|
//sys CloseServiceHandle(handle Handle) (err error) = advapi32.CloseServiceHandle
|
||||||
|
//sys CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) [failretval==0] = advapi32.CreateServiceW
|
||||||
|
//sys OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenServiceW
|
||||||
|
//sys DeleteService(service Handle) (err error) = advapi32.DeleteService
|
||||||
|
//sys StartService(service Handle, numArgs uint32, argVectors **uint16) (err error) = advapi32.StartServiceW
|
||||||
|
//sys QueryServiceStatus(service Handle, status *SERVICE_STATUS) (err error) = advapi32.QueryServiceStatus
|
||||||
|
//sys QueryServiceLockStatus(mgr Handle, lockStatus *QUERY_SERVICE_LOCK_STATUS, bufSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceLockStatusW
|
||||||
|
//sys ControlService(service Handle, control uint32, status *SERVICE_STATUS) (err error) = advapi32.ControlService
|
||||||
|
//sys StartServiceCtrlDispatcher(serviceTable *SERVICE_TABLE_ENTRY) (err error) = advapi32.StartServiceCtrlDispatcherW
|
||||||
|
//sys SetServiceStatus(service Handle, serviceStatus *SERVICE_STATUS) (err error) = advapi32.SetServiceStatus
|
||||||
|
//sys ChangeServiceConfig(service Handle, serviceType uint32, startType uint32, errorControl uint32, binaryPathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16, displayName *uint16) (err error) = advapi32.ChangeServiceConfigW
|
||||||
|
//sys QueryServiceConfig(service Handle, serviceConfig *QUERY_SERVICE_CONFIG, bufSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfigW
|
||||||
|
//sys ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) = advapi32.ChangeServiceConfig2W
|
||||||
|
//sys QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfig2W
|
||||||
|
//sys EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serviceState uint32, services *byte, bufSize uint32, bytesNeeded *uint32, servicesReturned *uint32, resumeHandle *uint32, groupName *uint16) (err error) = advapi32.EnumServicesStatusExW
|
||||||
|
//sys QueryServiceStatusEx(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceStatusEx
|
||||||
|
//sys NotifyServiceStatusChange(service Handle, notifyMask uint32, notifier *SERVICE_NOTIFY) (ret error) = advapi32.NotifyServiceStatusChangeW
|
||||||
|
//sys SubscribeServiceChangeNotifications(service Handle, eventType uint32, callback uintptr, callbackCtx uintptr, subscription *uintptr) (ret error) = sechost.SubscribeServiceChangeNotifications?
|
||||||
|
//sys UnsubscribeServiceChangeNotifications(subscription uintptr) = sechost.UnsubscribeServiceChangeNotifications?
|
||||||
|
//sys RegisterServiceCtrlHandlerEx(serviceName *uint16, handlerProc uintptr, context uintptr) (handle Handle, err error) = advapi32.RegisterServiceCtrlHandlerExW
|
||||||
|
//sys QueryServiceDynamicInformation(service Handle, infoLevel uint32, dynamicInfo unsafe.Pointer) (err error) = advapi32.QueryServiceDynamicInformation?
|
||||||
|
//sys EnumDependentServices(service Handle, activityState uint32, services *ENUM_SERVICE_STATUS, buffSize uint32, bytesNeeded *uint32, servicesReturned *uint32) (err error) = advapi32.EnumDependentServicesW
|
||||||
1425
vendor/golang.org/x/sys/windows/setupapi_windows.go
generated
vendored
Normal file
1425
vendor/golang.org/x/sys/windows/setupapi_windows.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
22
vendor/golang.org/x/sys/windows/str.go
generated
vendored
Normal file
22
vendor/golang.org/x/sys/windows/str.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
|
||||||
|
if val < 0 {
|
||||||
|
return "-" + itoa(-val)
|
||||||
|
}
|
||||||
|
var buf [32]byte // big enough for int64
|
||||||
|
i := len(buf) - 1
|
||||||
|
for val >= 10 {
|
||||||
|
buf[i] = byte(val%10 + '0')
|
||||||
|
i--
|
||||||
|
val /= 10
|
||||||
|
}
|
||||||
|
buf[i] = byte(val + '0')
|
||||||
|
return string(buf[i:])
|
||||||
|
}
|
||||||
104
vendor/golang.org/x/sys/windows/syscall.go
generated
vendored
Normal file
104
vendor/golang.org/x/sys/windows/syscall.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
// Package windows contains an interface to the low-level operating system
|
||||||
|
// primitives. OS details vary depending on the underlying system, and
|
||||||
|
// by default, godoc will display the OS-specific documentation for the current
|
||||||
|
// system. If you want godoc to display syscall documentation for another
|
||||||
|
// system, set $GOOS and $GOARCH to the desired system. For example, if
|
||||||
|
// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
|
||||||
|
// to freebsd and $GOARCH to arm.
|
||||||
|
//
|
||||||
|
// The primary use of this package is inside other packages that provide a more
|
||||||
|
// portable interface to the system, such as "os", "time" and "net". Use
|
||||||
|
// those packages rather than this one if you can.
|
||||||
|
//
|
||||||
|
// For details of the functions and data types in this package consult
|
||||||
|
// the manuals for the appropriate operating system.
|
||||||
|
//
|
||||||
|
// These calls return err == nil to indicate success; otherwise
|
||||||
|
// err represents an operating system error describing the failure and
|
||||||
|
// holds a value of type syscall.Errno.
|
||||||
|
package windows // import "golang.org/x/sys/windows"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ByteSliceFromString returns a NUL-terminated slice of bytes
|
||||||
|
// containing the text of s. If s contains a NUL byte at any
|
||||||
|
// location, it returns (nil, syscall.EINVAL).
|
||||||
|
func ByteSliceFromString(s string) ([]byte, error) {
|
||||||
|
if strings.IndexByte(s, 0) != -1 {
|
||||||
|
return nil, syscall.EINVAL
|
||||||
|
}
|
||||||
|
a := make([]byte, len(s)+1)
|
||||||
|
copy(a, s)
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytePtrFromString returns a pointer to a NUL-terminated array of
|
||||||
|
// bytes containing the text of s. If s contains a NUL byte at any
|
||||||
|
// location, it returns (nil, syscall.EINVAL).
|
||||||
|
func BytePtrFromString(s string) (*byte, error) {
|
||||||
|
a, err := ByteSliceFromString(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &a[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByteSliceToString returns a string form of the text represented by the slice s, with a terminating NUL and any
|
||||||
|
// bytes after the NUL removed.
|
||||||
|
func ByteSliceToString(s []byte) string {
|
||||||
|
if i := bytes.IndexByte(s, 0); i != -1 {
|
||||||
|
s = s[:i]
|
||||||
|
}
|
||||||
|
return string(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytePtrToString takes a pointer to a sequence of text and returns the corresponding string.
|
||||||
|
// If the pointer is nil, it returns the empty string. It assumes that the text sequence is terminated
|
||||||
|
// at a zero byte; if the zero byte is not present, the program may crash.
|
||||||
|
func BytePtrToString(p *byte) string {
|
||||||
|
if p == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if *p == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find NUL terminator.
|
||||||
|
n := 0
|
||||||
|
for ptr := unsafe.Pointer(p); *(*byte)(ptr) != 0; n++ {
|
||||||
|
ptr = unsafe.Pointer(uintptr(ptr) + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(unsafe.Slice(p, n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single-word zero for use when we need a valid pointer to 0 bytes.
|
||||||
|
// See mksyscall.pl.
|
||||||
|
var _zero uintptr
|
||||||
|
|
||||||
|
func (ts *Timespec) Unix() (sec int64, nsec int64) {
|
||||||
|
return int64(ts.Sec), int64(ts.Nsec)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tv *Timeval) Unix() (sec int64, nsec int64) {
|
||||||
|
return int64(tv.Sec), int64(tv.Usec) * 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *Timespec) Nano() int64 {
|
||||||
|
return int64(ts.Sec)*1e9 + int64(ts.Nsec)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tv *Timeval) Nano() int64 {
|
||||||
|
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
|
||||||
|
}
|
||||||
1951
vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
Normal file
1951
vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3940
vendor/golang.org/x/sys/windows/types_windows.go
generated
vendored
Normal file
3940
vendor/golang.org/x/sys/windows/types_windows.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
35
vendor/golang.org/x/sys/windows/types_windows_386.go
generated
vendored
Normal file
35
vendor/golang.org/x/sys/windows/types_windows_386.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
type WSAData struct {
|
||||||
|
Version uint16
|
||||||
|
HighVersion uint16
|
||||||
|
Description [WSADESCRIPTION_LEN + 1]byte
|
||||||
|
SystemStatus [WSASYS_STATUS_LEN + 1]byte
|
||||||
|
MaxSockets uint16
|
||||||
|
MaxUdpDg uint16
|
||||||
|
VendorInfo *byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type Servent struct {
|
||||||
|
Name *byte
|
||||||
|
Aliases **byte
|
||||||
|
Port uint16
|
||||||
|
Proto *byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type JOBOBJECT_BASIC_LIMIT_INFORMATION struct {
|
||||||
|
PerProcessUserTimeLimit int64
|
||||||
|
PerJobUserTimeLimit int64
|
||||||
|
LimitFlags uint32
|
||||||
|
MinimumWorkingSetSize uintptr
|
||||||
|
MaximumWorkingSetSize uintptr
|
||||||
|
ActiveProcessLimit uint32
|
||||||
|
Affinity uintptr
|
||||||
|
PriorityClass uint32
|
||||||
|
SchedulingClass uint32
|
||||||
|
_ uint32 // pad to 8 byte boundary
|
||||||
|
}
|
||||||
34
vendor/golang.org/x/sys/windows/types_windows_amd64.go
generated
vendored
Normal file
34
vendor/golang.org/x/sys/windows/types_windows_amd64.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
type WSAData struct {
|
||||||
|
Version uint16
|
||||||
|
HighVersion uint16
|
||||||
|
MaxSockets uint16
|
||||||
|
MaxUdpDg uint16
|
||||||
|
VendorInfo *byte
|
||||||
|
Description [WSADESCRIPTION_LEN + 1]byte
|
||||||
|
SystemStatus [WSASYS_STATUS_LEN + 1]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type Servent struct {
|
||||||
|
Name *byte
|
||||||
|
Aliases **byte
|
||||||
|
Proto *byte
|
||||||
|
Port uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type JOBOBJECT_BASIC_LIMIT_INFORMATION struct {
|
||||||
|
PerProcessUserTimeLimit int64
|
||||||
|
PerJobUserTimeLimit int64
|
||||||
|
LimitFlags uint32
|
||||||
|
MinimumWorkingSetSize uintptr
|
||||||
|
MaximumWorkingSetSize uintptr
|
||||||
|
ActiveProcessLimit uint32
|
||||||
|
Affinity uintptr
|
||||||
|
PriorityClass uint32
|
||||||
|
SchedulingClass uint32
|
||||||
|
}
|
||||||
35
vendor/golang.org/x/sys/windows/types_windows_arm.go
generated
vendored
Normal file
35
vendor/golang.org/x/sys/windows/types_windows_arm.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
type WSAData struct {
|
||||||
|
Version uint16
|
||||||
|
HighVersion uint16
|
||||||
|
Description [WSADESCRIPTION_LEN + 1]byte
|
||||||
|
SystemStatus [WSASYS_STATUS_LEN + 1]byte
|
||||||
|
MaxSockets uint16
|
||||||
|
MaxUdpDg uint16
|
||||||
|
VendorInfo *byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type Servent struct {
|
||||||
|
Name *byte
|
||||||
|
Aliases **byte
|
||||||
|
Port uint16
|
||||||
|
Proto *byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type JOBOBJECT_BASIC_LIMIT_INFORMATION struct {
|
||||||
|
PerProcessUserTimeLimit int64
|
||||||
|
PerJobUserTimeLimit int64
|
||||||
|
LimitFlags uint32
|
||||||
|
MinimumWorkingSetSize uintptr
|
||||||
|
MaximumWorkingSetSize uintptr
|
||||||
|
ActiveProcessLimit uint32
|
||||||
|
Affinity uintptr
|
||||||
|
PriorityClass uint32
|
||||||
|
SchedulingClass uint32
|
||||||
|
_ uint32 // pad to 8 byte boundary
|
||||||
|
}
|
||||||
34
vendor/golang.org/x/sys/windows/types_windows_arm64.go
generated
vendored
Normal file
34
vendor/golang.org/x/sys/windows/types_windows_arm64.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
type WSAData struct {
|
||||||
|
Version uint16
|
||||||
|
HighVersion uint16
|
||||||
|
MaxSockets uint16
|
||||||
|
MaxUdpDg uint16
|
||||||
|
VendorInfo *byte
|
||||||
|
Description [WSADESCRIPTION_LEN + 1]byte
|
||||||
|
SystemStatus [WSASYS_STATUS_LEN + 1]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type Servent struct {
|
||||||
|
Name *byte
|
||||||
|
Aliases **byte
|
||||||
|
Proto *byte
|
||||||
|
Port uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type JOBOBJECT_BASIC_LIMIT_INFORMATION struct {
|
||||||
|
PerProcessUserTimeLimit int64
|
||||||
|
PerJobUserTimeLimit int64
|
||||||
|
LimitFlags uint32
|
||||||
|
MinimumWorkingSetSize uintptr
|
||||||
|
MaximumWorkingSetSize uintptr
|
||||||
|
ActiveProcessLimit uint32
|
||||||
|
Affinity uintptr
|
||||||
|
PriorityClass uint32
|
||||||
|
SchedulingClass uint32
|
||||||
|
}
|
||||||
9468
vendor/golang.org/x/sys/windows/zerrors_windows.go
generated
vendored
Normal file
9468
vendor/golang.org/x/sys/windows/zerrors_windows.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
149
vendor/golang.org/x/sys/windows/zknownfolderids_windows.go
generated
vendored
Normal file
149
vendor/golang.org/x/sys/windows/zknownfolderids_windows.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
// Code generated by 'mkknownfolderids.bash'; DO NOT EDIT.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
type KNOWNFOLDERID GUID
|
||||||
|
|
||||||
|
var (
|
||||||
|
FOLDERID_NetworkFolder = &KNOWNFOLDERID{0xd20beec4, 0x5ca8, 0x4905, [8]byte{0xae, 0x3b, 0xbf, 0x25, 0x1e, 0xa0, 0x9b, 0x53}}
|
||||||
|
FOLDERID_ComputerFolder = &KNOWNFOLDERID{0x0ac0837c, 0xbbf8, 0x452a, [8]byte{0x85, 0x0d, 0x79, 0xd0, 0x8e, 0x66, 0x7c, 0xa7}}
|
||||||
|
FOLDERID_InternetFolder = &KNOWNFOLDERID{0x4d9f7874, 0x4e0c, 0x4904, [8]byte{0x96, 0x7b, 0x40, 0xb0, 0xd2, 0x0c, 0x3e, 0x4b}}
|
||||||
|
FOLDERID_ControlPanelFolder = &KNOWNFOLDERID{0x82a74aeb, 0xaeb4, 0x465c, [8]byte{0xa0, 0x14, 0xd0, 0x97, 0xee, 0x34, 0x6d, 0x63}}
|
||||||
|
FOLDERID_PrintersFolder = &KNOWNFOLDERID{0x76fc4e2d, 0xd6ad, 0x4519, [8]byte{0xa6, 0x63, 0x37, 0xbd, 0x56, 0x06, 0x81, 0x85}}
|
||||||
|
FOLDERID_SyncManagerFolder = &KNOWNFOLDERID{0x43668bf8, 0xc14e, 0x49b2, [8]byte{0x97, 0xc9, 0x74, 0x77, 0x84, 0xd7, 0x84, 0xb7}}
|
||||||
|
FOLDERID_SyncSetupFolder = &KNOWNFOLDERID{0x0f214138, 0xb1d3, 0x4a90, [8]byte{0xbb, 0xa9, 0x27, 0xcb, 0xc0, 0xc5, 0x38, 0x9a}}
|
||||||
|
FOLDERID_ConflictFolder = &KNOWNFOLDERID{0x4bfefb45, 0x347d, 0x4006, [8]byte{0xa5, 0xbe, 0xac, 0x0c, 0xb0, 0x56, 0x71, 0x92}}
|
||||||
|
FOLDERID_SyncResultsFolder = &KNOWNFOLDERID{0x289a9a43, 0xbe44, 0x4057, [8]byte{0xa4, 0x1b, 0x58, 0x7a, 0x76, 0xd7, 0xe7, 0xf9}}
|
||||||
|
FOLDERID_RecycleBinFolder = &KNOWNFOLDERID{0xb7534046, 0x3ecb, 0x4c18, [8]byte{0xbe, 0x4e, 0x64, 0xcd, 0x4c, 0xb7, 0xd6, 0xac}}
|
||||||
|
FOLDERID_ConnectionsFolder = &KNOWNFOLDERID{0x6f0cd92b, 0x2e97, 0x45d1, [8]byte{0x88, 0xff, 0xb0, 0xd1, 0x86, 0xb8, 0xde, 0xdd}}
|
||||||
|
FOLDERID_Fonts = &KNOWNFOLDERID{0xfd228cb7, 0xae11, 0x4ae3, [8]byte{0x86, 0x4c, 0x16, 0xf3, 0x91, 0x0a, 0xb8, 0xfe}}
|
||||||
|
FOLDERID_Desktop = &KNOWNFOLDERID{0xb4bfcc3a, 0xdb2c, 0x424c, [8]byte{0xb0, 0x29, 0x7f, 0xe9, 0x9a, 0x87, 0xc6, 0x41}}
|
||||||
|
FOLDERID_Startup = &KNOWNFOLDERID{0xb97d20bb, 0xf46a, 0x4c97, [8]byte{0xba, 0x10, 0x5e, 0x36, 0x08, 0x43, 0x08, 0x54}}
|
||||||
|
FOLDERID_Programs = &KNOWNFOLDERID{0xa77f5d77, 0x2e2b, 0x44c3, [8]byte{0xa6, 0xa2, 0xab, 0xa6, 0x01, 0x05, 0x4a, 0x51}}
|
||||||
|
FOLDERID_StartMenu = &KNOWNFOLDERID{0x625b53c3, 0xab48, 0x4ec1, [8]byte{0xba, 0x1f, 0xa1, 0xef, 0x41, 0x46, 0xfc, 0x19}}
|
||||||
|
FOLDERID_Recent = &KNOWNFOLDERID{0xae50c081, 0xebd2, 0x438a, [8]byte{0x86, 0x55, 0x8a, 0x09, 0x2e, 0x34, 0x98, 0x7a}}
|
||||||
|
FOLDERID_SendTo = &KNOWNFOLDERID{0x8983036c, 0x27c0, 0x404b, [8]byte{0x8f, 0x08, 0x10, 0x2d, 0x10, 0xdc, 0xfd, 0x74}}
|
||||||
|
FOLDERID_Documents = &KNOWNFOLDERID{0xfdd39ad0, 0x238f, 0x46af, [8]byte{0xad, 0xb4, 0x6c, 0x85, 0x48, 0x03, 0x69, 0xc7}}
|
||||||
|
FOLDERID_Favorites = &KNOWNFOLDERID{0x1777f761, 0x68ad, 0x4d8a, [8]byte{0x87, 0xbd, 0x30, 0xb7, 0x59, 0xfa, 0x33, 0xdd}}
|
||||||
|
FOLDERID_NetHood = &KNOWNFOLDERID{0xc5abbf53, 0xe17f, 0x4121, [8]byte{0x89, 0x00, 0x86, 0x62, 0x6f, 0xc2, 0xc9, 0x73}}
|
||||||
|
FOLDERID_PrintHood = &KNOWNFOLDERID{0x9274bd8d, 0xcfd1, 0x41c3, [8]byte{0xb3, 0x5e, 0xb1, 0x3f, 0x55, 0xa7, 0x58, 0xf4}}
|
||||||
|
FOLDERID_Templates = &KNOWNFOLDERID{0xa63293e8, 0x664e, 0x48db, [8]byte{0xa0, 0x79, 0xdf, 0x75, 0x9e, 0x05, 0x09, 0xf7}}
|
||||||
|
FOLDERID_CommonStartup = &KNOWNFOLDERID{0x82a5ea35, 0xd9cd, 0x47c5, [8]byte{0x96, 0x29, 0xe1, 0x5d, 0x2f, 0x71, 0x4e, 0x6e}}
|
||||||
|
FOLDERID_CommonPrograms = &KNOWNFOLDERID{0x0139d44e, 0x6afe, 0x49f2, [8]byte{0x86, 0x90, 0x3d, 0xaf, 0xca, 0xe6, 0xff, 0xb8}}
|
||||||
|
FOLDERID_CommonStartMenu = &KNOWNFOLDERID{0xa4115719, 0xd62e, 0x491d, [8]byte{0xaa, 0x7c, 0xe7, 0x4b, 0x8b, 0xe3, 0xb0, 0x67}}
|
||||||
|
FOLDERID_PublicDesktop = &KNOWNFOLDERID{0xc4aa340d, 0xf20f, 0x4863, [8]byte{0xaf, 0xef, 0xf8, 0x7e, 0xf2, 0xe6, 0xba, 0x25}}
|
||||||
|
FOLDERID_ProgramData = &KNOWNFOLDERID{0x62ab5d82, 0xfdc1, 0x4dc3, [8]byte{0xa9, 0xdd, 0x07, 0x0d, 0x1d, 0x49, 0x5d, 0x97}}
|
||||||
|
FOLDERID_CommonTemplates = &KNOWNFOLDERID{0xb94237e7, 0x57ac, 0x4347, [8]byte{0x91, 0x51, 0xb0, 0x8c, 0x6c, 0x32, 0xd1, 0xf7}}
|
||||||
|
FOLDERID_PublicDocuments = &KNOWNFOLDERID{0xed4824af, 0xdce4, 0x45a8, [8]byte{0x81, 0xe2, 0xfc, 0x79, 0x65, 0x08, 0x36, 0x34}}
|
||||||
|
FOLDERID_RoamingAppData = &KNOWNFOLDERID{0x3eb685db, 0x65f9, 0x4cf6, [8]byte{0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d}}
|
||||||
|
FOLDERID_LocalAppData = &KNOWNFOLDERID{0xf1b32785, 0x6fba, 0x4fcf, [8]byte{0x9d, 0x55, 0x7b, 0x8e, 0x7f, 0x15, 0x70, 0x91}}
|
||||||
|
FOLDERID_LocalAppDataLow = &KNOWNFOLDERID{0xa520a1a4, 0x1780, 0x4ff6, [8]byte{0xbd, 0x18, 0x16, 0x73, 0x43, 0xc5, 0xaf, 0x16}}
|
||||||
|
FOLDERID_InternetCache = &KNOWNFOLDERID{0x352481e8, 0x33be, 0x4251, [8]byte{0xba, 0x85, 0x60, 0x07, 0xca, 0xed, 0xcf, 0x9d}}
|
||||||
|
FOLDERID_Cookies = &KNOWNFOLDERID{0x2b0f765d, 0xc0e9, 0x4171, [8]byte{0x90, 0x8e, 0x08, 0xa6, 0x11, 0xb8, 0x4f, 0xf6}}
|
||||||
|
FOLDERID_History = &KNOWNFOLDERID{0xd9dc8a3b, 0xb784, 0x432e, [8]byte{0xa7, 0x81, 0x5a, 0x11, 0x30, 0xa7, 0x59, 0x63}}
|
||||||
|
FOLDERID_System = &KNOWNFOLDERID{0x1ac14e77, 0x02e7, 0x4e5d, [8]byte{0xb7, 0x44, 0x2e, 0xb1, 0xae, 0x51, 0x98, 0xb7}}
|
||||||
|
FOLDERID_SystemX86 = &KNOWNFOLDERID{0xd65231b0, 0xb2f1, 0x4857, [8]byte{0xa4, 0xce, 0xa8, 0xe7, 0xc6, 0xea, 0x7d, 0x27}}
|
||||||
|
FOLDERID_Windows = &KNOWNFOLDERID{0xf38bf404, 0x1d43, 0x42f2, [8]byte{0x93, 0x05, 0x67, 0xde, 0x0b, 0x28, 0xfc, 0x23}}
|
||||||
|
FOLDERID_Profile = &KNOWNFOLDERID{0x5e6c858f, 0x0e22, 0x4760, [8]byte{0x9a, 0xfe, 0xea, 0x33, 0x17, 0xb6, 0x71, 0x73}}
|
||||||
|
FOLDERID_Pictures = &KNOWNFOLDERID{0x33e28130, 0x4e1e, 0x4676, [8]byte{0x83, 0x5a, 0x98, 0x39, 0x5c, 0x3b, 0xc3, 0xbb}}
|
||||||
|
FOLDERID_ProgramFilesX86 = &KNOWNFOLDERID{0x7c5a40ef, 0xa0fb, 0x4bfc, [8]byte{0x87, 0x4a, 0xc0, 0xf2, 0xe0, 0xb9, 0xfa, 0x8e}}
|
||||||
|
FOLDERID_ProgramFilesCommonX86 = &KNOWNFOLDERID{0xde974d24, 0xd9c6, 0x4d3e, [8]byte{0xbf, 0x91, 0xf4, 0x45, 0x51, 0x20, 0xb9, 0x17}}
|
||||||
|
FOLDERID_ProgramFilesX64 = &KNOWNFOLDERID{0x6d809377, 0x6af0, 0x444b, [8]byte{0x89, 0x57, 0xa3, 0x77, 0x3f, 0x02, 0x20, 0x0e}}
|
||||||
|
FOLDERID_ProgramFilesCommonX64 = &KNOWNFOLDERID{0x6365d5a7, 0x0f0d, 0x45e5, [8]byte{0x87, 0xf6, 0x0d, 0xa5, 0x6b, 0x6a, 0x4f, 0x7d}}
|
||||||
|
FOLDERID_ProgramFiles = &KNOWNFOLDERID{0x905e63b6, 0xc1bf, 0x494e, [8]byte{0xb2, 0x9c, 0x65, 0xb7, 0x32, 0xd3, 0xd2, 0x1a}}
|
||||||
|
FOLDERID_ProgramFilesCommon = &KNOWNFOLDERID{0xf7f1ed05, 0x9f6d, 0x47a2, [8]byte{0xaa, 0xae, 0x29, 0xd3, 0x17, 0xc6, 0xf0, 0x66}}
|
||||||
|
FOLDERID_UserProgramFiles = &KNOWNFOLDERID{0x5cd7aee2, 0x2219, 0x4a67, [8]byte{0xb8, 0x5d, 0x6c, 0x9c, 0xe1, 0x56, 0x60, 0xcb}}
|
||||||
|
FOLDERID_UserProgramFilesCommon = &KNOWNFOLDERID{0xbcbd3057, 0xca5c, 0x4622, [8]byte{0xb4, 0x2d, 0xbc, 0x56, 0xdb, 0x0a, 0xe5, 0x16}}
|
||||||
|
FOLDERID_AdminTools = &KNOWNFOLDERID{0x724ef170, 0xa42d, 0x4fef, [8]byte{0x9f, 0x26, 0xb6, 0x0e, 0x84, 0x6f, 0xba, 0x4f}}
|
||||||
|
FOLDERID_CommonAdminTools = &KNOWNFOLDERID{0xd0384e7d, 0xbac3, 0x4797, [8]byte{0x8f, 0x14, 0xcb, 0xa2, 0x29, 0xb3, 0x92, 0xb5}}
|
||||||
|
FOLDERID_Music = &KNOWNFOLDERID{0x4bd8d571, 0x6d19, 0x48d3, [8]byte{0xbe, 0x97, 0x42, 0x22, 0x20, 0x08, 0x0e, 0x43}}
|
||||||
|
FOLDERID_Videos = &KNOWNFOLDERID{0x18989b1d, 0x99b5, 0x455b, [8]byte{0x84, 0x1c, 0xab, 0x7c, 0x74, 0xe4, 0xdd, 0xfc}}
|
||||||
|
FOLDERID_Ringtones = &KNOWNFOLDERID{0xc870044b, 0xf49e, 0x4126, [8]byte{0xa9, 0xc3, 0xb5, 0x2a, 0x1f, 0xf4, 0x11, 0xe8}}
|
||||||
|
FOLDERID_PublicPictures = &KNOWNFOLDERID{0xb6ebfb86, 0x6907, 0x413c, [8]byte{0x9a, 0xf7, 0x4f, 0xc2, 0xab, 0xf0, 0x7c, 0xc5}}
|
||||||
|
FOLDERID_PublicMusic = &KNOWNFOLDERID{0x3214fab5, 0x9757, 0x4298, [8]byte{0xbb, 0x61, 0x92, 0xa9, 0xde, 0xaa, 0x44, 0xff}}
|
||||||
|
FOLDERID_PublicVideos = &KNOWNFOLDERID{0x2400183a, 0x6185, 0x49fb, [8]byte{0xa2, 0xd8, 0x4a, 0x39, 0x2a, 0x60, 0x2b, 0xa3}}
|
||||||
|
FOLDERID_PublicRingtones = &KNOWNFOLDERID{0xe555ab60, 0x153b, 0x4d17, [8]byte{0x9f, 0x04, 0xa5, 0xfe, 0x99, 0xfc, 0x15, 0xec}}
|
||||||
|
FOLDERID_ResourceDir = &KNOWNFOLDERID{0x8ad10c31, 0x2adb, 0x4296, [8]byte{0xa8, 0xf7, 0xe4, 0x70, 0x12, 0x32, 0xc9, 0x72}}
|
||||||
|
FOLDERID_LocalizedResourcesDir = &KNOWNFOLDERID{0x2a00375e, 0x224c, 0x49de, [8]byte{0xb8, 0xd1, 0x44, 0x0d, 0xf7, 0xef, 0x3d, 0xdc}}
|
||||||
|
FOLDERID_CommonOEMLinks = &KNOWNFOLDERID{0xc1bae2d0, 0x10df, 0x4334, [8]byte{0xbe, 0xdd, 0x7a, 0xa2, 0x0b, 0x22, 0x7a, 0x9d}}
|
||||||
|
FOLDERID_CDBurning = &KNOWNFOLDERID{0x9e52ab10, 0xf80d, 0x49df, [8]byte{0xac, 0xb8, 0x43, 0x30, 0xf5, 0x68, 0x78, 0x55}}
|
||||||
|
FOLDERID_UserProfiles = &KNOWNFOLDERID{0x0762d272, 0xc50a, 0x4bb0, [8]byte{0xa3, 0x82, 0x69, 0x7d, 0xcd, 0x72, 0x9b, 0x80}}
|
||||||
|
FOLDERID_Playlists = &KNOWNFOLDERID{0xde92c1c7, 0x837f, 0x4f69, [8]byte{0xa3, 0xbb, 0x86, 0xe6, 0x31, 0x20, 0x4a, 0x23}}
|
||||||
|
FOLDERID_SamplePlaylists = &KNOWNFOLDERID{0x15ca69b3, 0x30ee, 0x49c1, [8]byte{0xac, 0xe1, 0x6b, 0x5e, 0xc3, 0x72, 0xaf, 0xb5}}
|
||||||
|
FOLDERID_SampleMusic = &KNOWNFOLDERID{0xb250c668, 0xf57d, 0x4ee1, [8]byte{0xa6, 0x3c, 0x29, 0x0e, 0xe7, 0xd1, 0xaa, 0x1f}}
|
||||||
|
FOLDERID_SamplePictures = &KNOWNFOLDERID{0xc4900540, 0x2379, 0x4c75, [8]byte{0x84, 0x4b, 0x64, 0xe6, 0xfa, 0xf8, 0x71, 0x6b}}
|
||||||
|
FOLDERID_SampleVideos = &KNOWNFOLDERID{0x859ead94, 0x2e85, 0x48ad, [8]byte{0xa7, 0x1a, 0x09, 0x69, 0xcb, 0x56, 0xa6, 0xcd}}
|
||||||
|
FOLDERID_PhotoAlbums = &KNOWNFOLDERID{0x69d2cf90, 0xfc33, 0x4fb7, [8]byte{0x9a, 0x0c, 0xeb, 0xb0, 0xf0, 0xfc, 0xb4, 0x3c}}
|
||||||
|
FOLDERID_Public = &KNOWNFOLDERID{0xdfdf76a2, 0xc82a, 0x4d63, [8]byte{0x90, 0x6a, 0x56, 0x44, 0xac, 0x45, 0x73, 0x85}}
|
||||||
|
FOLDERID_ChangeRemovePrograms = &KNOWNFOLDERID{0xdf7266ac, 0x9274, 0x4867, [8]byte{0x8d, 0x55, 0x3b, 0xd6, 0x61, 0xde, 0x87, 0x2d}}
|
||||||
|
FOLDERID_AppUpdates = &KNOWNFOLDERID{0xa305ce99, 0xf527, 0x492b, [8]byte{0x8b, 0x1a, 0x7e, 0x76, 0xfa, 0x98, 0xd6, 0xe4}}
|
||||||
|
FOLDERID_AddNewPrograms = &KNOWNFOLDERID{0xde61d971, 0x5ebc, 0x4f02, [8]byte{0xa3, 0xa9, 0x6c, 0x82, 0x89, 0x5e, 0x5c, 0x04}}
|
||||||
|
FOLDERID_Downloads = &KNOWNFOLDERID{0x374de290, 0x123f, 0x4565, [8]byte{0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b}}
|
||||||
|
FOLDERID_PublicDownloads = &KNOWNFOLDERID{0x3d644c9b, 0x1fb8, 0x4f30, [8]byte{0x9b, 0x45, 0xf6, 0x70, 0x23, 0x5f, 0x79, 0xc0}}
|
||||||
|
FOLDERID_SavedSearches = &KNOWNFOLDERID{0x7d1d3a04, 0xdebb, 0x4115, [8]byte{0x95, 0xcf, 0x2f, 0x29, 0xda, 0x29, 0x20, 0xda}}
|
||||||
|
FOLDERID_QuickLaunch = &KNOWNFOLDERID{0x52a4f021, 0x7b75, 0x48a9, [8]byte{0x9f, 0x6b, 0x4b, 0x87, 0xa2, 0x10, 0xbc, 0x8f}}
|
||||||
|
FOLDERID_Contacts = &KNOWNFOLDERID{0x56784854, 0xc6cb, 0x462b, [8]byte{0x81, 0x69, 0x88, 0xe3, 0x50, 0xac, 0xb8, 0x82}}
|
||||||
|
FOLDERID_SidebarParts = &KNOWNFOLDERID{0xa75d362e, 0x50fc, 0x4fb7, [8]byte{0xac, 0x2c, 0xa8, 0xbe, 0xaa, 0x31, 0x44, 0x93}}
|
||||||
|
FOLDERID_SidebarDefaultParts = &KNOWNFOLDERID{0x7b396e54, 0x9ec5, 0x4300, [8]byte{0xbe, 0x0a, 0x24, 0x82, 0xeb, 0xae, 0x1a, 0x26}}
|
||||||
|
FOLDERID_PublicGameTasks = &KNOWNFOLDERID{0xdebf2536, 0xe1a8, 0x4c59, [8]byte{0xb6, 0xa2, 0x41, 0x45, 0x86, 0x47, 0x6a, 0xea}}
|
||||||
|
FOLDERID_GameTasks = &KNOWNFOLDERID{0x054fae61, 0x4dd8, 0x4787, [8]byte{0x80, 0xb6, 0x09, 0x02, 0x20, 0xc4, 0xb7, 0x00}}
|
||||||
|
FOLDERID_SavedGames = &KNOWNFOLDERID{0x4c5c32ff, 0xbb9d, 0x43b0, [8]byte{0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4}}
|
||||||
|
FOLDERID_Games = &KNOWNFOLDERID{0xcac52c1a, 0xb53d, 0x4edc, [8]byte{0x92, 0xd7, 0x6b, 0x2e, 0x8a, 0xc1, 0x94, 0x34}}
|
||||||
|
FOLDERID_SEARCH_MAPI = &KNOWNFOLDERID{0x98ec0e18, 0x2098, 0x4d44, [8]byte{0x86, 0x44, 0x66, 0x97, 0x93, 0x15, 0xa2, 0x81}}
|
||||||
|
FOLDERID_SEARCH_CSC = &KNOWNFOLDERID{0xee32e446, 0x31ca, 0x4aba, [8]byte{0x81, 0x4f, 0xa5, 0xeb, 0xd2, 0xfd, 0x6d, 0x5e}}
|
||||||
|
FOLDERID_Links = &KNOWNFOLDERID{0xbfb9d5e0, 0xc6a9, 0x404c, [8]byte{0xb2, 0xb2, 0xae, 0x6d, 0xb6, 0xaf, 0x49, 0x68}}
|
||||||
|
FOLDERID_UsersFiles = &KNOWNFOLDERID{0xf3ce0f7c, 0x4901, 0x4acc, [8]byte{0x86, 0x48, 0xd5, 0xd4, 0x4b, 0x04, 0xef, 0x8f}}
|
||||||
|
FOLDERID_UsersLibraries = &KNOWNFOLDERID{0xa302545d, 0xdeff, 0x464b, [8]byte{0xab, 0xe8, 0x61, 0xc8, 0x64, 0x8d, 0x93, 0x9b}}
|
||||||
|
FOLDERID_SearchHome = &KNOWNFOLDERID{0x190337d1, 0xb8ca, 0x4121, [8]byte{0xa6, 0x39, 0x6d, 0x47, 0x2d, 0x16, 0x97, 0x2a}}
|
||||||
|
FOLDERID_OriginalImages = &KNOWNFOLDERID{0x2c36c0aa, 0x5812, 0x4b87, [8]byte{0xbf, 0xd0, 0x4c, 0xd0, 0xdf, 0xb1, 0x9b, 0x39}}
|
||||||
|
FOLDERID_DocumentsLibrary = &KNOWNFOLDERID{0x7b0db17d, 0x9cd2, 0x4a93, [8]byte{0x97, 0x33, 0x46, 0xcc, 0x89, 0x02, 0x2e, 0x7c}}
|
||||||
|
FOLDERID_MusicLibrary = &KNOWNFOLDERID{0x2112ab0a, 0xc86a, 0x4ffe, [8]byte{0xa3, 0x68, 0x0d, 0xe9, 0x6e, 0x47, 0x01, 0x2e}}
|
||||||
|
FOLDERID_PicturesLibrary = &KNOWNFOLDERID{0xa990ae9f, 0xa03b, 0x4e80, [8]byte{0x94, 0xbc, 0x99, 0x12, 0xd7, 0x50, 0x41, 0x04}}
|
||||||
|
FOLDERID_VideosLibrary = &KNOWNFOLDERID{0x491e922f, 0x5643, 0x4af4, [8]byte{0xa7, 0xeb, 0x4e, 0x7a, 0x13, 0x8d, 0x81, 0x74}}
|
||||||
|
FOLDERID_RecordedTVLibrary = &KNOWNFOLDERID{0x1a6fdba2, 0xf42d, 0x4358, [8]byte{0xa7, 0x98, 0xb7, 0x4d, 0x74, 0x59, 0x26, 0xc5}}
|
||||||
|
FOLDERID_HomeGroup = &KNOWNFOLDERID{0x52528a6b, 0xb9e3, 0x4add, [8]byte{0xb6, 0x0d, 0x58, 0x8c, 0x2d, 0xba, 0x84, 0x2d}}
|
||||||
|
FOLDERID_HomeGroupCurrentUser = &KNOWNFOLDERID{0x9b74b6a3, 0x0dfd, 0x4f11, [8]byte{0x9e, 0x78, 0x5f, 0x78, 0x00, 0xf2, 0xe7, 0x72}}
|
||||||
|
FOLDERID_DeviceMetadataStore = &KNOWNFOLDERID{0x5ce4a5e9, 0xe4eb, 0x479d, [8]byte{0xb8, 0x9f, 0x13, 0x0c, 0x02, 0x88, 0x61, 0x55}}
|
||||||
|
FOLDERID_Libraries = &KNOWNFOLDERID{0x1b3ea5dc, 0xb587, 0x4786, [8]byte{0xb4, 0xef, 0xbd, 0x1d, 0xc3, 0x32, 0xae, 0xae}}
|
||||||
|
FOLDERID_PublicLibraries = &KNOWNFOLDERID{0x48daf80b, 0xe6cf, 0x4f4e, [8]byte{0xb8, 0x00, 0x0e, 0x69, 0xd8, 0x4e, 0xe3, 0x84}}
|
||||||
|
FOLDERID_UserPinned = &KNOWNFOLDERID{0x9e3995ab, 0x1f9c, 0x4f13, [8]byte{0xb8, 0x27, 0x48, 0xb2, 0x4b, 0x6c, 0x71, 0x74}}
|
||||||
|
FOLDERID_ImplicitAppShortcuts = &KNOWNFOLDERID{0xbcb5256f, 0x79f6, 0x4cee, [8]byte{0xb7, 0x25, 0xdc, 0x34, 0xe4, 0x02, 0xfd, 0x46}}
|
||||||
|
FOLDERID_AccountPictures = &KNOWNFOLDERID{0x008ca0b1, 0x55b4, 0x4c56, [8]byte{0xb8, 0xa8, 0x4d, 0xe4, 0xb2, 0x99, 0xd3, 0xbe}}
|
||||||
|
FOLDERID_PublicUserTiles = &KNOWNFOLDERID{0x0482af6c, 0x08f1, 0x4c34, [8]byte{0x8c, 0x90, 0xe1, 0x7e, 0xc9, 0x8b, 0x1e, 0x17}}
|
||||||
|
FOLDERID_AppsFolder = &KNOWNFOLDERID{0x1e87508d, 0x89c2, 0x42f0, [8]byte{0x8a, 0x7e, 0x64, 0x5a, 0x0f, 0x50, 0xca, 0x58}}
|
||||||
|
FOLDERID_StartMenuAllPrograms = &KNOWNFOLDERID{0xf26305ef, 0x6948, 0x40b9, [8]byte{0xb2, 0x55, 0x81, 0x45, 0x3d, 0x09, 0xc7, 0x85}}
|
||||||
|
FOLDERID_CommonStartMenuPlaces = &KNOWNFOLDERID{0xa440879f, 0x87a0, 0x4f7d, [8]byte{0xb7, 0x00, 0x02, 0x07, 0xb9, 0x66, 0x19, 0x4a}}
|
||||||
|
FOLDERID_ApplicationShortcuts = &KNOWNFOLDERID{0xa3918781, 0xe5f2, 0x4890, [8]byte{0xb3, 0xd9, 0xa7, 0xe5, 0x43, 0x32, 0x32, 0x8c}}
|
||||||
|
FOLDERID_RoamingTiles = &KNOWNFOLDERID{0x00bcfc5a, 0xed94, 0x4e48, [8]byte{0x96, 0xa1, 0x3f, 0x62, 0x17, 0xf2, 0x19, 0x90}}
|
||||||
|
FOLDERID_RoamedTileImages = &KNOWNFOLDERID{0xaaa8d5a5, 0xf1d6, 0x4259, [8]byte{0xba, 0xa8, 0x78, 0xe7, 0xef, 0x60, 0x83, 0x5e}}
|
||||||
|
FOLDERID_Screenshots = &KNOWNFOLDERID{0xb7bede81, 0xdf94, 0x4682, [8]byte{0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f}}
|
||||||
|
FOLDERID_CameraRoll = &KNOWNFOLDERID{0xab5fb87b, 0x7ce2, 0x4f83, [8]byte{0x91, 0x5d, 0x55, 0x08, 0x46, 0xc9, 0x53, 0x7b}}
|
||||||
|
FOLDERID_SkyDrive = &KNOWNFOLDERID{0xa52bba46, 0xe9e1, 0x435f, [8]byte{0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}}
|
||||||
|
FOLDERID_OneDrive = &KNOWNFOLDERID{0xa52bba46, 0xe9e1, 0x435f, [8]byte{0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}}
|
||||||
|
FOLDERID_SkyDriveDocuments = &KNOWNFOLDERID{0x24d89e24, 0x2f19, 0x4534, [8]byte{0x9d, 0xde, 0x6a, 0x66, 0x71, 0xfb, 0xb8, 0xfe}}
|
||||||
|
FOLDERID_SkyDrivePictures = &KNOWNFOLDERID{0x339719b5, 0x8c47, 0x4894, [8]byte{0x94, 0xc2, 0xd8, 0xf7, 0x7a, 0xdd, 0x44, 0xa6}}
|
||||||
|
FOLDERID_SkyDriveMusic = &KNOWNFOLDERID{0xc3f2459e, 0x80d6, 0x45dc, [8]byte{0xbf, 0xef, 0x1f, 0x76, 0x9f, 0x2b, 0xe7, 0x30}}
|
||||||
|
FOLDERID_SkyDriveCameraRoll = &KNOWNFOLDERID{0x767e6811, 0x49cb, 0x4273, [8]byte{0x87, 0xc2, 0x20, 0xf3, 0x55, 0xe1, 0x08, 0x5b}}
|
||||||
|
FOLDERID_SearchHistory = &KNOWNFOLDERID{0x0d4c3db6, 0x03a3, 0x462f, [8]byte{0xa0, 0xe6, 0x08, 0x92, 0x4c, 0x41, 0xb5, 0xd4}}
|
||||||
|
FOLDERID_SearchTemplates = &KNOWNFOLDERID{0x7e636bfe, 0xdfa9, 0x4d5e, [8]byte{0xb4, 0x56, 0xd7, 0xb3, 0x98, 0x51, 0xd8, 0xa9}}
|
||||||
|
FOLDERID_CameraRollLibrary = &KNOWNFOLDERID{0x2b20df75, 0x1eda, 0x4039, [8]byte{0x80, 0x97, 0x38, 0x79, 0x82, 0x27, 0xd5, 0xb7}}
|
||||||
|
FOLDERID_SavedPictures = &KNOWNFOLDERID{0x3b193882, 0xd3ad, 0x4eab, [8]byte{0x96, 0x5a, 0x69, 0x82, 0x9d, 0x1f, 0xb5, 0x9f}}
|
||||||
|
FOLDERID_SavedPicturesLibrary = &KNOWNFOLDERID{0xe25b5812, 0xbe88, 0x4bd9, [8]byte{0x94, 0xb0, 0x29, 0x23, 0x34, 0x77, 0xb6, 0xc3}}
|
||||||
|
FOLDERID_RetailDemo = &KNOWNFOLDERID{0x12d4c69e, 0x24ad, 0x4923, [8]byte{0xbe, 0x19, 0x31, 0x32, 0x1c, 0x43, 0xa7, 0x67}}
|
||||||
|
FOLDERID_Device = &KNOWNFOLDERID{0x1c2ac1dc, 0x4358, 0x4b6c, [8]byte{0x97, 0x33, 0xaf, 0x21, 0x15, 0x65, 0x76, 0xf0}}
|
||||||
|
FOLDERID_DevelopmentFiles = &KNOWNFOLDERID{0xdbe8e08e, 0x3053, 0x4bbc, [8]byte{0xb1, 0x83, 0x2a, 0x7b, 0x2b, 0x19, 0x1e, 0x59}}
|
||||||
|
FOLDERID_Objects3D = &KNOWNFOLDERID{0x31c0dd25, 0x9439, 0x4f12, [8]byte{0xbf, 0x41, 0x7f, 0xf4, 0xed, 0xa3, 0x87, 0x22}}
|
||||||
|
FOLDERID_AppCaptures = &KNOWNFOLDERID{0xedc0fe71, 0x98d8, 0x4f4a, [8]byte{0xb9, 0x20, 0xc8, 0xdc, 0x13, 0x3c, 0xb1, 0x65}}
|
||||||
|
FOLDERID_LocalDocuments = &KNOWNFOLDERID{0xf42ee2d3, 0x909f, 0x4907, [8]byte{0x88, 0x71, 0x4c, 0x22, 0xfc, 0x0b, 0xf7, 0x56}}
|
||||||
|
FOLDERID_LocalPictures = &KNOWNFOLDERID{0x0ddd015d, 0xb06c, 0x45d5, [8]byte{0x8c, 0x4c, 0xf5, 0x97, 0x13, 0x85, 0x46, 0x39}}
|
||||||
|
FOLDERID_LocalVideos = &KNOWNFOLDERID{0x35286a68, 0x3c57, 0x41a1, [8]byte{0xbb, 0xb1, 0x0e, 0xae, 0x73, 0xd7, 0x6c, 0x95}}
|
||||||
|
FOLDERID_LocalMusic = &KNOWNFOLDERID{0xa0c69a99, 0x21c8, 0x4671, [8]byte{0x87, 0x03, 0x79, 0x34, 0x16, 0x2f, 0xcf, 0x1d}}
|
||||||
|
FOLDERID_LocalDownloads = &KNOWNFOLDERID{0x7d83ee9b, 0x2244, 0x4e70, [8]byte{0xb1, 0xf5, 0x53, 0x93, 0x04, 0x2a, 0xf1, 0xe4}}
|
||||||
|
FOLDERID_RecordedCalls = &KNOWNFOLDERID{0x2f8b40c2, 0x83ed, 0x48ee, [8]byte{0xb3, 0x83, 0xa1, 0xf1, 0x57, 0xec, 0x6f, 0x9a}}
|
||||||
|
FOLDERID_AllAppMods = &KNOWNFOLDERID{0x7ad67899, 0x66af, 0x43ba, [8]byte{0x91, 0x56, 0x6a, 0xad, 0x42, 0xe6, 0xc5, 0x96}}
|
||||||
|
FOLDERID_CurrentAppMods = &KNOWNFOLDERID{0x3db40b20, 0x2a30, 0x4dbe, [8]byte{0x91, 0x7e, 0x77, 0x1d, 0xd2, 0x1d, 0xd0, 0x99}}
|
||||||
|
FOLDERID_AppDataDesktop = &KNOWNFOLDERID{0xb2c5e279, 0x7add, 0x439f, [8]byte{0xb2, 0x8c, 0xc4, 0x1f, 0xe1, 0xbb, 0xf6, 0x72}}
|
||||||
|
FOLDERID_AppDataDocuments = &KNOWNFOLDERID{0x7be16610, 0x1f7f, 0x44ac, [8]byte{0xbf, 0xf0, 0x83, 0xe1, 0x5f, 0x2f, 0xfc, 0xa1}}
|
||||||
|
FOLDERID_AppDataFavorites = &KNOWNFOLDERID{0x7cfbefbc, 0xde1f, 0x45aa, [8]byte{0xb8, 0x43, 0xa5, 0x42, 0xac, 0x53, 0x6c, 0xc9}}
|
||||||
|
FOLDERID_AppDataProgramData = &KNOWNFOLDERID{0x559d40a3, 0xa036, 0x40fa, [8]byte{0xaf, 0x61, 0x84, 0xcb, 0x43, 0x0a, 0x4d, 0x34}}
|
||||||
|
)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user