using System.Text;
using Dpz.Core.Service.Network;
using Dpz.Core.Service.Network.Models;
using Dpz.Core.Service.RepositoryService;
using Hangfire;
using JetBrains.Annotations;
using Medallion.Threading;
using Microsoft.Extensions.Logging;
namespace Dpz.Core.Hangfire;
[UsedImplicitly]
public class AnalyzeCodeActivator(
ChatCompletionService chatCompletionService,
ICodeFileSystemEntryService codeFileSystemEntryService,
IDistributedLockProvider distributedLockProvider,
ILogger<AnalyzeCodeActivator> logger
) : JobActivator
{
/// <summary>
/// analyze code
/// </summary>
/// <param name="codeContent"></param>
/// <param name="path"></param>
/// <param name="fileName"></param>
[ProlongExpirationTime]
public async Task AnalyzeAsync(string codeContent, string[] path, string fileName)
{
if (GetContentLineCount(codeContent) < 50)
{
return;
}
var keyParts = new List<string>(path) { fileName };
var subKey = Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Join("\0", keyParts)));
var lockKey = $"AI_Analyze.Code.Lock:{subKey}";
await using (await distributedLockProvider.AcquireLockAsync(lockKey))
{
var entryPath = keyParts.ToArray();
var entry = await codeFileSystemEntryService.FindByPathWithoutCacheAsync(entryPath);
if (entry == null)
{
return;
}
var sourceHash = entry.Hash;
var hasFreshAnalyzeResult =
!string.IsNullOrWhiteSpace(entry.AiAnalyzeResult)
&& string.Equals(
entry.AiAnalyzeHash,
sourceHash,
StringComparison.OrdinalIgnoreCase
);
if (hasFreshAnalyzeResult)
{
return;
}
var prompt = new StringBuilder(codeContent)
.AppendLine()
.AppendLine()
.AppendLine("-------")
.AppendLine()
.AppendLine()
.Append("请解释一下上述代码的功能")
.ToString();
var result = await chatCompletionService.SendChatAsync(
[
new ChatMessage
{
Role = "system",
Message = "你是一个经验丰富且专业的开发人员",
},
new ChatMessage { Role = "user", Message = prompt },
],
x => x.Model = AiModel.Gpt5Mini
);
if (result is { Success: true, Data: not null })
{
logger.LogInformation(
"AI分析成功 | Path:{@Path} File:{FileName},Data:{@Data}",
path,
fileName,
result.Data
);
var content =
result.Data?.Choices.Count > 0
? result.Data.Choices[0].Message.Content
: string.Empty;
// 重新检查哈希值,以避免在 AI 调用期间源发生更改时写入过时的分析结果。
var latestEntry = await codeFileSystemEntryService.FindByPathWithoutCacheAsync(
entryPath
);
if (
latestEntry == null
|| !string.Equals(
latestEntry.Hash,
sourceHash,
StringComparison.OrdinalIgnoreCase
)
)
{
logger.LogInformation(
"跳过写入过期AI分析结果,文件已变更。Path:{@Path} File:{FileName} CurrentHash:{CurrentHash} AnalyzeHash:{AnalyzeHash}",
path,
fileName,
latestEntry?.Hash,
sourceHash
);
return;
}
await codeFileSystemEntryService.SaveAiAnalyzeResultAsync(
path,
fileName,
content,
sourceHash
);
return;
}
logger.LogWarning(
"AI分析失败 | 错误信息:{Message} | Path:{@Path} File:{FileName},Arguments:{@Arguments}",
result.Message,
path,
fileName,
result.Arguments
);
}
}
private static int GetContentLineCount(string codeContent)
{
return codeContent.Split(["\r\n", "\r", "\n"], StringSplitOptions.None).Length;
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
这段代码定义了一个名为 AnalyzeCodeActivator 的类,它是一个 Hangfire 任务激活器,主要用于分析代码并生成相应的注释或解释。以下是代码的主要功能和结构的详细解释:
类和构造函数
- 类定义:
AnalyzeCodeActivator继承自JobActivator,用于在 Hangfire 中激活任务。 - 构造函数: 接受四个参数:
AnalyzeService analyzeService: 用于与 AI 分析服务交互。ICodeNoteService codeNoteService: 用于处理代码注释的服务。IDistributedLockProvider distributedLockProvider: 用于提供分布式锁的服务,确保在并发情况下的安全性。ILogger<AnalyzeCodeActivator> logger: 用于记录日志的服务。
方法:AnalyzeAsync
参数:
string codeContent: 要分析的代码内容。string[] path: 代码文件的路径。string fileName: 代码文件的名称。
功能:
- 行数检查: 如果代码内容的行数少于 50 行,则直接返回,不进行分析。
- 生成锁键: 使用文件路径和文件名生成一个唯一的锁键,以确保同一时间只有一个分析任务在处理相同的文件。
- 获取分布式锁: 使用
distributedLockProvider获取锁,确保在并发环境下的安全性。 - 检查已有分析结果: 查询
codeNoteService,检查该文件是否已经有 AI 分析结果。如果有,则返回。 - 构建提示信息: 创建一个提示信息,要求 AI 解释代码的功能。
- 调用分析服务: 使用
analyzeService.ChatAsync方法与 AI 进行交互,发送构建的提示信息。 - 处理分析结果:
- 如果分析成功,记录成功日志,并将结果保存到
codeNoteService。 - 如果分析失败,记录警告日志,包含错误信息。
- 如果分析成功,记录成功日志,并将结果保存到
辅助方法:GetContentLineCount
- 功能: 计算给定代码内容的行数。使用
Split方法根据不同的换行符(\r\n,\r,\n)将内容分割成行,并返回行数。
总结
整体来看,这段代码的目的是在 Hangfire 任务中分析代码文件的内容,并通过 AI 生成相应的解释或注释。它确保了在并发环境下的安全性,并记录了分析的结果和可能的错误信息。
评论加载中...