完善 任务预览功能
This commit is contained in:
parent
59c8171ce8
commit
eb45f0fd41
|
|
@ -18,7 +18,7 @@
|
|||
<Routes @rendermode="InteractiveServer" />
|
||||
<script type="text/javascript" src="@("https://unpkg.com/@antv/g2plot@2.4.17/dist/g2plot.min.js")"></script>
|
||||
<script src="_content/AntDesign/js/ant-design-blazor.js"></script>
|
||||
<script src="_content/AntDesign.Charts/ant-design-charts-blazor.js"></script>
|
||||
@* <script src="_content/AntDesign.Charts/ant-design-charts-blazor.js"></script> *@
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
</body>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using System.Security.Policy;
|
||||
|
||||
namespace Learn.VideoAnalysis.Components.Pages.Dto
|
||||
{
|
||||
public class TaskShowRoute : PageModel
|
||||
{
|
||||
|
||||
public int ID;
|
||||
public void OnGet(int id)
|
||||
{
|
||||
ID = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +1,72 @@
|
|||
@page "/VideoTaskShow/{tid}"
|
||||
<div>
|
||||
<input type="file" id="videoFile" accept="video/*">
|
||||
<input type="file" id="subtitleFile" accept=".json">
|
||||
<input type="file" id="segmentsFile" accept=".json">
|
||||
</div>
|
||||
@page "/VideoTaskShow/{taskId:long}"
|
||||
|
||||
<div id="video-container">
|
||||
<video id="videoPlayer" controls></video>
|
||||
@if (videoKnows != null)
|
||||
{
|
||||
<div id="segmentsContainer">
|
||||
@for (int i = 0; i < videoKnows.Length; i++)
|
||||
{
|
||||
var item = videoKnows[i];
|
||||
<button class="kBtn" onclick="spClick(@i,this)">@getF(item) @item.Theme </button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<video id="videoPlayer" controls autoplay>
|
||||
<source type="video/mp4" />
|
||||
</video>
|
||||
<div id="subtitleArea" class="subtitles"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="segmentsContainer"></div>
|
||||
|
||||
<script>
|
||||
const
|
||||
window.b = []
|
||||
window.subtitles = []
|
||||
var displayButton = []
|
||||
var lastSegments = null;
|
||||
function init() {
|
||||
const videoPlayer = document.getElementById('videoPlayer');
|
||||
const subtitleArea = document.getElementById('subtitleArea');
|
||||
|
||||
|
||||
let subtitles = @captionsArr
|
||||
let segments = @videoKnows
|
||||
let displayButton = []
|
||||
let lastSegments = null;
|
||||
window.onload(() => {
|
||||
videoPlayer.src = @videoPath
|
||||
})
|
||||
|
||||
|
||||
//视频时间变化时
|
||||
videoPlayer.addEventListener('timeupdate', function () {
|
||||
if (displayButton.length == 0) initKD()
|
||||
const currentTime = videoPlayer.currentTime;
|
||||
subtitleArea.textContent = '';
|
||||
|
||||
subtitles.forEach(subtitle => {
|
||||
|
||||
let textContent = subtitle.Text || subtitle.Content;
|
||||
if (currentTime >= subtitle.Start
|
||||
&& currentTime <= subtitle.End
|
||||
//字幕
|
||||
window.subtitles.forEach(subtitle => {
|
||||
let textContent = subtitle.text
|
||||
if (currentTime >= subtitle.start
|
||||
&& currentTime <= subtitle.end
|
||||
&& subtitleArea.textContent != textContent) {
|
||||
|
||||
subtitleArea.textContent = textContent;
|
||||
}
|
||||
});
|
||||
let segment = displayButton.find(s => currentTime >= s.开始秒
|
||||
&& currentTime <= s.结束秒)
|
||||
//时间片
|
||||
let segment = displayButton.find(s => currentTime >= s.startTime
|
||||
&& currentTime <= s.endTime)
|
||||
if (segment) {
|
||||
segment.button.style.backgroundColor = "rgb(238, 200, 118)";
|
||||
if (lastSegments && lastSegments != segment) lastSegments.button.style.backgroundColor = "rgb(240, 249, 235)";
|
||||
lastSegments = segment
|
||||
}
|
||||
});
|
||||
function getF(segment) {
|
||||
let sf = parseInt(segment.开始秒 / 60)
|
||||
let sm = parseInt(segment.开始秒 % 60)
|
||||
let ef = parseInt(segment.结束秒 / 60)
|
||||
let em = parseInt(segment.结束秒 % 60)
|
||||
return `${sf}:${sm} - ${ef}:${em}`
|
||||
}
|
||||
function displaySegments() {
|
||||
const segmentsContainer = document.getElementById('segmentsContainer');
|
||||
segmentsContainer.innerHTML = '';
|
||||
segments.forEach(segment => {
|
||||
const button = document.createElement('button');
|
||||
displayButton.push(segment);
|
||||
segment.button = button;
|
||||
button.textContent =
|
||||
`${getF(segment)} ${segment.主题}`;
|
||||
button.addEventListener('click', () => {
|
||||
videoPlayer.currentTime = segment.开始秒;
|
||||
videoPlayer.play();
|
||||
});
|
||||
segmentsContainer.appendChild(button);
|
||||
});
|
||||
function initKD() {
|
||||
let btns = document.getElementsByClassName("kBtn")
|
||||
if(btns.length == 0) return
|
||||
displayButton = window.b.map((s, i) => { return { ...s, button: btns[i] } })
|
||||
}
|
||||
//后端传递初始化数据
|
||||
function setDB(a, b,c) {
|
||||
console.log("setDB", a, b,c)
|
||||
window.subtitles = a
|
||||
window.b = b
|
||||
const videoPlayer = document.getElementById('videoPlayer');
|
||||
videoPlayer.src=c
|
||||
init()
|
||||
}
|
||||
//点击时间片时
|
||||
function spClick(i, button) {
|
||||
videoPlayer.currentTime = displayButton[i].startTime;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Learn.VideoAnalysis.Controllers.Dto;
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.AspNetCore.DataProtection.KeyManagement;
|
||||
using Microsoft.JSInterop;
|
||||
using SqlSugar;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -14,15 +15,21 @@ using VideoAnalysisCore.Common;
|
|||
using VideoAnalysisCore.Enum;
|
||||
using VideoAnalysisCore.Model;
|
||||
using VideoAnalysisCore.Model.Dto;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
|
||||
namespace Learn.VideoAnalysis.Components.Pages
|
||||
{
|
||||
public partial class VideoTaskShow : ComponentBase
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 任务id
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public long? taskId { get; set; }
|
||||
[Inject] private ConfirmService ComfirmService { get; set; } = default!;
|
||||
[Inject] private IHttpContextAccessor HttpContext { get; set; } = default!;
|
||||
[Inject] private Repository<VideoTask> taskDB { get; set; } = default!;
|
||||
[Inject] private IJSRuntime JSRuntime { get; set; } = default!;
|
||||
|
||||
private VideoTask nowTask { get; set; } = default!;
|
||||
private string videoPath { get; set; } = default!;
|
||||
|
|
@ -42,24 +49,37 @@ namespace Learn.VideoAnalysis.Components.Pages
|
|||
/// <returns></returns>
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
public string getF(VideoKnowRes segment)
|
||||
{
|
||||
var sf = (int)((segment.StartTime ?? 0) / 60);
|
||||
var sm = (int)((segment.StartTime ?? 0) % 60);
|
||||
var ef = (int)((segment.EndTime ?? 0) / 60);
|
||||
var em = (int)((segment.EndTime ?? 0) % 60);
|
||||
return $"{sf}:{sm} - {ef}: {em}";
|
||||
}
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
protected override async void OnInitialized()
|
||||
{
|
||||
var routeData = HttpContext.HttpContext.GetRouteData();
|
||||
if (routeData is null)
|
||||
if (this.taskId is null)
|
||||
return;
|
||||
long taskId = (long)routeData.Values["id"];
|
||||
long taskId = this.taskId.Value;
|
||||
nowTask = await taskDB.GetFirstAsync(s => s.Id == taskId);
|
||||
if(nowTask is null)
|
||||
return;
|
||||
captionsArr = RedisExpand.Redis.HMGet<SenseVoiceRes[]>(RedisExpandKey.Task(taskId), "Captions").FirstOrDefault();
|
||||
videoKnows = RedisExpand.Redis.HMGet<VideoKnowRes[]>(RedisExpandKey.Task(taskId), "VideoKnows").FirstOrDefault();
|
||||
videoPath = AppCommon.GetVideoPath(nowTask.Id.ToString());
|
||||
|
||||
await JSRuntime.InvokeVoidAsync("setDB", captionsArr,videoKnows, videoPath);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task<bool> Comfirm(string message)
|
||||
|
|
|
|||
|
|
@ -6,27 +6,37 @@
|
|||
|
||||
#video-container {
|
||||
position: relative;
|
||||
width: 1600px;
|
||||
width: 1660px;
|
||||
height: 850px;
|
||||
float: left;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
width: 94%;
|
||||
height: 85%;
|
||||
}
|
||||
|
||||
.subtitles {
|
||||
position: absolute;
|
||||
bottom: -40px;
|
||||
bottom: 200px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
#segmentsContainer:is(:hover) {
|
||||
width: 400px;
|
||||
right: 0px;
|
||||
}
|
||||
#segmentsContainer {
|
||||
transition:right 0.7s;
|
||||
z-index:999;
|
||||
overflow-x: hidden;
|
||||
background-color: #e3e3e3c2;
|
||||
position: absolute;
|
||||
right: -180px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 265px;
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ namespace Learn.VideoAnalysis
|
|||
// app.UseExceptionHandler("/Login");
|
||||
//}
|
||||
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.UseStaticFiles(new StaticFileOptions
|
||||
{
|
||||
|
|
|
|||
|
|
@ -46,10 +46,10 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT
|
|||
foreach (var next in timeBases)
|
||||
{
|
||||
// 如果类型相同,则扩展时间段
|
||||
if (current.主题 == next.主题)
|
||||
if (current.Theme == next.Theme)
|
||||
{
|
||||
current.结束秒 = Math.Max(current.结束秒.Value, next.结束秒.Value);
|
||||
current.内容总结 += next.内容总结;
|
||||
current.EndTime = Math.Max(current.EndTime.Value, next.EndTime.Value);
|
||||
current.Content += next.Content;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,12 +15,24 @@ namespace VideoAnalysisCore.AICore.GPT.Dto
|
|||
/// <summary>
|
||||
/// 问题解释
|
||||
/// </summary>
|
||||
public float? 开始秒 { get; set; }
|
||||
public float? 结束秒 { get; set; }
|
||||
public float? 持续时间 => (结束秒 ?? 0) - 开始秒??0;
|
||||
public string? 主题 { get; set; }
|
||||
public string? 章节 { get; set; }
|
||||
public string? 内容总结 { get; set; }
|
||||
public float? StartTime { get; set; }
|
||||
public float? EndTime { get; set; }
|
||||
/// <summary>
|
||||
/// 持续时间
|
||||
/// </summary>
|
||||
public float? KeepTime => (EndTime ?? 0) - StartTime ?? 0;
|
||||
/// <summary>
|
||||
/// 主题
|
||||
/// </summary>
|
||||
public string? Theme { get; set; }
|
||||
/// <summary>
|
||||
/// 章节
|
||||
/// </summary>
|
||||
public string? Section { get; set; }
|
||||
/// <summary>
|
||||
/// 内容总结
|
||||
/// </summary>
|
||||
public string? Content { get; set; }
|
||||
|
||||
}
|
||||
public class FileNameInfo
|
||||
|
|
|
|||
|
|
@ -79,8 +79,7 @@ namespace VideoAnalysisCore.Common
|
|||
/// </summary>
|
||||
/// <param name="tid"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetVideoPath(string tid) =>
|
||||
Path.Combine(TaskCachedFile, tid, tid + ".mp4");
|
||||
public static string GetVideoPath(string tid) => $"./video/{tid}/{tid}.mp4";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ namespace VideoAnalysisCore.Common
|
|||
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.ChatAnalysisScore = gptRes?.Assessment?.Merit?.Sum(s => s.Score) ?? 0;
|
||||
taskData.ErrorMessage = string.Empty;
|
||||
taskData.LastEnum = RedisChannelEnum.EndTask;
|
||||
await DbScoped.SugarScope.Updateable(taskData)
|
||||
|
|
|
|||
Loading…
Reference in New Issue