diff --git a/apiserver/pkg/application/application.go b/apiserver/pkg/application/application.go index 66e395e8d..d13540e06 100644 --- a/apiserver/pkg/application/application.go +++ b/apiserver/pkg/application/application.go @@ -39,6 +39,7 @@ import ( apiprompt "github.com/kubeagi/arcadia/api/app-node/prompt/v1alpha1" apiretriever "github.com/kubeagi/arcadia/api/app-node/retriever/v1alpha1" "github.com/kubeagi/arcadia/api/base/v1alpha1" + pkgconf "github.com/kubeagi/arcadia/apiserver/config" "github.com/kubeagi/arcadia/apiserver/graph/generated" "github.com/kubeagi/arcadia/apiserver/pkg/common" "github.com/kubeagi/arcadia/apiserver/pkg/utils" @@ -73,7 +74,7 @@ func addDefaultValue(gApp *generated.Application, app *v1alpha1.Application) { gApp.ConversionWindowSize = pointer.Int(5) } -func cr2app(ctx context.Context, c client.Client, prompt *apiprompt.Prompt, chainConfig *apichain.CommonChainConfig, retriever *apiretriever.CommonRetrieverConfig, app *v1alpha1.Application, agent *apiagent.Agent, doc *apidocumentloader.DocumentLoader, enableRerank, enableMultiQuery *bool, rerankModel *string) (*generated.Application, error) { +func cr2app(prompt *apiprompt.Prompt, chainConfig *apichain.CommonChainConfig, retriever *apiretriever.CommonRetrieverConfig, app *v1alpha1.Application, agent *apiagent.Agent, doc *apidocumentloader.DocumentLoader, enableRerank, enableMultiQuery *bool, rerankModel *string) (*generated.Application, error) { if app == nil { return nil, errors.New("no app found") } @@ -81,7 +82,7 @@ func cr2app(ctx context.Context, c client.Client, prompt *apiprompt.Prompt, chai UpdateTimestamp := &condition.LastTransitionTime.Time status := common.GetObjStatus(app) - icon, _ := common.AppIconLink(ctx, app, c) + icon := common.AppIconLink(app, pkgconf.GetConfig().PlaygroundEndpointPrefix) gApp := &generated.Application{ Metadata: &generated.ApplicationMetadata{ Name: app.Name, @@ -153,22 +154,20 @@ func cr2app(ctx context.Context, c client.Client, prompt *apiprompt.Prompt, chai return gApp, nil } -func appConverterHelper(ctx context.Context, c client.Client) common.ResourceConverter { - return func(objApp client.Object) (generated.PageNode, error) { - app, ok := objApp.(*v1alpha1.Application) - if !ok { - return nil, errors.New("can't convert client.Object to Application") - } - return app2metadata(ctx, c, app) +func app2metadataConverter(objApp client.Object) (generated.PageNode, error) { + app, ok := objApp.(*v1alpha1.Application) + if !ok { + return nil, errors.New("can't convert client.Object to Application") } + return app2metadata(app) } -func app2metadata(ctx context.Context, c client.Client, app *v1alpha1.Application) (*generated.ApplicationMetadata, error) { +func app2metadata(app *v1alpha1.Application) (*generated.ApplicationMetadata, error) { condition := app.Status.GetCondition(v1alpha1.TypeReady) UpdateTimestamp := &condition.LastTransitionTime.Time status := common.GetObjStatus(app) - icon, _ := common.AppIconLink(ctx, app, c) + icon := common.AppIconLink(app, pkgconf.GetConfig().PlaygroundEndpointPrefix) return &generated.ApplicationMetadata{ Name: app.Name, Namespace: app.Namespace, @@ -219,7 +218,7 @@ func CreateApplication(ctx context.Context, c client.Client, input generated.Cre if err := c.Create(ctx, app); err != nil { return nil, err } - return app2metadata(ctx, c, app) + return app2metadata(app) } func UpdateApplication(ctx context.Context, c client.Client, input generated.UpdateApplicationMetadataInput) (*generated.ApplicationMetadata, error) { @@ -250,7 +249,7 @@ func UpdateApplication(ctx context.Context, c client.Client, input generated.Upd return nil, err } } - return app2metadata(ctx, c, app) + return app2metadata(app) } func DeleteApplication(ctx context.Context, c client.Client, input generated.DeleteCommonInput) (*string, error) { @@ -402,7 +401,7 @@ func GetApplication(ctx context.Context, c client.Client, name, namespace string return nil, err } - return cr2app(ctx, c, prompt, chainConfig, retriever, app, agent, doc, pointer.Bool(enableRerankRetriever), pointer.Bool(enableMultiQueryRetriever), pointer.String(rerankModel)) + return cr2app(prompt, chainConfig, retriever, app, agent, doc, pointer.Bool(enableRerankRetriever), pointer.Bool(enableMultiQueryRetriever), pointer.String(rerankModel)) } func ListApplicationMeatadatas(ctx context.Context, c client.Client, input generated.ListCommonInput) (*generated.PaginatedResult, error) { @@ -425,7 +424,7 @@ func ListApplicationMeatadatas(ctx context.Context, c client.Client, input gener for i := range res.Items { items[i] = &res.Items[i] } - return common.ListReources(items, page, pageSize, appConverterHelper(ctx, c), filter...) + return common.ListReources(items, page, pageSize, app2metadataConverter, filter...) } func UpdateApplicationConfig(ctx context.Context, c client.Client, input generated.UpdateApplicationConfigInput) (*generated.Application, error) { @@ -759,7 +758,7 @@ func UpdateApplicationConfig(ctx context.Context, c client.Client, input generat } } - return cr2app(ctx, c, prompt, chainConfig, retriever, app, agent, documentLoader, pointer.Bool(hasRerankRetriever), pointer.Bool(hasMultiQueryRetriever), pointer.String(rerankModel)) + return cr2app(prompt, chainConfig, retriever, app, agent, documentLoader, pointer.Bool(hasRerankRetriever), pointer.Bool(hasMultiQueryRetriever), pointer.String(rerankModel)) } func mutateApp(app *v1alpha1.Application, input generated.UpdateApplicationConfigInput, hasMultiQueryRetriever, hasRerankRetriever bool) error { diff --git a/apiserver/pkg/chat/chat_server.go b/apiserver/pkg/chat/chat_server.go index 1600eae36..a3072d3ce 100644 --- a/apiserver/pkg/chat/chat_server.go +++ b/apiserver/pkg/chat/chat_server.go @@ -37,6 +37,7 @@ import ( apiretriever "github.com/kubeagi/arcadia/api/app-node/retriever/v1alpha1" "github.com/kubeagi/arcadia/api/base/v1alpha1" + "github.com/kubeagi/arcadia/apiserver/config" "github.com/kubeagi/arcadia/apiserver/pkg/auth" "github.com/kubeagi/arcadia/apiserver/pkg/chat/storage" "github.com/kubeagi/arcadia/apiserver/pkg/client" @@ -433,13 +434,7 @@ func (cs *ChatServer) FillAppIconToConversations(ctx context.Context, conversati } app.Name = name app.Namespace = ns - link, err := common.AppIconLink(ctx, app, cs.cli) - if err != nil { - // FIXME: Currently, there is a request for an application that cannot be found in a conversation in the database, - // causing other conversations to be unable to add icons, so an error is encountered here and no error is returned. - klog.Errorf("failed to get application %s in namespace %s, error %s", name, ns, err) - return nil - } + link := common.AppIconLink(app, config.GetConfig().PlaygroundEndpointPrefix) result[index] = link return nil }) diff --git a/apiserver/pkg/common/common.go b/apiserver/pkg/common/common.go index fd0295004..34c02e536 100644 --- a/apiserver/pkg/common/common.go +++ b/apiserver/pkg/common/common.go @@ -20,9 +20,7 @@ import ( "context" "errors" "fmt" - "net/url" "strings" - "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" @@ -309,15 +307,10 @@ func NewListOptions(input generated.ListCommonInput) ([]client.ListOption, error return opts, nil } -func AppIconLink(ctx context.Context, app *v1alpha1.Application, client client.Client) (string, error) { - ds, err := SystemDatasourceOSS(ctx, client) - if err != nil { - return "", err - } - name := fmt.Sprintf("application/%s/icon/%s", app.Name, app.Name) - u, err := ds.Client.PresignedGetObject(ctx, app.Namespace, name, 24*time.Hour, url.Values{}) - if err != nil { - return "", err +func AppIconLink(app *v1alpha1.Application, endpointPrefix string) string { + base := fmt.Sprintf("/bff/icon?namespace=%s&application=%s", app.Namespace, app.Name) + if endpointPrefix != "" { + base = "/" + endpointPrefix + base } - return u.String(), nil + return base } diff --git a/apiserver/pkg/gpt/gpt.go b/apiserver/pkg/gpt/gpt.go index 321550f10..fcf78099e 100644 --- a/apiserver/pkg/gpt/gpt.go +++ b/apiserver/pkg/gpt/gpt.go @@ -29,6 +29,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/kubeagi/arcadia/api/base/v1alpha1" + pkgconf "github.com/kubeagi/arcadia/apiserver/config" "github.com/kubeagi/arcadia/apiserver/graph/generated" "github.com/kubeagi/arcadia/apiserver/pkg/chat" "github.com/kubeagi/arcadia/apiserver/pkg/chat/storage" @@ -46,7 +47,7 @@ func app2gpt(ctx context.Context, app *v1alpha1.Application, c client.Client) (* return nil, errors.New("no app found") } - icon, _ := common.AppIconLink(ctx, app, c) + icon := common.AppIconLink(app, pkgconf.GetConfig().PlaygroundEndpointPrefix) gpt := &generated.Gpt{ Name: pointer.String(strings.Join([]string{app.Namespace, app.Name}, "/")), DisplayName: pointer.String(app.Spec.DisplayName), diff --git a/apiserver/service/minio_server.go b/apiserver/service/minio_server.go index daee7b09e..c51803e8d 100644 --- a/apiserver/service/minio_server.go +++ b/apiserver/service/minio_server.go @@ -29,6 +29,7 @@ import ( "github.com/gin-gonic/gin" "github.com/minio/minio-go/v7" + "k8s.io/apimachinery/pkg/types" "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" @@ -50,6 +51,8 @@ type ( conf gqlconfig.ServerConfig client client.Client lru cache.Cache + + endpointPrefix string } Chunk struct { @@ -1009,6 +1012,43 @@ func (m *minioAPI) EditCSV(ctx *gin.Context) { ctx.JSON(http.StatusOK, "") } +func (m *minioAPI) Image(ctx *gin.Context) { + namespace := ctx.Query("namespace") + appName := ctx.Query("application") + app := &v1alpha1.Application{} + if err := m.client.Get(ctx, types.NamespacedName{Namespace: namespace, Name: appName}, app); err != nil { + klog.Errorf("failed to get application %s in namespace, error %s", appName, namespace, err) + ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ + "message": err.Error(), + }) + return + } + + source, err := common.SystemDatasourceOSS(ctx.Request.Context(), m.client) + if err != nil { + klog.Errorf("failed to get system datasource error %s", err) + ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ + "message": fmt.Sprintf("failed to get system datasource error %s", err.Error()), + }) + return + } + + objectName := fmt.Sprintf("application/%s/icon/%s", appName, appName) + info, err := source.Client.GetObject(ctx.Request.Context(), namespace, objectName, minio.GetObjectOptions{}) + if err != nil { + klog.Errorf("failed to get system datasource error %s", err) + ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ + "message": fmt.Sprintf("failed to get system datasource error %s", err.Error()), + }) + return + } + + bs, _ := io.ReadAll(info) + ct := http.DetectContentType(bs) + ctx.Writer.Header().Set("Content-Type", ct) + io.Copy(ctx.Writer, bytes.NewReader(bs)) +} + func registerMinIOAPI(group *gin.RouterGroup, conf gqlconfig.ServerConfig) { c, err := pkgclient.GetClient(nil) if err != nil { @@ -1049,4 +1089,5 @@ func registerMinIOAPI(group *gin.RouterGroup, conf gqlconfig.ServerConfig) { } group.GET("/rags/files/downloadlink", auth.AuthInterceptor(conf.EnableOIDC, oidc.Verifier, evaluationarcadiav1alpha1.GroupVersion, "get", "rags"), api.GetDownloadLink) + group.GET("/icon", api.Image) }