瀏覽代碼

学科网题目解析。

CrazyIter_Bin 3 年之前
父節點
當前提交
f03983a3dc

+ 6 - 0
TEAMModelOS.SDK/Models/Cosmos/Common/Inner/BaseItem.cs

@@ -59,5 +59,11 @@ namespace TEAMModelOS.SDK.Models
         /// //选项数量
         /// </summary>
         public int opts { get; set; }
+
+        /// <summary>
+        /// 来源 0.(学校,个人)文档导入 1.(学校,个人)自建 3.学科网
+        /// </summary>
+        public int source { get; set; }
+        public string tag { get; set; }
     }
 }

+ 2 - 2
TEAMModelOS/Controllers/School/SchoolController.cs

@@ -1425,12 +1425,12 @@ namespace TEAMModelOS.Controllers
             }
             catch (CosmosException ex)
             {
-                await _dingDing.SendBotMsg($"OS,{_option.Location},schoool/teacher-space\n{ex.Message}\n{ex.StackTrace}\n", GroupNames.醍摩豆服務運維群組);
+                await _dingDing.SendBotMsg($"OS,{_option.Location},schoool/teacher-space\n{ex.Message}\n{ex.StackTrace}\n{request.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
                 return BadRequest();
             }
             catch (Exception ex)
             {
-                await _dingDing.SendBotMsg($"OS,{_option.Location},schoool/teacher-space\n{ex.Message}\n{ex.StackTrace}\n", GroupNames.醍摩豆服務運維群組);
+                await _dingDing.SendBotMsg($"OS,{_option.Location},schoool/teacher-space\n{ex.Message}\n{ex.StackTrace}\n{request.ToJsonString()}", GroupNames.醍摩豆服務運維群組);
                 return BadRequest();
             }
         }

+ 17 - 6
TEAMModelOS/Controllers/Third/Xkw/Sdk/XkwConstant.cs

@@ -1,4 +1,5 @@
 using System.Collections.Generic;
+using TEAMModelOS.SDK.Models;
 
 namespace TEAMModelOS.Controllers.Third.Xkw.Sdk
 {
@@ -116,14 +117,14 @@ namespace TEAMModelOS.Controllers.Third.Xkw.Sdk
         public static readonly List<XkwDifficulty> xkwDifficulties = new List<XkwDifficulty>()
         {
             //new XkwDifficulty{ id=17,name="容易",ceiling=0.99,flooring=0.9  },
-            new XkwDifficulty{ id=17,name="容易",ceiling=1.0,flooring=0.9  },
-            new XkwDifficulty{ id=18,name="较易",ceiling=0.9,flooring=0.8  },
-            new XkwDifficulty{ id=19,name="一般",ceiling=0.8,flooring=0.5  },
-            new XkwDifficulty{ id=20,name="较难",ceiling=0.5,flooring=0.3  },
-            new XkwDifficulty{ id=21,name="困难",ceiling=0.3,flooring=0.0  },
+            new XkwDifficulty{ id=17,name="容易",ceiling=1.0,flooring=0.9 ,level=1  },
+            new XkwDifficulty{ id=18,name="较易",ceiling=0.9,flooring=0.8 ,level=2 },
+            new XkwDifficulty{ id=19,name="一般",ceiling=0.8,flooring=0.5 ,level=3 },
+            new XkwDifficulty{ id=20,name="较难",ceiling=0.5,flooring=0.3 ,level=4 },
+            new XkwDifficulty{ id=21,name="困难",ceiling=0.3,flooring=0.0 ,level=5 },
         };
 
-        public static readonly List<XkwQuestionType> xkwQuestionTypees = new List<XkwQuestionType>()
+        public static readonly List<XkwQuestionType> xkwQuestionTypes = new List<XkwQuestionType>()
         {
             new XkwQuestionType{id="0101",name="选择题",objective=true,course_id=1},
             new XkwQuestionType{id="0118",name="互动连线题",objective=false,course_id=1},
@@ -722,6 +723,7 @@ namespace TEAMModelOS.Controllers.Third.Xkw.Sdk
         public string name { get; set; }
         public double ceiling { get; set; }
         public double flooring { get; set; }
+        public int level { get; set; }
     }
     public class XkwDto { 
         public int id { get; set; }
@@ -746,6 +748,15 @@ namespace TEAMModelOS.Controllers.Third.Xkw.Sdk
     public class XkwBody {
         public List<XkwItem> questions { get; set; } = new List<XkwItem>();
     }
+
+    public class XkwItemInfo : ItemInfo
+    {
+        public string stemHtml { get; set; }
+        public string answerHtml { get; set; }
+        public string subjectName { get; set; }
+        public string periodName { get; set; }
+        public List<string> gradeNames { get; set; }
+    }
     /// <summary>
     /// 学科网题目结构
     /// </summary>

+ 204 - 10
TEAMModelOS/Controllers/Third/Xkw/XkwServiceController.cs

@@ -35,6 +35,9 @@ using Microsoft.Extensions.Primitives;
 using System.Net.Http;
 using TEAMModelOS.Controllers.Third.Xkw.Sdk;
 using TEAMModelOS.SDK.Models.Table;
+using System.Text.RegularExpressions;
+using HtmlAgilityPack;
+using TEAMModelOS.SDK.Helper.Security.ShaHash;
 
 namespace TEAMModelOS.Controllers.Third.Xkw
 { 
@@ -62,6 +65,15 @@ namespace TEAMModelOS.Controllers.Third.Xkw
         private readonly HttpTrigger _httpTrigger;
         private readonly IWebHostEnvironment _environment;
         private readonly XkwAPIHttpService _xkwAPIHttpService;
+        /// <summary>
+        /// 全角
+        /// </summary>
+        string[] aza = new string[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
+        /// <summary>
+        /// 半角
+        /// </summary>
+        string[] azh = new string[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
+
         public IConfiguration _configuration { get; set; }
         public XkwServiceController(XkwAPIHttpService xkwAPIHttpService, IWebHostEnvironment environment, AzureCosmosFactory azureCosmos, SnowflakeId snowflakeId, DingDing dingDing, IOptionsSnapshot<Option> option, AzureStorageFactory azureStorage,
             AzureRedisFactory azureRedis, AzureServiceBusFactory serviceBus, IConfiguration configuration, CoreAPIHttpService coreAPIHttpService, ThirdApisService scsApisService, HttpTrigger httpTrigger)
@@ -109,26 +121,208 @@ namespace TEAMModelOS.Controllers.Third.Xkw
             return Ok(authCode);
         }
 
-        [HttpGet("get-paper-items")]
-        //[Authorize(Roles = "IES")]
-        //[AuthToken(Roles = "teacher,admin,area,student")]
-        public async Task<IActionResult> GetPaperItems([FromQuery] OAuthCode authCode)
+        [HttpPost("get-paper-items")]
+#if DEBUG
+#else
+        [Authorize(Roles = "IES")]
+        [AuthToken(Roles = "teacher,admin,area,student")]
+#endif
+        public async Task<IActionResult> GetPaperItems(JsonElement json)
         {
-            Dictionary<string, string> dict = new Dictionary<string, string>() { { "id", $"{authCode.paperid}" }, { "user_id", $"{authCode.openid}" } };
+            if (!json.TryGetProperty("paperid", out JsonElement paperid)) { return BadRequest(); }
+            if (!json.TryGetProperty("openid", out JsonElement openid)) { return BadRequest(); }
+            Dictionary<string, string> dict = new Dictionary<string, string>() { { "id", $"{paperid}" }, { "user_id", $"{openid}" } };
             var paper = _xkwAPIHttpService.Get<JsonElement>("/xopqbm/zj-saas/users/download-papers/details", dict);
+            List<XkwItem> items = new List<XkwItem>();
+            string ps = paper.ToJsonString();
+            XkwDto course = null ;
             if (paper.TryGetProperty("code", out JsonElement code) && $"{code}".Equals("2000000"))
             {
-                if (paper.TryGetProperty("course_id", out JsonElement course_id)) {
-                    var course =  XkwConstant.xkwCourses.Find(x => $"{course_id}".Equals($"{x.id}"));
+                
+                    if (paper.TryGetProperty("data", out JsonElement data)  &&  data.TryGetProperty("course_id", out JsonElement course_id)) {
+                    course =  XkwConstant.xkwCourses.Find(x => $"{course_id}".Equals($"{x.id}"));
                     if (course != null) {
-                        if (paper.TryGetProperty("body", out JsonElement body)) {
+                        if (data.TryGetProperty("body", out JsonElement body)) {
                             List<XkwPaperPart> paperParts = body.ToObject<List<XkwPaperPart>>();
+                            items.AddRange(paperParts.SelectMany(x => x.part_body).SelectMany(z=>z.questions));
                         }
                     }
                 }
             }
-            await _dingDing.SendBotMsg($"学科网推送消息:{authCode.ToJsonString()}", GroupNames.成都开发測試群組);
-            return Ok(authCode);
+            List<XkwItemInfo> itemInfos = new List<XkwItemInfo>();
+            List<XkwDto> xkw_points = new List<XkwDto>();
+            var kpoint_ids=items.SelectMany(x => x.kpoint_ids).ToHashSet();
+            if (kpoint_ids.Any()) {
+                Dictionary<string, string> dict_pointids = new Dictionary<string, string>() { { "ids", String.Join(",", kpoint_ids.Select(x => x)) } };
+                var points = _xkwAPIHttpService.Get<JsonElement>("/xopqbm/knowledge-points", dict_pointids);
+
+                if (points.TryGetProperty("code", out JsonElement pcode) && $"{pcode}".Equals("2000000")) {
+                    if (points.TryGetProperty("data", out JsonElement pdata)) {
+                        xkw_points = pdata.ToObject<List<XkwDto>>();
+                    }
+                }
+            }
+            int index = 1;
+            items.ForEach(x => {
+                //x.kpoint_ids
+                XkwItemInfo itemInfo = new XkwItemInfo
+                {
+                    source = 3,
+                    shaCode = ShaHashHelper.GetSHA1(x.stem),
+                    id = x.id,
+                    order = index,
+                    explain = x.explanation,
+                    subjectName = course?.subject_name,
+                    periodName = course?.stage_name,
+                    // explain = x.explanation.Replace("【分析】", "分析:").Replace("【详解】", "详解:")
+                     
+                };
+                index += 1;
+                //设置默认难度,和默认认知层次
+                itemInfo.field = 1;
+                itemInfo.level = 3;
+                foreach (var difct in XkwConstant.xkwDifficulties) {
+                    if (x.difficulty < difct.ceiling && x.difficulty >= difct.flooring) {
+                        itemInfo.level = difct.level;
+                    }
+                }
+                var grades=    XkwConstant.xkwGrades.FindAll(g => x.grade_ids.Contains(g.id));
+                if (grades.Any()) {
+                    itemInfo.gradeNames = grades.Select(g => g.name).ToList();
+                }
+                if (x.kpoint_ids.Any()) {
+                    var points =  xkw_points.FindAll(p => x.kpoint_ids.Contains(p.id));
+                    if (points.Any()) {
+                        
+                        itemInfo.knowledge.AddRange(points.Select(x => x.name));
+                    }
+                }
+                var type= XkwConstant.xkwQuestionTypes.Find(t => t.id == x.type_id);
+                //判断是否 主客观题
+                if (type != null) {
+                    itemInfo.objective =type.objective;
+                    itemInfo.tag = type.name;
+                }
+                else { 
+                    itemInfo.objective = false; 
+                }
+                //如果是客观题,则需要处理选项和答案。
+                if (itemInfo.objective)
+                {
+                    string classpattern = "class=\"([^\"]*)\"";
+                    string pattern = "<span([^>]{0,})>";
+                    string apattern = "<a([^>]{0,})></a>";
+                    string shtml = x.stem;
+                    //去除class 以及span标签"
+                    //shtml = Regex.Replace(shtml, classpattern, "");
+                    //shtml = Regex.Replace(shtml, pattern, "");
+                    //shtml = Regex.Replace(shtml, apattern, "");
+                    //shtml = shtml.Replace(" close=\"\" separators=\" | \">", "");
+                    //shtml = shtml.Replace("\t", " ").Replace("<span>", "").Replace("</span>", "").Replace("dir=\"ltr\"", "");
+                    //处理 标签中包含的空格字符
+
+                    //处理题干
+                    (List<CodeValue> options, string question) = OptionProcess(shtml);
+                    itemInfo.option = options;
+                    itemInfo.opts = options.Count;
+                    itemInfo.question = question;
+
+                    //处理答案
+                    //去除class 以及span标签"
+                    string ahtml = x.answer;
+                    ahtml = Regex.Replace(ahtml, classpattern, "");
+                    ahtml = Regex.Replace(ahtml, pattern, "");
+                    ahtml = Regex.Replace(ahtml, apattern, "");
+                    ahtml = ahtml.Replace(" close=\"\" separators=\" | \">", "");
+                    ahtml = ahtml.Replace("\t", " ").Replace("<span>", "").Replace("</span>", "").Replace("dir=\"ltr\"", "");
+                    HashSet<string> ans = new HashSet<string>();
+                    var anstr = BlankTag(ahtml);
+                    for (int idx = 0; idx < 26; idx++)
+                    {
+                        anstr = anstr.Replace(aza[idx], azh[idx]);
+                    }
+
+                    anstr.Select(s => s.ToString()).ToList().ForEach(x =>
+                    {
+                        ans.Add(x);
+                    });
+                    itemInfo.answerHtml = x.answer;
+                    itemInfo.answer = ans.ToList() ;
+                    if (ans.Count > 1)
+                    {
+                        itemInfo.type = "multiple";
+                    }
+                    else {
+                        itemInfo.type = "single";
+                    }
+                }
+                else {
+                    itemInfo.type = "subjective";
+                    itemInfo.question = x.stem;
+                    itemInfo.answer = new List<string>() { HtmlHelper.DoUselessTag(x.answer.ToString()) };
+                }
+                itemInfos.Add(itemInfo);
+
+
+            });
+            HashSet<string> gradeNames = new HashSet<string>();
+            gradeNames = itemInfos.SelectMany(x => x.gradeNames).ToHashSet();
+           // await _dingDing.SendBotMsg($"学科网推送消息:{authCode.ToJsonString()}", GroupNames.成都开发測試群組);
+            return Ok(new { periodName=course.stage_name, subjectName=course.subject_name, gradeNames, knowledge=xkw_points.Select(x=>x.name), itemInfos, paper });
+        }
+
+        private string BlankTag(string tagHtml)
+        {
+            //去掉标签中的Html
+            HtmlDocument doc = new HtmlDocument();
+            doc.LoadHtml(tagHtml);
+            var tagValue = doc.DocumentNode.InnerText.Replace("{", "").Replace("}", "")
+                        .Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "")
+                        .Replace("&nbsp;", "").Replace("&emsp;", "").Replace("&emsp;", "");
+            // tagValue = Regex.Replace(tagValue, @"\d", "");
+            tagValue = Regex.Replace(tagValue, @"\s", "");
+            return tagValue;
+        }
+
+        public (List<CodeValue> options, string question) OptionProcess(string question) {
+
+            string Options = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+            string[] optionsKeys = Options.Select(s => s.ToString()).ToArray();
+            for (int idx = 0; idx < 26; idx++)
+            {
+                question = question.Replace(aza[idx], azh[idx]);
+            }
+            List<CodeValue> options = new List<CodeValue>();
+            string optsRgex = optionsKeys[0] + "\\s*(\\.|\\.|\\、|\\:|\\:)([\\s\\S]*?).*"; ;
+            string optsHtml = Regex.Match(question, optsRgex).Value;
+            StringBuilder textImg = new StringBuilder();
+            for (int i = 0; i < optionsKeys.Length - 1; i++)
+            {
+                string optRgex = optionsKeys[i] + "\\s*(\\.|\\.|\\、|\\:|\\:)([\\s\\S]*?)" + optionsKeys[i + 1] + "\\s*(\\.|\\.|\\、|\\:|\\:)";
+                string optHtml = Regex.Match(optsHtml, optRgex).Value;
+                if (string.IsNullOrWhiteSpace(optHtml))
+                {
+                    optRgex = optionsKeys[i] + "\\s*(\\.|\\.|\\、|\\:|\\:).*";
+                    optHtml = Regex.Match(optsHtml, optRgex).Value;
+                }
+                if (!string.IsNullOrEmpty(optHtml))
+                {
+                    optHtml = Regex.Replace(optHtml, optionsKeys[i + 1] + "\\s*(\\.|\\.|\\、|\\:|\\:)", "");
+                    optHtml = optHtml.Substring(2, optHtml.Length - 2);
+                    optHtml = HtmlHelper.DoUselessTag(optHtml);
+                    optHtml = optHtml.TrimStart().TrimEnd();
+                    textImg.Append(HtmlHelper.DoTextImg(optHtml));
+                    options.Add(new CodeValue { code = optionsKeys[i], value = optHtml });
+                }
+            }
+            if (!string.IsNullOrWhiteSpace(optsHtml))
+            {
+                return (options, question.Replace(optsHtml, ""));
+            }
+            else
+            {
+                return (new List<CodeValue>(), question);
+            }
         }
     }
 }