AI+C#+过温预警分析
十年河东,十年河西,莫欺少年穷
using AliyunHelper.AliyunOts; using Aop.Api.Domain; using CoreDbContext; using CoreDbContext.Context; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.AI; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using OpenAI; using OpenAI.Chat; using PgSqlPublicContext.Context; using swapCommon; using swapCommon.Enums; using swapModels.ChargeService; using swapModels.EvlDtos; using System.ClientModel; using System.ComponentModel; using System.Text; using System.Text.Json; using static AliyunHelper.AliyunOts.OtsDeviceAlmTxsn; using Microsoft.Extensions.AI.Mcp; namespace OpenClawClient { class Program { static async Task Main() { ConfigurationBuilder builder = new ConfigurationBuilder(); builder.AddJsonFile("appsettings.json", true, true); var ConfigRoot = builder.Build();//根节点 IServiceCollection Services = new ServiceCollection(); Services.AddDbContext<swapDbContext>(options => options.UseSqlServer(ConfigRoot.GetConnectionString("swapDbContext")), ServiceLifetime.Transient); // Services.AddLogging(log => { log.AddConsole(); log.SetMinimumLevel(LogLevel.Error); }); Services.AddOptions().Configure<openAiOptions>(A => ConfigRoot.GetSection("openAiOptions").Bind(A)); IConfigurationRoot config = new ConfigurationBuilder() .AddUserSecrets<Program>() .Build(); string model = ConfigurationHelper.GetConfig("openAiOptions:Model"); string key = ConfigurationHelper.GetConfig("openAiOptions:aiKey"); string Url = ConfigurationHelper.GetConfig("openAiOptions:Uri"); var options = new OpenAIClientOptions { Endpoint = new Uri(Url) }; var credential = new ApiKeyCredential(key); IChatClient client = new OpenAIClient(credential, options) .GetChatClient(model) .AsIChatClient(); // ========== 调用电池数据 API ========== Console.WriteLine("📡 正在获取电池数据..."); var batteryData = GetBatteryDataAsync(); if (batteryData == null) { Console.WriteLine("❌ 获取电池数据失败,退出程序"); return; } string jsonData = JsonSerializer.Serialize(batteryData, new JsonSerializerOptions { WriteIndented = false }); Console.WriteLine($"✅ 数据大小:{jsonData.Length} 字符"); //:6886216 if (jsonData.Length > 500000) { Console.WriteLine("⚠️ 数据过大..."); return; } // ========== 构建提示词 ========== //{ Createtime=A.Createtime, Ri=A.Ri, Rv=A.Rv, Ti=A.Ti, Tt=A.Tt, Tv=A.Tv, Txsn=A.Txsn} string userPrompt = $""" 你是充电设备运营情况分析专家。请根据充电设备充电时间及充电时间前后1小时的充电数据,提取充电设备发生过温的共性。 ## 提取说明 - 从结果中提取信息,返回 JSON 格式。 - 只返回 JSON,不要任何其他文字。 -JSON 格式:List<T> [("Txsn": "充电设备编号","createtime": "预警时间","pointsPowerMax": "功率差大于60W的points充电数据的数量","pointsPowerMin": "功率差小于等于60W的points充电数据的数量","pointsPowerMax_2": "功率差大于60W的points_2充电数据的数量","pointsPowerMin_2": "功率差小于等于60W的points_2充电数据的数量","minTemp": "points充电数据最小温度", "maxTemp": points充电数据最大温度,"avgTemp": "points充电数据平均温度","minTemp_2": "points_2充电数据最小温度", "maxTemp_2": points_2充电数据最大温度,"avgTemp_2": "points_2充电数据平均温度","TempTime": "points充电数据最小温度上升至最大问题的时间(分钟)","TempTime_2": "points_2充电数据最小温度上升至最大问题的时间(分钟)", "maxPWM": "points充电数据中PWM最大值", "minPWM": "points充电数据中PWM最小值", "avgPWM": "points充电数据中PWM平均值", "maxPWM_2": "points_2充电数据中PWM最大值", "minPWM_2": "points_2充电数据中PWM最小值", "avgPWM_2": "points_2充电数据中PWM平均值")、......], "Info": "你给出的总结" ## 充电设备及充电数据结构 ```json {jsonData} ``` ## 充电设备及充电数据结构 ### 关联充电数据JSON格式: "txsn": "充电设备编号", "createtime": 充电数据采集点(会采集前后各10小时的数据),"points": "本次充电关联的温度介于25-50摄氏度之间的充电数据","points_2": "本次充电关联的温度大于80摄氏度充电数据,温度大于89时触发高温报警" ### 本次充电关联的充电数据的JSON格式: "Txsn": "充电设备编号", "Rv": 电池电压, "Ri": "电池电流" , "Tt": "充电设备的温度" , "Tv": "充电设备电压" , "Ti": "充电设备电流" ,"PWM": "PWM值" - 要结合充电数据进行共性分析 - 重要:功率差的计算方式为:Ti*Tv-Ri*Rv - 重要:minTemp为points[本次充电的关联充电数据]中最小温度 - 重要:maxTemp为points[本次充电的关联充电数据]中最大温度 - 重要:avgTemp为points[本次充电的关联充电数据]中平均温度 - 重要:minTemp_2为points_2[本次充电的关联充电数据]中最小温度 - 重要:maxTemp_2为points_2[本次充电的关联充电数据]中最大温度 - 重要:avgTemp_2为points_2[本次充电的关联充电数据]中平均温度 - 重要:TempTime为points中最小温度上升至points_2最大温度的时间,单位分钟 - 重要:PWM最大值/最小值/平均值参考[本次充电的关联充电数据]points中的PWM字段进行计算 - 重要:PWM_2最大值/最小值/平均值参考[本次充电的关联充电数据]points_2中的PWM字段进行计算 - 最重要:Info字段最重要,你需要根据提供的充电数据,整体分析共性问题,给出合理的总结,特别是points和points_2之间的对比。 记住,只返回json数据,无需其他中文。 """; // ========== 构建聊天历史 ========== List<Microsoft.Extensions.AI.ChatMessage> chatMessages = new List<Microsoft.Extensions.AI.ChatMessage> { new Microsoft.Extensions.AI.ChatMessage(ChatRole.System, """ 你是专业的充电设备过温分析助手,具备无线充电相关知识。 回答要专业、准确、易懂。 """), new Microsoft.Extensions.AI.ChatMessage(ChatRole.User, userPrompt) }; // ========== 流式输出 AI 响应 ========== Console.WriteLine("\n🤖 AI 分析报告:\n"); string response = ""; try { await foreach (ChatResponseUpdate item in client.GetStreamingResponseAsync(chatMessages)) { Console.Write(item.Text); response += item.Text; } Console.WriteLine("\n"); } catch (Exception ex) { Console.WriteLine($"\n❌ AI 响应失败:{ex.Message}"); return; } // ========== 保存对话历史 ========== chatMessages.Add(new Microsoft.Extensions.AI.ChatMessage(ChatRole.Assistant, response)); // 可选:保存到文件 await File.WriteAllTextAsync($"battery_analysis_{DateTime.Now:yyyyMMdd_HHmmss}.txt", response); Console.WriteLine("✅ 分析报告已保存"); } /// <summary> /// 调用电池数据 API{"Deviceno":"C2412A0210","Rxsn":"2510100071","stime":"2026-03-18T15:01:48","etime":"2026-03-19T01:28:00","pageNumber":1,"pageSize":1000} /// </summary> static List<CleanResult> GetBatteryDataAsync() { List<CleanResult> results = new List<CleanResult>(); using (var context = new postgerPublicDbContext()) { var rst = context.Chargerecords.Where(A => A.Rxsngroupid == "54954cd9-a088-4e22-a770-d20f5fdb31f3" && A.Begintime > Convert.ToDateTime("2026-05-05") && A.Begintime < Convert.ToDateTime("2026-05-15") && A.Chargetime > 360); foreach(var item in rst) { results.Add(new CleanResult() { txsn = item.Txsn, createtime = item.Begintime.Value }); } } foreach (var item in results) { var pointData = OtsHelper.QueryPointChargeingData(new SearchPointChargeingDto() { Txsn = item.txsn, stime = item.createtime, etime = item.createtime.AddHours(10), pageNumber = 1, pageSize = 10000, Msgtype=4 }); if (!pointData.data.Any(A => A.Tt > 89)) { continue; } item.points = pointData.data.Select(A => new PointChargeingResult() { Createtime = A.Createtime, Ri = Convert.ToDouble(A.Ri)/ Convert.ToDouble(100), Rv = Convert.ToDouble(A.Rv) / Convert.ToDouble(100), Ti = Convert.ToDouble(A.Ti) / Convert.ToDouble(100), Tt = A.Tt, Tv = Convert.ToDouble(A.Tv) / Convert.ToDouble(100), Txsn = A.Txsn, PWM = A.PWM }).Where(A=>((A.Tt>25&&A.Tt<50))).ToList(); item.points_2 = pointData.data.Select(A => new PointChargeingResult() { Createtime = A.Createtime, Ri = Convert.ToDouble(A.Ri) / Convert.ToDouble(100), Rv = Convert.ToDouble(A.Rv) / Convert.ToDouble(100), Ti = Convert.ToDouble(A.Ti) / Convert.ToDouble(100), Tt = A.Tt, Tv = Convert.ToDouble(A.Tv) / Convert.ToDouble(100), Txsn = A.Txsn, PWM = A.PWM }).Where(A => ((A.Tt > 80))).ToList(); } return results; } } public class DeviceAlmTxsnCleaner { /// <summary> /// 数据清洗 - 10 小时窗口内取中间时间点 /// </summary> /// <param name="data">原始数据列表</param> /// <returns>清洗后的 txsn 和时间点</returns> public List<CleanResult> CleanData(List<DeviceAlmTxsnOtsResult> data) { // 1. 按 txsn 分组 var grouped = data .Where(x => !string.IsNullOrEmpty(x.txsn) && x.policetime > 0) .GroupBy(x => x.txsn) .ToList(); var results = new List<CleanResult>(); foreach (var group in grouped) { // 2. 将时间戳转换为 DateTime 并排序 var sortedItems = group .Select(x => new { Original = x, Time = DateTimeOffset.FromUnixTimeMilliseconds(x.policetime).DateTime }) .OrderBy(x => x.Time) .ToList(); // 3. 按 10 小时窗口分组 var windows = new List<List<dynamic>>(); var currentWindow = new List<dynamic>(); foreach (var item in sortedItems) { if (currentWindow.Count == 0) { currentWindow.Add(item); } else { var firstTime = currentWindow.First().Time; var currentTime = item.Time; // 如果与窗口第一个时间相差 <= 10 小时,加入当前窗口 if ((currentTime - firstTime).TotalHours <= 10) { currentWindow.Add(item); } else { // 否则保存当前窗口,开始新窗口 windows.Add(currentWindow); currentWindow = new List<dynamic> { item }; } } } // 添加最后一个窗口 if (currentWindow.Count > 0) { windows.Add(currentWindow); } // 4. 每个窗口取中间时间点 foreach (var window in windows) { if (window.Count == 0) continue; DateTime midTime; if (window.Count == 1) { // 只有一条记录,直接取该时间 midTime = window.First().Time; } else { // 多条记录,取中间时间点 var minTime = window.Min(x => x.Time); var maxTime = window.Max(x => x.Time); midTime = minTime.AddMinutes((maxTime - minTime).TotalMinutes / 2); } results.Add(new CleanResult { txsn = group.Key, createtime = midTime }); } } return results.OrderBy(x => x.createtime).ToList(); } } /// <summary> /// 清洗结果 /// </summary> public class CleanResult { [Description("发射端编号")] public string txsn { get; set; } [Description("中间时间点")] public DateTime createtime { get; set; } public List<PointChargeingResult> points { get; set; } public List<PointChargeingResult> points_2 { get; set; } } public class PointChargeingResult { public long Createtime { get; set; } public DateTime CreatetimeCn { get { return TimeHelper.GetTime(Createtime, true); } } public string Txsn { get; set; } public double Tv { get; set; } public double Rv { get; set; } public double Ri { get; set; } public long Tt { get; set; } public double Ti { get; set; } public long PWM { get; set; } } }

浙公网安备 33010602011771号