diff --git a/VideoAnalysis/Program.cs b/VideoAnalysis/Program.cs index 38c041a..34a7737 100644 --- a/VideoAnalysis/Program.cs +++ b/VideoAnalysis/Program.cs @@ -63,6 +63,7 @@ namespace Learn.VideoAnalysis builder.Configuration.AddAppConfig(args); builder.Services.AddSqlSugarExpand(); + builder.Services.AddSimpleTexOcrClient(); builder.Services.AddDownloadFileExpand(); builder.Services.AddAlibabaCloudVod(); builder.Services.AddRedisExpand(); diff --git a/VideoAnalysis/appsettings.json b/VideoAnalysis/appsettings.json index 2e2bc56..60d4698 100644 --- a/VideoAnalysis/appsettings.json +++ b/VideoAnalysis/appsettings.json @@ -48,6 +48,11 @@ "aliyun": { "Host": "https://dashscope.aliyuncs.com/compatible-mode/", "ApiKey": "sk-1742c2bf7b9846ae835de598dc6c427b" + }, + "SimpLetex": { + "Host": "https://api.deepseek.com/chat/completions", + "AppSecret": "05ZbPfCFZgTmfd4uIqHHc9pHgYR2V8bk", + "AppId": "GH2OXwuxSZEH5W28H61bdSzD" } }, "DB": { diff --git a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs index 28f492a..a5f5ca7 100644 --- a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs +++ b/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs @@ -76,10 +76,6 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek var captionsArr = JsonSerializer.Deserialize(taskInfo.Captions); var fileNameResFormat = "{授课章节: string|null}"; - //var fileNamePostMessages = title + - // " 这是一堂课的标题,请你基于标题帮我分析出这堂课所讲授的内容与最恰当的授课章节(关联最贴切的章节,保留一个章节!)." + - // $"章节范围限定在[{string.Join(',', xkwKnows)}]范围内." + - // $"输出格式 json字符串 对象格式{fileNameResFormat}"; var rCaptionArr = string.Join(',', captionsArr .Where((s, i) => i % 3 == 0) .Take((int)(captionsArr?.Length ?? 0 / 2.2)) diff --git a/VideoAnalysisCore/Common/AppConfig.cs b/VideoAnalysisCore/Common/AppConfig.cs index b5ce884..d2d53fd 100644 --- a/VideoAnalysisCore/Common/AppConfig.cs +++ b/VideoAnalysisCore/Common/AppConfig.cs @@ -59,8 +59,29 @@ namespace VideoAnalysisCore.Common /// public TaskSettingConfig TaskSetting { get; set; } = new TaskSettingConfig(); + /// + /// SimpLetex配置 + /// + public SimpLetexConfig SimpLetex { get; set; } = new SimpLetexConfig(); + } + public class SimpLetexConfig + { + /// + /// 请求 公开的服务地址 + /// + public string Host { get; set; } = string.Empty; + /// + /// api的密钥 + /// + public string AppSecret { get; set; } = string.Empty; + /// + /// 应用ID + /// + public string AppId { get; set; } = string.Empty; + + } public class TaskSettingConfig { /// diff --git a/VideoAnalysisCore/Common/AlibabaCloudVodExpand.cs b/VideoAnalysisCore/Common/Expand/AlibabaCloudVodExpand.cs similarity index 100% rename from VideoAnalysisCore/Common/AlibabaCloudVodExpand.cs rename to VideoAnalysisCore/Common/Expand/AlibabaCloudVodExpand.cs diff --git a/VideoAnalysisCore/Common/Expand/SimpLetexExpand.cs b/VideoAnalysisCore/Common/Expand/SimpLetexExpand.cs new file mode 100644 index 0000000..01a2dfb --- /dev/null +++ b/VideoAnalysisCore/Common/Expand/SimpLetexExpand.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Sockets; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using AlibabaCloud.OpenApiClient.Models; +using AlibabaCloud.SDK.Vod20170321; +using AlibabaCloud.SDK.Vod20170321.Models; +using AlibabaCloud.TeaUtil.Models; +using Azure; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using VideoAnalysisCore.Job; + +namespace VideoAnalysisCore.Common +{ + /// + /// 请求参数 + /// + public class SimpleTexOcrRequest + { + /// + /// 合法的图片二进制文件信息,包括png/jpg等格式,无法开启批量调用,仅支持一次上传一张图片 + /// + public FileStream file { get; set; } + /// + /// 用以指定识别图片的类型,如果使用auto则会自动检测,使用document会返回markdown文档结果,使用formula会返回LaTeX结果 + /// "auto", "document", "formula" + /// + public string rec_mode { get; set; } = "auto"; + /// + /// 开启后,模型将基于0°,90°, 180°, 270°自动矫正上传图片的方向,默认不开启 + /// + public bool enable_img_rot { get; set; }=false; + /// + /// 用于修改行内公式在markdown中的包裹符号。以Json形式填入,如果格式错误将使用默认的包裹符号 + /// 示例:["$","$"] + /// + public string inline_formula_wrapper { get; set; } + /// + /// 用于修改独立行公式在markdown中的包裹符号。以Json形式填入,如果格式错误将使用默认的包裹符号 + /// 示例:["$$","$$"] + /// + public string isolated_formula_wrapper { get; set; } + } + /// + /// ocr响应 + /// + public class SimpleTexOcrResponse + { + public bool Success { get; set; } + public string Result { get; set; } + public string Error { get; set; } + } + + + public class SimpLetexClient + { + private readonly IHttpClientFactory _httpClientFactory; + private const string ApiUrl = "https://server.simpletex.cn/api/simpletex_ocr"; + public SimpLetexClient( + IHttpClientFactory httpClientFactory) + { + _httpClientFactory = httpClientFactory; + } + + public async Task ProcessImageAsync(SimpleTexOcrRequest request) + { + var client = _httpClientFactory.CreateClient(); + using var content = new MultipartFormDataContent(); + var parameters = new Dictionary(); + + // 添加文件内容 + var fileContent = new StreamContent(request.file); + fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg"); + content.Add(fileContent, nameof(request.file)); + + // 添加并收集其他参数 + if (request.rec_mode != "auto") + { + content.Add(new StringContent(request.rec_mode), nameof(request.rec_mode)); + parameters[nameof(request.rec_mode)] = request.rec_mode; + } + + var enableImgRotStr = request.enable_img_rot.ToString().ToLower(); + content.Add(new StringContent(enableImgRotStr), nameof(request.enable_img_rot)); + parameters[nameof(request.enable_img_rot)] = enableImgRotStr; + + if (request.inline_formula_wrapper != null) + { + content.Add(new StringContent(request.inline_formula_wrapper), nameof(request.inline_formula_wrapper)); + parameters[nameof(request.inline_formula_wrapper)] = request.inline_formula_wrapper; + } + + if (request.isolated_formula_wrapper != null) + { + var isolatedWrapper = JsonConvert.SerializeObject(request.isolated_formula_wrapper); + content.Add(new StringContent(isolatedWrapper), nameof(request.isolated_formula_wrapper)); + parameters[nameof(request.isolated_formula_wrapper)] = isolatedWrapper; + } + + // 生成鉴权参数 + var randomStr = Guid.NewGuid().ToString().Take(16).ToString(); + var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); + var appId = AppCommon.Config.SimpLetex.AppId; + + // 添加鉴权参数到签名集合 + parameters["random-str"] = randomStr; + parameters["timestamp"] = timestamp; + parameters["app-id"] = appId; + + // 生成签名 + + var signStr = string.Join("&", parameters + .OrderBy(p => p.Key) + .Select(p => $"{p.Key}={Uri.EscapeDataString(p.Value)}")) + + $"&secret={AppCommon.Config.SimpLetex.AppSecret}"; + var sign = ComputeMD5(signStr); + + // 创建请求并添加Header + var requestMessage = new HttpRequestMessage(HttpMethod.Post, "api/simpletex_ocr") + { + Content = content + }; + + requestMessage.Headers.Add("random-str", randomStr); + requestMessage.Headers.Add("timestamp", timestamp); + requestMessage.Headers.Add("app-id", appId); + requestMessage.Headers.Add("sign", sign); + + try + { + var response = await client.SendAsync(requestMessage); + var responseContent = await response.Content.ReadAsStringAsync(); + + return new SimpleTexOcrResponse + { + Success = response.IsSuccessStatusCode, + Result = responseContent, + Error = response.IsSuccessStatusCode ? null : $"HTTP Error: {response.StatusCode}" + }; + } + catch (Exception ex) + { + return new SimpleTexOcrResponse + { + Success = false, + Error = $"Request Failed: {ex.Message}" + }; + } + } + + private string GenerateSignatureString(IDictionary parameters, string secret) + { + var sortedParams = parameters + .OrderBy(p => p.Key) + .Select(p => $"{p.Key}={Uri.EscapeDataString(p.Value)}"); + + return string.Join("&", sortedParams) + $"&secret={secret}"; + } + + private string ComputeMD5(string input) + { + using var md5 = MD5.Create(); + var inputBytes = Encoding.UTF8.GetBytes(input); + var hashBytes = md5.ComputeHash(inputBytes); + return BitConverter.ToString(hashBytes).Replace("-", "").ToLower(); + } + } + + /// + /// 服务注册扩展 + /// + public static class SSimpLetexExtensions + { + public static IServiceCollection AddSimpleTexOcrClient( this IServiceCollection services) + { + services.AddSingleton(); + return services; + } + } +} diff --git a/VideoAnalysisCore/Controllers/LJZK_Controller.cs b/VideoAnalysisCore/Controllers/LJZK_Controller.cs index 5922083..c116291 100644 --- a/VideoAnalysisCore/Controllers/LJZK_Controller.cs +++ b/VideoAnalysisCore/Controllers/LJZK_Controller.cs @@ -157,13 +157,14 @@ namespace VideoAnalysisCore.Controllers /// Զid /// [HttpGet(Name = "TaskKnowInfo")] - public async Task TaskKnowInfo(long taskId, string? tagId) + public async Task TaskKnowInfo(string? tagId) { - if (taskId == 0 && string.IsNullOrEmpty(tagId)) + if ( string.IsNullOrEmpty(tagId)) return BadRequest(); + + var taskId = int.Parse(tagId); var task = await videoTaskDB.AsQueryable() - .WhereIF(taskId != 0, s => s.Id == taskId) - .WhereIF(!string.IsNullOrEmpty(tagId), s => s.TagId == tagId) + .WhereIF(taskId != 0, s => s.Id == taskId || s.TagId == tagId || s.PPTVideoCode== tagId) .FirstAsync(); if (task is null) return BadRequest("Ч");