This commit is contained in:
mmrbnjd
2025-08-21 16:40:31 +03:30
parent 69a75731ce
commit be9dc286e5
2 changed files with 183 additions and 63 deletions

View File

@@ -50,9 +50,26 @@ else
</div>
<div class="d-flex mb-2 justify-content-end">
@if (msg.responseText=="null" && msg.dateTime==new DateTime(1400,01,01))
{
<Spinner Type="SpinnerType.Dots" Class="me-3" Color="SpinnerColor.Info" />
}
else{
<div class="chat-bubble chat-mine">
@if (DelayShowResponse && messages.Last()==msg)
{
<TypewriterComponent Text="@msg.responseText" />
}
else
{
@msg.responseText
}
</div>
}
</div>
}
@@ -98,6 +115,7 @@ else
</div>
@code {
public bool DelayShowResponse { get; set; } = false;
ReadANDUpdate_CompanyDto? CompanyInfo = new();
[Parameter] public int CompanyID { get; set; }
List<aiResponseDto> messages = new();
@@ -146,10 +164,23 @@ else
if (string.IsNullOrWhiteSpace(inputText)) return;
disSend = true;
var dto = new aiNewResponseDto { companyId = CompanyID, aiKeyUser = aikeyUser, requestText = inputText };
var waiting = new aiResponseDto()
{
requestText = inputText,
responseText = "null",
dateTime = new(1400, 01, 01)
};
messages.Add(waiting);
await JS.InvokeVoidAsync("scrollToBottom", "ai-chat");
var okmodel = await conversationService.AiNewResponse(dto);
if (okmodel != null)
{
DelayShowResponse = true;
messages.Add(okmodel);
inputText = string.Empty;
StateHasChanged();
await JS.InvokeVoidAsync("scrollToBottom", "ai-chat");
@@ -158,6 +189,7 @@ else
{
toastService.Notify(new ToastMessage(ToastType.Danger, "ارسال ناموفق بود"));
}
messages.Remove(waiting);
disSend = false;
}
@@ -287,7 +319,6 @@ else
-webkit-text-fill-color: transparent;
background-clip: text;
}
</style>
<script>
@@ -325,5 +356,4 @@ else
color: #353;
border-top-right-radius: 0;
}
</style>

View File

@@ -0,0 +1,90 @@

@* File: Typewriter.razor *@
@inherits ComponentBase
@* <span>@_display</span> *@
@_display
@code {
[Parameter] public string Text { get; set; }
public int WordDelay { get; set; } = 100;
public bool StartOnRender { get; set; } = true;
// [Parameter] public EventCallback OnFinished { get; set; }
private string _display = string.Empty;
private string[] _words = Array.Empty<string>();
private int _index = 0;
private CancellationTokenSource? _cts;
private bool _isRunning = false;
protected override async Task OnParametersSetAsync()
{
// Prepare tokenized words once per parameter set
_words = string.IsNullOrWhiteSpace(Text)
? Array.Empty<string>()
: System.Text.RegularExpressions.Regex.Split(Text.Trim(), "\\s+");
if (StartOnRender && !_isRunning && _index == 0)
{
await StartAsync();
}
}
/// <summary>
/// Start typing from the current index.
/// </summary>
public async Task StartAsync()
{
if (_isRunning) return;
_cts?.Cancel();
_cts = new CancellationTokenSource();
var token = _cts.Token;
_isRunning = true;
try
{
while (_index < _words.Length && !token.IsCancellationRequested)
{
if (_index > 0)
{
_display += " ";
}
_display += _words[_index++];
await InvokeAsync(StateHasChanged);
await Task.Delay(Math.Max(0, WordDelay), token);
}
}
catch (TaskCanceledException) { }
finally
{
_isRunning = false;
// if (_index >= _words.Length && OnFinished.HasDelegate)
// {
// await OnFinished.InvokeAsync();
// }
}
}
/// <summary>
/// Pause typing (can be resumed with StartAsync()).
/// </summary>
public void Pause()
{
_cts?.Cancel();
_isRunning = false;
}
/// <summary>
/// Stop and reset the text to the beginning.
/// </summary>
public async Task ResetAsync()
{
Pause();
_display = string.Empty;
_index = 0;
await InvokeAsync(StateHasChanged);
}
}