diff --git a/VideoAnalysisCore/AICore/GPT/BserGPT.cs b/VideoAnalysisCore/AICore/GPT/BserGPT.cs
index 48db489..4fa3ca3 100644
--- a/VideoAnalysisCore/AICore/GPT/BserGPT.cs
+++ b/VideoAnalysisCore/AICore/GPT/BserGPT.cs
@@ -15,7 +15,7 @@ using System.Text.Json.Serialization;
namespace VideoAnalysisCore.AICore.GPT
{
- public interface IBserGPT
+ public interface IBserGPTWorkflow
{
///
/// 访问GPT
@@ -190,8 +190,8 @@ namespace VideoAnalysisCore.AICore.GPT
public static void AddGPTService(this IServiceCollection services)
{
services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
}
diff --git a/VideoAnalysisCore/AICore/GPT/ChatGPT/ChatGPTClient.cs b/VideoAnalysisCore/AICore/GPT/ChatGPT/ChatGPTClient.cs
index 261eacc..6a47fda 100644
--- a/VideoAnalysisCore/AICore/GPT/ChatGPT/ChatGPTClient.cs
+++ b/VideoAnalysisCore/AICore/GPT/ChatGPT/ChatGPTClient.cs
@@ -15,7 +15,10 @@ using System.Text.Json;
namespace VideoAnalysisCore.AICore.GPT.ChatGPT
{
- public class ChatGPTClient : GPTClient
+ ///
+ /// 接入oaibest
+ ///
+ public class BestAIClient : GPTClient
{
public override GptConfig Config { get; set; } = AppCommon.Config.ChatGpt.ChatGpt;
@@ -23,7 +26,7 @@ namespace VideoAnalysisCore.AICore.GPT.ChatGPT
private readonly IHttpClientFactory _httpClientFactory;
private readonly RedisManager redisManager;
- public ChatGPTClient(IHttpClientFactory httpClientFactory, RedisManager redisManager) : base(httpClientFactory, redisManager)
+ public BestAIClient(IHttpClientFactory httpClientFactory, RedisManager redisManager) : base(httpClientFactory, redisManager)
{
_httpClientFactory = httpClientFactory;
this.redisManager = redisManager;
diff --git a/VideoAnalysisCore/AICore/GPT/ChatGPTType.cs b/VideoAnalysisCore/AICore/GPT/ChatGPTType.cs
index c21c81d..f5aaef5 100644
--- a/VideoAnalysisCore/AICore/GPT/ChatGPTType.cs
+++ b/VideoAnalysisCore/AICore/GPT/ChatGPTType.cs
@@ -16,5 +16,9 @@ namespace VideoAnalysisCore.AICore.GPT
public static string Deepseek_Chat = "deepseek-chat";
+ public static string Gemini_3_Chat_thinking = "gemini-3-pro-preview-thinking";
+ public static string Gemini_3_Chat = "gemini-3-pro-preview";
+
+
}
}
diff --git a/VideoAnalysisCore/AICore/GPT/GPTClient.cs b/VideoAnalysisCore/AICore/GPT/GPTClient.cs
index 7ce403f..441e737 100644
--- a/VideoAnalysisCore/AICore/GPT/GPTClient.cs
+++ b/VideoAnalysisCore/AICore/GPT/GPTClient.cs
@@ -167,7 +167,7 @@ namespace VideoAnalysisCore.AICore.GPT
var chatResp = await Chat(chatRep);
var chatResContent = chatResp?.res;
if (string.IsNullOrEmpty(chatResContent))
- throw new Exception("GPT返回message无效结果");
+ throw new Exception($"GPT返回message无效结果 => res:{chatResp?.res} reasoning:{chatResp?.reasoning}");
if (chatResp != null)
{
redisCached[1] = new object[] { chatResp.Value.res, chatResp.Value.u, chatResp.Value.reasoning };
diff --git a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs b/VideoAnalysisCore/AICore/GPT/GTP_Analysis_1.cs
similarity index 85%
rename from VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs
rename to VideoAnalysisCore/AICore/GPT/GTP_Analysis_1.cs
index 5e11d2f..d03f6f2 100644
--- a/VideoAnalysisCore/AICore/GPT/DeepSeek/DeepSeek_GPT.cs
+++ b/VideoAnalysisCore/AICore/GPT/GTP_Analysis_1.cs
@@ -26,12 +26,13 @@ using System.Text.RegularExpressions;
namespace VideoAnalysisCore.AICore.GPT.DeepSeek
{
///
- /// chatgpt 文本模型
+ /// 视频分析工作流1
///
- public class DeepSeek_GPT : IBserGPT
+ public class GTP_Analysis_1 : IBserGPTWorkflow
{
+ private readonly GeminiGPTClient geminiClient;
private readonly DeepSeekGPTClient chatClient;
- private readonly ChatGPTClient chatGPTClient;
+ private readonly BestAIClient chatGPTClient;
private readonly Repository criteriaDB;
private readonly RedisManager redisManager;
private readonly Repository videoTaskDB;
@@ -46,9 +47,9 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
///
///
///
- public DeepSeek_GPT(DeepSeekGPTClient moonshotClient, Repository criteria, Repository videoTaskDB,
+ public GTP_Analysis_1(DeepSeekGPTClient moonshotClient, Repository criteria, Repository videoTaskDB,
Repository knowledgeInfoDB, Repository videoKonwPointDB, SimpLetexClient simpLetexClient,
- Repository videoQuestionDB, OssClient ossClient, Repository videoQuestionKonwDB, RedisManager redisManager, ChatGPTClient chatGPTClient)
+ Repository videoQuestionDB, OssClient ossClient, Repository videoQuestionKonwDB, RedisManager redisManager, BestAIClient chatGPTClient, GeminiGPTClient geminiClient)
{
chatClient = moonshotClient;
criteriaDB = criteria;
@@ -61,6 +62,7 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
this.videoQuestionKonwDB = videoQuestionKonwDB;
this.redisManager = redisManager;
this.chatGPTClient = chatGPTClient;
+ this.geminiClient = geminiClient;
}
///
/// 获取分段内容对应的章节知识点
@@ -297,8 +299,8 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
try
{
var keyFrameArr = string.IsNullOrEmpty(taskInfo?.PPTVideoCode) || string.IsNullOrEmpty(taskInfo?.PPTKeyFrame)
- ? string.Empty
- : $"授课PPT发生了变化的时间是{taskInfo.PPTKeyFrame},所以在这些时间段附近应该发生了授课内容得变化,授课阶段结果尽量参考这些时间节点(PPT与字幕有一定的延时)。";
+ ? $""
+ : $"授课PPT发生了变化的时间是{taskInfo.PPTKeyFrame},基于PPT变化时间点,将字幕内容分割成时间段。每个时间段的起始和结束应接近这些时间点(例如,以时间点为中心,扩展至内容自然过渡处)。";
var resFormat = """[{"StartTime":开始秒(number),"EndTime":结束秒(number),"Stage":阶段(string),"Theme":主题(string),"Content":内容总结(string)}]""";
var postMessages = string.Empty;
@@ -306,46 +308,27 @@ namespace VideoAnalysisCore.AICore.GPT.DeepSeek
{
case AttachmentsInfoType.其他资料:
case AttachmentsInfoType.新课:
- postMessages =
- $"请通过视频字幕内容分析出视频中课堂的授课阶段。" +
- $"课堂内容与{taskInfo.Subject}学科下的{sections}章节相关。" +
- $"{keyFrameArr}" +
- $"完整的课堂标准流程包含以下5个阶段:课程引入/新知讲解/例题精讲/课堂练习/知识总结。" +
- $"每个类型的授课阶段允许有多个 例如 多个新知讲解/例题精讲..." +
- $"1.初步划分阶段:基于PPT变化时间点,将字幕内容分割成时间段。每个时间段的起始和结束应接近这些时间点(例如,以时间点为中心,扩展至内容自然过渡处)。" +
- $"2.内容分析:对每个时间段,提取主要讲解内容:识别关键词(如“例题”“证明”“练习”“总结”)和内容结构。" +
- $"3.判断阶段类型:如果内容以解题为主,归类为“例题精讲”;如果涉及新知识讲解,归类为“新知讲解”;以此类推。" +
- $"4.生成内容总结与主题:内容总结:用1-2句话简述该阶段的核心讲解内容(例如,“通过例题演示柯西不等式在求最值中的应用”)。" +
- $"5.阶段主题:基于内容总结,提炼一个具体主题(例如,“柯西不等式的基本应用”)。" +
- $"6.时长检查与调整:计算每个阶段的时长(结束时间减开始时间)。如果阶段时长低于50秒,则合并相邻的类似内容阶段(例如,将两个连续的例题讲解合并为一个阶段),或扩展时间段以确保最低50秒。调整时需保持内容连贯性。" +
- $"7.输出要求:最终分析结果应列出每个阶段的开始时间、结束时间、阶段类型、主题和详细的内容总结(50~100字不包含提示词内容),确保划分合理、无重叠,且时长符合要求。" +
- $"输出内容只返回json格式({resFormat})" +
- $"字幕格式(开始秒:内容|下一段字幕).以下是包含时间的视频字幕文本。" +
- $"字幕列表 {captions.Captions} 字幕结束!";
- break;
case AttachmentsInfoType.复习:
- postMessages =
- $"请通过视频字幕内容分析出视频中课堂的授课阶段。" +
- $"课堂内容与{taskInfo.Subject}学科下的{sections}章节相关。" +
- $"{keyFrameArr}" +
- $"完整的课堂标准流程包含以下5个阶段:课程引入/新知讲解/例题精讲/课堂练习/知识总结。" +
- $"但本堂课是习题课,所以大部分阶段是不同的例题讲解内容。" +
- $"1.初步划分阶段:基于PPT变化时间点,将字幕内容分割成时间段。每个时间段的起始和结束应接近这些时间点(例如,以时间点为中心,扩展至内容自然过渡处)。" +
- $"2.内容分析:对每个时间段,提取主要讲解内容:识别关键词(如“例题”“证明”“练习”“总结”)和内容结构。" +
- $"3.判断阶段类型:如果内容以解题为主,归类为“例题精讲”;如果涉及新知识讲解,归类为“新知讲解”;以此类推。" +
- $"4.生成内容总结与主题:内容总结:用1-2句话简述该阶段的核心讲解内容(例如,“通过例题演示柯西不等式在求最值中的应用”)。" +
- $"5.阶段主题:基于内容总结,提炼一个具体主题(例如,“柯西不等式的基本应用”)。" +
- $"6.时长检查与调整:计算每个阶段的时长(结束时间减开始时间)。如果阶段时长低于50秒,则合并相邻的类似内容阶段(例如,将两个连续的例题讲解合并为一个阶段),或扩展时间段以确保最低50秒。调整时需保持内容连贯性。" +
- $"7.输出要求:最终分析结果应列出每个阶段的开始时间、结束时间、阶段类型、主题和详细的内容总结(50~100字不包含提示词内容),确保划分合理、无重叠,且时长符合要求。" +
- $"输出格式要求:内容只返回json格式({resFormat})" +
- $"字幕格式(开始秒:内容|下一段字幕).以下是包含时间的视频字幕文本。" +
- $"字幕列表 {captions.Captions} 字幕结束!";
- break;
case AttachmentsInfoType.活动:
case AttachmentsInfoType.班会:
+ break;
default:
throw new Exception("无效的课程类型");
}
+ postMessages =
+ $"请通过视频字幕内容分析出视频中课堂的授课阶段。" +
+ $"课堂内容与{taskInfo.Subject}学科下的{sections}章节相关。" +
+ $"完整的课堂标准流程包含以下5个阶段:课程引入/新知讲解/例题精讲/课堂练习/知识总结。" +
+ (taskInfo?.VideoType == AttachmentsInfoType.复习 ? $"但本堂课是习题课,所以大部分阶段是不同的例题讲解内容。" : string.Empty) +
+ $"初步划分阶段:{keyFrameArr}" +
+ $"内容分析:对每个时间段,提取主要讲解内容:识别关键词(如“例题”“证明”“练习”“总结”)和内容结构。" +
+ $"判断阶段类型:如果内容以解题为主,归类为“例题精讲”;如果涉及新知识讲解,归类为“新知讲解”;以此类推。" +
+ $"内容总结:简述该阶段的核心讲解内容70~200字,确保内容与阶段时间内授课内容符合。" +
+ $"阶段主题:基于内容总结,提炼一个恰当的主题(例如,“柯西不等式的基本应用”)。" +
+ $"输出要求:确保阶段划分合理、无重叠,且时长符合要求" +
+ $"输出格式要求:内容只返回json格式({resFormat})" +
+ $"字幕格式(开始秒:内容|下一段字幕).以下是包含时间的视频字幕文本。" +
+ $"字幕列表 {captions.Captions} 字幕结束!";
await redisManager.AddTaskLog(taskInfo.Id, $"开始分析视频内容 {tryCount}");
//return await chatGPTClient.ChatAsync(taskInfo.Id.ToString(), postMessages, "分析字幕");
diff --git a/VideoAnalysisCore/AICore/GPT/Gemini/GeminiGPTClient.cs b/VideoAnalysisCore/AICore/GPT/Gemini/GeminiGPTClient.cs
new file mode 100644
index 0000000..2d18ef4
--- /dev/null
+++ b/VideoAnalysisCore/AICore/GPT/Gemini/GeminiGPTClient.cs
@@ -0,0 +1,69 @@
+using VideoAnalysisCore.Common;
+using System.Net.Http.Headers;
+using System.Text;
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json.Linq;
+using System.Net.Http;
+using Newtonsoft.Json;
+using System.Net.Http.Json;
+using System.Net;
+using VideoAnalysisCore.AICore.GPT.DeepSeek;
+using VideoAnalysisCore.AICore.GPT;
+using System.Text.Json;
+
+
+namespace VideoAnalysisCore.AICore.GPT.ChatGPT
+{
+
+ public class GeminiGPTClient : GPTClient
+ {
+
+ public override GptConfig Config { get; set; } = AppCommon.Config.ChatGpt.ChatGpt;
+
+ private readonly IHttpClientFactory _httpClientFactory;
+ private readonly RedisManager redisManager;
+
+ public GeminiGPTClient(IHttpClientFactory httpClientFactory, RedisManager redisManager) : base(httpClientFactory, redisManager)
+ {
+ _httpClientFactory = httpClientFactory;
+ this.redisManager = redisManager;
+ }
+
+
+ ///
+ /// 请求AI
+ ///
+ /// 返回JSON类型
+ /// 任务id
+ /// 提示词
+ /// 任务类型
+ /// GPT版本
+ /// 最大token 不设置默认最大值 16000/8000
+ ///
+ ///
+ public async Task ChatAsync(string task, string postMessages, string title, string model = null, int max_tokens = 8000)
+ {
+ Message[] messageArr = [
+ new Message(postMessages,"user"),
+ ];
+ model = model ?? ChatGPTType.Gemini_3_Chat;
+ messageArr = messageArr.Where(s => s != null).ToArray();
+ var chatReq = new ChatRequest
+ {
+ taskId = task,
+ model = model,
+ max_tokens =12000,
+ stream = true,
+ temperature = 0.2f,
+ messages = messageArr
+ };
+
+ chatReq.modalities = null;
+ chatReq.max_tokens = null;
+ chatReq.top_p = null;
+
+ return await base.ChatAsync(chatReq);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/VideoAnalysisCore/Common/RedisExpand.cs b/VideoAnalysisCore/Common/RedisExpand.cs
index 6b442b9..3692422 100644
--- a/VideoAnalysisCore/Common/RedisExpand.cs
+++ b/VideoAnalysisCore/Common/RedisExpand.cs
@@ -137,26 +137,26 @@ namespace VideoAnalysisCore.Common
SubscribeList.Add(RedisChannelEnum.AI课程类型, async (task) =>
{
using var scope = AppCommon.Services?.CreateScope();
- if (scope is null || scope.ServiceProvider.GetService() is null)
+ if (scope is null || scope.ServiceProvider.GetService() is null)
throw new Exception("IBserGPT 未注入");
else
- await scope.ServiceProvider.GetService()?.GetVideoType(task);
+ await scope.ServiceProvider.GetService()?.GetVideoType(task);
});
SubscribeList.Add(RedisChannelEnum.AI模型分析, async (task) =>
{
using var scope = AppCommon.Services?.CreateScope();
- if (scope is null || scope.ServiceProvider.GetService() is null)
+ if (scope is null || scope.ServiceProvider.GetService() is null)
throw new Exception("IBserGPT 未注入");
else
- await scope.ServiceProvider?.GetService()?.GetKnow(task);
+ await scope.ServiceProvider?.GetService()?.GetKnow(task);
});
SubscribeList.Add(RedisChannelEnum.AI分析试题, async (task) =>
{
using var scope = AppCommon.Services?.CreateScope();
- if (scope is null || scope.ServiceProvider.GetService() is null)
+ if (scope is null || scope.ServiceProvider.GetService() is null)
throw new Exception("IBserGPT 未注入");
else
- await scope.ServiceProvider?.GetService()?.GetVideoQuestion(task);
+ await scope.ServiceProvider?.GetService()?.GetVideoQuestion(task);
});
SubscribeList.Add(RedisChannelEnum.结束任务, redisManager.TaskEnd);