parent
f3932cfaef
commit
79d024f9f6
|
|
@ -5,18 +5,72 @@
|
||||||
@using SqlSugar
|
@using SqlSugar
|
||||||
@using VideoAnalysisCore.Model
|
@using VideoAnalysisCore.Model
|
||||||
@using VideoAnalysisCore.Model.Dto
|
@using VideoAnalysisCore.Model.Dto
|
||||||
|
@using VideoAnalysisCore.Enum
|
||||||
|
|
||||||
<Table @ref="_table" Loading="tableLoading" TItem="VideoTaskDto" PageSize="15" Total="_total" DataSource="_dataSource" @bind-SelectedRows="_selectedRows" OnChange="OnChange">
|
<Table @ref="_table" Loading="tableLoading" TItem="VideoTaskDto" PageSize="15" Total="_total" DataSource="_dataSource" @bind-SelectedRows="_selectedRows" OnChange="OnChange"
|
||||||
|
OnExpand="OnExpand">
|
||||||
<TitleTemplate>
|
<TitleTemplate>
|
||||||
<Flex Justify="end" Gap="10"> </Flex>
|
<Flex Justify="end" Gap="10"> </Flex>
|
||||||
</TitleTemplate>
|
</TitleTemplate>
|
||||||
<ColumnDefinitions Context="row">
|
<ColumnDefinitions Context="row">
|
||||||
<Selection />
|
<Selection />
|
||||||
<ActionColumn Title="操作列">
|
<PropertyColumn Property="c=>c.Id" Width="100" Filterable="true" Sortable="true"/>
|
||||||
<Button Type="@ButtonType.Link" Danger @onclick="() => ReStart(row)">
|
<PropertyColumn Property="c=>c.TagId" Width="100" />
|
||||||
重试
|
<PropertyColumn Property="c=>c.LastEnum" Width="120" />
|
||||||
</Button>
|
<PropertyColumn Property="c=>c.ApiToken" Width="120" />
|
||||||
</ActionColumn>
|
<PropertyColumn Property="c=>c.ComeFrom" Width="120" />
|
||||||
<GenerateColumns Definitions="@((n,c) => { c.Filterable = true; c.Sortable = true; })" />
|
<PropertyColumn Property="c=>c.MediaUrl" />
|
||||||
|
<PropertyColumn Property="c=>c.TotalTokens" Width="100" />
|
||||||
|
<PropertyColumn Property="c=>c.CreateTime" Width="100" />
|
||||||
</ColumnDefinitions>
|
</ColumnDefinitions>
|
||||||
|
<ExpandTemplate Context="rowData" >
|
||||||
|
<Descriptions Title="任务详情" Bordered>
|
||||||
|
|
||||||
|
<DescriptionsItem Title="@rowData.Data.LastEnum.ToString()">
|
||||||
|
@rowData.Data.Progress%
|
||||||
|
</DescriptionsItem>
|
||||||
|
|
||||||
|
<DescriptionsItem Title="操作" Span="2">
|
||||||
|
<Button Type="@ButtonType.Primary"
|
||||||
|
Loading="rowRestartLoading"
|
||||||
|
OnClick="()=>RowRestart(rowData)">
|
||||||
|
刷新数据
|
||||||
|
</Button>
|
||||||
|
<Button Type="@ButtonType.Primary" Danger @onclick="() => ReStart(rowData.Data)">
|
||||||
|
重试
|
||||||
|
</Button>
|
||||||
|
</DescriptionsItem>
|
||||||
|
|
||||||
|
<DescriptionsItem Title="任务时间轴" Span="5">
|
||||||
|
<Steps Current="@RowSTIndex(rowData)" Status="@RowSTStatus(rowData)">
|
||||||
|
<Step Title="下载文件"
|
||||||
|
Description="@RowST(rowData,RedisChannelEnum.DownloadFile)" />
|
||||||
|
|
||||||
|
<Step Title="分离音频"
|
||||||
|
Description="@RowST(rowData,RedisChannelEnum.SeparateAudio)" />
|
||||||
|
|
||||||
|
<Step Title="解析字幕"
|
||||||
|
Description="@RowST(rowData,RedisChannelEnum.ParsingCaptions)" />
|
||||||
|
|
||||||
|
<Step Title="解析说话人"
|
||||||
|
Description="@RowST(rowData,RedisChannelEnum.ParsingSpeaker)" />
|
||||||
|
|
||||||
|
<Step Title="Chat模型分析"
|
||||||
|
Description="@RowST(rowData,RedisChannelEnum.ChatModelAnalysis)" />
|
||||||
|
|
||||||
|
<Step Title="结束任务"
|
||||||
|
Description="@RowST(rowData,RedisChannelEnum.EndTask)" />
|
||||||
|
</Steps>
|
||||||
|
</DescriptionsItem>
|
||||||
|
|
||||||
|
@if (!string.IsNullOrEmpty( @rowData.Data.ErrorMessage))
|
||||||
|
{
|
||||||
|
<DescriptionsItem Title="任务异常" Span="3">
|
||||||
|
@rowData.Data.ErrorMessage
|
||||||
|
</DescriptionsItem>
|
||||||
|
}
|
||||||
|
|
||||||
|
</Descriptions>
|
||||||
|
|
||||||
|
</ExpandTemplate>
|
||||||
</Table>
|
</Table>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using AntDesign;
|
using AntDesign;
|
||||||
using AntDesign.TableModels;
|
using AntDesign.TableModels;
|
||||||
|
using FFmpeg.NET.Services;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.DataProtection.KeyManagement;
|
using Microsoft.AspNetCore.DataProtection.KeyManagement;
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
|
|
@ -19,6 +20,7 @@ namespace Learn.VideoAnalysis.Components.Pages
|
||||||
[Inject] private Repository<VideoTask> taskDB { get; set; } = default!;
|
[Inject] private Repository<VideoTask> taskDB { get; set; } = default!;
|
||||||
|
|
||||||
|
|
||||||
|
[Inject] private INotificationService _notice { get; set; } = default!;
|
||||||
IEnumerable<VideoTaskDto> _selectedRows = [];
|
IEnumerable<VideoTaskDto> _selectedRows = [];
|
||||||
ITable _table;
|
ITable _table;
|
||||||
|
|
||||||
|
|
@ -26,6 +28,8 @@ namespace Learn.VideoAnalysis.Components.Pages
|
||||||
RefAsync<int> _total = 0;
|
RefAsync<int> _total = 0;
|
||||||
|
|
||||||
bool tableLoading = false;
|
bool tableLoading = false;
|
||||||
|
private VideoTaskDto selectData;
|
||||||
|
private bool rowRestartLoading=false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重试
|
/// 重试
|
||||||
|
|
@ -34,16 +38,18 @@ namespace Learn.VideoAnalysis.Components.Pages
|
||||||
async void ReStart(VideoTaskDto query)
|
async void ReStart(VideoTaskDto query)
|
||||||
{
|
{
|
||||||
var lastEnum = (await RedisExpand.Redis.HMGetAsync<RedisChannelEnum>(RedisExpandKey.Task(query.Id), "LastEnum")).FirstOrDefault() ;
|
var lastEnum = (await RedisExpand.Redis.HMGetAsync<RedisChannelEnum>(RedisExpandKey.Task(query.Id), "LastEnum")).FirstOrDefault() ;
|
||||||
await taskDB.UpdateAsync(s => new VideoTask()
|
await RedisExpand.SetTaskErrorMessage(query.Id, string.Empty);
|
||||||
{ ErrorMessage = string.Empty },s => s.Id == query.Id);
|
|
||||||
RedisExpand.InsertChannel(lastEnum, query.Id);
|
RedisExpand.InsertChannel(lastEnum, query.Id);
|
||||||
}
|
}
|
||||||
|
private QueryModel<VideoTaskDto> lastQuery = null;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 分页 查询 筛选 时
|
/// 分页 查询 筛选 时
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="query"></param>
|
/// <param name="query"></param>
|
||||||
|
/// <param name="changed"></param>
|
||||||
async void OnChange(QueryModel<VideoTaskDto> query)
|
async void OnChange(QueryModel<VideoTaskDto> query)
|
||||||
{
|
{
|
||||||
|
lastQuery= query;
|
||||||
tableLoading = true;
|
tableLoading = true;
|
||||||
List<IConditionalModel> where = default!;
|
List<IConditionalModel> where = default!;
|
||||||
if (query.FilterModel != null && ((query.FilterModel?.Count() ?? 0) > 0))
|
if (query.FilterModel != null && ((query.FilterModel?.Count() ?? 0) > 0))
|
||||||
|
|
@ -55,39 +61,72 @@ namespace Learn.VideoAnalysis.Components.Pages
|
||||||
.Select<VideoTaskDto>()
|
.Select<VideoTaskDto>()
|
||||||
.ToPageListAsync(query.PageIndex - 1, query.PageSize, _total);
|
.ToPageListAsync(query.PageIndex - 1, query.PageSize, _total);
|
||||||
|
|
||||||
foreach (var item in _dataSource)
|
tableLoading = false;
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(item.ErrorMessage) || item.LastEnum == RedisChannelEnum.EndTask)
|
|
||||||
continue;
|
|
||||||
item.Progress = RedisExpand.Redis.HMGet<double>(RedisExpandKey.Task(item.Id), "Progress").FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
tableLoading = false;
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
|
|
||||||
}
|
}
|
||||||
private static System.Timers.Timer _timer;
|
public void RowRestart(RowData<VideoTaskDto> rowData)
|
||||||
public void StartTimer(Object source, System.Timers.ElapsedEventArgs e)
|
|
||||||
{
|
{
|
||||||
if (_dataSource is null)
|
rowRestartLoading = true;
|
||||||
|
var item = rowData.Data;
|
||||||
|
if (item is null)
|
||||||
return;
|
return;
|
||||||
foreach (var item in _dataSource)
|
var data = RedisExpand.Redis.HMGet<string>(RedisExpandKey.Task(item.Id),
|
||||||
{
|
"Progress", "LastEnum", "StartTime", "ErrorMessage");
|
||||||
if (!string.IsNullOrEmpty(item.ErrorMessage) || item.LastEnum == RedisChannelEnum.EndTask)
|
item.Progress = double.Parse(data[0]);
|
||||||
continue;
|
item.LastEnum = data[1].ToEnum<RedisChannelEnum>() ?? default;
|
||||||
item.Progress = RedisExpand.Redis.HMGet<double>(RedisExpandKey.Task(item.Id), "Progress").FirstOrDefault();
|
item.StartTimeDic = System.Text.Json.JsonSerializer.Deserialize<Dictionary<RedisChannelEnum, DateTime>>(data[2]) ?? null;
|
||||||
}
|
item.ErrorMessage = data[3];
|
||||||
|
rowRestartLoading = false;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private string RowST(RowData<VideoTaskDto> rowData, RedisChannelEnum e)
|
||||||
|
{
|
||||||
|
var dic = rowData.Data.StartTimeDic;
|
||||||
|
if (dic is null || !dic.ContainsKey(e))
|
||||||
|
return "--";
|
||||||
|
return dic[e].ToString();
|
||||||
|
}
|
||||||
|
private string RowSTStatus(RowData<VideoTaskDto> rowData)
|
||||||
|
{
|
||||||
|
var dic = rowData.Data.StartTimeDic;
|
||||||
|
if (dic is null)
|
||||||
|
return "wait";
|
||||||
|
if(!string.IsNullOrEmpty(rowData.Data.ErrorMessage))
|
||||||
|
return "error";
|
||||||
|
if(dic.ContainsKey(RedisChannelEnum.EndTask))
|
||||||
|
return "finish";
|
||||||
|
return "wait";
|
||||||
|
}
|
||||||
|
private int RowSTIndex(RowData<VideoTaskDto> rowData)
|
||||||
|
{
|
||||||
|
var dic = rowData.Data.StartTimeDic;
|
||||||
|
if (dic is null )
|
||||||
|
return 0;
|
||||||
|
return (int)dic.LastOrDefault().Key;
|
||||||
|
}
|
||||||
|
private void OnExpand(RowData<VideoTaskDto> rowData)
|
||||||
|
{
|
||||||
|
RowRestart(rowData);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 在渲染页面之后
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstRender"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化
|
/// 初始化
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
_timer = new System.Timers.Timer(2000);
|
|
||||||
_timer.Elapsed += StartTimer;
|
|
||||||
_timer.Enabled = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> Comfirm(string message)
|
private async Task<bool> Comfirm(string message)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
input[aria-hidden="true"] {
|
input[aria-hidden="true"] {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.task_status_tag {
|
||||||
|
display:flex;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ using VideoAnalysisCore.Model;
|
||||||
using VideoAnalysisCore.AICore.FFMPGE;
|
using VideoAnalysisCore.AICore.FFMPGE;
|
||||||
using VideoAnalysisCore.Model.Dto;
|
using VideoAnalysisCore.Model.Dto;
|
||||||
using VideoAnalysisCore.AICore.ChatGPT.Dto;
|
using VideoAnalysisCore.AICore.ChatGPT.Dto;
|
||||||
|
using AntDesign;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Learn.VideoAnalysis.Controllers
|
namespace Learn.VideoAnalysis.Controllers
|
||||||
{
|
{
|
||||||
|
|
@ -47,6 +49,8 @@ namespace Learn.VideoAnalysis.Controllers
|
||||||
.WhereIF(taskId!=0, s => s.Id == taskId)
|
.WhereIF(taskId!=0, s => s.Id == taskId)
|
||||||
.WhereIF(string.IsNullOrEmpty(tagId), s => s.TagId == tagId)
|
.WhereIF(string.IsNullOrEmpty(tagId), s => s.TagId == tagId)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
if(task is null)
|
||||||
|
return BadRequest();
|
||||||
if (task.LastEnum != RedisChannelEnum.EndTask)
|
if (task.LastEnum != RedisChannelEnum.EndTask)
|
||||||
return BadRequest(new { Enum = task.LastEnum ,Task = task.ChatAnalysis});
|
return BadRequest(new { Enum = task.LastEnum ,Task = task.ChatAnalysis});
|
||||||
return Ok(new { Enum = task.LastEnum, Task = task.ChatAnalysis });
|
return Ok(new { Enum = task.LastEnum, Task = task.ChatAnalysis });
|
||||||
|
|
@ -90,8 +94,7 @@ namespace Learn.VideoAnalysis.Controllers
|
||||||
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||||
.ToDictionary(s => s.Name, s => s.GetValue(task));
|
.ToDictionary(s => s.Name, s => s.GetValue(task));
|
||||||
RedisExpand.Redis.HMSet(RedisExpandKey.Task(task.Id), hashEntries);
|
RedisExpand.Redis.HMSet(RedisExpandKey.Task(task.Id), hashEntries);
|
||||||
|
RedisExpand.Redis.Set(RedisExpandKey.ChannelKey, task.Id);
|
||||||
RedisExpand.InsertChannel(RedisChannelEnum.DownloadFile,task.Id);
|
|
||||||
return Ok(task.Id);
|
return Ok(task.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,8 @@ namespace Learn.VideoAnalysis
|
||||||
builder.Configuration.GetSection("AppConfig").Bind(AppCommon.Config);
|
builder.Configuration.GetSection("AppConfig").Bind(AppCommon.Config);
|
||||||
|
|
||||||
//初始化 插件
|
//初始化 插件
|
||||||
//Speaker.Init();
|
RedisExpand.Init();
|
||||||
//RedisExpand.Init();
|
Speaker.Init();
|
||||||
//SenseVoice.Init();
|
//SenseVoice.Init();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
"AppConfig": {
|
"AppConfig": {
|
||||||
|
"ID": "APP0001",//程序唯一值
|
||||||
"Redis": {
|
"Redis": {
|
||||||
"ConnectionString": "127.0.0.1:6379,password=Woshiren123,defaultDatabase=10"
|
"ConnectionString": "127.0.0.1:6379,password=Woshiren123,defaultDatabase=10"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ using System.Reflection;
|
||||||
using FreeRedis;
|
using FreeRedis;
|
||||||
using VideoAnalysisCore.Model.Dto;
|
using VideoAnalysisCore.Model.Dto;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using AntDesign;
|
||||||
|
using SqlSugar.IOC;
|
||||||
|
|
||||||
namespace VideoAnalysisCore.AICore.ChatGPT.KIMI
|
namespace VideoAnalysisCore.AICore.ChatGPT.KIMI
|
||||||
{
|
{
|
||||||
|
|
@ -55,7 +57,7 @@ namespace VideoAnalysisCore.AICore.ChatGPT.KIMI
|
||||||
criteriaBuilder.Append(item.Id);
|
criteriaBuilder.Append(item.Id);
|
||||||
criteriaBuilder.Append(":");
|
criteriaBuilder.Append(":");
|
||||||
criteriaBuilder.Append(item.NamePrompt);
|
criteriaBuilder.Append(item.NamePrompt);
|
||||||
criteriaBuilder.Append("请基于解释打分(0-10分 6分为及格线) 结果类型 int |");
|
criteriaBuilder.Append("请基于解释打分(0-10分 6分为及格) 结果类型 int |");
|
||||||
}
|
}
|
||||||
//拼接枚举提问
|
//拼接枚举提问
|
||||||
foreach (var value in System.Enum.GetValues(typeof(QuestionTypeEnum)))
|
foreach (var value in System.Enum.GetValues(typeof(QuestionTypeEnum)))
|
||||||
|
|
@ -71,7 +73,7 @@ namespace VideoAnalysisCore.AICore.ChatGPT.KIMI
|
||||||
criteriaBuilder.Append("|");
|
criteriaBuilder.Append("|");
|
||||||
}
|
}
|
||||||
|
|
||||||
var resFormat = "[{问题编号:int,结果:array|bool,问题解释:string}]";
|
var resFormat = "[{问题编号:int,结果:array|bool|object,问题解释:string}]";
|
||||||
var postMessages =
|
var postMessages =
|
||||||
$"以下是一段音频的字幕,分析这段字幕(格式 说话人:开始秒:结束秒:内容|下一段字幕)." +
|
$"以下是一段音频的字幕,分析这段字幕(格式 说话人:开始秒:结束秒:内容|下一段字幕)." +
|
||||||
$"来简明的回答提出的问题 问题列表 {criteriaBuilder} " +
|
$"来简明的回答提出的问题 问题列表 {criteriaBuilder} " +
|
||||||
|
|
@ -95,6 +97,7 @@ namespace VideoAnalysisCore.AICore.ChatGPT.KIMI
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var chatResp = await moonshotClient.Chat(chatRep);
|
var chatResp = await moonshotClient.Chat(chatRep);
|
||||||
|
RedisExpand.SetTaskGPTCached(task, chatResp);
|
||||||
if (chatResp is null || chatResp.error != null)
|
if (chatResp is null || chatResp.error != null)
|
||||||
throw new Exception($"KIMI模型返回异常 Chat 请求参数: {System.Text.Json.JsonSerializer.Serialize(chatRep)} " +
|
throw new Exception($"KIMI模型返回异常 Chat 请求参数: {System.Text.Json.JsonSerializer.Serialize(chatRep)} " +
|
||||||
$" chatResp {System.Text.Json.JsonSerializer.Serialize(chatResp)}");
|
$" chatResp {System.Text.Json.JsonSerializer.Serialize(chatResp)}");
|
||||||
|
|
@ -121,7 +124,7 @@ namespace VideoAnalysisCore.AICore.ChatGPT.KIMI
|
||||||
{
|
{
|
||||||
Id = criteriaDic[s.问题编号].Id,
|
Id = criteriaDic[s.问题编号].Id,
|
||||||
ImprovedMethods = criteriaDic[s.问题编号].ImprovedMethods,
|
ImprovedMethods = criteriaDic[s.问题编号].ImprovedMethods,
|
||||||
Analyze = s.问题解释??string.Empty,
|
Analyze = s.问题解释 ?? string.Empty,
|
||||||
Score = s.结果.ToObject<int>(),
|
Score = s.结果.ToObject<int>(),
|
||||||
Prompt = criteriaDic[s.问题编号].Flaw,
|
Prompt = criteriaDic[s.问题编号].Flaw,
|
||||||
}).ToArray(),
|
}).ToArray(),
|
||||||
|
|
@ -137,7 +140,7 @@ namespace VideoAnalysisCore.AICore.ChatGPT.KIMI
|
||||||
};
|
};
|
||||||
|
|
||||||
//高频词汇
|
//高频词汇
|
||||||
gptRes.Hotwords = arr2[(int)QuestionTypeEnum.高频词].结果.ToObject<string[]>()??["暂无数据"];
|
gptRes.Hotwords = arr2[(int)QuestionTypeEnum.高频词].结果.ToObject<string[]>() ?? ["暂无数据"];
|
||||||
|
|
||||||
//时间段概览
|
//时间段概览
|
||||||
gptRes.TimeOverview = arr2[(int)QuestionTypeEnum.时间段概览]
|
gptRes.TimeOverview = arr2[(int)QuestionTypeEnum.时间段概览]
|
||||||
|
|
@ -148,27 +151,33 @@ namespace VideoAnalysisCore.AICore.ChatGPT.KIMI
|
||||||
|
|
||||||
//分析上课时间段情况 分析 独立学习 小组合作 随堂练习等情况
|
//分析上课时间段情况 分析 独立学习 小组合作 随堂练习等情况
|
||||||
var extraTimeBase = arr2[(int)QuestionTypeEnum.额外课堂情况]
|
var extraTimeBase = arr2[(int)QuestionTypeEnum.额外课堂情况]
|
||||||
.结果.ToObject<Dictionary<TimeBaseTypeEnum,string?>>()?.Select(s =>
|
.结果.ToObject<TimeBase[]>();
|
||||||
new TimeBase(s.Value,s.Key.ToString()));
|
if (extraTimeBase is not null)
|
||||||
|
foreach (var item in extraTimeBase)
|
||||||
|
{
|
||||||
|
if (item is null)
|
||||||
|
continue;
|
||||||
|
var arr = gptRes.TimeBase?
|
||||||
|
.Where(s => s.Start >= item.Start && s.End <= item.End);
|
||||||
|
if (arr is null)
|
||||||
|
continue;
|
||||||
|
foreach (var s in arr)
|
||||||
|
s.TimeBaseType = item.Content.ToEnum<TimeBaseTypeEnum>();
|
||||||
|
}
|
||||||
|
var totalTokens = chatResp?.usage.total_tokens ?? 0;
|
||||||
|
if (totalTokens > 1)
|
||||||
|
{
|
||||||
|
var tid = long.Parse(task);
|
||||||
|
await videoTaskDB.AsUpdateable()
|
||||||
|
.SetColumns(it => it.TotalTokens == totalTokens)//SetColumns是可以叠加的 写2个就2个字段赋值
|
||||||
|
.Where(it => it.Id == tid)
|
||||||
|
.ExecuteCommandAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
await RedisExpand.Redis
|
||||||
|
.HMSetAsync(RedisExpandKey.Task(task), "ChatAnalysis", gptRes);
|
||||||
|
RedisExpand.InsertChannel(Enum.RedisChannelEnum.EndTask, task);
|
||||||
|
|
||||||
|
|
||||||
var tId = long.Parse(task);
|
|
||||||
var taskData = await videoTaskDB.GetFirstAsync(s => s.Id == tId);
|
|
||||||
taskData.ChatAnalysis = gptRes;
|
|
||||||
taskData.ChatAnalysisScore = gptRes.Assessment.Merit?.Sum(s=>s.Score)??0;
|
|
||||||
taskData.ErrorMessage = string.Empty;
|
|
||||||
taskData.TotalTokens = chatResp.usage.total_tokens;
|
|
||||||
taskData.LastEnum = RedisChannelEnum.EndTask;
|
|
||||||
await videoTaskDB.AsUpdateable(taskData)
|
|
||||||
.UpdateColumns(it => new
|
|
||||||
{
|
|
||||||
it.ChatAnalysis,
|
|
||||||
it.ChatAnalysisScore,
|
|
||||||
it.ErrorMessage,
|
|
||||||
it.TotalTokens,
|
|
||||||
it.LastEnum,
|
|
||||||
}).ExecuteCommandAsync();
|
|
||||||
return gptRes;
|
return gptRes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,6 @@ namespace VideoAnalysisCore.AICore.ChatGPT.KIMI
|
||||||
{
|
{
|
||||||
var requestBody = Newtonsoft.Json.JsonConvert.SerializeObject(chatReq);
|
var requestBody = Newtonsoft.Json.JsonConvert.SerializeObject(chatReq);
|
||||||
var chatResp = await PostJsonStreamAsync("/v1/chat/completions", requestBody);
|
var chatResp = await PostJsonStreamAsync("/v1/chat/completions", requestBody);
|
||||||
var resStr = chatResp.Content.ReadAsStringAsync();
|
|
||||||
return await chatResp.Content.ReadFromJsonAsync<ChatRes>();
|
return await chatResp.Content.ReadFromJsonAsync<ChatRes>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,8 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task RunTask(string task)
|
public static async Task RunTask(string task)
|
||||||
{
|
{
|
||||||
|
if (OR is null)
|
||||||
|
Init();
|
||||||
var filePath = Path.Combine(task.LocalPath(), task + ".wav");
|
var filePath = Path.Combine(task.LocalPath(), task + ".wav");
|
||||||
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
|
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
|
||||||
throw new Exception("task 音频路径未找到");
|
throw new Exception("task 音频路径未找到");
|
||||||
|
|
@ -87,7 +89,7 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx
|
||||||
int windowSize = VADModelConfig.SileroVad.WindowSize;
|
int windowSize = VADModelConfig.SileroVad.WindowSize;
|
||||||
int sampleRate = VADModelConfig.SampleRate;
|
int sampleRate = VADModelConfig.SampleRate;
|
||||||
int numIter = numSamples / windowSize;
|
int numIter = numSamples / windowSize;
|
||||||
|
var totalSecond = numSamples / (double)sampleRate;
|
||||||
var res = new List<SenseVoiceRes>(500);
|
var res = new List<SenseVoiceRes>(500);
|
||||||
for (int i = 0; i != numIter; ++i)
|
for (int i = 0; i != numIter; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -115,7 +117,7 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx
|
||||||
Start= startTime,
|
Start= startTime,
|
||||||
End = startTime + duration
|
End = startTime + duration
|
||||||
});
|
});
|
||||||
var progress = (double)(startTime + duration) / numSamples * 100;
|
var progress = (double)(startTime + duration) / (totalSecond) * 100;
|
||||||
RedisExpand.SetTaskProgress(task, progress);
|
RedisExpand.SetTaskProgress(task, progress);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ namespace VideoAnalysisCore.AICore.SherpaOnnx
|
||||||
config.Embedding.Model = Path.Combine(AppCommon.AIModelFile, "wespeaker", "wespeaker_zh_cnceleb_resnet34_LM.onnx");
|
config.Embedding.Model = Path.Combine(AppCommon.AIModelFile, "wespeaker", "wespeaker_zh_cnceleb_resnet34_LM.onnx");
|
||||||
//说话人数量
|
//说话人数量
|
||||||
config.Clustering.NumClusters = speakerNumber;
|
config.Clustering.NumClusters = speakerNumber;
|
||||||
|
config.Embedding.NumThreads = 4;
|
||||||
//需要使用GPU
|
//需要使用GPU
|
||||||
if (!useGPU)
|
if (!useGPU)
|
||||||
config.Embedding.Provider = "cuda";
|
config.Embedding.Provider = "cuda";
|
||||||
|
|
|
||||||
|
|
@ -303,6 +303,10 @@ namespace VideoAnalysisCore.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AppConfig
|
public class AppConfig
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 程序ID
|
||||||
|
/// </summary>
|
||||||
|
public string ID { get; set; } = string.Empty;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// redis
|
/// redis
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
using System;
|
using AntDesign;
|
||||||
|
using Downloader;
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace VideoAnalysisCore.Common
|
namespace VideoAnalysisCore.Common
|
||||||
|
|
@ -9,6 +14,67 @@ namespace VideoAnalysisCore.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DownloadFile
|
public class DownloadFile
|
||||||
{
|
{
|
||||||
|
static DownloadConfiguration Opt { get; set; } = default!;
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化下载器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="DownloadSpeed">下载速度mb/s 默认8</param>
|
||||||
|
static void Init(int DownloadSpeed = 8)
|
||||||
|
{
|
||||||
|
Opt = new DownloadConfiguration()
|
||||||
|
{
|
||||||
|
// 通常,主机支持的最大值为8000字节,默认值是8000
|
||||||
|
BufferBlockSize = 10240,
|
||||||
|
// 要下载的文件部分数量,默认值是1
|
||||||
|
ChunkCount = 8,
|
||||||
|
// 下载速度限制为2MB/秒,默认值为零(即无限制)
|
||||||
|
MaximumBytesPerSecond = 1024 * 1024 * DownloadSpeed,
|
||||||
|
// 故障转移时的最大重试次数
|
||||||
|
MaxTryAgainOnFailover = 5,
|
||||||
|
// 每50MB后释放内存缓冲区
|
||||||
|
MaximumMemoryBufferBytes = 1024 * 1024 * 50,
|
||||||
|
// 是否并行下载文件的各个部分。默认值为false
|
||||||
|
ParallelDownload = true,
|
||||||
|
// 并行下载的数量。默认值与分块数量相同
|
||||||
|
ParallelCount = 4,
|
||||||
|
// 每个流块读取器的超时时间(毫秒),默认值是1000
|
||||||
|
Timeout = 1000,
|
||||||
|
// 如果只想下载大型文件的特定字节范围,则设置为true
|
||||||
|
RangeDownload = false,
|
||||||
|
// 大型文件下载范围的起始偏移量
|
||||||
|
RangeLow = 0,
|
||||||
|
// 大型文件下载范围的结束偏移量
|
||||||
|
RangeHigh = 0,
|
||||||
|
// 下载失败完成时清除包块数据,默认值为false
|
||||||
|
ClearPackageOnCompletionWithFailure = true,
|
||||||
|
// 将文件分多个部分下载时的最小分块大小,默认值是512
|
||||||
|
MinimumSizeOfChunking = 1024,
|
||||||
|
// 在开始下载之前,按照文件大小预留文件的存储空间,默认值为false
|
||||||
|
ReserveStorageSpaceBeforeStartingDownload = true,
|
||||||
|
// 在下载进度改变事件中,通过ReceivedBytes获取按需下载的数据
|
||||||
|
EnableLiveStreaming = false,
|
||||||
|
// 配置和自定义请求头
|
||||||
|
RequestConfiguration =
|
||||||
|
{
|
||||||
|
Accept = "*/*",
|
||||||
|
//CookieContainer = cookies,
|
||||||
|
Headers = new WebHeaderCollection(), // { 你的自定义头部信息 }
|
||||||
|
KeepAlive = true, // 默认值为false
|
||||||
|
ProtocolVersion = HttpVersion.Version11, // 默认值是HTTP 1.1
|
||||||
|
UseDefaultCredentials = false,
|
||||||
|
// 你的自定义用户代理或你的应用名称/应用版本。
|
||||||
|
UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
|
||||||
|
//Proxy = new WebProxy()//使用代理
|
||||||
|
//{
|
||||||
|
// Address = new Uri("http://Learn.VideoAnalysis"),
|
||||||
|
// UseDefaultCredentials = false,
|
||||||
|
// Credentials = System.Net.CredentialCache.DefaultNetworkCredentials,
|
||||||
|
// BypassProxyOnLocal = true
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// 根据 Content-Type 映射文件后缀
|
// 根据 Content-Type 映射文件后缀
|
||||||
static string GetExtensionFromContentType(HttpResponseMessage res)
|
static string GetExtensionFromContentType(HttpResponseMessage res)
|
||||||
{
|
{
|
||||||
|
|
@ -35,62 +101,56 @@ namespace VideoAnalysisCore.Common
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task RunTask(string task)
|
public static async Task RunTask(string task)
|
||||||
{
|
{
|
||||||
|
if (Opt is null)
|
||||||
|
Init();
|
||||||
//获取资源文件 地址
|
//获取资源文件 地址
|
||||||
var fileUrl = RedisExpand.Redis.HMGet(RedisExpandKey.Task(task), "MediaUrl")
|
var fileUrl = RedisExpand.Redis.HMGet(RedisExpandKey.Task(task), "MediaUrl")
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
if (string.IsNullOrEmpty(fileUrl))
|
if (string.IsNullOrEmpty(fileUrl))
|
||||||
throw new Exception($"任务id[{task}] 资源地址无效 {fileUrl}");
|
throw new Exception($"任务id[{task}] 资源地址无效 {fileUrl}");
|
||||||
|
|
||||||
using HttpClient client = new HttpClient();
|
|
||||||
// 发送 GET 请求以下载文件
|
|
||||||
var response = await client.GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead);
|
|
||||||
// 确保响应是成功的
|
|
||||||
response.EnsureSuccessStatusCode();
|
|
||||||
|
|
||||||
// 尝试从 URL 中获取文件后缀
|
// 尝试从 URL 中获取文件后缀
|
||||||
string fileExtension = Path.GetExtension(new Uri(fileUrl).AbsolutePath);
|
string fileExtension = Path.GetExtension(new Uri(fileUrl).AbsolutePath);
|
||||||
//否则 获取 从Content-Type 获取文件后缀
|
//否则 获取 从Content-Type 获取文件后缀
|
||||||
if (string.IsNullOrEmpty(fileExtension))
|
if (string.IsNullOrEmpty(fileExtension))
|
||||||
fileExtension = GetExtensionFromContentType(response);
|
throw new Exception($"未能从资源路径中获取文件后缀");
|
||||||
|
|
||||||
//创建下载文件缓存路径
|
//创建下载文件缓存路径
|
||||||
if (!Directory.Exists(AppCommon.TaskCachedFile)) Directory.CreateDirectory(AppCommon.TaskCachedFile);
|
if (!Directory.Exists(AppCommon.TaskCachedFile)) Directory.CreateDirectory(AppCommon.TaskCachedFile);
|
||||||
|
|
||||||
// 获取文件大小
|
|
||||||
var totalBytes = response.Content.Headers.ContentLength;
|
|
||||||
if (!totalBytes.HasValue)
|
|
||||||
throw new Exception(task+" 未能获取到下载文件的 ContentLength ");
|
|
||||||
var localPath = task.LocalPath();
|
var localPath = task.LocalPath();
|
||||||
var outputPath = Path.Combine(localPath, task + fileExtension);
|
var outputPath = Path.Combine(localPath, task + fileExtension);
|
||||||
if (!Directory.Exists(localPath)) Directory.CreateDirectory(localPath);
|
if (!Directory.Exists(localPath)) Directory.CreateDirectory(localPath);
|
||||||
|
|
||||||
|
|
||||||
//同步到redis
|
|
||||||
RedisExpand.Redis.HSet(RedisExpandKey.Task(task), "LocalMediaPath", outputPath);
|
RedisExpand.Redis.HSet(RedisExpandKey.Task(task), "LocalMediaPath", outputPath);
|
||||||
// 打开本地文件流以写入文件
|
IDownload download = DownloadBuilder.New()
|
||||||
using var fs = new FileStream(outputPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
|
.WithUrl(fileUrl)
|
||||||
// 读取响应内容流
|
.WithDirectory(localPath)
|
||||||
using var contentStream = await response.Content.ReadAsStreamAsync();
|
.WithFileName(task + fileExtension)
|
||||||
var buffer = new byte[512 * 1024]; // 512KB 缓冲区
|
.WithConfiguration(Opt)
|
||||||
long totalBytesRead = 0;
|
.Build();
|
||||||
var count = 0;
|
download.DownloadProgressChanged += (object? sender, Downloader.DownloadProgressChangedEventArgs e) =>
|
||||||
int bytesRead;
|
|
||||||
while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
|
|
||||||
{
|
{
|
||||||
count++;
|
RedisExpand.SetTaskProgress(task, e.ProgressPercentage);
|
||||||
await fs.WriteAsync(buffer, 0, bytesRead);
|
};
|
||||||
totalBytesRead += bytesRead;
|
download.DownloadFileCompleted +=async (object? sender, AsyncCompletedEventArgs e) =>
|
||||||
|
{
|
||||||
// 计算下载进度
|
if (download.Status == DownloadStatus.Failed && e.Error!=null)
|
||||||
if (count % 30 == 0)
|
|
||||||
{
|
{
|
||||||
var progress = (double)totalBytesRead / totalBytes.Value * 100;
|
await RedisExpand.SetTaskErrorMessage(long.Parse(task), e.Error)
|
||||||
RedisExpand.SetTaskProgress(task, progress);
|
.ConfigureAwait(false);//不切回上下文
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (download.Status == DownloadStatus.Completed)
|
||||||
|
{
|
||||||
|
//加入下一队列
|
||||||
|
RedisExpand.InsertChannel(Enum.RedisChannelEnum.SeparateAudio, task);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//加入下一队列
|
};
|
||||||
RedisExpand.InsertChannel(Enum.RedisChannelEnum.SeparateAudio, task);
|
await download.StartAsync();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
using FreeRedis;
|
using AntDesign;
|
||||||
|
using FreeRedis;
|
||||||
|
using FreeRedis.Internal;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using SqlSugar.IOC;
|
using SqlSugar.IOC;
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -6,6 +8,7 @@ using System.Threading.Channels;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using VideoAnalysisCore.AICore.ChatGPT;
|
using VideoAnalysisCore.AICore.ChatGPT;
|
||||||
|
using VideoAnalysisCore.AICore.ChatGPT.Dto;
|
||||||
using VideoAnalysisCore.AICore.FFMPGE;
|
using VideoAnalysisCore.AICore.FFMPGE;
|
||||||
|
|
||||||
//using VideoAnalysisCore.AICore.FFMPGE;
|
//using VideoAnalysisCore.AICore.FFMPGE;
|
||||||
|
|
@ -13,6 +16,7 @@ using VideoAnalysisCore.AICore.SherpaOnnx;
|
||||||
using VideoAnalysisCore.AICore.Whisper;
|
using VideoAnalysisCore.AICore.Whisper;
|
||||||
using VideoAnalysisCore.Enum;
|
using VideoAnalysisCore.Enum;
|
||||||
using VideoAnalysisCore.Model;
|
using VideoAnalysisCore.Model;
|
||||||
|
using VideoAnalysisCore.Model.Dto;
|
||||||
|
|
||||||
namespace VideoAnalysisCore.Common
|
namespace VideoAnalysisCore.Common
|
||||||
{
|
{
|
||||||
|
|
@ -28,7 +32,7 @@ namespace VideoAnalysisCore.Common
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 基础Channel key
|
/// 基础Channel key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string ChannelKey = BaseKey + "Channel:";
|
public const string ChannelKey = BaseKey + "TaskChannel";
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 下载文件
|
/// 下载文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -55,20 +59,13 @@ namespace VideoAnalysisCore.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string TaskArr = BaseKey + "TaskArr";
|
public const string TaskArr = BaseKey + "TaskArr";
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取枚举RedisKey
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="e"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string EnumKey(RedisChannelEnum e)
|
|
||||||
{
|
|
||||||
return ChannelKey + e.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 任务对象地址
|
/// 任务对象地址
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string Task(object taskId) => BaseKey + "Task:" + taskId;
|
public static string Task(object taskId) => BaseKey + "Task:" + taskId;
|
||||||
|
public static string IDTask => BaseKey + AppCommon.Config.ID;
|
||||||
|
public static string TaskGPT(object taskId) => Task(taskId) + ":GPTCached";
|
||||||
|
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -80,6 +77,12 @@ namespace VideoAnalysisCore.Common
|
||||||
/// redis 连接
|
/// redis 连接
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static RedisClient Redis = new RedisClient(AppCommon.Config.Redis.ConnectionString);
|
public static RedisClient Redis = new RedisClient(AppCommon.Config.Redis.ConnectionString);
|
||||||
|
public static Dictionary<RedisChannelEnum, Action<string>> SubscribeList = new Dictionary<RedisChannelEnum, Action<string>>();
|
||||||
|
/// <summary>
|
||||||
|
/// 队列池
|
||||||
|
/// </summary>
|
||||||
|
static SubscribeListObject? Subscribe;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化 redis
|
/// 初始化 redis
|
||||||
/// <para>需要在初始化配置文件时候调用</para>
|
/// <para>需要在初始化配置文件时候调用</para>
|
||||||
|
|
@ -92,6 +95,14 @@ namespace VideoAnalysisCore.Common
|
||||||
InitChannel();
|
InitChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取任务进度
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="taskId"></param>
|
||||||
|
public static void SetTaskGPTCached(object taskId, object data)
|
||||||
|
{
|
||||||
|
Redis.Set(RedisExpandKey.TaskGPT(taskId), data, 3600);
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取任务进度
|
/// 获取任务进度
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -105,9 +116,9 @@ namespace VideoAnalysisCore.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="p">进度百分比</param>
|
/// <param name="p">进度百分比</param>
|
||||||
/// <param name="taskId"></param>
|
/// <param name="taskId"></param>
|
||||||
public static void SetTaskProgress(object taskId,double p)
|
public static void SetTaskProgress(object taskId, double p)
|
||||||
{
|
{
|
||||||
Redis.HMSet(RedisExpandKey.Task(taskId), "Progress", Math.Round(p,2));
|
Redis.HMSet(RedisExpandKey.Task(taskId), "Progress", Math.Round(p, 2));
|
||||||
|
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -117,6 +128,7 @@ namespace VideoAnalysisCore.Common
|
||||||
/// <param name="taskId">任务id</param>
|
/// <param name="taskId">任务id</param>
|
||||||
public static void InsertChannel(RedisChannelEnum @enum, object taskId)
|
public static void InsertChannel(RedisChannelEnum @enum, object taskId)
|
||||||
{
|
{
|
||||||
|
if (taskId is null) throw new Exception("taskId为空");
|
||||||
if (Redis is null) throw new Exception("redis未初始化");
|
if (Redis is null) throw new Exception("redis未初始化");
|
||||||
|
|
||||||
var startTime = Redis.HMGet<Dictionary<RedisChannelEnum, DateTime>>(RedisExpandKey.Task(taskId), "StartTime").FirstOrDefault();
|
var startTime = Redis.HMGet<Dictionary<RedisChannelEnum, DateTime>>(RedisExpandKey.Task(taskId), "StartTime").FirstOrDefault();
|
||||||
|
|
@ -128,28 +140,61 @@ namespace VideoAnalysisCore.Common
|
||||||
startTime[@enum] = DateTime.Now;
|
startTime[@enum] = DateTime.Now;
|
||||||
|
|
||||||
Redis.HMSet(RedisExpandKey.Task(taskId), "StartTime", startTime);
|
Redis.HMSet(RedisExpandKey.Task(taskId), "StartTime", startTime);
|
||||||
Redis.LPush(RedisExpandKey.EnumKey(@enum), taskId);
|
|
||||||
|
|
||||||
|
if(!SubscribeList.ContainsKey(@enum))
|
||||||
|
throw new Exception(@enum+" 未实现");
|
||||||
|
|
||||||
|
SubscribeList[@enum].Invoke(taskId.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task TaskEnd(string task)
|
||||||
|
{
|
||||||
|
var tId = long.Parse(task);
|
||||||
|
var gptRes = (await RedisExpand.Redis
|
||||||
|
.HMGetAsync<CallGPTRes>(RedisExpandKey.Task(task), "ChatAnalysis")).FirstOrDefault();
|
||||||
|
if (gptRes is null)
|
||||||
|
throw new Exception("未能读取到GPT处理结果");
|
||||||
|
|
||||||
|
var taskData = await DbScoped.SugarScope.Queryable<VideoTask>()
|
||||||
|
.FirstAsync(s => s.Id == tId);
|
||||||
|
taskData.ChatAnalysis = gptRes;
|
||||||
|
taskData.ChatAnalysisScore = gptRes.Assessment.Merit?.Sum(s => s.Score) ?? 0;
|
||||||
|
taskData.ErrorMessage = string.Empty;
|
||||||
|
taskData.LastEnum = RedisChannelEnum.EndTask;
|
||||||
|
await DbScoped.SugarScope.Updateable(taskData)
|
||||||
|
.UpdateColumns(it => new
|
||||||
|
{
|
||||||
|
it.ChatAnalysis,
|
||||||
|
it.ChatAnalysisScore,
|
||||||
|
it.ErrorMessage,
|
||||||
|
it.TotalTokens,
|
||||||
|
it.LastEnum,
|
||||||
|
}).ExecuteCommandAsync();
|
||||||
|
|
||||||
|
|
||||||
|
await Redis.DelAsync(RedisExpandKey.IDTask);
|
||||||
|
await ReceivingTaskAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化 队列 任务
|
/// 初始化 队列 任务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void InitChannel()
|
public static async void InitChannel()
|
||||||
{
|
{
|
||||||
if (Redis is null) throw new Exception("redis未初始化");
|
if (Redis is null) throw new Exception("redis未初始化");
|
||||||
|
|
||||||
Redis.SubscribeList(RedisExpandKey.EnumKey(RedisChannelEnum.DownloadFile),
|
SubscribeList.Add(RedisChannelEnum.DownloadFile,
|
||||||
(msg) => { TouchChannel(RedisChannelEnum.DownloadFile, msg, DownloadFile.RunTask); });
|
(msg) => { TouchChannel(RedisChannelEnum.DownloadFile, msg, DownloadFile.RunTask); });
|
||||||
|
|
||||||
Redis.SubscribeList(RedisExpandKey.EnumKey(RedisChannelEnum.SeparateAudio),
|
|
||||||
|
SubscribeList.Add(RedisChannelEnum.SeparateAudio,
|
||||||
(msg) => { TouchChannel(RedisChannelEnum.SeparateAudio, msg, FFMPGEHandle.Audio2WAV16KAsync); });
|
(msg) => { TouchChannel(RedisChannelEnum.SeparateAudio, msg, FFMPGEHandle.Audio2WAV16KAsync); });
|
||||||
|
|
||||||
Redis.SubscribeList(RedisExpandKey.EnumKey(RedisChannelEnum.ParsingCaptions),
|
SubscribeList.Add(RedisChannelEnum.ParsingCaptions,
|
||||||
(msg) => { TouchChannel(RedisChannelEnum.ParsingCaptions, msg, SenseVoice.RunTask); });
|
(msg) => { TouchChannel(RedisChannelEnum.ParsingCaptions, msg, SenseVoice.RunTask); });
|
||||||
Redis.SubscribeList(RedisExpandKey.EnumKey(RedisChannelEnum.ParsingSpeaker),
|
SubscribeList.Add(RedisChannelEnum.ParsingSpeaker,
|
||||||
(msg) => { TouchChannel(RedisChannelEnum.ParsingSpeaker, msg, Speaker.Run); });
|
(msg) => { TouchChannel(RedisChannelEnum.ParsingSpeaker, msg, Speaker.Run); });
|
||||||
Redis.SubscribeList(RedisExpandKey.EnumKey(RedisChannelEnum.ChatModelAnalysis),
|
SubscribeList.Add(RedisChannelEnum.ChatModelAnalysis,
|
||||||
(msg) =>
|
(msg) =>
|
||||||
{
|
{
|
||||||
TouchChannel(RedisChannelEnum.ChatModelAnalysis, msg,
|
TouchChannel(RedisChannelEnum.ChatModelAnalysis, msg,
|
||||||
|
|
@ -159,12 +204,38 @@ namespace VideoAnalysisCore.Common
|
||||||
if (scope is null || scope.ServiceProvider.GetService<IBserGPT>() is null)
|
if (scope is null || scope.ServiceProvider.GetService<IBserGPT>() is null)
|
||||||
throw new Exception("IBserGPT 未注入");
|
throw new Exception("IBserGPT 未注入");
|
||||||
else
|
else
|
||||||
return scope.ServiceProvider.GetService<IBserGPT>()?.CallGPT(task)??Task.CompletedTask;
|
return scope.ServiceProvider.GetService<IBserGPT>()?.CallGPT(task) ?? Task.CompletedTask;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
Redis.SubscribeList(RedisExpandKey.EnumKey(RedisChannelEnum.CallBackSystem),
|
SubscribeList.Add(RedisChannelEnum.EndTask,
|
||||||
(msg) => { TouchChannel(RedisChannelEnum.ParsingSpeaker, msg); });
|
(msg) => { TouchChannel(RedisChannelEnum.EndTask, msg, TaskEnd); });
|
||||||
|
|
||||||
|
await ReceivingTaskAsync();
|
||||||
|
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 重新接收新任务
|
||||||
|
/// </summary>
|
||||||
|
public static async Task ReceivingTaskAsync()
|
||||||
|
{
|
||||||
|
var oldTask = await Redis.GetAsync(RedisExpandKey.IDTask);
|
||||||
|
if (!string.IsNullOrEmpty(oldTask))
|
||||||
|
{
|
||||||
|
var lastEnum = (await Redis.HMGetAsync<RedisChannelEnum>(RedisExpandKey.Task(oldTask), "LastEnum")).FirstOrDefault();
|
||||||
|
await SetTaskErrorMessage(long.Parse(oldTask), null);
|
||||||
|
InsertChannel(lastEnum, oldTask);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Subscribe = Redis.SubscribeList(RedisExpandKey.ChannelKey, (taskId) =>
|
||||||
|
{
|
||||||
|
if (taskId is null) return;
|
||||||
|
Subscribe?.Dispose();
|
||||||
|
//存储当前机器的任务
|
||||||
|
Redis.Set(RedisExpandKey.IDTask, taskId);
|
||||||
|
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + "-> 接收到任务 " + taskId);
|
||||||
|
InsertChannel(RedisChannelEnum.DownloadFile, taskId);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -173,10 +244,22 @@ namespace VideoAnalysisCore.Common
|
||||||
/// <param name="taskID"></param>
|
/// <param name="taskID"></param>
|
||||||
/// <param name="errorMessage"></param>
|
/// <param name="errorMessage"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<bool> SetTaskErrorMessage(long taskID, string errorMessage)
|
public static async Task<bool> SetTaskErrorMessage(long taskID, Exception? ex)
|
||||||
{
|
{
|
||||||
|
var error = string.Empty;
|
||||||
|
if (ex != null)
|
||||||
|
{
|
||||||
|
//执行任务时出现异常
|
||||||
|
error = ex.Message + ex.StackTrace;
|
||||||
|
Console.WriteLine("====================[出现异常]====================");
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
Console.WriteLine(ex.StackTrace);
|
||||||
|
Console.WriteLine("==============================================");
|
||||||
|
}
|
||||||
|
|
||||||
|
Redis.HMSet(RedisExpandKey.Task(taskID), "ErrorMessage", error);
|
||||||
return await DbScoped.SugarScope.Updateable<VideoTask>()
|
return await DbScoped.SugarScope.Updateable<VideoTask>()
|
||||||
.SetColumns(it => it.ErrorMessage == errorMessage)//SetColumns是可以叠加的 写2个就2个字段赋值
|
.SetColumns(it => it.ErrorMessage == error)//SetColumns是可以叠加的 写2个就2个字段赋值
|
||||||
.Where(it => it.Id == taskID)
|
.Where(it => it.Id == taskID)
|
||||||
.ExecuteCommandAsync() == 1;
|
.ExecuteCommandAsync() == 1;
|
||||||
}
|
}
|
||||||
|
|
@ -189,12 +272,12 @@ namespace VideoAnalysisCore.Common
|
||||||
public static async void TouchChannel(RedisChannelEnum key, string taskId, Func<string, Task> action = null)
|
public static async void TouchChannel(RedisChannelEnum key, string taskId, Func<string, Task> action = null)
|
||||||
{
|
{
|
||||||
if (taskId is null) return;
|
if (taskId is null) return;
|
||||||
|
var tID = long.Parse(taskId);
|
||||||
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + "-> " + key + " " + taskId);
|
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + "-> " + key + " " + taskId);
|
||||||
if (action is not null)
|
if (action is not null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var tID = long.Parse(taskId);
|
|
||||||
Redis.HMSet(RedisExpandKey.Task(taskId), "LastEnum", key);
|
Redis.HMSet(RedisExpandKey.Task(taskId), "LastEnum", key);
|
||||||
Redis.HMSet(RedisExpandKey.Task(taskId), "Progress", 0);
|
Redis.HMSet(RedisExpandKey.Task(taskId), "Progress", 0);
|
||||||
await DbScoped.SugarScope.Updateable<VideoTask>()
|
await DbScoped.SugarScope.Updateable<VideoTask>()
|
||||||
|
|
@ -206,15 +289,8 @@ namespace VideoAnalysisCore.Common
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
//执行任务时出现异常
|
await SetTaskErrorMessage(tID, ex)
|
||||||
var error = ex.Message + ex.StackTrace;
|
.ConfigureAwait(false);//不切回上下文
|
||||||
await SetTaskErrorMessage(long.Parse(taskId), error);
|
|
||||||
|
|
||||||
Console.WriteLine("====================[出现异常]====================");
|
|
||||||
Console.WriteLine(ex.Message);
|
|
||||||
Console.WriteLine(ex.StackTrace);
|
|
||||||
Console.WriteLine("==============================================");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,14 @@ namespace VideoAnalysisCore.Enum
|
||||||
[Display(Prompt = "分析授课中使用的高频词" +
|
[Display(Prompt = "分析授课中使用的高频词" +
|
||||||
"10个频率从高到低 结果类型[]")]
|
"10个频率从高到低 结果类型[]")]
|
||||||
高频词 = 100,
|
高频词 = 100,
|
||||||
[Display(Prompt = "总结字幕内容划分成10个时间段" +
|
[Display(Prompt = "基于字幕内容知识点精准的划分成最多10个片段" +
|
||||||
"并且提取它们的内容概览 结果类型[{Start:开始时间,End:结束时间,Content:概览}]")]
|
"提取片段的内容概览,字幕开始秒,结束秒 结果类型[{Start:开始秒,End:结束秒,Content:概览}]")]
|
||||||
时间段概览 = 101,
|
时间段概览 = 101,
|
||||||
[Display(Prompt = "统计授课中教师提问类型的次数 提问类型" +
|
[Display(Prompt = "统计授课中教师回答类型的次数 回答类型" +
|
||||||
"[重复回答,老师追问,简单性表扬,老师补充答案,表扬并补充答案] 结果类型{提问类型:次数}")]
|
"[重复回答,老师追问,简单性表扬,老师补充答案,表扬并补充答案] 结果类型{回答类型:次数}")]
|
||||||
提问类型 = 102,
|
提问类型 = 102,
|
||||||
[Display(Prompt = " 分析授课中教师提到 类型" +
|
[Display(Prompt = " 分析授课中教师提到 以下类型" +
|
||||||
"[独立学习,小组合作,随堂练习]的时间段 结果类型[{Start:开始时间/null,End:结束时间/null,Content:类型}]")]
|
"[独立学习,小组合作,随堂练习]的时间段,提取出其中字幕开始秒,结束秒 结果类型[{Start:开始秒,End:结束秒,Content:类型}/null]")]
|
||||||
额外课堂情况 = 103,
|
额外课堂情况 = 103,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,10 @@
|
||||||
/// Chat模型分析
|
/// Chat模型分析
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ChatModelAnalysis,
|
ChatModelAnalysis,
|
||||||
/// <summary>
|
///// <summary>
|
||||||
/// 回调三方系统
|
///// 回调三方系统
|
||||||
/// </summary>
|
///// </summary>
|
||||||
CallBackSystem,
|
//CallBackSystem,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 结束任务
|
/// 结束任务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using VideoAnalysisCore.Enum;
|
using VideoAnalysisCore.Enum;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace VideoAnalysisCore.Model.Dto
|
namespace VideoAnalysisCore.Model.Dto
|
||||||
{
|
{
|
||||||
|
|
@ -64,5 +65,10 @@ namespace VideoAnalysisCore.Model.Dto
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DisplayName("创建时间")]
|
[DisplayName("创建时间")]
|
||||||
public DateTime CreateTime { get; set; } = DateTime.Now;
|
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||||
|
/// <summary>
|
||||||
|
/// 开始时间轴
|
||||||
|
/// <para>逻辑字段</para>
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<RedisChannelEnum, DateTime>? StartTimeDic {get; set;}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,7 @@ namespace VideoAnalysisCore.Model
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// AI模型评分
|
/// AI模型评分
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[SugarColumn(IsNullable =true)]
|
||||||
public decimal? ChatAnalysisScore { get; set; }
|
public decimal? ChatAnalysisScore { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 消耗token
|
/// 消耗token
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FreeRedis" Version="1.3.2" />
|
<PackageReference Include="FreeRedis" Version="1.3.2" />
|
||||||
|
<PackageReference Include="Downloader" Version="3.2.1" />
|
||||||
<PackageReference Include="Mapster" Version="7.4.1-pre01" />
|
<PackageReference Include="Mapster" Version="7.4.1-pre01" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue