feat: Chemikalien-Recherche über lokale RiSU-Stoffliste (kein KI-Aufruf mehr)

Ersetzt den ursprünglichen KI-Websuche-Ansatz (GESTIS scheiterte sowohl über
Websuche als auch über direkten API-Zugriff an fehlenden schulspezifischen
Tätigkeitsbeschränkungen) durch einen reinen lokalen Datenbank-Lookup gegen die
offizielle RiSU-Stoffliste (1764 Stoffe inkl. Tätigkeitsbeschränkungs-Codes,
Legende zur Abfragezeit übersetzt statt in die Datenbank gebacken). Keine
KI-Kosten, keine Drittanbieter-Abhängigkeit mehr für diese Funktion.

HazardSubstance.AgeRestriction zu ActivityRestriction umbenannt, da die
Tätigkeitsbeschränkung mehr abdeckt als reine Altersgrenzen. Details und
verworfene Zwischenstände in TODO.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 23:43:56 +02:00
co-authored by Claude Sonnet 5
parent 038337997f
commit 7b883555bf
14 changed files with 647 additions and 37 deletions
@@ -81,14 +81,32 @@
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseLowBrush}"
BorderThickness="0,0,0,1" Padding="0,10">
<StackPanel Spacing="6">
<Grid ColumnDefinitions="*,140,Auto">
<Grid ColumnDefinitions="*,Auto,Auto">
<TextBox Grid.Column="0" Text="{Binding Name}" PlaceholderText="Stoffname"
Margin="0,0,8,0"/>
<TextBox Grid.Column="1" Text="{Binding Amount}" PlaceholderText="Menge, z.B. ca. 2 g"
Margin="0,0,8,0"/>
<Button Grid.Column="1" Content="🔍 Recherchieren" Command="{Binding ResearchCommand}"
IsVisible="{Binding CanResearch}" IsEnabled="{Binding !IsResearching}"
Margin="0,0,8,0"
ToolTip.Tip="Sucht Piktogramme, Signalwort, H-/P-Sätze und Tätigkeitsbeschränkung in der RiSU-Stoffliste (Sicheres Experimentieren im Unterricht)."/>
<Button Grid.Column="2" Content="✕" Command="{Binding RemoveCommand}"
ToolTip.Tip="Stoff entfernen"/>
</Grid>
<TextBlock Text="{Binding ResearchError}" Foreground="Red" FontSize="11"
IsVisible="{Binding ResearchError, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
<Grid ColumnDefinitions="*,12,140,12,140">
<StackPanel Grid.Column="0" Spacing="2">
<TextBlock Text="CAS-Nummer" FontSize="11" Opacity="0.6"/>
<TextBox Text="{Binding Cas}" PlaceholderText="z.B. 7440-23-5"/>
</StackPanel>
<StackPanel Grid.Column="2" Spacing="2">
<TextBlock Text="Menge" FontSize="11" Opacity="0.6"/>
<TextBox Text="{Binding Amount}" PlaceholderText="z.B. ca. 2 g"/>
</StackPanel>
<StackPanel Grid.Column="4" Spacing="2">
<TextBlock Text="Signalwort" FontSize="11" Opacity="0.6"/>
<TextBox Text="{Binding SignalWord}" PlaceholderText="Gefahr/Achtung"/>
</StackPanel>
</Grid>
<ItemsControl ItemsSource="{Binding PictogramOptions}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel ItemSpacing="10" LineSpacing="4"/></ItemsPanelTemplate>
@@ -109,6 +127,11 @@
<TextBox Text="{Binding PStatements}" PlaceholderText="z.B. P280, P305+P351+P338"/>
</StackPanel>
</Grid>
<StackPanel Spacing="2">
<TextBlock Text="Tätigkeitsbeschränkung" FontSize="11" Opacity="0.6"/>
<TextBox Text="{Binding ActivityRestriction}"
PlaceholderText="z.B. Für Schüler ab der 5. Klasse freigegeben"/>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
@@ -126,8 +126,8 @@ public partial class LessonDialog : Window
assessment.Title, assessment.GroupLabel, assessment.Date?.ToString("dd.MM.yyyy") ?? "",
ExperimentKindDisplay.Label(assessment.Kind), assessment.Procedure,
assessment.Substances.Select(s => new HazardSubstancePrintRow(
s.Name, s.Amount, string.Join(", ", s.GhsPictograms.Select(GhsPictogramDisplay.Code)),
s.HStatements, s.PStatements)).ToList(),
s.Name, s.Cas, s.Amount, string.Join(", ", s.GhsPictograms.Select(GhsPictogramDisplay.Code)),
s.SignalWord, s.HStatements, s.PStatements, s.ActivityRestriction)).ToList(),
assessment.Hazards, assessment.ProtectiveMeasures, assessment.FirstAid, assessment.Disposal,
assessment.Notes, assessment.IsAiAssisted);
var pdf = App.Services.GetRequiredService<PdfExportService>().BuildHazardAssessmentPdf(data);