-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathingestion_usecase.go
More file actions
191 lines (159 loc) · 6.65 KB
/
Copy pathingestion_usecase.go
File metadata and controls
191 lines (159 loc) · 6.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package usecase
import (
"context"
"fmt"
"log"
"path/filepath"
"strings"
"github.com/tmc/langchaingo/schema"
)
type IngestionUseCase struct {
loader DocumentLoader
splitter TextSplitter
embedder EmbeddingGenerator
store VectorStore
}
func NewIngestionUseCase(l DocumentLoader, s TextSplitter, e EmbeddingGenerator, vs VectorStore) *IngestionUseCase {
return &IngestionUseCase{
loader: l,
splitter: s,
embedder: e,
store: vs,
}
}
func (uc *IngestionUseCase) Execute(ctx context.Context, dirPath, filePattern, collectionName string, vectorSize int) error {
log.Printf("Starting ingestion process for directory: %s, pattern: %s", dirPath, filePattern)
log.Printf("Ensuring collection '%s' exists with vector size %d...", collectionName, vectorSize)
if err := uc.store.DeleteCollection(ctx, collectionName); err != nil {
log.Printf("Warning: Failed to delete collection '%s': %v", collectionName, err)
}
if err := uc.store.EnsureCollection(ctx, collectionName, vectorSize); err != nil {
return fmt.Errorf("failed to ensure collection '%s': %w", collectionName, err)
}
log.Printf("Collection '%s' ensured.", collectionName)
files, err := filepath.Glob(filepath.Join(dirPath, filePattern))
if err != nil {
return fmt.Errorf("failed to list files in '%s' with pattern '%s': %w", dirPath, filePattern, err)
}
if len(files) == 0 {
return fmt.Errorf("no files found matching pattern '%s' in directory '%s'", filePattern, dirPath)
}
log.Printf("Found %d files to process.", len(files))
var allDocs []schema.Document
var allTexts []string
for _, filePath := range files {
log.Printf("Processing file: %s", filePath)
docs, err := uc.loader.Load(ctx, filePath)
if err != nil {
log.Printf("Warning: Failed to load file %s: %v. Skipping.", filePath, err)
continue
}
splittedDocs, err := uc.splitter.SplitDocuments(ctx, docs)
if err != nil {
log.Printf("Warning: Failed to split documents from file %s: %v. Skipping.", filePath, err)
continue
}
for _, doc := range splittedDocs {
allDocs = append(allDocs, doc)
allTexts = append(allTexts, doc.PageContent)
}
log.Printf("Loaded and split %d documents from %s", len(splittedDocs), filePath)
}
if len(allDocs) == 0 {
return fmt.Errorf("no documents were successfully loaded and split from any files")
}
log.Printf("Total documents to embed and add: %d", len(allDocs))
log.Println("Generating embeddings for all documents...")
embeddings, err := uc.embedder.EmbedDocuments(ctx, allTexts)
if err != nil {
return fmt.Errorf("failed to generate embeddings: %w", err)
}
log.Printf("Generated %d embeddings.", len(embeddings))
log.Printf("Adding %d documents with embeddings to collection '%s'...", len(allDocs), collectionName)
ids, err := uc.store.AddDocuments(ctx, collectionName, allDocs, embeddings)
if err != nil {
return fmt.Errorf("failed to add documents to vector store: %w", err)
}
log.Printf("Successfully added %d documents to collection '%s'. Ingestion complete.", len(ids), collectionName)
return nil
}
// ExecutePerPDF executa o processo de ingestão criando uma coleção para cada arquivo PDF
func (uc *IngestionUseCase) ExecutePerPDF(ctx context.Context, dirPath, filePattern string, vectorSize int) error {
log.Printf("Starting per-PDF ingestion for directory: %s, pattern: %s", dirPath, filePattern)
files, err := filepath.Glob(filepath.Join(dirPath, filePattern))
if err != nil {
return fmt.Errorf("failed to list files in '%s' with pattern '%s': %w", dirPath, filePattern, err)
}
if len(files) == 0 {
return fmt.Errorf("no files found matching pattern '%s' in directory '%s'", filePattern, dirPath)
}
log.Printf("Found %d files to process.", len(files))
for _, filePath := range files {
// Obter nome do arquivo sem extensão para usar como nome da coleção
fileName := filepath.Base(filePath)
fileNameWithoutExt := strings.TrimSuffix(fileName, filepath.Ext(fileName))
// Sanitizar o nome da coleção (remover caracteres inválidos)
collectionName := sanitizeCollectionName(fileNameWithoutExt)
log.Printf("Processing file: %s -> collection: %s", filePath, collectionName)
// Garantir que a coleção exista
log.Printf("Ensuring collection '%s' exists with vector size %d...", collectionName, vectorSize)
if err := uc.store.DeleteCollection(ctx, collectionName); err != nil {
log.Printf("Warning: Failed to delete collection '%s': %v", collectionName, err)
}
if err := uc.store.EnsureCollection(ctx, collectionName, vectorSize); err != nil {
log.Printf("Warning: Failed to ensure collection '%s': %v. Skipping file.", collectionName, err)
continue
}
// Carregar e dividir o documento
docs, err := uc.loader.Load(ctx, filePath)
if err != nil {
log.Printf("Warning: Failed to load file %s: %v. Skipping.", filePath, err)
continue
}
splittedDocs, err := uc.splitter.SplitDocuments(ctx, docs)
if err != nil {
log.Printf("Warning: Failed to split documents from file %s: %v. Skipping.", filePath, err)
continue
}
if len(splittedDocs) == 0 {
log.Printf("No documents were successfully split from file %s. Skipping.", filePath)
continue
}
// Extrair textos para embedding
var texts []string
for _, doc := range splittedDocs {
texts = append(texts, doc.PageContent)
}
log.Printf("Generating embeddings for %d chunks from %s...", len(texts), filePath)
embeddings, err := uc.embedder.EmbedDocuments(ctx, texts)
if err != nil {
log.Printf("Warning: Failed to generate embeddings for %s: %v. Skipping.", filePath, err)
continue
}
// Adicionar documentos com embeddings à coleção específica
log.Printf("Adding %d documents with embeddings to collection '%s'...", len(splittedDocs), collectionName)
ids, err := uc.store.AddDocuments(ctx, collectionName, splittedDocs, embeddings)
if err != nil {
log.Printf("Warning: Failed to add documents to collection '%s': %v", collectionName, err)
continue
}
log.Printf("Successfully added %d documents to collection '%s' from file %s", len(ids), collectionName, filePath)
}
log.Printf("Per-PDF ingestion complete for all files.")
return nil
}
// sanitizeCollectionName sanitiza o nome do arquivo para ser usado como nome de coleção
func sanitizeCollectionName(name string) string {
// Substituir espaços, pontos e outros caracteres por underscores
name = strings.ReplaceAll(name, " ", "_")
name = strings.ReplaceAll(name, ".", "_")
name = strings.ReplaceAll(name, "-", "_")
// Remover caracteres especiais
var result strings.Builder
for _, char := range name {
if (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9') || char == '_' {
result.WriteRune(char)
}
}
return strings.ToLower(result.String())
}