376 lines
13 KiB
C#
376 lines
13 KiB
C#
using MahApps.Metro.Controls;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using System.Web;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Documents;
|
|
|
|
|
|
namespace PrototypWPFHAG
|
|
{
|
|
/// <summary>
|
|
/// Interaktionslogik für SearchWindow.xaml
|
|
/// </summary>
|
|
|
|
public class DocumentResponse
|
|
{
|
|
[JsonPropertyName("documents")]
|
|
public List<SearchResult> Documents { get; set; }
|
|
}
|
|
public partial class SearchWindow : MetroWindow
|
|
{
|
|
public readonly HttpClient _httpClient;
|
|
private bool _isSearchInProgress;
|
|
private readonly PdfServiceClient _pdfServiceClient = new();
|
|
private const string BaseUrl = "http://localhost:8000"; // Microservice-URL
|
|
private string _selectedPdfPath;
|
|
private List<string> _selectedPdfPaths = new List<string>();
|
|
public SearchWindow()
|
|
{
|
|
InitializeComponent();
|
|
_httpClient = new HttpClient
|
|
{
|
|
BaseAddress = new Uri(BaseUrl),
|
|
Timeout = TimeSpan.FromSeconds(30)
|
|
};
|
|
}
|
|
|
|
private void BackToLogIn_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
MainWindow loginWindow = new();
|
|
loginWindow.Show(); // Open new window
|
|
this.Close(); // Close this window
|
|
}
|
|
private async void SearchButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (_isSearchInProgress) return;
|
|
|
|
try
|
|
{
|
|
_isSearchInProgress = true;
|
|
SearchButton.IsEnabled = false;
|
|
|
|
if (SearchByIdRadio.IsChecked == true)
|
|
{
|
|
await SearchByIdAsync();
|
|
}
|
|
else
|
|
{
|
|
await SearchBySimilarityAsync();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Fehler bei der Suche: {ex.Message}",
|
|
"Fehler",
|
|
MessageBoxButton.OK,
|
|
MessageBoxImage.Error);
|
|
}
|
|
finally
|
|
{
|
|
_isSearchInProgress = false;
|
|
SearchButton.IsEnabled = true;
|
|
}
|
|
}
|
|
private async Task SearchByIdAsync()
|
|
{
|
|
if (!int.TryParse(SearchTextBox.Text, out int documentId))
|
|
{
|
|
MessageBox.Show("Bitte eine gültige ID eingeben");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var response = await _httpClient.GetAsync($"/documents/{documentId}");
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
var result = JsonSerializer.Deserialize<DocumentDetail>(json);
|
|
|
|
await Dispatcher.InvokeAsync(() =>
|
|
{
|
|
SearchResultsListBox.ItemsSource = new List<DocumentDetail> { result };
|
|
ContentTextBox.Text = result.Content;
|
|
SearchResultsListBox.DisplayMemberPath = "DocumentName";
|
|
});
|
|
}
|
|
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
|
|
{
|
|
MessageBox.Show("Dokument nicht gefunden");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Fehler: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private async Task SearchBySimilarityAsync()
|
|
{
|
|
try
|
|
{
|
|
var encodedQuery = HttpUtility.UrlEncode(SearchTextBox.Text);
|
|
var response = await _httpClient.GetAsync($"/documents/search/similarity?query={encodedQuery}");
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
var result = JsonSerializer.Deserialize<ApiResponse>(json);
|
|
|
|
await Dispatcher.InvokeAsync(() =>
|
|
{
|
|
SearchResultsListBox.ItemsSource = result?.Documents;
|
|
SearchResultsListBox.DisplayMemberPath = "DocumentName";
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Fehler: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private void PdfDropCanvas_DragEnter(object sender, DragEventArgs e)
|
|
{
|
|
// Nur PDF-Dateien erlauben
|
|
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
|
{
|
|
var files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
|
if (files.Any(f => System.IO.Path.GetExtension(f).Equals(".pdf", StringComparison.OrdinalIgnoreCase)))
|
|
{
|
|
e.Effects = DragDropEffects.Copy;
|
|
DropHintText.Visibility = Visibility.Collapsed; // Platzhalter ausblenden
|
|
}
|
|
}
|
|
else
|
|
{
|
|
e.Effects = DragDropEffects.None;
|
|
}
|
|
e.Handled = true;
|
|
}
|
|
|
|
private void ChoosePdfButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var openFileDialog = new Microsoft.Win32.OpenFileDialog
|
|
{
|
|
Filter = "PDF Files (*.pdf)|*.pdf",
|
|
Multiselect = true
|
|
};
|
|
|
|
if (openFileDialog.ShowDialog() == true)
|
|
{
|
|
_selectedPdfPaths.AddRange(openFileDialog.FileNames);
|
|
|
|
|
|
PdfIcon.Visibility = Visibility.Visible;
|
|
PdfFileNameText.Text = string.Join(", ", _selectedPdfPaths.Select(System.IO.Path.GetFileName));
|
|
PdfFileNameText.Visibility = Visibility.Visible;
|
|
DropHintText.Visibility = Visibility.Collapsed;
|
|
}
|
|
}
|
|
private void PdfDropCanvas_Drop(object sender, DragEventArgs e)
|
|
{
|
|
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
|
{
|
|
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
|
var pdfFiles = files.Where(f => System.IO.Path.GetExtension(f).Equals(".pdf", StringComparison.OrdinalIgnoreCase)).ToList();
|
|
|
|
if (pdfFiles.Any())
|
|
{
|
|
_selectedPdfPaths.AddRange(pdfFiles);
|
|
|
|
// 更新UI以显示所有文件
|
|
PdfIcon.Visibility = Visibility.Visible;
|
|
PdfFileNameText.Text = string.Join(", ", _selectedPdfPaths.Select(System.IO.Path.GetFileName));
|
|
PdfFileNameText.Visibility = Visibility.Visible;
|
|
DropHintText.Visibility = Visibility.Collapsed;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Response-Klassen
|
|
public class ApiResponse
|
|
{
|
|
[JsonPropertyName("success")]
|
|
public bool Success { get; set; }
|
|
|
|
[JsonPropertyName("document")]
|
|
public DocumentDetail Document { get; set; }
|
|
|
|
[JsonPropertyName("documents")]
|
|
public List<DocumentDetail> Documents { get; set; }
|
|
}
|
|
|
|
public class DocumentDetail : INotifyPropertyChanged
|
|
{
|
|
[JsonPropertyName("id")]
|
|
public int Id { get; set; }
|
|
|
|
[JsonPropertyName("document_name")]
|
|
public string DocumentName { get; set; }
|
|
|
|
[JsonPropertyName("content")]
|
|
public string Content { get; set; }
|
|
|
|
[JsonPropertyName("distance")]
|
|
public double Distance { get; set; }
|
|
|
|
private bool _isSelected;
|
|
public bool IsSelected
|
|
{
|
|
get => _isSelected;
|
|
set
|
|
{
|
|
if (_isSelected != value)
|
|
{
|
|
_isSelected = value;
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
{
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
}
|
|
}
|
|
|
|
public class ApiError
|
|
{
|
|
public string Detail { get; set; }
|
|
}
|
|
|
|
private async void UploadButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (!_selectedPdfPaths.Any())
|
|
{
|
|
MessageBox.Show("Keine PDF ausgewählt!");
|
|
return;
|
|
}
|
|
|
|
UploadProgressBar.Visibility = Visibility.Visible;
|
|
UploadProgressBar.Value = 0;
|
|
UploadStatusText.Text = "Upload läuft...";
|
|
|
|
try
|
|
{
|
|
using var formData = new MultipartFormDataContent();
|
|
|
|
foreach (var pdfPath in _selectedPdfPaths)
|
|
{
|
|
var fileContent = new StreamContent(File.OpenRead(pdfPath));
|
|
formData.Add(fileContent, "files", Path.GetFileName(pdfPath));
|
|
}
|
|
|
|
var response = await _httpClient.PostAsync("/upload-pdfs/", formData);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
var result = JsonSerializer.Deserialize<ApiResponse>(json);
|
|
|
|
if (result?.Success == true)
|
|
{
|
|
UploadStatusText.Text = "Upload erfolgreich!";
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
UploadStatusText.Text = $"Fehler: {ex.Message}";
|
|
}
|
|
finally
|
|
{
|
|
UploadProgressBar.Visibility = Visibility.Collapsed;
|
|
_selectedPdfPaths.Clear();
|
|
PdfIcon.Visibility = Visibility.Collapsed;
|
|
PdfFileNameText.Visibility = Visibility.Collapsed;
|
|
DropHintText.Visibility = Visibility.Visible;
|
|
}
|
|
}
|
|
private async void DeleteButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (SearchResultsListBox.SelectedItems.Count == 0)
|
|
{
|
|
MessageBox.Show("Bitte Dokumente auswählen.");
|
|
return;
|
|
}
|
|
|
|
var result = MessageBox.Show(
|
|
$"{SearchResultsListBox.SelectedItems.Count} Dokument(e) löschen?",
|
|
"Bestätigung",
|
|
MessageBoxButton.YesNo,
|
|
MessageBoxImage.Warning
|
|
);
|
|
|
|
if (result != MessageBoxResult.Yes) return;
|
|
|
|
var deletedIds = new List<int>();
|
|
var errorIds = new List<int>();
|
|
|
|
foreach (var item in SearchResultsListBox.SelectedItems.Cast<DocumentDetail>().ToList())
|
|
{
|
|
try
|
|
{
|
|
var response = await _httpClient.DeleteAsync($"/documents/{item.Id}");
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
deletedIds.Add(item.Id);
|
|
}
|
|
else
|
|
{
|
|
errorIds.Add(item.Id);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
errorIds.Add(item.Id);
|
|
}
|
|
}
|
|
|
|
// Aktualisiere die Liste
|
|
if (SearchByIdRadio.IsChecked == true)
|
|
{
|
|
await SearchByIdAsync();
|
|
}
|
|
else
|
|
{
|
|
await SearchBySimilarityAsync();
|
|
}
|
|
|
|
// Feedback
|
|
var message = new StringBuilder();
|
|
if (deletedIds.Count > 0) message.AppendLine($"{deletedIds.Count} Dokument(e) gelöscht.");
|
|
if (errorIds.Count > 0) message.AppendLine($"{errorIds.Count} Dokument(e) konnten nicht gelöscht werden.");
|
|
|
|
MessageBox.Show(message.ToString());
|
|
}
|
|
|
|
private async void SearchResultsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
{
|
|
if (SearchResultsListBox.SelectedItem is DocumentDetail selected)
|
|
{
|
|
try
|
|
{
|
|
var response = await _httpClient.GetAsync($"/documents/{selected.Id}/markdown");
|
|
var content = await response.Content.ReadAsStringAsync();
|
|
var result = JsonSerializer.Deserialize<JsonElement>(content);
|
|
|
|
ContentTextBox.Text = result.GetProperty("document")
|
|
.GetProperty("content")
|
|
.GetString();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ContentTextBox.Text = $"Fehler: {ex.Message}";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|