package monitoring import ( "context" "errors" "time" "knowledge-governance/internal/governance" ) type SimulationProvider struct{ now func() time.Time } func NewSimulationProvider(now func() time.Time) *SimulationProvider { if now == nil { now = time.Now } return &SimulationProvider{now: now} } func (provider *SimulationProvider) Overview(context.Context) (governance.MonitorOverview, error) { now := provider.now().UTC() return governance.MonitorOverview{ Mode: "simulation", Simulated: true, ObservedAt: now, Host: governance.MonitorHost{CPUPercent: 42, MemoryUsedBytes: 19971597926, MemoryTotalBytes: 34359738368, DiskUsedBytes: 128849018880, DiskTotalBytes: 536870912000, GPUState: "unknown", GPUDetail: "未接入真实GPU监控", Simulated: true}, Services: []governance.MonitorService{ {Key: "weknora", Name: "WeKnora API", State: "healthy", Detail: "模拟连接正常", LatencyMS: 86, ObservedAt: now, Simulated: true}, {Key: "embedding", Name: "Embedding模型", State: "healthy", Detail: "模拟探测通过", LatencyMS: 142, ObservedAt: now, Simulated: true}, {Key: "llm", Name: "LLM模型", State: "healthy", Detail: "模拟探测通过", LatencyMS: 318, ObservedAt: now, Simulated: true}, {Key: "mineru", Name: "MinerU", State: "healthy", Detail: "模拟处理中2,队列5", LatencyMS: 24, ObservedAt: now, Simulated: true}, {Key: "postgres", Name: "PostgreSQL", State: "unknown", Detail: "未接入真实监控", ObservedAt: now, Simulated: true}, {Key: "redis", Name: "Redis / MQ", State: "unknown", Detail: "未接入真实监控", ObservedAt: now, Simulated: true}, {Key: "oss", Name: "OSS", State: "unknown", Detail: "未接入真实监控", ObservedAt: now, Simulated: true}, }, KnowledgeBases: []governance.KnowledgeBaseProgress{{ID: "simulation-company-support", Name: "公司级技术支持知识库", Visibility: "mixed", Imported: 5750, Completed: 4530, Pending: 450, Processing: 50, Finalizing: 714, Failed: 6, InternalImported: 4200, InternalCompleted: 3300, ExternalImported: 1550, ExternalCompleted: 1230}}, }, nil } var simulationFiles = []governance.KnowledgeMonitorFile{ {Name: "[模拟] CR5用户手册.pdf", Directory: "02|产品资料/CR系列", Visibility: "internal", Status: "completed", StageDetail: "解析、切片和增强任务均完成", ElapsedSecond: 0}, {Name: "[模拟] MG400部署说明.pdf", Directory: "03|机器人部署与使用", Visibility: "internal", Status: "pending", StageDetail: "等待进入解析队列", ElapsedSecond: 420}, {Name: "[模拟] 产品参数总表.xlsx", Directory: "02|产品资料", Visibility: "external", Status: "finalizing", StageDetail: "基础检索可用,Wiki与图谱仍在生成", ElapsedSecond: 2100}, {Name: "[模拟] 二次开发接口说明.docx", Directory: "05|二次开发", Visibility: "internal", Status: "processing", StageDetail: "正在切片和向量化", ElapsedSecond: 480}, {Name: "[模拟] CRA-IP68产品介绍.pdf", Directory: "06|应用案例与解决方案", Visibility: "external", Status: "failed", StageDetail: "MinerU解析失败", ElapsedSecond: 720, ErrorCode: "mineru_parse_failed"}, } func (provider *SimulationProvider) ListFiles(_ context.Context, knowledgeBaseID, status string, limit, offset int) (governance.KnowledgeMonitorFilePage, error) { if knowledgeBaseID != "simulation-company-support" || limit < 1 || limit > 100 || offset < 0 { return governance.KnowledgeMonitorFilePage{}, errors.New("invalid monitor file query") } allowed := map[string]bool{"": true, "completed": true, "pending": true, "processing": true, "finalizing": true, "failed": true, "cancelled": true} if !allowed[status] { return governance.KnowledgeMonitorFilePage{}, errors.New("invalid monitor status") } filtered := make([]governance.KnowledgeMonitorFile, 0) for _, item := range simulationFiles { if status == "" || item.Status == status { filtered = append(filtered, item) } } page := governance.KnowledgeMonitorFilePage{Total: len(filtered), Limit: limit, Offset: offset, SampleOnly: true, Items: []governance.KnowledgeMonitorFile{}} if offset < len(filtered) { end := offset + limit if end > len(filtered) { end = len(filtered) } page.Items = append(page.Items, filtered[offset:end]...) } return page, nil } // Metrics declares that no real run metrics exist in simulation mode: every // sample-dependent number stays null instead of pretending to be zero (P9). func (provider *SimulationProvider) Metrics(context.Context) (governance.RunMetrics, error) { now := provider.now().UTC() return governance.RunMetrics{ ObservedAt: now, WorkerSource: "simulation", ShortWindow: governance.JobWindowMetrics{WindowSeconds: int((1 * time.Hour).Seconds())}, LongWindow: governance.JobWindowMetrics{WindowSeconds: int((24 * time.Hour).Seconds())}, }, nil } // Services declares that a simulation provider owns no real dependencies: every // readiness judgement belongs to the real provider. func (provider *SimulationProvider) Services(_ context.Context) []governance.ServiceHealth { return []governance.ServiceHealth{} }