fix errors
This commit is contained in:
@@ -9,40 +9,88 @@ namespace ChatBot.Migrations
|
||||
/// <inheritdoc />
|
||||
public partial class InitialCreate : Migration
|
||||
{
|
||||
private const string ChatSessionsTableName = "chat_sessions";
|
||||
private const string ChatMessagesTableName = "chat_messages";
|
||||
private const string ChatSessionsIdColumn = "id";
|
||||
private const string ChatMessagesSessionIdColumn = "session_id";
|
||||
private const string IntegerType = "integer";
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "chat_sessions",
|
||||
name: ChatSessionsTableName,
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
session_id = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
|
||||
id = table
|
||||
.Column<int>(type: IntegerType, nullable: false)
|
||||
.Annotation(
|
||||
"Npgsql:ValueGenerationStrategy",
|
||||
NpgsqlValueGenerationStrategy.IdentityByDefaultColumn
|
||||
),
|
||||
session_id = table.Column<string>(
|
||||
type: "character varying(50)",
|
||||
maxLength: 50,
|
||||
nullable: false
|
||||
),
|
||||
chat_id = table.Column<long>(type: "bigint", nullable: false),
|
||||
chat_type = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
|
||||
chat_title = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: false),
|
||||
model = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
||||
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
last_updated_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
max_history_length = table.Column<int>(type: "integer", nullable: false)
|
||||
chat_type = table.Column<string>(
|
||||
type: "character varying(20)",
|
||||
maxLength: 20,
|
||||
nullable: false
|
||||
),
|
||||
chat_title = table.Column<string>(
|
||||
type: "character varying(200)",
|
||||
maxLength: 200,
|
||||
nullable: false
|
||||
),
|
||||
model = table.Column<string>(
|
||||
type: "character varying(100)",
|
||||
maxLength: 100,
|
||||
nullable: false
|
||||
),
|
||||
created_at = table.Column<DateTime>(
|
||||
type: "timestamp with time zone",
|
||||
nullable: false
|
||||
),
|
||||
last_updated_at = table.Column<DateTime>(
|
||||
type: "timestamp with time zone",
|
||||
nullable: false
|
||||
),
|
||||
max_history_length = table.Column<int>(type: IntegerType, nullable: false),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_chat_sessions", x => x.id);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "chat_messages",
|
||||
name: ChatMessagesTableName,
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
session_id = table.Column<int>(type: "integer", nullable: false),
|
||||
content = table.Column<string>(type: "character varying(10000)", maxLength: 10000, nullable: false),
|
||||
role = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: false),
|
||||
created_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
message_order = table.Column<int>(type: "integer", nullable: false)
|
||||
id = table
|
||||
.Column<int>(type: IntegerType, nullable: false)
|
||||
.Annotation(
|
||||
"Npgsql:ValueGenerationStrategy",
|
||||
NpgsqlValueGenerationStrategy.IdentityByDefaultColumn
|
||||
),
|
||||
session_id = table.Column<int>(type: IntegerType, nullable: false),
|
||||
content = table.Column<string>(
|
||||
type: "character varying(10000)",
|
||||
maxLength: 10000,
|
||||
nullable: false
|
||||
),
|
||||
role = table.Column<string>(
|
||||
type: "character varying(20)",
|
||||
maxLength: 20,
|
||||
nullable: false
|
||||
),
|
||||
created_at = table.Column<DateTime>(
|
||||
type: "timestamp with time zone",
|
||||
nullable: false
|
||||
),
|
||||
message_order = table.Column<int>(type: IntegerType, nullable: false),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@@ -50,46 +98,51 @@ namespace ChatBot.Migrations
|
||||
table.ForeignKey(
|
||||
name: "FK_chat_messages_chat_sessions_session_id",
|
||||
column: x => x.session_id,
|
||||
principalTable: "chat_sessions",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
principalTable: ChatSessionsTableName,
|
||||
principalColumn: ChatSessionsIdColumn,
|
||||
onDelete: ReferentialAction.Cascade
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_chat_messages_created_at",
|
||||
table: "chat_messages",
|
||||
column: "created_at");
|
||||
table: ChatMessagesTableName,
|
||||
column: "created_at"
|
||||
);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_chat_messages_session_id",
|
||||
table: "chat_messages",
|
||||
column: "session_id");
|
||||
table: ChatMessagesTableName,
|
||||
column: ChatMessagesSessionIdColumn
|
||||
);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_chat_messages_session_id_message_order",
|
||||
table: "chat_messages",
|
||||
columns: new[] { "session_id", "message_order" });
|
||||
table: ChatMessagesTableName,
|
||||
columns: new[] { ChatMessagesSessionIdColumn, "message_order" }
|
||||
);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_chat_sessions_chat_id",
|
||||
table: "chat_sessions",
|
||||
column: "chat_id");
|
||||
table: ChatSessionsTableName,
|
||||
column: "chat_id"
|
||||
);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_chat_sessions_session_id",
|
||||
table: "chat_sessions",
|
||||
table: ChatSessionsTableName,
|
||||
column: "session_id",
|
||||
unique: true);
|
||||
unique: true
|
||||
);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "chat_messages");
|
||||
migrationBuilder.DropTable(name: ChatMessagesTableName);
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "chat_sessions");
|
||||
migrationBuilder.DropTable(name: ChatSessionsTableName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,94 +288,116 @@ namespace ChatBot.Services
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
const int maxRetries = 2; // Fewer retries for summarization to avoid delays
|
||||
const int maxRetries = 2;
|
||||
|
||||
for (int attempt = 1; attempt <= maxRetries; attempt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var chatRequest = new OllamaSharp.Models.Chat.ChatRequest
|
||||
{
|
||||
Messages = messages
|
||||
.Select(m => new OllamaSharp.Models.Chat.Message(m.Role, m.Content))
|
||||
.ToList(),
|
||||
Stream = false,
|
||||
Options = new OllamaSharp.Models.RequestOptions
|
||||
{
|
||||
Temperature = 0.3f, // Lower temperature for more focused summaries
|
||||
},
|
||||
};
|
||||
|
||||
// Create timeout cancellation token for compression operations
|
||||
using var timeoutCts = new CancellationTokenSource(
|
||||
TimeSpan.FromSeconds(_aiSettings.CompressionTimeoutSeconds)
|
||||
);
|
||||
using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(
|
||||
cancellationToken,
|
||||
timeoutCts.Token
|
||||
);
|
||||
|
||||
var response = new StringBuilder();
|
||||
await foreach (
|
||||
var chatResponse in _ollamaClient
|
||||
.ChatAsync(chatRequest)
|
||||
.WithCancellation(combinedCts.Token)
|
||||
)
|
||||
{
|
||||
if (chatResponse?.Message?.Content != null)
|
||||
{
|
||||
response.Append(chatResponse.Message.Content);
|
||||
}
|
||||
}
|
||||
|
||||
var result = response.ToString().Trim();
|
||||
return result.Length > _aiSettings.MaxSummarizedMessageLength
|
||||
? result.Substring(0, _aiSettings.MaxSummarizedMessageLength) + "..."
|
||||
: result;
|
||||
return await TryGenerateSummaryAsync(messages, cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
when (ex.InnerException is TaskCanceledException)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
ex,
|
||||
"Compression operation timed out after {TimeoutSeconds} seconds on attempt {Attempt}",
|
||||
_aiSettings.CompressionTimeoutSeconds,
|
||||
attempt
|
||||
);
|
||||
if (attempt == maxRetries)
|
||||
{
|
||||
if (HandleTimeoutAsync(attempt, maxRetries, ex))
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex) when (attempt < maxRetries)
|
||||
{
|
||||
var delay = 1000 * attempt; // Simple linear backoff for summarization
|
||||
_logger.LogWarning(
|
||||
ex,
|
||||
"Failed to generate AI summary on attempt {Attempt}/{MaxAttempts}. Retrying in {DelayMs}ms...",
|
||||
attempt,
|
||||
maxRetries,
|
||||
delay
|
||||
);
|
||||
await Task.Delay(delay, cancellationToken);
|
||||
await HandleHttpExceptionAsync(attempt, maxRetries, ex, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
ex,
|
||||
"Failed to generate AI summary on attempt {Attempt}",
|
||||
attempt
|
||||
);
|
||||
if (attempt == maxRetries)
|
||||
{
|
||||
if (HandleGenericExceptionAsync(attempt, maxRetries, ex))
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private async Task<string> TryGenerateSummaryAsync(
|
||||
List<ChatMessage> messages,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var chatRequest = CreateSummaryRequest(messages);
|
||||
using var timeoutCts = new CancellationTokenSource(
|
||||
TimeSpan.FromSeconds(_aiSettings.CompressionTimeoutSeconds)
|
||||
);
|
||||
using var combinedCts = CancellationTokenSource.CreateLinkedTokenSource(
|
||||
cancellationToken,
|
||||
timeoutCts.Token
|
||||
);
|
||||
|
||||
var response = new StringBuilder();
|
||||
await foreach (
|
||||
var chatResponse in _ollamaClient
|
||||
.ChatAsync(chatRequest)
|
||||
.WithCancellation(combinedCts.Token)
|
||||
)
|
||||
{
|
||||
if (chatResponse?.Message?.Content != null)
|
||||
{
|
||||
response.Append(chatResponse.Message.Content);
|
||||
}
|
||||
}
|
||||
|
||||
var result = response.ToString().Trim();
|
||||
return result.Length > _aiSettings.MaxSummarizedMessageLength
|
||||
? result.Substring(0, _aiSettings.MaxSummarizedMessageLength) + "..."
|
||||
: result;
|
||||
}
|
||||
|
||||
private static OllamaSharp.Models.Chat.ChatRequest CreateSummaryRequest(
|
||||
List<ChatMessage> messages
|
||||
)
|
||||
{
|
||||
return new OllamaSharp.Models.Chat.ChatRequest
|
||||
{
|
||||
Messages = messages
|
||||
.Select(m => new OllamaSharp.Models.Chat.Message(m.Role, m.Content))
|
||||
.ToList(),
|
||||
Stream = false,
|
||||
Options = new OllamaSharp.Models.RequestOptions { Temperature = 0.3f },
|
||||
};
|
||||
}
|
||||
|
||||
private bool HandleTimeoutAsync(int attempt, int maxRetries, OperationCanceledException ex)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
ex,
|
||||
"Compression operation timed out after {TimeoutSeconds} seconds on attempt {Attempt}",
|
||||
_aiSettings.CompressionTimeoutSeconds,
|
||||
attempt
|
||||
);
|
||||
return attempt == maxRetries;
|
||||
}
|
||||
|
||||
private async Task HandleHttpExceptionAsync(
|
||||
int attempt,
|
||||
int maxRetries,
|
||||
HttpRequestException ex,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var delay = 1000 * attempt;
|
||||
_logger.LogWarning(
|
||||
ex,
|
||||
"Failed to generate AI summary on attempt {Attempt}/{MaxAttempts}. Retrying in {DelayMs}ms...",
|
||||
attempt,
|
||||
maxRetries,
|
||||
delay
|
||||
);
|
||||
await Task.Delay(delay, cancellationToken);
|
||||
}
|
||||
|
||||
private bool HandleGenericExceptionAsync(int attempt, int maxRetries, Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to generate AI summary on attempt {Attempt}", attempt);
|
||||
return attempt == maxRetries;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a single message should be kept (not too short, not too long)
|
||||
/// </summary>
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace ChatBot.Services.Telegram.Commands
|
||||
/// <summary>
|
||||
/// Проверяет, есть ли аргументы у команды
|
||||
/// </summary>
|
||||
protected bool HasArguments(TelegramCommandContext context)
|
||||
protected static bool HasArguments(TelegramCommandContext context)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(context.Arguments);
|
||||
}
|
||||
@@ -61,7 +61,7 @@ namespace ChatBot.Services.Telegram.Commands
|
||||
/// <summary>
|
||||
/// Получает аргументы команды
|
||||
/// </summary>
|
||||
protected string GetArguments(TelegramCommandContext context)
|
||||
protected static string GetArguments(TelegramCommandContext context)
|
||||
{
|
||||
return context.Arguments;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user