使用了opensslsockets, fphttpclient, fpjson, jsonparse,cef4delphi,synedit,fpc_Markdown等单元,实现DeepSeek(只要兼容OpenAI接口就可以)或ollama本地部署的API Chat接口的流式接收的程序。
程序运行时的截图如下:

程序运行时的截图如下:

以下是精简后的代码【删除CEF4Delphi控件及与流接收功能无关的代码(可以正常编译运行)】:
unit LargeModels; {$Mode objfpc}{$H+} interface uses {$ifdef windows} Windows, {$endif} LCLIntf, Messages, SysUtils, Variants, Classes, Graphics, Menus, DB,process, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Types, ComCtrls, ClipBrd, DBGrids, Grids,fphttpclient, fpjson, jsonparser, HTTPThreadUnit, SynEdit; type ModelList=record Model:String; parameter_size:string; size:String; quantization_level:String; end; { TLargeModelFrm } TLargeModelFrm = class(TForm) Button1: TButton; Button2: TButton; Button4: TButton; ComboBox1: TComboBox; SynEdit1: TSynEdit; URLBox: TComboBox; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; Memo2: TMemo; Panel1: TPanel; Panel3: TPanel; Panel4: TPanel; Panel6: TPanel; StatusPnl: TPanel; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button4Click(Sender: TObject); procedure ComboBox1Change(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure updateModelList; procedure HandleStreamData(const Data: string); procedure LoadLargeModelAPI(question,urls,APIKey,modelType:string); procedure URLBoxChange(Sender: TObject); private ModelLists:array of ModelList; FHTTPThread: THTTPThread; // 保存线程引用 answerStr:String; RequestBody: TStringStream; StartTime:TDateTime; ollamapath:String; protected public end; var LargeModelFrm : TLargeModelFrm; implementation {$R *.lfm} procedure TLargeModelFrm.LoadLargeModelAPI(question,urls,APIkey,modelName:string); var JSONRequest: TJSONObject; begin if RequestBody<>nil then RequestBody.Free; RequestBody := TStringStream.Create('', TEncoding.UTF8); JSONRequest := TJSONObject.Create; try // 构建请求 JSON JSONRequest.Add('model', modelName); JSONRequest.Add('stream', true); JSONRequest.Add('messages', TJSONArray.Create([ TJSONObject.Create(['role', 'user', 'content', question])])); JSONRequest.Add('temperature', 0.7); // 设置请求头和 URL RequestBody.WriteString(JSONRequest.AsJSON); //启用多线程提交查询的问题 FHTTPThread := THTTPThread.Create(urls+'/v1/chat/completions',APIkey, RequestBody); FHTTPThread.OnStreamData := @HandleStreamData;//接收返回的答案 finally JSONRequest.Free; end; end; procedure TLargeModelFrm.URLBoxChange(Sender: TObject); begin Label1.Enabled:=true; ComboBox1.Enabled:=true; StatusPnl.Caption:=ComboBox1.Text+'【模型大小:'+ModelLists[ComboBox1.ItemIndex].size+' 模型参数(单位10亿):'+ModelLists[ComboBox1.ItemIndex].parameter_size+' 模型量化方案:'+ModelLists[ComboBox1.ItemIndex].quantization_level+'】'; end; //接收返回的答案 procedure TLargeModelFrm.HandleStreamData(const Data: string); begin answerStr:=answerStr+ Data; SynEdit1.Lines.Text:=answerStr; SynEdit1.TopLine:=SynEdit1.Lines.Count;//滚动到最后一行 Application.ProcessMessages; // 确保UI更新 end; procedure TLargeModelFrm.Button1Click(Sender: TObject); var Models,DeployType:String; begin if Memo2.Text<>'' Then begin answerStr:=''; StartTime:=now; SynEdit1.Lines.Add('-----------------------------------------'); SynEdit1.Lines.Add('使用的大模型:'+ComboBox1.Text); SynEdit1.Lines.Add('开始时间:'+DateTimeToStr(StartTime)); Panel6.Caption:=StatusPnl.Caption; if URLBox.ItemIndex<0 then URLBox.ItemIndex:=0; DeployType:=ComboBox1.Text; LoadLargeModelAPI(memo2.Text,URLBox.Text,'',DeployType); Button2.Enabled:=true; end; end; procedure TLargeModelFrm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin CanClose := True; Visible := False; end; //从Ollama取本地大模型列表 procedure TLargeModelFrm.updateModelList; var jData:TJSONData; jDataArr,jDataArr2:TJSONData; i,j:Integer; tempstr:String; HttpClient: TFPHttpClient; Response: String; begin HttpClient := TFPHttpClient.Create(nil); Response := HttpClient.Get(URLBox.Text+'/api/tags'); ComboBox1.Items.Clear; jData:=GetJSON(Response); jDataArr:=jData.FindPath('models'); i:=jDataArr.Count; SetLength(ModelLists,i); for j:=0 to i-1 do //列出已部署的大模型 begin jDataArr2:=jData.FindPath('models['+j.ToString+'].model'); tempstr:=jDataArr2.AsJSON; tempstr:= tempstr.Replace('"','',[rfReplaceAll,rfIgnoreCase]); ModelLists[j].Model:=tempstr; ComboBox1.Items.Add(tempstr); jDataArr2:=jData.FindPath('models['+j.ToString+'].size'); tempstr:=jDataArr2.AsJSON; tempstr:= tempstr.Replace('"','',[rfReplaceAll,rfIgnoreCase]); ModelLists[j].size:=tempstr; jDataArr2:=jData.FindPath('models['+j.ToString+'].details.parameter_size'); tempstr:=jDataArr2.AsJSON; tempstr:= tempstr.Replace('"','',[rfReplaceAll,rfIgnoreCase]); ModelLists[j].parameter_size:=tempstr; jDataArr2:=jData.FindPath('models['+j.ToString+'].details.quantization_level'); tempstr:=jDataArr2.AsJSON; tempstr:= tempstr.Replace('"','',[rfReplaceAll,rfIgnoreCase]); ModelLists[j].quantization_level:=tempstr; end; HttpClient.Free; ComboBox1.ItemIndex:=0; StatusPnl.Caption:=ComboBox1.Text+'【模型大小:'+ModelLists[ComboBox1.ItemIndex].size+' 模型参数(单位10亿):'+ModelLists[ComboBox1.ItemIndex].parameter_size+' 模型量化方案:'+ModelLists[ComboBox1.ItemIndex].quantization_level+'】'; end; procedure TLargeModelFrm.FormCreate(Sender: TObject); var i:Integer; begin updateModelList;//取本地大模型列表 Memo2.Lines.Clear; end; procedure TLargeModelFrm.FormDestroy(Sender: TObject); var s:String; begin if Assigned(FHTTPThread) then FreeAndNil(FHTTPThread); if Assigned(RequestBody) then RequestBody.Free; end; procedure TLargeModelFrm.Button2Click(Sender: TObject); begin if Assigned(FHTTPThread) then begin FHTTPThread.Terminate; // 触发终止 FHTTPThread.WaitFor; // 等待线程结束 FreeAndNil(FHTTPThread); // 释放线程 SynEdit1.Lines.Add('已终止请求'); Button2.Enabled:=False; end; end; procedure TLargeModelFrm.Button4Click(Sender: TObject); begin Memo2.Lines.Clear; end; procedure TLargeModelFrm.ComboBox1Change(Sender: TObject); begin StatusPnl.Caption:=ComboBox1.Text+'【模型大小:'+ModelLists[ComboBox1.ItemIndex].size+' 模型参数(单位10亿):'+ModelLists[ComboBox1.ItemIndex].parameter_size+' 模型量化方案:'+ModelLists[ComboBox1.ItemIndex].quantization_level+'】'; end; end.
LargeModels.lfm:
object LargeModelFrm: TLargeModelFrm Left = 0 Height = 1656 Top = 0 Width = 1836 Caption = 'Lazarus AI助手' ClientHeight = 1656 ClientWidth = 1836 Color = clBtnFace DesignTimePPI = 192 Font.Color = clWindowText Font.Height = -24 Font.Name = 'Tahoma' Position = poScreenCenter OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnDestroy = FormDestroy object StatusPnl: TPanel Left = 0 Height = 48 Top = 1608 Width = 1836 Align = alBottom BevelOuter = bvLowered ParentBackground = False TabOrder = 0 end object Panel1: TPanel Left = 0 Height = 1608 Top = 0 Width = 1836 Align = alClient ClientHeight = 1608 ClientWidth = 1836 ParentBackground = False TabOrder = 1 object Panel3: TPanel Left = 1 Height = 383 Top = 1224 Width = 1834 Align = alBottom ClientHeight = 383 ClientWidth = 1834 ParentBackground = False TabOrder = 0 object Label2: TLabel Left = 1337 Height = 1 Top = 24 Width = 1 ParentColor = False end object Button1: TButton Left = 1630 Height = 247 Top = 128 Width = 192 Anchors = [akTop, akRight, akBottom] Caption = '提问' TabOrder = 0 OnClick = Button1Click end object Label1: TLabel AnchorSideTop.Control = ComboBox1 AnchorSideTop.Side = asrCenter Left = 660 Height = 29 Top = 16 Width = 72 Caption = '大模型' end object Label3: TLabel AnchorSideTop.Side = asrCenter AnchorSideBottom.Control = Memo2 Left = 8 Height = 37 Top = 91 Width = 120 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Top = 5 Caption = '提问内容:' end object ComboBox1: TComboBox AnchorSideLeft.Control = Label1 AnchorSideLeft.Side = asrBottom Left = 737 Height = 37 Top = 12 Width = 496 BorderSpacing.Left = 5 ItemHeight = 29 ItemIndex = 0 Items.Strings = ( 'DeepSeek-v3' 'Kimi' ) Style = csDropDownList TabOrder = 1 Text = 'DeepSeek-v3' OnChange = ComboBox1Change end object Label4: TLabel AnchorSideTop.Side = asrCenter Left = 8 Height = 29 Top = 16 Width = 84 Caption = 'API地址' end object Label5: TLabel AnchorSideLeft.Control = ComboBox1 AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = ComboBox1 AnchorSideTop.Side = asrCenter Left = 1243 Height = 1 Top = 30 Width = 1 BorderSpacing.Left = 10 end object Memo2: TMemo Left = 8 Height = 247 Top = 128 Width = 1614 Anchors = [akTop, akLeft, akRight, akBottom] Lines.Strings = ( 'lazarus编写计算MD5的程序' ) ScrollBars = ssBoth TabOrder = 2 end object Button2: TButton AnchorSideTop.Control = ComboBox1 AnchorSideTop.Side = asrBottom AnchorSideBottom.Control = Memo2 Left = 1630 Height = 64 Top = 59 Width = 192 Anchors = [akTop, akRight, akBottom] BorderSpacing.Top = 10 BorderSpacing.Bottom = 5 Caption = '中止思考' Enabled = False TabOrder = 3 OnClick = Button2Click end object Button4: TButton AnchorSideTop.Control = ComboBox1 AnchorSideTop.Side = asrBottom AnchorSideBottom.Control = Memo2 Left = 1384 Height = 64 Top = 59 Width = 231 Anchors = [akTop, akRight, akBottom] BorderSpacing.Top = 10 BorderSpacing.Bottom = 5 Caption = '清空提问内容' TabOrder = 4 OnClick = Button4Click end object URLBox: TComboBox Left = 96 Height = 37 Top = 12 Width = 544 ItemHeight = 29 ItemIndex = 0 Items.Strings = ( 'http://localhost:11434' ) Style = csDropDownList TabOrder = 5 Text = 'http://localhost:11434' OnChange = URLBoxChange end end object Panel4: TPanel Left = 1 Height = 1223 Top = 1 Width = 1834 Align = alClient ClientHeight = 1223 ClientWidth = 1834 ParentBackground = False TabOrder = 1 object Panel6: TPanel Left = 1 Height = 47 Top = 1 Width = 1832 Align = alTop BevelOuter = bvNone ParentBackground = False TabOrder = 0 end inline SynEdit1: TSynEdit Left = 1 Height = 1174 Top = 48 Width = 1832 Align = alClient Anchors = [akTop, akLeft, akRight] Font.CharSet = ANSI_CHARSET Font.Height = -24 Font.Name = 'Courier New' Font.Pitch = fpFixed Font.Quality = fqDraft ParentColor = False ParentFont = False TabOrder = 1 Gutter.Width = 109 Gutter.MouseActions = <> RightGutter.Width = 0 RightGutter.MouseActions = <> Keystrokes = < item Command = ecUp ShortCut = 38 end item Command = ecSelUp ShortCut = 8230 end item Command = ecScrollUp ShortCut = 16422 end item Command = ecDown ShortCut = 40 end item Command = ecSelDown ShortCut = 8232 end item Command = ecScrollDown ShortCut = 16424 end item Command = ecLeft ShortCut = 37 end item Command = ecSelLeft ShortCut = 8229 end item Command = ecWordLeft ShortCut = 16421 end item Command = ecSelWordLeft ShortCut = 24613 end item Command = ecRight ShortCut = 39 end item Command = ecSelRight ShortCut = 8231 end item Command = ecWordRight ShortCut = 16423 end item Command = ecSelWordRight ShortCut = 24615 end item Command = ecPageDown ShortCut = 34 end item Command = ecSelPageDown ShortCut = 8226 end item Command = ecPageBottom ShortCut = 16418 end item Command = ecSelPageBottom ShortCut = 24610 end item Command = ecPageUp ShortCut = 33 end item Command = ecSelPageUp ShortCut = 8225 end item Command = ecPageTop ShortCut = 16417 end item Command = ecSelPageTop ShortCut = 24609 end item Command = ecLineStart ShortCut = 36 end item Command = ecSelLineStart ShortCut = 8228 end item Command = ecEditorTop ShortCut = 16420 end item Command = ecSelEditorTop ShortCut = 24612 end item Command = ecLineEnd ShortCut = 35 end item Command = ecSelLineEnd ShortCut = 8227 end item Command = ecEditorBottom ShortCut = 16419 end item Command = ecSelEditorBottom ShortCut = 24611 end item Command = ecToggleMode ShortCut = 45 end item Command = ecCopy ShortCut = 16429 end item Command = ecPaste ShortCut = 8237 end item Command = ecDeleteChar ShortCut = 46 end item Command = ecCut ShortCut = 8238 end item Command = ecDeleteLastChar ShortCut = 8 end item Command = ecDeleteLastChar ShortCut = 8200 end item Command = ecDeleteLastWord ShortCut = 16392 end item Command = ecUndo ShortCut = 32776 end item Command = ecRedo ShortCut = 40968 end item Command = ecLineBreak ShortCut = 13 end item Command = ecSelectAll ShortCut = 16449 end item Command = ecCopy ShortCut = 16451 end item Command = ecBlockIndent ShortCut = 16457 end item Command = ecLineBreak ShortCut = 16461 end item Command = ecInsertLine ShortCut = 16462 end item Command = ecDeleteWord ShortCut = 16468 end item Command = ecBlockUnindent ShortCut = 16469 end item Command = ecPaste ShortCut = 16470 end item Command = ecCut ShortCut = 16472 end item Command = ecDeleteLine ShortCut = 16473 end item Command = ecDeleteEOL ShortCut = 24665 end item Command = ecUndo ShortCut = 16474 end item Command = ecRedo ShortCut = 24666 end item Command = ecGotoMarker0 ShortCut = 16432 end item Command = ecGotoMarker1 ShortCut = 16433 end item Command = ecGotoMarker2 ShortCut = 16434 end item Command = ecGotoMarker3 ShortCut = 16435 end item Command = ecGotoMarker4 ShortCut = 16436 end item Command = ecGotoMarker5 ShortCut = 16437 end item Command = ecGotoMarker6 ShortCut = 16438 end item Command = ecGotoMarker7 ShortCut = 16439 end item Command = ecGotoMarker8 ShortCut = 16440 end item Command = ecGotoMarker9 ShortCut = 16441 end item Command = ecSetMarker0 ShortCut = 24624 end item Command = ecSetMarker1 ShortCut = 24625 end item Command = ecSetMarker2 ShortCut = 24626 end item Command = ecSetMarker3 ShortCut = 24627 end item Command = ecSetMarker4 ShortCut = 24628 end item Command = ecSetMarker5 ShortCut = 24629 end item Command = ecSetMarker6 ShortCut = 24630 end item Command = ecSetMarker7 ShortCut = 24631 end item Command = ecSetMarker8 ShortCut = 24632 end item Command = ecSetMarker9 ShortCut = 24633 end item Command = EcFoldLevel1 ShortCut = 41009 end item Command = EcFoldLevel2 ShortCut = 41010 end item Command = EcFoldLevel3 ShortCut = 41011 end item Command = EcFoldLevel4 ShortCut = 41012 end item Command = EcFoldLevel5 ShortCut = 41013 end item Command = EcFoldLevel6 ShortCut = 41014 end item Command = EcFoldLevel7 ShortCut = 41015 end item Command = EcFoldLevel8 ShortCut = 41016 end item Command = EcFoldLevel9 ShortCut = 41017 end item Command = EcFoldLevel0 ShortCut = 41008 end item Command = EcFoldCurrent ShortCut = 41005 end item Command = EcUnFoldCurrent ShortCut = 41003 end item Command = EcToggleMarkupWord ShortCut = 32845 end item Command = ecNormalSelect ShortCut = 24654 end item Command = ecColumnSelect ShortCut = 24643 end item Command = ecLineSelect ShortCut = 24652 end item Command = ecTab ShortCut = 9 end item Command = ecShiftTab ShortCut = 8201 end item Command = ecMatchBracket ShortCut = 24642 end item Command = ecColSelUp ShortCut = 40998 end item Command = ecColSelDown ShortCut = 41000 end item Command = ecColSelLeft ShortCut = 40997 end item Command = ecColSelRight ShortCut = 40999 end item Command = ecColSelPageDown ShortCut = 40994 end item Command = ecColSelPageBottom ShortCut = 57378 end item Command = ecColSelPageUp ShortCut = 40993 end item Command = ecColSelPageTop ShortCut = 57377 end item Command = ecColSelLineStart ShortCut = 40996 end item Command = ecColSelLineEnd ShortCut = 40995 end item Command = ecColSelEditorTop ShortCut = 57380 end item Command = ecColSelEditorBottom ShortCut = 57379 end> MouseActions = <> MouseTextActions = <> MouseSelActions = <> VisibleSpecialChars = [vscSpace, vscTabAtLast] ReadOnly = True SelectedColor.BackPriority = 50 SelectedColor.ForePriority = 50 SelectedColor.FramePriority = 50 SelectedColor.BoldPriority = 50 SelectedColor.ItalicPriority = 50 SelectedColor.UnderlinePriority = 50 SelectedColor.StrikeOutPriority = 50 BracketHighlightStyle = sbhsBoth BracketMatchColor.Background = clNone BracketMatchColor.Foreground = clNone BracketMatchColor.Style = [fsBold] FoldedCodeColor.Background = clNone FoldedCodeColor.Foreground = clGray FoldedCodeColor.FrameColor = clGray MouseLinkColor.Background = clNone MouseLinkColor.Foreground = clBlue LineHighlightColor.Background = clNone LineHighlightColor.Foreground = clNone inline SynLeftGutterPartList1: TSynGutterPartList object SynGutterMarks1: TSynGutterMarks Width = 48 MouseActions = <> MaxExtraMarksColums = 0 Options = [sgmoDeDuplicateMarksOnOverflow] end object SynGutterLineNumber1: TSynGutterLineNumber Width = 29 MouseActions = <> MarkupInfo.Background = clBtnFace MarkupInfo.Foreground = clNone DigitCount = 2 ShowOnlyLineNumbersMultiplesOf = 1 ZeroStart = False LeadingZeros = False end object SynGutterChanges1: TSynGutterChanges Width = 8 MouseActions = <> ModifiedColor = 59900 SavedColor = clGreen end object SynGutterSeparator1: TSynGutterSeparator Width = 4 MouseActions = <> MarkupInfo.Background = clWhite MarkupInfo.Foreground = clGray end object SynGutterCodeFolding1: TSynGutterCodeFolding Width = 20 MouseActions = <> MarkupInfo.Background = clNone MarkupInfo.Foreground = clGray MouseActionsExpanded = <> MouseActionsCollapsed = <> end end end end end end
HTTPThreadUnit.pas:
unit HTTPThreadUnit; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fphttpclient, opensslsockets,//使用HTTPS时引用这个单元,需要用到libeay32.dll和ssleay32.dll // ssockets, sslsockets,--使用HTTPS时引用这2个单元需要用到libcrypto-1_1-x64.dll/libssl-1_1-x64.dll fpjson, jsonparser; type TStreamDataEvent = procedure(const Data: string) of object; THTTPThread = class(TThread) private FTerminated: Boolean; //终止标志 FURL: string; FRequestStream: TStringStream; FClient: TFPHttpClient; FResponseStream:TStringStream; FBuffer: string; FOnStreamData: TStreamDataEvent; procedure DataReceivedHandler(Sender: TObject; const ContentLength, CurrentPos: Int64); procedure HandleEvent(const EventData: string); procedure ProcessData; procedure DoStreamData(const Data: string); protected procedure Execute; override; public constructor Create(const URL,APIKey: string; RequestStream: TStringStream); destructor Destroy; override; procedure Terminate; // 终止方法 property OnStreamData: TStreamDataEvent read FOnStreamData write FOnStreamData; end; implementation constructor THTTPThread.Create(const URL,APIKey: string; RequestStream: TStringStream); begin inherited Create(True); FURL := URL; FRequestStream:= RequestStream; FResponseStream := TStringStream.Create('', TEncoding.UTF8); FClient := TFPHttpClient.Create(nil); FClient.OnDataReceived := @DataReceivedHandler; FClient.RequestHeaders.Add('Accept: text/event-stream'); FClient.RequestHeaders.Add('Content-Type: application/json'); FClient.AddHeader('Authorization','Bearer '+ APIKey); FClient.RequestBody:=RequestStream; Start; end; destructor THTTPThread.Destroy; begin FResponseStream.Free; FClient.Free; inherited Destroy; end; procedure THTTPThread.Execute; begin try FClient.post(FURL, FResponseStream); except on E: Exception do if not FTerminated then // 仅处理非主动终止的异常 DoStreamData('Error: ' + E.Message); end; end; procedure THTTPThread.Terminate; begin FTerminated := True; if Assigned(FClient) then FClient.Terminate;// 强制断开连接以终止阻塞请求 end; procedure THTTPThread.DataReceivedHandler(Sender: TObject; const ContentLength, CurrentPos: Int64); begin if FTerminated then Exit; // 如果已终止则跳过处理 Synchronize(@ProcessData); end; procedure THTTPThread.ProcessData; var DataStr: string; EventEndPos: Integer; begin FResponseStream.Position := 0; SetLength(DataStr, FResponseStream.Size); FResponseStream.ReadBuffer(DataStr[1], FResponseStream.Size); FResponseStream.Clear; FBuffer := FBuffer + DataStr; repeat EventEndPos := Pos(#10#10, FBuffer); if EventEndPos > 0 then begin HandleEvent(Copy(FBuffer, 1, EventEndPos - 1)); Delete(FBuffer, 1, EventEndPos + 1); end; until EventEndPos = 0; end; procedure THTTPThread.HandleEvent(const EventData: string); var Lines: TStringList; i: Integer; DataLine, JSONData: string; JSON: TJSONData; begin Lines := TStringList.Create; try Lines.Text := StringReplace(EventData, #10, sLineBreak, [rfReplaceAll]); for i := 0 to Lines.Count - 1 do begin DataLine := Lines[i]; if Pos('data: ', DataLine) = 1 then begin JSONData := Trim(Copy(DataLine, 6, MaxInt)); if JSONData <> '' then begin if JSONData<>'[DONE]' then begin try JSON := GetJSON(JSONData); try if JSON.FindPath('choices[0].delta.content') <> nil then DoStreamData(JSON.FindPath('choices[0].delta.content').AsString); finally JSON.Free; end; except on E: Exception do DoStreamData('JSON Error: ' + E.Message); end; end; end; end; end; finally Lines.Free; end; end; procedure THTTPThread.DoStreamData(const Data: string); begin if Assigned(FOnStreamData) then FOnStreamData(Data); end; end.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)