diff --git a/api/v1alpha1/condition.go b/api/v1alpha1/condition.go index 14aef92d9..2cbb1d4c7 100644 --- a/api/v1alpha1/condition.go +++ b/api/v1alpha1/condition.go @@ -34,8 +34,6 @@ const ( TypeUnknown ConditionType = "Unknown" // TypeDone resources are believed to be processed TypeDone ConditionType = "Done" - // TypeUnavailable resources are unavailable - TypeUnavailable ConditionType = "Unavailable" ) // A ConditionReason represents the reason a resource is in a condition. diff --git a/config/arcadia.kubeagi.k8s.com.cn_laboratories.yaml b/config/arcadia.kubeagi.k8s.com.cn_laboratories.yaml deleted file mode 100644 index c45a1f152..000000000 --- a/config/arcadia.kubeagi.k8s.com.cn_laboratories.yaml +++ /dev/null @@ -1,50 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: laboratories.arcadia.kubeagi.k8s.com.cn -spec: - group: arcadia.kubeagi.k8s.com.cn - names: - kind: Laboratory - listKind: LaboratoryList - plural: laboratories - singular: laboratory - scope: Cluster - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: Laboratory is the Schema for the laboratories 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: LaboratorySpec defines the desired state of Laboratory - properties: - foo: - description: Foo is an example field of Laboratory. Edit laboratory_types.go - to remove/update - type: string - type: object - status: - description: LaboratoryStatus defines the observed state of Laboratory - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/arcadia.kubeagi.k8s.com.cn_llms.yaml b/config/arcadia.kubeagi.k8s.com.cn_llms.yaml deleted file mode 100644 index e3477d1ac..000000000 --- a/config/arcadia.kubeagi.k8s.com.cn_llms.yaml +++ /dev/null @@ -1,100 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: llms.arcadia.kubeagi.k8s.com.cn -spec: - group: arcadia.kubeagi.k8s.com.cn - names: - kind: LLM - listKind: LLMList - plural: llms - singular: llm - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: LLM is the Schema for the llms 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: LLMSpec defines the desired state of LLM - properties: - auth: - description: Auth keeps the authentication credentials when access - llm keeps in k8s secret - type: string - displayName: - type: string - type: - description: Type defines the type of llm - type: string - url: - description: URL keeps the URL of the llm service(Must required) - type: string - required: - - type - - url - type: object - status: - description: LLMStatus defines the observed state of LLM - 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 - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/arcadia.kubeagi.k8s.com.cn_prompts.yaml b/config/arcadia.kubeagi.k8s.com.cn_prompts.yaml deleted file mode 100644 index f3369cb8c..000000000 --- a/config/arcadia.kubeagi.k8s.com.cn_prompts.yaml +++ /dev/null @@ -1,84 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - name: prompts.arcadia.kubeagi.k8s.com.cn -spec: - group: 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 prompts 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: - llm: - description: LLM serivice name(CRD LLM) - type: string - zhiPuAIParams: - description: ZhiPuAIParams defines the params of ZhiPuAI - properties: - incremental: - description: Incremental is only Used for SSE Invoke - type: boolean - method: - description: Method used for this prompt call - type: string - model: - description: Model used for this prompt call - type: string - prompt: - description: Contents - items: - description: Prompt defines the content of ZhiPuAI Prompt Call - properties: - content: - type: string - role: - type: string - type: object - type: array - task_id: - description: TaskID is used for getting result of AsyncInvoke - type: string - temperature: - description: Temperature is float in zhipuai - top_p: - description: TopP is float in zhipuai - required: - - prompt - type: object - required: - - llm - type: object - status: - description: PromptStatus defines the observed state of Prompt - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/controllers/llm_controller.go b/controllers/llm_controller.go index 5b8647d28..aa77c5369 100644 --- a/controllers/llm_controller.go +++ b/controllers/llm_controller.go @@ -18,10 +18,11 @@ package controllers import ( "context" - "fmt" + "reflect" "github.com/go-logr/logr" "github.com/kubeagi/arcadia/pkg/llms" + "github.com/kubeagi/arcadia/pkg/llms/openai" "github.com/kubeagi/arcadia/pkg/llms/zhipuai" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -30,6 +31,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -73,10 +75,11 @@ func (r *LLMReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R err = r.CheckLLM(ctx, logger, instance) if err != nil { + logger.Error(err, "Failed to check LLM") + // Update conditioned status return ctrl.Result{}, err } - logger.Info("Instance is updated and synchronized") return ctrl.Result{}, nil } @@ -92,29 +95,32 @@ func (r *LLMReconciler) CheckLLM(ctx context.Context, logger logr.Logger, instan logger.Info("Checking LLM instance") // Check new URL/Auth availability var err error - var response llms.Response apiKey, err := instance.AuthAPIKey(ctx, r.Client) if err != nil { - return err + return r.UpdateStatus(ctx, instance, nil, err) } + var llmClient llms.LLM switch instance.Spec.Type { case llms.OpenAI: - // validator := openai.NewOpenAI(apiKey) - // response, err = validator.Validate() - return fmt.Errorf("openAI not implemented yet") + llmClient = openai.NewOpenAI(apiKey) case llms.ZhiPuAI: - validator := zhipuai.NewZhiPuAI(apiKey) - response, err = validator.Validate() + llmClient = zhipuai.NewZhiPuAI(apiKey) default: - return fmt.Errorf("unknown LLM type: %s", instance.Spec.Type) + llmClient = llms.NewUnknowLLM() } + response, err := llmClient.Validate() + return r.UpdateStatus(ctx, instance, response, err) +} + +func (r *LLMReconciler) UpdateStatus(ctx context.Context, instance *arcadiav1alpha1.LLM, response llms.Response, err error) error { + instanceCopy := instance.DeepCopy() if err != nil { // Set status to unavailable - instance.Status.SetConditions(arcadiav1alpha1.Condition{ - Type: arcadiav1alpha1.TypeUnavailable, + instanceCopy.Status.SetConditions(arcadiav1alpha1.Condition{ + Type: arcadiav1alpha1.TypeReady, Status: corev1.ConditionFalse, Reason: arcadiav1alpha1.ReasonUnavailable, Message: err.Error(), @@ -122,7 +128,7 @@ func (r *LLMReconciler) CheckLLM(ctx context.Context, logger logr.Logger, instan }) } else { // Set status to available - instance.Status.SetConditions(arcadiav1alpha1.Condition{ + instanceCopy.Status.SetConditions(arcadiav1alpha1.Condition{ Type: arcadiav1alpha1.TypeReady, Status: corev1.ConditionTrue, Reason: arcadiav1alpha1.ReasonAvailable, @@ -131,10 +137,21 @@ func (r *LLMReconciler) CheckLLM(ctx context.Context, logger logr.Logger, instan LastSuccessfulTime: metav1.Now(), }) } - - return r.Client.Status().Update(ctx, instance) + return r.Client.Status().Update(ctx, instanceCopy) } type LLMPredicates struct { predicate.Funcs } + +func (llm LLMPredicates) Create(ce event.CreateEvent) bool { + prompt := ce.Object.(*arcadiav1alpha1.LLM) + return len(prompt.Status.ConditionedStatus.Conditions) == 0 +} + +func (llm LLMPredicates) Update(ue event.UpdateEvent) bool { + oldLLM := ue.ObjectOld.(*arcadiav1alpha1.LLM) + newLLM := ue.ObjectNew.(*arcadiav1alpha1.LLM) + + return !reflect.DeepEqual(oldLLM.Spec, newLLM.Spec) +} diff --git a/controllers/prompt_controller.go b/controllers/prompt_controller.go index 2d614a7b0..55b71a200 100644 --- a/controllers/prompt_controller.go +++ b/controllers/prompt_controller.go @@ -18,14 +18,14 @@ package controllers import ( "context" - "fmt" + "reflect" "github.com/go-logr/logr" arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" "github.com/kubeagi/arcadia/pkg/llms" + "github.com/kubeagi/arcadia/pkg/llms/openai" llmszhipuai "github.com/kubeagi/arcadia/pkg/llms/zhipuai" corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -90,25 +90,35 @@ func (r *PromptReconciler) CallLLM(ctx context.Context, logger logr.Logger, prom apiKey, err := llm.AuthAPIKey(ctx, r.Client) if err != nil { - return err + return r.UpdateStatus(ctx, prompt, nil, err) } // llm call - var resp llms.Response + var llmClient llms.LLM + var callData []byte switch llm.Spec.Type { case llms.ZhiPuAI: - resp, err = llmszhipuai.NewZhiPuAI(apiKey).Call(*prompt.Spec.ZhiPuAIParams) + llmClient = llmszhipuai.NewZhiPuAI(apiKey) + callData = prompt.Spec.ZhiPuAIParams.Marshall() case llms.OpenAI: - err = fmt.Errorf("OpenAI not supported yet") + llmClient = openai.NewOpenAI(apiKey) default: - err = fmt.Errorf("unknown LLM type: %s", llm.Spec.Type) + llmClient = llms.NewUnknowLLM() } - promptDeepCodpy := prompt.DeepCopy() + resp, err := llmClient.Call(callData) + if err != nil { + return err + } + + return r.UpdateStatus(ctx, prompt, resp, err) +} +func (r *PromptReconciler) UpdateStatus(ctx context.Context, prompt *arcadiav1alpha1.Prompt, response llms.Response, err error) error { + promptDeepCodpy := prompt.DeepCopy() newCond := arcadiav1alpha1.Condition{ Type: arcadiav1alpha1.TypeDone, - Status: v1.ConditionTrue, + Status: corev1.ConditionTrue, LastTransitionTime: metav1.Now(), Reason: arcadiav1alpha1.ReasonReconcileSuccess, Message: "Finished CallLLM", @@ -118,11 +128,10 @@ func (r *PromptReconciler) CallLLM(ctx context.Context, logger logr.Logger, prom newCond.Reason = arcadiav1alpha1.ReasonReconcileError newCond.Message = err.Error() } - promptDeepCodpy.Status.ConditionedStatus = arcadiav1alpha1.ConditionedStatus{Conditions: []arcadiav1alpha1.Condition{newCond}} - if resp != nil { - promptDeepCodpy.Status.Data = resp.Bytes() + promptDeepCodpy.Status.SetConditions(newCond) + if response != nil { + promptDeepCodpy.Status.Data = response.Bytes() } - return r.Status().Update(ctx, promptDeepCodpy) } @@ -141,3 +150,10 @@ func (p PromptPredicates) Create(ce event.CreateEvent) bool { prompt := ce.Object.(*arcadiav1alpha1.Prompt) return len(prompt.Status.ConditionedStatus.Conditions) == 0 } + +func (p PromptPredicates) Update(ue event.UpdateEvent) bool { + oldPrompt := ue.ObjectOld.(*arcadiav1alpha1.Prompt) + newPrompt := ue.ObjectNew.(*arcadiav1alpha1.Prompt) + + return !reflect.DeepEqual(oldPrompt.Spec, newPrompt.Spec) +} diff --git a/go.mod b/go.mod index 175df188c..ccf818473 100644 --- a/go.mod +++ b/go.mod @@ -63,12 +63,12 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.1 // indirect - golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/net v0.14.0 // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect - golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/term v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 194520541..9f87c58eb 100644 --- a/go.sum +++ b/go.sum @@ -527,8 +527,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 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 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -614,8 +615,9 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -706,11 +708,13 @@ golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.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 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -719,8 +723,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 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 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/pkg/llms/llms.go b/pkg/llms/llms.go index b42959857..561fd0857 100644 --- a/pkg/llms/llms.go +++ b/pkg/llms/llms.go @@ -16,20 +16,46 @@ limitations under the License. package llms +import "errors" + type LLMType string const ( OpenAI LLMType = "openai" ZhiPuAI LLMType = "zhipuai" + Unknown LLMType = "unknown" ) type LLM interface { Type() LLMType + Call([]byte) (Response, error) Validate() (Response, error) } +type ModelParams interface { + Marshall() []byte + Unmarshall([]byte) error +} + type Response interface { Type() LLMType String() string Bytes() []byte } + +type UnknowLLM struct{} + +func NewUnknowLLM() UnknowLLM { + return UnknowLLM{} +} +func (unknown UnknowLLM) Type() LLMType { + return Unknown +} + +func (unknown UnknowLLM) Call(data []byte) (Response, error) { + return nil, errors.New("unknown llm type") +} + +func (unknown UnknowLLM) Validate() (Response, error) { + return nil, errors.New("unknown llm type") +} diff --git a/pkg/llms/openai/api.go b/pkg/llms/openai/api.go index 4775f4059..056922d78 100644 --- a/pkg/llms/openai/api.go +++ b/pkg/llms/openai/api.go @@ -17,6 +17,7 @@ limitations under the License. package openai import ( + "errors" "fmt" "net/http" "time" @@ -45,6 +46,10 @@ func (o OpenAI) Type() llms.LLMType { return llms.OpenAI } +func (o *OpenAI) Call(data []byte) (llms.Response, error) { + return nil, errors.New("not implemented yet") +} + func (o *OpenAI) Validate() (llms.Response, error) { // Validate OpenAI type CRD LLM Instance // instance.Spec.URL should be like "https://api.openai.com/" diff --git a/pkg/llms/zhipuai/api.go b/pkg/llms/zhipuai/api.go index d5d91f07b..018127da0 100644 --- a/pkg/llms/zhipuai/api.go +++ b/pkg/llms/zhipuai/api.go @@ -72,7 +72,11 @@ func (z ZhiPuAI) Type() llms.LLMType { } // Call wraps a common AI api call -func (z *ZhiPuAI) Call(params ModelParams) (*Response, error) { +func (z *ZhiPuAI) Call(data []byte) (llms.Response, error) { + params := ModelParams{} + if err := params.Unmarshall(data); err != nil { + return nil, err + } switch params.Method { case ZhiPuAIInvoke: return z.Invoke(params) diff --git a/pkg/llms/zhipuai/params.go b/pkg/llms/zhipuai/params.go index 03501cdf9..4649cffb3 100644 --- a/pkg/llms/zhipuai/params.go +++ b/pkg/llms/zhipuai/params.go @@ -19,7 +19,10 @@ limitations under the License. package zhipuai import ( + "encoding/json" "errors" + + "github.com/kubeagi/arcadia/pkg/llms" ) type Role string @@ -29,6 +32,8 @@ const ( Assistant Role = "assistant" ) +var _ llms.ModelParams = (*ModelParams)(nil) + // +kubebuilder:object:generate=true // ZhiPuAIParams defines the params of ZhiPuAI Prompt Call type ModelParams struct { @@ -69,6 +74,18 @@ func DefaultModelParams() ModelParams { } } +func (params *ModelParams) Marshall() []byte { + data, err := json.Marshal(params) + if err != nil { + return []byte{} + } + return data +} + +func (params *ModelParams) Unmarshall(bytes []byte) error { + return json.Unmarshal(bytes, params) +} + // MergeZhiPuAI merges b to a with this rule // - if a.x is emtpy and b.x is not, then a.x = b.x func MergeParams(a, b ModelParams) ModelParams {