-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy pathmain.go
More file actions
194 lines (168 loc) · 5.58 KB
/
main.go
File metadata and controls
194 lines (168 loc) · 5.58 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
192
193
194
package main
import (
"context"
"flag"
"fmt"
"os"
"path/filepath"
"runtime"
"time"
"github.com/kataras/golog"
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
"github.com/smallnest/notex/backend"
)
var Version = "1.0.0"
func main() {
// Command line flags
serverMode := flag.Bool("server", false, "Run in HTTP server mode")
ingestFile := flag.String("ingest", "", "Path to a file to ingest")
notebookName := flag.String("notebook", "", "Notebook name (for ingest)")
version := flag.Bool("version", false, "Show version information")
flag.Parse()
if *version {
fmt.Printf("Notex v%s\n", Version)
fmt.Println("A privacy-first, open-source alternative to NotebookLM")
fmt.Println("Powered by LangGraphGo")
os.Exit(0)
}
defer func() {
if err := recover(); err != nil {
golog.Error("recover:", err)
buf := make([]byte, 8192)
n := runtime.Stack(buf, true)
golog.Error("stack:", string(buf[:n]))
}
}()
golog.SetTimeFormat("2006/01/02 15:04:05.000")
logFiles := "./logs/notex.log.%Y%m%d"
w, err := rotatelogs.New(
logFiles,
rotatelogs.WithLinkName("./logs/notex.log"),
rotatelogs.WithMaxAge(7*24*time.Hour),
rotatelogs.WithRotationTime(24*time.Hour))
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create log file: %v\n", err)
os.Exit(1)
}
defer w.Close()
golog.SetOutput(w)
// Load and validate configuration
cfg := backend.LoadConfig()
if err := backend.ValidateConfig(cfg); err != nil {
fmt.Fprintf(os.Stderr, "\n❌ Configuration Error:\n\n%v\n\n", err)
fmt.Fprintf(os.Stderr, "Required environment variables:\n")
fmt.Fprintf(os.Stderr, " - OPENAI_API_KEY (for OpenAI) or\n")
fmt.Fprintf(os.Stderr, " - OLLAMA_BASE_URL (for local Ollama)\n\n")
fmt.Fprintf(os.Stderr, "Optional:\n")
fmt.Fprintf(os.Stderr, " - VECTOR_STORE_TYPE (default: sqlite)\n")
fmt.Fprintf(os.Stderr, " - STORE_PATH (default: ./data/checkpoints.db)\n")
fmt.Fprintf(os.Stderr, " - SERVER_PORT (default: 8080)\n\n")
os.Exit(1)
}
ctx := context.Background()
switch {
case *serverMode:
// Server mode
runServerMode(cfg)
case *ingestFile != "":
// Ingest mode
if *notebookName == "" {
*notebookName = "Default Notebook"
}
runIngestMode(ctx, cfg, *ingestFile, *notebookName)
default:
printUsage()
}
}
func runServerMode(cfg backend.Config) {
server, err := backend.NewServer(cfg)
if err != nil {
fmt.Fprintf(os.Stderr, "\n❌ Failed to create server: %v\n", err)
os.Exit(1)
}
fmt.Printf("\n✅ Notex v%s\n", Version)
fmt.Printf("📡 Server: http://%s:%s\n", cfg.ServerHost, cfg.ServerPort)
fmt.Printf("🤖 LLM: %s\n", cfg.OpenAIModel)
fmt.Printf("📦 Vector Store: %s\n\n", cfg.VectorStoreType)
if err := server.Start(); err != nil {
fmt.Fprintf(os.Stderr, "\n❌ Server error: %v\n", err)
os.Exit(1)
}
}
func runIngestMode(ctx context.Context, cfg backend.Config, filePath, notebookName string) {
golog.Infof("📂 ingesting file: %s...", filePath)
// Initialize vector store
vectorStore, err := backend.NewVectorStore(cfg)
if err != nil {
golog.Fatalf("failed to initialize vector store: %v", err)
}
// Initialize store
store, err := backend.NewStore(cfg)
if err != nil {
golog.Fatalf("failed to initialize store: %v", err)
}
// Create or get notebook
notebooks, _ := store.ListNotebooks(ctx, "")
var notebookID string
for _, nb := range notebooks {
if nb.Name == notebookName {
notebookID = nb.ID
break
}
}
if notebookID == "" {
nb, err := store.CreateNotebook(ctx, "", notebookName, "Created by ingest mode", nil)
if err != nil {
golog.Fatalf("failed to create notebook: %v", err)
}
notebookID = nb.ID
golog.Infof("📓 created notebook: %s", notebookName)
}
// Extract content
content, err := vectorStore.ExtractDocument(ctx, filePath)
if err != nil {
golog.Fatalf("extraction failed: %v", err)
}
// Create source in database
fileInfo, _ := os.Stat(filePath)
source := &backend.Source{
NotebookID: notebookID,
Name: filepath.Base(filePath),
Type: "file",
FileName: filepath.Base(filePath),
FileSize: fileInfo.Size(),
Content: content,
Metadata: map[string]interface{}{"path": filePath},
}
if err := store.CreateSource(ctx, source); err != nil {
golog.Fatalf("failed to create source: %v", err)
}
// Ingest document
if _, err := vectorStore.IngestText(ctx, notebookID, source.Name, content); err != nil {
golog.Fatalf("ingestion failed: %v", err)
}
golog.Infof("✅ ingestion complete!")
golog.Infof("📓 notebook: %s (ID: %s)", notebookName, notebookID)
}
func printUsage() {
fmt.Println("Notex - Privacy-first AI notebook")
fmt.Println("\nUsage:")
fmt.Println(" notex [options]")
fmt.Println("\nOptions:")
fmt.Println(" -server Start the web server")
fmt.Println(" -ingest <file> Ingest a file into the vector store")
fmt.Println(" -notebook <name> Notebook name for ingest (default: 'Default Notebook')")
fmt.Println(" -version Show version information")
fmt.Println("\nExamples:")
fmt.Println(" # Start web server")
fmt.Println(" notex -server")
fmt.Println("\n # Ingest a file")
fmt.Println(" notex -ingest document.pdf -notebook 'My Notes'")
fmt.Println("\nEnvironment Variables:")
fmt.Println(" OPENAI_API_KEY Your OpenAI API key")
fmt.Println(" OLLAMA_BASE_URL Ollama server URL (default: http://localhost:11434)")
fmt.Println(" OPENAI_MODEL Model name (default: gpt-4o-mini)")
fmt.Println(" VECTOR_STORE_TYPE Vector store type (default: sqlite)")
fmt.Println(" SERVER_PORT Server port (default: 8080)")
fmt.Println("\nFor more information, visit: https://github.com/smallnest/langgraphgo")
}