This is an automated email from the ASF dual-hosted git repository.
alexstocks pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/dubbo-go-samples.git
The following commit(s) were added to refs/heads/main by this push:
new c144f4a0 Functional implementation of the llm example (#802)
c144f4a0 is described below
commit c144f4a01dcf540d177738e0da73b5c5fe91cb8d
Author: Alan <[email protected]>
AuthorDate: Sat Mar 8 20:36:00 2025 +0800
Functional implementation of the llm example (#802)
* rename idl
* implement multi-turn conversation
* create inner func to use defer to close stream
* web page of llm chat bot
* web page of llm chat bot
* nil pointer bug
* nil pointer bug fix and change dir management
* bin file upload
* update readme
* add licences
* update readme
* update readme
* fix typo
* go import fmt & modify Chinese comment
* Wrapping some of the functionality from chat.go to context.go
---
go.mod | 32 +++-
go.sum | 73 ++++++--
llm/README.md | 16 +-
llm/README_zh.md | 13 ++
llm/go-client/cmd/client.go | 144 +++++++++++++--
llm/go-client/frontend/handlers/chat.go | 208 +++++++++++++++++++++
llm/go-client/frontend/main.go | 77 ++++++++
llm/go-client/frontend/service/context.go | 84 +++++++++
llm/go-client/frontend/static/file.png | Bin 0 -> 7952 bytes
llm/go-client/frontend/static/script.js | 209 +++++++++++++++++++++
llm/go-client/frontend/static/style.css | 238 ++++++++++++++++++++++++
llm/go-client/frontend/templates/index.html | 49 +++++
llm/go-server/cmd/server.go | 89 ++++++---
llm/proto/chat.pb.go | 269 ++++++++++++++++++++++++++++
llm/proto/{greet.proto => chat.proto} | 20 ++-
llm/proto/chat.triple.go | 177 ++++++++++++++++++
llm/proto/greet.pb.go | 197 --------------------
llm/proto/greet.triple.go | 177 ------------------
18 files changed, 1625 insertions(+), 447 deletions(-)
diff --git a/go.mod b/go.mod
index 889d0db2..a5f6658b 100644
--- a/go.mod
+++ b/go.mod
@@ -10,6 +10,8 @@ require (
github.com/dubbogo/gost v1.14.0
github.com/dubbogo/grpc-go v1.42.10
github.com/dubbogo/triple v1.2.2-rc3
+ github.com/gin-contrib/sessions v1.0.2
+ github.com/gin-gonic/gin v1.10.0
github.com/gogo/protobuf v1.3.2
github.com/golang/protobuf v1.5.4
github.com/nacos-group/nacos-sdk-go/v2 v2.2.2
@@ -38,9 +40,13 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
+ github.com/bytedance/sonic v1.11.6 // indirect
+ github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/cloudwego/base64x v0.1.4 // indirect
+ github.com/cloudwego/iasm v0.2.0 // indirect
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect
github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50 // indirect
github.com/coreos/go-semver v0.3.0 // indirect
@@ -53,19 +59,25 @@ require (
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
github.com/envoyproxy/go-control-plane v0.12.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
+ github.com/gabriel-vasile/mimetype v1.4.3 // indirect
+ github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-co-op/gocron v1.9.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // 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.12.0 // indirect
+ github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/go-resty/resty/v2 v2.7.0 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
+ github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
github.com/google/uuid v1.6.0 // indirect
+ github.com/gorilla/context v1.1.2 // indirect
+ github.com/gorilla/securecookie v1.1.2 // indirect
+ github.com/gorilla/sessions v1.2.2 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
@@ -77,8 +89,9 @@ require (
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/k0kubun/pp v3.0.1+incompatible // indirect
+ github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/knadh/koanf v1.5.0 // indirect
- github.com/leodido/go-urn v1.2.2 // indirect
+ github.com/leodido/go-urn v1.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 //
indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
@@ -95,6 +108,7 @@ require (
github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 //
indirect
github.com/opentracing-contrib/go-observer
v0.0.0-20170622124052-a52f23424492 // indirect
github.com/pelletier/go-toml v1.9.3 // indirect
+ github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pkoukk/tiktoken-go v0.1.6 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
@@ -110,8 +124,9 @@ require (
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
+ github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
- github.com/ugorji/go/codec v1.2.6 // indirect
+ github.com/ugorji/go/codec v1.2.12 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.etcd.io/etcd/api/v3 v3.5.7 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect
@@ -128,12 +143,13 @@ require (
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
- golang.org/x/crypto v0.29.0 // indirect
- golang.org/x/net v0.25.0 // indirect
+ golang.org/x/arch v0.8.0 // indirect
+ golang.org/x/crypto v0.31.0 // indirect
+ golang.org/x/net v0.33.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
- golang.org/x/sync v0.9.0 // indirect
- golang.org/x/sys v0.27.0 // indirect
- golang.org/x/text v0.20.0 // indirect
+ golang.org/x/sync v0.10.0 // indirect
+ golang.org/x/sys v0.28.0 // indirect
+ golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/genproto/googleapis/api
v0.0.0-20240604185151-ef581f913117 // indirect
google.golang.org/genproto/googleapis/rpc
v0.0.0-20240604185151-ef581f913117 // indirect
diff --git a/go.sum b/go.sum
index 90aa9945..5a9d56e9 100644
--- a/go.sum
+++ b/go.sum
@@ -124,6 +124,10 @@ github.com/bketelsen/crypt
v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod
h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/buger/jsonparser v1.1.1
h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod
h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
+github.com/bytedance/sonic v1.11.6
h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
+github.com/bytedance/sonic v1.11.6/go.mod
h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
+github.com/bytedance/sonic/loader v0.1.1
h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
+github.com/bytedance/sonic/loader v0.1.1/go.mod
h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/casbin/casbin/v2 v2.1.2/go.mod
h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod
h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff/v4 v4.2.1
h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
@@ -147,6 +151,10 @@ github.com/circonus-labs/circonus-gometrics
v2.3.1+incompatible/go.mod h1:nmEj6D
github.com/circonus-labs/circonusllhist v0.1.3/go.mod
h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod
h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod
h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudwego/base64x v0.1.4
h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
+github.com/cloudwego/base64x v0.1.4/go.mod
h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
+github.com/cloudwego/iasm v0.2.0
h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
+github.com/cloudwego/iasm v0.2.0/go.mod
h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod
h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod
h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod
h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
@@ -268,8 +276,16 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod
h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4
github.com/fsnotify/fsnotify v1.5.4/go.mod
h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0
h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod
h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+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/getsentry/raven-go v0.2.0/go.mod
h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/ghodss/yaml v1.0.0/go.mod
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gin-contrib/sessions v1.0.2
h1:UaIjUvTH1cMeOdj3in6dl+Xb6It8RiKRF9Z1anbUyCA=
+github.com/gin-contrib/sessions v1.0.2/go.mod
h1:KxKxWqWP5LJVDCInulOl4WbLzK2KSPlLesfZ66wRvMs=
+github.com/gin-contrib/sse v0.1.0
h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
+github.com/gin-contrib/sse v0.1.0/go.mod
h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.10.0
h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
+github.com/gin-gonic/gin v1.10.0/go.mod
h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/glycerine/go-unsnap-stream
v0.0.0-20181221182339-f9677308dec2/go.mod
h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod
h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod
h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
@@ -309,8 +325,8 @@ github.com/go-playground/universal-translator
v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
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.11.0/go.mod
h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
-github.com/go-playground/validator/v10 v10.12.0
h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI=
-github.com/go-playground/validator/v10 v10.12.0/go.mod
h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA=
+github.com/go-playground/validator/v10 v10.20.0
h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
+github.com/go-playground/validator/v10 v10.20.0/go.mod
h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-resty/resty/v2 v2.7.0
h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
github.com/go-resty/resty/v2 v2.7.0/go.mod
h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible
h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
@@ -320,6 +336,8 @@ github.com/go-stack/stack v1.8.0/go.mod
h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod
h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod
h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.2/go.mod
h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
+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/godbus/dbus/v5 v5.0.3/go.mod
h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod
h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/googleapis v1.1.0/go.mod
h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
@@ -400,6 +418,8 @@ github.com/google/go-cmp v0.5.9/go.mod
h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
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/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod
h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod
h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod
h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod
h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -424,11 +444,17 @@ github.com/gopherjs/gopherjs
v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99
h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod
h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod
h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/context v1.1.2
h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
+github.com/gorilla/context v1.1.2/go.mod
h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM=
github.com/gorilla/mux v1.6.2/go.mod
h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod
h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.0/go.mod
h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/securecookie v1.1.1/go.mod
h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
+github.com/gorilla/securecookie v1.1.2
h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
+github.com/gorilla/securecookie v1.1.2/go.mod
h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
github.com/gorilla/sessions v1.2.1/go.mod
h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
+github.com/gorilla/sessions v1.2.2
h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
+github.com/gorilla/sessions v1.2.2/go.mod
h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod
h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2
h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod
h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@@ -570,9 +596,13 @@ github.com/kisielk/errcheck v1.2.0/go.mod
h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
github.com/kisielk/errcheck v1.5.0/go.mod
h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod
h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6/go.mod
h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod
h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.7
h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
+github.com/klauspost/cpuid/v2 v2.2.7/go.mod
h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knadh/koanf v1.4.1/go.mod
h1:1cfH5223ZeZUOs8FU2UdTmaNfHpqgtjV0+NHjRO43gs=
github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs=
github.com/knadh/koanf v1.5.0/go.mod
h1:Hgyjp4y8v44hpZtPzs7JZfRAW5AhN7KfZcwv1RYggDs=
+github.com/knz/go-libedit v1.10.1/go.mod
h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7/go.mod
h1:Y2SaZf2Rzd0pXkLVhLlCiAXFCLSXAIbTKDivVgff/AM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod
h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod
h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -588,8 +618,8 @@ github.com/kr/text v0.1.0/go.mod
h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod
h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.1/go.mod
h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
-github.com/leodido/go-urn v1.2.2
h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4=
-github.com/leodido/go-urn v1.2.2/go.mod
h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ=
+github.com/leodido/go-urn v1.4.0
h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/leodido/go-urn v1.4.0/go.mod
h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570/go.mod
h1:BLt8L9ld7wVsvEWQbuLrUZnCMnUmLZ+CGDzKtclrTlE=
github.com/lestrrat/go-file-rotatelogs
v0.0.0-20180223000712-d3151e2a480f/go.mod
h1:UGmTpUd3rjbtfIpwAPrcfmGf/Z1HS95TATB+m57TPB8=
github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod
h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0=
@@ -715,6 +745,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod
h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
github.com/pelletier/go-toml v1.7.0/go.mod
h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pelletier/go-toml v1.9.3
h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
github.com/pelletier/go-toml v1.9.3/go.mod
h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/pelletier/go-toml/v2 v2.2.2
h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod
h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod
h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/philhofer/fwd v1.0.0/go.mod
h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod
h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
@@ -804,7 +836,6 @@ github.com/rogpeppe/go-internal v1.8.0/go.mod
h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6po
github.com/rogpeppe/go-internal v1.11.0
h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod
h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.0.1/go.mod
h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod
h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod
h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod
h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0/go.mod
h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
@@ -872,7 +903,7 @@ github.com/stretchr/testify v1.6.1/go.mod
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod
h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.2/go.mod
h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.1/go.mod
h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod
h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0
h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod
h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
@@ -898,14 +929,17 @@ github.com/tmc/langchaingo v0.1.13
h1:rcpMWBIi2y3B90XxfE4Ao8dhCQPVDMaNPnN5cGB1Ca
github.com/tmc/langchaingo v0.1.13/go.mod
h1:vpQ5NOIhpzxDfTZK9B6tf2GM/MoaHewPWM5KXXGh7hg=
github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3/go.mod
h1:QDlpd3qS71vYtakd2hmdpqhJ9nwv6mD6A30bQ1BPBFE=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod
h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
+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/uber/jaeger-client-go v2.29.1+incompatible/go.mod
h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-client-go v2.30.0+incompatible
h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod
h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.4.1+incompatible
h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod
h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ugorji/go v1.2.6/go.mod
h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
-github.com/ugorji/go/codec v1.2.6
h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
github.com/ugorji/go/codec v1.2.6/go.mod
h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
+github.com/ugorji/go/codec v1.2.12
h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
+github.com/ugorji/go/codec v1.2.12/go.mod
h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/urfave/cli v1.20.0/go.mod
h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod
h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.3.0/go.mod
h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
@@ -1011,6 +1045,9 @@ go.uber.org/zap v1.17.0/go.mod
h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod
h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
+golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod
h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod
h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -1026,8 +1063,8 @@ golang.org/x/crypto
v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod
h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod
h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod
h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
-golang.org/x/crypto v0.29.0/go.mod
h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod
h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1124,8 +1161,8 @@ golang.org/x/net
v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod
h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod
h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod
h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
-golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod
h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod
h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod
h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1148,8 +1185,8 @@ golang.org/x/sync
v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
-golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod
h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1235,12 +1272,13 @@ golang.org/x/sys
v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
-golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod
h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod
h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod
h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1253,8 +1291,8 @@ golang.org/x/text v0.3.5/go.mod
h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
-golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
-golang.org/x/text v0.20.0/go.mod
h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod
h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod
h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod
h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod
h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1504,6 +1542,7 @@ honnef.co/go/tools
v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod
h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod
h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod
h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+nullprogram.com/x/optparse v1.0.0/go.mod
h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/binaryregexp v0.2.0/go.mod
h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
diff --git a/llm/README.md b/llm/README.md
index 06a70f8a..ed909b81 100644
--- a/llm/README.md
+++ b/llm/README.md
@@ -36,6 +36,11 @@ $ ollama run deepseek-r1:1.5b
## 3. **Run the Example**
+You need to run all the commands in ```llm``` directory.
+
+```shell
+$ cd llm
+```
### **Run the Server**
The server integrates the Ollama model and uses Dubbo-go's RPC service for
invocation.
@@ -50,9 +55,18 @@ $ go run llm/go-server/cmd/server.go
The client invokes the server's RPC interface to retrieve the inference
results from the Ollama model.
-Run the client by executing:
+Run the cli client by executing:
```shell
$ go run llm/go-client/cmd/client.go
```
+Cli client supports multi-turn conversations, command interact, context
management.
+
+We also support a frontend using Gin framework for users to interact. If you
want run the frontend client you can executing the following command and open
it in ```localhost:8080``` by default:
+
+```shell
+$ go run llm/go-client/frontend/main.go
+```
+
+Frontend client supports multi-turn conversations, binary file (image) support
for LLM interactions.
diff --git a/llm/README_zh.md b/llm/README_zh.md
index 537d75fa..7f81488f 100644
--- a/llm/README_zh.md
+++ b/llm/README_zh.md
@@ -36,6 +36,11 @@ $ ollama run deepseek-r1:1.5b
## **3. 运行示例**
+以下所有的命令都需要在```llm``` 目录下运行.
+
+```shell
+$ cd llm
+```
### **服务端运行**
在服务端中集成 Ollama 模型,并使用 Dubbo-go 提供的 RPC 服务进行调用。
@@ -56,5 +61,13 @@ $ go run llm/go-server/cmd/server.go
$ go run llm/go-client/cmd/client.go
```
+命令行客户端支持多轮对话、命令交互、上下文管理功能。
+
+我们也提供了包含前端页面的基于Gin框架的客户端进行交互,运行以下命令然后访问 ```localhost:8080``` 即可使用:
+
+```shell
+$ go run llm/go-client/frontend/main.go
+```
+包含前端页面的客户端支持多轮对话,支持进行二进制文件(图片)传输并与大模型进行交互.
diff --git a/llm/go-client/cmd/client.go b/llm/go-client/cmd/client.go
index defca61a..23411724 100644
--- a/llm/go-client/cmd/client.go
+++ b/llm/go-client/cmd/client.go
@@ -18,49 +18,155 @@
package main
import (
+ "bufio"
"context"
"fmt"
+ "os"
+ "strings"
)
import (
"dubbo.apache.org/dubbo-go/v3/client"
_ "dubbo.apache.org/dubbo-go/v3/imports"
+
+ chat "github.com/apache/dubbo-go-samples/llm/proto"
)
-import (
- greet "github.com/apache/dubbo-go-samples/llm/proto"
+type ChatContext struct {
+ ID string
+ History []*chat.ChatMessage
+}
+
+var (
+ contexts = make(map[string]*ChatContext)
+ currentCtxID string
+ contextOrder []string
+ maxID uint8 = 0
)
+func handleCommand(cmd string) (resp string) {
+ cmd = strings.TrimSpace(cmd)
+ resp = ""
+ switch {
+ case cmd == "/?" || cmd == "/help":
+ resp += "Available commands:\n"
+ resp += "/? help - Show this help\n"
+ resp += "/list - List all contexts\n"
+ resp += "/cd <context> - Switch context\n"
+ resp += "/new - Create new context"
+ return resp
+ case cmd == "/list":
+ fmt.Println("Stored contexts (max 3):")
+ for _, ctxID := range contextOrder {
+ resp += fmt.Sprintf("- %s\n", ctxID)
+ }
+ return resp
+ case strings.HasPrefix(cmd, "/cd "):
+ target := strings.TrimPrefix(cmd, "/cd ")
+ if ctx, exists := contexts[target]; exists {
+ currentCtxID = ctx.ID
+ resp += fmt.Sprintf("Switched to context: %s\n", target)
+ } else {
+ resp += "Context not found"
+ }
+ return resp
+ case cmd == "/new":
+ newID := createContext()
+ currentCtxID = newID
+ resp += fmt.Sprintf("Created new context: %s\n", newID)
+ return resp
+ default:
+ resp += "Available commands:\n"
+ resp += "/? help - Show this help\n"
+ resp += "/list - List all contexts\n"
+ resp += "/cd <context> - Switch context\n"
+ resp += "/new - Create new context"
+ return resp
+ }
+}
+
+func createContext() string {
+ id := fmt.Sprintf("ctx%d", maxID)
+ maxID++
+ contexts[id] = &ChatContext{
+ ID: id,
+ History: []*chat.ChatMessage{},
+ }
+ contextOrder = append(contextOrder, id)
+
+ // up to 3 context
+ if len(contextOrder) > 3 {
+ delete(contexts, contextOrder[0])
+ contextOrder = contextOrder[1:]
+ }
+ return id
+}
+
func main() {
+ currentCtxID = createContext()
+
cli, err := client.NewClient(
client.WithClientURL("tri://127.0.0.1:20000"),
)
if err != nil {
- fmt.Printf("Error creating client: %v\n", err)
- return
+ panic(err)
}
- svc, err := greet.NewGreetService(cli)
+ svc, err := chat.NewChatService(cli)
if err != nil {
fmt.Printf("Error creating service: %v\n", err)
return
}
- stream, err := svc.Greet(context.Background(), &greet.GreetRequest{
- Prompt: "Write a simple function to calculate fibonacci
sequence in Go",
- })
- if err != nil {
- fmt.Printf("Error calling service: %v\n", err)
- return
- }
- defer stream.Close()
+ fmt.Print("\nSend a message (/? for help)")
+ scanner := bufio.NewScanner(os.Stdin)
+ for {
+ fmt.Print("\n> ")
+ scanner.Scan()
+ input := scanner.Text()
- for stream.Recv() {
- fmt.Print(stream.Msg().Content)
- }
+ // handle command
+ if strings.HasPrefix(input, "/") {
+ fmt.Println(handleCommand(input))
+ continue
+ }
- if err := stream.Err(); err != nil {
- fmt.Printf("Stream error: %v\n", err)
- return
+ func() {
+ currentCtx := contexts[currentCtxID]
+ currentCtx.History = append(currentCtx.History,
+ &chat.ChatMessage{
+ Role: "human",
+ Content: input,
+ Bin: nil,
+ })
+
+ stream, err := svc.Chat(context.Background(),
&chat.ChatRequest{
+ Messages: currentCtx.History,
+ })
+ if err != nil {
+ panic(err)
+ }
+ defer stream.Close()
+
+ resp := ""
+
+ for stream.Recv() {
+ c := stream.Msg().Content
+ resp += c
+ fmt.Print(c)
+ }
+
+ if err := stream.Err(); err != nil {
+ fmt.Printf("Stream error: %v\n", err)
+ return
+ }
+
+ currentCtx.History = append(currentCtx.History,
+ &chat.ChatMessage{
+ Role: "ai",
+ Content: resp,
+ Bin: nil,
+ })
+ }()
}
}
diff --git a/llm/go-client/frontend/handlers/chat.go
b/llm/go-client/frontend/handlers/chat.go
new file mode 100644
index 00000000..2f62c520
--- /dev/null
+++ b/llm/go-client/frontend/handlers/chat.go
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package handlers
+
+import (
+ "context"
+ "io"
+ "log"
+ "net/http"
+ "runtime/debug"
+ "strings"
+ "time"
+)
+
+import (
+ "github.com/apache/dubbo-go-samples/llm/go-client/frontend/service"
+ chat "github.com/apache/dubbo-go-samples/llm/proto"
+
+ "github.com/gin-contrib/sessions"
+
+ "github.com/gin-gonic/gin"
+)
+
+type ChatHandler struct {
+ svc chat.ChatService
+ ctxManager *service.ContextManager
+}
+
+func NewChatHandler(svc chat.ChatService, mgr *service.ContextManager)
*ChatHandler {
+ return &ChatHandler{
+ svc: svc,
+ ctxManager: mgr,
+ }
+}
+
+func (h *ChatHandler) Index(c *gin.Context) {
+ session := sessions.Default(c)
+ ctxID := session.Get("current_context")
+ if ctxID == nil {
+ ctxID = h.ctxManager.CreateContext()
+ session.Set("current_context", ctxID)
+ session.Save()
+ }
+
+ c.HTML(http.StatusOK, "index.html", gin.H{
+ "title": "LLM Chat",
+ })
+}
+
+func (h *ChatHandler) Chat(c *gin.Context) {
+ session := sessions.Default(c)
+ ctxID, ok := session.Get("current_context").(string)
+ if !ok {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid session
context"})
+ return
+ }
+
+ var req struct {
+ Message string `json:"message"`
+ Bin string `json:"bin"`
+ }
+
+ if err := c.BindJSON(&req); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request
payload"})
+ return
+ }
+
+ sepIndex := strings.Index(",", req.Bin)
+
+ messages := h.ctxManager.GetHistory(ctxID)
+ messages = append(messages, &chat.ChatMessage{
+ Role: "human",
+ Content: req.Message,
+ Bin: []byte(req.Bin[sepIndex+1:]),
+ })
+
+ stream, err := h.svc.Chat(context.Background(), &chat.ChatRequest{
+ Messages: messages,
+ })
+ if err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error":
err.Error()})
+ return
+ }
+ defer func() {
+ if err := stream.Close(); err != nil {
+ log.Println("Error closing stream:", err)
+ }
+ }()
+
+ c.Header("Content-Type", "text/event-stream")
+ c.Header("Cache-Control", "no-cache")
+ c.Header("Connection", "close")
+
+ responseCh := make(chan string, 100) // use buffer
+
+ go func() {
+ defer func() {
+ if r := recover(); r != nil {
+ log.Printf("Recovered in stream processing:
%v\n%s", r, debug.Stack())
+ }
+ close(responseCh)
+ }()
+
+ for {
+ select {
+ case <-c.Request.Context().Done(): // client disconnect
+ log.Println("Client disconnected, stopping
stream processing")
+ return
+ default:
+ if !stream.Recv() {
+ if err := stream.Err(); err != nil {
+ log.Printf("Stream receive
error: %v", err)
+ }
+ return
+ }
+ content := stream.Msg().Content
+ responseCh <- content
+ }
+ }
+ }()
+
+ // SSE stream output
+ c.Stream(func(w io.Writer) bool {
+ select {
+ case chunk, ok := <-responseCh:
+ if !ok {
+ return false
+ }
+ c.SSEvent("message", gin.H{"content": chunk})
+ return true
+ case <-time.After(30 * time.Second):
+ log.Println("Stream timed out")
+ return false
+ case <-c.Request.Context().Done():
+ log.Println("Client disconnected")
+ return false
+ }
+ })
+}
+
+func (h *ChatHandler) NewContext(c *gin.Context) {
+ session := sessions.Default(c)
+ newCtxID := h.ctxManager.CreateContext()
+ session.Set("current_context", newCtxID)
+ if err := session.Save(); err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "failed
to save session"})
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{
+ "context_id": newCtxID,
+ })
+}
+
+func (h *ChatHandler) ListContexts(c *gin.Context) {
+ session := sessions.Default(c)
+ currentCtx := session.Get("current_context").(string)
+
+ contexts := h.ctxManager.List()
+
+ c.JSON(http.StatusOK, gin.H{
+ "current": currentCtx,
+ "contexts": contexts,
+ })
+}
+
+func (h *ChatHandler) SwitchContext(c *gin.Context) {
+ var req struct {
+ ContextID string `json:"context_id"`
+ }
+ if err := c.BindJSON(&req); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+
+ exists := h.ctxManager.Consists(req.ContextID)
+
+ if !exists {
+ c.JSON(http.StatusNotFound, gin.H{"error": "context not found"})
+ return
+ }
+
+ session := sessions.Default(c)
+ session.Set("current_context", req.ContextID)
+ if err := session.Save(); err != nil {
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "failed
to save session"})
+ return
+ }
+
+ c.JSON(http.StatusOK, gin.H{
+ "message": "context switched",
+ })
+}
diff --git a/llm/go-client/frontend/main.go b/llm/go-client/frontend/main.go
new file mode 100644
index 00000000..5a48a04c
--- /dev/null
+++ b/llm/go-client/frontend/main.go
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package main
+
+import (
+ "fmt"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3/client"
+ _ "dubbo.apache.org/dubbo-go/v3/imports"
+
+ "github.com/apache/dubbo-go-samples/llm/go-client/frontend/handlers"
+ "github.com/apache/dubbo-go-samples/llm/go-client/frontend/service"
+ chat "github.com/apache/dubbo-go-samples/llm/proto"
+
+ "github.com/gin-contrib/sessions"
+ "github.com/gin-contrib/sessions/cookie"
+
+ "github.com/gin-gonic/gin"
+)
+
+func main() {
+ // init Dubbo
+ cli, err := client.NewClient(
+ client.WithClientURL("tri://127.0.0.1:20000"),
+ )
+ if err != nil {
+ panic(fmt.Sprintf("Error creating Dubbo client: %v", err))
+ }
+
+ svc, err := chat.NewChatService(cli)
+ if err != nil {
+ panic(fmt.Sprintf("Error creating chat service: %v", err))
+ }
+
+ // init Gin
+ r := gin.Default()
+
+ // config session
+ store := cookie.NewStore([]byte("secret"))
+ r.Use(sessions.Sessions("llm_session", store))
+
+ // register tmpl
+ r.LoadHTMLGlob("go-client/frontend/templates/*")
+ r.Static("../static", "go-client/frontend/static/")
+
+ // init service
+ ctxManager := service.NewContextManager()
+
+ // register route
+ h := handlers.NewChatHandler(svc, ctxManager)
+ r.GET("/", h.Index)
+ r.POST("/api/chat", h.Chat)
+ r.POST("/api/context/new", h.NewContext)
+ r.GET("/api/context/list", h.ListContexts)
+ r.POST("/api/context/switch", h.SwitchContext)
+
+ if err := r.Run(":8080"); err != nil {
+ panic(fmt.Sprintf("Failed to start server: %v", err))
+ }
+}
diff --git a/llm/go-client/frontend/service/context.go
b/llm/go-client/frontend/service/context.go
new file mode 100644
index 00000000..0241740a
--- /dev/null
+++ b/llm/go-client/frontend/service/context.go
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package service
+
+import (
+ "strconv"
+ "sync"
+)
+
+import (
+ chat "github.com/apache/dubbo-go-samples/llm/proto"
+)
+
+type ContextManager struct {
+ Contexts map[string][]*chat.ChatMessage
+ Mu sync.RWMutex
+}
+
+var nowID uint8
+
+func NewContextManager() *ContextManager {
+ return &ContextManager{
+ Contexts: make(map[string][]*chat.ChatMessage),
+ }
+}
+
+func (m *ContextManager) CreateContext() string {
+ m.Mu.Lock()
+ defer m.Mu.Unlock()
+ ctxID := nowID
+ nowID++
+ m.Contexts[strconv.Itoa(int(ctxID))] = []*chat.ChatMessage{}
+ return strconv.Itoa(int(ctxID))
+}
+
+func (m *ContextManager) GetHistory(ctxID string) []*chat.ChatMessage {
+ m.Mu.RLock()
+ defer m.Mu.RUnlock()
+ return m.Contexts[ctxID]
+}
+
+func (m *ContextManager) AppendMessage(ctxID string, msg *chat.ChatMessage) {
+ m.Mu.Lock()
+ defer m.Mu.Unlock()
+ if len(m.Contexts[ctxID]) >= 3 {
+ m.Contexts[ctxID] = m.Contexts[ctxID][1:]
+ }
+ m.Contexts[ctxID] = append(m.Contexts[ctxID], msg)
+}
+
+func (m *ContextManager) List() []string {
+ m.Mu.RLock()
+ defer m.Mu.RUnlock()
+ contexts := make([]string, 0, len(m.Contexts))
+ for ctxID := range m.Contexts {
+ contexts = append(contexts, ctxID)
+ }
+
+ return contexts
+}
+
+func (m *ContextManager) Consists(id string) bool {
+ m.Mu.RLock()
+ defer m.Mu.RUnlock()
+
+ _, ok := m.Contexts[id]
+
+ return ok
+}
diff --git a/llm/go-client/frontend/static/file.png
b/llm/go-client/frontend/static/file.png
new file mode 100644
index 00000000..04250526
Binary files /dev/null and b/llm/go-client/frontend/static/file.png differ
diff --git a/llm/go-client/frontend/static/script.js
b/llm/go-client/frontend/static/script.js
new file mode 100644
index 00000000..d09d1517
--- /dev/null
+++ b/llm/go-client/frontend/static/script.js
@@ -0,0 +1,209 @@
+// This file originally cloned from
https://github.com/yotam-halperin/chatbot-static-UI
+
+const chatbox = document.querySelector(".chatbox");
+const chatInput = document.querySelector(".chat-input textarea");
+const sendChatBtn = document.querySelector(".chat-input span");
+
+let userMessage = null; // Variable to store user's message
+let userBin = null; // Variable to store user's message
+const inputInitHeight = chatInput.scrollHeight;
+
+let fileBlobArr = [];
+let fileArr = [];
+
+const createChatLi = (message, className) => {
+ // Create a chat <li> element with passed message and className
+ const chatLi = document.createElement("li");
+ chatLi.classList.add("chat", `${className}`);
+ let chatContent = className === "outgoing" ? `<p></p>` : `<span
class="material-symbols-outlined">smart_toy</span><p></p>`;
+ chatLi.innerHTML = chatContent;
+ chatLi.querySelector("p").textContent = message;
+ return chatLi; // return chat <li> element
+}
+
+const handleChat = () => {
+ userMessage = chatInput.value.trim(); // Get user entered message and
remove extra whitespace
+ if (fileBlobArr.length > 0) {
+ userBin = fileBlobArr[0]
+ }
+ if(!userMessage && !userBin) return;
+
+ // Clear the input textarea and set its height to default
+ chatInput.value = "";
+ chatInput.style.height = `${inputInitHeight}px`;
+
+ // Append the user's message to the chatbox
+ chatbox.appendChild(createChatLi(userMessage, "outgoing"));
+ chatbox.scrollTo(0, chatbox.scrollHeight);
+
+ setTimeout(() => {
+ // Display "Thinking..." message while waiting for the response
+ const incomingChatLi = createChatLi("Thinking...", "incoming");
+ chatbox.appendChild(incomingChatLi);
+ chatbox.scrollTo(0, chatbox.scrollHeight);
+ generateResponse(incomingChatLi);
+ }, 600);
+
+ clear()
+}
+
+const generateResponse = (chatElement) => {
+ const API_URL = "/api/chat";
+ const messageElement = chatElement.querySelector("p");
+
+ // init stream
+ let accumulatedResponse = "";
+ messageElement.textContent = "";
+ messageElement.id = "content"
+
+ fetch(API_URL, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ message: userMessage, bin: userBin }),
+ })
+ .then(response => {
+ const reader = response.body.getReader();
+ const decoder = new TextDecoder();
+
+ function readStream() {
+ return reader.read().then(({ done, value }) => {
+ if (done) {
+ return;
+ }
+
+ const chunk = decoder.decode(value);
+ const events = chunk.split('\n\n');
+
+ events.forEach(event => {
+ if (event.startsWith('event:message')) {
+ // extract data
+ const dataLine = event.split('\n')[1];
+ if (dataLine && dataLine.startsWith('data:')) {
+ try {
+ const data =
JSON.parse(dataLine.replace('data:', ''));
+ accumulatedResponse += data.content;
+ messageElement.textContent =
accumulatedResponse;
+ chatbox.scrollTo(0, chatbox.scrollHeight);
+ } catch (error) {
+ console.error('Failed to parse event
data:', error);
+ }
+ }
+ }
+ });
+
+ return readStream();
+ });
+ }
+
+ return readStream();
+ })
+ .catch(error => {
+ console.error('Error:', error);
+ messageElement.classList.add("error");
+ messageElement.textContent = "Oops! Something went wrong. Please
try again.";
+ });
+}
+
+chatInput.addEventListener("input", () => {
+ // Adjust the height of the input textarea based on its content
+ chatInput.style.height = `${inputInitHeight}px`;
+ chatInput.style.height = `${chatInput.scrollHeight}px`;
+});
+chatInput.addEventListener("keydown", (e) => {
+ // If Enter key is pressed without Shift key and the window
+ // width is greater than 800px, handle the chat
+ if(e.key === "Enter" && !e.shiftKey && window.innerWidth > 800) {
+ e.preventDefault();
+ handleChat();
+ }
+});
+sendChatBtn.addEventListener("click", handleChat);
+
+addBtn = document.getElementById("add-btn");
+fileInput = document.getElementById("input");
+
+// file process
+function filesToBlob(file) {
+ let reader = new FileReader();
+ reader.readAsDataURL(file);
+ reader.onload = e => {
+ fileBlobArr.push(e.target.result);
+ let fileDiv = document.createElement('div');
+ // delete btn
+ let removeDiv = document.createElement('div');
+ removeDiv.id = 'file' + '-' + fileBlobArr.length;
+ removeDiv.innerHTML = '×';
+ // file name
+ let fileName = document.createElement('p');
+ fileName.innerHTML = file.name;
+ fileName.title = file.name;
+
+ let img = document.createElement('img');
+ img.src = "../static/file.png";
+
+ fileDiv.appendChild(img);
+ fileDiv.appendChild(removeDiv);
+ fileDiv.appendChild(fileName);
+
+ document.getElementById("drop").appendChild(fileDiv);
+ };
+
+ reader.onerror = () => {
+ switch(reader.error.code) {
+ case '1':
+ alert('File not found');
+ break;
+ case '2':
+ alert('Security error');
+ break;
+ case '3':
+ alert('Loading interrupted');
+ break;
+ case '4':
+ alert('File is not readable');
+ break;
+ case '5':
+ alert('Encode error');
+ break;
+ default:
+ alert('File read fail');
+ }
+ };
+}
+
+function handleFileSelect(event) {
+ const files = event.target.files;
+ if (files.length > 0) {
+ const file = files[0];
+
+ if (!file.type.startsWith('image/')) {
+ alert("Only support image files");
+ return;
+ }
+
+ fileArr.push(file);
+ filesToBlob(file);
+
+ document.querySelector('.drop-box').style.setProperty('--div-count',
"1");
+ document.getElementById("drop").style.display = "flex";
+ addBtn.style.display = "none";
+ }
+}
+
+fileInput.addEventListener('change', handleFileSelect);
+
+addBtn.addEventListener('click', () => {
+ fileInput.click();
+ document.getElementById("drop").style.display = "flex";
+});
+
+function clear() {
+ document.getElementById("drop").innerHTML = '';
+ document.getElementById("drop").style.display = "none";
+ addBtn.style.display = "flex";
+ fileInput.value = "";
+}
+
+document.getElementById("drop").addEventListener('click', clear);
\ No newline at end of file
diff --git a/llm/go-client/frontend/static/style.css
b/llm/go-client/frontend/static/style.css
new file mode 100644
index 00000000..8c0a0442
--- /dev/null
+++ b/llm/go-client/frontend/static/style.css
@@ -0,0 +1,238 @@
+/* This file originally cloned from
https://github.com/yotam-halperin/chatbot-static-UI*/
+
+
+/* Import Google font - Poppins */
+@import
url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap');
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ font-family: "Poppins", sans-serif;
+}
+body {
+ background: #E3F2FD;
+}
+
+
+.chatbot {
+ position: fixed;
+ left: 50%;
+ top: 50%;
+ width: 420px;
+ background: #fff;
+ border-radius: 15px;
+ overflow: hidden;
+ opacity: 1;
+ transform-origin: bottom right;
+ box-shadow: 0 0 128px 0 rgba(0,0,0,0.1),
+ 0 32px 64px -48px rgba(0,0,0,0.5);
+ transition: all 0.1s ease;
+ pointer-events: auto;
+ transform: translate(-50%, -50%) scale(1);
+}
+body.show-chatbot .chatbot {
+ opacity: 1;
+ pointer-events: auto;
+ transform: scale(1);
+}
+.chatbot header {
+ padding: 16px 0;
+ position: relative;
+ text-align: center;
+ color: #fff;
+ background: #724ae8;
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+}
+.chatbot header span {
+ position: absolute;
+ right: 15px;
+ top: 50%;
+ display: none;
+ cursor: pointer;
+ transform: translateY(-50%);
+}
+header h2 {
+ font-size: 1.4rem;
+}
+.chatbot .chatbox {
+ overflow-y: auto;
+ height: 510px;
+ padding: 30px 20px 100px;
+}
+.chatbot :where(.chatbox, textarea)::-webkit-scrollbar {
+ width: 6px;
+}
+.chatbot :where(.chatbox, textarea)::-webkit-scrollbar-track {
+ background: #fff;
+ border-radius: 25px;
+}
+.chatbot :where(.chatbox, textarea)::-webkit-scrollbar-thumb {
+ background: #ccc;
+ border-radius: 25px;
+}
+.chatbox .chat {
+ display: flex;
+ list-style: none;
+}
+.chatbox .outgoing {
+ margin: 20px 0;
+ justify-content: flex-end;
+}
+.chatbox .incoming span {
+ width: 32px;
+ height: 32px;
+ color: #fff;
+ cursor: default;
+ text-align: center;
+ line-height: 32px;
+ align-self: flex-end;
+ background: #724ae8;
+ border-radius: 4px;
+ margin: 0 10px 7px 0;
+}
+.chatbox .chat p {
+ white-space: pre-wrap;
+ padding: 12px 16px;
+ border-radius: 10px 10px 0 10px;
+ max-width: 75%;
+ color: #fff;
+ font-size: 0.95rem;
+ background: #724ae8;
+}
+.chatbox .incoming p {
+ border-radius: 10px 10px 10px 0;
+}
+.chatbox .chat p.error {
+ color: #721c24;
+ background: #f8d7da;
+}
+.chatbox .incoming p {
+ color: #000;
+ background: #f2f2f2;
+}
+.chatbot .chat-input {
+ display: flex;
+ gap: 5px;
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ background: #fff;
+ padding: 3px 20px;
+ border-top: 1px solid #ddd;
+}
+.chat-input textarea {
+ height: 55px;
+ width: 100%;
+ border: none;
+ outline: none;
+ resize: none;
+ max-height: 180px;
+ padding: 15px 15px 15px 0;
+ font-size: 0.95rem;
+}
+.chat-input span {
+ align-self: flex-end;
+ color: #724ae8;
+ cursor: pointer;
+ height: 55px;
+ display: flex;
+ align-items: center;
+ visibility: hidden;
+ font-size: 1.35rem;
+}
+.chat-input span1 {
+ align-self: flex-end;
+ color: #724ae8;
+ cursor: pointer;
+ height: 55px;
+ display: flex;
+ align-items: center;
+ font-size: 1.35rem;
+}
+.chat-input textarea:valid ~ span {
+ visibility: visible;
+}
+
+.drop-box {
+ display: none;
+ height: 60px;
+ width: 20%;
+ border: 1px dashed #a89b9b;
+ overflow: hidden;
+ overflow-y: auto;
+}
+
+.drop-box > div {
+ width: 40px;
+ height: 90%;
+ margin: 1px 3px;
+ display: block;
+ position: relative;
+}
+
+.drop-box > div > img {
+ width: 90%;
+ height: 70%;
+}
+
+.drop-box > div > div {
+ position: absolute;
+ right: 5px;
+ top: 5px;
+ width: 15px;
+ height: 15px;
+ background: #347aa5;
+ color: white;
+ border-radius: 50%;
+ text-align: center;
+ line-height: 15px;
+ /* font-weight: bold; */
+ font-size: 15px;
+ cursor: pointer;
+}
+
+.drop-box > div > p {
+ bottom: 5px;
+ text-align: center;
+ line-height: 10px;
+ font-size: 10px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.drop-text {
+ position: absolute;
+ width: 450px;
+ height: 50px;
+ top: 200px;
+ text-align: center;
+ line-height: 50px;
+ opacity: 0.3;
+}
+
+.drop-text > span {
+ color: #347aa5;
+ cursor: pointer;
+}
+
+
+@media (max-width: 600px), (max-height: 600px) {
+ .chatbot {
+ right: 0;
+ bottom: 0;
+ height: 100%;
+ border-radius: 0;
+ width: 100%;
+ }
+ .chatbot .chatbox {
+ height: 90%;
+ padding: 25px 15px 100px;
+ }
+ .chatbot .chat-input {
+ padding: 5px 15px;
+ }
+ .chatbot header span {
+ display: block;
+ }
+}
\ No newline at end of file
diff --git a/llm/go-client/frontend/templates/index.html
b/llm/go-client/frontend/templates/index.html
new file mode 100644
index 00000000..68eefdc5
--- /dev/null
+++ b/llm/go-client/frontend/templates/index.html
@@ -0,0 +1,49 @@
+<!-- This file originally cloned from
https://github.com/yotam-halperin/chatbot-static-UI-->
+
+
+<!DOCTYPE html>
+<!-- Coding By CodingNepal - www.codingnepalweb.com -->
+<html lang="en" dir="ltr">
+ <head>
+ <meta charset="utf-8">
+ <title>Chatbot in JavaScript | CodingNepal</title>
+ <link rel="stylesheet" href="../static/style.css">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <!-- Google Fonts Link For Icons -->
+ <link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0"
/>
+ <link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@48,400,1,0"
/>
+ <script src="../static/script.js" defer></script>
+ </head>
+ <body>
+
+ <div class="chatbot">
+ <header>
+ <h2>Chatbot</h2>
+ <span class="close-btn material-symbols-outlined">close</span>
+ </header>
+ <ul class="chatbox">
+ <li class="chat incoming">
+ <span class="material-symbols-outlined">smart_toy</span>
+ <p class="chat incoming content" id="content">Hi there 👋</p>
+ </li>
+ </ul>
+ <div class="chat-input">
+
+ <textarea placeholder="Enter a message..." spellcheck="false"
required></textarea>
+
+ <span id="send-btn" class="material-symbols-rounded">send</span>
+
+ <div id="drop" class="drop-box"></div>
+
+ <span1 id="add-btn" class="material-symbols-rounded">add</span1>
+
+ </div>
+
+ </div>
+
+ <input id="input" accept="image/*" type="file" style="display: none" >
+
+ </body>
+
+
+</html>
\ No newline at end of file
diff --git a/llm/go-server/cmd/server.go b/llm/go-server/cmd/server.go
index 084b8b40..0a438ea3 100644
--- a/llm/go-server/cmd/server.go
+++ b/llm/go-server/cmd/server.go
@@ -20,6 +20,8 @@ package main
import (
"context"
"fmt"
+ "log"
+ "runtime/debug"
)
import (
@@ -27,40 +29,85 @@ import (
"dubbo.apache.org/dubbo-go/v3/protocol"
"dubbo.apache.org/dubbo-go/v3/server"
+ chat "github.com/apache/dubbo-go-samples/llm/proto"
+
"github.com/tmc/langchaingo/llms"
"github.com/tmc/langchaingo/llms/ollama"
)
-import (
- greet "github.com/apache/dubbo-go-samples/llm/proto"
-)
-
-type GreetServer struct {
+type ChatServer struct {
llm *ollama.LLM
}
-func NewGreetServer() (*GreetServer, error) {
+func NewChatServer() (*ChatServer, error) {
llm, err := ollama.New(ollama.WithModel("deepseek-r1:1.5b"))
if err != nil {
return nil, err
}
- return &GreetServer{llm: llm}, nil
+ return &ChatServer{llm: llm}, nil
}
-func (s *GreetServer) Greet(ctx context.Context, req *greet.GreetRequest,
stream greet.GreetService_GreetServer) error {
- callback := func(ctx context.Context, chunk []byte) error {
- return stream.Send(&greet.GreetResponse{
- Content: string(chunk),
- })
+func (s *ChatServer) Chat(ctx context.Context, req *chat.ChatRequest, stream
chat.ChatService_ChatServer) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ log.Printf("panic in Chat: %v\n%s", r, debug.Stack())
+ err = fmt.Errorf("internal server error")
+ }
+ }()
+
+ if s.llm == nil {
+ return fmt.Errorf("LLM is not initialized")
}
- _, err := s.llm.GenerateContent(
+
+ if len(req.Messages) == 0 {
+ log.Println("Request contains no messages")
+ return fmt.Errorf("empty messages in request")
+ }
+
+ var messages []llms.MessageContent
+ for _, msg := range req.Messages {
+ msgType := llms.ChatMessageTypeHuman
+ if msg.Role == "ai" {
+ msgType = llms.ChatMessageTypeAI
+ }
+
+ messageContent := llms.MessageContent{
+ Role: msgType,
+ Parts: []llms.ContentPart{
+ llms.TextContent{msg.Content},
+ },
+ }
+
+ if msg.Bin != nil && len(msg.Bin) != 0 {
+ img := string(msg.Bin)
+ if err != nil {
+ log.Println("Decode image error:", err)
+ return fmt.Errorf("decode image error: %s", err)
+ }
+
+ messageContent.Parts = append(messageContent.Parts,
llms.BinaryPart("image/png", img))
+ }
+
+ messages = append(messages, messageContent)
+ }
+
+ _, err = s.llm.GenerateContent(
ctx,
- []llms.MessageContent{
- llms.TextParts(llms.ChatMessageTypeHuman, req.Prompt),
- },
- llms.WithStreamingFunc(callback),
+ messages,
+ llms.WithStreamingFunc(func(ctx context.Context, chunk []byte)
error {
+ if chunk == nil {
+ return nil
+ }
+ return stream.Send(&chat.ChatResponse{
+ Content: string(chunk),
+ })
+ }),
)
- return err
+ if err != nil {
+ log.Printf("GenerateContent failed: %v", err)
+ }
+
+ return nil
}
func main() {
@@ -74,13 +121,13 @@ func main() {
return
}
- greetServer, err := NewGreetServer()
+ chatServer, err := NewChatServer()
if err != nil {
- fmt.Printf("Error creating greet server: %v\n", err)
+ fmt.Printf("Error creating chat server: %v\n", err)
return
}
- if err := greet.RegisterGreetServiceHandler(srv, greetServer); err !=
nil {
+ if err := chat.RegisterChatServiceHandler(srv, chatServer); err != nil {
fmt.Printf("Error registering handler: %v\n", err)
return
}
diff --git a/llm/proto/chat.pb.go b/llm/proto/chat.pb.go
new file mode 100644
index 00000000..b6953d16
--- /dev/null
+++ b/llm/proto/chat.pb.go
@@ -0,0 +1,269 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You 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.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.5
+// protoc v3.6.1
+// source: proto/chat.proto
+
+package chat
+
+import (
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type ChatRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Messages []*ChatMessage
`protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ChatRequest) Reset() {
+ *x = ChatRequest{}
+ mi := &file_proto_chat_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ChatRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ChatRequest) ProtoMessage() {}
+
+func (x *ChatRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_proto_chat_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ChatRequest.ProtoReflect.Descriptor instead.
+func (*ChatRequest) Descriptor() ([]byte, []int) {
+ return file_proto_chat_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ChatRequest) GetMessages() []*ChatMessage {
+ if x != nil {
+ return x.Messages
+ }
+ return nil
+}
+
+type ChatMessage struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Role string
`protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"` // "human" or
"ai"
+ Content string
`protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"`
+ Bin []byte
`protobuf:"bytes,3,opt,name=bin,proto3" json:"bin,omitempty"` // binary file
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ChatMessage) Reset() {
+ *x = ChatMessage{}
+ mi := &file_proto_chat_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ChatMessage) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ChatMessage) ProtoMessage() {}
+
+func (x *ChatMessage) ProtoReflect() protoreflect.Message {
+ mi := &file_proto_chat_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ChatMessage.ProtoReflect.Descriptor instead.
+func (*ChatMessage) Descriptor() ([]byte, []int) {
+ return file_proto_chat_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ChatMessage) GetRole() string {
+ if x != nil {
+ return x.Role
+ }
+ return ""
+}
+
+func (x *ChatMessage) GetContent() string {
+ if x != nil {
+ return x.Content
+ }
+ return ""
+}
+
+func (x *ChatMessage) GetBin() []byte {
+ if x != nil {
+ return x.Bin
+ }
+ return nil
+}
+
+type ChatResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Content string
`protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ChatResponse) Reset() {
+ *x = ChatResponse{}
+ mi := &file_proto_chat_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ChatResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ChatResponse) ProtoMessage() {}
+
+func (x *ChatResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_proto_chat_proto_msgTypes[2]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ChatResponse.ProtoReflect.Descriptor instead.
+func (*ChatResponse) Descriptor() ([]byte, []int) {
+ return file_proto_chat_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ChatResponse) GetContent() string {
+ if x != nil {
+ return x.Content
+ }
+ return ""
+}
+
+var File_proto_chat_proto protoreflect.FileDescriptor
+
+var file_proto_chat_proto_rawDesc = string([]byte{
+ 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x68, 0x61, 0x74,
0x2e, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x12, 0x04, 0x63, 0x68, 0x61, 0x74, 0x22, 0x3c, 0x0a, 0x0b,
0x43, 0x68, 0x61, 0x74,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x08, 0x6d,
0x65, 0x73, 0x73, 0x61,
+ 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e,
0x63, 0x68, 0x61, 0x74,
+ 0x2e, 0x43, 0x68, 0x61, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x52, 0x08, 0x6d, 0x65,
+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x4d, 0x0a, 0x0b, 0x43, 0x68,
0x61, 0x74, 0x4d, 0x65,
+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c,
0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x18, 0x0a,
0x07, 0x63, 0x6f, 0x6e,
+ 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x63, 0x6f, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x69, 0x6e, 0x18, 0x03,
0x20, 0x01, 0x28, 0x0c,
+ 0x52, 0x03, 0x62, 0x69, 0x6e, 0x22, 0x28, 0x0a, 0x0c, 0x43, 0x68, 0x61,
0x74, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e,
0x74, 0x65, 0x6e, 0x74,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74,
0x65, 0x6e, 0x74, 0x32,
+ 0x40, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x12, 0x31,
+ 0x0a, 0x04, 0x43, 0x68, 0x61, 0x74, 0x12, 0x11, 0x2e, 0x63, 0x68, 0x61,
0x74, 0x2e, 0x43, 0x68,
+ 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e,
0x63, 0x68, 0x61, 0x74,
+ 0x2e, 0x43, 0x68, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x30,
+ 0x01, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f,
+ 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2f, 0x64, 0x75, 0x62, 0x62, 0x6f,
0x2d, 0x67, 0x6f, 0x2d,
+ 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x6c, 0x6c, 0x6d, 0x2f,
0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x3b, 0x63, 0x68, 0x61, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
+})
+
+var (
+ file_proto_chat_proto_rawDescOnce sync.Once
+ file_proto_chat_proto_rawDescData []byte
+)
+
+func file_proto_chat_proto_rawDescGZIP() []byte {
+ file_proto_chat_proto_rawDescOnce.Do(func() {
+ file_proto_chat_proto_rawDescData =
protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_chat_proto_rawDesc),
len(file_proto_chat_proto_rawDesc)))
+ })
+ return file_proto_chat_proto_rawDescData
+}
+
+var file_proto_chat_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_proto_chat_proto_goTypes = []any{
+ (*ChatRequest)(nil), // 0: chat.ChatRequest
+ (*ChatMessage)(nil), // 1: chat.ChatMessage
+ (*ChatResponse)(nil), // 2: chat.ChatResponse
+}
+var file_proto_chat_proto_depIdxs = []int32{
+ 1, // 0: chat.ChatRequest.messages:type_name -> chat.ChatMessage
+ 0, // 1: chat.ChatService.Chat:input_type -> chat.ChatRequest
+ 2, // 2: chat.ChatService.Chat:output_type -> chat.ChatResponse
+ 2, // [2:3] is the sub-list for method output_type
+ 1, // [1:2] is the sub-list for method input_type
+ 1, // [1:1] is the sub-list for extension type_name
+ 1, // [1:1] is the sub-list for extension extendee
+ 0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_proto_chat_proto_init() }
+func file_proto_chat_proto_init() {
+ if File_proto_chat_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor:
unsafe.Slice(unsafe.StringData(file_proto_chat_proto_rawDesc),
len(file_proto_chat_proto_rawDesc)),
+ NumEnums: 0,
+ NumMessages: 3,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_proto_chat_proto_goTypes,
+ DependencyIndexes: file_proto_chat_proto_depIdxs,
+ MessageInfos: file_proto_chat_proto_msgTypes,
+ }.Build()
+ File_proto_chat_proto = out.File
+ file_proto_chat_proto_goTypes = nil
+ file_proto_chat_proto_depIdxs = nil
+}
diff --git a/llm/proto/greet.proto b/llm/proto/chat.proto
similarity index 75%
rename from llm/proto/greet.proto
rename to llm/proto/chat.proto
index b0cbcf55..7b363ac2 100644
--- a/llm/proto/greet.proto
+++ b/llm/proto/chat.proto
@@ -17,18 +17,24 @@
syntax = "proto3";
-package greet;
+package chat;
-option go_package = "github.com/apache/dubbo-go-samples/llm/proto;greet";
+option go_package = "github.com/apache/dubbo-go-samples/llm/proto;chat";
-message GreetRequest {
- string prompt = 1;
+message ChatRequest {
+ repeated ChatMessage messages = 1;
}
-message GreetResponse {
+message ChatMessage {
+ string role = 1; // "human" or "ai"
+ string content = 2;
+ bytes bin = 3; // binary file
+}
+
+message ChatResponse {
string content = 1;
}
-service GreetService {
- rpc Greet(GreetRequest) returns (stream GreetResponse) {}
+service ChatService {
+ rpc Chat(ChatRequest) returns (stream ChatResponse) {}
}
\ No newline at end of file
diff --git a/llm/proto/chat.triple.go b/llm/proto/chat.triple.go
new file mode 100644
index 00000000..75aaf337
--- /dev/null
+++ b/llm/proto/chat.triple.go
@@ -0,0 +1,177 @@
+// Code generated by protoc-gen-triple. DO NOT EDIT.
+//
+// Source: proto/chat.proto
+package chat
+
+import (
+ "context"
+ "net/http"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3"
+ "dubbo.apache.org/dubbo-go/v3/client"
+ "dubbo.apache.org/dubbo-go/v3/common"
+ "dubbo.apache.org/dubbo-go/v3/common/constant"
+ "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+ "dubbo.apache.org/dubbo-go/v3/server"
+)
+
+// This is a compile-time assertion to ensure that this generated file and the
Triple package
+// are compatible. If you get a compiler error that this constant is not
defined, this code was
+// generated with a version of Triple newer than the one compiled into your
binary. You can fix the
+// problem by either regenerating this code with an older version of Triple or
updating the Triple
+// version compiled into your binary.
+const _ = triple_protocol.IsAtLeastVersion0_1_0
+
+const (
+ // ChatServiceName is the fully-qualified name of the ChatService
service.
+ ChatServiceName = "chat.ChatService"
+)
+
+// These constants are the fully-qualified names of the RPCs defined in this
package. They're
+// exposed at runtime as procedure and as the final two segments of the HTTP
route.
+//
+// Note that these are different from the fully-qualified method names used by
+// google.golang.org/protobuf/reflect/protoreflect. To convert from these
constants to
+// reflection-formatted method names, remove the leading slash and convert the
remaining slash to a
+// period.
+const (
+ // ChatServiceChatProcedure is the fully-qualified name of the
ChatService's Chat RPC.
+ ChatServiceChatProcedure = "/chat.ChatService/Chat"
+)
+
+var (
+ _ ChatService = (*ChatServiceImpl)(nil)
+
+ _ ChatService_ChatClient = (*ChatServiceChatClient)(nil)
+
+ _ ChatService_ChatServer = (*ChatServiceChatServer)(nil)
+)
+
+// ChatService is a client for the chat.ChatService service.
+type ChatService interface {
+ Chat(ctx context.Context, req *ChatRequest, opts ...client.CallOption)
(ChatService_ChatClient, error)
+}
+
+// NewChatService constructs a client for the chat.ChatService service.
+func NewChatService(cli *client.Client, opts ...client.ReferenceOption)
(ChatService, error) {
+ conn, err := cli.DialWithInfo("chat.ChatService",
&ChatService_ClientInfo, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ChatServiceImpl{
+ conn: conn,
+ }, nil
+}
+
+func SetConsumerChatService(srv common.RPCService) {
+ dubbo.SetConsumerServiceWithInfo(srv, &ChatService_ClientInfo)
+}
+
+// ChatServiceImpl implements ChatService.
+type ChatServiceImpl struct {
+ conn *client.Connection
+}
+
+func (c *ChatServiceImpl) Chat(ctx context.Context, req *ChatRequest, opts
...client.CallOption) (ChatService_ChatClient, error) {
+ stream, err := c.conn.CallServerStream(ctx, req, "Chat", opts...)
+ if err != nil {
+ return nil, err
+ }
+ rawStream := stream.(*triple_protocol.ServerStreamForClient)
+ return &ChatServiceChatClient{rawStream}, nil
+}
+
+type ChatService_ChatClient interface {
+ Recv() bool
+ ResponseHeader() http.Header
+ ResponseTrailer() http.Header
+ Msg() *ChatResponse
+ Err() error
+ Conn() (triple_protocol.StreamingClientConn, error)
+ Close() error
+}
+
+type ChatServiceChatClient struct {
+ *triple_protocol.ServerStreamForClient
+}
+
+func (cli *ChatServiceChatClient) Recv() bool {
+ msg := new(ChatResponse)
+ return cli.ServerStreamForClient.Receive(msg)
+}
+
+func (cli *ChatServiceChatClient) Msg() *ChatResponse {
+ msg := cli.ServerStreamForClient.Msg()
+ if msg == nil {
+ return new(ChatResponse)
+ }
+ return msg.(*ChatResponse)
+}
+
+func (cli *ChatServiceChatClient) Conn() (triple_protocol.StreamingClientConn,
error) {
+ return cli.ServerStreamForClient.Conn()
+}
+
+var ChatService_ClientInfo = client.ClientInfo{
+ InterfaceName: "chat.ChatService",
+ MethodNames: []string{"Chat"},
+ ConnectionInjectFunc: func(dubboCliRaw interface{}, conn
*client.Connection) {
+ dubboCli := dubboCliRaw.(*ChatServiceImpl)
+ dubboCli.conn = conn
+ },
+}
+
+// ChatServiceHandler is an implementation of the chat.ChatService service.
+type ChatServiceHandler interface {
+ Chat(context.Context, *ChatRequest, ChatService_ChatServer) error
+}
+
+func RegisterChatServiceHandler(srv *server.Server, hdlr ChatServiceHandler,
opts ...server.ServiceOption) error {
+ return srv.Register(hdlr, &ChatService_ServiceInfo, opts...)
+}
+
+func SetProviderChatService(srv common.RPCService) {
+ dubbo.SetProviderServiceWithInfo(srv, &ChatService_ServiceInfo)
+}
+
+type ChatService_ChatServer interface {
+ Send(*ChatResponse) error
+ ResponseHeader() http.Header
+ ResponseTrailer() http.Header
+ Conn() triple_protocol.StreamingHandlerConn
+}
+
+type ChatServiceChatServer struct {
+ *triple_protocol.ServerStream
+}
+
+func (g *ChatServiceChatServer) Send(msg *ChatResponse) error {
+ return g.ServerStream.Send(msg)
+}
+
+var ChatService_ServiceInfo = server.ServiceInfo{
+ InterfaceName: "chat.ChatService",
+ ServiceType: (*ChatServiceHandler)(nil),
+ Methods: []server.MethodInfo{
+ {
+ Name: "Chat",
+ Type: constant.CallServerStream,
+ ReqInitFunc: func() interface{} {
+ return new(ChatRequest)
+ },
+ StreamInitFunc: func(baseStream interface{})
interface{} {
+ return
&ChatServiceChatServer{baseStream.(*triple_protocol.ServerStream)}
+ },
+ MethodFunc: func(ctx context.Context, args
[]interface{}, handler interface{}) (interface{}, error) {
+ req := args[0].(*ChatRequest)
+ stream := args[1].(ChatService_ChatServer)
+ if err :=
handler.(ChatServiceHandler).Chat(ctx, req, stream); err != nil {
+ return nil, err
+ }
+ return nil, nil
+ },
+ },
+ },
+}
diff --git a/llm/proto/greet.pb.go b/llm/proto/greet.pb.go
deleted file mode 100644
index e6f4985e..00000000
--- a/llm/proto/greet.pb.go
+++ /dev/null
@@ -1,197 +0,0 @@
-//
-// Licensed to the Apache Software Foundation (ASF) under one or more
-// contributor license agreements. See the NOTICE file distributed with
-// this work for additional information regarding copyright ownership.
-// The ASF licenses this file to You 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.
-
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// protoc-gen-go v1.36.5
-// protoc v4.25.2
-// source: greet.proto
-
-package greet
-
-import (
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
- protoimpl "google.golang.org/protobuf/runtime/protoimpl"
- reflect "reflect"
- sync "sync"
- unsafe "unsafe"
-)
-
-const (
- // Verify that this generated code is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
- // Verify that runtime/protoimpl is sufficiently up-to-date.
- _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type GreetRequest struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- Prompt string
`protobuf:"bytes,1,opt,name=prompt,proto3" json:"prompt,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GreetRequest) Reset() {
- *x = GreetRequest{}
- mi := &file_greet_proto_msgTypes[0]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GreetRequest) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GreetRequest) ProtoMessage() {}
-
-func (x *GreetRequest) ProtoReflect() protoreflect.Message {
- mi := &file_greet_proto_msgTypes[0]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GreetRequest.ProtoReflect.Descriptor instead.
-func (*GreetRequest) Descriptor() ([]byte, []int) {
- return file_greet_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *GreetRequest) GetPrompt() string {
- if x != nil {
- return x.Prompt
- }
- return ""
-}
-
-type GreetResponse struct {
- state protoimpl.MessageState `protogen:"open.v1"`
- Content string
`protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
-}
-
-func (x *GreetResponse) Reset() {
- *x = GreetResponse{}
- mi := &file_greet_proto_msgTypes[1]
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- ms.StoreMessageInfo(mi)
-}
-
-func (x *GreetResponse) String() string {
- return protoimpl.X.MessageStringOf(x)
-}
-
-func (*GreetResponse) ProtoMessage() {}
-
-func (x *GreetResponse) ProtoReflect() protoreflect.Message {
- mi := &file_greet_proto_msgTypes[1]
- if x != nil {
- ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
- if ms.LoadMessageInfo() == nil {
- ms.StoreMessageInfo(mi)
- }
- return ms
- }
- return mi.MessageOf(x)
-}
-
-// Deprecated: Use GreetResponse.ProtoReflect.Descriptor instead.
-func (*GreetResponse) Descriptor() ([]byte, []int) {
- return file_greet_proto_rawDescGZIP(), []int{1}
-}
-
-func (x *GreetResponse) GetContent() string {
- if x != nil {
- return x.Content
- }
- return ""
-}
-
-var File_greet_proto protoreflect.FileDescriptor
-
-var file_greet_proto_rawDesc = string([]byte{
- 0x0a, 0x0b, 0x67, 0x72, 0x65, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x05, 0x67,
- 0x72, 0x65, 0x65, 0x74, 0x22, 0x26, 0x0a, 0x0c, 0x47, 0x72, 0x65, 0x65,
0x74, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x6d,
0x70, 0x74, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74,
0x22, 0x29, 0x0a, 0x0d,
- 0x47, 0x72, 0x65, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x18, 0x0a,
- 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x07,
- 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x32, 0x46, 0x0a, 0x0c, 0x47,
0x72, 0x65, 0x65, 0x74,
- 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x36, 0x0a, 0x05, 0x47,
0x72, 0x65, 0x65, 0x74,
- 0x12, 0x13, 0x2e, 0x67, 0x72, 0x65, 0x65, 0x74, 0x2e, 0x47, 0x72, 0x65,
0x65, 0x74, 0x52, 0x65,
- 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x67, 0x72, 0x65, 0x65,
0x74, 0x2e, 0x47, 0x72,
- 0x65, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x00, 0x30, 0x01, 0x42,
- 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x61, 0x70,
- 0x61, 0x63, 0x68, 0x65, 0x2f, 0x64, 0x75, 0x62, 0x62, 0x6f, 0x2d, 0x67,
0x6f, 0x2d, 0x73, 0x61,
- 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x6c, 0x6c, 0x6d, 0x2f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x3b,
- 0x67, 0x72, 0x65, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
-})
-
-var (
- file_greet_proto_rawDescOnce sync.Once
- file_greet_proto_rawDescData []byte
-)
-
-func file_greet_proto_rawDescGZIP() []byte {
- file_greet_proto_rawDescOnce.Do(func() {
- file_greet_proto_rawDescData =
protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_greet_proto_rawDesc),
len(file_greet_proto_rawDesc)))
- })
- return file_greet_proto_rawDescData
-}
-
-var file_greet_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
-var file_greet_proto_goTypes = []any{
- (*GreetRequest)(nil), // 0: greet.GreetRequest
- (*GreetResponse)(nil), // 1: greet.GreetResponse
-}
-var file_greet_proto_depIdxs = []int32{
- 0, // 0: greet.GreetService.Greet:input_type -> greet.GreetRequest
- 1, // 1: greet.GreetService.Greet:output_type -> greet.GreetResponse
- 1, // [1:2] is the sub-list for method output_type
- 0, // [0:1] is the sub-list for method input_type
- 0, // [0:0] is the sub-list for extension type_name
- 0, // [0:0] is the sub-list for extension extendee
- 0, // [0:0] is the sub-list for field type_name
-}
-
-func init() { file_greet_proto_init() }
-func file_greet_proto_init() {
- if File_greet_proto != nil {
- return
- }
- type x struct{}
- out := protoimpl.TypeBuilder{
- File: protoimpl.DescBuilder{
- GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
- RawDescriptor:
unsafe.Slice(unsafe.StringData(file_greet_proto_rawDesc),
len(file_greet_proto_rawDesc)),
- NumEnums: 0,
- NumMessages: 2,
- NumExtensions: 0,
- NumServices: 1,
- },
- GoTypes: file_greet_proto_goTypes,
- DependencyIndexes: file_greet_proto_depIdxs,
- MessageInfos: file_greet_proto_msgTypes,
- }.Build()
- File_greet_proto = out.File
- file_greet_proto_goTypes = nil
- file_greet_proto_depIdxs = nil
-}
diff --git a/llm/proto/greet.triple.go b/llm/proto/greet.triple.go
deleted file mode 100644
index 99d6ef13..00000000
--- a/llm/proto/greet.triple.go
+++ /dev/null
@@ -1,177 +0,0 @@
-// Code generated by protoc-gen-triple. DO NOT EDIT.
-//
-// Source: greet.proto
-package greet
-
-import (
- "context"
- "net/http"
-)
-
-import (
- "dubbo.apache.org/dubbo-go/v3"
- "dubbo.apache.org/dubbo-go/v3/client"
- "dubbo.apache.org/dubbo-go/v3/common"
- "dubbo.apache.org/dubbo-go/v3/common/constant"
- "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
- "dubbo.apache.org/dubbo-go/v3/server"
-)
-
-// This is a compile-time assertion to ensure that this generated file and the
Triple package
-// are compatible. If you get a compiler error that this constant is not
defined, this code was
-// generated with a version of Triple newer than the one compiled into your
binary. You can fix the
-// problem by either regenerating this code with an older version of Triple or
updating the Triple
-// version compiled into your binary.
-const _ = triple_protocol.IsAtLeastVersion0_1_0
-
-const (
- // GreetServiceName is the fully-qualified name of the GreetService
service.
- GreetServiceName = "greet.GreetService"
-)
-
-// These constants are the fully-qualified names of the RPCs defined in this
package. They're
-// exposed at runtime as procedure and as the final two segments of the HTTP
route.
-//
-// Note that these are different from the fully-qualified method names used by
-// google.golang.org/protobuf/reflect/protoreflect. To convert from these
constants to
-// reflection-formatted method names, remove the leading slash and convert the
remaining slash to a
-// period.
-const (
- // GreetServiceGreetProcedure is the fully-qualified name of the
GreetService's Greet RPC.
- GreetServiceGreetProcedure = "/greet.GreetService/Greet"
-)
-
-var (
- _ GreetService = (*GreetServiceImpl)(nil)
-
- _ GreetService_GreetClient = (*GreetServiceGreetClient)(nil)
-
- _ GreetService_GreetServer = (*GreetServiceGreetServer)(nil)
-)
-
-// GreetService is a client for the greet.GreetService service.
-type GreetService interface {
- Greet(ctx context.Context, req *GreetRequest, opts
...client.CallOption) (GreetService_GreetClient, error)
-}
-
-// NewGreetService constructs a client for the greet.GreetService service.
-func NewGreetService(cli *client.Client, opts ...client.ReferenceOption)
(GreetService, error) {
- conn, err := cli.DialWithInfo("greet.GreetService",
&GreetService_ClientInfo, opts...)
- if err != nil {
- return nil, err
- }
- return &GreetServiceImpl{
- conn: conn,
- }, nil
-}
-
-func SetConsumerGreetService(srv common.RPCService) {
- dubbo.SetConsumerServiceWithInfo(srv, &GreetService_ClientInfo)
-}
-
-// GreetServiceImpl implements GreetService.
-type GreetServiceImpl struct {
- conn *client.Connection
-}
-
-func (c *GreetServiceImpl) Greet(ctx context.Context, req *GreetRequest, opts
...client.CallOption) (GreetService_GreetClient, error) {
- stream, err := c.conn.CallServerStream(ctx, req, "Greet", opts...)
- if err != nil {
- return nil, err
- }
- rawStream := stream.(*triple_protocol.ServerStreamForClient)
- return &GreetServiceGreetClient{rawStream}, nil
-}
-
-type GreetService_GreetClient interface {
- Recv() bool
- ResponseHeader() http.Header
- ResponseTrailer() http.Header
- Msg() *GreetResponse
- Err() error
- Conn() (triple_protocol.StreamingClientConn, error)
- Close() error
-}
-
-type GreetServiceGreetClient struct {
- *triple_protocol.ServerStreamForClient
-}
-
-func (cli *GreetServiceGreetClient) Recv() bool {
- msg := new(GreetResponse)
- return cli.ServerStreamForClient.Receive(msg)
-}
-
-func (cli *GreetServiceGreetClient) Msg() *GreetResponse {
- msg := cli.ServerStreamForClient.Msg()
- if msg == nil {
- return new(GreetResponse)
- }
- return msg.(*GreetResponse)
-}
-
-func (cli *GreetServiceGreetClient) Conn()
(triple_protocol.StreamingClientConn, error) {
- return cli.ServerStreamForClient.Conn()
-}
-
-var GreetService_ClientInfo = client.ClientInfo{
- InterfaceName: "greet.GreetService",
- MethodNames: []string{"Greet"},
- ConnectionInjectFunc: func(dubboCliRaw interface{}, conn
*client.Connection) {
- dubboCli := dubboCliRaw.(*GreetServiceImpl)
- dubboCli.conn = conn
- },
-}
-
-// GreetServiceHandler is an implementation of the greet.GreetService service.
-type GreetServiceHandler interface {
- Greet(context.Context, *GreetRequest, GreetService_GreetServer) error
-}
-
-func RegisterGreetServiceHandler(srv *server.Server, hdlr GreetServiceHandler,
opts ...server.ServiceOption) error {
- return srv.Register(hdlr, &GreetService_ServiceInfo, opts...)
-}
-
-func SetProviderGreetService(srv common.RPCService) {
- dubbo.SetProviderServiceWithInfo(srv, &GreetService_ServiceInfo)
-}
-
-type GreetService_GreetServer interface {
- Send(*GreetResponse) error
- ResponseHeader() http.Header
- ResponseTrailer() http.Header
- Conn() triple_protocol.StreamingHandlerConn
-}
-
-type GreetServiceGreetServer struct {
- *triple_protocol.ServerStream
-}
-
-func (g *GreetServiceGreetServer) Send(msg *GreetResponse) error {
- return g.ServerStream.Send(msg)
-}
-
-var GreetService_ServiceInfo = server.ServiceInfo{
- InterfaceName: "greet.GreetService",
- ServiceType: (*GreetServiceHandler)(nil),
- Methods: []server.MethodInfo{
- {
- Name: "Greet",
- Type: constant.CallServerStream,
- ReqInitFunc: func() interface{} {
- return new(GreetRequest)
- },
- StreamInitFunc: func(baseStream interface{})
interface{} {
- return
&GreetServiceGreetServer{baseStream.(*triple_protocol.ServerStream)}
- },
- MethodFunc: func(ctx context.Context, args
[]interface{}, handler interface{}) (interface{}, error) {
- req := args[0].(*GreetRequest)
- stream := args[1].(GreetService_GreetServer)
- if err :=
handler.(GreetServiceHandler).Greet(ctx, req, stream); err != nil {
- return nil, err
- }
- return nil, nil
- },
- },
- },
-}