添加项目文件。

This commit is contained in:
youngq 2024-11-19 16:22:57 +08:00
parent e8e7f09210
commit 919c295b13
32 changed files with 1385 additions and 0 deletions

28
AI.Api.sln Normal file
View File

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35506.116
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AI.Api", "AI.Api\AI.Api.csproj", "{DC60489F-F76C-47FF-8698-5EF3454FA974}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AI.Common", "AI.Common\AI.Common.csproj", "{B5A93DD0-B38E-40D4-B6A3-40BA62A2FA2D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DC60489F-F76C-47FF-8698-5EF3454FA974}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DC60489F-F76C-47FF-8698-5EF3454FA974}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC60489F-F76C-47FF-8698-5EF3454FA974}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC60489F-F76C-47FF-8698-5EF3454FA974}.Release|Any CPU.Build.0 = Release|Any CPU
{B5A93DD0-B38E-40D4-B6A3-40BA62A2FA2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B5A93DD0-B38E-40D4-B6A3-40BA62A2FA2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B5A93DD0-B38E-40D4-B6A3-40BA62A2FA2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B5A93DD0-B38E-40D4-B6A3-40BA62A2FA2D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

19
AI.Api/AI.Api.csproj Normal file
View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.11" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AI.Common\AI.Common.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,26 @@
using AI.Common.Dtos;
using AI.Common.Services.Interface;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace AI.Api.Controllers
{
[Route("[controller]")]
public class AuthController : BaseController
{
private readonly IAuthService _authService;
public AuthController(IAuthService authService)
{
this._authService = authService;
}
[AllowAnonymous]
[HttpPost("login")]
public async Task<IActionResult> LoginAsync([FromBody] LoginDto loginDto)
{
return Ok(await _authService.LoginAsync(loginDto));
}
}
}

View File

@ -0,0 +1,25 @@
using AI.Common.Helpers;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
namespace AI.Api.Controllers
{
[ApiController]
[Authorize]
public class BaseController : ControllerBase
{
public long UId
{
get
{
var uid = HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
if (string.IsNullOrWhiteSpace(uid))
{
throw Oops.Oh("用户信息有误,请重新登录");
}
return long.Parse(uid);
}
}
}
}

View File

@ -0,0 +1,25 @@
using AI.Common.Dtos;
using AI.Common.Entities;
using AI.Common.Services.Interface;
using Mapster;
using Microsoft.AspNetCore.Mvc;
namespace AI.Api.Controllers
{
[Route("[controller]")]
public class PromptController : BaseController
{
private readonly IPromptService _promptService;
public PromptController(IPromptService promptService)
{
this._promptService = promptService;
}
[HttpGet("list")]
public async Task<List<PromptDto>> GetListAsync()
{
return await _promptService.GetListAsync();
}
}
}

View File

@ -0,0 +1,28 @@
using AI.Common.Dtos;
using AI.Common.Entities;
using AI.Common.Services.Interface;
using Mapster;
using Microsoft.AspNetCore.Mvc;
namespace AI.Api.Controllers
{
[Route("[controller]")]
public class QuestLogController : BaseController
{
private readonly IQuestionLogService _questionLogService;
public QuestLogController(IQuestionLogService questionLogService)
{
this._questionLogService = questionLogService;
}
[HttpGet("record")]
public async Task<long> RecordAsync([FromBody] QuestionLogDto questionLogDto)
{
var entity = questionLogDto.Adapt<QuestionLog>();
entity.Uid = UId;
return await _questionLogService.RecordAsync(entity);
}
}
}

71
AI.Api/Program.cs Normal file
View File

@ -0,0 +1,71 @@
using AI.Api.WebCore;
using AI.Common.Services;
using AI.Common.Services.Interface;
using SqlSugar;
using DbType = SqlSugar.DbType;
namespace AI.Api
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
var configuration = builder.Configuration;
// Add services to the container.
builder.Services.AddControllers(options =>
{
// 全局异常捕获,无需在代码中 写 try catch
options.Filters.Add<GlobalExceptionFilter>();
// 全局模型赋值默认值 和 统一返回格式处理
options.Filters.Add<ModelActionFilter>();
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton(new Common.Helpers.JwtHelper(configuration));
builder.Services.AddAuth(configuration["Jwt:Issuer"],
configuration["Jwt:Audience"],
configuration["Jwt:SecretKey"]);
builder.Services.AddSqlsugar(builder.Environment.EnvironmentName, new ConnectionConfig
{
DbType = DbType.MySql,
ConfigId = "walle",
ConnectionString = configuration.GetConnectionString("walle"),
IsAutoCloseConnection = true
},
new ConnectionConfig
{
DbType = DbType.MySql,
ConfigId = "usercenter",
ConnectionString = configuration.GetConnectionString("usercenter"),
IsAutoCloseConnection = true
});
builder.Services.AddScoped<IAuthService, AuthService>();
builder.Services.AddScoped<IQuestionLogService, QuestionLogService>();
builder.Services.AddScoped<IPromptService, PromptService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
//调用中间件UseAuthentication认证必须在所有需要身份认证的中间件前调用比如 UseAuthorization授权
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}

View File

@ -0,0 +1,23 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:29214",
"sslPort": 0
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5108",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,47 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
namespace AI.Api.WebCore
{
public static class AuthenticationServiceExtensions
{
/// <summary>
/// 添加认证和授权
/// </summary>
/// <param name="services">服务集合</param>
/// <returns></returns>
public static IServiceCollection AddAuth(this IServiceCollection services, string issuer, string audience, string secretKey)
{
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true, //是否验证Issuer
ValidIssuer = issuer, //发行人Issuer
ValidateAudience = true, //是否验证Audience
ValidAudience = audience, //订阅人Audience
ValidateIssuerSigningKey = true, //是否验证SecurityKey
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)), //SecurityKey
ValidateLifetime = true, //是否验证失效时间
ClockSkew = TimeSpan.FromSeconds(30), //过期时间容错值,解决服务器端时间不同步问题(秒)
RequireExpirationTime = true,
};
});
return services;
//services.AddAuthorization(options =>
//{
// options.AddPolicy(Constant.Policy.FreePolicyName,
// policy => policy.RequireClaim(Constant.Auth.PermissionsKey, Constant.Auth.FreeClaimValue, Constant.Auth.VipClaimValue));
// options.AddPolicy(Constant.Policy.VipPolicyName,
// policy => policy.RequireClaim(Constant.Auth.PermissionsKey, Constant.Auth.VipClaimValue));
//});
}
}
}

View File

@ -0,0 +1,66 @@
using AI.Common;
using Masuit.Tools;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace AI.Api.WebCore
{
/// <summary>
/// 全局异常捕获
/// </summary>
public class GlobalExceptionFilter : IAsyncExceptionFilter
{
private readonly ILogger<GlobalExceptionFilter> _logger;
public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)
{
_logger = logger; //在构造函数中注入日志处理实例
}
public async Task OnExceptionAsync(ExceptionContext context)
{
// 如果异常没有被处理则进行处理
if (context.ExceptionHandled == false)
{
// 定义返回类型
UniformResult<object> result;
// 如果为业务逻辑抛出的内部异常
if (context.Exception is FriendlyInternalException ex)
{
// 企业微信异常通知
//await ExceptionNotice.SendFriendlyExceptionAsync(ex);
result = UniformResult<object>
.Create(ex.FriendlyData, ex.ErrorCode, context.Exception.Message);
}
else
{
// 程序异常,不对外暴露程序异常细节
result = UniformResult<object>
.Create(null, 500, "程序出错啦🐞🐞🐞!");
//使用日志对象 _logger 的 LogError() 方法将异常信息写入日志文件
_logger.LogError(context.Exception, context.Exception.Message);
// 企业微信异常通知
await ExceptionNotice.SendAsync(context.Exception, "全局异常捕获");
}
context.Result = new ContentResult
{
// 返回状态码设置为200表示成功
StatusCode = StatusCodes.Status200OK,
// 设置返回格式
ContentType = "application/json;charset=utf-8",
Content = result.ToJsonString()
};
}
// 设置为true表示异常已经被处理了
context.ExceptionHandled = true;
}
}
}

View File

@ -0,0 +1,60 @@
using AI.Common;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace AI.Api.WebCore
{
public class ModelActionFilter : ActionFilterAttribute
{
/// <summary>
/// 在Controller的Action执行后执行
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuted(ActionExecutedContext context)
{
//特殊处理对有ApiResultIgnoreAttribute标签的不进行返回结果包装原样输出
//var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
//if (controllerActionDescriptor != null)
//{
// var isDefined = controllerActionDescriptor.EndpointMetadata.Any(a => a.GetType().Equals(typeof(ApiResultIgnoreAttribute)));
// if (isDefined)
// {
// return;
// }
//}
// 返回结果为JsonResult的请求进行Result包装
if (context.Result != null)
{
switch (context.Result)
{
case ObjectResult:
{
var result = context.Result as ObjectResult;
context.Result = new JsonResult(UniformResult<object>.Create(result.Value));
break;
}
case EmptyResult:
context.Result = new JsonResult(UniformResult<object>.Create(null));
break;
case ContentResult:
{
var result = context.Result as ContentResult;
context.Result = new JsonResult(UniformResult<object>.Create(result.Content));
break;
}
}
}
base.OnActionExecuted(context);
}
/// <summary>
/// 在Controller的Action执行前执行
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
}
}
}

View File

@ -0,0 +1,58 @@
using SqlSugar;
using System.Text.RegularExpressions;
namespace AI.Api.WebCore
{
public static class SqlsugarServiceExtensions
{
/// <summary>
/// 添加SqlSugar
/// </summary>
/// <param name="services">服务集合</param>
/// <returns></returns>
public static IServiceCollection AddSqlsugar(this IServiceCollection services, string env, params ConnectionConfig[] connectionConfigs)
{
SqlSugarScope sqlSugar = new SqlSugarScope(connectionConfigs.ToList(),
db =>
{
if (env == Environments.Development)
{
// 正则表达式匹配Ip
var ipMatch = Regex.Match(db.CurrentConnectionConfig.ConnectionString, @"((25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))");
var connections = db.CurrentConnectionConfig.ConnectionString.Split(';');
string dbNamne = string.Empty;
foreach (var item in connections)
{
if (item.Contains("Database"))
{
dbNamne = item.Split('=')[1];
}
}
//SQL执行前
db.Aop.OnLogExecuting = (sql, pars) =>
{
// 打印 Sql 语句
Console.WriteLine($@"{DateTime.Now.ToShortTimeString()}{new string('=', 10)}BEGIN{new string('=', 5)} DB-IP{ipMatch.Value} {new string('=', 5)} DB-Name:{dbNamne} {new string('=', 15)}");
Console.WriteLine($"执行Sql:{Environment.NewLine}{sql}");
Console.WriteLine($"参数:{db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))}");
};
//SQL执行完成
db.Aop.OnLogExecuted = (sql, pars) =>
{
//执行完了可以输出SQL执行时间
Console.WriteLine("Sql用时:" + db.Ado.SqlExecutionTime.ToString());
Console.WriteLine($@"{DateTime.Now.ToShortTimeString()}{new string('=', 10)}END{new string('=', 7)} DB-IP{ipMatch.Value} {new string('=', 5)} DB-Name:{dbNamne} {new string('=', 15)}");
};
}
});
services.AddSingleton<ISqlSugarClient>(sqlSugar);
StaticConfig.Check_StringIdentity = false;
return services;
}
}
}

View File

@ -0,0 +1,26 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft.AspNetCore": "Information"
},
"Console": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Information",
"Hangfire": "Information"
}
}
},
"ConnectionStrings": {
"walle": "Database=walle;Server=192.168.2.9;Port=3306;Uid=root;Pwd=qwe123!@#;AllowZeroDateTime=True;ConvertZeroDateTime=True;",
"usercenter": "Database=usercenter;Server=192.168.2.9;Port=3306;Uid=root;Pwd=qwe123!@#;AllowZeroDateTime=True;ConvertZeroDateTime=True;"
},
"Jwt": {
"SecretKey": "apDbztyqjSNuvWnezhbdUxduhDidZbF897t2uTJs53RMdY9Cai7eexavBhka3HN6mcTe9oohjFg6bNffRRkcfMqnVKNBnmyPzkRgNopHGJAL7KMwkeZdZ7BaWnT57jCi",
"Issuer": "AI.Api",
"Audience": "AIClient",
//
"Expires": 108000
}
}

9
AI.Api/appsettings.json Normal file
View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mapster" Version="7.4.0" />
<PackageReference Include="Masuit.Tools.Core" Version="2024.6.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.11" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.170" />
</ItemGroup>
<ItemGroup>
<Folder Include="Entities\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AI.Common.Dtos
{
public class LoginDto
{
public string Account { get; set; }
public string Password { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AI.Common.Dtos
{
public class PromptDto
{
public long Id { get; set; }
public string Name { get; set; }
public string Prompt { get; set; }
public DateTime CreateTime { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AI.Common.Dtos
{
public class QuestionLogDto
{
public long Id { get; set; }
public string QuestionContent { get; set; }
public string? GptAnswer { get; set; }
}
}

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SqlSugar;
namespace AI.Common.Entities
{
/// <summary>
///
///</summary>
[SugarTable("prompts")]
public class Prompts
{
/// <summary>
/// 备 注:
/// 默认值:
///</summary>
[SugarColumn(ColumnName="id" ,IsPrimaryKey = true,IsIdentity = true) ]
public long Id { get; set; }
/// <summary>
/// 备 注:角色名称
/// 默认值:
///</summary>
[SugarColumn(ColumnName="name" ) ]
public string Name { get; set; } = null!;
/// <summary>
/// 备 注:提示词
/// 默认值:
///</summary>
[SugarColumn(ColumnName="prompt" ) ]
public string Prompt { get; set; } = null!;
/// <summary>
/// 备 注:
/// 默认值:
///</summary>
[SugarColumn(ColumnName="create_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true) ]
public DateTime CreateTime { get; set; }
/// <summary>
/// 备 注:
/// 默认值:
///</summary>
[SugarColumn(ColumnName="is_delete" ) ]
public bool IsDelete { get; set; }
}
}

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SqlSugar;
namespace AI.Common.Entities
{
/// <summary>
///
///</summary>
[SugarTable("question_log")]
public class QuestionLog
{
/// <summary>
/// 备 注:
/// 默认值:
///</summary>
[SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsIdentity = true)]
public long Id { get; set; }
/// <summary>
/// 备 注:
/// 默认值:
///</summary>
[SugarColumn(ColumnName = "create_time", IsOnlyIgnoreInsert = true, IsOnlyIgnoreUpdate = true)]
public DateTime Create_time { get; set; }
/// <summary>
/// 备 注:
/// 默认值:
///</summary>
[SugarColumn(ColumnName = "uid")]
public long Uid { get; set; }
/// <summary>
/// 备 注:问题内容
/// 默认值:
///</summary>
[SugarColumn(ColumnName = "question_content")]
public string? QuestionContent { get; set; }
/// <summary>
/// 备 注:
/// 默认值:
///</summary>
[SugarColumn(ColumnName = "gpt_answer")]
public string? GptAnswer { get; set; }
}
}

298
AI.Common/Entities/User.cs Normal file
View File

@ -0,0 +1,298 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SqlSugar;
namespace AI.Common.Entities
{
/// <summary>
/// 用户表【学生,教师,校职工】
///</summary>
[SugarTable("user")]
public class User
{
/// <summary>
/// 备 注:
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Id" ,IsPrimaryKey = true) ]
public long Id { get; set; }
/// <summary>
/// 备 注:模板id
/// 默认值:
///</summary>
[SugarColumn(ColumnName="TemplateId" ) ]
public long TemplateId { get; set; }
/// <summary>
/// 备 注:学校Id
/// 默认值:
///</summary>
[SugarColumn(ColumnName="SchoolId" ) ]
public long? SchoolId { get; set; }
/// <summary>
/// 备 注:用户类型 1学生 2领导
/// 默认值:
///</summary>
[SugarColumn(ColumnName="UserType" ) ]
public int UserType { get; set; }
/// <summary>
/// 备 注:账号
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Account" ) ]
public string Account { get; set; } = null!;
/// <summary>
/// 备 注:学号/考号
/// 默认值:
///</summary>
[SugarColumn(ColumnName="StudentId" ) ]
public string StudentId { get; set; } = null!;
/// <summary>
/// 备 注:身份证号 18位数长度限制
/// 默认值:
///</summary>
[SugarColumn(ColumnName="IdCard" ) ]
public string? IdCard { get; set; }
/// <summary>
/// 备 注:密码
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Password" ) ]
public string Password { get; set; } = null!;
/// <summary>
/// 备 注:姓名
/// 默认值:
///</summary>
[SugarColumn(ColumnName="RealName" ) ]
public string RealName { get; set; } = null!;
/// <summary>
/// 备 注:性别 0=男 1=女
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Sex" ) ]
public int Sex { get; set; }
/// <summary>
/// 备 注:出生日期
/// 默认值:
///</summary>
[SugarColumn(ColumnName="BirthDate" ) ]
public DateTime BirthDate { get; set; }
/// <summary>
/// 备 注:家庭户口
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Residence" ) ]
public string Residence { get; set; } = null!;
/// <summary>
/// 备 注:民族
/// 默认值:
///</summary>
[SugarColumn(ColumnName="National" ) ]
public string National { get; set; } = null!;
/// <summary>
/// 备 注:头像
/// 默认值:
///</summary>
[SugarColumn(ColumnName="HeadImage" ) ]
public string HeadImage { get; set; } = null!;
/// <summary>
/// 备 注:省Id
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Pid" ) ]
public int Pid { get; set; }
/// <summary>
/// 备 注:
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Pname" ) ]
public string Pname { get; set; } = null!;
/// <summary>
/// 备 注:市Id
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Cid" ) ]
public int Cid { get; set; }
/// <summary>
/// 备 注:
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Cname" ) ]
public string Cname { get; set; } = null!;
/// <summary>
/// 备 注:区Id
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Rid" ) ]
public int Rid { get; set; }
/// <summary>
/// 备 注:
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Rname" ) ]
public string Rname { get; set; } = null!;
/// <summary>
/// 备 注:微信号
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Wx" ) ]
public string Wx { get; set; } = null!;
/// <summary>
/// 备 注:是否完善信息 0:否 1:是
/// 默认值:
///</summary>
[SugarColumn(ColumnName="IsPerfectInfo" ) ]
public int IsPerfectInfo { get; set; }
/// <summary>
/// 备 注:账户状态 0禁用 1正常
/// 默认值:
///</summary>
[SugarColumn(ColumnName="State" ) ]
public int State { get; set; }
/// <summary>
/// 备 注:直播平台编号
/// 默认值:
///</summary>
[SugarColumn(ColumnName="LiveId" ) ]
public long LiveId { get; set; }
/// <summary>
/// 备 注:上次登录时间
/// 默认值:
///</summary>
[SugarColumn(ColumnName="LastLoginTime" ) ]
public DateTime LastLoginTime { get; set; }
/// <summary>
/// 备 注:登录IP
/// 默认值:
///</summary>
[SugarColumn(ColumnName="LastLoginIP" ) ]
public string LastLoginIP { get; set; } = null!;
/// <summary>
/// 备 注:添加时间
/// 默认值:
///</summary>
[SugarColumn(ColumnName="CreateTime" ) ]
public DateTime CreateTime { get; set; }
/// <summary>
/// 备 注:层次
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Level" ) ]
public int Level { get; set; }
/// <summary>
/// 备 注:会议系统账号
/// 默认值:
///</summary>
[SugarColumn(ColumnName="MeetingAccount" ) ]
public string? MeetingAccount { get; set; }
/// <summary>
/// 备 注:新高考物理化学选科
/// 默认值:
///</summary>
[SugarColumn(ColumnName="GLSubject" ) ]
public int? GLSubject { get; set; }
/// <summary>
/// 备 注:新高考政地化生选科1
/// 默认值:
///</summary>
[SugarColumn(ColumnName="GSubject1" ) ]
public int? GSubject1 { get; set; }
/// <summary>
/// 备 注:新高考政地化生选科2
/// 默认值:
///</summary>
[SugarColumn(ColumnName="GSubject2" ) ]
public int? GSubject2 { get; set; }
/// <summary>
/// 备 注:第三方id
/// 默认值:
///</summary>
[SugarColumn(ColumnName="ThirdPartyId" ) ]
public string? ThirdPartyId { get; set; }
/// <summary>
/// 备 注:电话号码
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Phone" ) ]
public string? Phone { get; set; }
/// <summary>
/// 备 注:点阵笔SN
/// 默认值:
///</summary>
[SugarColumn(ColumnName="PointPenSN" ) ]
public string? PointPenSN { get; set; }
/// <summary>
/// 备 注:删除状态
/// 默认值:
///</summary>
[SugarColumn(ColumnName="DeleteState" ) ]
public SByte DeleteState { get; set; }
/// <summary>
/// 备 注:互动课堂创建人Id
/// 默认值:
///</summary>
[SugarColumn(ColumnName="HdktCreatorId" ) ]
public long? HdktCreatorId { get; set; }
/// <summary>
/// 备 注:用户来源
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Source" ) ]
public int Source { get; set; }
/// <summary>
/// 备 注:点阵笔MAC
/// 默认值:
///</summary>
[SugarColumn(ColumnName="PointPenMAC" ) ]
public string? PointPenMAC { get; set; }
/// <summary>
/// 备 注:创建人名称
/// 默认值:
///</summary>
[SugarColumn(ColumnName="Creator" ) ]
public string? Creator { get; set; }
}
}

View File

@ -0,0 +1,44 @@
using System.Net.Http.Json;
namespace AI.Common
{
/// <summary>
/// 异常通知
/// </summary>
public class ExceptionNotice
{
private static HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri("https://oapi.dingtalk.com/robot/send?access_token=0ba23267d03084010ee5ffae60e6f4a11e541db8e062f5cde75f3205c10c42c8"),
};
/// <summary>
/// 发送异常信息
/// </summary>
/// <param name="exp">异常</param>
/// <param name="expSrc">异常来源(用于显示)</param>
/// <returns></returns>
public static async Task<bool> SendAsync(Exception exp, string expSrc)
{
#if DEBUG
Console.WriteLine("*************** Excpetion ***************");
Console.WriteLine(exp.Message, exp);
Console.WriteLine("*************** Excpetion ***************");
return true;
#endif
var reponse = await httpClient.PostAsync(string.Empty, JsonContent.Create(new
{
msgtype = "markdown",
markdown = new
{
title = "AI.Api异常",
text = $"AI.Api异常.描述:{exp.Message}\n详情:{exp}"
},
}));
return reponse.IsSuccessStatusCode;
}
}
}

View File

@ -0,0 +1,17 @@
namespace AI.Common
{
/// <summary>
/// Api内部错误错误细节不暴露给外部
/// </summary>
public class FriendlyInternalException : Exception
{
public int ErrorCode { get; private set; }
public object FriendlyData { get; private set; }
public FriendlyInternalException(string message, object friendlyData = null, int errorCode = 1000) : base(message)
{
ErrorCode = errorCode;
FriendlyData = friendlyData;
}
}
}

View File

@ -0,0 +1,54 @@
using Masuit.Tools;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace AI.Common.Helpers
{
public class JwtHelper
{
private readonly IConfiguration _configuration;
public JwtHelper(IConfiguration configuration)
{
_configuration = configuration;
}
public string CreateToken(string uid, List<Claim> claims = null)
{
if (claims.IsNullOrEmpty())
claims = new();
claims.AddRange(new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, uid),
});
// 2. 从 appsettings.json 中读取SecretKey
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"]));
// 3. 选择加密算法
var algorithm = SecurityAlgorithms.HmacSha256;
// 4. 生成Credentials
var signingCredentials = new SigningCredentials(secretKey, algorithm);
// 5. 根据以上生成token
var jwtSecurityToken = new JwtSecurityToken(
_configuration["Jwt:Issuer"], //Issuer
_configuration["Jwt:Audience"], //Audience
claims, //Claims,
DateTime.Now, //notBefore
DateTime.Now.AddSeconds(_configuration["Jwt:Expires"].ToDouble()), //expires
signingCredentials //Credentials
);
// 6. 将token变为string
var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
return token;
}
}
}

68
AI.Common/Helpers/Oops.cs Normal file
View File

@ -0,0 +1,68 @@
namespace AI.Common.Helpers
{
/// <summary>
/// 异常抛出帮助类
/// </summary>
public static class Oops
{
public static FriendlyInternalException Oh(string message)
{
return new FriendlyInternalException(message);
}
/// <summary>
/// 删除失败异常
/// </summary>
/// <returns></returns>
public static FriendlyInternalException OhDeleteFailed()
{
return new FriendlyInternalException("删除失败!");
}
/// <summary>
/// 数据不存在异常
/// </summary>
/// <returns></returns>
public static FriendlyInternalException OhDataNotExists()
{
return new FriendlyInternalException("数据不存在!");
}
/// <summary>
/// 更新失败异常
/// </summary>
/// <returns></returns>
public static FriendlyInternalException OhUpdateFailed()
{
return new FriendlyInternalException("更新失败!");
}
/// <summary>
/// 新增失败异常
/// </summary>
/// <returns></returns>
public static FriendlyInternalException OhAddFailed()
{
return new FriendlyInternalException("新增失败!");
}
/// <summary>
/// 业务处理失败自定义消息
/// </summary>
/// <returns></returns>
public static FriendlyInternalException OhBusinessFailed(string msg, object data)
{
return new FriendlyInternalException(msg, data, 200);
}
/// <summary>
/// 操作失败
/// </summary>
/// <returns></returns>
public static FriendlyInternalException OperationFailed()
{
return new FriendlyInternalException("操作失败!");
}
}
}

View File

@ -0,0 +1,50 @@
using AI.Common.Dtos;
using AI.Common.Entities;
using AI.Common.Helpers;
using AI.Common.Services.Interface;
using Masuit.Tools;
using Microsoft.Extensions.Configuration;
using SqlSugar;
using System.Security.Claims;
namespace AI.Common.Services
{
public class AuthService : IAuthService
{
private readonly ISqlSugarClient _sqlSugarClient;
private readonly JwtHelper _jwtHelper;
private readonly IConfiguration _configuration;
public AuthService(ISqlSugarClient sqlSugarClient, JwtHelper jwtHelper, IConfiguration configuration)
{
this._sqlSugarClient = sqlSugarClient.AsTenant().GetConnection("usercenter");
this._jwtHelper = jwtHelper;
this._configuration = configuration;
}
public async Task<object> LoginAsync(LoginDto loginDto)
{
var user = await _sqlSugarClient.Queryable<User>()
.FirstAsync(x => x.Account == loginDto.Account && x.Password == loginDto.Password && x.DeleteState == 0);
if (user == null)
{
throw Oops.Oh("登录失败,账号或密码错误!");
}
var accessToken = _jwtHelper.CreateToken(user.Id.ToString(), new List<Claim>
{
new Claim("account",user.Account),
new Claim(ClaimTypes.Name,user.RealName),
});
return new
{
token = accessToken,
userName = user.RealName,
account = user.Account,
expire = _configuration["Jwt:Expires"].ToInt32(),
};
}
}
}

View File

@ -0,0 +1,14 @@
using AI.Common.Dtos;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AI.Common.Services.Interface
{
public interface IAuthService
{
Task<object> LoginAsync(LoginDto loginDto);
}
}

View File

@ -0,0 +1,18 @@
using AI.Common.Dtos;
using AI.Common.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AI.Common.Services.Interface
{
public interface IPromptService
{
Task AddAsync(Prompts prompts);
Task DeleteAsync(long id);
Task<List<PromptDto>> GetListAsync();
Task UpdateAsync(Prompts prompts);
}
}

View File

@ -0,0 +1,14 @@
using AI.Common.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AI.Common.Services.Interface
{
public interface IQuestionLogService
{
Task<long> RecordAsync(QuestionLog questionLog);
}
}

View File

@ -0,0 +1,49 @@
using AI.Common.Dtos;
using AI.Common.Entities;
using AI.Common.Services.Interface;
using Mapster;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AI.Common.Services
{
public class PromptService : IPromptService
{
private readonly ISqlSugarClient _sqlSugarClient;
public PromptService(ISqlSugarClient sqlSugarClient)
{
this._sqlSugarClient = sqlSugarClient;
}
public async Task<List<PromptDto>> GetListAsync()
{
var entities = await _sqlSugarClient.Queryable<Prompts>().ToListAsync();
return entities.Adapt<List<PromptDto>>();
}
public async Task AddAsync(Prompts prompts)
{
await _sqlSugarClient.Insertable(prompts).ExecuteCommandAsync();
}
public async Task UpdateAsync(Prompts prompts)
{
await _sqlSugarClient.Updateable(prompts)
.UpdateColumns(x => new { x.Name, x.Prompt })
.ExecuteCommandHasChangeAsync();
}
public async Task DeleteAsync(long id)
{
await _sqlSugarClient.Updateable<Prompts>()
.SetColumns(x => x.IsDelete == true)
.Where(x => x.Id == id).ExecuteCommandAsync();
}
}
}

View File

@ -0,0 +1,38 @@
using AI.Common.Dtos;
using AI.Common.Entities;
using AI.Common.Services.Interface;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AI.Common.Services
{
public class QuestionLogService : IQuestionLogService
{
private readonly ISqlSugarClient _sqlSugarClient;
public QuestionLogService(ISqlSugarClient sqlSugarClient)
{
this._sqlSugarClient = sqlSugarClient;
}
public async Task<long> RecordAsync(QuestionLog questionLog)
{
if (questionLog.Id <= 0)
{
// 新增
return await _sqlSugarClient.Insertable(questionLog).ExecuteReturnBigIdentityAsync();
}
// 更新
await _sqlSugarClient.Updateable(questionLog)
.UpdateColumns(x => new { x.QuestionContent, x.GptAnswer }).ExecuteCommandAsync();
return questionLog.Id;
}
}
}

View File

@ -0,0 +1,39 @@
namespace AI.Common
{
/// <summary>
/// 统一返回结果模型
/// </summary>
/// <typeparam name="T"></typeparam>
public class UniformResult<T>
{
public UniformResult(T data, int code = 200, string msg = "success")
{
this.data = data;
this.code = code;
message = msg;
}
/// <summary>
/// 消息
/// </summary>
public string message { get; set; } = "success";
/// <summary>
/// 返回代码
/// </summary>
public int code { get; set; }
/// <summary>
/// 数据
/// </summary>
public T data { get; set; }
public static UniformResult<T> Create(T data, int code = 200, string msg = "success")
{
return new UniformResult<T>(data, code, msg);
}
}
}