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,242 @@
|
||||
// Package types defines data structures and types used throughout the system
|
||||
// These types are shared across different service modules to ensure data consistency
|
||||
package types
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// ChunkType 定义了不同类型的 Chunk
|
||||
type ChunkType = string
|
||||
|
||||
const (
|
||||
// ChunkTypeText 表示普通的文本 Chunk
|
||||
ChunkTypeText ChunkType = "text"
|
||||
// ChunkTypeParentText 表示父子分块策略中的父文本 Chunk(仅用于上下文,不参与向量索引)
|
||||
ChunkTypeParentText ChunkType = "parent_text"
|
||||
// ChunkTypeImageOCR 表示图片 OCR 文本的 Chunk
|
||||
ChunkTypeImageOCR ChunkType = "image_ocr"
|
||||
// ChunkTypeImageCaption 表示图片描述的 Chunk
|
||||
ChunkTypeImageCaption ChunkType = "image_caption"
|
||||
// ChunkTypeSummary 表示摘要类型的 Chunk
|
||||
ChunkTypeSummary = "summary"
|
||||
// ChunkTypeEntity 表示实体类型的 Chunk
|
||||
ChunkTypeEntity ChunkType = "entity"
|
||||
// ChunkTypeRelationship 表示关系类型的 Chunk
|
||||
ChunkTypeRelationship ChunkType = "relationship"
|
||||
// ChunkTypeFAQ 表示 FAQ 条目 Chunk
|
||||
ChunkTypeFAQ ChunkType = "faq"
|
||||
// ChunkTypeWebSearch 表示 Web 搜索结果的 Chunk
|
||||
ChunkTypeWebSearch ChunkType = "web_search"
|
||||
// ChunkTypeTableSummary 表示数据表摘要的 Chunk
|
||||
ChunkTypeTableSummary ChunkType = "table_summary"
|
||||
// ChunkTypeTableColumn 表示数据表列描述的 Chunk
|
||||
ChunkTypeTableColumn ChunkType = "table_column"
|
||||
// ChunkTypeWikiPage 表示 Wiki 页面同步的 Chunk,用于将 wiki 页面接入现有检索管线
|
||||
ChunkTypeWikiPage ChunkType = "wiki_page"
|
||||
)
|
||||
|
||||
// ChunkStatus 定义了不同状态的 Chunk
|
||||
type ChunkStatus int
|
||||
|
||||
const (
|
||||
ChunkStatusDefault ChunkStatus = 0
|
||||
// ChunkStatusStored 表示已存储的 Chunk
|
||||
ChunkStatusStored ChunkStatus = 1
|
||||
// ChunkStatusIndexed 表示已索引的 Chunk
|
||||
ChunkStatusIndexed ChunkStatus = 2
|
||||
)
|
||||
|
||||
// ChunkFlags 定义 Chunk 的标志位,用于管理多个布尔状态
|
||||
type ChunkFlags int
|
||||
|
||||
const (
|
||||
// ChunkFlagRecommended 表示可推荐状态(1 << 0 = 1)
|
||||
// 当设置此标志时,该 Chunk 可以被推荐给用户
|
||||
ChunkFlagRecommended ChunkFlags = 1 << 0
|
||||
// 未来可扩展更多标志位:
|
||||
// ChunkFlagPinned ChunkFlags = 1 << 1 // 置顶
|
||||
// ChunkFlagHot ChunkFlags = 1 << 2 // 热门
|
||||
)
|
||||
|
||||
// HasFlag 检查是否设置了指定标志
|
||||
func (f ChunkFlags) HasFlag(flag ChunkFlags) bool {
|
||||
return f&flag != 0
|
||||
}
|
||||
|
||||
// SetFlag 设置指定标志
|
||||
func (f ChunkFlags) SetFlag(flag ChunkFlags) ChunkFlags {
|
||||
return f | flag
|
||||
}
|
||||
|
||||
// ClearFlag 清除指定标志
|
||||
func (f ChunkFlags) ClearFlag(flag ChunkFlags) ChunkFlags {
|
||||
return f &^ flag
|
||||
}
|
||||
|
||||
// ToggleFlag 切换指定标志
|
||||
func (f ChunkFlags) ToggleFlag(flag ChunkFlags) ChunkFlags {
|
||||
return f ^ flag
|
||||
}
|
||||
|
||||
// ImageInfo 表示与 Chunk 关联的图片信息
|
||||
type ImageInfo struct {
|
||||
// 图片URL(COS)
|
||||
URL string `json:"url" gorm:"type:text"`
|
||||
// 原始图片URL
|
||||
OriginalURL string `json:"original_url" gorm:"type:text"`
|
||||
// 图片在文本中的开始位置
|
||||
StartPos int `json:"start_pos"`
|
||||
// 图片在文本中的结束位置
|
||||
EndPos int `json:"end_pos"`
|
||||
// 图片描述
|
||||
Caption string `json:"caption"`
|
||||
// 图片OCR文本
|
||||
OCRText string `json:"ocr_text"`
|
||||
}
|
||||
|
||||
// VideoInfo 表示与 Chunk 关联的视频信息
|
||||
type VideoInfo struct {
|
||||
// 视频URL
|
||||
URL string `json:"url" gorm:"type:text"`
|
||||
}
|
||||
|
||||
// Chunk represents a document chunk
|
||||
// Chunks are meaningful text segments extracted from original documents
|
||||
// and are the basic units of knowledge base retrieval
|
||||
// Each chunk contains a portion of the original content
|
||||
// and maintains its positional relationship with the original text
|
||||
// Chunks can be independently embedded as vectors and retrieved, supporting precise content localization
|
||||
type Chunk struct {
|
||||
// Unique identifier of the chunk, using UUID format
|
||||
ID string `json:"id" gorm:"type:varchar(36);primaryKey"`
|
||||
// SeqID is an auto-increment integer ID for external API usage (FAQ entries)
|
||||
SeqID int64 `json:"seq_id" gorm:"type:bigint;uniqueIndex;autoIncrement"`
|
||||
// Tenant ID, used for multi-tenant isolation
|
||||
TenantID uint64 `json:"tenant_id"`
|
||||
// ID of the parent knowledge, associated with the Knowledge model
|
||||
KnowledgeID string `json:"knowledge_id"`
|
||||
// ID of the knowledge base, for quick location
|
||||
KnowledgeBaseID string `json:"knowledge_base_id"`
|
||||
// Optional tag ID for categorization within a knowledge base (used for FAQ)
|
||||
TagID string `json:"tag_id" gorm:"type:varchar(36);index"`
|
||||
// Actual text content of the chunk
|
||||
Content string `json:"content"`
|
||||
// SourceContent is the immutable parser output. Legacy rows are lazily
|
||||
// backfilled from Content on the first manual edit.
|
||||
SourceContent string `json:"-"`
|
||||
// ContentRevision is incremented for every user edit or rollback.
|
||||
ContentRevision int `json:"content_revision" gorm:"not null;default:0"`
|
||||
// IndexStatus reports whether the current content is reflected in the
|
||||
// retrieval stores: ready | processing | failed.
|
||||
IndexStatus string `json:"index_status" gorm:"type:varchar(16);not null;default:'ready'"`
|
||||
// LastEditorID records the actor that produced the current revision.
|
||||
LastEditorID string `json:"last_editor_id" gorm:"type:varchar(64);not null;default:''"`
|
||||
// Index position of the chunk in the original document
|
||||
ChunkIndex int `json:"chunk_index"`
|
||||
// Whether the chunk is enabled, can be used to temporarily disable certain chunks
|
||||
IsEnabled bool `json:"is_enabled" gorm:"default:true"`
|
||||
// Flags 存储多个布尔状态的位标志(如推荐状态等)
|
||||
// 默认值为 ChunkFlagRecommended (1),表示默认可推荐
|
||||
Flags ChunkFlags `json:"flags" gorm:"default:1"`
|
||||
// Status of the chunk
|
||||
Status int `json:"status" gorm:"default:0"`
|
||||
// Starting character position in the original text
|
||||
StartAt int `json:"start_at"`
|
||||
// Ending character position in the original text
|
||||
EndAt int `json:"end_at"`
|
||||
// Previous chunk ID
|
||||
PreChunkID string `json:"pre_chunk_id"`
|
||||
// Next chunk ID
|
||||
NextChunkID string `json:"next_chunk_id"`
|
||||
// Chunk 类型,用于区分不同类型的 Chunk
|
||||
ChunkType ChunkType `json:"chunk_type" gorm:"type:varchar(20);default:'text'"`
|
||||
// 父 Chunk ID,用于关联图片 Chunk 和原始文本 Chunk
|
||||
ParentChunkID string `json:"parent_chunk_id" gorm:"type:varchar(36);index"`
|
||||
// 关系 Chunk ID,用于关联关系 Chunk 和原始文本 Chunk
|
||||
RelationChunks JSON `json:"relation_chunks" gorm:"type:json"`
|
||||
// 间接关系 Chunk ID,用于关联间接关系 Chunk 和原始文本 Chunk
|
||||
IndirectRelationChunks JSON `json:"indirect_relation_chunks" gorm:"type:json"`
|
||||
// Metadata 存储 chunk 级别的扩展信息,例如 FAQ 元数据
|
||||
Metadata JSON `json:"metadata" gorm:"type:json"`
|
||||
// ContentHash 存储内容的 hash 值,用于快速匹配(主要用于 FAQ)
|
||||
ContentHash string `json:"content_hash" gorm:"type:varchar(64);index"`
|
||||
// 图片信息,存储为 JSON
|
||||
ImageInfo string `json:"image_info" gorm:"type:text"`
|
||||
// Chunk creation time
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
// Chunk last update time
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
// Soft delete marker, supports data recovery
|
||||
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
|
||||
// ContextHeader is a Markdown heading breadcrumb prepended when indexing.
|
||||
// It is persisted so a later content edit can rebuild the same index input.
|
||||
ContextHeader string `json:"-" gorm:"type:text"`
|
||||
}
|
||||
|
||||
// ChunkRevision is an immutable snapshot of a superseded chunk revision.
|
||||
// The current content lives on Chunk; this table stores prior versions.
|
||||
type ChunkRevision struct {
|
||||
ID string `json:"id" gorm:"type:varchar(36);primaryKey"`
|
||||
TenantID uint64 `json:"tenant_id" gorm:"index"`
|
||||
KnowledgeBaseID string `json:"knowledge_base_id" gorm:"type:varchar(36);index"`
|
||||
KnowledgeID string `json:"knowledge_id" gorm:"type:varchar(36);index"`
|
||||
ChunkID string `json:"chunk_id" gorm:"type:varchar(36);uniqueIndex:idx_chunk_revision"`
|
||||
Revision int `json:"revision" gorm:"uniqueIndex:idx_chunk_revision"`
|
||||
Content string `json:"content" gorm:"type:text"`
|
||||
IsEnabled bool `json:"is_enabled"`
|
||||
EditorID string `json:"editor_id" gorm:"type:varchar(64)"`
|
||||
EditSource string `json:"edit_source" gorm:"type:varchar(16)"`
|
||||
EditedAt time.Time `json:"edited_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// EmbeddingContent returns the chunk content with ContextHeader prepended
|
||||
// when set. Use this where the embedding model needs section context that
|
||||
// isn't part of the literal Content. Surrounding whitespace on Content is
|
||||
// trimmed so leading/trailing newlines from boundary slicing don't dilute
|
||||
// the embedded vector.
|
||||
func (c *Chunk) EmbeddingContent() string {
|
||||
if c == nil {
|
||||
return ""
|
||||
}
|
||||
body := strings.TrimSpace(c.Content)
|
||||
if c.ContextHeader == "" {
|
||||
return body
|
||||
}
|
||||
return c.ContextHeader + "\n\n" + body
|
||||
}
|
||||
|
||||
// AssignChunkSeqIDs assigns sequential SeqIDs to a batch of chunks that have SeqID == 0.
|
||||
// Must be called before CreateInBatches for SQLite compatibility.
|
||||
func AssignChunkSeqIDs(tx *gorm.DB, chunks []*Chunk) error {
|
||||
needAssign := false
|
||||
for _, c := range chunks {
|
||||
if c.SeqID == 0 {
|
||||
needAssign = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !needAssign {
|
||||
return nil
|
||||
}
|
||||
|
||||
var maxSeqID *int64
|
||||
if err := tx.Unscoped().Model(&Chunk{}).Select("MAX(seq_id)").Scan(&maxSeqID).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
next := int64(1)
|
||||
if maxSeqID != nil {
|
||||
next = *maxSeqID + 1
|
||||
}
|
||||
for _, c := range chunks {
|
||||
if c.SeqID == 0 {
|
||||
c.SeqID = next
|
||||
next++
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user