f89d54362d
Closes deep-tuning gaps in v0.4-shipped doc / kb / session commands. Each command had multiple SDK fields the CLI silently hardcoded or omitted; this commit threads them through. doc upload: - --enable-multimodel (tri-state via NoOptDefVal): toggle multimodal extraction (PDF/DOCX image-to-text) per upload. Empty explicit value (e.g. --enable-multimodel="" from uninterpolated shell var) rejected as input.invalid_argument rather than silently coerced. - --metadata key=value (repeatable): attach arbitrary metadata - --channel <name> (default api, override for browser / wechat ingests) - URL mode gains --title / --file-type / --tag-id; URL-only flags rejected with input.invalid_argument when used without --from-url doc list filter flags: - --keyword (server-side LIKE — case-sensitive per PG) - --file-type / --source / --tag-id - --start-time / --end-time (RFC3339) search docs switches from client-side substring to server-side Keyword via ListKnowledgeWithFilter — smaller wire payload, but case-sensitivity shifts (documented in CHANGELOG + help text + Long). MCP doc_list schema gains the same 6 filter fields (parity with CLI). session view --full + --limit: loads chat history via LoadMessages SDK method. kb view human KV expanded: type / pinned / temporary / processing state + count / summary model / created timestamp. All omit-empty. doc view human KV expanded: title (when distinct from filename) / description / source / channel / summary_status / enable_status / tag_id / storage (human bytes) / file_hash (12-char prefix).
104 lines
3.2 KiB
Go
104 lines
3.2 KiB
Go
package kb
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/Tencent/WeKnora/cli/internal/cmdutil"
|
|
"github.com/Tencent/WeKnora/cli/internal/iostreams"
|
|
"github.com/Tencent/WeKnora/cli/internal/text"
|
|
sdk "github.com/Tencent/WeKnora/client"
|
|
)
|
|
|
|
// kbViewFields enumerates the fields surfaced for `--json` discovery on
|
|
// `kb view`. Lists the KnowledgeBase top-level json tags; nested config
|
|
// structs are omitted (use --jq for those).
|
|
var kbViewFields = []string{
|
|
"id", "name", "type", "description",
|
|
"is_temporary", "is_pinned",
|
|
"embedding_model_id", "summary_model_id",
|
|
"knowledge_count", "chunk_count",
|
|
"is_processing", "processing_count",
|
|
"created_at", "updated_at",
|
|
}
|
|
|
|
type ViewOptions struct{}
|
|
|
|
// ViewService is the narrow SDK surface this command depends on.
|
|
type ViewService interface {
|
|
GetKnowledgeBase(ctx context.Context, id string) (*sdk.KnowledgeBase, error)
|
|
}
|
|
|
|
// NewCmdView builds `weknora kb view <id>`.
|
|
func NewCmdView(f *cmdutil.Factory) *cobra.Command {
|
|
opts := &ViewOptions{}
|
|
cmd := &cobra.Command{
|
|
Use: "view <id>",
|
|
Short: "Show a knowledge base by ID",
|
|
Long: `Fetch a knowledge base's full configuration: chunking settings, embedding / summary model IDs, knowledge_count, chunk_count.`,
|
|
Args: cobra.ExactArgs(1),
|
|
RunE: func(c *cobra.Command, args []string) error {
|
|
jopts, err := cmdutil.CheckJSONFlags(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
cli, err := f.Client()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return runView(c.Context(), opts, jopts, cli, args[0])
|
|
},
|
|
}
|
|
cmdutil.AddJSONFlags(cmd, kbViewFields)
|
|
return cmd
|
|
}
|
|
|
|
func runView(ctx context.Context, opts *ViewOptions, jopts *cmdutil.JSONOptions, svc ViewService, id string) error {
|
|
kb, err := svc.GetKnowledgeBase(ctx, id)
|
|
if err != nil {
|
|
return cmdutil.WrapHTTP(err, "get knowledge base %q", id)
|
|
}
|
|
if jopts.Enabled() {
|
|
return jopts.Emit(iostreams.IO.Out, kb)
|
|
}
|
|
// Human: KEY: VALUE. Nested config structs (chunking_config, vlm_config,
|
|
// etc.) are intentionally omitted from the human render — those are for
|
|
// `--json | jq '.chunking_config'` workflows.
|
|
w := iostreams.IO.Out
|
|
fmt.Fprintf(w, "ID: %s\n", kb.ID)
|
|
fmt.Fprintf(w, "NAME: %s\n", kb.Name)
|
|
if kb.Type != "" {
|
|
fmt.Fprintf(w, "TYPE: %s\n", kb.Type)
|
|
}
|
|
if kb.Description != "" {
|
|
fmt.Fprintf(w, "DESC: %s\n", kb.Description)
|
|
}
|
|
if kb.IsPinned {
|
|
fmt.Fprintf(w, "PINNED: yes\n")
|
|
}
|
|
if kb.IsTemporary {
|
|
fmt.Fprintf(w, "TEMPORARY: yes\n")
|
|
}
|
|
fmt.Fprintf(w, "DOCS: %s\n", text.Pluralize(int(kb.KnowledgeCount), "doc"))
|
|
fmt.Fprintf(w, "CHUNKS: %s\n", text.Pluralize(int(kb.ChunkCount), "chunk"))
|
|
if kb.IsProcessing {
|
|
fmt.Fprintf(w, "PROCESSING: %s\n", text.Pluralize(int(kb.ProcessingCount), "doc"))
|
|
}
|
|
if kb.EmbeddingModelID != "" {
|
|
fmt.Fprintf(w, "EMBEDDING: %s\n", kb.EmbeddingModelID)
|
|
}
|
|
if kb.SummaryModelID != "" {
|
|
fmt.Fprintf(w, "SUMMARY MODEL: %s\n", kb.SummaryModelID)
|
|
}
|
|
if !kb.CreatedAt.IsZero() {
|
|
fmt.Fprintf(w, "CREATED: %s\n", kb.CreatedAt.Format("2006-01-02 15:04:05"))
|
|
}
|
|
if !kb.UpdatedAt.IsZero() {
|
|
// Detail page favors absolute time; FuzzyAgo is reserved for list views.
|
|
fmt.Fprintf(w, "UPDATED: %s\n", kb.UpdatedAt.Format("2006-01-02 15:04:05"))
|
|
}
|
|
return nil
|
|
}
|