diff --git a/EbayListingTool/Services/AiAssistantService.cs b/EbayListingTool/Services/AiAssistantService.cs
index aa0466d..f697734 100644
--- a/EbayListingTool/Services/AiAssistantService.cs
+++ b/EbayListingTool/Services/AiAssistantService.cs
@@ -134,6 +134,54 @@ public class AiAssistantService
}
}
+ ///
+ /// Takes an existing AI-generated listing and rewrites title, description and price
+ /// to incorporate user corrections (e.g. "earrings are white gold, not silver").
+ /// Returns the updated fields; other PhotoAnalysisResult fields are unchanged.
+ ///
+ public async Task<(string Title, string Description, decimal Price, string PriceReasoning)>
+ RefineWithCorrectionsAsync(string title, string description, decimal price, string corrections)
+ {
+ var prompt =
+ "You are an expert eBay UK seller. I have a listing with incorrect details that need fixing.\n\n" +
+ $"Current title: {title}\n" +
+ $"Current description:\n{description}\n\n" +
+ $"Current price: £{price:F2}\n\n" +
+ $"CORRECTIONS FROM SELLER: {corrections}\n\n" +
+ "Rewrite the listing incorporating these corrections. " +
+ "Return ONLY valid JSON — no markdown, no explanation:\n" +
+ "{\n" +
+ " \"title\": \"corrected eBay UK title, max 80 chars, keyword-rich\",\n" +
+ " \"description\": \"corrected full plain-text eBay UK description\",\n" +
+ " \"price_suggested\": 0.00,\n" +
+ " \"price_reasoning\": \"one sentence why this price\"\n" +
+ "}";
+
+ var json = await CallAsync(prompt);
+
+ try
+ {
+ JObject obj;
+ try { obj = JObject.Parse(json.Trim()); }
+ catch (JsonReaderException)
+ {
+ var m = System.Text.RegularExpressions.Regex.Match(json, @"```(?:json)?\s*(\{[\s\S]*?\})\s*```");
+ obj = JObject.Parse(m.Success ? m.Groups[1].Value : json.Trim());
+ }
+
+ return (
+ obj["title"]?.ToString() ?? title,
+ obj["description"]?.ToString() ?? description,
+ obj["price_suggested"]?.Value() ?? price,
+ obj["price_reasoning"]?.ToString() ?? ""
+ );
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"Could not parse AI refinement response: {ex.Message}");
+ }
+ }
+
/// Convenience wrapper — analyses a single photo.
public Task AnalyseItemFromPhotoAsync(string imagePath)
=> AnalyseItemFromPhotosAsync(new[] { imagePath });
diff --git a/EbayListingTool/Views/PhotoAnalysisView.xaml b/EbayListingTool/Views/PhotoAnalysisView.xaml
index 6fb16d2..af741cc 100644
--- a/EbayListingTool/Views/PhotoAnalysisView.xaml
+++ b/EbayListingTool/Views/PhotoAnalysisView.xaml
@@ -554,6 +554,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/EbayListingTool/Views/PhotoAnalysisView.xaml.cs b/EbayListingTool/Views/PhotoAnalysisView.xaml.cs
index f55a34b..ee947a4 100644
--- a/EbayListingTool/Views/PhotoAnalysisView.xaml.cs
+++ b/EbayListingTool/Views/PhotoAnalysisView.xaml.cs
@@ -220,6 +220,63 @@ public partial class PhotoAnalysisView : UserControl
private void ReAnalyse_Click(object sender, RoutedEventArgs e)
=> Analyse_Click(sender, e);
+ private async void Refine_Click(object sender, RoutedEventArgs e)
+ {
+ if (_aiService == null || _lastResult == null) return;
+
+ var corrections = CorrectionsBox.Text.Trim();
+ if (string.IsNullOrEmpty(corrections))
+ {
+ CorrectionsBox.Focus();
+ return;
+ }
+
+ var title = TitleBox.Text;
+ var description = DescriptionBox.Text;
+ var price = (decimal)(PriceOverride.Value ?? (double)_lastResult.PriceSuggested);
+
+ SetRefining(true);
+ try
+ {
+ var (newTitle, newDesc, newPrice, newReasoning) =
+ await _aiService.RefineWithCorrectionsAsync(title, description, price, corrections);
+
+ TitleBox.Text = newTitle;
+ DescriptionBox.Text = newDesc;
+ PriceOverride.Value = (double)newPrice;
+
+ _lastResult.Title = newTitle;
+ _lastResult.Description = newDesc;
+ _lastResult.PriceSuggested = newPrice;
+
+ if (!string.IsNullOrWhiteSpace(newReasoning))
+ {
+ PriceReasoningText.Text = newReasoning;
+ PriceReasoningText.Visibility = Visibility.Visible;
+ }
+
+ // Clear the corrections box now they're applied
+ CorrectionsBox.Text = "";
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"Refinement failed:\n\n{ex.Message}", "AI Error",
+ MessageBoxButton.OK, MessageBoxImage.Warning);
+ }
+ finally
+ {
+ SetRefining(false);
+ }
+ }
+
+ private void SetRefining(bool busy)
+ {
+ RefineBtn.IsEnabled = !busy;
+ RefineIcon.Visibility = busy ? Visibility.Collapsed : Visibility.Visible;
+ RefineSpinner.Visibility = busy ? Visibility.Visible : Visibility.Collapsed;
+ RefineBtnText.Text = busy ? "Refining…" : "Refine with AI";
+ }
+
private void ShowResults(PhotoAnalysisResult r)
{
IdlePanel.Visibility = Visibility.Collapsed;