WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/Tencent/WeKnora/internal/types"
|
||||
)
|
||||
|
||||
// Reuse the same access-checked scope resolver as retrieval. Descriptions are
|
||||
// persisted document summaries, not a claim that every raw chunk was read.
|
||||
func (s *sessionService) KnowledgeReadingOverview(ctx context.Context, kbs, files []string, scopes []types.TagScope) (*types.KnowledgeReadingOverview, error) {
|
||||
tenant, ok := types.TenantIDFromContext(ctx)
|
||||
if !ok { return nil, fmt.Errorf("workspace ID not found in context") }
|
||||
targets, err := s.buildSearchTargets(ctx, tenant, kbs, files, scopes)
|
||||
if err != nil { return nil, err }
|
||||
result := &types.KnowledgeReadingOverview{Entries: []types.KnowledgeReadingEntry{}}
|
||||
scopeParts := []string{}
|
||||
seen := map[string]bool{}
|
||||
for _, target := range targets {
|
||||
ids, tags := append([]string(nil), target.KnowledgeIDs...), append([]string(nil), target.TagIDs...)
|
||||
sort.Strings(ids)
|
||||
sort.Strings(tags)
|
||||
scopeParts = append(scopeParts, fmt.Sprintf("%s|%s|%v|%v", target.KnowledgeBaseID, target.Type, ids, tags))
|
||||
base, checkErr := s.knowledgeBaseService.GetKnowledgeBaseByID(ctx, target.KnowledgeBaseID)
|
||||
if checkErr != nil { return nil, checkErr }
|
||||
if base == nil { return nil, fmt.Errorf("知识库不存在或无权使用") }
|
||||
listCtx := ctx
|
||||
if base.TenantID != tenant {
|
||||
if s.kbShareService == nil { return nil, fmt.Errorf("知识库不存在或无权使用") }
|
||||
allowed, shareErr := s.kbShareService.HasTenantKBPermission(ctx, base.ID, tenant, types.TenantRoleFromContext(ctx), types.OrgRoleViewer)
|
||||
if shareErr != nil || !allowed { return nil, fmt.Errorf("知识库不存在或无权使用") }
|
||||
listCtx = context.WithValue(ctx, types.TenantIDContextKey, base.TenantID)
|
||||
}
|
||||
var rows []*types.Knowledge
|
||||
if target.Type == types.SearchTargetTypeKnowledge {
|
||||
rows, err = s.knowledgeService.GetKnowledgeBatchWithSharedAccess(ctx, tenant, target.KnowledgeIDs)
|
||||
} else {
|
||||
rows, err = s.knowledgeService.ListKnowledgeByKnowledgeBaseID(listCtx, target.KnowledgeBaseID)
|
||||
}
|
||||
if err != nil { return nil, err }
|
||||
for _, row := range rows {
|
||||
if row == nil || row.KnowledgeBaseID != target.KnowledgeBaseID || seen[row.ID] || row.EnableStatus == "disabled" || row.ParseStatus != types.ParseStatusCompleted { continue }
|
||||
seen[row.ID] = true
|
||||
title := row.Title
|
||||
if title == "" { title = row.FileName }
|
||||
summary := ""
|
||||
// FAQ tags select chunks within one document; its whole-document
|
||||
// summary could expose content outside the chosen category.
|
||||
if row.SummaryStatus == types.SummaryStatusCompleted && len(target.TagIDs) == 0 { summary = strings.TrimSpace(row.Description) }
|
||||
entry := types.KnowledgeReadingEntry{ID: row.ID, KnowledgeBaseID: row.KnowledgeBaseID, Title: title, Folder: row.FolderPath, Summary: summary}
|
||||
entry.Fingerprint = fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprintf("%s|%s|%s|%s|%s", row.ID, row.FileHash, row.UpdatedAt.UTC().Format("2006-01-02T15:04:05.999999999Z"), title, summary))))
|
||||
result.Entries = append(result.Entries, entry)
|
||||
result.DocumentCount++
|
||||
if summary != "" { result.SummaryCount++ }
|
||||
}
|
||||
}
|
||||
sort.Slice(result.Entries, func(i,j int) bool { return result.Entries[i].ID < result.Entries[j].ID })
|
||||
hash := sha256.New()
|
||||
sort.Strings(scopeParts)
|
||||
for _, part := range scopeParts { fmt.Fprintln(hash, part) }
|
||||
for _, entry := range result.Entries { fmt.Fprintln(hash, entry.Fingerprint) }
|
||||
result.Fingerprint = fmt.Sprintf("%x", hash.Sum(nil))
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user