diff --git a/install.sh b/install.sh index c42a4a2..094e13d 100755 --- a/install.sh +++ b/install.sh @@ -213,9 +213,20 @@ case "$AI_CHOICE" in sleep 2 done info "Pulling model $AI_MODEL (this may take a while)..." - # Pull explicitly via the API URL so it works regardless of which user - # runs the command (the Ollama service listens on 127.0.0.1:11434) - sudo_if sh -c "OLLAMA_HOST=http://127.0.0.1:11434 ollama pull $AI_MODEL" 2>&1 | tail -3 + # Pull via the API URL so it works regardless of which user runs it + OLLAMA_HOST="http://127.0.0.1:11434" + export OLLAMA_HOST + if id -u ollama &>/dev/null; then + sudo -u ollama sh -c "OLLAMA_HOST=$OLLAMA_HOST ollama pull $AI_MODEL" 2>&1 | tail -3 + else + ollama pull "$AI_MODEL" 2>&1 | tail -3 + fi + # Warm-up: send a quick prompt to preload the model into memory + # so the first user request isn't delayed by model loading. + info "Warming up $AI_MODEL..." + curl -s --max-time 120 -X POST "$OLLAMA_HOST/api/chat" \ + -d "{\"model\":\"$AI_MODEL\",\"messages\":[{\"role\":\"user\",\"content\":\"say ok\"}],\"stream\":false,\"options\":{\"num_predict\":10}}" > /dev/null 2>&1 && \ + info "Model ready" || warn "Model warm-up timed out (will load on first use)" AI_BASE_URL="http://localhost:11434" ;; *) diff --git a/internal/ai/ollama.go b/internal/ai/ollama.go index c69d73a..c4b28fa 100644 --- a/internal/ai/ollama.go +++ b/internal/ai/ollama.go @@ -36,7 +36,8 @@ type ollamaMessage struct { type ollamaResponse struct { Message struct { - Content string `json:"content"` + Content string `json:"content"` + Thinking string `json:"thinking"` } `json:"message"` Error string `json:"error,omitempty"` } @@ -106,7 +107,11 @@ func (p *ollamaProvider) ExtractReceipt(imagePath string) (*ReceiptData, error) return &ReceiptData{}, fmt.Errorf("Ollama error: %s", apiResp.Error) } - contentStr := stripMarkdownFences(apiResp.Message.Content) + contentStr := apiResp.Message.Content + if contentStr == "" { + contentStr = apiResp.Message.Thinking + } + contentStr = stripMarkdownFences(contentStr) var receipt ReceiptData if err := json.Unmarshal([]byte(contentStr), &receipt); err != nil { return &ReceiptData{}, fmt.Errorf("parse JSON: %w (content: %s)", err, contentStr)