diff --git a/kb/kb.go b/kb/kb.go index e7a66199..f849809f 100644 --- a/kb/kb.go +++ b/kb/kb.go @@ -8,6 +8,12 @@ import ( "github.com/yaoapp/gou/graphrag/types" "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/config" + + // Register the built-in providers + _ "github.com/yaoapp/yao/kb/providers" + + // Import the kb types + kbtypes "github.com/yaoapp/yao/kb/types" ) // Instance is the GraphRag instance @@ -15,7 +21,7 @@ var Instance types.GraphRag = nil // KnowledgeBase is the Knowledge Base instance type KnowledgeBase struct { - Config *Config // Knowledge Base configuration + Config *kbtypes.Config // Knowledge Base configuration *graphrag.GraphRag } @@ -33,7 +39,7 @@ func Load(appConfig config.Config) (*KnowledgeBase, error) { } // Parse the configuration - var config Config + var config kbtypes.Config raw, err := application.App.Read(filepath.Join("kb", "kb.yao")) if err != nil { return nil, err diff --git a/kb/provider.go b/kb/provider.go new file mode 100644 index 00000000..b310b909 --- /dev/null +++ b/kb/provider.go @@ -0,0 +1 @@ +package kb diff --git a/kb/providers/chunking.go b/kb/providers/chunking.go new file mode 100644 index 00000000..e286c938 --- /dev/null +++ b/kb/providers/chunking.go @@ -0,0 +1,54 @@ +package providers + +import ( + "github.com/yaoapp/gou/graphrag/chunking" + "github.com/yaoapp/gou/graphrag/types" + "github.com/yaoapp/yao/kb/providers/factory" + kbtypes "github.com/yaoapp/yao/kb/types" +) + +// Structured is a structured chunking provider +type Structured struct{} + +// Semantic is a semantic chunking provider +type Semantic struct{} + +// AutoRegister registers the chunking providers +func init() { + factory.Chunkings["__yao.structured"] = &Structured{} + factory.Chunkings["__yao.semantic"] = &Semantic{} +} + +// === Structured Chunking === + +// Make creates a structured chunking provider +func (s *Structured) Make(_ *kbtypes.ProviderOption) (types.Chunking, error) { + return chunking.NewStructuredChunker(), nil +} + +// Options returns the options for the structured chunking provider +func (s *Structured) Options(option *kbtypes.ProviderOption) (*types.ChunkingOptions, error) { + return nil, nil +} + +// Schema returns the schema for the structured chunking provider +func (s *Structured) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} + +// === Semantic Chunking === + +// Make creates a semantic chunking provider +func (s *Semantic) Make(_ *kbtypes.ProviderOption) (types.Chunking, error) { + return chunking.NewSemanticChunker(nil), nil +} + +// Options returns the options for the semantic chunking provider +func (s *Semantic) Options(option *kbtypes.ProviderOption) (*types.ChunkingOptions, error) { + return nil, nil +} + +// Schema returns the schema for the semantic chunking provider +func (s *Semantic) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} diff --git a/kb/providers/converter.go b/kb/providers/converter.go new file mode 100644 index 00000000..e73f949b --- /dev/null +++ b/kb/providers/converter.go @@ -0,0 +1,251 @@ +package providers + +import ( + "strings" + + "github.com/yaoapp/gou/graphrag/converter" + "github.com/yaoapp/gou/graphrag/types" + "github.com/yaoapp/yao/kb/providers/factory" + kbtypes "github.com/yaoapp/yao/kb/types" +) + +// Converter is a base converter provider +type Converter struct { + Autodetect []string `json:"autodetect" yaml:"autodetect"` // Optional, default is empty, if not set, will not use autodetect + MatchPriority int `json:"match_priority" yaml:"match_priority"` // Optional, default is 0, the higher the number, the higher the priority +} + +// UTF8 is a converter provider for utf8 files +type UTF8 struct{ Converter } + +// Office is a converter provider for office files, support docx, pptx. +type Office struct{ Converter } + +// OCR is a converter provider for ocr files, support pdf, image. +type OCR struct{ Converter } + +// Video is a converter provider for video files +type Video struct{ Converter } + +// Whisper is a converter provider for audio files +type Whisper struct{ Converter } + +// Vision is a converter provider for vision files +type Vision struct{ Converter } + +// MCP is a converter provider for mcp files +type MCP struct{ Converter } + +// AutoRegister registers the converter providers +func init() { + factory.Converters["__yao.utf8"] = &UTF8{ + Converter: Converter{ + Autodetect: []string{"text/plain", "text/markdown", ".txt", ".md"}, + MatchPriority: 100, + }, + } + factory.Converters["__yao.office"] = &Office{ + Converter: Converter{ + Autodetect: []string{"application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.openxmlformats-officedocument.presentationml.presentation", ".docx", ".pptx"}, + MatchPriority: 10, + }, + } + factory.Converters["__yao.ocr"] = &OCR{ + Converter: Converter{ + Autodetect: []string{"application/pdf", "image/jpeg", "image/png", "image/gif", "image/webp", ".pdf", ".jpg", ".jpeg", ".png", ".gif", ".webp"}, + MatchPriority: 10, + }, + } + + factory.Converters["__yao.video"] = &Video{ + Converter: Converter{ + Autodetect: []string{"video/mp4", "video/mpeg", "video/quicktime", "video/webm", ".mp4", ".mpeg", ".mov", ".webm"}, + MatchPriority: 10, + }, + } + + factory.Converters["__yao.whisper"] = &Whisper{ + Converter: Converter{ + Autodetect: []string{"audio/mpeg", "audio/wav", "audio/webm", ".mp3", ".wav", ".webm"}, + MatchPriority: 10, + }, + } + + factory.Converters["__yao.vision"] = &Vision{ + Converter: Converter{ + Autodetect: []string{"image/jpeg", "image/png", "image/gif", "image/webp", ".jpg", ".jpeg", ".png", ".gif", ".webp"}, + MatchPriority: 20, + }, + } + + factory.Converters["__yao.mcp"] = &MCP{Converter: Converter{}} + +} + +// AutoDetect detects the converter based on the filename and content types +func (c Converter) AutoDetect(filename, contentTypes string) (bool, int, error) { + + // If autodetect is empty, return false + if c.Autodetect == nil { + return false, 0, nil + } + + // Check if the filename matches the autodetect + for _, autodetect := range c.Autodetect { + if strings.HasSuffix(filename, autodetect) { + return true, c.MatchPriority, nil + } + + // Check if the content types matches the autodetect + if strings.Contains(contentTypes, autodetect) { + return true, c.MatchPriority, nil + } + } + + return false, 0, nil +} + +// === UTF8 === + +// Make creates a new UTF8 converter +func (utf8 *UTF8) Make(option *kbtypes.ProviderOption) (types.Converter, error) { + return converter.NewUTF8(), nil +} + +// Schema returns the schema for the UTF8 converter +func (utf8 *UTF8) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} + +// === Office === + +// Make creates a new Office converter +func (office *Office) Make(option *kbtypes.ProviderOption) (types.Converter, error) { + // TODO: Map kbtypes.ProviderOption to converter.OfficeOption + officeOption := converter.OfficeOption{ + // VisionConverter: nil, // TODO: Get vision converter from option + // VideoConverter: nil, // TODO: Get video converter from option + // WhisperConverter: nil, // TODO: Get whisper converter from option + // MaxConcurrency: 0, // Will use default + // TempDir: "", // Will use default + // CleanupTemp: false, + } + return converter.NewOffice(officeOption) +} + +// Schema returns the schema for the Office converter +func (office *Office) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} + +// === OCR === + +// Make creates a new OCR converter +func (ocr *OCR) Make(option *kbtypes.ProviderOption) (types.Converter, error) { + // TODO: Map kbtypes.ProviderOption to converter.OCROption + ocrOption := converter.OCROption{ + // Vision: nil, // TODO: Get vision converter from option + // Mode: "", // Will use default + // MaxConcurrency: 0, // Will use default + // CompressSize: 0, // Will use default + // ForceImageMode: false, + } + return converter.NewOCR(ocrOption) +} + +// Schema returns the schema for the OCR converter +func (ocr *OCR) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} + +// === Video === + +// Make creates a new Video converter +func (video *Video) Make(option *kbtypes.ProviderOption) (types.Converter, error) { + // TODO: Map kbtypes.ProviderOption to converter.VideoOption + videoOption := converter.VideoOption{ + // AudioConverter: nil, // TODO: Get audio converter from option + // VisionConverter: nil, // TODO: Get vision converter from option + // KeyframeInterval: 0, // Will use default + // MaxKeyframes: 0, // Will use default + // TempDir: "", // Will use default + // CleanupTemp: false, + // MaxConcurrency: 0, // Will use default + // TextOptimization: false, + // DeduplicationRatio: 0, // Will use default + } + return converter.NewVideo(videoOption) +} + +// Schema returns the schema for the Video converter +func (video *Video) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} + +// === Whisper === + +// Make creates a new Whisper converter +func (whisper *Whisper) Make(option *kbtypes.ProviderOption) (types.Converter, error) { + // TODO: Map kbtypes.ProviderOption to converter.WhisperOption + whisperOption := converter.WhisperOption{ + // ConnectorName: "", // TODO: Get connector name from option + // Model: "", // Will use default + // Options: nil, + // Language: "", // Will use default + // ChunkDuration: 0, // Will use default + // MappingDuration: 0, // Will use default + // SilenceThreshold: 0, // Will use default + // SilenceMinLength: 0, // Will use default + // EnableSilenceDetection: false, + // MaxConcurrency: 0, // Will use default + // TempDir: "", // Will use default + // CleanupTemp: false, + } + return converter.NewWhisper(whisperOption) +} + +// Schema returns the schema for the Whisper converter +func (whisper *Whisper) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} + +// === Vision === + +// Make creates a new Vision converter +func (vision *Vision) Make(option *kbtypes.ProviderOption) (types.Converter, error) { + // TODO: Map kbtypes.ProviderOption to converter.VisionOption + visionOption := converter.VisionOption{ + // ConnectorName: "", // TODO: Get connector name from option + // Model: "", // Will use default + // Prompt: "", // Will use default + // Options: nil, + // CompressSize: 0, // Will use default + // Language: "", // Will use default + } + return converter.NewVision(visionOption) +} + +// Schema returns the schema for the Vision converter +func (vision *Vision) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} + +// === MCP === + +// Make creates a new MCP converter +func (mcp *MCP) Make(option *kbtypes.ProviderOption) (types.Converter, error) { + // TODO: Map kbtypes.ProviderOption to converter.MCPOptions + mcpOptions := &converter.MCPOptions{ + // ID: "", // TODO: Get ID from option + // Tool: "", // TODO: Get tool from option + // ArgumentsMapping: nil, // TODO: Get arguments mapping from option + // ResultMapping: nil, // TODO: Get result mapping from option + // NotificationMapping: nil, // TODO: Get notification mapping from option + } + return converter.NewMCP(mcpOptions) +} + +// Schema returns the schema for the MCP converter +func (mcp *MCP) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} diff --git a/kb/providers/embedding.go b/kb/providers/embedding.go new file mode 100644 index 00000000..23a2e965 --- /dev/null +++ b/kb/providers/embedding.go @@ -0,0 +1,43 @@ +package providers + +import ( + "github.com/yaoapp/gou/graphrag/embedding" + "github.com/yaoapp/gou/graphrag/types" + "github.com/yaoapp/yao/kb/providers/factory" + kbtypes "github.com/yaoapp/yao/kb/types" +) + +// OpenAI is an embedding provider +type OpenAI struct{} + +// Fastembed is an embedding provider +type Fastembed struct{} + +func init() { + factory.Embeddings["__yao.openai"] = &OpenAI{} + factory.Embeddings["__yao.fastembed"] = &Fastembed{} +} + +// === OpenAI === + +// Make creates an OpenAI embedding provider +func (o *OpenAI) Make(option *kbtypes.ProviderOption) (types.Embedding, error) { + return embedding.NewOpenai(embedding.OpenaiOptions{}) +} + +// Schema returns the schema for the OpenAI embedding provider +func (o *OpenAI) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} + +// === Fastembed === + +// Make creates a Fastembed embedding provider +func (f *Fastembed) Make(option *kbtypes.ProviderOption) (types.Embedding, error) { + return embedding.NewFastEmbed(embedding.FastEmbedOptions{}) +} + +// Schema returns the schema for the Fastembed embedding provider +func (f *Fastembed) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} diff --git a/kb/providers/extractor.go b/kb/providers/extractor.go new file mode 100644 index 00000000..497aecb1 --- /dev/null +++ b/kb/providers/extractor.go @@ -0,0 +1,41 @@ +package providers + +import ( + "github.com/yaoapp/gou/graphrag/extraction/openai" + "github.com/yaoapp/gou/graphrag/types" + "github.com/yaoapp/yao/kb/providers/factory" + kbtypes "github.com/yaoapp/yao/kb/types" +) + +// ExtractorOpenAI is an extractor provider for entity and relationship extraction +type ExtractorOpenAI struct{} + +// AutoRegister registers the extractor providers +func init() { + factory.Extractors["__yao.openai"] = &ExtractorOpenAI{} +} + +// === ExtractorOpenAI === + +// Make creates a new OpenAI extractor +func (e *ExtractorOpenAI) Make(option *kbtypes.ProviderOption) (types.Extraction, error) { + // TODO: Map kbtypes.ProviderOption to openai.Options + openaiOptions := openai.Options{ + // ConnectorName: "", // TODO: Get connector name from option + // Concurrent: 0, // Will use default + // Model: "", // Will use default + // Temperature: 0, // Will use default + // MaxTokens: 0, // Will use default + // Prompt: "", // Will use default + // Toolcall: nil, // Will use default + // Tools: nil, // Will use default + // RetryAttempts: 0, // Will use default + // RetryDelay: 0, // Will use default + } + return openai.NewOpenai(openaiOptions) +} + +// Schema returns the schema for the OpenAI extractor +func (e *ExtractorOpenAI) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} diff --git a/kb/providers/factory/factory.go b/kb/providers/factory/factory.go new file mode 100644 index 00000000..c7d83f5e --- /dev/null +++ b/kb/providers/factory/factory.go @@ -0,0 +1,151 @@ +package factory + +import ( + "fmt" + + "github.com/yaoapp/gou/graphrag/types" + kbtypes "github.com/yaoapp/yao/kb/types" +) + +// ProviderType is a type for provider types +type ProviderType string + +const ( + // ProviderTypeChunking is a type for chunking providers + ProviderTypeChunking ProviderType = "chunking" + // ProviderTypeConverter is a type for converter providers + ProviderTypeConverter ProviderType = "converter" + // ProviderTypeEmbedding is a type for embedding providers + ProviderTypeEmbedding ProviderType = "embedding" + // ProviderTypeExtractor is a type for extractor providers + ProviderTypeExtractor ProviderType = "extractor" + // ProviderTypeFetcher is a type for fetcher providers + ProviderTypeFetcher ProviderType = "fetcher" +) + +// DetectMatch is a match for auto detect +type DetectMatch struct { + ID string + Priority int +} + +// Chunkings is a map of chunking providers +var Chunkings = map[string]Chunking{} + +// Converters is a map of converter providers +var Converters = map[string]Converter{} + +// Embeddings is a map of embedding providers +var Embeddings = map[string]Embedding{} + +// Extractors is a map of extractor providers +var Extractors = map[string]Extractor{} + +// Fetchers is a map of fetcher providers +var Fetchers = map[string]Fetcher{} + +// === Chunking API === + +// MakeChunking creates a new chunking provider +func MakeChunking(id string, option *kbtypes.ProviderOption) (types.Chunking, error) { + chunking, ok := Chunkings[id] + if !ok { + return nil, fmt.Errorf("chunking provider %s not found", id) + } + return chunking.Make(option) +} + +// ChunkingOptions returns the options for a chunking provider +func ChunkingOptions(id string, option *kbtypes.ProviderOption) (*types.ChunkingOptions, error) { + chunking, ok := Chunkings[id] + if !ok { + return nil, fmt.Errorf("chunking provider %s not found", id) + } + return chunking.Options(option) +} + +// === Converter API === + +// MakeConverter creates a new converter provider +func MakeConverter(id string, option *kbtypes.ProviderOption) (types.Converter, error) { + converter, ok := Converters[id] + if !ok { + return nil, fmt.Errorf("converter provider %s not found", id) + } + return converter.Make(option) +} + +// AutoDetectConverter detects the converter based on the filename and content types +// return matched, id, error +func AutoDetectConverter(filename, contentTypes string) (bool, string, error) { + var highestPriority int = 0 + var highestID string = "" + for id, converter := range Converters { + ok, priority, err := converter.AutoDetect(filename, contentTypes) + if err != nil { + continue + } + if ok && priority > highestPriority { + highestPriority = priority + highestID = id + } + } + return highestID != "", highestID, nil +} + +// === Embedding API === + +// MakeEmbedding creates a new embedding provider +func MakeEmbedding(id string, option *kbtypes.ProviderOption) (types.Embedding, error) { + embedding, ok := Embeddings[id] + if !ok { + return nil, fmt.Errorf("embedding provider %s not found", id) + } + return embedding.Make(option) +} + +// === Extractor API === + +// MakeExtractor creates a new extractor provider +func MakeExtractor(id string, option *kbtypes.ProviderOption) (types.Extraction, error) { + extractor, ok := Extractors[id] + if !ok { + return nil, fmt.Errorf("extractor provider %s not found", id) + } + return extractor.Make(option) +} + +// === Fetcher API === + +// MakeFetcher creates a new fetcher provider +func MakeFetcher(id string, option *kbtypes.ProviderOption) (types.Fetcher, error) { + fetcher, ok := Fetchers[id] + if !ok { + return nil, fmt.Errorf("fetcher provider %s not found", id) + } + return fetcher.Make(option) +} + +// === Schema API === + +// GetSchema returns the schema for a provider +func GetSchema(typ ProviderType, provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + var schema Schema = nil + var exists bool = false + switch typ { + case ProviderTypeChunking: + schema, exists = Chunkings[provider.ID] + case ProviderTypeConverter: + schema, exists = Converters[provider.ID] + case ProviderTypeEmbedding: + schema, exists = Embeddings[provider.ID] + case ProviderTypeExtractor: + schema, exists = Extractors[provider.ID] + case ProviderTypeFetcher: + schema, exists = Fetchers[provider.ID] + } + if !exists { + return nil, fmt.Errorf("%s provider %s not found", typ, provider.ID) + } + return schema.Schema(provider) +} diff --git a/kb/providers/factory/interfaces.go b/kb/providers/factory/interfaces.go new file mode 100644 index 00000000..8effcdaa --- /dev/null +++ b/kb/providers/factory/interfaces.go @@ -0,0 +1,43 @@ +package factory + +import ( + "github.com/yaoapp/gou/graphrag/types" + kbtypes "github.com/yaoapp/yao/kb/types" +) + +// Chunking is a factory for chunking providers +type Chunking interface { + Make(option *kbtypes.ProviderOption) (types.Chunking, error) + Options(option *kbtypes.ProviderOption) (*types.ChunkingOptions, error) + Schema +} + +// Converter is a factory for converter providers +type Converter interface { + Make(option *kbtypes.ProviderOption) (types.Converter, error) + AutoDetect(filename, contentTypes string) (bool, int, error) + Schema +} + +// Embedding is a factory for embedding providers +type Embedding interface { + Make(options *kbtypes.ProviderOption) (types.Embedding, error) + Schema +} + +// Extractor is a factory for extractor providers +type Extractor interface { + Make(option *kbtypes.ProviderOption) (types.Extraction, error) + Schema +} + +// Fetcher is a factory for fetcher providers +type Fetcher interface { + Make(option *kbtypes.ProviderOption) (types.Fetcher, error) + Schema +} + +// Schema interface for providers +type Schema interface { + Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) +} diff --git a/kb/providers/fetcher.go b/kb/providers/fetcher.go new file mode 100644 index 00000000..0530b5dc --- /dev/null +++ b/kb/providers/fetcher.go @@ -0,0 +1,58 @@ +package providers + +import ( + "github.com/yaoapp/gou/graphrag/fetcher" + "github.com/yaoapp/gou/graphrag/types" + "github.com/yaoapp/yao/kb/providers/factory" + kbtypes "github.com/yaoapp/yao/kb/types" +) + +// FetcherHTTP is a fetcher provider for HTTP/HTTPS URLs +type FetcherHTTP struct{} + +// FetcherMCP is a fetcher provider for MCP-based URL fetching +type FetcherMCP struct{} + +// AutoRegister registers the fetcher providers +func init() { + factory.Fetchers["__yao.http"] = &FetcherHTTP{} + factory.Fetchers["__yao.mcp"] = &FetcherMCP{} +} + +// === FetcherHTTP === + +// Make creates a new HTTP fetcher +func (f *FetcherHTTP) Make(option *kbtypes.ProviderOption) (types.Fetcher, error) { + // TODO: Map kbtypes.ProviderOption to fetcher.HTTPOptions + httpOptions := &fetcher.HTTPOptions{ + // Headers: nil, // TODO: Get headers from option + // UserAgent: "", // Will use default + // Timeout: 0, // Will use default + } + return fetcher.NewHTTPFetcher(httpOptions), nil +} + +// Schema returns the schema for the HTTP fetcher +func (f *FetcherHTTP) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} + +// === FetcherMCP === + +// Make creates a new MCP fetcher +func (f *FetcherMCP) Make(option *kbtypes.ProviderOption) (types.Fetcher, error) { + // TODO: Map kbtypes.ProviderOption to fetcher.MCPOptions + mcpOptions := &fetcher.MCPOptions{ + // ID: "", // TODO: Get ID from option + // Tool: "", // TODO: Get tool from option + // ArgumentsMapping: nil, // TODO: Get arguments mapping from option + // ResultMapping: nil, // TODO: Get result mapping from option + // NotificationMapping: nil, // TODO: Get notification mapping from option + } + return fetcher.NewMCP(mcpOptions) +} + +// Schema returns the schema for the MCP fetcher +func (f *FetcherMCP) Schema(provider *kbtypes.Provider) (*kbtypes.ProviderSchema, error) { + return nil, nil +} diff --git a/kb/config.go b/kb/types/config.go similarity index 99% rename from kb/config.go rename to kb/types/config.go index f5fcf701..c141a207 100644 --- a/kb/config.go +++ b/kb/types/config.go @@ -1,4 +1,4 @@ -package kb +package types import ( "encoding/json" diff --git a/kb/config_test.go b/kb/types/config_test.go similarity index 99% rename from kb/config_test.go rename to kb/types/config_test.go index 1a28a5d0..d2121e8c 100644 --- a/kb/config_test.go +++ b/kb/types/config_test.go @@ -1,4 +1,4 @@ -package kb +package types import ( "encoding/json" diff --git a/kb/types/provider.go b/kb/types/provider.go new file mode 100644 index 00000000..3257c7c0 --- /dev/null +++ b/kb/types/provider.go @@ -0,0 +1,43 @@ +package types + +import jsoniter "github.com/json-iterator/go" + +// GetOption returns the option for a provider +func (p *Provider) GetOption(id string) (*ProviderOption, bool) { + if p.Options == nil { + return nil, false + } + + // Find the option by id + for _, option := range p.Options { + if option.Value == id { + return option, true + } + } + + return nil, false +} + +// GetOptionByIndex returns the option by index +func (p *Provider) GetOptionByIndex(index int) (*ProviderOption, bool) { + if len(p.Options) <= index { + return nil, false + } + return p.Options[index], true +} + +// Parse parses the provider option +func (p *ProviderOption) Parse(v interface{}) error { + + raw, err := jsoniter.Marshal(p) + if err != nil { + return err + } + + err = jsoniter.Unmarshal(raw, v) + if err != nil { + return err + } + + return nil +} diff --git a/kb/types.go b/kb/types/types.go similarity index 99% rename from kb/types.go rename to kb/types/types.go index a4018ce1..2cd94ce8 100644 --- a/kb/types.go +++ b/kb/types/types.go @@ -1,4 +1,4 @@ -package kb +package types // Features represents the available features based on current configuration type Features struct {