The full LiveAISummarizer sample project (in the GPAL.sln solution), start to finish. Each part is explained below.
using System;
using System
using GenerallyPositive;
using GenerallyPositive
using static GenerallyPositive
using static GenerallyPositive
namespace LiveAISummarizer
{
class Program
{
static IGPALAI aiTask; // set in Main; combo callback checks for null
static readonly Array taskValues = Enum
static GPALLabel instructions = GPAL
static GPALTextArea inputArea = GPAL
static GPALLabel taskLabel = GPAL
static GPALComboBox taskCombo = (GPALComboBox)GPAL
{
if (aiTask == null) return;
int idx = taskCombo
if (idx < 0 || idx >= taskValues
((IAllowAITaskConfig)aiTask)
outputLabel
if (!string
aiTask
})
static GPALLabel outputLabel = GPAL
static GPALRichTextBox outputArea = (GPALRichTextBox)GPAL
static GPALStatusStrip statusBar = (GPALStatusStrip)GPAL
[STAThread]
static void Main(string[] args)
{
GPAL
ICredentials credentials = GPAL
IRESTClient restClient = GPAL
credentials = GPAL
aiTask = GPAL
GPALForm form = GPAL
form
}
}
}
Seven controls make up the form. inputArea is a GPALTextArea where text gets typed or pasted. taskLabel and taskCombo sit between the input and the output - the combo lets the user pick which AI task to run. outputLabel changes its text to match the selected task (Summary:, Generated Text:, etc.). outputArea is a GPALRichTextBox that renders the AI result as Markdown. statusBar is a GPALStatusStrip that shows Ready when idle and a processing message while the AI call is in flight. aiTask is declared at class level (not inside Main) so the combo callback can reach it.
static IGPALAI aiTask; // class-level so the combo callback can swap the task
static readonly Array taskValues = Enum
static GPALLabel instructions = GPAL
static GPALTextArea inputArea = GPAL
static GPALLabel taskLabel = GPAL
// taskCombo - see The Task Selector Combo below
static GPALLabel outputLabel = GPAL
static GPALRichTextBox outputArea = (GPALRichTextBox)GPAL
static GPALStatusStrip statusBar = (GPALStatusStrip)GPAL
taskCombo is populated directly from the AITask enum via Enum.GetValues - no hardcoded string list. WithItems(Array) (the overload that accepts a non-generic Array) calls ToString() on each enum value and adds the result as a combo item. The callback reads the selected index, fetches the corresponding enum value via taskValues.GetValue(idx) and casts it to AITask, calls WithTask to hot-swap the active task, updates outputLabel using taskCombo.SelectedValue (the same string WithItems stored), and re-runs if there is already text in inputArea. The null guard on aiTask protects against the callback firing before Main finishes wiring the AI chain.
static GPALComboBox taskCombo = (GPALComboBox)GPAL
{
if (aiTask == null) return;
int idx = taskCombo
if (idx < 0 || idx >= taskValues
((IAllowAITaskConfig)aiTask)
outputLabel
if (!string
aiTask
})
WithTask on an existing IGPALAI replaces the active task without rebuilding the whole AI chain. The debounce timer and live-input wiring stay intact - only the task changes. This is why aiTask must be at class level rather than a local variable in Main.
The Anthropic API key is read from the ANTKEY environment variable via WithKeyFromEnv. The code also shows an alternative: fetching the key live from a REST API endpoint, which keeps it out of source control and allows rotation without redeploying. That path is left in as commented-out reference - swap it in if your deployment serves keys through an API rather than environment variables.
// Active: read the key from the ANTKEY environment variable
credentials = GPAL
// Alternative: fetch the key live from a REST API endpoint
//IRESTClient restClient = GPAL
//
//
//credentials = GPAL
//
//
//
WithLiveInputFrom(inputArea, debounceMilliseconds: 800) registers a debounced TextChanged callback on inputArea that calls Execute() automatically after 800ms of no typing. WithOutputTo(outputArea) writes each result back to outputArea as Markdown. WithStatusTo(statusBar) updates the status strip with a processing message while the AI call is in flight and resets it to Ready when done. The whole chain assigns into the class-level aiTask field so the combo callback can call WithTask on it later.
aiTask = GPAL
See Building Live AI Forms with WithLiveInputFrom for why WithLiveInputFrom has to be called before WithFormControl/Show/ShowDialog.
With the AI task wired and the combo ready, the form is built by adding all seven controls in top-to-bottom order via WithFormControl. The height is 540 to accommodate the extra taskLabel and taskCombo row. form.ShowDialog() displays the form and blocks until it is closed - from that point on, typing in inputArea triggers the debounced summarizer, and changing the combo hot-swaps the task.
GPALForm form = GPAL
form
Showing off some plain text in these paragraphs eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Here you can find different accents and emphasis sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
This is a link and how it could look like bestlinkinthebeautifulworld. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Here's just some classic bold text adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam notBoldSecondbestlinkinthebeautifulworld illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Obcaecati, iste distinctio veritatis eligendi laboriosam adipisicing elit illo nostrum corporis at adipisicing elit libero vel voluptas? Expedita, adipisicing facere dolores voluptatem ad ab rem assumenda soluta!
Other cuple of colors in case we want to emphasize several ways adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam adipisicing elit illo nostrum corporis at voluptatem libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta! Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quod veniam, quam ad expedita laborum sed at voluptates culpa ipsam ut vel. Ullam temporibus a mollitia quod aliquam ratione exercitationem nesciunt.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta! Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quod veniam, quam ad expedita laborum sed at voluptates culpa ipsam ut vel. Ullam temporibus a mollitia quod aliquam ratione exercitationem nesciunt.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Repudiandae quas consequuntur illo numquam assumenda autem exercitationem distinctio perspiciatis in natus. Eius dicta similique ipsam ipsa minima, nemo quae enim tempore.
GPAL
.CallIfNotFound(GenericCallIfNotFound)
.WithPublishToConsole();
//System.Drawing.Rectangle windowSize = new System.Drawing.Rectangle(10, 10, 1500, 1024);
// NOTE: we have to set browser = before we execute any steps
// this is due to the 'GenericCallIfNotFound' which might throw an exception, and BankScraper will not have the browser set when it calls scraper.Close()
// until the complete fluent line gets executed (meaning every step, meaning browser is not set until everything else succeeds)
browser = GPAL.Browser
.WithBrowserType(Enums.BrowserType.Chrome)
.WithProfileDataDirectory(ChromeProfileLocation)
.WithUseAutomationEngine(AutomationEngine.Selenium)
.WithWindowSize(new System.Drawing.Rectangle(0,0,1920,1080))
.ToGPALObject();