2 Коммиты 914189a8af ... 7d5cfae252

Автор SHA1 Сообщение Дата
  Lyyyi 7d5cfae252 混元AI 和 豆包AI 共同修改处合并 дней назад: 4
  Lyyyi 5f90111417 接入 混元AI дней назад: 4

+ 101 - 0
OASystem/OASystem.Api/Controllers/AITestController.cs

@@ -0,0 +1,101 @@
+using Microsoft.AspNetCore.Mvc;
+using OASystem.API.OAMethodLib.HunYuanAPI;
+using TencentCloud.Hunyuan.V20230901.Models;
+
+namespace OASystem.API.Controllers
+{
+    /// <summary>
+    /// AI测试控制器
+    /// </summary>
+    [Route("api/[controller]")]
+    public class AITestController : ControllerBase
+    {
+        private readonly IHunyuanService _hunyuanService;
+        private readonly ILogger<AITestController> _logger;
+
+        public AITestController(IHunyuanService hunyuanService, ILogger<AITestController> logger)
+        {
+            _hunyuanService = hunyuanService;
+            _logger = logger;
+        }
+
+        #region 混元 AI
+        /// <summary>
+        /// 基础对话示例
+        /// </summary>
+        [HttpPost("chat")]
+        public async Task<ActionResult<string>> BasicChat(string question)
+        {
+            try
+            {
+                var response = await _hunyuanService.ChatCompletionsHunyuan_t1_latestAsync(question);
+                return Ok(response);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, "调用腾讯云混元API失败。");
+                return StatusCode(500, new { Message = "调用腾讯云API失败,请检查配置或网络。", Detail = ex.Message });
+            }
+        }
+
+        /// <summary>
+        /// 模拟“根据文件提问”的API端点
+        /// 注意:此示例中,文件内容通过请求体传入。
+        /// 实际场景中,文件内容可能来自用户上传并解析(如PDF、TXT解析为文本)后的结果。
+        /// </summary>
+        [HttpPost("ask-with-file")]
+        public async Task<ActionResult<string>> AskBasedOnFile([FromBody] AskWithFileRequest request)
+        {
+            if (string.IsNullOrEmpty(request.FileContent) || string.IsNullOrEmpty(request.Question))
+            {
+                return BadRequest(new { Message = "FileContent和Question字段不能为空。" });
+            }
+
+            try
+            {
+                var answer = await _hunyuanService.AskWithFileContextAsync(request.FileContent, request.Question, request.Model);
+                return Ok(answer);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, "处理基于文件的提问失败。");
+                return StatusCode(500, new { Message = "处理请求失败。", Detail = ex.Message });
+            }
+        }
+
+        /// <summary>
+        /// 用于测试的GET端点,快速验证服务可用性(使用示例数据)
+        /// </summary>
+        [HttpGet("test-file-query")]
+        public async Task<ActionResult<string>> TestFileQuery()
+        {
+            // 示例文件内容和问题
+            var sampleFileContent = "在软件开发中,依赖注入(Dependency Injection)是一种设计模式,用于实现控制反转(Inversion of Control, IoC)。它允许在类外部创建依赖对象,并通过构造函数、属性或方法将其‘注入’到类中,从而降低类之间的耦合度。";
+            var sampleQuestion = "依赖注入的主要目的是什么?";
+            var model = "hunyuan-lite"; // 可使用 "hunyuan-pro" 等
+
+            try
+            {
+                var answer = await _hunyuanService.AskWithFileContextAsync(sampleFileContent, sampleQuestion, model);
+                return Ok($"测试成功。问题:'{sampleQuestion}'\n回答:{answer}");
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, "测试文件提问失败。");
+                return StatusCode(500, new { Message = "测试失败。", Detail = ex.Message });
+            }
+        }
+
+        /// <summary>
+        /// 用于“根据文件提问”的请求体
+        /// </summary>
+        public class AskWithFileRequest
+        {
+            public string FileContent { get; set; } = string.Empty;
+            public string Question { get; set; } = string.Empty;
+            public string Model { get; set; } = "hunyuan-lite";
+        }
+        #endregion
+
+    }
+}

+ 96 - 0
OASystem/OASystem.Api/OAMethodLib/HunYuanAPI/HunyuanService.cs

@@ -0,0 +1,96 @@
+using TencentCloud.Hunyuan.V20230901;
+using TencentCloud.Hunyuan.V20230901.Models;
+
+namespace OASystem.API.OAMethodLib.HunYuanAPI
+{
+    public class HunyuanService : IHunyuanService
+    {
+        private readonly HunyuanClient _hunyuanClient;
+
+        /// <summary>
+        /// 构造函数注入配置好的HunyuanClient
+        /// </summary>
+        /// <param name="hunyuanClient"></param>
+        public HunyuanService(HunyuanClient hunyuanClient)
+        {
+            _hunyuanClient = hunyuanClient;
+        }
+
+        /// <inheritdoc />
+        public async Task<string> ChatCompletionsHunyuan_t1_latestAsync(string question)
+        {
+            var request = new ChatCompletionsRequest
+            {
+                Model = "hunyuan-t1-latest",
+                Messages = new Message[]
+                {
+                    new Message
+                    {
+                        Role = "user",
+                        Content = question
+                    }
+                },
+                Stream = false,
+                Temperature = 0.5f,
+                TopP = 1.0f,
+                // 其他参数根据需要设置
+            };
+
+            // 直接调用SDK方法
+            var response = await _hunyuanClient.ChatCompletions(request);
+
+            // 提取并返回模型生成的回答
+            // 注意:响应结构可能包含多个Choice,这里取第一个。
+            if (response.Choices != null && response.Choices.Length > 0)
+            {
+                return response.Choices[0].Message.Content?.Trim() ?? "模型未返回内容。";
+            }
+
+            return "模型未生成有效回答。";
+        }
+
+        public async Task<ChatCompletionsResponse> ChatCompletionsAsync(ChatCompletionsRequest request)
+        {
+            // 直接调用SDK方法
+            return await _hunyuanClient.ChatCompletions(request);
+        }
+
+        /// <inheritdoc />
+        public async Task<string> AskWithFileContextAsync(string fileContent, string question, string model = "hunyuan-lite")
+        {
+            // 1. 构建提示词:将文件内容作为上下文,与用户问题结合。
+            // 这是一个简单示例,实际可根据需求设计更复杂的Prompt。
+            string prompt = $"请根据以下文本内容回答问题。\n文本内容:{fileContent}\n问题:{question}";
+
+            // 2. 使用SDK自带实体构建请求
+            var request = new ChatCompletionsRequest
+            {
+                Model = model,
+                Messages = new Message[]
+                {
+                    new Message
+                    {
+                        Role = "user",
+                        Content = prompt
+                    }
+                },
+                // 可根据需要设置其他参数,如Stream, Temperature, TopP等
+                // Stream = false,
+                // Temperature = 0.5f,
+                // TopP = 1.0f,
+            };
+
+            // 3. 调用SDK方法
+            var response = await ChatCompletionsAsync(request);
+
+            // 4. 提取并返回模型生成的回答
+            // 注意:响应结构可能包含多个Choice,这里取第一个。
+            if (response.Choices != null && response.Choices.Length > 0)
+            {
+                return response.Choices[0].Message.Content?.Trim() ?? "模型未返回内容。";
+            }
+
+            return "模型未生成有效回答。";
+        }
+    }
+}

+ 35 - 0
OASystem/OASystem.Api/OAMethodLib/HunYuanAPI/IHunyuanService.cs

@@ -0,0 +1,35 @@
+using TencentCloud.Hunyuan.V20230901.Models;
+
+namespace OASystem.API.OAMethodLib.HunYuanAPI
+{
+    /// <summary>
+    /// 腾讯云混元大模型服务接口
+    /// </summary>
+    public interface IHunyuanService
+    {
+        /// <summary>
+        /// 发送聊天补全请求 - 使用"hunyuan-t1-latest"模型(基础对话)
+        /// </summary>
+        /// <param name="question">问题</param>
+        /// <returns>回答的具体信息</returns>
+        Task<string> ChatCompletionsHunyuan_t1_latestAsync(string question);
+
+        /// <summary>
+        /// 发送聊天补全请求(基础对话)
+        /// </summary>
+        /// <param name="request">问题</param>
+        /// <returns>SDK自带的响应实体</returns>
+        Task<ChatCompletionsResponse> ChatCompletionsAsync(ChatCompletionsRequest request);
+
+        /// <summary>
+        /// 模拟“根据文件内容提问”的流程
+        /// 注意:此方法假设您已通过其他方式(如上传、解析)获取了文件文本内容。
+        /// 本方法仅负责将文件内容作为上下文与问题拼接后,调用大模型。
+        /// </summary>
+        /// <param name="fileContent">已读取的文件文本内容</param>
+        /// <param name="question">针对文件内容提出的问题</param>
+        /// <param name="model">模型名称,默认使用"hunyuan-lite"</param>
+        /// <returns>大模型生成的回答</returns>
+        Task<string> AskWithFileContextAsync(string fileContent, string question, string model = "hunyuan-lite");
+    }
+}

+ 1 - 1
OASystem/OASystem.Api/OASystem.API.csproj

@@ -71,7 +71,7 @@
     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
     <PackageReference Include="System.Data.OleDb" Version="8.0.0" />
     <PackageReference Include="System.Security.Permissions" Version="6.0.1" />
-    <PackageReference Include="TencentCloudSDK.Common" Version="3.0.734" />
+    <PackageReference Include="TencentCloudSDK.Hunyuan" Version="3.0.1378" />
     <PackageReference Include="TencentCloudSDK.Ocr" Version="3.0.734" />
     <PackageReference Include="TinyPinyin.Net" Version="1.0.2" />
     <PackageReference Include="UAParser" Version="3.1.47" />

+ 48 - 0
OASystem/OASystem.Api/Program.cs

@@ -1,8 +1,10 @@
+using Microsoft.AspNetCore.DataProtection;
 using Microsoft.AspNetCore.Http.Connections;
 using Microsoft.AspNetCore.Http.Features;
 using Microsoft.AspNetCore.ResponseCompression;
 using Microsoft.AspNetCore.Server.Kestrel.Core;
 using Microsoft.Extensions.DependencyInjection.Extensions;
+using NPOI.POIFS.Crypt;
 using OASystem.API.Middlewares;
 using OASystem.API.OAMethodLib;
 using OASystem.API.OAMethodLib.AMapApi;
@@ -10,6 +12,7 @@ using OASystem.API.OAMethodLib.APNs;
 using OASystem.API.OAMethodLib.DeepSeekAPI;
 using OASystem.API.OAMethodLib.GenericSearch;
 using OASystem.API.OAMethodLib.Hub.Hubs;
+using OASystem.API.OAMethodLib.HunYuanAPI;
 using OASystem.API.OAMethodLib.JuHeAPI;
 using OASystem.API.OAMethodLib.QiYeWeChatAPI;
 using OASystem.API.OAMethodLib.Quartz.Jobs;
@@ -21,6 +24,9 @@ using Quartz.Spi;
 using QuzrtzJob.Factory;
 using Serilog.Events;
 using System.IO.Compression;
+using TencentCloud.Common;
+using TencentCloud.Common.Profile;
+using TencentCloud.Hunyuan.V20230901;
 using static OASystem.API.Middlewares.RateLimitMiddleware;
 
 Console.Title = $"FMGJ OASystem Server";
@@ -498,6 +504,48 @@ builder.Services.AddHttpClient("PublicQiYeWeChatApi", c => c.BaseAddress = new U
 
 #endregion
 
+#region 混元API
+
+// 从配置中读取腾讯云密钥信息(请确保appsettings.json中有对应配置)
+var secretId = builder.Configuration["TencentCloud:SecretId"];
+var secretKey = builder.Configuration["TencentCloud:SecretKey"];
+var region = builder.Configuration["TencentCloud:Region"] ?? "ap-guangzhou";
+
+// 配置HttpClientFactory(SDK内部会用到)
+builder.Services.AddHttpClient();
+
+// 注册腾讯云Hunyuan Client为Singleton(推荐)
+builder.Services.AddSingleton(provider =>
+{
+    Credential cred = new Credential
+    {
+        SecretId = secretId,
+        SecretKey = secretKey
+    };
+
+    ClientProfile clientProfile = new ClientProfile();
+    HttpProfile httpProfile = new HttpProfile
+    {
+        Endpoint = "hunyuan.tencentcloudapi.com"
+    };
+    clientProfile.HttpProfile = httpProfile;
+
+    return new HunyuanClient(cred, region, clientProfile);
+});
+
+// 注册自定义服务接口及其实现为Scoped生命周期
+builder.Services.AddScoped<IHunyuanService, HunyuanService>();
+
+// 注册混元服务
+//builder.Services.AddHttpClient<IHunyuanService, HunyuanService>(client =>
+//{
+//    client.BaseAddress = new Uri("https://hunyuan.ap-chengdu.tencentcloudapi.com/");
+//    client.Timeout = TimeSpan.FromSeconds(60);
+//});
+
+//builder.Services.Configure<HunyuanApiSettings>(builder.Configuration.GetSection("HunyuanApiSettings"));
+#endregion
+
 #region 有道API 服务
 //builder.Services.AddControllersWithViews();
 //builder.Services.AddSingleton<IYouDaoApiService, YouDaoApiService>();

+ 9 - 1
OASystem/OASystem.Api/appsettings.json

@@ -580,5 +580,13 @@
       //}
     ]
   },
-  "AllowedHosts": "*"
+  "AllowedHosts": "*",
+  // 混元API 配置
+  "TencentCloud": {
+    "SecretId": "AKIDISQCm9K9wYDsT8hMuIVXO2WouugFpMlF",
+    "SecretKey": "PfleOvELH3dz9g4OWWKwLYXIp9F7mDUY",
+    "AppId": 100015480940,
+    "Region": "ap-chengdu",
+    "Version": "2023-09-01"
+  }
 }