fix: qwen3.5 reasoning model outputs to thinking field not content

- ollamaResponse now reads both content and thinking fields
- Falls back to thinking if content is empty
- Install script adds model warm-up prompt to preload into memory
- Warm-up uses OLLAMA_HOST for correct user context
- Makes first real receipt analysis faster
This commit is contained in:
Claus Lohmar 2026-05-30 16:51:43 +00:00
parent 59f73830fb
commit 1eca4ae777
2 changed files with 21 additions and 5 deletions

View file

@ -213,9 +213,20 @@ case "$AI_CHOICE" in
sleep 2 sleep 2
done done
info "Pulling model $AI_MODEL (this may take a while)..." info "Pulling model $AI_MODEL (this may take a while)..."
# Pull explicitly via the API URL so it works regardless of which user # Pull via the API URL so it works regardless of which user runs it
# runs the command (the Ollama service listens on 127.0.0.1:11434) OLLAMA_HOST="http://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 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" AI_BASE_URL="http://localhost:11434"
;; ;;
*) *)

View file

@ -37,6 +37,7 @@ type ollamaMessage struct {
type ollamaResponse struct { type ollamaResponse struct {
Message struct { Message struct {
Content string `json:"content"` Content string `json:"content"`
Thinking string `json:"thinking"`
} `json:"message"` } `json:"message"`
Error string `json:"error,omitempty"` 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) 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 var receipt ReceiptData
if err := json.Unmarshal([]byte(contentStr), &receipt); err != nil { if err := json.Unmarshal([]byte(contentStr), &receipt); err != nil {
return &ReceiptData{}, fmt.Errorf("parse JSON: %w (content: %s)", err, contentStr) return &ReceiptData{}, fmt.Errorf("parse JSON: %w (content: %s)", err, contentStr)