Compare commits

...

16 Commits

Author SHA1 Message Date
a6654ef708 Error fixing with input validation 2025-04-10 15:20:57 +02:00
9445cec743 asd 2025-04-10 14:38:31 +02:00
52b64e4430 MOD: Frontend SearchWindow 2025-04-10 11:47:33 +02:00
3e9d887a12 more pdf 2025-04-10 11:22:48 +02:00
0041872afd MOD: Window behavior while resizing // new search logic due to vector embedding in postgre 2025-04-10 10:41:37 +02:00
ba44f03264 Mergeconflicts by sourcetree also deleted in xaml 2025-04-09 10:28:46 +02:00
e94dfb54e1 Mergekonflikt von Sourcetree behoben 2025-04-09 10:27:04 +02:00
c6b6a2359c Merge branch 'main' of https://git.bib.de/PBG2H23ASA/HAG_BIB_Projekt 2025-04-09 10:00:36 +02:00
8bf09d9088 Add: SearchWindow with Id and string search 2025-04-09 10:00:17 +02:00
ebea635c53 Merge branch 'main' of https://git.bib.de/PBG2H23ASA/HAG_BIB_Projekt
# Conflicts:
#	PrototypWPFHAG/MainWindow.xaml
#	PrototypWPFHAG/MainWindow.xaml.cs
2025-03-19 09:45:02 +01:00
d740e9a298 test gelöscht 2025-03-19 09:44:27 +01:00
1195250b98 MOD: MainWindow with simple log in logic + connection to PostgreSQL (Database)
ADD: SearchWindow with logic from Suchenfenster + "Zurück"-Button to change back to MainWindow
DEL: SuchenFenster (exhcanged with Search Window)
2025-03-13 14:07:13 +01:00
fdf61b30df app.config gelöscht. MainWindow mit Datenbank verbunden 2025-03-12 12:04:32 +01:00
0105bf1025 error fixed 2025-03-12 11:12:41 +01:00
a8d19abc13 Merge branch 'main' of https://git.bib.de/PBG2H23ASA/HAG_BIB_Projekt
# Conflicts:
#	PrototypWPFHAG/PrototypWPFHAG.csproj
2025-03-12 11:03:28 +01:00
e0130d7eca version update 2025-03-12 11:02:45 +01:00
10 changed files with 727 additions and 127 deletions

View File

@@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PrototypWPFHAG"
StartupUri="MainWindow.xaml">
StartupUri="SearchWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -1,4 +1,5 @@
<mah:MetroWindow xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" x:Class="PrototypWPFHAG.MainWindow"
<mah:MetroWindow xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
x:Class="PrototypWPFHAG.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
@@ -11,13 +12,36 @@
TitleCharacterCasing="Normal"
WindowTitleBrush="Firebrick"
Icon="pack://application:,,,/Images/databaseicon.png"
ResizeMode="CanResizeWithGrip">
ResizeMode="CanResizeWithGrip"
Loaded="Window_Loaded">
<Grid>
<Border BorderBrush="Firebrick" BorderThickness="3">
</Border>
<StackPanel>
<TextBlock Width="120" Margin="100" Background="AliceBlue"></TextBlock>
<Button Height="25" Width="44" Content="Log in"/>
<Border BorderBrush="Firebrick" BorderThickness="3" Padding="20">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<!-- Username -->
<TextBlock Text="Benutzername" Margin="0,10,0,0" FontSize="14" FontWeight="Bold" />
<TextBox Width="200" Height="30" Margin="0,5,0,0" x:Name="UsernameTextBox" />
<TextBlock Text="Passwort" Margin="0,10,0,0" FontSize="14" FontWeight="Bold" />
<Grid>
<!-- Passwortbox (hidden when Password is visible) -->
<PasswordBox Width="170" Height="30" Margin="0,5,34,0" x:Name="PasswordTextBox"
PasswordChanged="PasswordTextBox_PasswordChanged"/>
<!-- Textbox for visible password (hidden at default) -->
<TextBox Width="170" Height="30" Margin="0,5,34,0" x:Name="PasswordVisibleTextBox"
Visibility="Collapsed" IsReadOnly="True"/>
<!-- Button with Eye-Icon -->
<Button Width="30" Height="30" Margin="175,5,0,0" Content="👁"
Click="ShowPasswordButton_Click"/>
</Grid>
<!-- Login Button -->
<Button Height="30" Width="100" Content="Zur Suche" Margin="0,20,0,0"
Click="loginButton_Click" IsDefault="True" />
</StackPanel>
</Border>
</Grid>
</mah:MetroWindow>

View File

@@ -23,47 +23,100 @@ public partial class MainWindow : MetroWindow
public MainWindow()
{
InitializeComponent();
TestConnection();
Console.ReadKey();
}
private static void TestConnection()
private void Window_Loaded(object sender, RoutedEventArgs e)
{
UsernameTextBox.Focus(); // Focus first TextBox on start
}
private static NpgsqlConnection GetConnection()
{
return new NpgsqlConnection("Server=localhost;Port=5432;User Id=postgres;Password=postgres;Database=postgres;");
}
private string ValidateUser(string username, string password)
{
using (NpgsqlConnection con = GetConnection())
{
con.Open();
if (con.State == ConnectionState.Open)
// Check for correct UserName
string userQuery = "SELECT COUNT(*) FROM \"users\" WHERE \"username\" = @username";
using (NpgsqlCommand userCmd = new NpgsqlCommand(userQuery, con))
{
Console.WriteLine("Connected to Server");
}
}
}
private static NpgsqlConnection GetConnection()
userCmd.Parameters.AddWithValue("@username", username);
int userExists = Convert.ToInt32(userCmd.ExecuteScalar());
if (userExists == 0)
{
return new NpgsqlConnection(@"Server=localhost;Port=5432;User Id=postgres;Password=postgres;Database=postgres;");
return "Dieser Benutzername existiert nicht";
}
}
//class Program
//{
// static void Main(string[] args)
// {
// TestConnection();
// Console.ReadKey();
// }
// private static void TestConnection()
// {
// using(NpgsqlConnection con = GetConnection()){
// con.Open();
// if (con.State == ConnectionState.Open) {
// Console.WriteLine("Connected to Server");
// }
// }
// }
// private static NpgsqlConnection GetConnection()
// {
// return new NpgsqlConnection(@"Server=localhost;Port=5432;User Id=postgres;Password=postgres;Database=TestServer;");
// }
//}
// Check for correct Password
string pwQuery = "SELECT COUNT(*) FROM \"users\" WHERE \"username\" = @username AND \"password\" = @password";
using (NpgsqlCommand pwCmd = new NpgsqlCommand(pwQuery, con))
{
pwCmd.Parameters.AddWithValue("@username", username);
pwCmd.Parameters.AddWithValue("@password", password);
int correctPassword = Convert.ToInt32(pwCmd.ExecuteScalar());
if (correctPassword == 0)
{
return "Falsches Password!";
}
}
}
return "Erfolgreich";
}
private void ShowPasswordButton_PreviewMouseDown(object sender, RoutedEventArgs e)
{
PasswordVisibleTextBox.Text = PasswordTextBox.Password; // Write password in the visible box
PasswordVisibleTextBox.Visibility = Visibility.Visible;
PasswordTextBox.Visibility = Visibility.Collapsed;
}
private void ShowPasswordButton_Click(object sender, RoutedEventArgs e)
{
if (PasswordTextBox.Visibility == Visibility.Visible)
{
// Show password
PasswordVisibleTextBox.Text = PasswordTextBox.Password;
PasswordVisibleTextBox.Visibility = Visibility.Visible;
PasswordTextBox.Visibility = Visibility.Collapsed;
}
else
{
// Hide password
PasswordTextBox.Visibility = Visibility.Visible;
PasswordVisibleTextBox.Visibility = Visibility.Collapsed;
}
}
// Syncs password with visible TextBox
private void PasswordTextBox_PasswordChanged(object sender, RoutedEventArgs e)
{
PasswordVisibleTextBox.Text = PasswordTextBox.Password;
}
private void loginButton_Click(object sender, RoutedEventArgs e)
{
string username = UsernameTextBox.Text;
string password = PasswordTextBox.Password;
string result = ValidateUser(username, password);
if (result == "Erfolgreich")
{
SearchWindow searchWindow = new();
searchWindow.Show(); // Open new window
this.Close(); // Close this window
}
else
{
MessageBox.Show(result, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}

View File

@@ -0,0 +1,52 @@
using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
public class DocumentResponse
{
[JsonPropertyName("documents")] // Konsistent mit Such-Endpoint
public List<SearchResult> Documents { get; set; }
}
public class PdfServiceClient
{
private readonly HttpClient _httpClient;
private const string BaseUrl = "http://localhost:8000"; // Microservice-URL
public PdfServiceClient()
{
_httpClient = new HttpClient
{
BaseAddress = new Uri(BaseUrl), Timeout = TimeSpan.FromSeconds(30)
};
}
public async Task<string> GetDocumentContentAsync(int documentId)
{
var response = await _httpClient.GetAsync($"{BaseUrl}/documents/{documentId}/markdown");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<JsonElement>(json);
return result.GetProperty("content").GetString();
}
public async Task<List<SearchResult>> SearchDocumentsAsync(string query)
{
var response = await _httpClient.GetAsync($"{BaseUrl}/documents/search?query={query}");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<List<SearchResult>>(json);
}
}
public class SearchResult
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("filename")]
public string Filename { get; set; }
[JsonPropertyName("content")]
public string Content { get; set; }
}

View File

@@ -1,7 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<OutputType>WinExe</OutputType>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
@@ -10,6 +14,7 @@
<ItemGroup>
<None Remove="Images\databaseicon.png" />
<None Remove="Images\pdf-icon.png" />
</ItemGroup>
<ItemGroup>
@@ -20,11 +25,17 @@
<ItemGroup>
<PackageReference Include="MahApps.Metro" Version="2.4.10" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Negotiate" Version="9.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Negotiate" Version="9.0.3" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.69.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Npgsql" Version="9.0.3" />
<PackageReference Include="PdfPig" Version="0.1.9" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.6" />
<PackageReference Include="PdfPig" Version="0.1.10" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
</ItemGroup>
<ItemGroup>
<Resource Include="Images\pdf-icon.png" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,153 @@
<mah:MetroWindow xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
x:Class="PrototypWPFHAG.SearchWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PrototypWPFHAG"
Title="PDF-Verwaltung (Admin)"
Height="600" Width="1000"
MinWidth="800" MinHeight="500"
WindowTitleBrush="FireBrick"
Icon="pack://application:,,,/Images/databaseicon.png"
ResizeMode="CanResizeWithGrip"
WindowStartupLocation="CenterScreen">
<Border BorderBrush="FireBrick" BorderThickness="3">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="500" MinWidth="400"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Linke Seite -->
<Border Grid.Column="0" Margin="10" Padding="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<!-- Drag & Drop -->
<RowDefinition Height="Auto"/>
<!-- Upload/Auswahl-Buttons -->
<RowDefinition Height="Auto"/>
<!-- Suchmodus -->
<RowDefinition Height="Auto"/>
<!-- Suchfeld -->
<RowDefinition Height="*"/>
<!-- Suchergebnisse -->
<RowDefinition Height="Auto"/>
<!-- Status -->
<RowDefinition Height="Auto"/>
<!-- Zurück-Button -->
</Grid.RowDefinitions>
<!-- Drag & Drop Bereich -->
<Border Grid.Row="0" Height="75" Margin="0,5"
BorderBrush="Gray" BorderThickness="1">
<Grid Background="Transparent" AllowDrop="True"
DragEnter="PdfDropCanvas_DragEnter"
Drop="PdfDropCanvas_Drop">
<TextBlock x:Name="DropHintText" Text="PDF hier rein ziehen"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<Image x:Name="PdfIcon" Source="pack://application:,,,/Images/pdf-icon.png"
Width="25" Height="25" Visibility="Collapsed"/>
<TextBlock x:Name="PdfFileNameText" Margin="10"
TextWrapping="Wrap" Visibility="Collapsed"/>
</StackPanel>
</Grid>
</Border>
<!-- Upload/Auswahl-Buttons -->
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,10">
<Button Content="PDF hochladen"
Width="210" Height="30"
Background="LightGreen"
Click="UploadButton_Click"/>
<Button Content="PDF auswählen"
Width="210" Height="30" Margin="40,0,0,0"
Background="Firebrick"
Click="ChoosePdfButton_Click"/>
</StackPanel>
<!-- Suchmodus-Auswahl -->
<StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0,10">
<RadioButton x:Name="SearchByIdRadio"
Content="ID"
Margin="5"
IsChecked="True"/>
<RadioButton x:Name="SearchByTextRadio"
Content="Text"
Margin="5"/>
</StackPanel>
<!-- Suchfeld -->
<StackPanel Grid.Row="3" Margin="0,10">
<TextBox x:Name="SearchTextBox"
Margin="0,0,0,5"
HorizontalAlignment="Stretch"/>
<Button Content="Suchen"
x:Name="SearchButton"
Height="30"
HorizontalAlignment="Stretch"
Click="SearchButton_Click"/>
</StackPanel>
<!-- Suchergebnisse -->
<ListBox Grid.Row="4"
x:Name="SearchResultsListBox"
Margin="0,10"
DisplayMemberPath="DocumentName"
ScrollViewer.VerticalScrollBarVisibility="Auto"
SelectionMode="Extended"
SelectionChanged="SearchResultsListBox_SelectionChanged"/>
<!-- Status & Fortschritt -->
<StackPanel Grid.Row="5" Orientation="Vertical" Margin="0,10">
<TextBlock x:Name="UploadStatusText" TextAlignment="Center"/>
<ProgressBar x:Name="UploadProgressBar"
Height="10"
Minimum="0"
Maximum="100"
Visibility="Collapsed"/>
</StackPanel>
<!-- Zurück-Button -->
<Button Grid.Row="6"
Content="Zurück zur Anmeldung"
Height="30" Margin="0,10"
HorizontalAlignment="Stretch"
Background="#ffd64f"
Click="BackToLogIn_Click"/>
</Grid>
</Border>
<!-- Rechte Seite -->
<Border Grid.Column="1" Margin="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Content="PDF-Inhalt:" Margin="0,0,0,5"/>
<TextBox Grid.Row="1"
x:Name="ContentTextBox"
TextWrapping="Wrap"
AcceptsReturn="True"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto"
IsReadOnly="True"/>
<Button Grid.Row="2"
Content="Löschen"
Width="100" Height="30"
Margin="0,10"
HorizontalAlignment="Center"
Background="Firebrick"
Click="DeleteButton_Click"/>
</Grid>
</Border>
</Grid>
</Border>
</mah:MetroWindow>

View File

@@ -0,0 +1,375 @@
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}";
}
}
}
}
}

View File

@@ -1,67 +0,0 @@
<Window x:Class="SuchenFenster.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Suchen Fenster" Height="600" Width="800">
<Grid>
<!-- 左侧垂直布局 -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<!-- 左侧固定宽度 -->
<ColumnDefinition Width="*"/>
<!-- 右侧占满剩余空间 -->
</Grid.ColumnDefinitions>
<!-- 左侧区域 -->
<StackPanel Orientation="Vertical" Margin="10">
<Grid Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox x:Name="TextField" Grid.Row="0" Height="50" VerticalContentAlignment="Center" Margin="0,0,5,0"/>
<Border Grid.Row="0" Grid.Column="1" Background="LightGray" Height="50" Margin="5,0,0,0">
<TextBlock Text="Bild hochladen" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
<Line Grid.Row="0" Grid.Column="1" X1="0" Y1="25" X2="1" Y2="25" Stroke="Black" StrokeThickness="1" Margin="5,0,0,0"/>
<Button Content="Suchen" Width="180" Height="30" Grid.Row="1" Grid.ColumnSpan="2" HorizontalAlignment="Right" Margin="0,5,0,0"/>
</Grid>
<!-- PDFField -->
<Grid Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border Background="LightGray" Height="30" Margin="0,0,0,0" Grid.Column="0">
<TextBlock Text="PDF hochladen" VerticalAlignment="Center" HorizontalAlignment="Center" RenderTransformOrigin="0.514,5.613"/>
</Border>
<Button Content="ADD" Width="60" Height="30" Grid.Column="1" Margin="5,0,0,0"/>
</Grid>
</StackPanel>
<!-- 右侧区域 -->
<Grid Grid.Column="1" Margin="10">
<Label Content="Zeugnisse:" HorizontalAlignment="Left" Margin="0,2,0,8"/>
<!-- ListField -->
<ListBox x:Name="ListField" Margin="0,29,0,35" BorderThickness="1" BorderBrush="Black">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<!-- 内容 -->
<TextBlock Text="{Binding}" VerticalAlignment="Center" HorizontalAlignment="Stretch" Padding="5"/>
<!-- 分隔线 -->
<Border Height="1" Background="Black" Margin="0,2,0,2"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- 删除按钮 -->
<Button Content="Löschen" Width="100" Height="30" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
</Grid>
</Grid>
</Window>

View File

@@ -1 +0,0 @@