MoofenController.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. using Microsoft.AspNetCore.Authorization;
  2. using Microsoft.AspNetCore.Http;
  3. using Microsoft.AspNetCore.Mvc;
  4. using Microsoft.Extensions.Configuration;
  5. using Microsoft.IdentityModel.Tokens;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.IdentityModel.Tokens.Jwt;
  9. using System.Security.Claims;
  10. using System.Text;
  11. using System.Text.Json;
  12. using System.Threading.Tasks;
  13. using System.Web;
  14. using TEAMModelOS.Filter;
  15. using TEAMModelOS.SDK;
  16. using TEAMModelOS.SDK.Models;
  17. using TEAMModelOS.SDK.Extension;
  18. using DocumentFormat.OpenXml.Wordprocessing;
  19. using System.Linq;
  20. using System.Net.Http;
  21. using System.Net.Http.Json;
  22. using System.Net;
  23. using System.Net.Http.Headers;
  24. using HTEXLib.COMM.Helpers;
  25. using TEAMModelOS.SDK.DI;
  26. using HTEXLib.Helpers.ShapeHelpers;
  27. using HtmlAgilityPack;
  28. using Top.Api.Util;
  29. namespace TEAMModelOS.Controllers.Third.Moofen
  30. {
  31. [ProducesResponseType(StatusCodes.Status200OK)]
  32. [ProducesResponseType(StatusCodes.Status400BadRequest)]
  33. [ApiController]
  34. public class MoofenController : ControllerBase
  35. {
  36. private readonly CoreAPIHttpService _coreAPIHttpService;
  37. private readonly IConfiguration _configuration;
  38. private readonly IHttpClientFactory _httpClient;
  39. private readonly DingDing _dingDing;
  40. private readonly AzureCosmosFactory _azureCosmos;
  41. public MoofenController(AzureCosmosFactory azureCosmos,CoreAPIHttpService coreAPIHttpService, IConfiguration configuration, IHttpClientFactory httpClient, DingDing dingDing)
  42. {
  43. _coreAPIHttpService=coreAPIHttpService;
  44. _configuration=configuration;
  45. _httpClient=httpClient;
  46. _dingDing=dingDing;
  47. _azureCosmos=azureCosmos;
  48. }
  49. [HttpPost("moofen/question")]
  50. [AuthToken(Roles = "teacher,admin")]
  51. [Authorize(Roles = "IES")]
  52. public async Task<IActionResult> Question(JsonElement json)
  53. {
  54. var tokenData= HttpContext.GetAuthTokenInfo();
  55. string content = string.Empty;
  56. try {
  57. School school = null;
  58. Dictionary<string, string> dict = new Dictionary<string, string>();
  59. if (json.TryGetProperty("search", out JsonElement search) && !string.IsNullOrWhiteSpace($"{search}"))
  60. {
  61. dict.Add("search", $"{search}");
  62. }
  63. if (json.TryGetProperty("isSchoolItem", out JsonElement schoolItem) && schoolItem.ValueKind.Equals(JsonValueKind.True) &&!string.IsNullOrWhiteSpace(tokenData.school))
  64. {
  65. dict.Add("exSchId", $"{tokenData.school}");
  66. school= await _azureCosmos.GetCosmosClient().GetContainer(Constant.TEAMModelOS, Constant.School).ReadItemAsync<School>(tokenData.school, new Azure.Cosmos.PartitionKey("Base"));
  67. }
  68. if (json.TryGetProperty("subject", out JsonElement subject) && !string.IsNullOrWhiteSpace($"{subject}"))
  69. {
  70. dict.Add("subject", $"{subject}");
  71. }
  72. if (json.TryGetProperty("grades", out JsonElement grades) && !string.IsNullOrWhiteSpace($"{grades}"))
  73. {
  74. dict.Add("grades", $"{grades}");
  75. }
  76. if (json.TryGetProperty("type", out JsonElement type) && !string.IsNullOrWhiteSpace($"{type}"))
  77. {
  78. dict.Add("type", $"{type}");
  79. }
  80. if (json.TryGetProperty("difficulty", out JsonElement difficulty) && !string.IsNullOrWhiteSpace($"{difficulty}"))
  81. {
  82. dict.Add("difficulty", $"{difficulty}");
  83. }
  84. if (json.TryGetProperty("year", out JsonElement year) && !string.IsNullOrWhiteSpace($"{year}"))
  85. {
  86. dict.Add("year", $"{year}");
  87. }
  88. if (json.TryGetProperty("hasKps", out JsonElement hasKps) && !string.IsNullOrWhiteSpace($"{hasKps}"))
  89. {
  90. dict.Add("hasKps", $"{hasKps}");
  91. }
  92. if (json.TryGetProperty("hasAnswer", out JsonElement hasAnswer) && !string.IsNullOrWhiteSpace($"{hasAnswer}"))
  93. {
  94. dict.Add("hasAnswer", $"{hasAnswer}");
  95. }
  96. if (json.TryGetProperty("pageSize", out JsonElement pageSize) && !string.IsNullOrWhiteSpace($"{pageSize}"))
  97. {
  98. dict.Add("pageSize", $"{pageSize}");
  99. }
  100. if (json.TryGetProperty("currentPage", out JsonElement currentPage) && !string.IsNullOrWhiteSpace($"{currentPage}"))
  101. {
  102. dict.Add("currentPage", $"{currentPage}");
  103. }
  104. dict.Add("signKey", "TMD");
  105. var keys = dict.Keys.OrderBy(x => x);
  106. var parmas = string.Join("&", keys.Select(x => $"{x}={dict[x]}"));
  107. var signtime = DateTimeOffset.UtcNow.GetGMTTime(8).ToUnixTimeSeconds();
  108. parmas=$"{parmas}&signtime={signtime}";
  109. string sign = Md5Hash.Encrypt(parmas);
  110. dict.Add("signtime", $"{signtime}");
  111. dict.Add("sign", $"{sign}");
  112. dict.Remove("signKey");
  113. var pkeys = dict.Keys;
  114. string url = "http://www.moofen.net/esi/tmd/question/list";
  115. parmas= string.Join("&", pkeys.Select(x => $"{x}={dict[x]}"));
  116. var httpClient = _httpClient.CreateClient();
  117. var request = new HttpRequestMessage();
  118. request.Method = new HttpMethod("POST");
  119. request.RequestUri = new Uri(url);
  120. request.Content = new FormUrlEncodedContent(dict);
  121. // 设置请求头中的Content-Type
  122. // httpClient.DefaultRequestHeaders.Add("Content-Type", "application/x-www-form-urlencoded");
  123. var mediaTypeHeader = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
  124. mediaTypeHeader.CharSet = "UTF-8";
  125. request.Content.Headers.ContentType=mediaTypeHeader;
  126. HttpResponseMessage response = await _httpClient.CreateClient().SendAsync(request);
  127. List<MoofenItemInfo> items = new List<MoofenItemInfo>();
  128. if (response.StatusCode.Equals(HttpStatusCode.OK))
  129. {
  130. content = await response.Content.ReadAsStringAsync();
  131. var data = content.ToObject<JsonElement>();
  132. int count = 0;
  133. if (data.TryGetProperty("data", out JsonElement _data) )
  134. {
  135. if (_data.TryGetProperty("total", out JsonElement _total) && int.TryParse($"{_total}", out count))
  136. {
  137. if (_data.TryGetProperty("data", out JsonElement __data))
  138. {
  139. List<MoofenQuestion> questions = __data.ToObject<List<MoofenQuestion>>();
  140. items = MoofenQS(questions, $"{subject}", schoolId: $"{tokenData.school}", pquestion: null);
  141. //foreach (var item in items)
  142. //{
  143. // //break;
  144. // string urlAI = "https://appraisal-test.teammodel.cn/ai/chat/completion";
  145. // ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
  146. // var contentAI = new StringContent(JsonSerializer.Serialize(new
  147. // {
  148. // // appId = "5ac43c20-221e-4564-829d-15680ad761df",
  149. // appId = "eef773fd-85e7-4c2b-a6f7-e667af2f4f45",
  150. // sessionId = "",
  151. // text = item.description,
  152. // }), Encoding.UTF8, "application/json");
  153. // var httpreq = new HttpRequestMessage(HttpMethod.Post, urlAI) { Content = contentAI };
  154. // var authtoken = HttpContext.GetXAuth("AuthToken");
  155. // if (!httpClient.DefaultRequestHeaders.Contains("X-Auth-Authtoken"))
  156. // {
  157. // httpClient.DefaultRequestHeaders.Add("X-Auth-Authtoken", authtoken);
  158. // }
  159. // var AuthorizationToken = HttpContext.GetAuthorization();
  160. // if (httpClient.DefaultRequestHeaders.Contains("Authorization"))
  161. // {
  162. // httpClient.DefaultRequestHeaders.Remove("Authorization");
  163. // }
  164. // httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {AuthorizationToken}");
  165. // httpClient.DefaultRequestHeaders.AcceptCharset.Add(new StringWithQualityHeaderValue("utf-8"));
  166. // var responseAI = await httpClient.SendAsync(httpreq, HttpCompletionOption.ResponseHeadersRead);
  167. // if (responseAI.StatusCode==HttpStatusCode.OK)
  168. // {
  169. // StringBuilder dataAI = new StringBuilder();
  170. // // 读取响应内容的异步流
  171. // using (var responseStream = await responseAI.Content.ReadAsStreamAsync())
  172. // {
  173. // //Debug.Print("============start response use minseconds=" + (DateTime.Now - d).TotalMilliseconds + " =================\r\n");
  174. // // 逐块读取并处理响应内容
  175. // var buffer = new byte[1024];
  176. // int bytesRead;
  177. // while ((bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
  178. // {
  179. // // 处理响应内容
  180. // string contentData = System.Text.Encoding.UTF8.GetString(buffer, 0, bytesRead);
  181. // if (contentData.Contains("data:"))
  182. // {
  183. // contentData = contentData.Replace("data:", "").Replace("[DONE]", "");
  184. // }
  185. // if (contentData.Contains("[DONE]"))
  186. // {
  187. // contentData = contentData.Replace("data:", "").Replace("[DONE]", "");
  188. // }
  189. // dataAI.Append(contentData);
  190. // }
  191. // }
  192. // item.explain=dataAI.ToString();
  193. // }
  194. //}
  195. }
  196. }
  197. }
  198. return Ok(new { code = 200, data, items , count });
  199. }
  200. else
  201. {
  202. content = await response.Content.ReadAsStringAsync();
  203. return Ok(new { code = response.StatusCode, data = content }) ;
  204. }
  205. } catch (Exception ex) {
  206. await _dingDing.SendBotMsg($"多分题目异常{ex.Message}\n{ex.StackTrace}",GroupNames.成都开发測試群組);
  207. return Ok(new { code = 500,msg=$"{ex.Message}",data= content });
  208. }
  209. }
  210. private List<MoofenItemInfo> MoofenQS(List<MoofenQuestion> questions, string subject,string pquestion,string schoolId, string pid = null)
  211. {
  212. List<MoofenItemInfo> items = new List<MoofenItemInfo>();
  213. if (questions.IsNotEmpty())
  214. {
  215. //综合题 子题id处理
  216. if (!string.IsNullOrWhiteSpace(pid)) {
  217. int index = 1;
  218. foreach (MoofenQuestion question in questions) {
  219. question.questionCode= $"{pid}_{index}";
  220. index++;
  221. }
  222. }
  223. foreach(var x in questions) {
  224. MoofenItemInfo item = new MoofenItemInfo()
  225. {
  226. id=x.questionCode,
  227. source=4,
  228. question=x.trunk,
  229. option=x.options?.Select(x => new CodeValue { code=x.label, value=x.content }).ToList(),
  230. level=x.difficulty,
  231. knowledge=x.kps?.Select(x => x.kpName).ToList(),
  232. grade=x.scope?.grade?.code,
  233. gradeName=x.scope?.grade?.name,
  234. subject=subject,
  235. pid=pid,
  236. code=!string.IsNullOrWhiteSpace(schoolId)?$"{schoolId}":null,
  237. pk="Item",
  238. scope=!string.IsNullOrWhiteSpace(schoolId) ? "school" : null,
  239. };
  240. //
  241. StringBuilder description = new StringBuilder($"科目:{subject}") ;
  242. if (!string.IsNullOrWhiteSpace(pquestion)) {
  243. description.AppendLine($";综合题:{pquestion}");
  244. }
  245. //处理年级转换
  246. if (!string.IsNullOrWhiteSpace(x.scope?.grade?.code) ) {
  247. item.gradeIds= new List<string>() { x.scope?.grade?.code };
  248. }
  249. if (!string.IsNullOrWhiteSpace(x.type?.code))
  250. {
  251. switch (x.type.code)
  252. {
  253. //选择
  254. case "C":
  255. var lables = x.options?.Where(y => y.correct==true).Select(v => v.label);
  256. if (lables!=null)
  257. {
  258. item.answer=lables.ToList();
  259. }
  260. item.objective=true;
  261. item.type="single";
  262. if (item.answer!=null && item.answer.Count()>1)
  263. {
  264. item.type="multiple";
  265. }
  266. if (x.options.IsNotEmpty())
  267. {
  268. item.opts=x.options.Count();
  269. }
  270. item.field=1;
  271. description.AppendLine(";题型:选择题");
  272. break;
  273. //填空
  274. case "F":
  275. var fills = x.items?.Select(b => b.content);
  276. if (fills!=null)
  277. {
  278. item.answer=fills.ToList();
  279. item.blankCount=fills.Count();
  280. }
  281. item.type="complete";
  282. item.field=2;
  283. description.AppendLine(";题型:填空题");
  284. break;
  285. //问答
  286. case "Q":
  287. if (!string.IsNullOrWhiteSpace(x.content))
  288. {
  289. item.answer=new List<string>() { x.content };
  290. }
  291. item.type="subjective";
  292. description.AppendLine(";题型:问答题");
  293. item.field=4;
  294. break;
  295. //写作
  296. case "W":
  297. if (!string.IsNullOrWhiteSpace(x.content))
  298. {
  299. item.answer=new List<string>() { x.content };
  300. }
  301. item.type="subjective";
  302. description.AppendLine(";题型:写作题");
  303. item.field=6;
  304. break;
  305. //综合
  306. case "S":
  307. item.type="compose";
  308. item.field=3;
  309. if (x.questions.IsNotEmpty() && x.questions.Count>0) {
  310. item.children.AddRange(MoofenQS(x.questions,subject: subject,pquestion: item.question,schoolId:schoolId,pid: item.id));
  311. }
  312. description.AppendLine(";题型:综合题");
  313. break;
  314. }
  315. }
  316. StringBuilder sb = new StringBuilder($"{item.question}");
  317. if (item.option.IsNotEmpty()) {
  318. foreach (var option in item.option)
  319. {
  320. sb.Append(option.value);
  321. }
  322. }
  323. if (item.children.IsNotEmpty()) {
  324. foreach(var child in item.children)
  325. {
  326. sb.Append(child.question);
  327. if (child.option.IsNotEmpty())
  328. {
  329. foreach (var option in child.option)
  330. {
  331. sb.Append(option.value);
  332. }
  333. }
  334. }
  335. }
  336. string unhtml = HtmlHelper.DoUselessTag(sb.ToString());
  337. description.AppendLine($";题干:{item.question}");
  338. if (item.option.IsNotEmpty())
  339. {
  340. description.AppendLine($";选项:");
  341. foreach (var option in item.option) {
  342. description.AppendLine($"{option.code}:{option.value}");
  343. }
  344. }
  345. if(item.answer.IsNotEmpty())
  346. {
  347. description.AppendLine($";答案:{string.Join(",",item.answer)}");
  348. }
  349. if (item.knowledge.IsNotEmpty()) {
  350. description.AppendLine($";知识点:{string.Join(",", item.knowledge)}");
  351. }
  352. //HtmlDocument doc = new HtmlDocument();
  353. //doc.LoadHtml(description.ToString());
  354. item.description = description.ToString().Replace("\r\n","").Replace("&nbsp;","").Replace("\n\n","").Replace("&ldquo;","").Replace("&rdquo;","").Replace("<br />","").Replace("<!--EA-->","").Replace("<!--BA-->","")
  355. .Replace("</sup>","").Replace("<sup>", "").Replace("<u>", "").Replace("</u>", "");
  356. item.shaCode= ShaHashHelper.GetSHA1(unhtml);
  357. items.Add(item);
  358. }
  359. }
  360. return items;
  361. }
  362. [HttpPost("moofen/sso")]
  363. [AuthToken(Roles = "teacher,admin")]
  364. [Authorize(Roles = "IES")]
  365. public async Task<IActionResult> Sso(JsonElement json)
  366. {
  367. (string _id, _, _, string school) = HttpContext.GetAuthTokenInfo();
  368. CoreUser core = await _coreAPIHttpService.GetUserInfo(new Dictionary<string, string>()
  369. { { "key",$"{_id}" }
  370. }, "China", _configuration
  371. );
  372. if ( !string.IsNullOrWhiteSpace(core?.mobile))
  373. {
  374. string key = "U@vY42qlgq9ASXLXNqfze%Jj-NQ!ZKrX$iKonXy1u^8F021c7bzo@t5$ANwWCor#";
  375. string code = core?.mobile; //手机号码
  376. var claims = new[]
  377. {
  378. new Claim("code",code)
  379. };
  380. var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
  381. var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
  382. var jwt = new JwtSecurityToken(
  383. claims: claims,
  384. expires: DateTime.Now.AddMinutes(5),
  385. signingCredentials: signinCredentials
  386. );
  387. var tokenString = new JwtSecurityTokenHandler().WriteToken(jwt);
  388. string url = $"http://www.moofen.net/sso/tmodel/login?a={HttpUtility.UrlEncode(tokenString)}&c=doofen&t={DateTimeOffset.Now.ToUnixTimeSeconds()}";
  389. return Ok(new {code=200,url });
  390. }
  391. return Ok(new { code = 400 });
  392. }
  393. }
  394. public class MoofenQuestion
  395. {
  396. public int difficulty { get; set; }
  397. public string questionCode { get; set; }
  398. public MoofenScope scope { get; set; }
  399. public List<MoofenOption> options { get; set; }
  400. public MoofenType @type { get; set; }
  401. public string trunk { get; set; }
  402. public List<MoofenQuestion> questions { get; set; }
  403. /// <summary>
  404. /// 填空题的答案
  405. /// </summary>
  406. public List<MoofenFill> items { get; set; }
  407. /// <summary>
  408. /// 问答题的答案
  409. /// </summary>
  410. public string content { get; set; }
  411. public List<MoofenKnowledgePoint> kps { get; set; }
  412. }
  413. public class MoofenFill
  414. {
  415. public string content { get; set; }
  416. }
  417. public class MoofenScope {
  418. public MoofenGrade grade { get; set; }
  419. }
  420. public class MoofenGrade
  421. {
  422. public string code { get; set; }
  423. public string name { get; set; }
  424. }
  425. public class MoofenOption
  426. {
  427. public bool correct { get; set; }
  428. public string label { get; set; }
  429. public string content { get; set; }
  430. }
  431. public class MoofenType
  432. {
  433. public string code { get; set; }
  434. public string name { get; set; }
  435. }
  436. public class MoofenKnowledgePoint
  437. {
  438. public string kpCode { get; set; }
  439. public string kpId { get; set; }
  440. public string kpSetId { get; set; }
  441. public string kpName { get; set; }
  442. public string subCode { get; set; }
  443. public int kpLevel { get; set; }
  444. public string id { get; set; }
  445. public string parKpId { get; set; }
  446. }
  447. }