<# .SYNOPSIS Semantische Suche in TED Ausschreibungen .DESCRIPTION Fuehrt eine semantische Aehnlichkeitssuche gegen die TED Procurement Datenbank durch. .PARAMETER Query Der Suchtext fuer die semantische Suche .PARAMETER TopK Anzahl der zurueckgegebenen Ergebnisse (Standard: 10, Max: 100) .PARAMETER Threshold Minimaler Aehnlichkeitsschwellwert 0.0-1.0 (Standard: 0.5) .PARAMETER ApiUrl URL des API-Servers (Standard: http://localhost:8888/api) .EXAMPLE .\Search-TED.ps1 -Query "Software Entwicklung Cloud Services" .EXAMPLE .\Search-TED.ps1 -Query "IT Beratung Digitalisierung" -TopK 20 -Threshold 0.6 #> param( [Parameter(Mandatory=$true, Position=0, HelpMessage="Suchtext fuer semantische Suche")] [string]$Query, [Parameter(Mandatory=$false)] [ValidateRange(1, 100)] [int]$TopK = 100, [Parameter(Mandatory=$false)] [ValidateRange(0.0, 1.0)] [double]$Threshold = 0.5, [Parameter(Mandatory=$false)] [string]$ApiUrl = "http://localhost:8888/api" ) # Farben fuer Ausgabe $colors = @{ Header = "Cyan" Success = "Green" Warning = "Yellow" Error = "Red" Info = "White" Highlight = "Magenta" } function Write-Header { param([string]$Text) Write-Host "" Write-Host ("=" * 80) -ForegroundColor $colors.Header Write-Host $Text -ForegroundColor $colors.Header Write-Host ("=" * 80) -ForegroundColor $colors.Header } function Write-Result { param( [int]$Rank, [PSObject]$Doc ) $similarity = if ($Doc.similarityPercent) { "$($Doc.similarityPercent)%" } else { "N/A" } $deadline = "-" if ($Doc.submissionDeadline) { try { # Handle ISO 8601 format (e.g., "2025-04-28T06:00:59Z") $deadline = ([DateTime]::Parse($Doc.submissionDeadline, [System.Globalization.CultureInfo]::InvariantCulture)).ToString("dd.MM.yyyy") } catch { $deadline = $Doc.submissionDeadline.Substring(0, 10) # Fallback: first 10 chars (YYYY-MM-DD) } } Write-Host "" Write-Host "[$Rank] " -NoNewline -ForegroundColor $colors.Highlight Write-Host "$similarity Aehnlichkeit" -ForegroundColor $colors.Success Write-Host " Titel: " -NoNewline -ForegroundColor $colors.Info Write-Host $Doc.projectTitle -ForegroundColor $colors.Warning Write-Host " Auftraggeber: " -NoNewline -ForegroundColor $colors.Info Write-Host "$($Doc.buyerName) ($($Doc.buyerCountryCode))" -ForegroundColor White Write-Host " Vertragsart: " -NoNewline -ForegroundColor $colors.Info Write-Host $Doc.contractNature -ForegroundColor White Write-Host " Einreichfrist:" -NoNewline -ForegroundColor $colors.Info Write-Host " $deadline" -ForegroundColor White Write-Host " TED Link: " -NoNewline -ForegroundColor $colors.Info Write-Host $Doc.noticeUrl -ForegroundColor Cyan if ($Doc.projectDescription) { $desc = $Doc.projectDescription if ($desc.Length -gt 200) { $desc = $desc.Substring(0, 197) + "..." } Write-Host " Beschreibung: " -NoNewline -ForegroundColor $colors.Info Write-Host $desc -ForegroundColor DarkGray } } # Hauptprogramm try { Write-Header "TED Semantische Suche" Write-Host "Suchtext: " -NoNewline -ForegroundColor $colors.Info Write-Host $Query -ForegroundColor $colors.Warning Write-Host "Parameter: TopK=$TopK, Threshold=$Threshold" -ForegroundColor DarkGray Write-Host "" # Request Body erstellen $body = @{ text = $Query topK = $TopK threshold = $Threshold } | ConvertTo-Json # API aufrufen Write-Host "Suche laeuft..." -ForegroundColor $colors.Info $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() $response = Invoke-RestMethod -Uri "$ApiUrl/similarity/text" ` -Method Post ` -ContentType "application/json; charset=utf-8" ` -Body $body ` -ErrorAction Stop $stopwatch.Stop() # Ergebnisse anzeigen $resultCount = $response.resultCount $embeddingTime = $response.embeddingTimeMs $searchTime = $response.searchTimeMs $totalTime = $stopwatch.ElapsedMilliseconds Write-Header "Suchergebnisse: $resultCount Treffer" Write-Host "Zeiten: Embedding=${embeddingTime}ms, Suche=${searchTime}ms, Gesamt=${totalTime}ms" -ForegroundColor DarkGray if ($resultCount -eq 0) { Write-Host "" Write-Host "Keine passenden Ausschreibungen gefunden." -ForegroundColor $colors.Warning Write-Host "Versuchen Sie:" -ForegroundColor $colors.Info Write-Host " - Andere Suchbegriffe" -ForegroundColor DarkGray Write-Host " - Niedrigeren Schwellwert (-Threshold 0.3)" -ForegroundColor DarkGray } else { $rank = 1 foreach ($doc in $response.results) { Write-Result -Rank $rank -Doc $doc $rank++ } } Write-Host "" Write-Host ("-" * 80) -ForegroundColor DarkGray Write-Host "Suche abgeschlossen." -ForegroundColor $colors.Success } catch { Write-Host "" Write-Host "FEHLER: $_" -ForegroundColor $colors.Error if ($_.Exception.Response.StatusCode -eq 503) { Write-Host "Der Vektorisierungsdienst ist nicht verfuegbar." -ForegroundColor $colors.Warning Write-Host "Stellen Sie sicher, dass der Embedding-Service auf Port 8001 laeuft." -ForegroundColor $colors.Info } elseif ($_.Exception.Message -like "*Unable to connect*") { Write-Host "Konnte keine Verbindung zum Server herstellen." -ForegroundColor $colors.Warning Write-Host "Stellen Sie sicher, dass die Anwendung auf $ApiUrl laeuft." -ForegroundColor $colors.Info } exit 1 }