From 151757c2fe7268aa55f4eb6b315682594aae85e9 Mon Sep 17 00:00:00 2001 From: Sakurasan <26715255+Sakurasan@users.noreply.github.com> Date: Sun, 21 Apr 2024 00:27:35 +0800 Subject: [PATCH 1/5] gemini --- go.mod | 46 +++++++-- go.sum | 216 +++++++++++++++++++++++++++++------------ pkg/google/chat.go | 237 +++++++++++++++++++++++++++++++++++++++++++++ pkg/openai/chat.go | 5 + router/router.go | 23 +++++ 5 files changed, 457 insertions(+), 70 deletions(-) create mode 100644 pkg/google/chat.go diff --git a/go.mod b/go.mod index ab27f47..1f88120 100644 --- a/go.mod +++ b/go.mod @@ -1,36 +1,56 @@ module opencatd-open -go 1.20 +go 1.21 + +toolchain go1.21.9 require ( + cloud.google.com/go/vertexai v0.7.1 github.com/Sakurasan/to v0.0.0-20180919163141-e72657dd7c7d github.com/duke-git/lancet/v2 v2.2.7 github.com/faiface/beep v1.1.0 github.com/gin-gonic/gin v1.9.1 github.com/glebarez/sqlite v1.10.0 github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/google/uuid v1.4.0 + github.com/google/generative-ai-go v0.11.0 + github.com/google/uuid v1.6.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkoukk/tiktoken-go v0.1.6 github.com/sashabaranov/go-openai v1.17.9 + golang.org/x/oauth2 v0.19.0 + google.golang.org/api v0.173.0 gopkg.in/vansante/go-ffprobe.v2 v2.1.1 gorm.io/gorm v1.25.5 ) require ( + cloud.google.com/go v0.112.1 // indirect + cloud.google.com/go/ai v0.3.5-0.20240409161017-ce55ad694f21 // indirect + cloud.google.com/go/aiplatform v1.60.0 // indirect + cloud.google.com/go/compute v1.24.0 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v1.1.6 // indirect + cloud.google.com/go/longrunning v0.5.6 // indirect github.com/bytedance/sonic v1.10.2 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect github.com/dlclark/regexp2 v1.10.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/glebarez/go-sqlite v1.21.2 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.3 // indirect github.com/hajimehoshi/go-mp3 v0.3.4 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect @@ -45,13 +65,25 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect golang.org/x/arch v0.6.0 // indirect - golang.org/x/crypto v0.16.0 // indirect + golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/net v0.22.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240325203815-454cdb8f5daa // indirect + google.golang.org/grpc v1.62.1 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/libc v1.35.0 // indirect modernc.org/mathutil v1.6.0 // indirect diff --git a/go.sum b/go.sum index 7f5467b..0308890 100644 --- a/go.sum +++ b/go.sum @@ -1,36 +1,56 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= +cloud.google.com/go/ai v0.3.5-0.20240409161017-ce55ad694f21 h1:kSJt55RNa+qATWnX2xjyq9S2YGDxxBwpmUVZNuFLOi0= +cloud.google.com/go/ai v0.3.5-0.20240409161017-ce55ad694f21/go.mod h1:iX72tmUodGXVDxRDCGUZEPiB9HaMeERXkOdgCkUi8sA= +cloud.google.com/go/aiplatform v1.60.0 h1:0cSrii1ZeLr16MbBoocyy5KVnrSdiQ3KN/vtrTe7RqE= +cloud.google.com/go/aiplatform v1.60.0/go.mod h1:eTlGuHOahHprZw3Hio5VKmtThIOak5/qy6pzdsqcQnM= +cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= +cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/longrunning v0.5.6 h1:xAe8+0YaWoCKr9t1+aWe+OeQgN/iJK1fEgZSXmjuEaE= +cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA= +cloud.google.com/go/vertexai v0.7.1 h1:CSdqsEwjklLIlI1e5SrsnkwG/I+CeJekkBbMTzeYhVg= +cloud.google.com/go/vertexai v0.7.1/go.mod h1:HfnfYR9aPS+qF2436S6Hzuw0Fp+PORjzK3ggqymdzSU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/Sakurasan/to v0.0.0-20180919163141-e72657dd7c7d h1:3v1QFdgk450QH+7C+lw1k+olbjK4fKGsrEfnEG/HLkY= github.com/Sakurasan/to v0.0.0-20180919163141-e72657dd7c7d/go.mod h1:2sp0vsMyh5sqmKl5N+ps/cSspqLkoXUlesSzsufIGRU= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.2 h1:GDaNjuWSGu09guE9Oql0MSTNhNCLlWwO8y/xM5BzcbM= -github.com/bytedance/sonic v1.9.2/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/duke-git/lancet/v2 v2.2.3 h1:Lj4iWgvEbgktEjAfqxE1G2BoGm1mL7l3QHBlXRYptjE= -github.com/duke-git/lancet/v2 v2.2.3/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc= github.com/duke-git/lancet/v2 v2.2.7 h1:u9zr6HR+MDUvZEtTlAFtSTIgZfEFsN7cKi27n5weZsw= github.com/duke-git/lancet/v2 v2.2.7/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/faiface/beep v1.1.0 h1:A2gWP6xf5Rh7RG/p9/VAW2jRSDEGQm5sbOb38sf5d4c= github.com/faiface/beep v1.1.0/go.mod h1:6I8p6kK2q4opL/eWb+kAkk38ehnTunWeToJB+s51sT4= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= @@ -41,37 +61,66 @@ github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= -github.com/glebarez/sqlite v1.8.0 h1:02X12E2I/4C1n+v90yTqrjRa8yuo7c3KeHI3FRznCvc= -github.com/glebarez/sqlite v1.8.0/go.mod h1:bpET16h1za2KOOMb8+jCp6UBP/iahDpfPQqSaYLTLx8= github.com/glebarez/sqlite v1.10.0 h1:u4gt8y7OND/cCei/NMHmfbLxF6xP2wgKcT/BJf2pYkc= github.com/glebarez/sqlite v1.10.0/go.mod h1:IJ+lfSOmiekhQsFTJRx/lHtGYmCdtAiTaf5wI9u5uHA= github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs= github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498= github.com/go-audio/wav v1.0.0/go.mod h1:3yoReyQOsiARkvPl3ERCi8JFjihzG6WhjYpZCf5zAWE= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= -github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE= github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/generative-ai-go v0.11.0 h1:+wL9xu5jVIgJKC6NmZOxZsBYWDtIap7DGUZ1diQSSnk= +github.com/google/generative-ai-go v0.11.0/go.mod h1:RauvbBjc+AzW0b1LV0VSlxHI5n2i3dz8oJfjboOSiWQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hajimehoshi/go-mp3 v0.3.0 h1:fTM5DXjp/DL2G74HHAs/aBGiS9Tg7wnp+jkU38bHy4g= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/hajimehoshi/go-mp3 v0.3.0/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM= github.com/hajimehoshi/go-mp3 v0.3.4 h1:NUP7pBYH8OguP4diaTZ9wJbUbk3tC0KlfzsEpWmYj68= github.com/hajimehoshi/go-mp3 v0.3.4/go.mod h1:fRtZraRFcWb0pu7ok0LqyFhCUrPeMsGRSVop0eemFmo= @@ -89,16 +138,12 @@ github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -111,23 +156,18 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkoukk/tiktoken-go v0.1.4 h1:bniMzWdUvNO6YkRbASo2x5qJf2LAG/TIJojqz+Igm8E= -github.com/pkoukk/tiktoken-go v0.1.4/go.mod h1:9NiV+i9mJKGj1rYOT+njbv+ZwA/zJxYdewGl6qVatpg= github.com/pkoukk/tiktoken-go v0.1.6 h1:JF0TlJzhTbrI30wCvFuiw6FzP2+/bR+FIxUdgEAcUsw= github.com/pkoukk/tiktoken-go v0.1.6/go.mod h1:9NiV+i9mJKGj1rYOT+njbv+ZwA/zJxYdewGl6qVatpg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/sashabaranov/go-openai v1.13.0 h1:EAusFfnhaMaaUspUZ2+MbB/ZcVeD4epJmTOlZ+8AcAE= -github.com/sashabaranov/go-openai v1.13.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/sashabaranov/go-openai v1.17.9 h1:QEoBiGKWW68W79YIfXWEFZ7l5cEgZBV4/Ow3uy+5hNY= github.com/sashabaranov/go-openai v1.17.9/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -139,56 +179,112 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= -golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw= -golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= -golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= +golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/api v0.173.0 h1:fz6B7GWYWLS/HfruiTsRYVKQQApJ6vasTYWAK6+Qo8g= +google.golang.org/api v0.173.0/go.mod h1:ins7pTzjeBPQ3SdC/plzki6d/dQWwAWy8qVZ4Vgkzl8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= +google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda h1:b6F6WIV4xHHD0FA4oIyzU6mHWg2WI2X1RBehwa5QN38= +google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda/go.mod h1:AHcE/gZH76Bk/ROZhQphlRoWo5xKDEtz3eVEO1LfA8c= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240325203815-454cdb8f5daa h1:RBgMaUMP+6soRkik4VoN8ojR2nex2TqZwjSSogic+eo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240325203815-454cdb8f5daa/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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/vansante/go-ffprobe.v2 v2.1.1 h1:DIh5fMn+tlBvG7pXyUZdemVmLdERnf2xX6XOFF+0BBU= @@ -196,22 +292,16 @@ gopkg.in/vansante/go-ffprobe.v2 v2.1.1/go.mod h1:qF0AlAjk7Nqzqf3y333Ly+KxN3cKF2J gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho= -gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= -modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= modernc.org/libc v1.35.0 h1:EQ4szx6Q/QLZuysmAnI4dfRnKbAbNlENp23ruvTJ2nE= modernc.org/libc v1.35.0/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= -modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o= -modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= -modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM= -modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= modernc.org/sqlite v1.27.0 h1:MpKAHoyYB7xqcwnUwkuD+npwEa0fojF0B5QRbN+auJ8= modernc.org/sqlite v1.27.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/pkg/google/chat.go b/pkg/google/chat.go new file mode 100644 index 0000000..7c066c1 --- /dev/null +++ b/pkg/google/chat.go @@ -0,0 +1,237 @@ +package google + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/http" + "opencatd-open/pkg/openai" + "opencatd-open/pkg/tokenizer" + "opencatd-open/store" + "strings" + + "github.com/gin-gonic/gin" + "github.com/google/generative-ai-go/genai" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +type GeminiChatRequest struct { + Contents []GeminiContent `json:"contents,omitempty"` +} + +func (g GeminiChatRequest) ByteJson() []byte { + bytejson, _ := json.Marshal(g) + return bytejson +} + +type GeminiContent struct { + Role string `json:"role,omitempty"` + Parts []GeminiPart `json:"parts,omitempty"` +} +type GeminiPart struct { + Text string `json:"text,omitempty"` + // InlineData GeminiPartInlineData `json:"inlineData,omitempty"` +} +type GeminiPartInlineData struct { + MimeType string `json:"mimeType,omitempty"` + Data string `json:"data,omitempty"` // base64 +} + +type GeminiResponse struct { + Candidates []struct { + Content struct { + Parts []struct { + Text string `json:"text"` + } `json:"parts"` + Role string `json:"role"` + } `json:"content"` + FinishReason string `json:"finishReason"` + Index int `json:"index"` + SafetyRatings []struct { + Category string `json:"category"` + Probability string `json:"probability"` + } `json:"safetyRatings"` + } `json:"candidates"` + PromptFeedback struct { + SafetyRatings []struct { + Category string `json:"category"` + Probability string `json:"probability"` + } `json:"safetyRatings"` + } `json:"promptFeedback"` + Error struct { + Code int `json:"code"` + Message string `json:"message"` + Status string `json:"status"` + Details []struct { + Type string `json:"@type"` + FieldViolations []struct { + Field string `json:"field"` + Description string `json:"description"` + } `json:"fieldViolations"` + } `json:"details"` + } `json:"error"` +} + +func ChatProxy(c *gin.Context, chatReq *openai.ChatCompletionRequest) { + usagelog := store.Tokens{Model: chatReq.Model} + + token, _ := c.Get("localuser") + + lu, err := store.GetUserByToken(token.(string)) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "error": gin.H{ + "message": err.Error(), + }, + }) + return + } + usagelog.UserID = int(lu.ID) + var prompts []genai.Part + var prompt string + for _, msg := range chatReq.Messages { + var visioncontent []openai.VisionContent + if err := json.Unmarshal(msg.Content, &visioncontent); err != nil { + prompt += "<" + msg.Role + ">: " + string(msg.Content) + "\n" + prompts = append(prompts, genai.Text("<"+msg.Role+">: "+string(msg.Content))) + } else { + if len(visioncontent) > 0 { + for _, content := range visioncontent { + if content.Type == "text" { + prompt += "<" + msg.Role + ">: " + content.Text + "\n" + prompts = append(prompts, genai.Text("<"+msg.Role+">: "+content.Text)) + } else if content.Type == "image_url" { + if strings.HasPrefix(content.ImageURL.URL, "http") { + fmt.Println("链接:", content.ImageURL.URL) + } else if strings.HasPrefix(content.ImageURL.URL, "data:image") { + fmt.Println("base64:", content.ImageURL.URL[:20]) + if chatReq.Model != "gemini-pro-vision" { + chatReq.Model = "gemini-pro-vision" + } + + var mime string + // openai 会以 data:image 开头,则去掉 data:image/png;base64, 和 data:image/jpeg;base64, + if strings.HasPrefix(content.ImageURL.URL, "data:image/png") { + mime = "image/png" + } else if strings.HasPrefix(content.ImageURL.URL, "data:image/jpeg") { + mime = "image/jpeg" + } else { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Unsupported image format"}) + return + } + imageString := strings.Split(content.ImageURL.URL, ",")[1] + imageBytes, err := base64.StdEncoding.DecodeString(imageString) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + prompts = append(prompts, genai.Blob{MIMEType: mime, Data: imageBytes}) + } + + // todo image tokens + } + + } + + } + } + if len(chatReq.Tools) > 0 { + tooljson, _ := json.Marshal(chatReq.Tools) + prompt += ": " + string(tooljson) + "\n" + + // for _, tool := range chatReq.Tools { + + // } + + } + } + + usagelog.PromptCount = tokenizer.NumTokensFromStr(prompt, chatReq.Model) + + onekey, err := store.SelectKeyCache("google") + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx := context.Background() + + client, err := genai.NewClient(ctx, option.WithAPIKey(onekey.Key)) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + defer client.Close() + + model := client.GenerativeModel(chatReq.Model) + + iter := model.GenerateContentStream(ctx, prompts...) + datachan := make(chan string) + // closechan := make(chan error) + var result string + go func() { + for { + resp, err := iter.Next() + if err == iterator.Done { + + var chatResp openai.ChatCompletionStreamResponse + chatResp.Model = chatReq.Model + chatResp.Choices[0].FinishReason = "stop" + datachan <- "data: " + string(chatResp.ByteJson()) + close(datachan) + break + } + if err != nil { + var errResp openai.ErrResponse + errResp.Error.Code = "500" + errResp.Error.Message = err.Error() + datachan <- string(errResp.ByteJson()) + close(datachan) + break + } + var content string + if resp.Candidates != nil && len(resp.Candidates) > 0 && len(resp.Candidates[0].Content.Parts) > 0 { + if s, ok := resp.Candidates[0].Content.Parts[0].(genai.Text); ok { + content = string(s) + result += content + } + } else { + continue + } + + var chatResp openai.ChatCompletionStreamResponse + chatResp.Model = chatReq.Model + chatResp.Choices[0].Delta.Role = resp.Candidates[0].Content.Role + chatResp.Choices[0].Delta.Content = content + chunk := "data: " + string(chatResp.ByteJson()) + "\n\n" + datachan <- chunk + } + }() + + c.Writer.Header().Set("Content-Type", "text/event-stream") + c.Writer.Header().Set("Cache-Control", "no-cache") + c.Writer.Header().Set("Connection", "keep-alive") + c.Writer.Header().Set("Transfer-Encoding", "chunked") + c.Writer.Header().Set("X-Accel-Buffering", "no") + + c.Stream(func(w io.Writer) bool { + if data, ok := <-datachan; ok { + if strings.HasPrefix(data, "data: ") { + c.Writer.WriteString(data) + // c.Writer.WriteString("\n\n") + } else { + c.Writer.WriteHeader(http.StatusBadGateway) + c.Writer.WriteString(data) + } + c.Writer.Flush() + return true + } + go func() { + + }() + return false + }) +} diff --git a/pkg/openai/chat.go b/pkg/openai/chat.go index 7d3ba6d..b7270b7 100644 --- a/pkg/openai/chat.go +++ b/pkg/openai/chat.go @@ -328,3 +328,8 @@ type ErrResponse struct { Code string `json:"code"` } `json:"error"` } + +func (e *ErrResponse) ByteJson() []byte { + bytejson, _ := json.Marshal(e) + return bytejson +} diff --git a/router/router.go b/router/router.go index af2b2c1..7e639e4 100644 --- a/router/router.go +++ b/router/router.go @@ -325,6 +325,29 @@ func HandleAddKey(c *gin.Context) { }}) return } + } else if strings.HasPrefix(body.Name, "google.") { + keynames := strings.Split(body.Name, ".") + if len(keynames) < 2 { + c.JSON(http.StatusBadRequest, gin.H{"error": gin.H{ + "message": "Invalid Key Name", + }}) + return + } + + k := &store.Key{ + // ApiType: "anthropic", + ApiType: "google", + Name: body.Name, + Key: body.Key, + ResourceNmae: keynames[1], + EndPoint: body.Endpoint, + } + if err := store.CreateKey(k); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": gin.H{ + "message": err.Error(), + }}) + return + } } else { if body.ApiType == "" { if err := store.AddKey("openai", body.Key, body.Name); err != nil { From 752053f7c4e4e3c3780ad08b8f51738b73ed4b9e Mon Sep 17 00:00:00 2001 From: Sakurasan <26715255+Sakurasan@users.noreply.github.com> Date: Sun, 21 Apr 2024 00:54:57 +0800 Subject: [PATCH 2/5] up --- .gitignore | 1 + docker/Dockerfile | 4 ++-- pkg/tokenizer/tokenizer.go | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index e0f0e0c..2312a81 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ bin/ test/ *.log *.db +demo/ \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile index 5be92be..f11aa0d 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -3,7 +3,7 @@ WORKDIR /frontend-build COPY ./web/ . RUN npm install && npm run build && rm -rf node_modules -FROM golang:1.19-alpine as builder +FROM golang:1.21-alpine as builder LABEL anther="github.com/Sakurasan" RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && apk --no-cache add make cmake upx WORKDIR /build @@ -11,7 +11,7 @@ COPY --from=frontend /frontend-build/dist /build/dist COPY . /build ENV GO111MODULE=on # ENV GOPROXY=https://goproxy.cn,direct -CMD [ "go mod download" ] +CMD [ "go mod tidy","go mod download" ] RUN make build FROM alpine:latest AS runner diff --git a/pkg/tokenizer/tokenizer.go b/pkg/tokenizer/tokenizer.go index b1a6987..e68389f 100644 --- a/pkg/tokenizer/tokenizer.go +++ b/pkg/tokenizer/tokenizer.go @@ -155,7 +155,8 @@ func Cost(model string, promptCount, completionCount int) float64 { case "gemini-1.5-pro-latest": cost = (0.00025/1000)*float64(prompt) + (0.0005/1000)*float64(completion) - // Mistral AI + // Mistral AI + // https://docs.mistral.ai/platform/pricing/ case "mistral-small-latest": cost = (0.002/1000)*float64(prompt) + (0.006/1000)*float64(completion) case "mistral-medium-latest": From 08ce7e2a4b8d4a95c46435a749c23b428e75ae5a Mon Sep 17 00:00:00 2001 From: Sakurasan <26715255+Sakurasan@users.noreply.github.com> Date: Sun, 21 Apr 2024 01:40:42 +0800 Subject: [PATCH 3/5] up --- router/chat.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/router/chat.go b/router/chat.go index f132428..8d2cd8f 100644 --- a/router/chat.go +++ b/router/chat.go @@ -5,6 +5,7 @@ import ( "strings" "opencatd-open/pkg/claude" + "opencatd-open/pkg/google" "opencatd-open/pkg/openai" "github.com/gin-gonic/gin" @@ -26,4 +27,9 @@ func ChatHandler(c *gin.Context) { claude.ChatProxy(c, &chatreq) return } + + if strings.HasPrefix(chatreq.Model, "gemini") { + google.ChatProxy(c, &chatreq) + return + } } From 3db8ebe34e41c227cb940dc5b3c80f2b0047c18b Mon Sep 17 00:00:00 2001 From: Sakurasan <26715255+Sakurasan@users.noreply.github.com> Date: Tue, 23 Apr 2024 01:19:25 +0800 Subject: [PATCH 4/5] fix: nil pointer --- pkg/google/chat.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pkg/google/chat.go b/pkg/google/chat.go index 7c066c1..034bdea 100644 --- a/pkg/google/chat.go +++ b/pkg/google/chat.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io" + "log" "net/http" "opencatd-open/pkg/openai" "opencatd-open/pkg/tokenizer" @@ -179,12 +180,15 @@ func ChatProxy(c *gin.Context, chatReq *openai.ChatCompletionRequest) { var chatResp openai.ChatCompletionStreamResponse chatResp.Model = chatReq.Model - chatResp.Choices[0].FinishReason = "stop" + choice := openai.Choice{} + choice.FinishReason = "stop" + chatResp.Choices = append(chatResp.Choices, choice) datachan <- "data: " + string(chatResp.ByteJson()) close(datachan) break } if err != nil { + log.Println(err) var errResp openai.ErrResponse errResp.Error.Code = "500" errResp.Error.Message = err.Error() @@ -204,8 +208,11 @@ func ChatProxy(c *gin.Context, chatReq *openai.ChatCompletionRequest) { var chatResp openai.ChatCompletionStreamResponse chatResp.Model = chatReq.Model - chatResp.Choices[0].Delta.Role = resp.Candidates[0].Content.Role - chatResp.Choices[0].Delta.Content = content + choice := openai.Choice{} + choice.Delta.Role = resp.Candidates[0].Content.Role + choice.Delta.Content = content + chatResp.Choices = append(chatResp.Choices, choice) + chunk := "data: " + string(chatResp.ByteJson()) + "\n\n" datachan <- chunk } From 0d01ab4617767351d60511801dd64ca7daab3ef0 Mon Sep 17 00:00:00 2001 From: Sakurasan <26715255+Sakurasan@users.noreply.github.com> Date: Tue, 23 Apr 2024 01:45:03 +0800 Subject: [PATCH 5/5] update doc --- doc/gemini.md | 6 ++++++ doc/gemini_key.jpg | Bin 0 -> 39611 bytes 2 files changed, 6 insertions(+) create mode 100644 doc/gemini.md create mode 100644 doc/gemini_key.jpg diff --git a/doc/gemini.md b/doc/gemini.md new file mode 100644 index 0000000..ca1b57d --- /dev/null +++ b/doc/gemini.md @@ -0,0 +1,6 @@ +## 添加ApiKey + gemini的"ApiType":"google" + + 或者使用 google.xxxx 的apikey名称 添加 +![gemini key](./gemini_key.jpg) + \ No newline at end of file diff --git a/doc/gemini_key.jpg b/doc/gemini_key.jpg new file mode 100644 index 0000000000000000000000000000000000000000..32c65fb94f4a9201c59b1cc819ab441fc11b5f62 GIT binary patch literal 39611 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 L{<~cNXY_vnZ5eZT literal 0 HcmV?d00001