From 1823608d35fd611f6894fcf34e581df44f8cbd7e Mon Sep 17 00:00:00 2001 From: Abirdcfly Date: Thu, 9 Nov 2023 17:09:52 +0800 Subject: [PATCH] feat: add CRDs for App Signed-off-by: Abirdcfly --- Makefile | 1 + PROJECT | 48 +++- .../chain/v1alpha1/groupversion_info.go | 41 ++++ api/app-node/chain/v1alpha1/llmchain_types.go | 87 ++++++++ .../chain/v1alpha1/zz_generated.deepcopy.go | 184 +++++++++++++++ api/app-node/common_type.go | 75 +++++++ .../prompt/v1alpha1/groupversion_info.go | 41 ++++ .../prompt/v1alpha1/prompttemplate_types.go | 84 +++++++ .../prompt/v1alpha1/zz_generated.deepcopy.go | 167 ++++++++++++++ api/app-node/zz_generated.deepcopy.go | 106 +++++++++ api/base/v1alpha1/application.go | 22 ++ api/base/v1alpha1/application_types.go | 79 +++++++ api/{ => base}/v1alpha1/common.go | 0 api/{ => base}/v1alpha1/condition.go | 32 +++ api/{ => base}/v1alpha1/dataset.go | 0 api/{ => base}/v1alpha1/dataset_types.go | 0 api/{ => base}/v1alpha1/datasource.go | 0 api/{ => base}/v1alpha1/datasource_types.go | 0 api/{ => base}/v1alpha1/embedder.go | 0 api/{ => base}/v1alpha1/embedder_types.go | 0 api/{ => base}/v1alpha1/groupversion_info.go | 0 api/{ => base}/v1alpha1/knowledgebase.go | 0 .../v1alpha1/knowledgebase_types.go | 0 api/{ => base}/v1alpha1/laboratory_types.go | 0 api/{ => base}/v1alpha1/llm.go | 0 api/{ => base}/v1alpha1/llm_types.go | 0 api/{ => base}/v1alpha1/model.go | 0 api/{ => base}/v1alpha1/model_types.go | 0 api/{ => base}/v1alpha1/prompt_types.go | 0 api/{ => base}/v1alpha1/prompt_webhook.go | 0 api/{ => base}/v1alpha1/vectorstore.go | 0 api/{ => base}/v1alpha1/vectorstore_types.go | 0 api/{ => base}/v1alpha1/versioneddataset.go | 0 .../v1alpha1/versioneddataset_types.go | 0 api/{ => base}/v1alpha1/webhook_suite_test.go | 4 +- api/{ => base}/v1alpha1/worker.go | 0 api/{ => base}/v1alpha1/worker_types.go | 0 .../v1alpha1/zz_generated.deepcopy.go | 139 ++++++++++++ ...cadia.kubeagi.k8s.com.cn_applications.yaml | 141 ++++++++++++ ....arcadia.kubeagi.k8s.com.cn_llmchains.yaml | 168 ++++++++++++++ ...pt.arcadia.kubeagi.k8s.com.cn_prompts.yaml | 136 ++++++++++++ config/crd/kustomization.yaml | 5 + .../patches/cainjection_in_applications.yaml | 7 + .../crd/patches/webhook_in_applications.yaml | 16 ++ config/rbac/application_editor_role.yaml | 24 ++ config/rbac/application_viewer_role.yaml | 20 ++ config/rbac/role.yaml | 78 +++++++ .../samples/app_llmchain_englishteacher.yaml | 118 ++++++++++ config/samples/kustomization.yaml | 2 + .../app-node/chain/llmchain_controller.go | 142 ++++++++++++ .../app-node/prompt/prompt_controller.go | 140 ++++++++++++ controllers/application_controller.go | 210 ++++++++++++++++++ controllers/dataset_controller.go | 2 +- controllers/datasource_controller.go | 2 +- controllers/embedder_controller.go | 2 +- controllers/knowledgebase_controller.go | 2 +- controllers/laboratory_controller.go | 2 +- controllers/llm_controller.go | 2 +- controllers/model_controller.go | 2 +- controllers/prompt_controller.go | 2 +- controllers/suite_test.go | 2 +- controllers/vectorstore_controller.go | 2 +- controllers/versioneddataset_controller.go | 2 +- controllers/worker_controller.go | 2 +- ...cadia.kubeagi.k8s.com.cn_applications.yaml | 141 ++++++++++++ ....arcadia.kubeagi.k8s.com.cn_llmchains.yaml | 168 ++++++++++++++ ...pt.arcadia.kubeagi.k8s.com.cn_prompts.yaml | 136 ++++++++++++ deploy/charts/arcadia/templates/rbac.yaml | 78 +++++++ go.mod | 23 ++ go.sum | 59 +++++ .../go-server/graph/impl/dataset.resolvers.go | 2 +- .../graph/impl/knowledgebase.resolvers.go | 2 +- graphql-server/go-server/main.go | 72 ++++-- graphql-server/go-server/pkg/chat/chat.go | 98 ++++++++ .../go-server/pkg/chat/chat_type.go | 57 +++++ .../go-server/pkg/dataset/dataset.go | 2 +- .../go-server/pkg/datasource/datasource.go | 2 +- .../go-server/pkg/embedder/embedder.go | 2 +- .../pkg/knowledgebase/knowledgebase.go | 2 +- graphql-server/go-server/pkg/model/model.go | 2 +- .../pkg/versioneddataset/versioned_dataset.go | 2 +- main.go | 29 ++- pkg/application/app_run.go | 195 ++++++++++++++++ pkg/application/base/input.go | 37 +++ pkg/application/base/node.go | 98 ++++++++ pkg/application/base/output.go | 37 +++ pkg/application/chain/llmchain.go | 67 ++++++ pkg/application/llm/base.go | 53 +++++ pkg/application/llm/zhipu.go | 81 +++++++ pkg/application/prompt/prompt.go | 62 ++++++ pkg/config/config.go | 2 +- pkg/config/config_type.go | 2 +- pkg/datasource/datasource.go | 2 +- pkg/llms/zhipuai/langchainllm.go | 83 +++++++ pkg/scheduler/executor.go | 2 +- pkg/scheduler/scheduler.go | 2 +- pkg/worker/loader.go | 2 +- pkg/worker/runner.go | 2 +- pkg/worker/worker.go | 2 +- tests/example-test.sh | 12 +- 100 files changed, 3896 insertions(+), 63 deletions(-) create mode 100644 api/app-node/chain/v1alpha1/groupversion_info.go create mode 100644 api/app-node/chain/v1alpha1/llmchain_types.go create mode 100644 api/app-node/chain/v1alpha1/zz_generated.deepcopy.go create mode 100644 api/app-node/common_type.go create mode 100644 api/app-node/prompt/v1alpha1/groupversion_info.go create mode 100644 api/app-node/prompt/v1alpha1/prompttemplate_types.go create mode 100644 api/app-node/prompt/v1alpha1/zz_generated.deepcopy.go create mode 100644 api/app-node/zz_generated.deepcopy.go create mode 100644 api/base/v1alpha1/application.go create mode 100644 api/base/v1alpha1/application_types.go rename api/{ => base}/v1alpha1/common.go (100%) rename api/{ => base}/v1alpha1/condition.go (88%) rename api/{ => base}/v1alpha1/dataset.go (100%) rename api/{ => base}/v1alpha1/dataset_types.go (100%) rename api/{ => base}/v1alpha1/datasource.go (100%) rename api/{ => base}/v1alpha1/datasource_types.go (100%) rename api/{ => base}/v1alpha1/embedder.go (100%) rename api/{ => base}/v1alpha1/embedder_types.go (100%) rename api/{ => base}/v1alpha1/groupversion_info.go (100%) rename api/{ => base}/v1alpha1/knowledgebase.go (100%) rename api/{ => base}/v1alpha1/knowledgebase_types.go (100%) rename api/{ => base}/v1alpha1/laboratory_types.go (100%) rename api/{ => base}/v1alpha1/llm.go (100%) rename api/{ => base}/v1alpha1/llm_types.go (100%) rename api/{ => base}/v1alpha1/model.go (100%) rename api/{ => base}/v1alpha1/model_types.go (100%) rename api/{ => base}/v1alpha1/prompt_types.go (100%) rename api/{ => base}/v1alpha1/prompt_webhook.go (100%) rename api/{ => base}/v1alpha1/vectorstore.go (100%) rename api/{ => base}/v1alpha1/vectorstore_types.go (100%) rename api/{ => base}/v1alpha1/versioneddataset.go (100%) rename api/{ => base}/v1alpha1/versioneddataset_types.go (100%) rename api/{ => base}/v1alpha1/webhook_suite_test.go (95%) rename api/{ => base}/v1alpha1/worker.go (100%) rename api/{ => base}/v1alpha1/worker_types.go (100%) rename api/{ => base}/v1alpha1/zz_generated.deepcopy.go (90%) create mode 100644 config/crd/bases/arcadia.kubeagi.k8s.com.cn_applications.yaml create mode 100644 config/crd/bases/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml create mode 100644 config/crd/bases/prompt.arcadia.kubeagi.k8s.com.cn_prompts.yaml create mode 100644 config/crd/patches/cainjection_in_applications.yaml create mode 100644 config/crd/patches/webhook_in_applications.yaml create mode 100644 config/rbac/application_editor_role.yaml create mode 100644 config/rbac/application_viewer_role.yaml create mode 100644 config/samples/app_llmchain_englishteacher.yaml create mode 100644 controllers/app-node/chain/llmchain_controller.go create mode 100644 controllers/app-node/prompt/prompt_controller.go create mode 100644 controllers/application_controller.go create mode 100644 deploy/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_applications.yaml create mode 100644 deploy/charts/arcadia/crds/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml create mode 100644 deploy/charts/arcadia/crds/prompt.arcadia.kubeagi.k8s.com.cn_prompts.yaml create mode 100644 graphql-server/go-server/pkg/chat/chat.go create mode 100644 graphql-server/go-server/pkg/chat/chat_type.go create mode 100644 pkg/application/app_run.go create mode 100644 pkg/application/base/input.go create mode 100644 pkg/application/base/node.go create mode 100644 pkg/application/base/output.go create mode 100644 pkg/application/chain/llmchain.go create mode 100644 pkg/application/llm/base.go create mode 100644 pkg/application/llm/zhipu.go create mode 100644 pkg/application/prompt/prompt.go create mode 100644 pkg/llms/zhipuai/langchainllm.go diff --git a/Makefile b/Makefile index 2cbb4a753..95ac8191c 100644 --- a/Makefile +++ b/Makefile @@ -268,6 +268,7 @@ gql-sdk-generator: run-graphql-server config_rule_line_num = $(shell grep -n "rules:" config/rbac/role.yaml | cut -d: -f1) chart_rule_line_num = $(shell grep -n "rules:" deploy/charts/arcadia/templates/rbac.yaml | cut -d: -f1) prepare-push: manifests generate fmt vet + @go mod tidy @echo "install golangci-lint" @go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest @echo "run golangci-lint with auto-fix" diff --git a/PROJECT b/PROJECT index 0f57bac66..c8554097c 100644 --- a/PROJECT +++ b/PROJECT @@ -5,6 +5,7 @@ layout: plugins: manifests.sdk.operatorframework.io/v2: {} scorecard.sdk.operatorframework.io/v2: {} +multigroup: true projectName: arcadia repo: github.com/kubeagi/arcadia resources: @@ -14,7 +15,7 @@ resources: domain: kubeagi.k8s.com.cn group: arcadia kind: Laboratory - path: github.com/kubeagi/arcadia/api/v1alpha1 + path: github.com/kubeagi/arcadia/api/base/v1alpha1 version: v1alpha1 - api: crdVersion: v1 @@ -23,7 +24,7 @@ resources: domain: kubeagi.k8s.com.cn group: arcadia kind: LLM - path: github.com/kubeagi/arcadia/api/v1alpha1 + path: github.com/kubeagi/arcadia/api/base/v1alpha1 version: v1alpha1 - api: crdVersion: v1 @@ -32,7 +33,7 @@ resources: domain: kubeagi.k8s.com.cn group: arcadia kind: Prompt - path: github.com/kubeagi/arcadia/api/v1alpha1 + path: github.com/kubeagi/arcadia/api/base/v1alpha1 version: v1alpha1 webhooks: validation: true @@ -43,7 +44,7 @@ resources: domain: kubeagi.k8s.com.cn group: arcadia kind: Datasource - path: github.com/kubeagi/arcadia/api/v1alpha1 + path: github.com/kubeagi/arcadia/api/base/v1alpha1 version: v1alpha1 - api: crdVersion: v1 @@ -52,7 +53,7 @@ resources: domain: kubeagi.k8s.com.cn group: arcadia kind: Embedders - path: github.com/kubeagi/arcadia/api/v1alpha1 + path: github.com/kubeagi/arcadia/api/base/v1alpha1 version: v1alpha1 - api: crdVersion: v1 @@ -61,7 +62,7 @@ resources: domain: kubeagi.k8s.com.cn group: arcadia kind: Dataset - path: github.com/kubeagi/arcadia/api/v1alpha1 + path: github.com/kubeagi/arcadia/api/base/v1alpha1 version: v1alpha1 - api: crdVersion: v1 @@ -70,7 +71,7 @@ resources: domain: kubeagi.k8s.com.cn group: arcadia kind: VersionedDataset - path: github.com/kubeagi/arcadia/api/v1alpha1 + path: github.com/kubeagi/arcadia/api/base/v1alpha1 version: v1alpha1 - api: crdVersion: v1 @@ -79,7 +80,7 @@ resources: domain: kubeagi.k8s.com.cn group: arcadia kind: Worker - path: github.com/kubeagi/arcadia/api/v1alpha1 + path: github.com/kubeagi/arcadia/api/base/v1alpha1 version: v1alpha1 - api: crdVersion: v1 @@ -88,7 +89,7 @@ resources: domain: kubeagi.k8s.com.cn group: arcadia kind: Model - path: github.com/kubeagi/arcadia/api/v1alpha1 + path: github.com/kubeagi/arcadia/api/base/v1alpha1 version: v1alpha1 - api: crdVersion: v1 @@ -97,7 +98,7 @@ resources: domain: kubeagi.k8s.com.cn group: arcadia kind: KnowledgeBase - path: github.com/kubeagi/arcadia/api/v1alpha1 + path: github.com/kubeagi/arcadia/api/base/v1alpha1 version: v1alpha1 - api: crdVersion: v1 @@ -106,6 +107,31 @@ resources: domain: kubeagi.k8s.com.cn group: arcadia kind: VectorStore - path: github.com/kubeagi/arcadia/api/v1alpha1 + path: github.com/kubeagi/arcadia/api/base/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: kubeagi.k8s.com.cn + group: arcadia + kind: Application + path: github.com/kubeagi/arcadia/api/base/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + controller: true + domain: arcadia.kubeagi.k8s.com.cn + group: chain + kind: LLMChain + path: github.com/kubeagi/arcadia/api/app-node/chain/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + controller: true + domain: arcadia.kubeagi.k8s.com.cn + group: prompt + kind: Prompt + path: github.com/kubeagi/arcadia/api/app-node/prompt/v1alpha1 version: v1alpha1 version: "3" diff --git a/api/app-node/chain/v1alpha1/groupversion_info.go b/api/app-node/chain/v1alpha1/groupversion_info.go new file mode 100644 index 000000000..c9a8a5802 --- /dev/null +++ b/api/app-node/chain/v1alpha1/groupversion_info.go @@ -0,0 +1,41 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1alpha1 contains API Schema definitions for the arcadia v1alpha1 API group +// +kubebuilder:object:generate=true +// +groupName=chain.arcadia.kubeagi.k8s.com.cn +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +const ( + Group = "chain.arcadia.kubeagi.k8s.com.cn" + Version = "v1alpha1" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: Group, Version: Version} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/api/app-node/chain/v1alpha1/llmchain_types.go b/api/app-node/chain/v1alpha1/llmchain_types.go new file mode 100644 index 000000000..94e2888b0 --- /dev/null +++ b/api/app-node/chain/v1alpha1/llmchain_types.go @@ -0,0 +1,87 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + node "github.com/kubeagi/arcadia/api/app-node" + "github.com/kubeagi/arcadia/api/base/v1alpha1" +) + +// LLMChainSpec defines the desired state of LLMChain +type LLMChainSpec struct { + v1alpha1.CommonSpec `json:",inline"` + + CommonChainConfig `json:",inline"` + + Input Input `json:"input"` + Output Output `json:"output"` +} + +type Input struct { + LLM node.LLMRef `json:"llm"` + Prompt node.PromptRef `json:"prompt"` +} +type Output struct { + node.CommonOrInPutOrOutputRef `json:",inline"` +} + +type CommonChainConfig struct { + // 记忆相关参数 + Memory Memory `json:"memory,omitempty"` +} + +type Memory struct { + // 能记住的最大 token 数 + MaxTokenLimit int `json:"maxTokenLimit,omitempty"` +} + +// LLMChainStatus defines the observed state of LLMChain +type LLMChainStatus struct { + // ObservedGeneration is the last observed generation. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // ConditionedStatus is the current status + v1alpha1.ConditionedStatus `json:",inline"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// LLMChain is the Schema for the LLMChains API +type LLMChain struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec LLMChainSpec `json:"spec,omitempty"` + Status LLMChainStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// LLMChainList contains a list of LLMChain +type LLMChainList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []LLMChain `json:"items"` +} + +func init() { + SchemeBuilder.Register(&LLMChain{}, &LLMChainList{}) +} diff --git a/api/app-node/chain/v1alpha1/zz_generated.deepcopy.go b/api/app-node/chain/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 000000000..d6208044f --- /dev/null +++ b/api/app-node/chain/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,184 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommonChainConfig) DeepCopyInto(out *CommonChainConfig) { + *out = *in + out.Memory = in.Memory +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonChainConfig. +func (in *CommonChainConfig) DeepCopy() *CommonChainConfig { + if in == nil { + return nil + } + out := new(CommonChainConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Input) DeepCopyInto(out *Input) { + *out = *in + out.LLM = in.LLM + out.Prompt = in.Prompt +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Input. +func (in *Input) DeepCopy() *Input { + if in == nil { + return nil + } + out := new(Input) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMChain) DeepCopyInto(out *LLMChain) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMChain. +func (in *LLMChain) DeepCopy() *LLMChain { + if in == nil { + return nil + } + out := new(LLMChain) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LLMChain) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMChainList) DeepCopyInto(out *LLMChainList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]LLMChain, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMChainList. +func (in *LLMChainList) DeepCopy() *LLMChainList { + if in == nil { + return nil + } + out := new(LLMChainList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LLMChainList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMChainSpec) DeepCopyInto(out *LLMChainSpec) { + *out = *in + out.CommonSpec = in.CommonSpec + out.CommonChainConfig = in.CommonChainConfig + out.Input = in.Input + in.Output.DeepCopyInto(&out.Output) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMChainSpec. +func (in *LLMChainSpec) DeepCopy() *LLMChainSpec { + if in == nil { + return nil + } + out := new(LLMChainSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMChainStatus) DeepCopyInto(out *LLMChainStatus) { + *out = *in + in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMChainStatus. +func (in *LLMChainStatus) DeepCopy() *LLMChainStatus { + if in == nil { + return nil + } + out := new(LLMChainStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Memory) DeepCopyInto(out *Memory) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Memory. +func (in *Memory) DeepCopy() *Memory { + if in == nil { + return nil + } + out := new(Memory) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Output) DeepCopyInto(out *Output) { + *out = *in + in.CommonOrInPutOrOutputRef.DeepCopyInto(&out.CommonOrInPutOrOutputRef) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Output. +func (in *Output) DeepCopy() *Output { + if in == nil { + return nil + } + out := new(Output) + in.DeepCopyInto(out) + return out +} diff --git a/api/app-node/common_type.go b/api/app-node/common_type.go new file mode 100644 index 000000000..c83f3d8f0 --- /dev/null +++ b/api/app-node/common_type.go @@ -0,0 +1,75 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package appnode + +// +kubebuilder:object:generate=true +type CommonRef struct { + // Kind is the type of resource being referenced + // +optional + Kind string `json:"kind,omitempty"` + // Name is the name of resource being referenced + // +optional + Name string `json:"name,omitempty"` +} + +// +kubebuilder:object:generate=true +type ChainRef struct { + CommonRef `json:",inline"` + // +kubebuilder:validation:Enum="chain.arcadia.kubeagi.k8s.com.cn" + // kubebuilder:default="chain.arcadia.kubeagi.k8s.com.cn" + // APIGroup is the group for the resource being referenced. + APIGroup string `json:"apiGroup"` +} + +// +kubebuilder:object:generate=true +type PromptRef struct { + CommonRef `json:",inline"` + // +kubebuilder:validation:Enum="prompt.arcadia.kubeagi.k8s.com.cn" + // kubebuilder:default="prompt.arcadia.kubeagi.k8s.com.cn" + // APIGroup is the group for the resource being referenced. + APIGroup string `json:"apiGroup"` +} + +// +kubebuilder:object:generate=true +type LLMRef struct { + // +kubebuilder:validation:Enum="LLM" + // kubebuilder:default="LLM" + // Kind is the type of resource being referenced + Kind string `json:"kind"` + // Name is the name of resource being referenced + // +optional + Name string `json:"name,omitempty"` + // +kubebuilder:validation:Enum="arcadia.kubeagi.k8s.com.cn" + // kubebuilder:default="arcadia.kubeagi.k8s.com.cn" + // APIGroup is the group for the resource being referenced. + APIGroup string `json:"apiGroup"` +} + +// +kubebuilder:object:generate=true +type CommonOrInPutOrOutputRef struct { + // APIGroup is the group for the resource being referenced. + // If APIGroup is not specified, the specified Kind must be in the core API group. + // For any other third-party types, APIGroup is required. + APIGroup *string `json:"apiGroup,omitempty"` + // Kind is the type of resource being referenced + //+kubebuilder:default=Input + //+kubebuilder:example=Input;Output + // +optional + Kind string `json:"kind,omitempty"` + // Name is the name of resource being referenced + Name string `json:"name,omitempty"` +} diff --git a/api/app-node/prompt/v1alpha1/groupversion_info.go b/api/app-node/prompt/v1alpha1/groupversion_info.go new file mode 100644 index 000000000..6e7c8d645 --- /dev/null +++ b/api/app-node/prompt/v1alpha1/groupversion_info.go @@ -0,0 +1,41 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1alpha1 contains API Schema definitions for the arcadia v1alpha1 API group +// +kubebuilder:object:generate=true +// +groupName=prompt.arcadia.kubeagi.k8s.com.cn +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +const ( + Group = "prompt.arcadia.kubeagi.k8s.com.cn" + Version = "v1alpha1" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: Group, Version: Version} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/api/app-node/prompt/v1alpha1/prompttemplate_types.go b/api/app-node/prompt/v1alpha1/prompttemplate_types.go new file mode 100644 index 000000000..1dbc22216 --- /dev/null +++ b/api/app-node/prompt/v1alpha1/prompttemplate_types.go @@ -0,0 +1,84 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + node "github.com/kubeagi/arcadia/api/app-node" + "github.com/kubeagi/arcadia/api/base/v1alpha1" +) + +// PromptSpec defines the desired state of Prompt +type PromptSpec struct { + v1alpha1.CommonSpec `json:",inline"` + + CommonPromptConfig `json:",inline"` + + Input Input `json:"input,omitempty"` + Output Output `json:"output,omitempty"` +} + +type CommonPromptConfig struct { + // system prompts, support template + SystemMessage string `json:"systemMessage,omitempty"` + // user prompts,support template + UserMessage string `json:"userMessage,omitempty"` +} + +type Input struct { + node.CommonOrInPutOrOutputRef `json:",inline"` +} + +type Output struct { + node.CommonOrInPutOrOutputRef `json:",inline"` +} + +// PromptStatus defines the observed state of Prompt +type PromptStatus struct { + // ObservedGeneration is the last observed generation. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // ConditionedStatus is the current status + v1alpha1.ConditionedStatus `json:",inline"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// Prompt is the Schema for the Prompt API +type Prompt struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PromptSpec `json:"spec,omitempty"` + Status PromptStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// PromptList contains a list of Prompt +type PromptList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Prompt `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Prompt{}, &PromptList{}) +} diff --git a/api/app-node/prompt/v1alpha1/zz_generated.deepcopy.go b/api/app-node/prompt/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 000000000..b495f910b --- /dev/null +++ b/api/app-node/prompt/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,167 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommonPromptConfig) DeepCopyInto(out *CommonPromptConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonPromptConfig. +func (in *CommonPromptConfig) DeepCopy() *CommonPromptConfig { + if in == nil { + return nil + } + out := new(CommonPromptConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Input) DeepCopyInto(out *Input) { + *out = *in + in.CommonOrInPutOrOutputRef.DeepCopyInto(&out.CommonOrInPutOrOutputRef) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Input. +func (in *Input) DeepCopy() *Input { + if in == nil { + return nil + } + out := new(Input) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Output) DeepCopyInto(out *Output) { + *out = *in + in.CommonOrInPutOrOutputRef.DeepCopyInto(&out.CommonOrInPutOrOutputRef) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Output. +func (in *Output) DeepCopy() *Output { + if in == nil { + return nil + } + out := new(Output) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Prompt) DeepCopyInto(out *Prompt) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Prompt. +func (in *Prompt) DeepCopy() *Prompt { + if in == nil { + return nil + } + out := new(Prompt) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Prompt) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PromptList) DeepCopyInto(out *PromptList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Prompt, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PromptList. +func (in *PromptList) DeepCopy() *PromptList { + if in == nil { + return nil + } + out := new(PromptList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PromptList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PromptSpec) DeepCopyInto(out *PromptSpec) { + *out = *in + out.CommonSpec = in.CommonSpec + out.CommonPromptConfig = in.CommonPromptConfig + in.Input.DeepCopyInto(&out.Input) + in.Output.DeepCopyInto(&out.Output) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PromptSpec. +func (in *PromptSpec) DeepCopy() *PromptSpec { + if in == nil { + return nil + } + out := new(PromptSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PromptStatus) DeepCopyInto(out *PromptStatus) { + *out = *in + in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PromptStatus. +func (in *PromptStatus) DeepCopy() *PromptStatus { + if in == nil { + return nil + } + out := new(PromptStatus) + in.DeepCopyInto(out) + return out +} diff --git a/api/app-node/zz_generated.deepcopy.go b/api/app-node/zz_generated.deepcopy.go new file mode 100644 index 000000000..d0565a589 --- /dev/null +++ b/api/app-node/zz_generated.deepcopy.go @@ -0,0 +1,106 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package appnode + +import () + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ChainRef) DeepCopyInto(out *ChainRef) { + *out = *in + out.CommonRef = in.CommonRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChainRef. +func (in *ChainRef) DeepCopy() *ChainRef { + if in == nil { + return nil + } + out := new(ChainRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommonOrInPutOrOutputRef) DeepCopyInto(out *CommonOrInPutOrOutputRef) { + *out = *in + if in.APIGroup != nil { + in, out := &in.APIGroup, &out.APIGroup + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonOrInPutOrOutputRef. +func (in *CommonOrInPutOrOutputRef) DeepCopy() *CommonOrInPutOrOutputRef { + if in == nil { + return nil + } + out := new(CommonOrInPutOrOutputRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommonRef) DeepCopyInto(out *CommonRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonRef. +func (in *CommonRef) DeepCopy() *CommonRef { + if in == nil { + return nil + } + out := new(CommonRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMRef) DeepCopyInto(out *LLMRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMRef. +func (in *LLMRef) DeepCopy() *LLMRef { + if in == nil { + return nil + } + out := new(LLMRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PromptRef) DeepCopyInto(out *PromptRef) { + *out = *in + out.CommonRef = in.CommonRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PromptRef. +func (in *PromptRef) DeepCopy() *PromptRef { + if in == nil { + return nil + } + out := new(PromptRef) + in.DeepCopyInto(out) + return out +} diff --git a/api/base/v1alpha1/application.go b/api/base/v1alpha1/application.go new file mode 100644 index 000000000..b5935ad22 --- /dev/null +++ b/api/base/v1alpha1/application.go @@ -0,0 +1,22 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +const ( + InputNode = "Input" + OutputNode = "Output" +) diff --git a/api/base/v1alpha1/application_types.go b/api/base/v1alpha1/application_types.go new file mode 100644 index 000000000..c68f338d7 --- /dev/null +++ b/api/base/v1alpha1/application_types.go @@ -0,0 +1,79 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type NodeConfig struct { + // +kubebuilder:validation:Required + Name string `json:"name,omitempty"` + DisplayName string `json:"displayName,omitempty"` + Description string `json:"description,omitempty"` + Ref *TypedObjectReference `json:"ref,omitempty"` +} + +// ApplicationSpec defines the desired state of Application +type ApplicationSpec struct { + CommonSpec `json:",inline"` + // 开场白,只给客户看的内容,引导客户首次输入 + Prologue string `json:"prologue,omitempty"` + // 节点 + // +kubebuilder:validation:Required + Nodes []Node `json:"nodes"` +} + +type Node struct { + NodeConfig `json:",inline"` + NextNodeName []string `json:"nextNodeName,omitempty"` +} + +// ApplicationStatus defines the observed state of Application +type ApplicationStatus struct { + // ObservedGeneration is the last observed generation. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // ConditionedStatus is the current status + ConditionedStatus `json:",inline"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// Application is the Schema for the applications API +type Application struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ApplicationSpec `json:"spec,omitempty"` + Status ApplicationStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ApplicationList contains a list of Application +type ApplicationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Application `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Application{}, &ApplicationList{}) +} diff --git a/api/v1alpha1/common.go b/api/base/v1alpha1/common.go similarity index 100% rename from api/v1alpha1/common.go rename to api/base/v1alpha1/common.go diff --git a/api/v1alpha1/condition.go b/api/base/v1alpha1/condition.go similarity index 88% rename from api/v1alpha1/condition.go rename to api/base/v1alpha1/condition.go index 0221def95..f831d565c 100644 --- a/api/v1alpha1/condition.go +++ b/api/base/v1alpha1/condition.go @@ -214,3 +214,35 @@ func (s *ConditionedStatus) Equal(other *ConditionedStatus) bool { func (s *ConditionedStatus) IsReady() bool { return s.GetCondition(TypeReady).Status == corev1.ConditionTrue } + +func (s *ConditionedStatus) WaitingCompleteCondition() []Condition { + return []Condition{{ + Type: TypeReady, + Status: corev1.ConditionUnknown, + Reason: "Pending", + Message: "Waiting for user to complete", + LastTransitionTime: metav1.Now(), + LastSuccessfulTime: metav1.Now(), + }} +} + +func (s *ConditionedStatus) ErrorCondition(msg string) []Condition { + return []Condition{{ + Type: TypeReady, + Status: corev1.ConditionFalse, + Reason: "Error", + Message: msg, + LastTransitionTime: metav1.Now(), + LastSuccessfulTime: metav1.Now(), + }} +} + +func (s *ConditionedStatus) ReadyCondition() []Condition { + return []Condition{{ + Type: TypeReady, + Status: corev1.ConditionTrue, + LastTransitionTime: metav1.Now(), + LastSuccessfulTime: metav1.Now(), + Message: "Success", + }} +} diff --git a/api/v1alpha1/dataset.go b/api/base/v1alpha1/dataset.go similarity index 100% rename from api/v1alpha1/dataset.go rename to api/base/v1alpha1/dataset.go diff --git a/api/v1alpha1/dataset_types.go b/api/base/v1alpha1/dataset_types.go similarity index 100% rename from api/v1alpha1/dataset_types.go rename to api/base/v1alpha1/dataset_types.go diff --git a/api/v1alpha1/datasource.go b/api/base/v1alpha1/datasource.go similarity index 100% rename from api/v1alpha1/datasource.go rename to api/base/v1alpha1/datasource.go diff --git a/api/v1alpha1/datasource_types.go b/api/base/v1alpha1/datasource_types.go similarity index 100% rename from api/v1alpha1/datasource_types.go rename to api/base/v1alpha1/datasource_types.go diff --git a/api/v1alpha1/embedder.go b/api/base/v1alpha1/embedder.go similarity index 100% rename from api/v1alpha1/embedder.go rename to api/base/v1alpha1/embedder.go diff --git a/api/v1alpha1/embedder_types.go b/api/base/v1alpha1/embedder_types.go similarity index 100% rename from api/v1alpha1/embedder_types.go rename to api/base/v1alpha1/embedder_types.go diff --git a/api/v1alpha1/groupversion_info.go b/api/base/v1alpha1/groupversion_info.go similarity index 100% rename from api/v1alpha1/groupversion_info.go rename to api/base/v1alpha1/groupversion_info.go diff --git a/api/v1alpha1/knowledgebase.go b/api/base/v1alpha1/knowledgebase.go similarity index 100% rename from api/v1alpha1/knowledgebase.go rename to api/base/v1alpha1/knowledgebase.go diff --git a/api/v1alpha1/knowledgebase_types.go b/api/base/v1alpha1/knowledgebase_types.go similarity index 100% rename from api/v1alpha1/knowledgebase_types.go rename to api/base/v1alpha1/knowledgebase_types.go diff --git a/api/v1alpha1/laboratory_types.go b/api/base/v1alpha1/laboratory_types.go similarity index 100% rename from api/v1alpha1/laboratory_types.go rename to api/base/v1alpha1/laboratory_types.go diff --git a/api/v1alpha1/llm.go b/api/base/v1alpha1/llm.go similarity index 100% rename from api/v1alpha1/llm.go rename to api/base/v1alpha1/llm.go diff --git a/api/v1alpha1/llm_types.go b/api/base/v1alpha1/llm_types.go similarity index 100% rename from api/v1alpha1/llm_types.go rename to api/base/v1alpha1/llm_types.go diff --git a/api/v1alpha1/model.go b/api/base/v1alpha1/model.go similarity index 100% rename from api/v1alpha1/model.go rename to api/base/v1alpha1/model.go diff --git a/api/v1alpha1/model_types.go b/api/base/v1alpha1/model_types.go similarity index 100% rename from api/v1alpha1/model_types.go rename to api/base/v1alpha1/model_types.go diff --git a/api/v1alpha1/prompt_types.go b/api/base/v1alpha1/prompt_types.go similarity index 100% rename from api/v1alpha1/prompt_types.go rename to api/base/v1alpha1/prompt_types.go diff --git a/api/v1alpha1/prompt_webhook.go b/api/base/v1alpha1/prompt_webhook.go similarity index 100% rename from api/v1alpha1/prompt_webhook.go rename to api/base/v1alpha1/prompt_webhook.go diff --git a/api/v1alpha1/vectorstore.go b/api/base/v1alpha1/vectorstore.go similarity index 100% rename from api/v1alpha1/vectorstore.go rename to api/base/v1alpha1/vectorstore.go diff --git a/api/v1alpha1/vectorstore_types.go b/api/base/v1alpha1/vectorstore_types.go similarity index 100% rename from api/v1alpha1/vectorstore_types.go rename to api/base/v1alpha1/vectorstore_types.go diff --git a/api/v1alpha1/versioneddataset.go b/api/base/v1alpha1/versioneddataset.go similarity index 100% rename from api/v1alpha1/versioneddataset.go rename to api/base/v1alpha1/versioneddataset.go diff --git a/api/v1alpha1/versioneddataset_types.go b/api/base/v1alpha1/versioneddataset_types.go similarity index 100% rename from api/v1alpha1/versioneddataset_types.go rename to api/base/v1alpha1/versioneddataset_types.go diff --git a/api/v1alpha1/webhook_suite_test.go b/api/base/v1alpha1/webhook_suite_test.go similarity index 95% rename from api/v1alpha1/webhook_suite_test.go rename to api/base/v1alpha1/webhook_suite_test.go index 7546a2b66..a93ebed9b 100644 --- a/api/v1alpha1/webhook_suite_test.go +++ b/api/base/v1alpha1/webhook_suite_test.go @@ -64,10 +64,10 @@ var _ = BeforeSuite(func() { By("bootstrapping test environment") testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crd", "bases")}, ErrorIfCRDPathMissing: false, WebhookInstallOptions: envtest.WebhookInstallOptions{ - Paths: []string{filepath.Join("..", "..", "config", "webhook")}, + Paths: []string{filepath.Join("..", "..", "..", "config", "webhook")}, }, } diff --git a/api/v1alpha1/worker.go b/api/base/v1alpha1/worker.go similarity index 100% rename from api/v1alpha1/worker.go rename to api/base/v1alpha1/worker.go diff --git a/api/v1alpha1/worker_types.go b/api/base/v1alpha1/worker_types.go similarity index 100% rename from api/v1alpha1/worker_types.go rename to api/base/v1alpha1/worker_types.go diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/base/v1alpha1/zz_generated.deepcopy.go similarity index 90% rename from api/v1alpha1/zz_generated.deepcopy.go rename to api/base/v1alpha1/zz_generated.deepcopy.go index d63e0b2e5..5b77708d6 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/base/v1alpha1/zz_generated.deepcopy.go @@ -27,6 +27,104 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Application) DeepCopyInto(out *Application) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Application. +func (in *Application) DeepCopy() *Application { + if in == nil { + return nil + } + out := new(Application) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Application) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationList) DeepCopyInto(out *ApplicationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Application, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationList. +func (in *ApplicationList) DeepCopy() *ApplicationList { + if in == nil { + return nil + } + out := new(ApplicationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApplicationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationSpec) DeepCopyInto(out *ApplicationSpec) { + *out = *in + out.CommonSpec = in.CommonSpec + if in.Nodes != nil { + in, out := &in.Nodes, &out.Nodes + *out = make([]Node, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationSpec. +func (in *ApplicationSpec) DeepCopy() *ApplicationSpec { + if in == nil { + return nil + } + out := new(ApplicationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationStatus) DeepCopyInto(out *ApplicationStatus) { + *out = *in + in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationStatus. +func (in *ApplicationStatus) DeepCopy() *ApplicationStatus { + if in == nil { + return nil + } + out := new(ApplicationStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Chroma) DeepCopyInto(out *Chroma) { *out = *in @@ -877,6 +975,47 @@ func (in *ModelStatus) DeepCopy() *ModelStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Node) DeepCopyInto(out *Node) { + *out = *in + in.NodeConfig.DeepCopyInto(&out.NodeConfig) + if in.NextNodeName != nil { + in, out := &in.NextNodeName, &out.NextNodeName + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Node. +func (in *Node) DeepCopy() *Node { + if in == nil { + return nil + } + out := new(Node) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeConfig) DeepCopyInto(out *NodeConfig) { + *out = *in + if in.Ref != nil { + in, out := &in.Ref, &out.Ref + *out = new(TypedObjectReference) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeConfig. +func (in *NodeConfig) DeepCopy() *NodeConfig { + if in == nil { + return nil + } + out := new(NodeConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OSS) DeepCopyInto(out *OSS) { *out = *in diff --git a/config/crd/bases/arcadia.kubeagi.k8s.com.cn_applications.yaml b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_applications.yaml new file mode 100644 index 000000000..afdd76892 --- /dev/null +++ b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_applications.yaml @@ -0,0 +1,141 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: applications.arcadia.kubeagi.k8s.com.cn +spec: + group: arcadia.kubeagi.k8s.com.cn + names: + kind: Application + listKind: ApplicationList + plural: applications + singular: application + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Application is the Schema for the applications API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ApplicationSpec defines the desired state of Application + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + nodes: + description: 节点 + items: + properties: + description: + type: string + displayName: + type: string + name: + type: string + nextNodeName: + items: + type: string + type: array + ref: + properties: + apiGroup: + description: APIGroup is the group for the resource being + referenced. If APIGroup is not specified, the specified + Kind must be in the core API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: Namespace is the namespace of resource being + referenced + type: string + required: + - kind + - name + type: object + type: object + type: array + prologue: + description: 开场白,只给客户看的内容,引导客户首次输入 + type: string + required: + - nodes + type: object + status: + description: ApplicationStatus defines the observed state of Application + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml b/config/crd/bases/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml new file mode 100644 index 000000000..6feaaeb55 --- /dev/null +++ b/config/crd/bases/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml @@ -0,0 +1,168 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: llmchains.chain.arcadia.kubeagi.k8s.com.cn +spec: + group: chain.arcadia.kubeagi.k8s.com.cn + names: + kind: LLMChain + listKind: LLMChainList + plural: llmchains + singular: llmchain + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: LLMChain is the Schema for the LLMChains API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: LLMChainSpec defines the desired state of LLMChain + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + input: + properties: + llm: + properties: + apiGroup: + description: kubebuilder:default="arcadia.kubeagi.k8s.com.cn" + APIGroup is the group for the resource being referenced. + enum: + - arcadia.kubeagi.k8s.com.cn + type: string + kind: + description: kubebuilder:default="LLM" Kind is the type of + resource being referenced + enum: + - LLM + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - apiGroup + - kind + type: object + prompt: + properties: + apiGroup: + description: kubebuilder:default="prompt.arcadia.kubeagi.k8s.com.cn" + APIGroup is the group for the resource being referenced. + enum: + - prompt.arcadia.kubeagi.k8s.com.cn + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - apiGroup + type: object + required: + - llm + - prompt + type: object + memory: + description: 记忆相关参数 + properties: + maxTokenLimit: + description: 能记住的最大 token 数 + type: integer + type: object + output: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + required: + - input + - output + type: object + status: + description: LLMChainStatus defines the observed state of LLMChain + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/prompt.arcadia.kubeagi.k8s.com.cn_prompts.yaml b/config/crd/bases/prompt.arcadia.kubeagi.k8s.com.cn_prompts.yaml new file mode 100644 index 000000000..a8f1ca74d --- /dev/null +++ b/config/crd/bases/prompt.arcadia.kubeagi.k8s.com.cn_prompts.yaml @@ -0,0 +1,136 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: prompts.prompt.arcadia.kubeagi.k8s.com.cn +spec: + group: prompt.arcadia.kubeagi.k8s.com.cn + names: + kind: Prompt + listKind: PromptList + plural: prompts + singular: prompt + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Prompt is the Schema for the Prompt API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PromptSpec defines the desired state of Prompt + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + input: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + output: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + systemMessage: + description: system prompts, support template + type: string + userMessage: + description: user prompts,support template + type: string + type: object + status: + description: PromptStatus defines the observed state of Prompt + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index f9dc429a0..39c249b35 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -13,6 +13,9 @@ resources: - bases/arcadia.kubeagi.k8s.com.cn_models.yaml - bases/arcadia.kubeagi.k8s.com.cn_knowledgebases.yaml - bases/arcadia.kubeagi.k8s.com.cn_vectorstores.yaml +- bases/arcadia.kubeagi.k8s.com.cn_applications.yaml +- bases/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml +- bases/prompt.arcadia.kubeagi.k8s.com.cn_prompts.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -29,6 +32,7 @@ patchesStrategicMerge: #- patches/webhook_in_vectorstores.yaml #- patches/webhook_in_workers.yaml #- patches/webhook_in_models.yaml +#- patches/webhook_in_applications.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. @@ -44,6 +48,7 @@ patchesStrategicMerge: #- patches/cainjection_in_models.yaml #- patches/cainjection_in_knowledgebases.yaml #- patches/cainjection_in_vectorstores.yaml +#- patches/cainjection_in_applications.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/config/crd/patches/cainjection_in_applications.yaml b/config/crd/patches/cainjection_in_applications.yaml new file mode 100644 index 000000000..350815709 --- /dev/null +++ b/config/crd/patches/cainjection_in_applications.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: applications.arcadia.kubeagi.k8s.com.cn diff --git a/config/crd/patches/webhook_in_applications.yaml b/config/crd/patches/webhook_in_applications.yaml new file mode 100644 index 000000000..a97acbbba --- /dev/null +++ b/config/crd/patches/webhook_in_applications.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: applications.arcadia.kubeagi.k8s.com.cn +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/config/rbac/application_editor_role.yaml b/config/rbac/application_editor_role.yaml new file mode 100644 index 000000000..98fe8ae57 --- /dev/null +++ b/config/rbac/application_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit applications. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: application-editor-role +rules: +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications/status + verbs: + - get diff --git a/config/rbac/application_viewer_role.yaml b/config/rbac/application_viewer_role.yaml new file mode 100644 index 000000000..d484d4ca6 --- /dev/null +++ b/config/rbac/application_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view applications. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: application-viewer-role +rules: +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications + verbs: + - get + - list + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications/status + verbs: + - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 01ae04585..16ea0e05e 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -79,6 +79,32 @@ rules: - patch - update - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications/finalizers + verbs: + - update +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications/status + verbs: + - get + - patch + - update - apiGroups: - arcadia.kubeagi.k8s.com.cn resources: @@ -402,3 +428,55 @@ rules: - get - patch - update +- apiGroups: + - chain.arcadia.kubeagi.k8s.com.cn + resources: + - llmchains + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - chain.arcadia.kubeagi.k8s.com.cn + resources: + - llmchains/finalizers + verbs: + - update +- apiGroups: + - chain.arcadia.kubeagi.k8s.com.cn + resources: + - llmchains/status + verbs: + - get + - patch + - update +- apiGroups: + - prompt.arcadia.kubeagi.k8s.com.cn + resources: + - prompts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - prompt.arcadia.kubeagi.k8s.com.cn + resources: + - prompts/finalizers + verbs: + - update +- apiGroups: + - prompt.arcadia.kubeagi.k8s.com.cn + resources: + - prompts/status + verbs: + - get + - patch + - update diff --git a/config/samples/app_llmchain_englishteacher.yaml b/config/samples/app_llmchain_englishteacher.yaml new file mode 100644 index 000000000..15ae6a8b9 --- /dev/null +++ b/config/samples/app_llmchain_englishteacher.yaml @@ -0,0 +1,118 @@ +apiVersion: arcadia.kubeagi.k8s.com.cn/v1alpha1 +kind: Application +metadata: + name: base-chat-english-teacher + namespace: arcadia +spec: + displayName: "AI英语老师" + description: "最简单的应用,AI英语老师" + prologue: "Hello, I am English Teacher KubeAGI 🤖" + nodes: + - name: Input + displayName: "用户输入" + description: "用户输入节点,必须" + ref: + kind: Input + name: Input + nextNodeName: ["prompt-node"] + - name: prompt-node + displayName: "prompt" + description: "设定prompt,template中可以使用{{xx}}来替换变量" + ref: + apiGroup: prompt.arcadia.kubeagi.k8s.com.cn + kind: Prompt + name: base-chat-english-teacher + nextNodeName: ["chain-node"] + - name: llm-node + displayName: "zhipu大模型服务" + description: "设定质谱大模型的访问信息" + ref: + apiGroup: arcadia.kubeagi.k8s.com.cn + kind: LLM + name: base-chat-english-teacher + nextNodeName: ["chain-node"] + - name: chain-node + displayName: "llm chain" + description: "chain是langchain的核心概念,llmChain用于连接prompt和llm" + ref: + apiGroup: chain.arcadia.kubeagi.k8s.com.cn + kind: LLMChain + name: base-chat-english-teacher + nextNodeName: ["Output"] + - name: Output + displayName: "最终输出" + description: "最终输出节点,必须" + ref: + kind: Output + name: Output +--- +apiVersion: prompt.arcadia.kubeagi.k8s.com.cn/v1alpha1 +kind: Prompt +metadata: + name: base-chat-english-teacher + namespace: arcadia +spec: + displayName: "设定英语老师的prompt" + description: "设定英语老师的prompt,来自https://github.com/f/awesome-chatgpt-prompts?tab=readme-ov-file#act-as-an-english-translator-and-improver" + userMessage: | + I want you to act as an English translator, spelling corrector and improver. + I will speak to you in any language, and you will detect the language, + translate it and answer in the corrected and improved version of my text, in English. + I want you to replace my simplified A0-level words and sentences with more beautiful and elegant, upper level English words and sentences. + Keep the meaning same, but make them more literary. + I want you to only reply the correction, the improvements and nothing else, do not write explanations. + My sentence is: '{{.question}}' + input: + kind: "Input" + name: "Input" + output: + apiGroup: chain.arcadia.kubeagi.k8s.com.cn + kind: LLMChain + name: base-chat-english-teacher +--- +apiVersion: chain.arcadia.kubeagi.k8s.com.cn/v1alpha1 +kind: LLMChain +metadata: + name: base-chat-english-teacher + namespace: arcadia +spec: + displayName: "llm chain" + description: "llm chain" + memory: + maxTokenLimit: 20480 + input: + llm: + apiGroup: arcadia.kubeagi.k8s.com.cn + kind: LLM + name: base-chat-english-teacher + prompt: + apiGroup: prompt.arcadia.kubeagi.k8s.com.cn + kind: Prompt + name: base-chat-english-teacher + output: + apiGroup: "arcadia.kubeagi.k8s.com.cn" + kind: "Output" + name: "output-node" +--- +apiVersion: v1 +kind: Secret +metadata: + name: base-chat-english-teacher + namespace: arcadia +type: Opaque +data: + apiKey: "NGZjY2VjZWIxNjY2Y2QxMTgwOGMyMThkNmQ2MTk5NTAuVENYVXZhUUNXRnlJa3hCMw==" # replace this with your API key +--- +apiVersion: arcadia.kubeagi.k8s.com.cn/v1alpha1 +kind: LLM +metadata: + name: base-chat-english-teacher + namespace: arcadia +spec: + type: "zhipuai" + provider: + endpoint: + url: "https://open.bigmodel.cn/api/paas/v3/model-api" # replace this with your LLM URL(Zhipuai use predefined url https://open.bigmodel.cn/api/paas/v3/model-api) + authSecret: + kind: secret + name: base-chat-english-teacher diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index 4e72faac0..2535b1a8b 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -11,4 +11,6 @@ resources: - arcadia_v1alpha1_vectorstore.yaml - arcadia_v1alpha1_worker.yaml - arcadia_v1alpha1_model.yaml +- arcadia_v1alpha1_application.yaml +- app_llmchain_englishteacher.yaml #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/controllers/app-node/chain/llmchain_controller.go b/controllers/app-node/chain/llmchain_controller.go new file mode 100644 index 000000000..f28e34629 --- /dev/null +++ b/controllers/app-node/chain/llmchain_controller.go @@ -0,0 +1,142 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chain + +import ( + "context" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + api "github.com/kubeagi/arcadia/api/app-node/chain/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" +) + +// LLMChainReconciler reconciles an LLMChain object +type LLMChainReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=chain.arcadia.kubeagi.k8s.com.cn,resources=llmchains,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=chain.arcadia.kubeagi.k8s.com.cn,resources=llmchains/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=chain.arcadia.kubeagi.k8s.com.cn,resources=llmchains/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *LLMChainReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := ctrl.LoggerFrom(ctx) + log.V(1).Info("Start LLMChain Reconcile") + instance := &api.LLMChain{} + if err := r.Get(ctx, req.NamespacedName, instance); err != nil { + // There's no need to requeue if the resource no longer exists. + // Otherwise, we'll be requeued implicitly because we return an error. + log.V(1).Info("Failed to get LLMChain") + return ctrl.Result{}, client.IgnoreNotFound(err) + } + log = log.WithValues("Generation", instance.GetGeneration(), "ObservedGeneration", instance.Status.ObservedGeneration, "creator", instance.Spec.Creator) + log.V(1).Info("Get LLMChain instance") + + // Add a finalizer.Then, we can define some operations which should + // occur before the LLMChain to be deleted. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers + if newAdded := controllerutil.AddFinalizer(instance, arcadiav1alpha1.Finalizer); newAdded { + log.Info("Try to add Finalizer for LLMChain") + if err := r.Update(ctx, instance); err != nil { + log.Error(err, "Failed to update LLMChain to add finalizer, will try again later") + return ctrl.Result{}, err + } + log.Info("Adding Finalizer for LLMChain done") + return ctrl.Result{}, nil + } + + // Check if the LLMChain instance is marked to be deleted, which is + // indicated by the deletion timestamp being set. + if instance.GetDeletionTimestamp() != nil && controllerutil.ContainsFinalizer(instance, arcadiav1alpha1.Finalizer) { + log.Info("Performing Finalizer Operations for LLMChain before delete CR") + // TODO perform the finalizer operations here, for example: remove vectorstore data? + log.Info("Removing Finalizer for LLMChain after successfully performing the operations") + controllerutil.RemoveFinalizer(instance, arcadiav1alpha1.Finalizer) + if err := r.Update(ctx, instance); err != nil { + log.Error(err, "Failed to remove the finalizer for LLMChain") + return ctrl.Result{}, err + } + log.Info("Remove LLMChain done") + return ctrl.Result{}, nil + } + + instance, result, err := r.reconcile(ctx, log, instance) + + // Update status after reconciliation. + if updateStatusErr := r.patchStatus(ctx, instance); updateStatusErr != nil { + log.Error(updateStatusErr, "unable to update status after reconciliation") + return ctrl.Result{Requeue: true}, updateStatusErr + } + + return result, err +} + +func (r *LLMChainReconciler) reconcile(ctx context.Context, log logr.Logger, instance *api.LLMChain) (*api.LLMChain, ctrl.Result, error) { + // Observe generation change + if instance.Status.ObservedGeneration != instance.Generation { + instance.Status.ObservedGeneration = instance.Generation + r.setCondition(instance, instance.Status.WaitingCompleteCondition()...) + if updateStatusErr := r.patchStatus(ctx, instance); updateStatusErr != nil { + log.Error(updateStatusErr, "unable to update status after generation update") + return instance, ctrl.Result{Requeue: true}, updateStatusErr + } + } + + if instance.Status.IsReady() { + return instance, ctrl.Result{}, nil + } + // Note: should change here + // TODO: we should do more checks later.For example: + // LLM status + // Prompt status + if instance.Spec.Input.LLM.Name != "" && instance.Spec.Input.Prompt.Name != "" { + instance.Status.SetConditions(instance.Status.ReadyCondition()...) + } + return instance, ctrl.Result{}, nil +} + +func (r *LLMChainReconciler) patchStatus(ctx context.Context, instance *api.LLMChain) error { + latest := &api.LLMChain{} + if err := r.Client.Get(ctx, client.ObjectKeyFromObject(instance), latest); err != nil { + return err + } + patch := client.MergeFrom(latest.DeepCopy()) + latest.Status = instance.Status + return r.Client.Status().Patch(ctx, latest, patch, client.FieldOwner("LLMChain-controller")) +} + +// SetupWithManager sets up the controller with the Manager. +func (r *LLMChainReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&api.LLMChain{}). + Complete(r) +} + +func (r *LLMChainReconciler) setCondition(instance *api.LLMChain, condition ...arcadiav1alpha1.Condition) *api.LLMChain { + instance.Status.SetConditions(condition...) + return instance +} diff --git a/controllers/app-node/prompt/prompt_controller.go b/controllers/app-node/prompt/prompt_controller.go new file mode 100644 index 000000000..f5e0cf5d4 --- /dev/null +++ b/controllers/app-node/prompt/prompt_controller.go @@ -0,0 +1,140 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chain + +import ( + "context" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + api "github.com/kubeagi/arcadia/api/app-node/prompt/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" +) + +// PromptReconciler reconciles an Prompt object +type PromptReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=prompt.arcadia.kubeagi.k8s.com.cn,resources=prompts,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=prompt.arcadia.kubeagi.k8s.com.cn,resources=prompts/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=prompt.arcadia.kubeagi.k8s.com.cn,resources=prompts/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *PromptReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := ctrl.LoggerFrom(ctx) + log.V(1).Info("Start Prompt Reconcile") + instance := &api.Prompt{} + if err := r.Get(ctx, req.NamespacedName, instance); err != nil { + // There's no need to requeue if the resource no longer exists. + // Otherwise, we'll be requeued implicitly because we return an error. + log.V(1).Info("Failed to get Prompt") + return ctrl.Result{}, client.IgnoreNotFound(err) + } + log = log.WithValues("Generation", instance.GetGeneration(), "ObservedGeneration", instance.Status.ObservedGeneration, "creator", instance.Spec.Creator) + log.V(1).Info("Get Prompt instance") + + // Add a finalizer.Then, we can define some operations which should + // occur before the Prompt to be deleted. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers + if newAdded := controllerutil.AddFinalizer(instance, arcadiav1alpha1.Finalizer); newAdded { + log.Info("Try to add Finalizer for Prompt") + if err := r.Update(ctx, instance); err != nil { + log.Error(err, "Failed to update Prompt to add finalizer, will try again later") + return ctrl.Result{}, err + } + log.Info("Adding Finalizer for Prompt done") + return ctrl.Result{}, nil + } + + // Check if the Prompt instance is marked to be deleted, which is + // indicated by the deletion timestamp being set. + if instance.GetDeletionTimestamp() != nil && controllerutil.ContainsFinalizer(instance, arcadiav1alpha1.Finalizer) { + log.Info("Performing Finalizer Operations for Prompt before delete CR") + // TODO perform the finalizer operations here, for example: remove vectorstore data? + log.Info("Removing Finalizer for Prompt after successfully performing the operations") + controllerutil.RemoveFinalizer(instance, arcadiav1alpha1.Finalizer) + if err := r.Update(ctx, instance); err != nil { + log.Error(err, "Failed to remove the finalizer for Prompt") + return ctrl.Result{}, err + } + log.Info("Remove Prompt done") + return ctrl.Result{}, nil + } + + instance, result, err := r.reconcile(ctx, log, instance) + + // Update status after reconciliation. + if updateStatusErr := r.patchStatus(ctx, instance); updateStatusErr != nil { + log.Error(updateStatusErr, "unable to update status after reconciliation") + return ctrl.Result{Requeue: true}, updateStatusErr + } + + return result, err +} + +func (r *PromptReconciler) reconcile(ctx context.Context, log logr.Logger, instance *api.Prompt) (*api.Prompt, ctrl.Result, error) { + // Observe generation change + if instance.Status.ObservedGeneration != instance.Generation { + instance.Status.ObservedGeneration = instance.Generation + r.setCondition(instance, instance.Status.WaitingCompleteCondition()...) + if updateStatusErr := r.patchStatus(ctx, instance); updateStatusErr != nil { + log.Error(updateStatusErr, "unable to update status after generation update") + return instance, ctrl.Result{Requeue: true}, updateStatusErr + } + } + + if instance.Status.IsReady() { + return instance, ctrl.Result{}, nil + } + // Note: should change here + // TODO: should add more check here + if instance.Spec.Input.Name != "" { + instance.Status.SetConditions(instance.Status.ReadyCondition()...) + } + return instance, ctrl.Result{}, nil +} + +func (r *PromptReconciler) patchStatus(ctx context.Context, instance *api.Prompt) error { + latest := &api.Prompt{} + if err := r.Client.Get(ctx, client.ObjectKeyFromObject(instance), latest); err != nil { + return err + } + patch := client.MergeFrom(latest.DeepCopy()) + latest.Status = instance.Status + return r.Client.Status().Patch(ctx, latest, patch, client.FieldOwner("Prompt-controller")) +} + +// SetupWithManager sets up the controller with the Manager. +func (r *PromptReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&api.Prompt{}). + Complete(r) +} + +func (r *PromptReconciler) setCondition(instance *api.Prompt, condition ...arcadiav1alpha1.Condition) *api.Prompt { + instance.Status.SetConditions(condition...) + return instance +} diff --git a/controllers/application_controller.go b/controllers/application_controller.go new file mode 100644 index 000000000..e0ffa4ac7 --- /dev/null +++ b/controllers/application_controller.go @@ -0,0 +1,210 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers + +import ( + "context" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" +) + +// ApplicationReconciler reconciles an Application object +type ApplicationReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=applications,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=applications/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=applications/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *ApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := ctrl.LoggerFrom(ctx) + log.V(1).Info("Start Application Reconcile") + app := &arcadiav1alpha1.Application{} + if err := r.Get(ctx, req.NamespacedName, app); err != nil { + // There's no need to requeue if the resource no longer exists. + // Otherwise, we'll be requeued implicitly because we return an error. + log.V(1).Info("Failed to get Application") + return ctrl.Result{}, client.IgnoreNotFound(err) + } + log = log.WithValues("Generation", app.GetGeneration(), "ObservedGeneration", app.Status.ObservedGeneration, "creator", app.Spec.Creator) + log.V(1).Info("Get Application instance") + + // Add a finalizer.Then, we can define some operations which should + // occur before the Application to be deleted. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers + if newAdded := controllerutil.AddFinalizer(app, arcadiav1alpha1.Finalizer); newAdded { + log.Info("Try to add Finalizer for Application") + if err := r.Update(ctx, app); err != nil { + log.Error(err, "Failed to update Application to add finalizer, will try again later") + return ctrl.Result{}, err + } + log.Info("Adding Finalizer for Application done") + return ctrl.Result{}, nil + } + + // Check if the Application instance is marked to be deleted, which is + // indicated by the deletion timestamp being set. + if app.GetDeletionTimestamp() != nil && controllerutil.ContainsFinalizer(app, arcadiav1alpha1.Finalizer) { + log.Info("Performing Finalizer Operations for Application before delete CR") + // TODO perform the finalizer operations here, for example: remove vectorstore data? + log.Info("Removing Finalizer for Application after successfully performing the operations") + controllerutil.RemoveFinalizer(app, arcadiav1alpha1.Finalizer) + if err := r.Update(ctx, app); err != nil { + log.Error(err, "Failed to remove finalizer for Application") + return ctrl.Result{}, err + } + log.Info("Remove Application done") + return ctrl.Result{}, nil + } + + app, result, err := r.reconcile(ctx, log, app) + + // Update status after reconciliation. + if updateStatusErr := r.patchStatus(ctx, app); updateStatusErr != nil { + log.Error(updateStatusErr, "unable to update status after reconciliation") + return ctrl.Result{Requeue: true}, updateStatusErr + } + + return result, err +} + +// validate nodes: +// todo remove to webhook +// 1. input node must have next node +// 2. output node must not have next node +// 3. input node must only have one +// 4. input node must only have one +// 5. only one node connected to output, and this node type should be chain or agent +// 6. when this node points to output, it can only point to output +// 7. should not have cycle TODO +// 8. nodeName should be unique +func (r *ApplicationReconciler) validateNodes(ctx context.Context, log logr.Logger, app *arcadiav1alpha1.Application) (*arcadiav1alpha1.Application, ctrl.Result, error) { + var input, output int + var outputNodeName string + nodeName := make(map[string]bool, len(app.Spec.Nodes)) + for _, node := range app.Spec.Nodes { + if _, ok := nodeName[node.Name]; ok { + r.setCondition(app, app.Status.ErrorCondition("node name should be unique")...) + return app, ctrl.Result{}, nil + } + nodeName[node.Name] = true + if node.Ref.Kind == arcadiav1alpha1.InputNode { + input++ + if len(node.NextNodeName) == 0 { + r.setCondition(app, app.Status.ErrorCondition("input node needs one or more next nodes")...) + return app, ctrl.Result{}, nil + } + } + if node.Ref.Kind == arcadiav1alpha1.OutputNode { + output++ + outputNodeName = node.Name + if len(node.NextNodeName) != 0 { + r.setCondition(app, app.Status.ErrorCondition("output node should not have next nodes")...) + return app, ctrl.Result{}, nil + } + } + } + if input != 1 { + r.setCondition(app, app.Status.ErrorCondition("need one input node")...) + return app, ctrl.Result{}, nil + } + if output != 1 { + r.setCondition(app, app.Status.ErrorCondition("need one output node")...) + return app, ctrl.Result{}, nil + } + + var toOutput int + var toOutputNodeNext int + for _, node := range app.Spec.Nodes { + for _, n := range node.NextNodeName { + if n == outputNodeName { + toOutput++ + group := node.Ref.APIGroup + if group == nil { + r.setCondition(app, app.Status.ErrorCondition("node should have ref.group setting")...) + return app, ctrl.Result{}, nil + } + if *group != "chain.arcadia.kubeagi.k8s.com.cn" && *group != "agent.arcadia.kubeagi.k8s.com.cn" { + r.setCondition(app, app.Status.ErrorCondition("ending node should be chain or agent")...) + return app, ctrl.Result{}, nil + } + } + toOutputNodeNext = len(node.NextNodeName) + } + } + if toOutput != 1 { + r.setCondition(app, app.Status.ErrorCondition("only one node can output")...) + return app, ctrl.Result{}, nil + } + if toOutputNodeNext != 1 { + r.setCondition(app, app.Status.ErrorCondition("when this node points to output, it can only point to output")...) + return app, ctrl.Result{}, nil + } + + r.setCondition(app, app.Status.ReadyCondition()...) + return app, ctrl.Result{}, nil +} + +func (r *ApplicationReconciler) reconcile(ctx context.Context, log logr.Logger, app *arcadiav1alpha1.Application) (*arcadiav1alpha1.Application, ctrl.Result, error) { + // Observe generation change + if app.Status.ObservedGeneration != app.Generation { + app.Status.ObservedGeneration = app.Generation + r.setCondition(app, app.Status.WaitingCompleteCondition()...) + if updateStatusErr := r.patchStatus(ctx, app); updateStatusErr != nil { + log.Error(updateStatusErr, "unable to update status after generation update") + return app, ctrl.Result{Requeue: true}, updateStatusErr + } + } + if app.Status.IsReady() { + return app, ctrl.Result{}, nil + } + return r.validateNodes(ctx, log, app) +} + +func (r *ApplicationReconciler) patchStatus(ctx context.Context, app *arcadiav1alpha1.Application) error { + latest := &arcadiav1alpha1.Application{} + if err := r.Client.Get(ctx, client.ObjectKeyFromObject(app), latest); err != nil { + return err + } + patch := client.MergeFrom(latest.DeepCopy()) + latest.Status = app.Status + return r.Client.Status().Patch(ctx, latest, patch, client.FieldOwner("application-controller")) +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ApplicationReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&arcadiav1alpha1.Application{}). + Complete(r) +} + +func (r *ApplicationReconciler) setCondition(app *arcadiav1alpha1.Application, condition ...arcadiav1alpha1.Condition) *arcadiav1alpha1.Application { + app.Status.SetConditions(condition...) + return app +} diff --git a/controllers/dataset_controller.go b/controllers/dataset_controller.go index f1ab93b04..d9592e0ab 100644 --- a/controllers/dataset_controller.go +++ b/controllers/dataset_controller.go @@ -26,7 +26,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/reconcile" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/pkg/utils" ) diff --git a/controllers/datasource_controller.go b/controllers/datasource_controller.go index e1bbcdc0e..9e3b63688 100644 --- a/controllers/datasource_controller.go +++ b/controllers/datasource_controller.go @@ -34,7 +34,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/pkg/config" "github.com/kubeagi/arcadia/pkg/datasource" ) diff --git a/controllers/embedder_controller.go b/controllers/embedder_controller.go index 5da870bcc..4ac5833ac 100644 --- a/controllers/embedder_controller.go +++ b/controllers/embedder_controller.go @@ -31,7 +31,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/log" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/pkg/embeddings" "github.com/kubeagi/arcadia/pkg/llms/openai" "github.com/kubeagi/arcadia/pkg/llms/zhipuai" diff --git a/controllers/knowledgebase_controller.go b/controllers/knowledgebase_controller.go index 2ef0c899a..cccfa9c14 100644 --- a/controllers/knowledgebase_controller.go +++ b/controllers/knowledgebase_controller.go @@ -40,7 +40,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/pkg/config" "github.com/kubeagi/arcadia/pkg/datasource" pkgdocumentloaders "github.com/kubeagi/arcadia/pkg/documentloaders" diff --git a/controllers/laboratory_controller.go b/controllers/laboratory_controller.go index d04f2649b..b547abb80 100644 --- a/controllers/laboratory_controller.go +++ b/controllers/laboratory_controller.go @@ -24,7 +24,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/log" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" ) // LaboratoryReconciler reconciles a Laboratory object diff --git a/controllers/llm_controller.go b/controllers/llm_controller.go index 6a9d22b7b..f94ec01ea 100644 --- a/controllers/llm_controller.go +++ b/controllers/llm_controller.go @@ -35,7 +35,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/predicate" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/pkg/llms" "github.com/kubeagi/arcadia/pkg/llms/openai" "github.com/kubeagi/arcadia/pkg/llms/zhipuai" diff --git a/controllers/model_controller.go b/controllers/model_controller.go index 5390de98d..497b264d8 100644 --- a/controllers/model_controller.go +++ b/controllers/model_controller.go @@ -35,7 +35,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/pkg/config" "github.com/kubeagi/arcadia/pkg/datasource" ) diff --git a/controllers/prompt_controller.go b/controllers/prompt_controller.go index 36d29df97..69204d5e5 100644 --- a/controllers/prompt_controller.go +++ b/controllers/prompt_controller.go @@ -34,7 +34,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/pkg/llms" "github.com/kubeagi/arcadia/pkg/llms/openai" llmszhipuai "github.com/kubeagi/arcadia/pkg/llms/zhipuai" diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 4eab5516a..4e34c08e2 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -28,7 +28,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" diff --git a/controllers/vectorstore_controller.go b/controllers/vectorstore_controller.go index 3ab695455..8791c838e 100644 --- a/controllers/vectorstore_controller.go +++ b/controllers/vectorstore_controller.go @@ -27,7 +27,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/reconcile" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" ) // VectorStoreReconciler reconciles a VectorStore object diff --git a/controllers/versioneddataset_controller.go b/controllers/versioneddataset_controller.go index 4e2ebfa7b..3fd7e0cb8 100644 --- a/controllers/versioneddataset_controller.go +++ b/controllers/versioneddataset_controller.go @@ -31,7 +31,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/pkg/config" "github.com/kubeagi/arcadia/pkg/datasource" "github.com/kubeagi/arcadia/pkg/scheduler" diff --git a/controllers/worker_controller.go b/controllers/worker_controller.go index eea036b36..431fbb4fc 100644 --- a/controllers/worker_controller.go +++ b/controllers/worker_controller.go @@ -36,7 +36,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/source" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/pkg/config" arcadiaworker "github.com/kubeagi/arcadia/pkg/worker" ) diff --git a/deploy/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_applications.yaml b/deploy/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_applications.yaml new file mode 100644 index 000000000..afdd76892 --- /dev/null +++ b/deploy/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_applications.yaml @@ -0,0 +1,141 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: applications.arcadia.kubeagi.k8s.com.cn +spec: + group: arcadia.kubeagi.k8s.com.cn + names: + kind: Application + listKind: ApplicationList + plural: applications + singular: application + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Application is the Schema for the applications API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ApplicationSpec defines the desired state of Application + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + nodes: + description: 节点 + items: + properties: + description: + type: string + displayName: + type: string + name: + type: string + nextNodeName: + items: + type: string + type: array + ref: + properties: + apiGroup: + description: APIGroup is the group for the resource being + referenced. If APIGroup is not specified, the specified + Kind must be in the core API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: Namespace is the namespace of resource being + referenced + type: string + required: + - kind + - name + type: object + type: object + type: array + prologue: + description: 开场白,只给客户看的内容,引导客户首次输入 + type: string + required: + - nodes + type: object + status: + description: ApplicationStatus defines the observed state of Application + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/charts/arcadia/crds/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml b/deploy/charts/arcadia/crds/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml new file mode 100644 index 000000000..6feaaeb55 --- /dev/null +++ b/deploy/charts/arcadia/crds/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml @@ -0,0 +1,168 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: llmchains.chain.arcadia.kubeagi.k8s.com.cn +spec: + group: chain.arcadia.kubeagi.k8s.com.cn + names: + kind: LLMChain + listKind: LLMChainList + plural: llmchains + singular: llmchain + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: LLMChain is the Schema for the LLMChains API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: LLMChainSpec defines the desired state of LLMChain + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + input: + properties: + llm: + properties: + apiGroup: + description: kubebuilder:default="arcadia.kubeagi.k8s.com.cn" + APIGroup is the group for the resource being referenced. + enum: + - arcadia.kubeagi.k8s.com.cn + type: string + kind: + description: kubebuilder:default="LLM" Kind is the type of + resource being referenced + enum: + - LLM + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - apiGroup + - kind + type: object + prompt: + properties: + apiGroup: + description: kubebuilder:default="prompt.arcadia.kubeagi.k8s.com.cn" + APIGroup is the group for the resource being referenced. + enum: + - prompt.arcadia.kubeagi.k8s.com.cn + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - apiGroup + type: object + required: + - llm + - prompt + type: object + memory: + description: 记忆相关参数 + properties: + maxTokenLimit: + description: 能记住的最大 token 数 + type: integer + type: object + output: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + required: + - input + - output + type: object + status: + description: LLMChainStatus defines the observed state of LLMChain + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/charts/arcadia/crds/prompt.arcadia.kubeagi.k8s.com.cn_prompts.yaml b/deploy/charts/arcadia/crds/prompt.arcadia.kubeagi.k8s.com.cn_prompts.yaml new file mode 100644 index 000000000..a8f1ca74d --- /dev/null +++ b/deploy/charts/arcadia/crds/prompt.arcadia.kubeagi.k8s.com.cn_prompts.yaml @@ -0,0 +1,136 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: prompts.prompt.arcadia.kubeagi.k8s.com.cn +spec: + group: prompt.arcadia.kubeagi.k8s.com.cn + names: + kind: Prompt + listKind: PromptList + plural: prompts + singular: prompt + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Prompt is the Schema for the Prompt API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PromptSpec defines the desired state of Prompt + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + input: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + output: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + systemMessage: + description: system prompts, support template + type: string + userMessage: + description: user prompts,support template + type: string + type: object + status: + description: PromptStatus defines the observed state of Prompt + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/charts/arcadia/templates/rbac.yaml b/deploy/charts/arcadia/templates/rbac.yaml index 53c1c8bab..b96a95fae 100644 --- a/deploy/charts/arcadia/templates/rbac.yaml +++ b/deploy/charts/arcadia/templates/rbac.yaml @@ -96,6 +96,32 @@ rules: - patch - update - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications/finalizers + verbs: + - update +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications/status + verbs: + - get + - patch + - update - apiGroups: - arcadia.kubeagi.k8s.com.cn resources: @@ -419,3 +445,55 @@ rules: - get - patch - update +- apiGroups: + - chain.arcadia.kubeagi.k8s.com.cn + resources: + - llmchains + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - chain.arcadia.kubeagi.k8s.com.cn + resources: + - llmchains/finalizers + verbs: + - update +- apiGroups: + - chain.arcadia.kubeagi.k8s.com.cn + resources: + - llmchains/status + verbs: + - get + - patch + - update +- apiGroups: + - prompt.arcadia.kubeagi.k8s.com.cn + resources: + - prompts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - prompt.arcadia.kubeagi.k8s.com.cn + resources: + - prompts/finalizers + verbs: + - update +- apiGroups: + - prompt.arcadia.kubeagi.k8s.com.cn + resources: + - prompts/status + verbs: + - get + - patch + - update diff --git a/go.mod b/go.mod index d9816fd39..95b6f17cc 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/KawashiroNitori/butcher/v2 v2.0.1 github.com/amikos-tech/chroma-go v0.0.0-20230901221218-d0087270239e github.com/coreos/go-oidc/v3 v3.7.0 + github.com/gin-gonic/gin v1.9.1 github.com/go-logr/logr v1.2.0 github.com/gofiber/fiber/v2 v2.49.1 github.com/golang-jwt/jwt v3.2.2+incompatible @@ -26,19 +27,41 @@ require ( ) require ( + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.2.0 // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // 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.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.3 // indirect + github.com/huandu/xstrings v1.3.3 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/leodido/go-urn v1.2.4 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/sha256-simd v1.0.1 // indirect + github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.0 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/xid v1.5.0 // indirect + github.com/shopspring/decimal v1.2.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sosodev/duration v1.1.0 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 // indirect + golang.org/x/arch v0.3.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/go.sum b/go.sum index 150815a89..a9c033bab 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,11 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/KawashiroNitori/butcher/v2 v2.0.1 h1:yJJyf9WO5BUvJxnxWAOAXQcY9+VqwnYcLV9MAgdrbtg= github.com/KawashiroNitori/butcher/v2 v2.0.1/go.mod h1:weH8qSjiTj6yGC956511noOaW4W6W9IW08Qhg78aVas= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -109,6 +112,9 @@ github.com/bjwswang/chroma-go v0.0.0-20231011091545-0041221c9bb3 h1:s82xa+vCYaW2 github.com/bjwswang/chroma-go v0.0.0-20231011091545-0041221c9bb3/go.mod h1:uJwgGN4rBUTMI88Rn68Xia+cTRogOo0/elcPvJYFtBU= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= @@ -116,6 +122,9 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -177,9 +186,15 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= 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/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.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -208,8 +223,18 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +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.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofiber/fiber/v2 v2.49.1 h1:0W2DRWevSirc8pJl4o8r8QejDR8TV6ZUCawHxwbIdOk= github.com/gofiber/fiber/v2 v2.49.1/go.mod h1:nPUeEBUeeYGgwbDm59Gp7vS8MDyScL6ezr/Np9A13WU= @@ -294,6 +319,7 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -336,9 +362,11 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= @@ -367,6 +395,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -382,6 +411,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -411,6 +442,7 @@ github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dz github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -422,6 +454,7 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -460,6 +493,8 @@ github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5h github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -515,6 +550,7 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -535,6 +571,7 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= @@ -546,12 +583,19 @@ github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= @@ -559,6 +603,10 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/langchaingo v0.0.0-20231017212009-949349d5ef9c h1:CgTequ9Xl8+3sOsjXeKj2g2jH+P3QLNXtATONeDMziE= github.com/tmc/langchaingo v0.0.0-20231017212009-949349d5ef9c/go.mod h1:SiwyRS7sBSSi6f3NB4dKENw69X6br/wZ2WRkM+8pZWk= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.49.0 h1:9FdvCpmxB74LH4dPb7IJ1cOSsluR07XG3I1txXWwJpE= @@ -619,6 +667,7 @@ go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4 go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 h1:Ss6D3hLXTM0KobyBYEAygXzFfGcjnmfEJOBgSbemCtg= +go.starlark.net v0.0.0-20230302034142-4b1e35fe2254/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -633,6 +682,9 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 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= @@ -645,6 +697,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -739,6 +792,7 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= @@ -840,12 +894,15 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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.2.0/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.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= @@ -859,6 +916,7 @@ 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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= @@ -1115,6 +1173,7 @@ k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= 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= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= diff --git a/graphql-server/go-server/graph/impl/dataset.resolvers.go b/graphql-server/go-server/graph/impl/dataset.resolvers.go index da1c333a7..9d96a52b2 100644 --- a/graphql-server/go-server/graph/impl/dataset.resolvers.go +++ b/graphql-server/go-server/graph/impl/dataset.resolvers.go @@ -8,7 +8,7 @@ import ( "context" "fmt" - "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/graphql-server/go-server/graph/generated" "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/auth" "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/client" diff --git a/graphql-server/go-server/graph/impl/knowledgebase.resolvers.go b/graphql-server/go-server/graph/impl/knowledgebase.resolvers.go index 1555dfc38..d5191c6e7 100644 --- a/graphql-server/go-server/graph/impl/knowledgebase.resolvers.go +++ b/graphql-server/go-server/graph/impl/knowledgebase.resolvers.go @@ -8,7 +8,7 @@ import ( "context" "strings" - "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/graphql-server/go-server/graph/generated" "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/auth" "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/client" diff --git a/graphql-server/go-server/main.go b/graphql-server/go-server/main.go index 5a739abca..68828ed79 100644 --- a/graphql-server/go-server/main.go +++ b/graphql-server/go-server/main.go @@ -27,11 +27,13 @@ import ( "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/playground" + "github.com/gin-gonic/gin" "k8s.io/klog/v2" "github.com/kubeagi/arcadia/graphql-server/go-server/graph/generated" "github.com/kubeagi/arcadia/graphql-server/go-server/graph/impl" "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/auth" + "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/chat" "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/dataprocessing" "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/minio" "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/oidc" @@ -68,6 +70,25 @@ func main() { // initialize dataprocessing dataprocessing.Init(*dataProcessingURL) + r := gin.Default() + r.POST("/bff", graphqlHandler()) + if *enablePlayground { + r.GET("/", playgroundHandler()) + } + r.POST("/chat", chatHandler()) + + // todo refactor these handlers like others + http.HandleFunc("/minio/get_chunks", minio.GetSuccessChunks) + http.HandleFunc("/minio/new_multipart", minio.NewMultipart) + http.HandleFunc("/minio/get_multipart_url", minio.GetMultipartUploadURL) + http.HandleFunc("/minio/complete_multipart", minio.CompleteMultipart) + http.HandleFunc("/minio/update_chunk", minio.UpdateMultipart) + + klog.Infof("listening server on port: %d", *port) + log.Fatal(r.Run(fmt.Sprintf("%s:%d", *host, *port))) +} + +func graphqlHandler() gin.HandlerFunc { srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &impl.Resolver{}})) srv.AroundFields(func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { rc := graphql.GetFieldContext(ctx) @@ -76,29 +97,40 @@ func main() { klog.Infoln("Left", rc.Object, rc.Field.Name, "=>", res, err) return res, err }) + serveHTTP := srv.ServeHTTP + if *enableOIDC { + serveHTTP = auth.AuthInterceptor(oidc.Verifier, srv.ServeHTTP) + } + return func(c *gin.Context) { + serveHTTP(c.Writer, c.Request) + } +} - if *enablePlayground { - endpoint := "/bff" - if *playgroundEndpointPrefix != "" { - if prefix := strings.TrimPrefix(strings.TrimSuffix(*playgroundEndpointPrefix, "/"), "/"); prefix != "" { - endpoint = fmt.Sprintf("/%s%s", prefix, endpoint) - } +func playgroundHandler() gin.HandlerFunc { + endpoint := "/bff" + if *playgroundEndpointPrefix != "" { + if prefix := strings.TrimPrefix(strings.TrimSuffix(*playgroundEndpointPrefix, "/"), "/"); prefix != "" { + endpoint = fmt.Sprintf("/%s%s", prefix, endpoint) } - http.Handle("/", playground.Handler("Arcadia-Graphql-Server", endpoint)) } - - if *enableOIDC { - http.Handle("/bff", auth.AuthInterceptor(oidc.Verifier, srv.ServeHTTP)) - } else { - http.Handle("/bff", srv) + h := playground.Handler("Arcadia-Graphql-Server", endpoint) + return func(c *gin.Context) { + h.ServeHTTP(c.Writer, c.Request) } +} - http.HandleFunc("/minio/get_chunks", minio.GetSuccessChunks) - http.HandleFunc("/minio/new_multipart", minio.NewMultipart) - http.HandleFunc("/minio/get_multipart_url", minio.GetMultipartUploadURL) - http.HandleFunc("/minio/complete_multipart", minio.CompleteMultipart) - http.HandleFunc("/minio/update_chunk", minio.UpdateMultipart) - - klog.Infof("listening server on port: %d", *port) - log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%d", *host, *port), nil)) +func chatHandler() gin.HandlerFunc { + return func(c *gin.Context) { + req := chat.ChatReqBody{} + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + resp, err := chat.AppRun(c, req) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, resp) + } } diff --git a/graphql-server/go-server/pkg/chat/chat.go b/graphql-server/go-server/pkg/chat/chat.go new file mode 100644 index 000000000..9cc93e606 --- /dev/null +++ b/graphql-server/go-server/pkg/chat/chat.go @@ -0,0 +1,98 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chat + +import ( + "context" + "errors" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/uuid" + + "github.com/kubeagi/arcadia/api/base/v1alpha1" + "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/auth" + "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/client" + "github.com/kubeagi/arcadia/pkg/application" +) + +var Conversions = map[string]Conversion{} + +func AppRun(ctx context.Context, req ChatReqBody) (*ChatRespBody, error) { + token := auth.ForOIDCToken(ctx) + c, err := client.GetClient(token) + if err != nil { + return nil, err + } + obj, err := c.Resource(schema.GroupVersionResource{Group: v1alpha1.GroupVersion.Group, Version: v1alpha1.GroupVersion.Version, Resource: "applications"}). + Namespace(req.AppNamespace).Get(ctx, req.APPName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + app := &v1alpha1.Application{} + err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), app) + if err != nil { + return nil, err + } + if !app.Status.IsReady() { + return nil, errors.New("application is not ready") + } + var conversion Conversion + if req.ConversionID != "" { + var ok bool + conversion, ok = Conversions[req.ConversionID] + if !ok { + return nil, errors.New("conversion is not found") + } + if conversion.AppName != req.APPName || conversion.AppNamespce != req.AppNamespace { + return nil, errors.New("conversion id not match with app info") + } + } else { + conversion = Conversion{ + ID: string(uuid.NewUUID()), + AppName: req.APPName, + AppNamespce: req.AppNamespace, + StartedAt: time.Now(), + UpdatedAt: time.Now(), + Messages: make([]Message, 0), + } + } + conversion.Messages = append(conversion.Messages, Message{ + ID: string(uuid.NewUUID()), + Query: req.Query, + Answer: "", + }) + appRun, err := application.NewAppOrGetFromCache(ctx, app, c) + if err != nil { + return nil, err + } + out, err := appRun.Run(ctx, c, application.Input{Question: req.Query}) + if err != nil { + return nil, err + } + conversion.Messages[len(conversion.Messages)-1].Answer = out.Answer + Conversions[conversion.ID] = conversion + return &ChatRespBody{ + ConversionID: conversion.ID, + Message: out.Answer, + CreatedAt: time.Now(), + }, nil +} + +// todo Reuse the flow without having to rebuild req same, not finish, Flow doesn't start with/contain nodes that depend on incomingInput.question diff --git a/graphql-server/go-server/pkg/chat/chat_type.go b/graphql-server/go-server/pkg/chat/chat_type.go new file mode 100644 index 000000000..44e917f18 --- /dev/null +++ b/graphql-server/go-server/pkg/chat/chat_type.go @@ -0,0 +1,57 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chat + +import "time" + +type ResponseMode string + +const ( + Blocking ResponseMode = "blocking" + Streaming ResponseMode = "streaming" + // todo isFlowValidForStream only some node(llm chain) support streaming +) + +type ChatReqBody struct { + Query string `json:"query" binding:"required"` + ResponseMode ResponseMode `json:"response_mode" binding:"required"` + ConversionID string `json:"conversion_id"` + APPName string `json:"app_name" binding:"required"` + AppNamespace string `json:"app_namespace" binding:"required"` +} + +type ChatRespBody struct { + ConversionID string `json:"conversion_id"` + MessageID string `json:"message_id"` + Message string `json:"message"` + CreatedAt time.Time `json:"created_at"` +} + +type Conversion struct { + ID string `json:"id"` + AppName string `json:"app_name"` + AppNamespce string `json:"app_namespace"` + StartedAt time.Time `json:"started_at"` + UpdatedAt time.Time `json:"updated_at"` + Messages []Message `json:"messages"` +} + +type Message struct { + ID string `json:"id"` + Query string `json:"query"` + Answer string `json:"answer"` +} diff --git a/graphql-server/go-server/pkg/dataset/dataset.go b/graphql-server/go-server/pkg/dataset/dataset.go index 38b02419b..16cdfa9ad 100644 --- a/graphql-server/go-server/pkg/dataset/dataset.go +++ b/graphql-server/go-server/pkg/dataset/dataset.go @@ -28,7 +28,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" - "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/graphql-server/go-server/graph/generated" ) diff --git a/graphql-server/go-server/pkg/datasource/datasource.go b/graphql-server/go-server/pkg/datasource/datasource.go index 7fa1f8572..ea15020cc 100644 --- a/graphql-server/go-server/pkg/datasource/datasource.go +++ b/graphql-server/go-server/pkg/datasource/datasource.go @@ -27,7 +27,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" - "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/base/v1alpha1" model "github.com/kubeagi/arcadia/graphql-server/go-server/graph/generated" ) diff --git a/graphql-server/go-server/pkg/embedder/embedder.go b/graphql-server/go-server/pkg/embedder/embedder.go index 5326c15cc..6a16a077e 100644 --- a/graphql-server/go-server/pkg/embedder/embedder.go +++ b/graphql-server/go-server/pkg/embedder/embedder.go @@ -27,7 +27,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" - "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/base/v1alpha1" model "github.com/kubeagi/arcadia/graphql-server/go-server/graph/generated" "github.com/kubeagi/arcadia/pkg/embeddings" ) diff --git a/graphql-server/go-server/pkg/knowledgebase/knowledgebase.go b/graphql-server/go-server/pkg/knowledgebase/knowledgebase.go index 5af9659c3..f12c38276 100644 --- a/graphql-server/go-server/pkg/knowledgebase/knowledgebase.go +++ b/graphql-server/go-server/pkg/knowledgebase/knowledgebase.go @@ -27,7 +27,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" - "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/base/v1alpha1" model "github.com/kubeagi/arcadia/graphql-server/go-server/graph/generated" ) diff --git a/graphql-server/go-server/pkg/model/model.go b/graphql-server/go-server/pkg/model/model.go index e1bfaa1bc..4b8e80bc7 100644 --- a/graphql-server/go-server/pkg/model/model.go +++ b/graphql-server/go-server/pkg/model/model.go @@ -26,7 +26,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" - "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/base/v1alpha1" model "github.com/kubeagi/arcadia/graphql-server/go-server/graph/generated" ) diff --git a/graphql-server/go-server/pkg/versioneddataset/versioned_dataset.go b/graphql-server/go-server/pkg/versioneddataset/versioned_dataset.go index 36a96fb5a..7d66ee6da 100644 --- a/graphql-server/go-server/pkg/versioneddataset/versioned_dataset.go +++ b/graphql-server/go-server/pkg/versioneddataset/versioned_dataset.go @@ -30,7 +30,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" - "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/graphql-server/go-server/graph/generated" "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/minio" "github.com/kubeagi/arcadia/pkg/utils/minioutils" diff --git a/main.go b/main.go index b2d9bd160..9ffde6374 100644 --- a/main.go +++ b/main.go @@ -33,8 +33,12 @@ import ( "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/log/zap" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + apichain "github.com/kubeagi/arcadia/api/app-node/chain/v1alpha1" + apiprompt "github.com/kubeagi/arcadia/api/app-node/prompt/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/controllers" + chaincontrollers "github.com/kubeagi/arcadia/controllers/app-node/chain" + promptcontrollers "github.com/kubeagi/arcadia/controllers/app-node/prompt" "github.com/kubeagi/arcadia/pkg/utils" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) @@ -52,6 +56,8 @@ func init() { utilruntime.Must(arcadiav1alpha1.AddToScheme(scheme)) utilruntime.Must(v1.AddToScheme(scheme)) + utilruntime.Must(apichain.AddToScheme(scheme)) + utilruntime.Must(apiprompt.AddToScheme(scheme)) //+kubebuilder:scaffold:scheme } @@ -213,6 +219,27 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "Namespace") os.Exit(1) } + if err = (&controllers.ApplicationReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Application") + os.Exit(1) + } + if err = (&chaincontrollers.LLMChainReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "LLMChain") + os.Exit(1) + } + if err = (&promptcontrollers.PromptReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Prompt") + os.Exit(1) + } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/pkg/application/app_run.go b/pkg/application/app_run.go new file mode 100644 index 000000000..3b9ec76ab --- /dev/null +++ b/pkg/application/app_run.go @@ -0,0 +1,195 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package application + +import ( + "container/list" + "context" + "errors" + "fmt" + "reflect" + + "k8s.io/client-go/dynamic" + + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" + "github.com/kubeagi/arcadia/pkg/application/base" + "github.com/kubeagi/arcadia/pkg/application/chain" + "github.com/kubeagi/arcadia/pkg/application/llm" + "github.com/kubeagi/arcadia/pkg/application/prompt" +) + +type Input struct { + Question string + // History []schema.ChatMessage + // overrideConfig +} +type Output struct { + Answer string +} + +type Application struct { + Spec arcadiav1alpha1.ApplicationSpec + Inited bool + Nodes map[string]base.Node + StartingNodes []base.Node + EndingNode base.Node +} + +var cache = map[string]*Application{} + +func cacheKey(app *arcadiav1alpha1.Application) string { + return app.Namespace + "/" + app.Name +} + +func NewAppOrGetFromCache(ctx context.Context, app *arcadiav1alpha1.Application, cli dynamic.Interface) (*Application, error) { + if app == nil || app.Name == "" || app.Namespace == "" { + return nil, errors.New("app has no name or namespace") + } + a, ok := cache[cacheKey(app)] + if !ok { + a = &Application{ + Spec: app.Spec, + } + cache[cacheKey(app)] = a + return a, a.Init(ctx, cli) + } + if reflect.DeepEqual(a.Spec, app.Spec) { + return a, nil + } + a.Spec = app.Spec + a.Inited = false + return a, a.Init(ctx, cli) +} + +// todo 防止无限循环,需要找一下是不是成环 +func (a *Application) Init(ctx context.Context, cli dynamic.Interface) (err error) { + if a.Inited { + return + } + a.Nodes = make(map[string]base.Node) + + var inputNodeName, outputNodeName string + for _, node := range a.Spec.Nodes { + if node.Ref != nil { + if node.Ref.Kind == arcadiav1alpha1.OutputNode { + outputNodeName = node.Name + } else if node.Ref.Kind == arcadiav1alpha1.InputNode { + inputNodeName = node.Name + } + } + } + + for _, node := range a.Spec.Nodes { + n, err := InitNode(ctx, node.Name, *node.Ref, cli) + if err != nil { + return err + } + if err := n.Init(ctx, cli, map[string]any{}); err != nil { // TODO arg + return err + } + a.Nodes[node.Name] = n + if node.Name == inputNodeName { + a.StartingNodes = append(a.StartingNodes, n) + } else if node.Name == outputNodeName { + a.EndingNode = n + } + } + + for _, node := range a.Spec.Nodes { + current := a.Nodes[node.Name] + for _, next := range node.NextNodeName { + n, ok := a.Nodes[next] + if !ok { + return fmt.Errorf("node %s not found", next) + } + current.SetNextNode(n) + } + } + + for _, current := range a.Nodes { + for _, next := range current.GetNextNode() { + next.SetPrevNode(current) + } + } + + for _, current := range a.Nodes { + if len(current.GetPrevNode()) == 0 && current.Name() != inputNodeName { + a.StartingNodes = append(a.StartingNodes, current) + } + } + return nil +} + +func (a *Application) Run(ctx context.Context, cli dynamic.Interface, input Input) (output Output, err error) { + out := map[string]any{ + "question": input.Question, + } + visited := make(map[string]bool) + waitRunningNodes := list.New() + for _, v := range a.StartingNodes { + waitRunningNodes.PushBack(v) + } + for e := waitRunningNodes.Front(); e != nil; e = e.Next() { + e := e.Value.(base.Node) + if !visited[e.Name()] { + if out, err = e.Run(ctx, cli, out); err != nil { + return Output{}, err + } + visited[e.Name()] = true + } + for _, n := range e.GetNextNode() { + waitRunningNodes.PushBack(n) + } + } + if a, ok := out["answer"]; ok { + return Output{Answer: a.(string)}, nil + } + return Output{}, errors.New("no answer") +} + +func InitNode(ctx context.Context, name string, ref arcadiav1alpha1.TypedObjectReference, cli dynamic.Interface) (base.Node, error) { + baseNode := base.NewBaseNode(name, ref) + switch baseNode.Group() { + case "chain": + switch baseNode.Kind() { + case "llmchain": + return chain.NewLLMChain(baseNode), nil + default: + return nil, fmt.Errorf("%s:%v kind is not found", name, ref) + } + case "": + switch baseNode.Kind() { + case "llm": + return llm.NewLLM(ctx, baseNode, ref, cli) + case "input": + return base.NewInput(baseNode), nil + case "output": + return base.NewOutput(baseNode), nil + default: + return nil, fmt.Errorf("%s:%v kind is not found", name, ref) + } + case "prompt": + switch baseNode.Kind() { + case "prompt": + return prompt.NewPrompt(baseNode), nil + default: + return nil, fmt.Errorf("%s:%v kind is not found", name, ref) + } + default: + return nil, fmt.Errorf("%s:%v group is not found", name, ref) + } +} diff --git a/pkg/application/base/input.go b/pkg/application/base/input.go new file mode 100644 index 000000000..dd2826a83 --- /dev/null +++ b/pkg/application/base/input.go @@ -0,0 +1,37 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package base + +import ( + "context" + + "k8s.io/client-go/dynamic" +) + +type Input struct { + BaseNode +} + +func NewInput(baseNode BaseNode) *Input { + return &Input{ + BaseNode: baseNode, + } +} + +func (c *Input) Run(ctx context.Context, _ dynamic.Interface, args map[string]any) (map[string]any, error) { + return args, nil +} diff --git a/pkg/application/base/node.go b/pkg/application/base/node.go new file mode 100644 index 000000000..50c79343b --- /dev/null +++ b/pkg/application/base/node.go @@ -0,0 +1,98 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package base + +import ( + "context" + "strings" + + "k8s.io/client-go/dynamic" + + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" +) + +type Node interface { + Name() string + Group() string + Kind() string + Init(ctx context.Context, cli dynamic.Interface, args map[string]any) error + Run(ctx context.Context, cli dynamic.Interface, args map[string]any) (map[string]any, error) + SetPrevNode(nodes ...Node) + SetNextNode(nodes ...Node) + GetPrevNode() []Node + GetNextNode() []Node +} + +func NewBaseNode(nodeName string, ref arcadiav1alpha1.TypedObjectReference) BaseNode { + return BaseNode{ + name: nodeName, + Ref: ref, + prev: make([]Node, 0), + next: make([]Node, 0), + } +} + +type BaseNode struct { + name string + Ref arcadiav1alpha1.TypedObjectReference + prev []Node + next []Node +} + +func (c *BaseNode) Name() string { + return c.name +} + +func (c *BaseNode) Group() string { + group := c.Ref.APIGroup + if group == nil { + return "" + } + before, _, _ := strings.Cut(*group, "/") + if before == "arcadia.kubeagi.k8s.com.cn" { + return "" + } + return strings.ToLower(strings.TrimSuffix(before, ".arcadia.kubeagi.k8s.com.cn")) +} + +func (c *BaseNode) Kind() string { + return strings.ToLower(c.Ref.Kind) +} + +func (c *BaseNode) GetPrevNode() []Node { + return c.prev +} + +func (c *BaseNode) GetNextNode() []Node { + return c.next +} + +func (c *BaseNode) SetPrevNode(nodes ...Node) { + c.prev = append(c.prev, nodes...) +} + +func (c *BaseNode) SetNextNode(nodes ...Node) { + c.next = append(c.next, nodes...) +} + +func (c *BaseNode) Init(_ context.Context, _ dynamic.Interface, _ map[string]any) error { + return nil +} + +func (c *BaseNode) Run(_ context.Context, _ dynamic.Interface, _ map[string]any) (map[string]any, error) { + return nil, nil +} diff --git a/pkg/application/base/output.go b/pkg/application/base/output.go new file mode 100644 index 000000000..741879e32 --- /dev/null +++ b/pkg/application/base/output.go @@ -0,0 +1,37 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package base + +import ( + "context" + + "k8s.io/client-go/dynamic" +) + +type Output struct { + BaseNode +} + +func NewOutput(baseNode BaseNode) *Output { + return &Output{ + BaseNode: baseNode, + } +} + +func (c *Output) Run(_ context.Context, _ dynamic.Interface, args map[string]any) (map[string]any, error) { + return args, nil +} diff --git a/pkg/application/chain/llmchain.go b/pkg/application/chain/llmchain.go new file mode 100644 index 000000000..a9c4a1e41 --- /dev/null +++ b/pkg/application/chain/llmchain.go @@ -0,0 +1,67 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chain + +import ( + "context" + "errors" + + "github.com/tmc/langchaingo/chains" + "github.com/tmc/langchaingo/llms" + "github.com/tmc/langchaingo/prompts" + "k8s.io/client-go/dynamic" + + "github.com/kubeagi/arcadia/pkg/application/base" +) + +type LLMChain struct { + chains.LLMChain + base.BaseNode +} + +func NewLLMChain(baseNode base.BaseNode) *LLMChain { + return &LLMChain{ + chains.LLMChain{}, + baseNode, + } +} + +func (l *LLMChain) Run(ctx context.Context, _ dynamic.Interface, args map[string]any) (map[string]any, error) { + v1, ok := args["llm"] + if !ok { + return args, errors.New("no llm") + } + llm, ok := v1.(llms.LanguageModel) + if !ok { + return args, errors.New("llm not llms.LanguageModel") + } + v2, ok := args["prompt"] + if !ok { + return args, errors.New("no prompt") + } + prompt, ok := v2.(prompts.FormatPrompter) + if !ok { + return args, errors.New("prompt not prompts.FormatPrompter") + } + chain := chains.NewLLMChain(llm, prompt) + l.LLMChain = *chain + out, err := chains.Predict(ctx, l.LLMChain, args) + if err == nil { + args["answer"] = out + } + return args, err +} diff --git a/pkg/application/llm/base.go b/pkg/application/llm/base.go new file mode 100644 index 000000000..a31d341e1 --- /dev/null +++ b/pkg/application/llm/base.go @@ -0,0 +1,53 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package llm + +import ( + "context" + "errors" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" + + "github.com/kubeagi/arcadia/api/base/v1alpha1" + "github.com/kubeagi/arcadia/pkg/application/base" + "github.com/kubeagi/arcadia/pkg/llms" +) + +func NewLLM(ctx context.Context, baseNode base.BaseNode, ref v1alpha1.TypedObjectReference, cli dynamic.Interface) (node base.Node, err error) { + instance := &v1alpha1.LLM{} + obj, err := cli.Resource(schema.GroupVersionResource{Group: v1alpha1.GroupVersion.Group, Version: v1alpha1.GroupVersion.Version, Resource: "llms"}). + Namespace(ref.GetNamespace()).Get(ctx, ref.Name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), instance) + if err != nil { + return nil, err + } + switch instance.Spec.Type { + case llms.OpenAI: + // TODO + case llms.ZhiPuAI: + node = NewZhipuLLM(baseNode) + default: + err = errors.New("llm type is not found") + } + return node, err +} diff --git a/pkg/application/llm/zhipu.go b/pkg/application/llm/zhipu.go new file mode 100644 index 000000000..1b68a60a0 --- /dev/null +++ b/pkg/application/llm/zhipu.go @@ -0,0 +1,81 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package llm + +import ( + "context" + + "github.com/tmc/langchaingo/llms" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" + + "github.com/kubeagi/arcadia/api/base/v1alpha1" + "github.com/kubeagi/arcadia/pkg/application/base" + "github.com/kubeagi/arcadia/pkg/llms/zhipuai" +) + +var _ llms.LLM = (*ZhipuLLM)(nil) + +type ZhipuLLM struct { + base.BaseNode + zhipuai.ZhiPuAILLM +} + +func NewZhipuLLM(baseNode base.BaseNode) *ZhipuLLM { + return &ZhipuLLM{ + baseNode, + zhipuai.ZhiPuAILLM{}, + } +} + +func (z *ZhipuLLM) Init(ctx context.Context, cli dynamic.Interface, args map[string]any) error { + instance := &v1alpha1.LLM{} + obj, err := cli.Resource(schema.GroupVersionResource{Group: v1alpha1.GroupVersion.Group, Version: v1alpha1.GroupVersion.Version, Resource: "llms"}). + Namespace(z.Ref.GetNamespace()).Get(ctx, z.Ref.Name, metav1.GetOptions{}) + if err != nil { + return err + } + err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), instance) + if err != nil { + return err + } + var apiKey string + if instance.Spec.Enpoint != nil && instance.Spec.Enpoint.AuthSecret != nil { + authSecret := &corev1.Secret{} + obj, err := cli.Resource(schema.GroupVersionResource{Group: "", Version: "v1", Resource: "secrets"}). + Namespace(z.Ref.GetNamespace()).Get(ctx, instance.Spec.Enpoint.AuthSecret.Name, metav1.GetOptions{}) + if err != nil { + return err + } + err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), authSecret) + if err != nil { + return err + } + apiKey = string(authSecret.Data["apiKey"]) + } + llm := zhipuai.NewZhiPuAI(apiKey) + z.ZhiPuAI = *llm + return nil +} + +func (z *ZhipuLLM) Run(_ context.Context, _ dynamic.Interface, args map[string]any) (map[string]any, error) { + args["llm"] = z + return args, nil +} diff --git a/pkg/application/prompt/prompt.go b/pkg/application/prompt/prompt.go new file mode 100644 index 000000000..fa91dd3ac --- /dev/null +++ b/pkg/application/prompt/prompt.go @@ -0,0 +1,62 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package prompt + +import ( + "context" + + "github.com/tmc/langchaingo/prompts" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" + + "github.com/kubeagi/arcadia/api/app-node/prompt/v1alpha1" + "github.com/kubeagi/arcadia/pkg/application/base" +) + +type Prompt struct { + base.BaseNode + prompts.ChatPromptTemplate +} + +func NewPrompt(baseNode base.BaseNode) *Prompt { + return &Prompt{ + baseNode, + prompts.ChatPromptTemplate{}, + } +} +func (p *Prompt) Run(ctx context.Context, cli dynamic.Interface, args map[string]any) (map[string]any, error) { + instance := &v1alpha1.Prompt{} + obj, err := cli.Resource(schema.GroupVersionResource{Group: v1alpha1.GroupVersion.Group, Version: v1alpha1.GroupVersion.Version, Resource: "prompts"}). + Namespace(p.Ref.GetNamespace()).Get(ctx, p.Ref.Name, metav1.GetOptions{}) + if err != nil { + return args, err + } + err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), instance) + if err != nil { + return args, err + } + template := prompts.NewChatPromptTemplate([]prompts.MessageFormatter{ + prompts.NewSystemMessagePromptTemplate(instance.Spec.SystemMessage, []string{}), + prompts.NewHumanMessagePromptTemplate(instance.Spec.UserMessage, []string{"question"}), + }) + // todo format + p.ChatPromptTemplate = template + args["prompt"] = p + return args, nil +} diff --git a/pkg/config/config.go b/pkg/config/config.go index ec43ed72d..5f17d2957 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -31,7 +31,7 @@ import ( "k8s.io/utils/env" "sigs.k8s.io/controller-runtime/pkg/client" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/pkg/utils" ) diff --git a/pkg/config/config_type.go b/pkg/config/config_type.go index a46371c0c..389f567c2 100644 --- a/pkg/config/config_type.go +++ b/pkg/config/config_type.go @@ -17,7 +17,7 @@ limitations under the License. package config import ( - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" ) // Config defines the configuration for the Arcadia controller diff --git a/pkg/datasource/datasource.go b/pkg/datasource/datasource.go index 8b06102a1..37588dec7 100644 --- a/pkg/datasource/datasource.go +++ b/pkg/datasource/datasource.go @@ -28,7 +28,7 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/base/v1alpha1" ) var ( diff --git a/pkg/llms/zhipuai/langchainllm.go b/pkg/llms/zhipuai/langchainllm.go new file mode 100644 index 000000000..6e359d395 --- /dev/null +++ b/pkg/llms/zhipuai/langchainllm.go @@ -0,0 +1,83 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package zhipuai + +import ( + "context" + "encoding/json" + "errors" + "strings" + + lanchainllm "github.com/tmc/langchaingo/llms" + "github.com/tmc/langchaingo/schema" + "k8s.io/klog/v2" +) + +var ( + ErrEmptyResponse = errors.New("no response") + ErrEmptyPrompt = errors.New("empty prompt") + ErrIncompleteEmbedding = errors.New("no all input got emmbedded") +) + +type ZhiPuAILLM struct { + ZhiPuAI +} + +func (z ZhiPuAILLM) Call(ctx context.Context, prompt string, options ...lanchainllm.CallOption) (string, error) { + r, err := z.Generate(ctx, []string{prompt}, options...) + if err != nil { + return "", err + } + if len(r) == 0 { + return "", ErrEmptyResponse + } + return r[0].Text, nil +} + +func (z ZhiPuAILLM) Generate(ctx context.Context, prompts []string, options ...lanchainllm.CallOption) ([]*lanchainllm.Generation, error) { + params := DefaultModelParams() + if len(prompts) == 0 { + return nil, ErrEmptyPrompt + } + params.Prompt = []Prompt{ + {Role: User, Content: prompts[0]}, + } + klog.Infoln("prompt:", prompts[0]) + client := NewZhiPuAI(z.apiKey) + resp, err := client.Invoke(params) + if err != nil { + return nil, err + } + var s string + if err := json.Unmarshal([]byte(resp.Data.Choices[0].Content), &s); err != nil { + return nil, err + } + return []*lanchainllm.Generation{ + { + Text: strings.TrimSpace(s), + }, + }, nil +} + +func (z ZhiPuAILLM) GeneratePrompt(ctx context.Context, promptValues []schema.PromptValue, options ...lanchainllm.CallOption) (lanchainllm.LLMResult, error) { + return lanchainllm.GeneratePrompt(ctx, z, promptValues, options...) +} + +func (z ZhiPuAILLM) GetNumTokens(text string) int { + // TODO implement me + panic("implement me") +} diff --git a/pkg/scheduler/executor.go b/pkg/scheduler/executor.go index 976d6595e..5b8cb2a48 100644 --- a/pkg/scheduler/executor.go +++ b/pkg/scheduler/executor.go @@ -26,7 +26,7 @@ import ( "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/base/v1alpha1" ) type executor struct { diff --git a/pkg/scheduler/scheduler.go b/pkg/scheduler/scheduler.go index c53b64621..aa2e07bfc 100644 --- a/pkg/scheduler/scheduler.go +++ b/pkg/scheduler/scheduler.go @@ -26,7 +26,7 @@ import ( "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/pkg/config" "github.com/kubeagi/arcadia/pkg/datasource" ) diff --git a/pkg/worker/loader.go b/pkg/worker/loader.go index b34ac0e43..cfe7d3dfb 100644 --- a/pkg/worker/loader.go +++ b/pkg/worker/loader.go @@ -25,7 +25,7 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/pkg/datasource" ) diff --git a/pkg/worker/runner.go b/pkg/worker/runner.go index ddc0d5993..e267435de 100644 --- a/pkg/worker/runner.go +++ b/pkg/worker/runner.go @@ -24,7 +24,7 @@ import ( corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" "github.com/kubeagi/arcadia/pkg/config" ) diff --git a/pkg/worker/worker.go b/pkg/worker/worker.go index bc70a99b6..0b1f9be37 100644 --- a/pkg/worker/worker.go +++ b/pkg/worker/worker.go @@ -32,7 +32,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/base/v1alpha1" ) const ( diff --git a/tests/example-test.sh b/tests/example-test.sh index 6db33ea1c..badcc0e08 100755 --- a/tests/example-test.sh +++ b/tests/example-test.sh @@ -238,7 +238,7 @@ waitCRDStatusReady "KnowledgeBase" "arcadia" "knowledgebase-sample" info "7.5 check this vectorstore has data" kubectl port-forward -n arcadia svc/chroma-chromadb 8000:8000 >/dev/null 2>&1 & chroma_pid=$! -info "port-forward chroma in pid: $minio_pid" +info "port-forward chroma in pid: $chroma_pid" sleep 3 collection_test_id=$(curl http://127.0.0.1:8000/api/v1/collections/arcadia_knowledgebase-sample | jq -r .id) collection_test_count=$(curl http://127.0.0.1:8000/api/v1/collections/${collection_test_id}/count) @@ -249,4 +249,14 @@ else exit 1 fi +info "8 check app work fine" +helm upgrade -narcadia arcadia deploy/charts/arcadia --reuse-values --wait --timeout $HelmTimeout --set portal.enabled=true +kubectl apply -f config/samples/app_llmchain_englishteacher.yaml +waitCRDStatusReady "Application" "arcadia" "base-chat-english-teacher" +kubectl port-forward svc/arcadia-portal-server -n arcadia 8081:8081 >/dev/null 2>&1 & +portal_pid=$! +info "port-forward portal in pid: $portal_pid" +sleep 3 +curl -XPOST http://127.0.0.1:8081/chat --data '{"query":"hi, how are you?","response_mode":"blocking","conversion_id":"","app_name":"base-chat-english-teacher", "app_namespace":"arcadia"}' + info "all finished! ✅"