TMS FNC Cloud AI Guides
TTMSFNCCloudAI is a single non-visual component that talks to many AI language
model services — OpenAI, Gemini, Claude, Grok, Perplexity, Mistral, DeepSeek and
local Ollama or llama.cpp servers — through one consistent API. You set a
Service, supply the matching API key, push a prompt into Context, and call
Execute; the reply arrives asynchronously in OnExecuted. The same component
also transcribes and translates audio, submits documents (PDF, Word, Excel) as
context, exposes tool/function calling, and tracks token usage across requests.
Reach for it whenever an application needs chat completions, document Q&A, or
speech-to-text without binding to a single vendor's SDK. This guide covers the
core request flow and the capabilities added in recent releases.
Quick start: send a prompt
Configure the service and key, assign an OnExecuted handler, set the prompt
text on Context, and call Execute. Requests are asynchronous — Execute
returns immediately and the response is delivered to the event handler, so never
block the UI thread waiting on it.
procedure TForm1.FormCreate(Sender: TObject);
begin
TMSFNCCloudAI1.Service := aiOpenAI;
TMSFNCCloudAI1.APIKeys.OpenAI := 'your-openai-api-key';
TMSFNCCloudAI1.Settings.OpenAIModel := 'gpt-4o';
TMSFNCCloudAI1.OnExecuted := AIExecuted;
TMSFNCCloudAI1.Context.Text := 'Summarize the benefits of unit testing in two sentences.';
TMSFNCCloudAI1.Execute; // asynchronous; the result arrives in OnExecuted
end;
procedure TForm1.AIExecuted(Sender: TObject; AResponse: TTMSFNCCloudAIResponse;
AHttpStatusCode: Integer; AHttpResult: string);
begin
if (AHttpStatusCode = 200) and Assigned(AResponse) then
Memo1.Lines.Text := AResponse.Content.Text
else
Memo1.Lines.Add('Request failed: ' + AHttpResult);
end;
AResponse.Content holds the reply text; AResponse.TotalTokens and the
component's Usage object report token consumption. Always check
AHttpStatusCode before reading the response — on a transport or service error
AResponse may be nil and AHttpResult carries the raw error body.
Choosing a service at runtime
When the same app may be configured with different providers, let the user pick
from only the services that are actually usable. GetActiveServices returns the
services that have an API key set (or a reachable local endpoint), and the
capability flags narrow the list further — for example to services that accept
file input or support function calling.
procedure TForm1.PopulateServiceList;
var
Services: TStringList;
begin
// GetActiveServices returns only services with an available API key or local endpoint.
// Pass UseFiles := True to keep only services that accept file input.
Services := TMSFNCCloudAI1.GetActiveServices(False, False);
// The returned list is owned by the component - copy it, do not free it.
ComboBox1.Items.Assign(Services);
end;
The returned TStringList is owned by the component and reused on the next call,
so copy it (as above) rather than freeing it. Use GetServices instead of
GetActiveServices when you want the full catalogue regardless of configured
keys.
Requesting reasoning effort
Reasoning-capable models can spend extra internal "thinking" on harder problems.
Set Settings.Reasoning to ask for more or less effort; the component maps the
value to each provider's own reasoning option (OpenAI, Claude, Gemini, Ollama
and llama.cpp are supported). Use it for multi-step logic, code analysis, or
math where a quick answer is often wrong.
procedure TForm1.AskWithReasoning;
begin
TMSFNCCloudAI1.Service := aiOpenAI;
TMSFNCCloudAI1.APIKeys.OpenAI := 'your-openai-api-key';
// Ask reasoning-capable services (OpenAI, Claude, Gemini, Ollama, llama.cpp) to think harder.
// aiIgnore (default) sends no option; aiOff explicitly disables reasoning.
TMSFNCCloudAI1.Settings.Reasoning := aiHigh;
TMSFNCCloudAI1.OnExecuted := AIExecuted;
TMSFNCCloudAI1.Context.Text :=
'A bat and a ball cost 1.10 in total. The bat costs 1.00 more than the ball. How much is the ball?';
TMSFNCCloudAI1.Execute;
end;
The default aiIgnore sends no reasoning option at all (the model decides),
while aiOff explicitly disables reasoning on services that support switching it
off. Higher effort increases latency and token cost, so reserve aiHigh for
prompts that genuinely need it.
Submitting documents as context
OpenAI accepts PDF, Word (.docx) and Excel (.xlsx) files as request context,
and Mistral accepts PDF; the model can then answer questions grounded in the
document. Attach files with AddFile, passing the matching
TTMSFNCCloudAIFileType, then send your question through Context as usual.
procedure TForm1.AskAboutDocument;
begin
TMSFNCCloudAI1.Service := aiOpenAI; // OpenAI accepts PDF, DOCX and XLSX context
TMSFNCCloudAI1.APIKeys.OpenAI := 'your-openai-api-key';
TMSFNCCloudAI1.ClearFiles;
TMSFNCCloudAI1.AddFile('C:\docs\contract.pdf', aiftPDF);
// Also supported: aiftWord (.docx), aiftExcel (.xlsx), aiftImage, aiftCSV, aiftText.
// Mistral accepts PDF context; set Service := aiMistral and APIKeys.Mistral to use it.
TMSFNCCloudAI1.OnExecuted := AIExecuted;
TMSFNCCloudAI1.Context.Text := 'List the payment terms described in the attached contract.';
TMSFNCCloudAI1.Execute;
end;
Call ClearFiles before building a new request so files from a previous prompt
do not leak into the next one. Use AddText to inject inline text content and
AddURL to reference a remote resource; AddFile also accepts aiftImage,
aiftCSV and aiftText for other content kinds.
Transcribing and translating audio
TTMSFNCCloudAI performs speech-to-text in addition to chat. Transcribe
returns text in the spoken language, while Translate transcribes non-English
audio directly into English. Both are asynchronous and deliver their result to
OnTranscribeAudio. Set the provider's transcription model first —
Settings.OpenAITranscribeModel for OpenAI or Settings.MistralTranscribeModel
for Mistral.
procedure TForm1.TranscribeRecording;
begin
TMSFNCCloudAI1.Service := aiOpenAI;
TMSFNCCloudAI1.APIKeys.OpenAI := 'your-openai-api-key';
TMSFNCCloudAI1.Settings.OpenAITranscribeModel := 'whisper-1';
// For Mistral or Gemini, set Service accordingly and use Settings.MistralTranscribeModel.
TMSFNCCloudAI1.OnTranscribeAudio := AITranscribed;
// The language hint is optional (ISO code); pass '' to let the service auto-detect.
TMSFNCCloudAI1.Transcribe('C:\audio\meeting.mp3', 'en');
end;
procedure TForm1.AITranscribed(Sender: TObject; HttpStatusCode: integer;
HttpResult: string; Text: string);
begin
if HttpStatusCode = 200 then
Memo1.Lines.Text := Text
else
Memo1.Lines.Add('Transcription failed: ' + HttpResult);
end;
To translate foreign-language audio into English instead of transcribing it
verbatim, call Translate:
procedure TForm1.TranslateRecording;
begin
TMSFNCCloudAI1.Service := aiOpenAI;
TMSFNCCloudAI1.APIKeys.OpenAI := 'your-openai-api-key';
TMSFNCCloudAI1.Settings.OpenAITranscribeModel := 'whisper-1';
TMSFNCCloudAI1.OnTranscribeAudio := AITranscribed;
// Translate transcribes non-English audio and returns English text in OnTranscribeAudio.
TMSFNCCloudAI1.Translate('C:\audio\interview-es.mp3');
end;
Both methods also have an overload that accepts a TMemoryStream, which is handy
when the audio is captured in memory rather than saved to disk.
Tracking token usage
The Usage object accumulates token counters across every request the component
makes, so you can surface running cost or enforce a budget. Read PromptTokens,
CompletionTokens and TotalTokens at any time, and call Usage.Reset to start
a fresh accounting window. Audio requests additionally report AudioDuration and
AudioCharacters.
procedure TForm1.ShowUsage;
begin
// Usage accumulates across every request until Reset is called.
Label1.Caption := Format('Prompt: %d Completion: %d Total: %d',
[TMSFNCCloudAI1.Usage.PromptTokens,
TMSFNCCloudAI1.Usage.CompletionTokens,
TMSFNCCloudAI1.Usage.TotalTokens]);
end;
procedure TForm1.StartNewSession;
begin
TMSFNCCloudAI1.Usage.Reset; // clear the counters before a new billing window
end;
Usage keeps counting until you call Reset, so reset it at the start of each
logical session (per user, per document, per billing window) to keep the figures
meaningful.
Combining features: analysed document Q&A with usage
Real workflows combine several of the capabilities above. The example below submits a PDF as context, asks a reasoning-capable model to analyse it, resets the usage window beforehand, and reports the exact token cost of the analysis when the response arrives — document context, reasoning effort, and usage tracking working together in one request.
procedure TForm1.AnalyzeContract;
begin
TMSFNCCloudAI1.Service := aiOpenAI;
TMSFNCCloudAI1.APIKeys.OpenAI := 'your-openai-api-key';
TMSFNCCloudAI1.Settings.OpenAIModel := 'gpt-4o';
// Ask a reasoning-capable model to analyse the document carefully.
TMSFNCCloudAI1.Settings.Reasoning := aiHigh;
// Start a clean usage window so the counters reflect only this analysis.
TMSFNCCloudAI1.Usage.Reset;
TMSFNCCloudAI1.ClearFiles;
TMSFNCCloudAI1.AddFile('C:\docs\contract.pdf', aiftPDF);
TMSFNCCloudAI1.OnExecuted := ContractAnalyzed;
TMSFNCCloudAI1.Context.Text :=
'Identify any clauses that expose us to financial penalties and explain why.';
TMSFNCCloudAI1.Execute;
end;
procedure TForm1.ContractAnalyzed(Sender: TObject; AResponse: TTMSFNCCloudAIResponse;
AHttpStatusCode: Integer; AHttpResult: string);
begin
if (AHttpStatusCode = 200) and Assigned(AResponse) then
begin
Memo1.Lines.Text := AResponse.Content.Text;
StatusBar1.SimpleText := Format('Tokens - prompt: %d, completion: %d, total: %d',
[TMSFNCCloudAI1.Usage.PromptTokens,
TMSFNCCloudAI1.Usage.CompletionTokens,
TMSFNCCloudAI1.Usage.TotalTokens]);
end
else
Memo1.Lines.Add('Analysis failed: ' + AHttpResult);
end;
Common pitfalls
- Treating
Executeas synchronous. It returns immediately; read the result only insideOnExecuted(orOnTranscribeAudiofor audio). Do not inspectContextor any "result" property right after the call. - Not checking
AHttpStatusCode. On failureAResponsecan benil. Guard every handler with a status check and fall back toAHttpResultfor the error detail. - Freeing the
GetServices/GetActiveServiceslist. The list is the component's own internal object — copy its contents; never free it. - Leftover files between requests.
AddFile,AddTextandAddURLaccumulate. CallClearFilesbefore composing a new prompt or the model receives stale context. - Usage counters never resetting.
Usageis cumulative untilReset; a long-running app will keep adding to the totals across unrelated requests. - Setting the wrong model for the task. Text uses
Settings.OpenAIModel(and the per-service equivalents), transcription usesSettings.OpenAITranscribeModel/Settings.MistralTranscribeModel, and speech generation usesSettings.OpenAISoundModel.