parent
c39fbb7501
commit
17f75c975e
|
|
@ -49,6 +49,7 @@ namespace VideoAnalysisRazor.Layouts
|
|||
Name = "课堂指标",
|
||||
Key = "EvaluationProject",
|
||||
Icon = "question-circle",
|
||||
HideInMenu = true,
|
||||
},
|
||||
new MenuDataItem
|
||||
{
|
||||
|
|
@ -63,6 +64,14 @@ namespace VideoAnalysisRazor.Layouts
|
|||
Name = "视频任务预览",
|
||||
Key = "VideoTaskShow",
|
||||
HideInMenu = true,
|
||||
},
|
||||
new MenuDataItem
|
||||
{
|
||||
Path = "/NodeSubscriptionPage",
|
||||
Name = "文件订阅",
|
||||
Key = "NodeSubscriptionPage",
|
||||
Icon="clock-circle",
|
||||
HideInMenu = false,
|
||||
}
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
@page "/NodeSubscriptionPage"
|
||||
@using AntDesign
|
||||
@using AntDesign.TableModels
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using SqlSugar
|
||||
@using VideoAnalysisCore.Model
|
||||
@using UserCenter.Model.Enum
|
||||
|
||||
<Table @ref="_table" Loading="tableLoading" TItem="NodeSubscription" ScrollY="600px"
|
||||
PageSize="20" Total="_total" DataSource="_dataSource" @bind-SelectedRows="_selectedRows" OnChange="OnChange">
|
||||
<TitleTemplate>
|
||||
<Flex Justify="end" Gap="10">
|
||||
</Flex>
|
||||
</TitleTemplate>
|
||||
<ColumnDefinitions Context="row">
|
||||
|
||||
<ActionColumn Title="操作" Width="130px">
|
||||
<Button Type="primary" @onclick="()=> StartEdit(row)">编辑</Button>
|
||||
</ActionColumn>
|
||||
<PropertyColumn Property="c=>c.Id" Width="130px" Filterable="true" Sortable="true" />
|
||||
<PropertyColumn Property="c=>c.Subject" Filterable="true" Width="130px" />
|
||||
<PropertyColumn Property="c=>c.TaskType" Width="230px" Filterable="true" />
|
||||
<PropertyColumn Property="c=>c.NodeId" Width="130px" Filterable="true" />
|
||||
<PropertyColumn Property="c=>c.Enable" Width="100px" Filterable="true" />
|
||||
<PropertyColumn Property="c=>c.LastId" Width="200px" />
|
||||
<PropertyColumn Property="c=>c.CreateTime" />
|
||||
</ColumnDefinitions>
|
||||
</Table>
|
||||
|
||||
@{
|
||||
RenderFragment modelfooter = @<Template>
|
||||
<Button OnClick="@EditOnOkAsync" @key="@( "submit" )"
|
||||
Type="primary"
|
||||
Loading="@modalBtnLoading">
|
||||
提交
|
||||
</Button>
|
||||
<Button OnClick="()=>modalShow = false" @key="@( "back" )">取消</Button>
|
||||
</Template>;
|
||||
}
|
||||
|
||||
<Modal Title="@("编辑订阅节点")" Visible="modalShow" Width="650"
|
||||
Footer="@modelfooter">
|
||||
<Form @ref="form" Model="rowData" LabelAlign="AntLabelAlignType.Left">
|
||||
<GridRow>
|
||||
<GridCol Span="24">
|
||||
<FormItem Label="是否启用">
|
||||
<Switch Rows="1" @bind-Value="@context.Enable" />
|
||||
</FormItem>
|
||||
</GridCol>
|
||||
</GridRow>
|
||||
</Form>
|
||||
</Modal>
|
||||
@code
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
using AntDesign;
|
||||
using AntDesign.TableModels;
|
||||
using FreeRedis;
|
||||
using Learn.VideoAnalysis.Controllers.Dto;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using SqlSugar;
|
||||
using System.Drawing;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using UserCenter.Model;
|
||||
using UserCenter.Model.Enum;
|
||||
using VideoAnalysisCore.Common;
|
||||
using VideoAnalysisCore.Model.Enum;
|
||||
using VideoAnalysisCore.Model;
|
||||
|
||||
|
||||
namespace Learn.VideoAnalysis.Components.Pages
|
||||
{
|
||||
public partial class NodeSubscriptionPage : ComponentBase
|
||||
{
|
||||
|
||||
[Inject] private ConfirmService ComfirmService { get; set; } = default!;
|
||||
[Inject] private ModalService ModalService { get; set; } = default!;
|
||||
[Inject] private Repository<NodeSubscription> criteria { get; set; } = default!;
|
||||
[Inject] private INotificationService _notice { get; set; } = default!;
|
||||
|
||||
|
||||
IEnumerable<NodeSubscription> _selectedRows = [];
|
||||
ITable _table;
|
||||
IForm? form;
|
||||
|
||||
List<NodeSubscription> _dataSource = null;
|
||||
RefAsync<int> _total = 0;
|
||||
|
||||
bool tableLoading = false;
|
||||
Table<NodeSubscription> tableRef;
|
||||
List<NodeSubscription> _editSource = null;
|
||||
|
||||
|
||||
bool modalShow =false;
|
||||
bool modalBtnLoading = false;
|
||||
NodeSubscription rowData;
|
||||
SubjectEnum editSubject;
|
||||
|
||||
async void SubjectEnumSelect()
|
||||
{
|
||||
_editSource = await criteria.GetListAsync(x => x.Subject == editSubject);
|
||||
await this.InvokeAsync(StateHasChanged);
|
||||
}
|
||||
void EditAddRow()
|
||||
{
|
||||
if (form is not null && form.Validate())
|
||||
{
|
||||
var data = rowData;
|
||||
data.Subject = editSubject;
|
||||
if (_editSource is null)
|
||||
_editSource = new() { data };
|
||||
else
|
||||
_editSource.Add(data);
|
||||
rowData = new();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 新增或者修改
|
||||
/// </summary>
|
||||
void StartEdit(NodeSubscription data)
|
||||
{
|
||||
rowData = data?? new();
|
||||
modalShow = true;
|
||||
}
|
||||
|
||||
async Task EditOnOkAsync()
|
||||
{
|
||||
var data = rowData;
|
||||
modalBtnLoading = true;
|
||||
await criteria.DeleteAsync(s => s.Subject == editSubject);
|
||||
await criteria.InsertRangeAsync(_editSource);
|
||||
|
||||
_table.ReloadData();
|
||||
modalShow = false;
|
||||
modalBtnLoading = false;
|
||||
StateHasChanged();
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 分页 查询 筛选 时
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
async void OnChange(QueryModel<NodeSubscription> query)
|
||||
{
|
||||
tableLoading = true;
|
||||
List<IConditionalModel> where = default!;
|
||||
if (query.FilterModel != null && ((query.FilterModel?.Count() ?? 0) > 0))
|
||||
{
|
||||
where = query.ToSqlSugerWhere();
|
||||
}
|
||||
_dataSource = await criteria.AsQueryable()
|
||||
.Where(where)
|
||||
.ToPageListAsync(query.PageIndex, query.PageSize, _total);
|
||||
tableLoading = false;
|
||||
StateHasChanged();
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 删除行
|
||||
/// </summary>
|
||||
/// <param name="row"></param>
|
||||
/// <returns></returns>
|
||||
async Task Delete(NodeSubscription row)
|
||||
{
|
||||
if (!await Comfirm($"确定要删除这条数据吗? [{row.NodeId}]?"))
|
||||
return;
|
||||
await criteria.DeleteByIdAsync(row.Id);
|
||||
_table.ReloadData();
|
||||
}
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
}
|
||||
|
||||
private async Task<bool> Comfirm(string message)
|
||||
{
|
||||
return await ComfirmService.Show(message, "提示", ConfirmButtons.YesNo, ConfirmIcon.Warning) == ConfirmResult.Yes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
input[aria-hidden="true"] {
|
||||
display: none !important;
|
||||
}
|
||||
.displayNone {
|
||||
display:none !important;
|
||||
}
|
||||
.ant-table-pagination {
|
||||
display:none !important;
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ namespace Learn.VideoAnalysis.Expand
|
|||
provider.UseScheduler(scheduler =>
|
||||
{
|
||||
//每5分钟执行一次 未处理视频扫描
|
||||
//scheduler.Schedule<NodeSubscriptionJob>().EveryFiveMinutes();
|
||||
scheduler.Schedule<NodeSubscriptionJob>().EveryFiveMinutes();
|
||||
//每天两点
|
||||
scheduler.Schedule<TaskFileClearJob>().DailyAtHour(2);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ namespace Learn.VideoAnalysis.Expand
|
|||
foreach (var t in entityTypes)
|
||||
{
|
||||
Console.Write($"【1】{entityTypes.Count()}/{(++i).ToString().PadLeft(totalCount, '0')} 执行 {t.FullName}".PadRight(60, ' '));
|
||||
DbScoped.SugarScope.CodeFirst.InitTables(t);
|
||||
DbScoped.Sugar.CodeFirst.InitTables(t);
|
||||
Console.WriteLine($"【√】");
|
||||
}
|
||||
Console.WriteLine($"【1】数量{entityTypes.Count()} 执行完毕");
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="Components\Pages\NodeSubscriptionPage.razor">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
<Content Update="Components\Pages\Login.razor">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
</Content>
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ namespace Learn.VideoAnalysis
|
|||
|
||||
//³õʼ»¯ ²å¼þ
|
||||
builder.Services.AddSqlSugarExpand();
|
||||
builder.Services.AddDownloadFileExpand(2);
|
||||
builder.Services.AddAlibabaCloudVod();
|
||||
builder.Services.AddRedisExpand();
|
||||
builder.Services.AddSpeakerAI();
|
||||
|
|
@ -93,6 +94,7 @@ namespace Learn.VideoAnalysis
|
|||
builder.Services.Configure<ProSettings>(builder.Configuration.GetSection("ProSettings"));
|
||||
|
||||
builder.Services.AddHttpClient();
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
builder.Services.AddSingleton<ChatGPTClient>();
|
||||
builder.Services.AddSingleton<DeepSeekGPTClient>();
|
||||
//builder.Services.AddSingleton<IBserGPT, KIMI_GPT>();
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace VideoAnalysisCore.AICore.FFMPGE
|
|||
public static async Task Audio2WAV16KAsync(string task)
|
||||
{
|
||||
Task = task;
|
||||
var filePath = await DbScoped.SugarScope
|
||||
var filePath = await DbScoped.Sugar
|
||||
.Queryable<VideoTask>()
|
||||
.Where(s => s.Id == long.Parse(task))
|
||||
.Select(s=>s.LocalMediaPath).FirstAsync();
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
|||
throw new Exception("未能找到对应知识点=>" + fileNameInfoRes.授课章节);
|
||||
//提升到父级
|
||||
var kInfo = await knowledgeInfoDB.GetByIdAsync(know.Parent_Id);
|
||||
var knowledgeInfos = await knowledgeInfoDB.AsQueryable().ToChildListAsync(s => s.Parent_Id, kInfo.Parent_Id == 0? kInfo.Id: kInfo.Parent_Id);
|
||||
var knowledgeInfos = await knowledgeInfoDB.AsQueryable().ToChildListAsync(s => s.Parent_Id, kInfo.Parent_Id == 0 ? kInfo.Id : kInfo.Parent_Id);
|
||||
var knows = string.Join(',', knowledgeInfos.Select(s => s.Id + "|" + s.Name));
|
||||
var knowDic = knowledgeInfos
|
||||
.OrderBy(s => s.Id)
|
||||
|
|
@ -112,15 +112,17 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
|||
|
||||
var resFormat = """[{"StartTime":开始秒(number),"Theme":主题(string),"Content":内容总结(string)}]""";
|
||||
var postMessages =
|
||||
$"你的任务是分析视频字幕内容并提取出中国高考考试试题方法点,然后分析出<知识块>,来帮助学生快速了解视频字幕的内容" +
|
||||
$"你的任务是分析视频字幕内容并提取出中国高考考试试题方法点,然后分析出<知识块>来帮助学生快速了解视频字幕的内容。" +
|
||||
$"通过阅读并理解字幕内容.然后识别出{subject}学科中属于{fileNameInfoRes.授课章节}章节相关的时间段。" +
|
||||
$"关联合并知识内容相似的知识点来合并为<知识块>。" +
|
||||
$"分配空余未使用的时间段到内容相近的<知识块>时间区间来获取更加详细的上下文,但是请避免<知识块>之间时间重合。" +
|
||||
$"字幕格式(开始秒:结束秒:内容|下一段字幕).以下是包含时间的视频字幕文本。字幕列表 {captions.Captions}。" +
|
||||
$"最后请检查某些<知识块>之间的过渡是否自然,如果<知识块>时长超过500秒则考虑拆封为两个更加贴切的<知识块>.或者<知识块>时长小于30秒则考虑合并<知识块>到相邻的<知识块>)。" +
|
||||
$"字幕格式(开始秒:结束秒:内容|下一段字幕).以下是包含时间的视频字幕文本。" +
|
||||
$"字幕列表 {captions.Captions}。" +
|
||||
$"最后请检查某些<知识块>之间的过渡是否自然,如果<知识块>时长超过500秒则考虑拆封为两个更加贴切的<知识块>。" +
|
||||
$"请检查<知识块>时长小于30秒则考虑合并<知识块>到相邻的<知识块>)。" +
|
||||
$"输出内容只返回json格式({resFormat})";
|
||||
|
||||
Console.WriteLine(DateTime.Now + "=>开始分析视频内容");
|
||||
Console.WriteLine(DateTime.Now + "=>1.开始分析视频内容");
|
||||
|
||||
questionRes = await ChatAsync<VideoKnowRes[]>(task, postMessages, null);
|
||||
|
||||
|
|
@ -130,54 +132,55 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
|
|||
|
||||
var thems = JsonSerializer.Serialize(questionRes.Adapt<VideoKnowQueryDto[]>());// string.Join(',', questionRes.Select(s => s.StartTime + "->" + s.Theme));
|
||||
var checkResFormat1 = """[{"StartTime":开始秒(number),"KnowPoint":知识点名称(string),"KnowPointId":知识点Id(string)}]""";
|
||||
var knowStr = string.Join(',', knowledgeInfos.Select(s => s.Name));
|
||||
var knowMessages =
|
||||
$"我针对视频<{title}>分析出了一些视频的知识片段,现在需要你帮我将每个片段分配恰当的知识点(单个片段允许多个知识点用逗号','分割)。" +
|
||||
$"这是我的分段 {thems}。" +
|
||||
$"提供的知识点名称({knows})。 格式 (方法点Id|方法点名称) " +
|
||||
$"最后请确保分配的知识点是用户提供的,否则片段知识点值留空!。" +
|
||||
$"输出内容只返回json格式({checkResFormat1})";
|
||||
Console.WriteLine(DateTime.Now + "=>开始分析视频内容知识点");
|
||||
Console.WriteLine(DateTime.Now + "=>2.开始分析视频内容知识点");
|
||||
var konwRes = await ChatAsync<VideoKnowRes[]>(task, knowMessages, null);
|
||||
|
||||
|
||||
for (int i = 0; i < konwRes.Count(); i++)
|
||||
questionRes[i].KnowPoint = konwRes[i].KnowPoint;
|
||||
for (int i = 0; i < questionRes.Length; i++)
|
||||
{
|
||||
var item = questionRes[i];
|
||||
if (i == questionRes.Length - 1)
|
||||
item.EndTime = maxVideoTime;
|
||||
else
|
||||
item.EndTime = (int)(questionRes[i + 1]?.StartTime ?? 0) - 1;
|
||||
}
|
||||
thems = JsonSerializer.Serialize(questionRes.Adapt<VideoKnowQueryDto[]>());
|
||||
var checkResFormat = """{"Score":打分(number),"Evaluation":评价(string)""";//,"Data":优化后的分段(array)}""";
|
||||
var checkMessage = "我为视频的讲解内容做了一些分段,你能帮我检查下这些分段的时间,主题,知识点分配是否合理符合实际吗?" +
|
||||
$"请给出你的打分(0-100,70分及格)以及打分原因" +//,并且给出优化后的分段 分段格式(${checkResFormat1})" +
|
||||
//$"如果不合理的话强帮我修改优化他们(注意优化知识点时只允许使用已存在的知识点不允许杜撰猜测捏造)" +
|
||||
$"这是我的分段 {thems}." +
|
||||
var checkMessage = "我为视频的讲解内容做了一些分段,希望你能通读字幕内容后检查下的分段是否符合我的要求?" +
|
||||
$"检查这些分段的时间是否合理 与相邻的时间段间隔是否处于合理区间30~900秒之间?" +
|
||||
$"分段的主题内容,知识点分配是否合理符合实际吗?" +
|
||||
$"请给出你的打分(0-100,70分及格)以及打分原因。" +
|
||||
$"这是我的分段 {thems}。" +
|
||||
$"后续的内容是包含时间戳的视频字幕的固定格式文本。" +
|
||||
$"字幕格式(说话人:开始秒:结束秒:内容|下一段字幕).以下是包含时间的视频字幕文本。字幕列表 {captions.Captions}。" +
|
||||
$"最后输出格式为json({checkResFormat})";
|
||||
|
||||
Console.WriteLine(DateTime.Now + "=>开始检查视频分段结果");
|
||||
Console.WriteLine(DateTime.Now + "=>3.开始检查视频分段结果");
|
||||
var checkRes = await ChatAsync<CheckMessageDto>(task, checkMessage, null);
|
||||
if (checkRes != null && checkRes.Score >= 80 && questionRes.Count() == checkRes.Data.Count())
|
||||
if (checkRes != null && checkRes.Score >= 80)
|
||||
{
|
||||
for (int i = 0; i < checkRes.Data.Count(); i++)
|
||||
{
|
||||
questionRes[i].Theme = checkRes.Data[i].Theme;
|
||||
questionRes[i].StartTime = checkRes.Data[i].StartTime;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Console.WriteLine(DateTime.Now + $"=>{task} 得分过低/分段长度不匹配 得分{checkRes?.Score} 长度 {questionRes.Count()}/{checkRes.Data.Count()}");
|
||||
Console.WriteLine(DateTime.Now + $"=>{task} 得分过低/分段长度不匹配 得分{checkRes?.Score} ");
|
||||
Console.WriteLine(checkRes.Evaluation);
|
||||
Console.WriteLine();
|
||||
}
|
||||
if (questionRes.Any(s => s.KeepTime < 30))
|
||||
{
|
||||
Console.WriteLine(DateTime.Now + "=>视频分段过短!! 重新进行AI分析");
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
for (int i = 0; i < questionRes.Length; i++)
|
||||
{
|
||||
var item = questionRes[i];
|
||||
if (i == questionRes.Length - 1)
|
||||
item.EndTime = maxVideoTime;
|
||||
else
|
||||
item.EndTime = (int)(questionRes[i + 1]?.StartTime ?? 0) - 1;
|
||||
}
|
||||
|
||||
//todo 未包含的知识点片段 如何处理
|
||||
var insertData = questionRes
|
||||
|
|
|
|||
|
|
@ -262,13 +262,16 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx
|
|||
Console.WriteLine(DateTime.Now + "=> SenseVoice 字幕数量"+ res.Count);
|
||||
|
||||
var captionsStr = JsonSerializer.Serialize(res);
|
||||
await DbScoped.SugarScope
|
||||
await DbScoped.Sugar
|
||||
.Updateable<VideoTask>()
|
||||
.SetColumns(it => it.Captions == captionsStr)
|
||||
.Where(it => it.Id == long.Parse(task))
|
||||
.ExecuteCommandAsync();
|
||||
await RedisExpand.Redis.HMSetAsync(RedisExpandKey.Task(task), "Captions", res);
|
||||
//RedisExpand.InsertChannel(Enum.RedisChannelEnum.ParsingSpeaker, task);
|
||||
//分析完成视频字幕后继续接收任务
|
||||
RedisExpand.NewTask();
|
||||
|
||||
RedisExpand.InsertChannel(RedisChannelEnum.ChatModelAnalysis, task);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx
|
|||
var res = segments.Select(s => new OfflineSpeakerRes(s));
|
||||
await RedisExpand.Redis.HSetAsync(RedisExpandKey.Task(task), "Speaker", res);
|
||||
var speakerStr = JsonSerializer.Serialize(res);
|
||||
DbScoped.SugarScope
|
||||
DbScoped.Sugar
|
||||
.Updateable<VideoTask>()
|
||||
.SetColumns(it => it.Speaker == speakerStr)
|
||||
.Where(it => it.Id == long.Parse(task));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using AntDesign;
|
||||
using Downloader;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using SqlSugar;
|
||||
using SqlSugar.IOC;
|
||||
using System;
|
||||
|
|
@ -8,22 +9,35 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using VideoAnalysisCore.Job;
|
||||
using VideoAnalysisCore.Model;
|
||||
using VideoAnalysisCore.Model.Enum;
|
||||
|
||||
namespace VideoAnalysisCore.Common
|
||||
{
|
||||
public static class DownloadFileExpand
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化下载器
|
||||
/// </summary>
|
||||
/// <param name="DownloadSpeed">下载速度mb/s 默认8</param>
|
||||
public static void AddDownloadFileExpand(this IServiceCollection services, int DownloadSpeed)
|
||||
{
|
||||
DownloadFile.DownloadSpeed = DownloadSpeed;
|
||||
services.AddSingleton<DownloadFile>();
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class DownloadFile
|
||||
{
|
||||
static DownloadConfiguration Opt { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// 初始化下载器
|
||||
/// </summary>
|
||||
/// <param name="DownloadSpeed">下载速度mb/s 默认8</param>
|
||||
static void Init(int DownloadSpeed = 8)
|
||||
static DownloadConfiguration Opt { get; set; } = default!;
|
||||
public static int DownloadSpeed { get; set; } = default!;
|
||||
private readonly Repository<VideoTask> videoTaskDB;
|
||||
|
||||
public DownloadFile(Repository<VideoTask> videoTaskDB)
|
||||
{
|
||||
Opt = new DownloadConfiguration()
|
||||
{
|
||||
|
|
@ -77,6 +91,7 @@ namespace VideoAnalysisCore.Common
|
|||
//}
|
||||
}
|
||||
};
|
||||
this.videoTaskDB = videoTaskDB;
|
||||
}
|
||||
|
||||
// 根据 Content-Type 映射文件后缀
|
||||
|
|
@ -103,15 +118,15 @@ namespace VideoAnalysisCore.Common
|
|||
/// </summary>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task RunTask(string task)
|
||||
public async Task RunTask(string task)
|
||||
{
|
||||
if (Opt is null)
|
||||
Init();
|
||||
var taskId = long.Parse(task);
|
||||
//获取资源文件 地址
|
||||
var fileUrl =await DbScoped.SugarScope.Queryable<VideoTask>()
|
||||
.Where(s => s.Id == taskId)
|
||||
.Select(s=>s.MediaUrl).FirstAsync();
|
||||
var taskInfo =await videoTaskDB.AsQueryable()
|
||||
.Where(s => s.Id == taskId).FirstAsync();
|
||||
if (taskInfo is null || string.IsNullOrEmpty(taskInfo.MediaName) || taskInfo.MediaName.Contains("教研"))
|
||||
throw new Exception($"任务为null/是教研视频/没有视频课程名称");
|
||||
var fileUrl = taskInfo.MediaUrl;
|
||||
if (string.IsNullOrEmpty(fileUrl))
|
||||
throw new Exception($"任务id[{task}] 资源地址无效 {fileUrl}");
|
||||
|
||||
|
|
@ -128,8 +143,8 @@ namespace VideoAnalysisCore.Common
|
|||
var outputPath = Path.Combine(localPath, task + fileExtension);
|
||||
if (!Directory.Exists(localPath)) Directory.CreateDirectory(localPath);
|
||||
|
||||
await DbScoped.SugarScope
|
||||
.Updateable<VideoTask>()
|
||||
await videoTaskDB
|
||||
.AsUpdateable()
|
||||
.SetColumns(it => it.LocalMediaPath == outputPath)
|
||||
.Where(it => it.Id == long.Parse(task))
|
||||
.ExecuteCommandAsync();
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ namespace VideoAnalysisCore.Common
|
|||
if (gptRes is null)
|
||||
throw new Exception("未能读取到GPT处理结果");
|
||||
|
||||
var taskData = await DbScoped.SugarScope.Queryable<VideoTask>()
|
||||
var taskData = await DbScoped.Sugar.Queryable<VideoTask>()
|
||||
.FirstAsync(s => s.Id == tId);
|
||||
if (taskData.Captions == "[]")
|
||||
taskData.Captions = (await Redis.HMGetAsync(RedisExpandKey.Task(task), "Captions")).First();
|
||||
|
|
@ -193,7 +193,7 @@ namespace VideoAnalysisCore.Common
|
|||
taskData.ChatAnalysisScore = gptRes?.Assessment?.Merit?.Sum(s => s.Score) ?? 0;
|
||||
taskData.ErrorMessage = string.Empty;
|
||||
taskData.LastEnum = RedisChannelEnum.EndTask;
|
||||
await DbScoped.SugarScope.Updateable(taskData)
|
||||
await DbScoped.Sugar.Updateable(taskData)
|
||||
.UpdateColumns(it => new
|
||||
{
|
||||
it.ChatAnalysis,
|
||||
|
|
@ -205,9 +205,7 @@ namespace VideoAnalysisCore.Common
|
|||
it.LastEnum,
|
||||
}).ExecuteCommandAsync();
|
||||
|
||||
|
||||
await Redis.DelAsync(RedisExpandKey.IDTask);
|
||||
await ReceivingTaskAsync();
|
||||
//NewTask();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -218,8 +216,16 @@ namespace VideoAnalysisCore.Common
|
|||
if (Redis is null) throw new Exception("redis未初始化");
|
||||
|
||||
SubscribeList.Add(RedisChannelEnum.DownloadFile,
|
||||
(msg) => { TouchChannel(RedisChannelEnum.DownloadFile, msg, DownloadFile.RunTask); });
|
||||
|
||||
(msg) => { TouchChannel(RedisChannelEnum.DownloadFile, msg,
|
||||
(task) =>
|
||||
{
|
||||
using var scope = AppCommon.Services?.CreateScope();
|
||||
if (scope is null || scope.ServiceProvider.GetService<DownloadFile>() is null)
|
||||
throw new Exception("DownloadFile 未注入");
|
||||
else
|
||||
return scope.ServiceProvider.GetService<DownloadFile>()?.RunTask(task) ?? Task.CompletedTask;
|
||||
});
|
||||
});
|
||||
|
||||
SubscribeList.Add(RedisChannelEnum.SeparateAudio,
|
||||
(msg) => { TouchChannel(RedisChannelEnum.SeparateAudio, msg, FFMPGEHandle.Audio2WAV16KAsync); });
|
||||
|
|
@ -247,6 +253,19 @@ namespace VideoAnalysisCore.Common
|
|||
await ReceivingTaskAsync();
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 重新执行新任务
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static void NewTask()
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Redis.DelAsync(RedisExpandKey.IDTask);
|
||||
await ReceivingTaskAsync();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新接收新任务
|
||||
/// </summary>
|
||||
|
|
@ -297,7 +316,7 @@ namespace VideoAnalysisCore.Common
|
|||
|
||||
Redis.HMSet(RedisExpandKey.Task(taskID), "ErrorMessage", error);
|
||||
|
||||
return await DbScoped.SugarScope.Updateable<VideoTask>()
|
||||
return await DbScoped.Sugar.Updateable<VideoTask>()
|
||||
.SetColumns(it => it.ErrorMessage == error)//SetColumns是可以叠加的 写2个就2个字段赋值
|
||||
.Where(it => it.Id == taskID)
|
||||
.ExecuteCommandAsync() == 1;
|
||||
|
|
@ -323,10 +342,14 @@ namespace VideoAnalysisCore.Common
|
|||
{
|
||||
Redis.HMSet(RedisExpandKey.Task(taskId), "LastEnum", key);
|
||||
Redis.HMSet(RedisExpandKey.Task(taskId), "Progress", 0);
|
||||
await DbScoped.SugarScope.Updateable<VideoTask>()
|
||||
.SetColumns(it => it.LastEnum == key)
|
||||
.Where(it => it.Id == tID)
|
||||
.ExecuteCommandAsync();
|
||||
lock (Redis)
|
||||
{
|
||||
DbScoped.Sugar.Updateable<VideoTask>()
|
||||
.SetColumns(it => it.LastEnum == key)
|
||||
.Where(it => it.Id == tID)
|
||||
.ExecuteCommand();
|
||||
|
||||
}
|
||||
await action(taskId);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,15 +23,15 @@ namespace VideoAnalysisCore.Common
|
|||
var t = typeof(T);
|
||||
if (CID.ContainsKey(t))
|
||||
{
|
||||
base.Context = DbScoped.SugarScope.GetConnectionScope(CID[t]);
|
||||
base.Context = DbScoped.Sugar.GetConnectionScope(CID[t]);
|
||||
return;
|
||||
}
|
||||
var c = t.GetCustomAttribute<TenantAttribute>();
|
||||
if (!CID.ContainsKey(typeof(T)))
|
||||
CID.Add(typeof(T), c?.configId);
|
||||
base.Context = c != null
|
||||
? DbScoped.SugarScope.GetConnectionScope(c.configId)
|
||||
: DbScoped.SugarScope;
|
||||
? DbScoped.Sugar.GetConnectionScope(c.configId)
|
||||
: DbScoped.Sugar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,11 +33,12 @@ namespace VideoAnalysisCore.Model
|
|||
/// <summary>
|
||||
/// 绑定学科
|
||||
/// </summary>
|
||||
[DisplayName("绑定学科")]
|
||||
[DisplayName("任务类型")]
|
||||
public TaskTypeEnum TaskType { get; set; }
|
||||
/// <summary>
|
||||
/// 学科
|
||||
/// </summary>
|
||||
[DisplayName("学科")]
|
||||
public SubjectEnum Subject { get; set; }
|
||||
/// <summary>
|
||||
/// 是否启用
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ namespace VideoAnalysisCore.Model
|
|||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||
[SugarColumn( IsNullable = true)]
|
||||
public DateTime EndTime { get; set; }
|
||||
/// <summary>
|
||||
/// 开始时间轴
|
||||
/// </summary>
|
||||
|
|
|
|||
Loading…
Reference in New Issue