110 lines
4.1 KiB
Go
110 lines
4.1 KiB
Go
package engine
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/local/glpi-neural-brain/internal/model"
|
|
"github.com/local/glpi-neural-brain/internal/research"
|
|
)
|
|
|
|
type ResearchTestResult struct {
|
|
OK bool `json:"ok"`
|
|
Query string `json:"query"`
|
|
Diagnostic research.Diagnostic `json:"diagnostic"`
|
|
Results []model.ResearchResult `json:"results"`
|
|
}
|
|
|
|
func (e *Engine) ResearchStatus() research.Diagnostic {
|
|
if e == nil || e.Research == nil {
|
|
return research.Diagnostic{Configured: false, OK: false, ErrorKind: "not_configured", Error: "SearXNG ist nicht konfiguriert"}
|
|
}
|
|
status := e.Research.Status()
|
|
if !e.ResearchEnabledForRuntime() {
|
|
status.OK = false
|
|
status.ErrorKind = "disabled"
|
|
status.Error = "BRAIN_RESEARCH_ENABLED und Autonomous Research sind deaktiviert"
|
|
}
|
|
return status
|
|
}
|
|
|
|
func (e *Engine) TestResearch(ctx context.Context, query string, limit int) (ResearchTestResult, error) {
|
|
query = sanitizeSearchQuerySiteFilters(strings.TrimSpace(query))
|
|
if query == "" {
|
|
query = "Btrfs Snapshots und ZFS History Unterschiede Timeline"
|
|
}
|
|
if limit < 1 {
|
|
limit = 4
|
|
}
|
|
if limit > 10 {
|
|
limit = 10
|
|
}
|
|
if !e.ResearchEnabledForRuntime() {
|
|
err := errors.New("SearXNG-Recherche ist deaktiviert")
|
|
return ResearchTestResult{Query: query, Diagnostic: e.ResearchStatus()}, err
|
|
}
|
|
if e.Research == nil {
|
|
err := errors.New("SearXNG-Client ist nicht konfiguriert")
|
|
return ResearchTestResult{Query: query, Diagnostic: e.ResearchStatus()}, err
|
|
}
|
|
|
|
researchID := newResearchRunID("research-test", query)
|
|
started := time.Now()
|
|
startMetadata := map[string]any{
|
|
"trigger": "diagnostic",
|
|
"research_id": researchID,
|
|
"research_query": query,
|
|
"animation_min_ms": 2000,
|
|
"test_only": true,
|
|
"searxng_base_url": e.Research.Status().BaseURL,
|
|
}
|
|
e.Broker.Publish(model.Activity{Type: "research.test.started", Source: "searxng", Phase: "diagnostic", Message: "SearXNG-Verbindung und JSON-Suche werden direkt getestet", Strength: .92, Metadata: startMetadata})
|
|
|
|
var results []model.ResearchResult
|
|
var diagnostic research.Diagnostic
|
|
err := e.withSharedResearchWork(ctx, "searxng.diagnostic", func() error {
|
|
var searchErr error
|
|
results, diagnostic, searchErr = e.Research.SearchDetailed(ctx, query, limit)
|
|
return searchErr
|
|
})
|
|
if err != nil {
|
|
metadata := mergeResearchMetadata(startMetadata, researchDiagnosticMetadata(diagnostic))
|
|
metadata["duration_ms"] = time.Since(started).Milliseconds()
|
|
metadata["error"] = err.Error()
|
|
slog.Warn("SearXNG diagnostic search failed", "base_url", diagnostic.BaseURL, "kind", diagnostic.ErrorKind, "duration_ms", diagnostic.DurationMS, "error", err)
|
|
e.Broker.Publish(model.Activity{Type: "research.test.failed", Source: "searxng", Phase: "diagnostic", Message: "SearXNG-Test fehlgeschlagen", Strength: .4, Metadata: metadata})
|
|
return ResearchTestResult{OK: false, Query: query, Diagnostic: diagnostic}, err
|
|
}
|
|
|
|
metadata := mergeResearchMetadata(researchEventMetadata("diagnostic", researchID, query, results, time.Since(started)), researchDiagnosticMetadata(diagnostic))
|
|
metadata["test_only"] = true
|
|
message := fmt.Sprintf("SearXNG-Test erfolgreich · %d verwertbare Treffer", len(results))
|
|
if len(results) == 0 {
|
|
message = "SearXNG-Test erfolgreich · JSON-Antwort erhalten, aber keine verwertbaren Treffer"
|
|
}
|
|
e.Broker.Publish(model.Activity{Type: "research.test.results", Source: "searxng", Phase: "diagnostic", Message: message, Strength: 1, Metadata: metadata})
|
|
return ResearchTestResult{OK: true, Query: query, Diagnostic: diagnostic, Results: results}, nil
|
|
}
|
|
|
|
func researchDiagnosticMetadata(diagnostic research.Diagnostic) map[string]any {
|
|
metadata := map[string]any{
|
|
"searxng_configured": diagnostic.Configured,
|
|
"searxng_ok": diagnostic.OK,
|
|
"searxng_base_url": diagnostic.BaseURL,
|
|
"searxng_http_status": diagnostic.HTTPStatus,
|
|
"searxng_content_type": diagnostic.ContentType,
|
|
"error_kind": diagnostic.ErrorKind,
|
|
}
|
|
if diagnostic.DurationMS > 0 {
|
|
metadata["duration_ms"] = diagnostic.DurationMS
|
|
}
|
|
if diagnostic.Error != "" {
|
|
metadata["error"] = diagnostic.Error
|
|
}
|
|
return metadata
|
|
}
|