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
-                       },
-               },
-       },
-}


Reply via email to