Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.git
ollama_storage
bin/
*.exe
13 changes: 12 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,15 @@ EMBEDDING_DIM=768
SERVER_ADDR=:8080
OLLAMA_ADDR=11434
MAX_MEMORY_DISTANCE=0.5
TOP_K_MEMORIES=10
TOP_K_MEMORIES=10

SUMMARIZATION_MODEL=deepseek-r1:1.5b
LLM_MODEL=deepseek-r1:1.5b
WEAVIATE_HOST=weaviate:8080
WEAVIATE_SCHEME=http

# Summarization settings
SUMMARY_THRESHOLD=2 # Trigger summarization after N memories
SUMMARY_BATCH_SIZE=2 # Number of memories to summarize at once
SUMMARY_MAX_AGE_DAYS=3000 # Only summarize memories older than this
ENABLE_AUTO_SUMMARY=true # Enable automatic summarization
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.env
.DS_Store
.DS_Store
ollama_storage/
11 changes: 8 additions & 3 deletions Dockerfile.ollama
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Base Ollama image
FROM ollama/ollama:latest

# Start the Ollama server by default
ENTRYPOINT ["ollama", "serve"]
# We'll use the default path during build
RUN ollama serve & \
sleep 5 && \
ollama pull nomic-embed-text && \
ollama pull deepseek-r1:1.5b && \
pkill ollama

ENTRYPOINT ["ollama", "serve"]
105 changes: 97 additions & 8 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
@@ -1,46 +1,135 @@
package main

import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"strconv"
"time"

"github.com/joho/godotenv"
"github.com/weaviate/weaviate-go-client/v4/weaviate"

wv "github.com/sobowalebukola/memcortex/internal/db/weaviate"
ollama "github.com/sobowalebukola/memcortex/internal/embedder"
"github.com/sobowalebukola/memcortex/internal/handlers"
"github.com/sobowalebukola/memcortex/internal/memory"
"github.com/sobowalebukola/memcortex/internal/middleware"
)

func main() {

err := godotenv.Load()
if err != nil {
log.Println("No .env file found, using system environment")
}

dimStr := os.Getenv("EMBEDDING_DIM")
if dimStr == "" {
dimStr = "768"

cfg := weaviate.Config{
Host: os.Getenv("WEAVIATE_HOST"),
Scheme: os.Getenv("WEAVIATE_SCHEME"),
}
if cfg.Host == "" {
cfg.Host = "weaviate:8080"
}
if cfg.Scheme == "" {
cfg.Scheme = "http"
}
dim, _ := strconv.Atoi(dimStr)

store, err := memory.NewStore("memory_idx", dim)
wClient, err := weaviate.NewClient(cfg)
if err != nil {
log.Fatalf("failed to create memory store: %v", err)
log.Fatalf("failed to create weaviate client: %v", err)
}


wv.EnsureSchema(wClient)


emb := ollama.NewEmbeddingClient(os.Getenv("EMBEDDING_MODEL"))


store := memory.NewWeaviateStore(wClient, "Memory_idx")


m := memory.NewManager(store, emb)

log.Println("MemCortex initialized successfully!")
log.Println("MemCortex initialized with Weaviate successfully!")


chatHandler := handlers.NewChatHandler(m)
mw := &middleware.MemoryMiddleware{Manager: m}

mux := http.NewServeMux()


mux.Handle("/chat", mw.Handler(chatHandler))


mux.HandleFunc("/api/summarize", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}

userID := r.Header.Get("X-User-ID")
if userID == "" {
http.Error(w, "Missing X-User-ID header", http.StatusBadRequest)
return
}


if err := m.SummarizeUserMemories(r.Context(), userID); err != nil {
http.Error(w, fmt.Sprintf("Summarization failed: %v", err), http.StatusInternalServerError)
return
}

w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"status": "summarization completed"})
})

mux.HandleFunc("/api/register", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}

var req struct {
Username string `json:"username"`
Bio string `json:"bio"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid body", http.StatusBadRequest)
return
}


newID := fmt.Sprintf("u-%d", time.Now().Unix())


_, err := wClient.Data().Creator().
WithClassName("User").
WithProperties(map[string]interface{}{
"username": req.Username,
"userId": newID,
"bio": req.Bio,
"createdAt": time.Now().Format(time.RFC3339),
}).Do(r.Context())

if err != nil {
log.Printf("Error saving user: %v", err)
http.Error(w, "Failed to register", http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"user_id": newID,
"status": "Registration successful!",
})
})


addr := os.Getenv("SERVER_ADDR")
if addr == "" {
addr = ":8080"
Expand Down
25 changes: 17 additions & 8 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
services:
ollama:
build:
context: .
dockerfile: Dockerfile.ollama
image: ollama/ollama:latest
container_name: ollama
ports:
- "${OLLAMA_ADDR}:11434"
- "11434:11434"
restart: unless-stopped
entrypoint: ["/bin/sh", "-c"]
command: >
Expand All @@ -14,12 +12,15 @@ services:
ollama pull ${EMBEDDING_MODEL} &&
wait"
volumes:
- /root/.ollama
- ./ollama_storage:/root/.ollama
healthcheck:
test: ["CMD", "ollama", "list"]
interval: 10s
timeout: 5s
retries: 5
retries: 10
start_period: 60s



weaviate:
image: semitechnologies/weaviate:1.25.3
Expand All @@ -34,7 +35,7 @@ services:
DEFAULT_VECTORIZER_MODULE: "none"
CLUSTER_HOSTNAME: "node1"
volumes:
- /var/lib/weaviate
- weaviate_data:/var/lib/weaviate
restart: unless-stopped
go-server:
build:
Expand All @@ -43,13 +44,21 @@ services:
container_name: go-server
ports:
- "${SERVER_ADDR}:8080"
env_file:
- .env
environment:
- OLLAMA_HOST=http://ollama:11434
- EMBEDDING_MODEL=nomic-embed-text
- WEAVIATE_HOST=http://weaviate:8080
- SUMMARIZATION_MODEL=deepseek-r1:1.5b
- LLM_MODEL=deepseek-r1:1.5b
- WEAVIATE_HOST=weaviate:8080
- SUMMARY_THRESHOLD=5
- SUMMARY_BATCH_SIZE=2
depends_on:
ollama:
condition: service_healthy
weaviate:
condition: service_started
restart: unless-stopped
volumes:
weaviate_data:
Loading