db95b8e4ee
Add prompt_content columns to kol_prompts and kol_prompt_revisions so prompt bodies live alongside their metadata, eliminating an extra round trip to object storage for the common read path while keeping the old asset key as a fallback for legacy rows. Reads go through a singleflight-deduped, cache-backed loader that prefers the database column, falls back to the asset key, and tolerates missing objects via a new objectstorage.ErrObjectNotFound returned by both the Aliyun OSS and MinIO clients on 404/NoSuchKey responses. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
81 lines
1.8 KiB
Go
81 lines
1.8 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
|
|
"golang.org/x/sync/singleflight"
|
|
|
|
sharedcache "github.com/geo-platform/tenant-api/internal/shared/cache"
|
|
"github.com/geo-platform/tenant-api/internal/shared/objectstorage"
|
|
"github.com/geo-platform/tenant-api/internal/tenant/repository"
|
|
)
|
|
|
|
func loadKolPromptContent(
|
|
ctx context.Context,
|
|
cache sharedcache.Cache,
|
|
group *singleflight.Group,
|
|
promptRepo repository.KolPromptRepository,
|
|
asset *KolPromptAsset,
|
|
prompt *repository.KolPrompt,
|
|
) (string, error) {
|
|
if prompt == nil {
|
|
return "", nil
|
|
}
|
|
|
|
loader := func(loadCtx context.Context) (string, error) {
|
|
return loadKolPromptContentUncached(loadCtx, promptRepo, asset, prompt)
|
|
}
|
|
if cache == nil || group == nil {
|
|
return loader(ctx)
|
|
}
|
|
|
|
return sharedcache.LoadJSON(
|
|
ctx,
|
|
cache,
|
|
group,
|
|
kolPromptContentCacheKey(prompt.TenantID, prompt.ID),
|
|
defaultCacheTTL(),
|
|
loader,
|
|
)
|
|
}
|
|
|
|
func loadKolPromptContentUncached(
|
|
ctx context.Context,
|
|
promptRepo repository.KolPromptRepository,
|
|
asset *KolPromptAsset,
|
|
prompt *repository.KolPrompt,
|
|
) (string, error) {
|
|
if prompt == nil {
|
|
return "", nil
|
|
}
|
|
|
|
if promptRepo != nil {
|
|
content, err := promptRepo.GetContentByID(ctx, prompt.TenantID, prompt.ID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if content != nil && strings.TrimSpace(*content) != "" {
|
|
return *content, nil
|
|
}
|
|
}
|
|
|
|
if prompt.PromptContent != nil && strings.TrimSpace(*prompt.PromptContent) != "" {
|
|
return *prompt.PromptContent, nil
|
|
}
|
|
|
|
if prompt.PromptAssetKey == nil || strings.TrimSpace(*prompt.PromptAssetKey) == "" || asset == nil {
|
|
return "", nil
|
|
}
|
|
|
|
content, err := asset.Get(ctx, strings.TrimSpace(*prompt.PromptAssetKey))
|
|
if err != nil {
|
|
if errors.Is(err, objectstorage.ErrObjectNotFound) || errors.Is(err, objectstorage.ErrNotConfigured) {
|
|
return "", nil
|
|
}
|
|
return "", err
|
|
}
|
|
return content, nil
|
|
}
|