CrazyIter_Bin 8 ماه پیش
والد
کامیت
23c8af4daf

+ 388 - 189
TEAMModelOS.Extension/HTEX.Test/Controllers/LessonRecordController.cs

@@ -17,6 +17,8 @@ using System.Diagnostics;
 using Microsoft.OData.UriParser;
 using HTEX.Test.Service;
 using System.IO;
+using static Pipelines.Sockets.Unofficial.SocketConnection;
+using static HTEX.Test.Controllers.LessonRecordController;
 
 namespace HTEX.Test.Controllers
 {
@@ -138,22 +140,7 @@ namespace HTEX.Test.Controllers
           
         }
         
-        
-        public static List<string> ListAllFiles(string directoryPath)
-        {
-            List<string> filePaths = new List<string>();
-            DirectoryInfo dirInfo = new DirectoryInfo(directoryPath);
-
-            // 获取目录下的所有文件(包括子目录中的文件)
-            FileInfo[] files = dirInfo.GetFiles("*", SearchOption.AllDirectories);
-
-            foreach (FileInfo file in files)
-            {
-                filePaths.Add(file.FullName);
-               // Console.WriteLine(file.FullName);
-            }
-            return filePaths;
-        }
+   
         [HttpPost("process-preview")]
         public async Task<IActionResult> ProcessPreview(JsonElement json)
         {
@@ -169,83 +156,178 @@ namespace HTEX.Test.Controllers
             "smartRatingCount": 0,
             "timeCount":
              */
-            await Parallel.ForEachAsync(files, async( item, _) => 
-            {
-                if (item.EndsWith("count.json"))
+            bool  loadLocal = true;
+            LessonDataAnlysis lessonDataAnlysis = new LessonDataAnlysis();
+            var files_anlysis = files.Where(x => x.EndsWith("anlysis.json")).Take(1).FirstOrDefault();
+            if (files_anlysis!=null) {
+                string jsons = await System.IO.File.ReadAllTextAsync(files_anlysis);
+                lessonDataAnlysis= jsons.ToObject<LessonDataAnlysis>();
+                loadLocal=false; 
+            }
+            if (loadLocal) {
+                foreach (var item in files)
                 {
-                    string jsons = await System.IO.File.ReadAllTextAsync(item);
-                    TechCount count=  jsons.ToObject<TechCount>();
-                    var pickupResult =  count.timeCount.Where(x => x.code.Equals("PickupResult", StringComparison.OrdinalIgnoreCase));
-                    if (count.examCount==0)
+                    if (item.EndsWith("count.json"))
                     {
+                        string jsons = await System.IO.File.ReadAllTextAsync(item);
+                        TechCount count = jsons.ToObject<TechCount>();
+                        var pickupResult = count.timeCount.Where(x => x.code.Equals("PickupResult", StringComparison.OrdinalIgnoreCase));
+                        int pickCount = 0;
                         if (pickupResult!=null && pickupResult.Count()>0)
                         {
-                            count.interactNormalCount+=pickupResult.Sum(x => (int)x.value);
+                            pickCount+=pickupResult.Sum(x => (int)x.value);
                         }
-                        count.interactNormalCount+=count.irsCount;
-                        
-                    }
-                    if (pickupResult!=null && pickupResult.Count()>0)
-                    {
-                        count.interactExamCount+=pickupResult.Sum(x => (int)x.value);
+                        count.interactNormalCount=pickCount+  count.irsCount;
+
+                        count.lessonId=item.Replace("-count.json", "").Replace(path, "").Replace("\\", "");
+                        string localjson = await System.IO.File.ReadAllTextAsync($"{path}\\{count.lessonId}-local.json");
+                        var lessonLocal  = localjson.ToObject<LessonLocal>();
+                        if (lessonLocal?.lessonBase?.summary!=null) {
+                            count.smartRatingCountBase=lessonLocal.lessonBase.summary.smartRatingCount;
+                            count.irsCountBase=lessonLocal.lessonBase.summary.interactionCount;
+                            count.taskCountBase=lessonLocal.lessonBase.summary.collateTaskCount;
+                            count.coworkCountBase=lessonLocal.lessonBase.summary.coworkTaskCount;
+                            count.examCountBase=lessonLocal.lessonBase.summary.examCount;
+                            count.interactNormalCountBase= count.interactNormalCount;
+                        }
+                        if (lessonLocal?.lessonBase?.report?.clientSummaryList!=null)
+                        {
+                            count.pscore= lessonLocal.lessonBase.report.clientSummaryList.Where(x=>x.score>0).Select(x => x.score);
+                            count.gscore= lessonLocal.lessonBase.report.clientSummaryList.Where(x => x.groupScore>0).Select(x => x.groupScore);
+                            count.tscore= lessonLocal.lessonBase.report.clientSummaryList.Where(x => x.interactScore>0).Select(x => x.interactScore);
+                        }
+                        await System.IO.File.WriteAllTextAsync(item, count.ToJsonString());
+                        techCounts.Add(count);
                     }
-                    count.interactExamCount+=count.irsCount;
+                }
+                Console.WriteLine($"techCounts:{techCounts.Count}");
+                //标准差偏差N倍,视为异常数据
+                int thresholdMultiplier = 2;
+                lessonDataAnlysis.pscore  = techCounts.SelectMany(x =>x.pscore);
+                lessonDataAnlysis.pscore= CleanDataBySDThreshold(lessonDataAnlysis.pscore, thresholdMultiplier).OrderBy(x => x);
+                List<KeyValuePair<double, List<double>>> clustersDataPscore = new();
+                var clusterPscore = KMeansService.KMeans(lessonDataAnlysis.pscore.Select(x => x).OrderBy(x => x));
+                foreach (var item in clusterPscore)
+                {
+                    Console.WriteLine($"dp:{item.Key} ,avg: {item.Value.Average()}, count: {item.Value.Count}, min:{item.Value.Min()}, max:{item.Value.Max()}");
+                }
+                Console.WriteLine($"avg: {lessonDataAnlysis.pscore.Average()}");
 
-                    count.lessonId=item.Replace("-count.json", "").Replace(path,"").Replace("\\","");
-                    //string jsonl = await System.IO.File.ReadAllTextAsync($"F:\\lesson-local\\{count.lessonId}-local.json");
-                    //LessonLocal lesson = jsonl.ToObject<LessonLocal>();
-                    //if (!string.IsNullOrWhiteSpace(lesson.lessonRecord?.school) ) 
-                    //{
-                    //    if (!lesson.lessonRecord.school.Equals("hbcn")&& !lesson.lessonRecord.school.Equals("habook")) 
-                    //    {
-                           
-                    //    }
-                    //}
-                    techCounts.Add(count);
+                foreach (var s in clusterPscore.OrderBy(x => x.Key))
+                {
+                    clustersDataPscore.Add(s);
                 }
-            });
-     
-            //标准差偏差N倍,视为异常数据
-            int thresholdMultiplier = 2;
-            var cowork = techCounts.Where(x => x.coworkCount>0).Select(x => (double)x.coworkCount);
-            cowork= CleanDataBySDThreshold(cowork, thresholdMultiplier);
+                lessonDataAnlysis.clustersPscore=clustersDataPscore;
 
-            var task = techCounts.Where(x => x.taskCount > 0).Select(x => (double)x.taskCount);
-            task= CleanDataBySDThreshold(task, thresholdMultiplier);
+                lessonDataAnlysis.gscore  = techCounts.SelectMany(x => x.gscore);
+                lessonDataAnlysis.gscore= CleanDataBySDThreshold(lessonDataAnlysis.gscore, thresholdMultiplier).OrderBy(x => x);
+                List<KeyValuePair<double, List<double>>> clustersDataGscore = new();
+                var clusterGscore = KMeansService.KMeans(lessonDataAnlysis.gscore.Select(x => x).OrderBy(x => x));
+                foreach (var item in clusterGscore)
+                {
+                    Console.WriteLine($"dp:{item.Key} ,avg: {item.Value.Average()}, count: {item.Value.Count}, min:{item.Value.Min()}, max:{item.Value.Max()}");
+                }
+                Console.WriteLine($"avg: {lessonDataAnlysis.gscore.Average()}");
 
-            var irs = techCounts.Where(x => x.irsCount > 0).Select(x => (double)x.irsCount);
-            irs = CleanDataBySDThreshold(irs, thresholdMultiplier);
+                foreach (var s in clusterGscore.OrderBy(x => x.Key))
+                {
+                    clustersDataGscore.Add(s);
+                }
+                lessonDataAnlysis.clustersGscore=clustersDataGscore;
 
-            var exam = techCounts.Where(x => x.examCount > 0).Select(x => (double)x.examCount);
-            exam= CleanDataBySDThreshold(exam, thresholdMultiplier);
 
-            var smartRating = techCounts.Where(x => x.smartRatingCount > 0).Select(x => (double)x.smartRatingCount);
-            smartRating= CleanDataBySDThreshold(smartRating, thresholdMultiplier);
+                lessonDataAnlysis.tscore  = techCounts.SelectMany(x => x.tscore);
+                lessonDataAnlysis.tscore= CleanDataBySDThreshold(lessonDataAnlysis.tscore, thresholdMultiplier).OrderBy(x => x);
+                List<KeyValuePair<double, List<double>>> clustersDataTscore = new();
+                var clusterTscore = KMeansService.KMeans(lessonDataAnlysis.tscore.Select(x => x).OrderBy(x => x));
+                foreach (var item in clusterTscore)
+                {
+                    Console.WriteLine($"dp:{item.Key} ,avg: {item.Value.Average()}, count: {item.Value.Count}, min:{item.Value.Min()}, max:{item.Value.Max()}");
+                }
+                Console.WriteLine($"avg: {lessonDataAnlysis.tscore.Average()}");
+                foreach (var s in clusterTscore.OrderBy(x => x.Key))
+                {
+                    clustersDataTscore.Add(s);
+                }
+                lessonDataAnlysis.clustersTscore=clustersDataTscore;
 
-            var interactExam = techCounts.Where(x => x.interactExamCount > 0).Select(x => (double)x.interactExamCount);
-            interactExam= CleanDataBySDThreshold(interactExam, thresholdMultiplier).OrderBy(x=>x);
 
-            var interactNormal = techCounts.Where(x => x.interactNormalCount > 0).Select(x => (double)x.interactNormalCount);
-            interactNormal= CleanDataBySDThreshold(interactNormal, thresholdMultiplier).OrderBy(x => x);
-            //var tcount = techCounts.Where(x => x.coworkCount > 0  || x.taskCount>0  || x.irsCount>0|| x.examCount>0  || x.smartRatingCount>0);
-            //double coworkWeight = cowork.Count()*1.0/tcount.Count();
-            //double taskWeight = task.Count()*1.0/tcount.Count();
-            //double irsWeight =   irs.Count()*1.0/tcount.Count();
-            //double examWeight = exam.Count()*1.0/tcount.Count();
-            //double smartRatingWeight = smartRating.Count()*1.0/tcount.Count();
+                lessonDataAnlysis.cowork = techCounts.Where(x => x.coworkCount>0).Select(x => (double)x.coworkCount);
+                lessonDataAnlysis.cowork= CleanDataBySDThreshold(lessonDataAnlysis.cowork, thresholdMultiplier);
 
+                lessonDataAnlysis.coworkBase = techCounts.Where(x => x.coworkCountBase>0).Select(x => (double)x.coworkCountBase);
+                lessonDataAnlysis.coworkBase= CleanDataBySDThreshold(lessonDataAnlysis.coworkBase, thresholdMultiplier);
 
-            var groups = techCounts.SelectMany(x => x.timeCount).GroupBy(x => x.code).Select(x => new { key = x.Key, list = x.ToList() });
-            Dictionary<string,IEnumerable<double>> techDict= new Dictionary<string, IEnumerable<double>>();
-            foreach (var group in groups) 
-            {
-                var array =   group.list.Where(x => x.value>0).Select(x =>(double) x.value);
-                array = CleanDataBySDThreshold(array, thresholdMultiplier);
-                techDict.Add(group.key, array);
+                lessonDataAnlysis.task = techCounts.Where(x => x.taskCount > 0).Select(x => (double)x.taskCount);
+                lessonDataAnlysis.task= CleanDataBySDThreshold(lessonDataAnlysis.task, thresholdMultiplier);
+
+                lessonDataAnlysis.taskBase = techCounts.Where(x => x.taskCountBase  > 0).Select(x => (double)x.taskCountBase);
+                lessonDataAnlysis.taskBase = CleanDataBySDThreshold(lessonDataAnlysis.taskBase, thresholdMultiplier);
+
+
+                lessonDataAnlysis.exam  = techCounts.Where(x => x.examCount  > 0).Select(x => (double)x.examCount);
+                lessonDataAnlysis.exam = CleanDataBySDThreshold(lessonDataAnlysis.exam, thresholdMultiplier);
+
+                lessonDataAnlysis.examBase  = techCounts.Where(x => x.examCountBase  > 0).Select(x => (double)x.examCountBase);
+                lessonDataAnlysis.examBase = CleanDataBySDThreshold(lessonDataAnlysis.examBase, thresholdMultiplier);
+
+
+                lessonDataAnlysis.smartRating  = techCounts.Where(x => x.smartRatingCount  > 0).Select(x => (double)x.smartRatingCount);
+                lessonDataAnlysis.smartRating = CleanDataBySDThreshold(lessonDataAnlysis.smartRating, thresholdMultiplier);
+
+                lessonDataAnlysis.smartRatingBase  = techCounts.Where(x => x.smartRatingCountBase  > 0).Select(x => (double)x.smartRatingCountBase);
+                lessonDataAnlysis.smartRatingBase = CleanDataBySDThreshold(lessonDataAnlysis.smartRatingBase, thresholdMultiplier);
+
+                lessonDataAnlysis.irs = techCounts.Where(x => x.irsCount > 0).Select(x => (double)x.irsCount);
+                lessonDataAnlysis.irs = CleanDataBySDThreshold(lessonDataAnlysis.irs, thresholdMultiplier);
+
+
+                lessonDataAnlysis.interactNormal = techCounts.Where(x => x.interactNormalCount > 0).Select(x => (double)x.interactNormalCount);
+              
+                Console.WriteLine($"interactNormal{lessonDataAnlysis.interactNormal.Count()}");
+                lessonDataAnlysis.interactNormal= CleanDataBySDThreshold(lessonDataAnlysis.interactNormal, thresholdMultiplier).OrderBy(x => x);
+                Console.WriteLine($"interactNormal{lessonDataAnlysis.interactNormal.Count()}");
+
+
+                var tcount = techCounts.Where(x => x.coworkCount > 0  || x.taskCount>0  || x.interactNormalCount>0|| x.examCount>0  || x.smartRatingCount>0);
+                double coworkWeight = lessonDataAnlysis.cowork.Count()*1.0/tcount.Count();
+                lessonDataAnlysis.coworkWeight=coworkWeight;
+                double taskWeight = lessonDataAnlysis.task.Count()*1.0/tcount.Count();
+                lessonDataAnlysis.taskWeight=taskWeight;
+                double interactWeight = lessonDataAnlysis.interactNormal.Count()*1.0/tcount.Count();
+                lessonDataAnlysis.interactWeight=interactWeight;
+                double examWeight = lessonDataAnlysis. exam.Count()*1.0/tcount.Count();
+                lessonDataAnlysis.examWeight=examWeight;
+                double smartRatingWeight = lessonDataAnlysis. smartRating.Count()*1.0/tcount.Count();
+                lessonDataAnlysis.smartRatingWeight=smartRatingWeight;
+
+                List<KeyValuePair<double, List<int>>> clustersDataInteract = new();
+                var clusterInteract = KMeansService.KMeans(lessonDataAnlysis.interactNormal.Select(x => (int)x).OrderBy(x => x));
+                foreach (var item in clusterInteract)
+                {
+                    Console.WriteLine($"dp:{item.Key} ,avg: {item.Value.Average()}, count: {item.Value.Count}, min:{item.Value.Min()}, max:{item.Value.Max()}");
+                }
+                foreach (var s in clusterInteract.OrderBy(x => x.Key))
+                {
+                    clustersDataInteract.Add(s);
+                }
+                lessonDataAnlysis.clustersInteract=clustersDataInteract;
+                var groups = techCounts.SelectMany(x => x.timeCount).GroupBy(x => x.code).Select(x => new { key = x.Key, list = x.ToList() });
+                Dictionary<string, IEnumerable<double>> techDict = new Dictionary<string, IEnumerable<double>>();
+                foreach (var group in groups)
+                {
+                    var array = group.list.Where(x => x.value>0).Select(x => (double)x.value);
+                    array = CleanDataBySDThreshold(array, thresholdMultiplier);
+                    techDict.Add(group.key, array);
+                }
+                System.IO. File.WriteAllText(Path.Combine(path, "anlysis.json"), lessonDataAnlysis.ToJsonString());
             }
+          
+     
+
             List<LessonLocal> lessons = new List<LessonLocal>();
-            var files_local = files.Where(x=>x.EndsWith("548724334458441728-local.json")).Take(100).ToList();
-            await Parallel.ForEachAsync(files_local, async (item, _) =>
+            var files_local = files.Where(x=>x.EndsWith("608942756458532864-local.json")).Take(100).ToList();
+            foreach (var item in files_local)
             {
                 if (item.EndsWith("local.json"))
                 {
@@ -258,58 +340,172 @@ namespace HTEX.Test.Controllers
                     lesson.studentLessonDatas =  GetSmartRatingData(lesson.lessonBase!, lesson.timeLineData!, lesson.smartRatingDatas, lesson.studentLessonDatas);
                     lesson.studentLessonDatas =  GetTaskData(lesson.lessonBase!, lesson.timeLineData!, lesson.taskDatas, lesson.studentLessonDatas);
                     var techCount = techCounts.Find(x => !string.IsNullOrWhiteSpace(x.lessonId)  &&  !string.IsNullOrWhiteSpace(lesson?.lessonRecord?.id) &&  x.lessonId.Equals(lesson.lessonRecord.id));
-                    if (techCount != null) {
-
-                        IEnumerable<double> interact = null;
-                        int interactCount = 0;
-                        if (lesson.examDatas.IsNotEmpty())
-                        {
-                            interact= interactExam;
-                            interactCount= techCount.interactExamCount;
-
-                        }
-                        else {
-                            interact= interactNormal;
-                            interactCount= techCount.interactNormalCount;
-                        }
-
+                    if (techCount != null)
+                    {
+                        //互动的计分相关的 
+                        var x = 0.0;
+                        IEnumerable<double> interact = lessonDataAnlysis.interactNormal;
+                        int interactCount = techCount.interactNormalCount;
                         //当前课例的互动次数在互动总列表超过N%;
-                        var persent =  GetPersent(interact, interactCount);
-                        foreach(var  studentLessonData in lesson.studentLessonDatas) 
+                        var persent = GetPersent(interact, interactCount);
+                        foreach (var studentLessonData in lesson.studentLessonDatas)
                         {
+                            double i = 0, s = 0;
+                            if (lesson?.lessonBase?.report?.clientSummaryList!=null)
+                            {
+                                var d = lesson?.lessonBase?.report?.clientSummaryList.Find(x => $"{x.seatID}".Equals(studentLessonData.seatID));
+                                if (d!=null)
+                                {
+                                    i=d.interactScore;
+                                    s =d.score;
+                                }
+                            }
+                            var q = lessonDataAnlysis.pscore.Max();
+                            var t = lessonDataAnlysis.tscore.Max();
                             if (studentLessonData.interactRecord.interactRecords.Count==interactCount && interactCount>0)
                             {
-                                
-                                var score = studentLessonData.interactRecord.interactRecords.Select(x=>x.resultWeight*1.0/100* persent).Sum()/interactCount;
-                                var rate = studentLessonData.interactRecord.interactRecords.Where(x=>x.resultWeight>0).Count()*100.0/interactCount;
-                                studentLessonData.interactRecord.interactScore=score;
-                                studentLessonData.interactRecord.interactRate=rate;
+                                var n = studentLessonData.interactRecord.interactRecords.Count()*1.0;
+                                //聚类分数量大和数量小的类群。判断当前出题数在两个类群的最大范围内,再取其质心。
+                                var m = n<=lessonDataAnlysis.clustersInteract.First().Value.Max() ? lessonDataAnlysis.clustersInteract.First().Key*1.0 : lessonDataAnlysis.clustersInteract.Last().Key *1.0;
+                                var w = studentLessonData.interactRecord.interactRecords.Where(x => x.resultWeight>=InteractWeight.T1).Count()*1.0;
+                                var r = studentLessonData.interactRecord.interactRecords.Where(x => x.resultWeight>InteractWeight.TT).Count()*1.0;
+                                var p = InteractWeight.TT;
+                                var j = InteractWeight.T1;
+                                //学习成效算法
+                                x=((i/t) + ((n/m)*(w*(w/n)+(p/j)* (r/n) *r)))/n;
+                                var rate = w*100.0/interactCount;
+                               // studentLessonData.interactRecord.interactScore=data;
+                               // studentLessonData.interactRecord.interactRate=rate;
                             }
-                            else 
+                            else
                             {
-                                if (studentLessonData.interactRecord.interactRecords.Count()!=0) 
+                                if (studentLessonData.interactRecord.interactRecords.Count()!=0)
                                 {
-                                    Console.WriteLine($"{lesson.lessonRecord?.id}的互动次数不匹配。");
+                                    Console.WriteLine($"{studentLessonData.id}{lesson.lessonRecord?.id}的互动次数不匹配。");
                                 }
                             }
+                            var data = 190.0/(1+Math.Exp(-(s/q+x)))-95.0;
+                            studentLessonData.achieve=data;
                         }
 
                     }
                 }
-            });
-
+            }
             return Ok(new
             {
                 lessons,
-                interactExam=interactExam.OrderByDescending(x=>x),
-                interactNormal = interactNormal.OrderByDescending(x=>x),
-                cowork = cowork.OrderByDescending(x => x),
-                exam = exam.OrderByDescending(x => x),
-                smartRating = smartRating.OrderByDescending(x => x),
+                interactNormal = lessonDataAnlysis.interactNormal.OrderByDescending(x=>x),
+                cowork = lessonDataAnlysis.cowork.OrderByDescending(x => x),
+                exam = lessonDataAnlysis.exam.OrderByDescending(x => x),
+                smartRating = lessonDataAnlysis.smartRating.OrderByDescending(x => x),
             });
         }
 
 
+        [HttpPost("process-history")]
+        public async Task<IActionResult> ProcessHistory(JsonElement json)
+        {
+            //1709222400000 2024.3.1
+            var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
+                .GetList<LessonRecord>($"SELECT value c FROM School AS c  where c.startTime>1706716800000 and c.expire<=0  and c.status<>404  and c.duration>300 and c.pk='LessonRecord' and c.school<>'hbcn' and c.school<>'habook' and (c.tLevel>0 or c.pLevel>0) ", null);
+            if (result.list.IsNotEmpty())
+            {
+                List<string> ignore = new List<string>() { "PgJump", "PgRcv", "PgAdd" };
+                Stopwatch stopwatch = Stopwatch.StartNew();
+                //stopwatch.Start();
+                //await GetLessData(result, ignore);
+                //stopwatch.Stop();
+                //Console.WriteLine($"Elapsed Time: {stopwatch.ElapsedMilliseconds} ms");
+                //stopwatch.Reset();
+                stopwatch.Start();
+                string path = "F:\\lesson-local";
+                await foreach (var item in GetLessonLocal(result.list))
+                {
+                    if (item.lessonBase!=null && item.lessonBase.student!=null)
+                    {
+                        TechCount techCount = new TechCount
+                        {
+                            lessonId=item.lessonRecord?.id,
+                            examCount = item.examDatas.Count,
+                            taskCount = item.taskDatas.Count,
+                            irsCount = item.irsDatas.Count,
+                            coworkCount = item.coworkDatas.Count,
+                            smartRatingCount =item.smartRatingDatas.Count,
+                            timeCount=item.sokratesDatas.Where(x => !ignore.Contains(x.Event)  &&  !x.Event.Contains("End", StringComparison.OrdinalIgnoreCase)).GroupBy(x => x.Event).Select(x => new CodeLong() { code=x.Key, value= x.ToList().Count }).ToList()
+                        };
+                        await System.IO.File.WriteAllTextAsync($"{path}\\{item.lessonRecord!.id}-local.json", item.ToJsonString());
+                        await System.IO.File.WriteAllTextAsync($"{path}\\{item.lessonRecord.id}-count.json", techCount.ToJsonString());
+                    }
+                    else {
+                        Console.WriteLine($"没有课例id的数据:{item.lessonRecord?.id}");
+                        System.IO.File.Delete($"{path}\\{item.lessonRecord!.id}-local.json");
+                        System.IO.File.Delete($"{path}\\{item.lessonRecord!.id}-count.json");
+                    }
+                   
+                }
+                stopwatch.Stop();
+                Console.WriteLine($"Elapsed Time: {stopwatch.ElapsedMilliseconds} ms");
+            }
+            return Ok("Lesson records");
+        }
+
+
+        public static List<string> ListAllFiles(string directoryPath)
+        {
+            List<string> filePaths = new List<string>();
+            DirectoryInfo dirInfo = new DirectoryInfo(directoryPath);
+
+            // 获取目录下的所有文件(包括子目录中的文件)
+            FileInfo[] files = dirInfo.GetFiles("*", SearchOption.AllDirectories);
+
+            foreach (FileInfo file in files)
+            {
+                filePaths.Add(file.FullName);
+                // Console.WriteLine(file.FullName);
+            }
+            return filePaths;
+        }
+
+        public class LessonDataAnlysis
+        {
+            public long updateTime { get; set; }
+            public IEnumerable<double> cowork { get; set; } = new List<double>();
+            public IEnumerable<double> coworkBase { get; set; } = new List<double>();
+            public IEnumerable<double> task { get; set; } = new List<double>();
+            public IEnumerable<double> taskBase { get; set; } = new List<double>();
+            public IEnumerable<double> exam { get; set; } = new List<double>();
+            public IEnumerable<double> examBase { get; set; } = new List<double>();
+            public IEnumerable<double> smartRating { get; set; } = new List<double>();
+            public IEnumerable<double> smartRatingBase { get; set; } = new List<double>();
+            public IEnumerable<double> irs { get; set; } = new List<double>();
+            public IEnumerable<double> interactNormal { get; set; } = new List<double>();
+            public List<KeyValuePair<double, List<int>>> clustersInteract { get; set; } = new List<KeyValuePair<double, List<int>>>();
+            public List<KeyValuePair<double, List<double>>> clustersPscore { get; set; } = new List<KeyValuePair<double, List<double>>>();
+            public List<KeyValuePair<double, List<double>>> clustersTscore { get; set; } = new List<KeyValuePair<double, List<double>>>();
+            public List<KeyValuePair<double, List<double>>> clustersGscore { get; set; } = new List<KeyValuePair<double, List<double>>>();
+            /// <summary>
+            /// 个人计分
+            /// </summary>
+            public IEnumerable<double> pscore { get; set; } = new List<double>();
+            /// <summary>
+            /// 小组计分
+            /// </summary>
+            public IEnumerable<double> gscore { get; set; } = new List<double>();
+            /// <summary>
+            /// 互动计分
+            /// </summary>
+            public IEnumerable<double> tscore { get; set; } = new List<double>();
+
+
+
+            public double coworkWeight { get; set; }
+            public double taskWeight { get; set; }
+            public double interactWeight { get; set; }
+            public double examWeight { get; set; }
+            public double smartRatingWeight { get; set; }
+        }
+
+
         /// <summary>
         /// 计算当前元素在集合中超过了多少百分比的值
         /// </summary>
@@ -319,7 +515,7 @@ namespace HTEX.Test.Controllers
         public static double GetPersent(IEnumerable<double> nums, int curr)
         {
             int count = 0;
-            foreach (var  op in nums.OrderBy(x => x))
+            foreach (var op in nums.OrderBy(x => x))
             {
                 if (op < curr)
                 {
@@ -333,7 +529,7 @@ namespace HTEX.Test.Controllers
                 {
                     break;
                 }
-            } 
+            }
             return count *1.0/ nums.Count() * 100;
         }
 
@@ -342,32 +538,27 @@ namespace HTEX.Test.Controllers
         /// </summary>
         /// <param name="array"></param>
         /// <returns></returns>
-        public static List<double> CleanDataBySDThreshold(IEnumerable<double> array ,double thresholdMultiplier=2)
+        public static List<double> CleanDataBySDThreshold(IEnumerable<double> array, double thresholdMultiplier = 2)
         {
             if (array.Count() == 0) return new List<double>();
-            double average = array.Average();
-            double variance = array.Average(x => Math.Pow(x - average, 2));
-            double standardDeviation = Math.Sqrt(variance);
-
-            // 定义异常值的阈值
-            double threshold = thresholdMultiplier * standardDeviation;
+            double average = Math.Round(array.Sum()*1.0/array.Count(), 4);
+            double variance = array.Select(x => Math.Round(Math.Pow(x - average, 2), 4)).Sum()*1.0/array.Count();
+            double standardDeviation = Math.Sqrt(Math.Round(variance, 4));
+            double threshold = Math.Round(thresholdMultiplier * standardDeviation);
             List<double> datas = new List<double>();
             foreach (double value in array)
             {
-                double deviation = Math.Abs(value - average);
+                double deviation = Math.Round(Math.Abs(value - average), 4);
                 if (deviation <= threshold)
                 {
                     datas.Add(value);
                 }
-                //else {
-                //   Console.WriteLine($"异常值:{value}, {deviation},{threshold}");
-                //}
             }
             return datas;
         }
         private async IAsyncEnumerable<LessonLocal> GetLessonLocal(List<LessonRecord> lessonRecords)
-        { 
-            foreach(var lessonRecord in lessonRecords) 
+        {
+            foreach (var lessonRecord in lessonRecords)
             {
                 LessonLocal lessonLocal = new LessonLocal { lessonRecord=lessonRecord };
                 if (System.IO.File.Exists($"F:\\lesson-local\\{lessonRecord.id}-local.json"))
@@ -375,7 +566,7 @@ namespace HTEX.Test.Controllers
                     string jsonp = await System.IO.File.ReadAllTextAsync($"F:\\lesson-local\\{lessonRecord.id}-local.json");
                     lessonLocal = jsonp.ToObject<LessonLocal>();
                 }
-                else 
+                else
                 {
                     List<string> files = new List<string>()
                     {
@@ -402,11 +593,12 @@ namespace HTEX.Test.Controllers
                 yield return lessonLocal;
             }
         }
-        private async Task<LessonLocal> GetLessonFiles(LessonLocal lessonLocal , List<string> files ,  string school)
+        private async Task<LessonLocal> GetLessonFiles(LessonLocal lessonLocal, List<string> files, string school)
         {
             await Parallel.ForEachAsync(files, async (file, _) =>
             {
-                try {
+                try
+                {
                     BlobDownloadResult blobDownloadResult = await _azureStorage.GetBlobContainerClient(school).GetBlobClient(file).DownloadContentAsync();
                     switch (true)
                     {
@@ -432,60 +624,15 @@ namespace HTEX.Test.Controllers
                             lessonLocal.sokratesDatas= blobDownloadResult.Content.ToObjectFromJson<List<TimeLineEvent>>();
                             break;
                     }
-                } catch (Exception ex) {
+                }
+                catch (Exception ex)
+                {
                     //Console.WriteLine($"{file}");
                 }
             });
             return lessonLocal;
         }
 
-        [HttpPost("process-history")]
-        public async Task<IActionResult> ProcessHistory(JsonElement json)
-        {
-            //1709222400000 2024.3.1
-            var result = await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School)
-                .GetList<LessonRecord>($"SELECT value c FROM School AS c  where c.startTime>1706716800000 and c.expire<=0  and c.status<>404  and c.duration>300 and c.pk='LessonRecord' ", null);
-            if (result.list.IsNotEmpty())
-            {
-                List<string> ignore = new List<string>() { "PgJump", "PgRcv", "PgAdd" };
-                Stopwatch stopwatch = Stopwatch.StartNew();
-                //stopwatch.Start();
-                //await GetLessData(result, ignore);
-                //stopwatch.Stop();
-                //Console.WriteLine($"Elapsed Time: {stopwatch.ElapsedMilliseconds} ms");
-                //stopwatch.Reset();
-                stopwatch.Start();
-                string path = "F:\\lesson-local";
-                await foreach (var item in GetLessonLocal(result.list))
-                {
-                    if (item.lessonBase!=null && item.lessonBase.student!=null)
-                    {
-                        TechCount techCount = new TechCount
-                        {
-
-                            examCount = item.examDatas.Count,
-                            taskCount = item.taskDatas.Count,
-                            irsCount = item.irsDatas.Count,
-                            coworkCount = item.coworkDatas.Count,
-                            smartRatingCount =item.smartRatingDatas.Count,
-                            timeCount=item.sokratesDatas.Where(x => !ignore.Contains(x.Event)  &&  !x.Event.Contains("End", StringComparison.OrdinalIgnoreCase)).GroupBy(x => x.Event).Select(x => new CodeLong() { code=x.Key, value= x.ToList().Count }).ToList()
-                        };
-                        await System.IO.File.WriteAllTextAsync($"{path}\\{item.lessonRecord!.id}-local.json", item.ToJsonString());
-                        await System.IO.File.WriteAllTextAsync($"{path}\\{item.lessonRecord.id}-count.json", techCount.ToJsonString());
-                    }
-                    else {
-                        Console.WriteLine($"没有课例id的数据:{item.lessonRecord?.id}");
-                        System.IO.File.Delete($"{path}\\{item.lessonRecord!.id}-local.json");
-                        System.IO.File.Delete($"{path}\\{item.lessonRecord!.id}-count.json");
-                    }
-                   
-                }
-                stopwatch.Stop();
-                Console.WriteLine($"Elapsed Time: {stopwatch.ElapsedMilliseconds} ms");
-            }
-            return Ok("Lesson records");
-        }
-
         private async Task GetLessData(CosmosDBResult<LessonRecord> result, List<string> ignore)
         {
             foreach (var item in result.list)
@@ -727,7 +874,7 @@ namespace HTEX.Test.Controllers
             /// <summary>
             /// 互动次数
             /// </summary>
-            public int interactExamCount { get; set; }
+            //public int interactExamCount { get; set; }
 
             /// <summary>
             /// 互动次数
@@ -742,6 +889,39 @@ namespace HTEX.Test.Controllers
             /// </summary>
             public int smartRatingCount { get; set; }
             public List<CodeLong> timeCount { get; set; } = new List<CodeLong>();
+            public IEnumerable<double> pscore { get; set; } = new List<double>();
+            public IEnumerable<double> gscore { get; set; } = new List<double>();
+            public IEnumerable<double> tscore { get; set; } = new List<double>();
+            /// <summary>
+            /// 评测数量
+            /// </summary>
+            public int examCountBase { get; set; }
+            /// <summary>
+            /// 任务数量
+            /// </summary>
+            public int taskCountBase { get; set; }
+            /// <summary>
+            /// IRS次数
+            /// </summary>
+            public int irsCountBase { get; set; }
+
+            /// <summary>
+            /// 互动次数
+            /// </summary>
+            //public int interactExamCountBase { get; set; }
+
+            /// <summary>
+            /// 互动次数
+            /// </summary>
+            public int interactNormalCountBase { get; set; }
+            /// <summary>
+            /// 协作次数
+            /// </summary>
+            public int coworkCountBase { get; set; }
+            /// <summary>
+            /// 智能评分次数
+            /// </summary>
+            public int smartRatingCountBase { get; set; }
 
         }
         /// <summary>
@@ -841,19 +1021,34 @@ namespace HTEX.Test.Controllers
                 foreach (var item in enventsPickup)
                 {
                     List<int> mbrs = item.PickupMemberId.ToObject<List<int>>();
-
-                    foreach (var mbr in mbrs)
+                    // 挑人挑中 TT ,没有挑中 T1
+                    foreach (var studentLessonData in studentLessonDatas) 
                     {
-                        var studentLessonData = studentLessonDatas.Find(x => x.seatID!.Equals($"{mbr}"));
-                        if (studentLessonData!=null)
+                        var mbr = mbrs.FindAll(x => studentLessonData.seatID!.Equals($"{x}"));
+                        if (mbr.IsNotEmpty())
                         {
-                            studentLessonData.attend=1;
-                            studentLessonData.interactRecord.interactRecords.Add(new ItemRecord() 
+                            foreach (var m in mbr)
                             {
-                                resultWeight = InteractWeight.TT,
-                                resultType="TT",
-                                itemType = string.IsNullOrWhiteSpace(item.PickupType) ? "PickupResult" : item.PickupType
-                            });
+                                studentLessonData.attend=1;
+                                studentLessonData.interactRecord.interactRecords.Add(new ItemRecord()
+                                {
+                                    resultWeight = InteractWeight.TT,
+                                    resultType=InteractReultType.TT,
+                                    itemType = string.IsNullOrWhiteSpace(item.PickupType) ? "PickupResult" : item.PickupType
+                                });
+                            }
+                        }
+                        else {
+                            //处理未挑中的
+                            if (studentLessonData.attend==1) 
+                            {
+                                studentLessonData.interactRecord.interactRecords.Add(new ItemRecord()
+                                {
+                                    resultWeight = InteractWeight.T1,
+                                    resultType=InteractReultType.T1,
+                                    itemType = string.IsNullOrWhiteSpace(item.PickupType) ? "PickupResult" : item.PickupType
+                                });
+                            }
                         }
                     }
                 }
@@ -1474,8 +1669,9 @@ namespace HTEX.Test.Controllers
                     var student =  studentLessonDatas.Find(x => x.seatID!.Equals(key));
                     if (student!=null && student.attend==1) 
                     {
-                        var score = coworkData.participateLevelList[key];//协作得分
-                        var itemRecord = new ItemRecord {  criterion=-1, itemType= coworkData.coworkType,itemScore=score };
+                        var score = coworkData.participateLevelList[key];//协作得分,是否是经过指数计算的
+                        var itemRecord = new ItemRecord { criterion=-1, itemType= coworkData.coworkType, itemScore=score, isGroup= coworkData.coworkType.Equals("Group") ? true : false };
+                        //不能完全依赖 
                         if (score>0)
                         {
                             itemRecord.resultWeight =  InteractWeight.T1;
@@ -1603,7 +1799,7 @@ namespace HTEX.Test.Controllers
                             }
                         }
                         var meteor_VoteSummary = smartRatingData.smartRateSummary!.meteor_VoteSummary[key];
-                        var order = meteor_VoteSummary.Where(x=>x.result>0).OrderByDescending(x => x.result);
+                        var order = meteor_VoteSummary.OrderByDescending(x => x.result);
                         var maxItems = meteor_VoteSummary.FindAll(x => x.result==order.First().result);
                         var max=  meteor_VoteSummary.FindAll(x => x.result==order.First().result).First().result;
                         var min = meteor_VoteSummary.FindAll(x => x.result==order.Last().result).First().result;
@@ -1633,6 +1829,8 @@ namespace HTEX.Test.Controllers
                                         var data=  MinMaxNormalization(min, max, datasD.result);
                                         //student.rateingRecord.itemRecords[index].resultWeight= InteractWeight.TP;
                                         student.rateingRecord.itemRecords[index].resultWeight=InteractWeight.T1+  data * 1.0  / maxRank * (InteractWeight.TT-InteractWeight.T1);
+                                        //获得的票数
+                                        student.rateingRecord.itemRecords[index].itemScore=datasD.result;
                                         //TT是评论了别人,且被别人评论次数最高,或者分值最高。
                                         if (maxItems.Select(x => x.id).Contains(student.seatID))
                                         {
@@ -1699,7 +1897,8 @@ namespace HTEX.Test.Controllers
                                     var data = MinMaxNormalization(min, max, meteor_ScoreSummary.result);
                                     //student.rateingRecord.itemRecords[index].resultWeight= InteractWeight.TP;
                                     student.rateingRecord.itemRecords[index].resultWeight= InteractWeight.T1+  data * 1.0  / maxRank * (InteractWeight.TT-InteractWeight.T1);
-                                   
+                                    //被评论次数
+                                    student.rateingRecord.itemRecords[index].itemScore=meteor_ScoreSummary.result;
                                     //TT是评论了别人,且被别人评论次数最高,或者分值最高。
                                     if (maxItems.Select(x => x.id).Contains(student.seatID))
                                     {
@@ -1767,7 +1966,7 @@ namespace HTEX.Test.Controllers
                                     var data = MinMaxNormalization(min, max, mutualResult.result);
                                     //student.rateingRecord.itemRecords[index].resultWeight= InteractWeight.TP;
                                     student.rateingRecord.itemRecords[index].resultWeight=  InteractWeight.T1+ data * 1.0  / maxRank * (InteractWeight.TT-InteractWeight.T1);
-
+                                    student.rateingRecord.itemRecords[index].itemScore=mutualResult.result;
                                     //TT是评论了别人,且被别人评论次数最高,或者分值最高。
                                     if (maxItems.Select(x => x.id).Contains(student.seatID))
                                     {

+ 92 - 7
TEAMModelOS.Extension/HTEX.Test/Program.cs

@@ -3,9 +3,13 @@ using HTEX.Test.Service;
 using MathNet.Numerics;
 using System.Configuration;
 using System.Diagnostics;
+using System.Linq;
 using System.Text.RegularExpressions;
+using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
+using TEAMModelOS.SDK.Models;
+using static HTEX.Test.Controllers.LessonRecordController;
 namespace HTEX.Test
 {
     public class Program
@@ -41,18 +45,99 @@ namespace HTEX.Test
             app.Run();
         }
 
+        public static string Test2() 
+        {
+            // 创建一个包含三万个元素的数组
+            int[] data = Enumerable.Range(1, 30000).Select(i => new Random().Next(1, 31)).ToArray();
+
+            // 设置聚类的数量
+            int k = 2;
+            // 初始化质心,可以选择数据中的k个随机点作为初始质心
+            List<int> centroids = new List<int>();
+            Random rand = new Random();
+            for (int i = 0; i < k; i++)
+            {
+                centroids.Add(rand.Next(1, 31));
+            }
+            centroids.Sort(); // 对质心进行排序以避免重复
 
+            Dictionary<int, List<int>> clustersD= new Dictionary<int, List<int>>();
+            // 迭代次数
+            int maxIterations = 100;
+            for (int iteration = 0; iteration < maxIterations; iteration++)
+            {
+                // 将数据点分配给最近的质心
+                Dictionary<int, List<int>> clusters = new Dictionary<int, List<int>>();
+                foreach (int point in data)
+                {
+                    int nearestCentroid = centroids.OrderBy(c => Math.Abs(point - c)).First();
+                    if (!clusters.ContainsKey(nearestCentroid))
+                    {
+                        clusters[nearestCentroid] = new List<int>();
+                    }
+                    clusters[nearestCentroid].Add(point);
+                }
 
-        public static string Test()
-        {
-            var a = new int[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27];
-            var b = new int[2192, 2379, 2070, 1813, 1662, 1421, 1134, 1043, 861, 763, 608, 563, 451, 358, 291, 252, 213, 170, 152, 133, 132, 95, 82, 71, 73, 63, 43];
+                // 更新质心位置
+                List<int> newCentroids = new List<int>();
+                foreach (KeyValuePair<int, List<int>> cluster in clusters)
+                {
+                    int sum = cluster.Value.Sum();
+                    int count = cluster.Value.Count;
+                    int newCentroid = sum / count; // 计算均值
+                    newCentroids.Add(newCentroid);
+
+                    // 输出当前聚类的信息
+                    Console.WriteLine($"Cluster with centroid {cluster.Key}:");
+                    Console.WriteLine($"Min: {cluster.Value.Min()}, Max: {cluster.Value.Max()}, Average: {sum / count}");
+                }
 
+                // 检查质心是否改变
+                newCentroids.Sort();
+                clustersD=clusters;
+                if (newCentroids.SequenceEqual(centroids))
+                {
+                   
+                    break;
+                }
+                centroids = newCentroids;
+            }
+            return "";
+        }
 
-          //   var per= GetPersent(array,3);
-         //   Console.WriteLine(per);
+        public static string Test()
+        {
+            //  Test2();
+            //var n = 2.0;
+            //var w = 2.0;
+            //var r = 1.0;
+            //var p = InteractWeight.TT;
+            //var j = InteractWeight.T1;
+            //var data = 190/(1+Math.Exp(-(n/4*(w*w/n+p/j * w/n * r/w *r))/n))-95;
+            var n = 3.0;
+            var m = 5.6;
+            var w = 3.0;
+            var r = 3.0;
+            var p = InteractWeight.TT;
+            var j = InteractWeight.T1;
+            //var data = 190.0/(1+Math.Exp(-((n/m.avg)*(w*(w/n)+(p/j)* (w/n)* (r/w) *r))/n))-95.0;
+            var data = 190.0/(1+Math.Exp(-((n/m)*(w*(w/n)+(p/j)* (r/n) *r))/n))-95.0;
+
+            //int[] a = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 };
+            //int [] b = new int[] { 2192, 2379, 2070, 1813, 1662, 1421, 1134, 1043, 861, 763, 608, 563, 451, 358, 291, 252, 213, 170, 152, 133, 132, 95, 82, 71, 73, 63, 43 };
+            //var lib= b.Sum();
+            //List<int > ds= new List<int>();
+            //for(int i = 0; i<a.Length; i++) 
+            //{
+            //    int d=   b[i]*  a[i];
+            //    ds.Add(d);
+            //}
+            //var q = ds.Sum() *1.0/lib;
+            //Console.WriteLine(q);
+            //   var per= GetPersent(array,3);
+            //   Console.WriteLine(per);
 
-           //var data =  MLService.GetNormalCluster(array.ToArray(),3,0.3);
+            //var data =  MLService.GetNormalCluster(array.ToArray(),3,0.3);
             //  var group =  array.GroupBy(x=>x).Select(x=>new { key = x.Key, list = x.ToList()}).OrderBy(x=>x.key);
             // Console.WriteLine(group.Select(x => x.key).ToJsonString());
             //Console.WriteLine(group.Select(x => x.list.Count()).ToJsonString());

+ 118 - 0
TEAMModelOS.Extension/HTEX.Test/Service/KMeansService.cs

@@ -0,0 +1,118 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using static Pipelines.Sockets.Unofficial.SocketConnection;
+
+namespace HTEX.Test.Service
+{
+    public class KMeansService
+    {
+        public static Dictionary<double, List<double>> KMeans(IEnumerable<double> datas) 
+        {
+
+            // 初始化质心,可以选择数据中的k个随机点作为初始质心
+            List<double> centroids = new List<double>();
+
+            centroids.Add(datas.Min());
+            centroids.Add(datas.Max());
+            centroids.Sort(); // 对质心进行排序以避免重复
+
+            Dictionary<double, List<double>> clustersResults = new Dictionary<double, List<double>>();
+            // 迭代次数
+            int maxIterations = 100;
+            for (int iteration = 0; iteration < maxIterations; iteration++)
+            {
+                // 将数据点分配给最近的质心
+                Dictionary<double, List<double>> clusters = new Dictionary<double, List<double>>();
+                foreach (int point in datas)
+                {
+                    double nearestCentroid = centroids.OrderBy(c => Math.Abs(point - c)).First();
+                    if (!clusters.ContainsKey(nearestCentroid))
+                    {
+                        clusters[nearestCentroid] = new List<double>();
+                    }
+                    clusters[nearestCentroid].Add(point);
+                }
+
+                // 更新质心位置
+                List<double> newCentroids = new List<double>();
+                foreach (KeyValuePair<double, List<double>> cluster in clusters)
+                {
+                    double sum = cluster.Value.Sum();
+                    int count = cluster.Value.Count;
+                    double newCentroid = sum *1.0/ count; // 计算均值
+                    newCentroids.Add(newCentroid);
+                    // 输出当前聚类的信息
+                    //Console.WriteLine($"Cluster with centroid {cluster.Key}:");
+                    //Console.WriteLine($"Min: {cluster.Value.Min()}, Max: {cluster.Value.Max()}, Average: {sum / count}");
+                }
+
+                // 检查质心是否改变
+                newCentroids.Sort();
+
+                clustersResults=clusters;
+
+                if (newCentroids.SequenceEqual(centroids))
+                {
+                    break;
+                }
+                centroids = newCentroids;
+            }
+            return clustersResults;
+        }
+
+         public static Dictionary<double, List<int>> KMeans(IEnumerable<int> datas )
+         {
+            // 初始化质心,可以选择数据中的k个随机点作为初始质心
+            List<double> centroids = new List<double>();
+
+            centroids.Add(datas.Min());
+            centroids.Add(datas.Max());
+            centroids.Sort(); // 对质心进行排序以避免重复
+
+            Dictionary<double, List<int>> clustersResults = new Dictionary<double, List<int>>();
+            // 迭代次数
+            int maxIterations = 100;
+            for (int iteration = 0; iteration < maxIterations; iteration++)
+            {
+                // 将数据点分配给最近的质心
+                Dictionary<double, List<int>> clusters = new Dictionary<double, List<int>>();
+                foreach (int point in datas)
+                {
+                    double nearestCentroid = centroids.OrderBy(c => Math.Abs(point - c)).First();
+                    if (!clusters.ContainsKey(nearestCentroid))
+                    {
+                        clusters[nearestCentroid] = new List<int>();
+                    }
+                    clusters[nearestCentroid].Add(point);
+                }
+
+                // 更新质心位置
+                List<double> newCentroids = new List<double>();
+                foreach (KeyValuePair<double, List<int>> cluster in clusters)
+                {
+                    int sum = cluster.Value.Sum();
+                    int count = cluster.Value.Count;
+                    double newCentroid = sum *1.0/ count; // 计算均值
+                    newCentroids.Add(newCentroid);
+                    // 输出当前聚类的信息
+                    //Console.WriteLine($"Cluster with centroid {cluster.Key}:");
+                    //Console.WriteLine($"Min: {cluster.Value.Min()}, Max: {cluster.Value.Max()}, Average: {sum / count}");
+                }
+
+                // 检查质心是否改变
+                newCentroids.Sort();
+               
+                clustersResults=clusters;
+               
+                if (newCentroids.SequenceEqual(centroids))
+                {
+                    break;
+                }
+                centroids = newCentroids;
+            }
+            return clustersResults ;
+        }
+    }
+}
+

+ 3 - 3
TEAMModelOS.Extension/HTEX.Test/Service/MLService.cs

@@ -12,7 +12,7 @@ namespace HTEX.Test.Service
         /// <param name="datas">数据需要去掉0</param>
         /// <param name="numberOfClusters"></param>
         /// <returns></returns>
-        public static List<ClusterData> KMeans(float[] datas, int numberOfClusters = 5)
+        public static List<ClusterData> KMeans(float[] datas, int numberOfClusters = 2)
         {
             List<DataPoint> data = new List<DataPoint>();
             foreach (var d in datas)
@@ -49,7 +49,7 @@ namespace HTEX.Test.Service
                 {
                     clusterData.count +=1;
                     clusterData.datas.Add(data[index].Feature);
-                    clusterData.avg=clusterData.datas.Sum() / clusterData.datas.Count();
+                    clusterData.avg=clusterData.datas.Sum()*1.0F / clusterData.datas.Count();
                 }
                 else
                 {
@@ -83,7 +83,7 @@ namespace HTEX.Test.Service
        /// <param name="numberOfClusters"></param>
        /// <param name="dropPercent">最大平均数的聚类与数量最多的聚类数量的落差小于30% 则以更高的为准</param>
        /// <returns></returns>
-        public static (ClusterData clusterData, List<ClusterData> clusterDatas) GetNormalCluster (float[] datas, int numberOfClusters = 5,double dropPercent=0.3)
+        public static (ClusterData clusterData, List<ClusterData> clusterDatas) GetNormalCluster (float[] datas, int numberOfClusters = 2,double dropPercent=0.3)
         {
             List<ClusterData> clusterDatas = KMeans(datas, numberOfClusters);
             clusterDatas=clusterDatas.OrderByDescending(dr => dr.count).ToList();

+ 31 - 6
TEAMModelOS.SDK/Models/Cosmos/Common/LessonRecord.cs

@@ -466,7 +466,9 @@ namespace TEAMModelOS.SDK.Models
     public class StudentLessonData
     {
 
-        //是否出席
+        /// <summary>
+        /// 出席状态 1出席,6公假,5事假,4病假,2缺席,0未签到
+        /// </summary>
         public int attend { get; set; }
         /// <summary>
         /// 课例id
@@ -521,7 +523,27 @@ namespace TEAMModelOS.SDK.Models
         ///评分记录
         /// </summary>
         public StudentRateingRecord rateingRecord { get; set; } = new StudentRateingRecord();
-         
+
+        /// <summary>
+        /// 学习态度
+        /// </summary>
+        public double attitude { get; set; }
+        /// <summary>
+        /// 学习成效
+        /// </summary>
+        public double achieve { get; set; }
+        /// <summary>
+        /// 合作能力
+        /// </summary>
+        public double cooperation { get; set; }
+        /// <summary>
+        /// 评价能力
+        /// </summary>
+        public  double appraise { get; set; }
+        /// <summary>
+        /// 协作能力
+        /// </summary>
+        public double cowork { get; set; }
     }
     public class StudentRateingRecord
     {
@@ -562,7 +584,7 @@ namespace TEAMModelOS.SDK.Models
     public class StudentTaskRecord
     {
         /// <summary>
-        /// 协作参与率
+        /// 任务参与率
         /// </summary>
         public double taskRate { get; set; }
         
@@ -678,15 +700,15 @@ namespace TEAMModelOS.SDK.Models
         /// <summary>
         /// 作答错误,有参加,有抢权1
         /// </summary>
-        public static readonly double T1 = 60;
+        public static readonly double T1 = 60.0;
         /// <summary>
         /// 部分正确1.3
         /// </summary>
-        public static readonly double TP = 80;
+        public static readonly double TP = 80.0;
         /// <summary>
         /// 作答正确,抢权成功,被抽到1.5
         /// </summary>
-        public static readonly double TT = 100;
+        public static readonly double TT = 100.0;
     }
     public class MutualSummary
     {
@@ -1201,6 +1223,9 @@ namespace TEAMModelOS.SDK.Models
         public double groupScore { get; set; }//組記分
 
         public int groupTaskCompleteCount { get; set; }//組任務數完成數
+        /// <summary>
+        /// 出席状态 1出席,6公假,5事假,4病假,2缺席,0未签到
+        /// </summary>
         public int attendState { get; set; } //出席狀態
 
         public double score { get; set; }//個人記分