Upgrade to version 1.4.1.1 with .NET 8.0 support
- Updated application version from 1.3.2.1 to 1.4.1.1. - Dockerfile now uses .NET 8.0 for runtime and SDK. - Added new API endpoints in HospitalController for sections by hospital ID. - Modified UniversityController to retrieve hospitals instead of sections. - Enhanced DocuMed.Api.csproj with new using directives for commands and queries. - Updated AccountService and UserService to handle hospital IDs and sections. - Introduced HospitalId and ProfileType properties in various DTOs. - Updated RestApiWrapper to include new REST API interfaces for hospitals and AI. - Enhanced MedicalHistoryTemplate components with AI interaction features. - Modified CSS files to include new styles and animations. - Introduced new classes and interfaces for AI interactions, including AiController and MetisMessage. - Updated ProfilePage to support hospital selection and related logic. - Revised API endpoints for hospitals and universities for improved data management.master
parent
ab56bf3c20
commit
3fb22c8c48
|
@ -1,9 +1,9 @@
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||||
ENV ASPNETCORE_URLS=http://0.0.0.0:8010
|
ENV ASPNETCORE_URLS=http://0.0.0.0:8010
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 8010
|
EXPOSE 8010
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY ["DocuMed.Api/DocuMed.Api.csproj", "DocuMed.Api/"]
|
COPY ["DocuMed.Api/DocuMed.Api.csproj", "DocuMed.Api/"]
|
||||||
RUN dotnet restore "DocuMed.Api/DocuMed.Api.csproj"
|
RUN dotnet restore "DocuMed.Api/DocuMed.Api.csproj"
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
namespace DocuMed.Api.Controllers;
|
||||||
|
|
||||||
|
public class AiController : ICarterModule
|
||||||
|
{
|
||||||
|
public void AddRoutes(IEndpointRouteBuilder app)
|
||||||
|
{
|
||||||
|
var group = app.NewVersionedApi("Ai").MapGroup("api/ai");
|
||||||
|
group.MapPost("chat", ChatAsync)
|
||||||
|
.WithDisplayName("AiChatBot")
|
||||||
|
.HasApiVersion(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IResult> ChatAsync([FromBody] MetisMessage message, [FromServices] IRestApiWrapper apiWrapper, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var messageRequest = new MetisMessageRequest
|
||||||
|
{
|
||||||
|
message = new MetisMessage
|
||||||
|
{
|
||||||
|
content = message.content
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var response = await apiWrapper.MetisRestApi.SendMessage("7324c5a0-5cad-4239-a8d9-38d99d490493", messageRequest, "tpsg-epC8BoLfa7uSL4ogjlocFLKiW7Un66e");
|
||||||
|
return TypedResults.Ok(response.Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,8 +1,4 @@
|
||||||
using DocuMed.Domain.CommandQueries.Commands;
|
namespace DocuMed.Api.Controllers;
|
||||||
using DocuMed.Domain.Entities.MedicalHistory;
|
|
||||||
using MediatR;
|
|
||||||
|
|
||||||
namespace DocuMed.Api.Controllers;
|
|
||||||
|
|
||||||
public class HospitalController : ICarterModule
|
public class HospitalController : ICarterModule
|
||||||
{
|
{
|
||||||
|
@ -12,6 +8,9 @@ public class HospitalController : ICarterModule
|
||||||
.MapGroup("api/hospital")
|
.MapGroup("api/hospital")
|
||||||
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser());
|
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser());
|
||||||
|
|
||||||
|
group.MapGet("{id}/section", GetSectionsAsync)
|
||||||
|
.WithDisplayName("Get All Sections")
|
||||||
|
.HasApiVersion(1.0);
|
||||||
|
|
||||||
group.MapGet("", GetAllAsync)
|
group.MapGet("", GetAllAsync)
|
||||||
.WithDisplayName("GetAll")
|
.WithDisplayName("GetAll")
|
||||||
|
@ -31,37 +30,31 @@ public class HospitalController : ICarterModule
|
||||||
.HasApiVersion(1.0);
|
.HasApiVersion(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET:Get All Entity
|
// GET:Get All Sections
|
||||||
private async Task<IResult> GetAllAsync([FromQuery] int page, IMedicalHistoryRepository repository, CancellationToken cancellationToken)
|
public virtual async Task<IResult> GetSectionsAsync(Guid id, IRepositoryWrapper repositoryWrapper, ICurrentUserService currentUserService, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return TypedResults.Ok(await repository.GetMedicalHistoriesAsync(page, cancellationToken));
|
return TypedResults.Ok(await repositoryWrapper.SetRepository<Section>().TableNoTracking
|
||||||
|
.Where(s => s.HospitalId == id)
|
||||||
|
.Select(SectionMapper.ProjectToSDto).ToListAsync(cancellationToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GET:Get All Entity
|
||||||
|
private async Task<IResult> GetAllAsync([FromQuery] int page, IMediator mediator, CancellationToken cancellationToken)
|
||||||
|
=> TypedResults.Ok(await mediator.Send(new GetHospitalsQuery(page), cancellationToken));
|
||||||
|
|
||||||
// GET:Get An Entity By Id
|
// GET:Get An Entity By Id
|
||||||
private async Task<IResult> GetAsync(Guid id, IMedicalHistoryRepository repository, CancellationToken cancellationToken)
|
private async Task<IResult> GetAsync(Guid id, IMediator mediator, CancellationToken cancellationToken)
|
||||||
{
|
=> TypedResults.Ok(await mediator.Send(new GetHospitalQuery(id), cancellationToken));
|
||||||
|
|
||||||
return TypedResults.Ok(await repository.GetMedicalHistoryAsync(id, cancellationToken));
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST:Add New Entity
|
// POST:Add New Entity
|
||||||
private async Task<IResult> Post([FromBody] CreateHospitalCommand dto, IMediator service, ICurrentUserService currentUserService, CancellationToken cancellationToken)
|
private async Task<IResult> Post([FromBody] CreateHospitalCommand dto, IMediator service, ICurrentUserService currentUserService, CancellationToken cancellationToken)
|
||||||
{
|
=> TypedResults.Ok(await service.Send(dto, cancellationToken));
|
||||||
return TypedResults.Ok(await service.Send(dto,cancellationToken));
|
|
||||||
}
|
|
||||||
|
|
||||||
// PUT:Update Entity
|
// PUT:Update Entity
|
||||||
private async Task<IResult> Put([FromBody] UpdateHospitalCommand dto, IMediator service, ICurrentUserService currentUserService, CancellationToken cancellationToken)
|
private async Task<IResult> Put([FromBody] UpdateHospitalCommand dto, IMediator service, ICurrentUserService currentUserService, CancellationToken cancellationToken)
|
||||||
{
|
=> TypedResults.Ok(await service.Send(dto, cancellationToken));
|
||||||
return TypedResults.Ok(await service.Send(dto,cancellationToken));
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE:Delete Entity
|
// DELETE:Delete Entity
|
||||||
private async Task<IResult> Delete(Guid id, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
private async Task<IResult> Delete(Guid id, IMediator mediator, CancellationToken cancellationToken)
|
||||||
{
|
=> TypedResults.Ok(await mediator.Send(new DeleteHospitalCommand(id), cancellationToken));
|
||||||
var ent = await repositoryWrapper.SetRepository<MedicalHistory>().GetByIdAsync(cancellationToken, id);
|
|
||||||
repositoryWrapper.SetRepository<MedicalHistory>().Delete(ent);
|
|
||||||
await repositoryWrapper.SaveChangesAsync(cancellationToken);
|
|
||||||
return TypedResults.Ok();
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@ public class UniversityController : ICarterModule
|
||||||
.WithDisplayName("Get All")
|
.WithDisplayName("Get All")
|
||||||
.HasApiVersion(1.0);
|
.HasApiVersion(1.0);
|
||||||
|
|
||||||
group.MapGet("{id}/section", GetAllByUniversityAsync)
|
group.MapGet("{id}/hospital", GetHospitalsAsync)
|
||||||
.WithDisplayName("Get All Sections")
|
.WithDisplayName("Get All Sections")
|
||||||
.HasApiVersion(1.0);
|
.HasApiVersion(1.0);
|
||||||
|
|
||||||
|
@ -34,25 +34,25 @@ public class UniversityController : ICarterModule
|
||||||
|
|
||||||
|
|
||||||
// GET:Get All Sections
|
// GET:Get All Sections
|
||||||
public virtual async Task<IResult> GetAllByUniversityAsync(Guid id, IRepositoryWrapper repositoryWrapper, ICurrentUserService currentUserService, CancellationToken cancellationToken)
|
private async Task<IResult> GetHospitalsAsync(Guid id, IRepositoryWrapper repositoryWrapper, ICurrentUserService currentUserService, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return TypedResults.Ok(await repositoryWrapper.SetRepository<Section>().TableNoTracking
|
return TypedResults.Ok(await repositoryWrapper.SetRepository<Hospital>().TableNoTracking
|
||||||
.Where(s => s.HospitalId == id)
|
.Where(s => s.UniversityId == id)
|
||||||
.Select(SectionMapper.ProjectToSDto).ToListAsync(cancellationToken));
|
.Select(HospitalMapper.ProjectToSDto).ToListAsync(cancellationToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET:Get All Entity
|
// GET:Get All Entity
|
||||||
public virtual async Task<IResult> GetAllAsync([FromQuery] int page, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
private async Task<IResult> GetAllAsync([FromQuery] int page, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||||
=> TypedResults.Ok(await repositoryWrapper.SetRepository<University>()
|
=> TypedResults.Ok(await repositoryWrapper.SetRepository<University>()
|
||||||
.TableNoTracking
|
.TableNoTracking
|
||||||
.Select(UniversityMapper.ProjectToSDto).ToListAsync(cancellationToken));
|
.Select(UniversityMapper.ProjectToSDto).ToListAsync(cancellationToken));
|
||||||
|
|
||||||
// GET:Get An Entity By Id
|
// GET:Get An Entity By Id
|
||||||
public async Task<IResult> GetAsync(int id, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
private async Task<IResult> GetAsync(int id, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||||
=> TypedResults.Ok(await repositoryWrapper.SetRepository<University>().GetByIdAsync(cancellationToken, id));
|
=> TypedResults.Ok(await repositoryWrapper.SetRepository<University>().GetByIdAsync(cancellationToken, id));
|
||||||
|
|
||||||
// POST:Add New Entity
|
// POST:Add New Entity
|
||||||
public virtual async Task<IResult> Post([FromBody] UniversitySDto dto, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
private async Task<IResult> Post([FromBody] UniversitySDto dto, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var ent = University.Create(dto.Name,dto.Address,dto.CityId);
|
var ent = University.Create(dto.Name,dto.Address,dto.CityId);
|
||||||
repositoryWrapper.SetRepository<University>().Add(ent);
|
repositoryWrapper.SetRepository<University>().Add(ent);
|
||||||
|
@ -61,7 +61,7 @@ public class UniversityController : ICarterModule
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT:Update Entity
|
// PUT:Update Entity
|
||||||
public virtual async Task<IResult> Put([FromBody] UniversitySDto dto, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
private async Task<IResult> Put([FromBody] UniversitySDto dto, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var ent = University.Create(dto.Name,dto.Address,dto.CityId);
|
var ent = University.Create(dto.Name,dto.Address,dto.CityId);
|
||||||
ent.Id = dto.Id;
|
ent.Id = dto.Id;
|
||||||
|
@ -71,7 +71,7 @@ public class UniversityController : ICarterModule
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE:Delete Entity
|
// DELETE:Delete Entity
|
||||||
public virtual async Task<IResult> Delete(int id, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
private async Task<IResult> Delete(int id, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var ent = await repositoryWrapper.SetRepository<University>().GetByIdAsync(cancellationToken, id);
|
var ent = await repositoryWrapper.SetRepository<University>().GetByIdAsync(cancellationToken, id);
|
||||||
repositoryWrapper.SetRepository<University>().Delete(ent);
|
repositoryWrapper.SetRepository<University>().Delete(ent);
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
<DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
|
<DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||||
<AssemblyVersion>1.3.2.1</AssemblyVersion>
|
<AssemblyVersion>1.4.1.1</AssemblyVersion>
|
||||||
<FileVersion>1.3.2.1</FileVersion>
|
<FileVersion>1.4.1.1</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -74,10 +74,13 @@
|
||||||
<Using Include="DocuMed.Core.EntityServices.Abstracts" />
|
<Using Include="DocuMed.Core.EntityServices.Abstracts" />
|
||||||
<Using Include="DocuMed.Core.Models.Api" />
|
<Using Include="DocuMed.Core.Models.Api" />
|
||||||
<Using Include="DocuMed.Domain" />
|
<Using Include="DocuMed.Domain" />
|
||||||
|
<Using Include="DocuMed.Domain.CommandQueries.Commands" />
|
||||||
|
<Using Include="DocuMed.Domain.CommandQueries.Queries" />
|
||||||
<Using Include="DocuMed.Domain.Dtos.LargDtos" />
|
<Using Include="DocuMed.Domain.Dtos.LargDtos" />
|
||||||
<Using Include="DocuMed.Domain.Dtos.RequestDtos" />
|
<Using Include="DocuMed.Domain.Dtos.RequestDtos" />
|
||||||
<Using Include="DocuMed.Domain.Dtos.SmallDtos" />
|
<Using Include="DocuMed.Domain.Dtos.SmallDtos" />
|
||||||
<Using Include="DocuMed.Domain.Entities.City" />
|
<Using Include="DocuMed.Domain.Entities.City" />
|
||||||
|
<Using Include="DocuMed.Domain.Entities.Hospitals" />
|
||||||
<Using Include="DocuMed.Domain.Entities.MedicalHistoryTemplate" />
|
<Using Include="DocuMed.Domain.Entities.MedicalHistoryTemplate" />
|
||||||
<Using Include="DocuMed.Domain.Entities.User" />
|
<Using Include="DocuMed.Domain.Entities.User" />
|
||||||
<Using Include="DocuMed.Domain.Enums.QueryFilters" />
|
<Using Include="DocuMed.Domain.Enums.QueryFilters" />
|
||||||
|
@ -85,12 +88,15 @@
|
||||||
<Using Include="DocuMed.Domain.Models.Settings" />
|
<Using Include="DocuMed.Domain.Models.Settings" />
|
||||||
<Using Include="DocuMed.Infrastructure" />
|
<Using Include="DocuMed.Infrastructure" />
|
||||||
<Using Include="DocuMed.Infrastructure.Models" />
|
<Using Include="DocuMed.Infrastructure.Models" />
|
||||||
|
<Using Include="DocuMed.Infrastructure.Models.Metis" />
|
||||||
|
<Using Include="DocuMed.Infrastructure.RestServices" />
|
||||||
<Using Include="DocuMed.Repository" />
|
<Using Include="DocuMed.Repository" />
|
||||||
<Using Include="DocuMed.Repository.Abstracts" />
|
<Using Include="DocuMed.Repository.Abstracts" />
|
||||||
<Using Include="DocuMed.Repository.Extensions" />
|
<Using Include="DocuMed.Repository.Extensions" />
|
||||||
<Using Include="DocuMed.Repository.Models" />
|
<Using Include="DocuMed.Repository.Models" />
|
||||||
<Using Include="DocuMed.Repository.Repositories.Base.Contracts" />
|
<Using Include="DocuMed.Repository.Repositories.Base.Contracts" />
|
||||||
<Using Include="DocuMed.Repository.Repositories.Entities.Abstracts" />
|
<Using Include="DocuMed.Repository.Repositories.Entities.Abstracts" />
|
||||||
|
<Using Include="MediatR" />
|
||||||
<Using Include="MediatR.Extensions.Autofac.DependencyInjection" />
|
<Using Include="MediatR.Extensions.Autofac.DependencyInjection" />
|
||||||
<Using Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
|
<Using Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
|
||||||
<Using Include="Microsoft.AspNetCore.Identity" />
|
<Using Include="Microsoft.AspNetCore.Identity" />
|
||||||
|
|
|
@ -141,6 +141,8 @@ public class AccountService(
|
||||||
if (section != null)
|
if (section != null)
|
||||||
{
|
{
|
||||||
token.User.SectionName = section.Name;
|
token.User.SectionName = section.Name;
|
||||||
|
token.User.SectionId = section.Id;
|
||||||
|
token.User.HospitalId = section.HospitalId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
namespace DocuMed.Core.EntityServices;
|
using DocuMed.Domain.Entities.Staffs;
|
||||||
|
|
||||||
|
namespace DocuMed.Core.EntityServices;
|
||||||
|
|
||||||
|
|
||||||
public class UserService(
|
public class UserService(
|
||||||
|
@ -85,6 +87,23 @@ public class UserService(
|
||||||
user.BirthDate = request.BirthDate;
|
user.BirthDate = request.BirthDate;
|
||||||
user.Gender = request.Gender;
|
user.Gender = request.Gender;
|
||||||
|
|
||||||
|
switch (request.ProfileType)
|
||||||
|
{
|
||||||
|
case ProfileType.Student:
|
||||||
|
var student = await repositoryWrapper.SetRepository<Student>().TableNoTracking
|
||||||
|
.FirstOrDefaultAsync(s => s.UserId == user.Id, cancellationToken);
|
||||||
|
if (student == null)
|
||||||
|
throw new AppException("Student not found", ApiResultStatusCode.NotFound);
|
||||||
|
student.SetSection(request.SectionId);
|
||||||
|
repositoryWrapper.SetRepository<Student>().Update(student);
|
||||||
|
await repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||||
|
break;
|
||||||
|
case ProfileType.Patient:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
var result = await userManager.UpdateAsync(user);
|
var result = await userManager.UpdateAsync(user);
|
||||||
if (!result.Succeeded)
|
if (!result.Succeeded)
|
||||||
throw new AppException(string.Join('|', result.Errors));
|
throw new AppException(string.Join('|', result.Errors));
|
||||||
|
|
|
@ -13,4 +13,6 @@ public class UserActionRequestDto
|
||||||
public string RoleName { get; set; } = string.Empty;
|
public string RoleName { get; set; } = string.Empty;
|
||||||
public Guid UniversityId { get; set; }
|
public Guid UniversityId { get; set; }
|
||||||
public Guid SectionId { get; set; }
|
public Guid SectionId { get; set; }
|
||||||
|
public Guid HospitalId { get; set; }
|
||||||
|
public ProfileType ProfileType { get; set; }
|
||||||
}
|
}
|
|
@ -14,6 +14,8 @@ public class ApplicationUserSDto : BaseDto<ApplicationUserSDto,ApplicationUser>
|
||||||
public Gender Gender { get; set; }
|
public Gender Gender { get; set; }
|
||||||
public SignUpStatus SignUpStatus { get; set; }
|
public SignUpStatus SignUpStatus { get; set; }
|
||||||
public Guid UniversityId { get; set; }
|
public Guid UniversityId { get; set; }
|
||||||
|
public Guid HospitalId { get; set; }
|
||||||
|
public string HospitalName { get; set; }
|
||||||
public Guid SectionId { get; set; }
|
public Guid SectionId { get; set; }
|
||||||
public string SectionName { get; set; } = string.Empty;
|
public string SectionName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace DocuMed.Domain.Enums;
|
||||||
|
|
||||||
|
public enum ProfileType
|
||||||
|
{
|
||||||
|
Student,
|
||||||
|
Patient
|
||||||
|
}
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Refit" Version="7.2.1" />
|
<PackageReference Include="Refit" Version="7.2.1" />
|
||||||
|
<PackageReference Include="Refit.Newtonsoft.Json" Version="7.2.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
<Using Include="DocuMed.Core.Abstracts" />
|
<Using Include="DocuMed.Core.Abstracts" />
|
||||||
<Using Include="DocuMed.Domain.Models.Settings" />
|
<Using Include="DocuMed.Domain.Models.Settings" />
|
||||||
<Using Include="DocuMed.Infrastructure.Models" />
|
<Using Include="DocuMed.Infrastructure.Models" />
|
||||||
|
<Using Include="DocuMed.Infrastructure.Models.Metis" />
|
||||||
<Using Include="DocuMed.Infrastructure.Models.RestApi.KaveNegar" />
|
<Using Include="DocuMed.Infrastructure.Models.RestApi.KaveNegar" />
|
||||||
<Using Include="DocuMed.Infrastructure.RestServices" />
|
<Using Include="DocuMed.Infrastructure.RestServices" />
|
||||||
<Using Include="Microsoft.Extensions.Logging" />
|
<Using Include="Microsoft.Extensions.Logging" />
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace DocuMed.Infrastructure.Models.Metis;
|
||||||
|
|
||||||
|
public class CreateSessionRequestDto
|
||||||
|
{
|
||||||
|
public string BotId { get; set; } = string.Empty;
|
||||||
|
public MetisUser? User { get; set; }
|
||||||
|
public MetisMessageRequest? InitializeMessage { get; set; }
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
namespace DocuMed.Infrastructure.Models.Metis;
|
||||||
|
|
||||||
|
public class MetisMessageRequest
|
||||||
|
{
|
||||||
|
public MetisMessage message { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MetisMessage
|
||||||
|
{
|
||||||
|
public string content { get; set; } = string.Empty;
|
||||||
|
public string type { get; set; } = "USER";
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace DocuMed.Infrastructure.Models.Metis;
|
||||||
|
|
||||||
|
public class MetisMessageResponse
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string Type { get; set; } = string.Empty;
|
||||||
|
public string Content { get; set; } = string.Empty;
|
||||||
|
public object Attachments { get; set; } = string.Empty;
|
||||||
|
public long Timestamp { get; set; }
|
||||||
|
public string FinishReason { get; set; } = string.Empty;
|
||||||
|
public object Citations { get; set; } = string.Empty;
|
||||||
|
public object ToolCalls { get; set; } = string.Empty;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace DocuMed.Infrastructure.Models.Metis;
|
||||||
|
|
||||||
|
public class MetisUser
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string Id { get; set; } = Guid.NewGuid().ToString("N").Substring(0, 8);
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace DocuMed.Infrastructure.RestServices;
|
||||||
|
|
||||||
|
public interface IMetisRestApi
|
||||||
|
{
|
||||||
|
[Post("/chat/session")]
|
||||||
|
public Task CreateSession(string sessionId, [Body] CreateSessionRequestDto request, [Header("x-api-key")] string metisToken);
|
||||||
|
|
||||||
|
[Post("/chat/session/{sessionId}/message")]
|
||||||
|
public Task<MetisMessageResponse> SendMessage(string sessionId, [Body] MetisMessageRequest request, [Header("x-api-key")] string metisToken);
|
||||||
|
|
||||||
|
[Post("/chat/session/{sessionId}/message/stream")]
|
||||||
|
public Task<MetisMessageResponse> SendStreamMessage(string sessionId, [Body] MetisMessageRequest request, [Header("x-api-key")] string metisToken);
|
||||||
|
}
|
|
@ -1,11 +1,21 @@
|
||||||
namespace DocuMed.Infrastructure.RestServices;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace DocuMed.Infrastructure.RestServices;
|
||||||
|
|
||||||
public interface IRestApiWrapper : IScopedDependency
|
public interface IRestApiWrapper : IScopedDependency
|
||||||
{
|
{
|
||||||
IKaveNegarRestApi KaveNegarRestApi { get; }
|
IKaveNegarRestApi KaveNegarRestApi { get; }
|
||||||
|
|
||||||
|
IMetisRestApi MetisRestApi { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RestApiWrapper : IRestApiWrapper
|
public class RestApiWrapper : IRestApiWrapper
|
||||||
{
|
{
|
||||||
|
private static readonly RefitSettings setting = new RefitSettings(new NewtonsoftJsonContentSerializer(new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
||||||
|
|
||||||
|
}));
|
||||||
public IKaveNegarRestApi KaveNegarRestApi => RestService.For<IKaveNegarRestApi>(RestAddress.BaseKaveNegar);
|
public IKaveNegarRestApi KaveNegarRestApi => RestService.For<IKaveNegarRestApi>(RestAddress.BaseKaveNegar);
|
||||||
|
public IMetisRestApi MetisRestApi => RestService.For<IMetisRestApi>("https://api.metisai.ir/api/v1", setting);
|
||||||
}
|
}
|
|
@ -7,8 +7,8 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
|
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
|
||||||
<AssemblyVersion>1.3.2.1</AssemblyVersion>
|
<AssemblyVersion>1.4.1.1</AssemblyVersion>
|
||||||
<FileVersion>1.3.2.1</FileVersion>
|
<FileVersion>1.4.1.1</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -8,12 +8,15 @@ public static class Address
|
||||||
#else
|
#else
|
||||||
public static string BaseAddress = "https://api.documed.ir/api";
|
public static string BaseAddress = "https://api.documed.ir/api";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public static string AuthController = $"{BaseAddress}/auth";
|
public static string AuthController = $"{BaseAddress}/auth";
|
||||||
public static string CityController = $"{BaseAddress}/city";
|
public static string CityController = $"{BaseAddress}/city";
|
||||||
public static string UniversityController = $"{BaseAddress}/university";
|
public static string UniversityController = $"{BaseAddress}/university";
|
||||||
|
public static string AiController = $"{BaseAddress}/ai";
|
||||||
public static string SectionController = $"{BaseAddress}/section";
|
public static string SectionController = $"{BaseAddress}/section";
|
||||||
public static string UserController = $"{BaseAddress}/user";
|
public static string UserController = $"{BaseAddress}/user";
|
||||||
public static string MedicalHistoryTemplateController = $"{BaseAddress}/medicalhistory/template";
|
public static string MedicalHistoryTemplateController = $"{BaseAddress}/medicalhistory/template";
|
||||||
public static string MedicalHistoryController = $"{BaseAddress}/medicalhistory";
|
public static string MedicalHistoryController = $"{BaseAddress}/medicalhistory";
|
||||||
public static string PatientController = $"{BaseAddress}/patient";
|
public static string PatientController = $"{BaseAddress}/patient";
|
||||||
|
public static string HospitalController = $"{BaseAddress}/hospital";
|
||||||
}
|
}
|
|
@ -221,7 +221,7 @@
|
||||||
{
|
{
|
||||||
var token = await UserUtility.GetBearerTokenAsync();
|
var token = await UserUtility.GetBearerTokenAsync();
|
||||||
var user = await UserUtility.GetUserAsync();
|
var user = await UserUtility.GetUserAsync();
|
||||||
Sections = await RestWrapper.SectionRestApi.GetByUniversityAsync(user.UniversityId, token);
|
Sections = await RestWrapper.HospitalRestApi.GetSectionsAsync(user.HospitalId, token);
|
||||||
|
|
||||||
if (section.IsNullOrEmpty())
|
if (section.IsNullOrEmpty())
|
||||||
return Sections;
|
return Sections;
|
||||||
|
|
|
@ -27,17 +27,17 @@
|
||||||
</MudCarouselItem>
|
</MudCarouselItem>
|
||||||
<MudCarouselItem>
|
<MudCarouselItem>
|
||||||
<div class="flex flex-col h-full p-4">
|
<div class="flex flex-col h-full p-4">
|
||||||
<MedicalHistoryTemplateActionStep2 PiQuestions="@ViewModel.PiQuestions" />
|
<MedicalHistoryTemplateActionStep2 ChiefComplaint="@ViewModel.PageDto.ChiefComplaint" PiQuestions="@ViewModel.PiQuestions" />
|
||||||
</div>
|
</div>
|
||||||
</MudCarouselItem>
|
</MudCarouselItem>
|
||||||
<MudCarouselItem>
|
<MudCarouselItem>
|
||||||
<div class="flex flex-col h-full p-4">
|
<div class="flex flex-col h-full p-4">
|
||||||
<MedicalHistoryTemplateActionStep3 PdhQuestions="@ViewModel.PdhQuestions" PshQuestions="@ViewModel.PshQuestions" />
|
<MedicalHistoryTemplateActionStep3 ChiefComplaint="@ViewModel.PageDto.ChiefComplaint" PdhQuestions="@ViewModel.PdhQuestions" PshQuestions="@ViewModel.PshQuestions" />
|
||||||
</div>
|
</div>
|
||||||
</MudCarouselItem>
|
</MudCarouselItem>
|
||||||
<MudCarouselItem>
|
<MudCarouselItem>
|
||||||
<div class="flex flex-col h-full p-4">
|
<div class="flex flex-col h-full p-4">
|
||||||
<MedicalHistoryTemplateActionStep4 FamilyHistories="@ViewModel.FhQuestions" DrugHistories="@ViewModel.DhQuestions" AhMedicines="@ViewModel.AhQuestions" />
|
<MedicalHistoryTemplateActionStep4 ChiefComplaint="@ViewModel.PageDto.ChiefComplaint" FamilyHistories="@ViewModel.FhQuestions" DrugHistories="@ViewModel.DhQuestions" AhMedicines="@ViewModel.AhQuestions" />
|
||||||
</div>
|
</div>
|
||||||
</MudCarouselItem>
|
</MudCarouselItem>
|
||||||
<MudCarouselItem>
|
<MudCarouselItem>
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
{
|
{
|
||||||
var token = await UserUtility.GetBearerTokenAsync();
|
var token = await UserUtility.GetBearerTokenAsync();
|
||||||
var user = await UserUtility.GetUserAsync();
|
var user = await UserUtility.GetUserAsync();
|
||||||
Sections = await RestWrapper.SectionRestApi.GetByUniversityAsync(user.UniversityId, token);
|
Sections = await RestWrapper.HospitalRestApi.GetSectionsAsync(user.HospitalId, token);
|
||||||
|
|
||||||
if (section.IsNullOrEmpty())
|
if (section.IsNullOrEmpty())
|
||||||
return Sections;
|
return Sections;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
@using DocuMed.Domain.Entities.MedicalHistoryTemplate
|
@inject IRestWrapper RestWrapper
|
||||||
|
@inject ISnackbar Snackbar
|
||||||
<MudStack class="pb-20 font-iranyekan">
|
<MudStack class="pb-20 font-iranyekan">
|
||||||
<BasePartDivider Index="2" Title="تاریخچه بیماری فعلی ( PI )" />
|
<BasePartDivider Index="2" Title="تاریخچه بیماری فعلی ( PI )" />
|
||||||
|
|
||||||
|
@ -19,24 +20,47 @@
|
||||||
Variant="Variant.Outlined" />
|
Variant="Variant.Outlined" />
|
||||||
|
|
||||||
@* <MudAutocomplete T="string" Label="وابستگی به سوال قبلی" Variant="Variant.Outlined" /> *@
|
@* <MudAutocomplete T="string" Label="وابستگی به سوال قبلی" Variant="Variant.Outlined" /> *@
|
||||||
|
|
||||||
<MudButton @onclick="AddQuestion" Variant="Variant.Filled" DisableElevation="true"
|
<MudButton @onclick="AddQuestion" Variant="Variant.Filled" DisableElevation="true"
|
||||||
class="font-extrabold text-lg right-0 rounded-md py-3 bg-[--color-medicalhistory] text-gray-800">
|
class="font-extrabold text-lg right-0 rounded-md py-3 bg-[--color-medicalhistory] text-gray-800">
|
||||||
+ افزودن
|
+ افزودن
|
||||||
</MudButton>
|
</MudButton>
|
||||||
|
|
||||||
|
@AiResponse
|
||||||
|
|
||||||
|
<button @onclick="AskWithAi" class="relative inline-flex h-12 overflow-hidden rounded-full p-[1px] ">
|
||||||
|
<span class="absolute inset-[-1000%] animate-[spin_2s_linear_infinite] bg-[conic-gradient(from_90deg_at_50%_50%,#E2CBFF_0%,#393BB2_50%,#E2CBFF_100%)]"></span>
|
||||||
|
<span class="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-white px-4 py-2 text-sm font-medium text-black backdrop-blur-3xl">
|
||||||
|
<p class="font-bold bg-gradient-to-r from-sky-600 via-violet-500 to-fuchsia-400 inline-block text-transparent bg-clip-text">
|
||||||
|
از هوش مصنوعی بپرس !
|
||||||
|
</p>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
@if (IsProcessing)
|
||||||
|
{
|
||||||
|
<p class="mx-2 -mt-2 bg-gradient-to-r from-sky-600 via-blue-500 to-violet-400 inline-block text-transparent bg-clip-text">
|
||||||
|
در حال فکر کردن ....
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
|
||||||
</MudStack>
|
</MudStack>
|
||||||
|
|
||||||
|
@* focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 focus:ring-offset-slate-50 *@
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
private MedicalHistoryQuestionType _questionType;
|
private MedicalHistoryQuestionType _questionType;
|
||||||
private string _questionTitle = string.Empty;
|
private string _questionTitle = string.Empty;
|
||||||
private MedicalHistoryPart _questionPart = MedicalHistoryPart.PresentIllness;
|
private MedicalHistoryPart _questionPart = MedicalHistoryPart.PresentIllness;
|
||||||
|
private bool IsProcessing { get; set; }
|
||||||
|
private MarkupString AiResponse { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public List<MedicalHistoryQuestionSDto> PiQuestions { get; set; } = new();
|
public List<MedicalHistoryQuestionSDto> PiQuestions { get; set; } = new();
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string ChiefComplaint { get; set; } = string.Empty;
|
||||||
|
|
||||||
private void RemoveQuestion(MedicalHistoryQuestionSDto question)
|
private void RemoveQuestion(MedicalHistoryQuestionSDto question)
|
||||||
{
|
{
|
||||||
PiQuestions.Remove(question);
|
PiQuestions.Remove(question);
|
||||||
|
@ -44,11 +68,43 @@
|
||||||
private void AddQuestion()
|
private void AddQuestion()
|
||||||
{
|
{
|
||||||
PiQuestions.Add(new MedicalHistoryQuestionSDto
|
PiQuestions.Add(new MedicalHistoryQuestionSDto
|
||||||
{
|
{
|
||||||
Part = _questionPart,
|
Part = _questionPart,
|
||||||
Question = _questionTitle,
|
Question = _questionTitle,
|
||||||
QuestionType = _questionType
|
QuestionType = _questionType
|
||||||
});
|
});
|
||||||
_questionTitle = string.Empty;
|
_questionTitle = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task AskWithAi()
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IsProcessing = true;
|
||||||
|
var request = new
|
||||||
|
{
|
||||||
|
content = $"شکایت اصلی بیمار (CC) {ChiefComplaint} است. لطفاً سوالات بخش PI (Present Illness) را در سه دسته زیر تولید کنید: سوالات توضیحی (Open-ended): سوالاتی که بیمار باید توضیح دهد. سوالات بله/خیر (Yes/No): سوالاتی که پاسخ مشخص بله یا خیر دارند. سوالات زمانی (Time-based): سوالاتی مرتبط با زمان شروع، مدت و تغییرات مشکل. لطفاً سوالات مرتبط با سردرد شامل شدت، محل، عوامل تشدیدکننده یا تسکیندهنده و علائم همراه (مثل تهوع یا تاری دید) باشد. use html concept for response and just send html and remove , head , html and body tag"
|
||||||
|
};
|
||||||
|
var response = await RestWrapper.AiRestApi.ChatAsync(request);
|
||||||
|
response = response.Replace("```html", null);
|
||||||
|
response = response.Replace("```", null);
|
||||||
|
response = response.Replace("\\n", null);
|
||||||
|
response = response.Replace(@"""", null);
|
||||||
|
AiResponse = (MarkupString)response;
|
||||||
|
}
|
||||||
|
catch (ApiException ex)
|
||||||
|
{
|
||||||
|
var exe = await ex.GetContentAsAsync<ApiResult>();
|
||||||
|
Snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Snackbar.Add(e.Message, Severity.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsProcessing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
@using DocuMed.Domain.Entities.MedicalHistoryTemplate
|
@inject IRestWrapper RestWrapper
|
||||||
|
@inject ISnackbar Snackbar
|
||||||
<MudStack class="pb-20 font-iranyekan">
|
<MudStack class="pb-20 font-iranyekan">
|
||||||
<BasePartDivider Index="3" Title="تاریخچه بیماری قبلی ( PMH )" />
|
<BasePartDivider Index="3" Title="تاریخچه بیماری قبلی ( PMH )" />
|
||||||
|
|
||||||
|
@ -22,6 +22,25 @@
|
||||||
+ افزودن
|
+ افزودن
|
||||||
</MudButton>
|
</MudButton>
|
||||||
|
|
||||||
|
@AiPMHResponse
|
||||||
|
|
||||||
|
<button @onclick="AskPMHWithAi" class="relative inline-flex h-12 overflow-hidden rounded-full p-[1px] ">
|
||||||
|
<span class="absolute inset-[-1000%] animate-[spin_2s_linear_infinite] bg-[conic-gradient(from_90deg_at_50%_50%,#E2CBFF_0%,#393BB2_50%,#E2CBFF_100%)]"></span>
|
||||||
|
<span class="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-white px-4 py-2 text-sm font-medium text-black backdrop-blur-3xl">
|
||||||
|
<p class="font-bold bg-gradient-to-r from-sky-600 via-violet-500 to-fuchsia-400 inline-block text-transparent bg-clip-text">
|
||||||
|
از هوش مصنوعی بپرس !
|
||||||
|
</p>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
@if (IsProcessing)
|
||||||
|
{
|
||||||
|
<p class="mx-2 -mt-2 bg-gradient-to-r from-sky-600 via-blue-500 to-violet-400 inline-block text-transparent bg-clip-text">
|
||||||
|
در حال فکر کردن ....
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
<BasePartDivider Index="4" class="mt-9" Title="تاریخچه جراحی های قبلی ( PSH )" />
|
<BasePartDivider Index="4" class="mt-9" Title="تاریخچه جراحی های قبلی ( PSH )" />
|
||||||
|
|
||||||
@foreach (var item in PshQuestions)
|
@foreach (var item in PshQuestions)
|
||||||
|
@ -50,6 +69,23 @@
|
||||||
+ افزودن
|
+ افزودن
|
||||||
</MudButton>
|
</MudButton>
|
||||||
|
|
||||||
|
@AiPSHResponse
|
||||||
|
|
||||||
|
<button @onclick="AskPSHWithAi" class="relative inline-flex h-12 overflow-hidden rounded-full p-[1px] ">
|
||||||
|
<span class="absolute inset-[-1000%] animate-[spin_2s_linear_infinite] bg-[conic-gradient(from_90deg_at_50%_50%,#E2CBFF_0%,#393BB2_50%,#E2CBFF_100%)]"></span>
|
||||||
|
<span class="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-white px-4 py-2 text-sm font-medium text-black backdrop-blur-3xl">
|
||||||
|
<p class="font-bold bg-gradient-to-r from-sky-600 via-violet-500 to-fuchsia-400 inline-block text-transparent bg-clip-text">
|
||||||
|
از هوش مصنوعی بپرس !
|
||||||
|
</p>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
@if (IsProcessing)
|
||||||
|
{
|
||||||
|
<p class="mx-2 -mt-2 bg-gradient-to-r from-sky-600 via-blue-500 to-violet-400 inline-block text-transparent bg-clip-text">
|
||||||
|
در حال فکر کردن ....
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
|
||||||
</MudStack>
|
</MudStack>
|
||||||
|
|
||||||
|
@ -60,11 +96,12 @@
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public List<MedicalHistoryQuestionSDto> PshQuestions { get; set; } = new();
|
public List<MedicalHistoryQuestionSDto> PshQuestions { get; set; } = new();
|
||||||
|
|
||||||
|
|
||||||
private string _pdhQuestionTitle = string.Empty;
|
private string _pdhQuestionTitle = string.Empty;
|
||||||
private MedicalHistoryQuestionType _pdhQuestionType;
|
private MedicalHistoryQuestionType _pdhQuestionType;
|
||||||
private string _pshQuestionTitle = string.Empty;
|
private string _pshQuestionTitle = string.Empty;
|
||||||
private MedicalHistoryQuestionType _pshQuestionType;
|
private MedicalHistoryQuestionType _pshQuestionType;
|
||||||
|
[Parameter]
|
||||||
|
public string ChiefComplaint { get; set; } = string.Empty;
|
||||||
|
|
||||||
private void RemovePiQuestion(MedicalHistoryQuestionSDto question)
|
private void RemovePiQuestion(MedicalHistoryQuestionSDto question)
|
||||||
{
|
{
|
||||||
|
@ -96,4 +133,72 @@
|
||||||
_pshQuestionTitle = string.Empty;
|
_pshQuestionTitle = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private bool IsProcessing { get; set; }
|
||||||
|
private MarkupString AiPMHResponse { get; set; }
|
||||||
|
private async Task AskPMHWithAi()
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IsProcessing = true;
|
||||||
|
var request = new
|
||||||
|
{
|
||||||
|
content = $"شکایت اصلی بیمار (CC) {ChiefComplaint} است. لطفاً سوالات بخش تاریخچه بیماری قبلی ( Past Medical History ) را در سه دسته زیر تولید کنید: سوالات توضیحی (Open-ended): سوالاتی که بیمار باید توضیح دهد. سوالات بله/خیر (Yes/No): سوالاتی که پاسخ مشخص بله یا خیر دارند. سوالات زمانی (Time-based): سوالاتی مرتبط با زمان شروع، مدت و تغییرات مشکل. لطفاً سوالات مرتبط با سردرد شامل شدت، محل، عوامل تشدیدکننده یا تسکیندهنده و علائم همراه (مثل تهوع یا تاری دید) باشد. use html concept for response and just send html and remove , head , html and body tag"
|
||||||
|
};
|
||||||
|
var response = await RestWrapper.AiRestApi.ChatAsync(request);
|
||||||
|
response = response.Replace("```html", null);
|
||||||
|
response = response.Replace("```", null);
|
||||||
|
response = response.Replace("\\n", null);
|
||||||
|
response = response.Replace(@"""", null);
|
||||||
|
AiPMHResponse = (MarkupString)response;
|
||||||
|
}
|
||||||
|
catch (ApiException ex)
|
||||||
|
{
|
||||||
|
var exe = await ex.GetContentAsAsync<ApiResult>();
|
||||||
|
Snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Snackbar.Add(e.Message, Severity.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsProcessing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private MarkupString AiPSHResponse { get; set; }
|
||||||
|
private async Task AskPSHWithAi()
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IsProcessing = true;
|
||||||
|
var request = new
|
||||||
|
{
|
||||||
|
content = $"شکایت اصلی بیمار (CC) {ChiefComplaint} است. لطفاً سوالات بخش تاریخچه جراحی های قبلی ( Past Surgery History ) را در سه دسته زیر تولید کنید: سوالات توضیحی (Open-ended): سوالاتی که بیمار باید توضیح دهد. سوالات بله/خیر (Yes/No): سوالاتی که پاسخ مشخص بله یا خیر دارند. سوالات زمانی (Time-based): سوالاتی مرتبط با زمان شروع، مدت و تغییرات مشکل. لطفاً سوالات مرتبط با سردرد شامل شدت، محل، عوامل تشدیدکننده یا تسکیندهنده و علائم همراه (مثل تهوع یا تاری دید) باشد. use html concept for response and just send html and remove , head , html and body tag"
|
||||||
|
};
|
||||||
|
var response = await RestWrapper.AiRestApi.ChatAsync(request);
|
||||||
|
response = response.Replace("```html", null);
|
||||||
|
response = response.Replace("```", null);
|
||||||
|
response = response.Replace("\\n", null);
|
||||||
|
response = response.Replace(@"""", null);
|
||||||
|
AiPSHResponse = (MarkupString)response;
|
||||||
|
}
|
||||||
|
catch (ApiException ex)
|
||||||
|
{
|
||||||
|
var exe = await ex.GetContentAsAsync<ApiResult>();
|
||||||
|
Snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Snackbar.Add(e.Message, Severity.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsProcessing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
@using DocuMed.Domain.Entities.MedicalHistoryTemplate
|
@inject IRestWrapper RestWrapper
|
||||||
|
@inject ISnackbar Snackbar
|
||||||
<MudStack class="pb-20 font-iranyekan">
|
<MudStack class="pb-20 font-iranyekan">
|
||||||
<BasePartDivider Index="5" Title="تاریخچه بیماری های خانوادگی ( FH )" />
|
<BasePartDivider Index="5" Title="تاریخچه بیماری های خانوادگی ( FH )" />
|
||||||
|
|
||||||
|
@ -22,6 +23,23 @@
|
||||||
+ افزودن
|
+ افزودن
|
||||||
</MudButton>
|
</MudButton>
|
||||||
|
|
||||||
|
@AiResponse
|
||||||
|
|
||||||
|
<button @onclick="AskWithAi" class="relative inline-flex h-12 overflow-hidden rounded-full p-[1px] ">
|
||||||
|
<span class="absolute inset-[-1000%] animate-[spin_2s_linear_infinite] bg-[conic-gradient(from_90deg_at_50%_50%,#E2CBFF_0%,#393BB2_50%,#E2CBFF_100%)]"></span>
|
||||||
|
<span class="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-white px-4 py-2 text-sm font-medium text-black backdrop-blur-3xl">
|
||||||
|
<p class="font-bold bg-gradient-to-r from-sky-600 via-violet-500 to-fuchsia-400 inline-block text-transparent bg-clip-text">
|
||||||
|
از هوش مصنوعی بپرس !
|
||||||
|
</p>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
@if (IsProcessing)
|
||||||
|
{
|
||||||
|
<p class="mx-2 -mt-2 bg-gradient-to-r from-sky-600 via-blue-500 to-violet-400 inline-block text-transparent bg-clip-text">
|
||||||
|
در حال فکر کردن ....
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
|
||||||
<BasePartDivider Index="6" class="mt-9" Title="داروهای مصرفی ( DH )" />
|
<BasePartDivider Index="6" class="mt-9" Title="داروهای مصرفی ( DH )" />
|
||||||
|
|
||||||
|
@ -66,9 +84,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</MudStack>
|
</MudStack>
|
||||||
@code {
|
@code
|
||||||
|
{
|
||||||
|
private bool IsProcessing { get; set; }
|
||||||
|
private MarkupString AiResponse { get; set; }
|
||||||
|
[Parameter]
|
||||||
|
public string ChiefComplaint { get; set; } = string.Empty;
|
||||||
|
|
||||||
private string _familyHistoryQuestionTitle = string.Empty;
|
private string _familyHistoryQuestionTitle = string.Empty;
|
||||||
private MedicalHistoryQuestionType _familyHistoryQuestionType;
|
private MedicalHistoryQuestionType _familyHistoryQuestionType;
|
||||||
[Parameter]
|
[Parameter]
|
||||||
|
@ -125,4 +148,37 @@
|
||||||
});
|
});
|
||||||
_hhName = string.Empty;
|
_hhName = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task AskWithAi()
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IsProcessing = true;
|
||||||
|
var request = new
|
||||||
|
{
|
||||||
|
content = $"شکایت اصلی بیمار (CC) {ChiefComplaint} است. لطفاً سوالات بخش PI (Present Illness) را در سه دسته زیر تولید کنید: سوالات توضیحی (Open-ended): سوالاتی که بیمار باید توضیح دهد. سوالات بله/خیر (Yes/No): سوالاتی که پاسخ مشخص بله یا خیر دارند. سوالات زمانی (Time-based): سوالاتی مرتبط با زمان شروع، مدت و تغییرات مشکل. لطفاً سوالات مرتبط با سردرد شامل شدت، محل، عوامل تشدیدکننده یا تسکیندهنده و علائم همراه (مثل تهوع یا تاری دید) باشد. use html concept for response and just send html and remove , head , html and body tag"
|
||||||
|
};
|
||||||
|
var response = await RestWrapper.AiRestApi.ChatAsync(request);
|
||||||
|
response = response.Replace("```html", null);
|
||||||
|
response = response.Replace("```", null);
|
||||||
|
response = response.Replace("\\n", null);
|
||||||
|
response = response.Replace(@"""", null);
|
||||||
|
AiResponse = (MarkupString)response;
|
||||||
|
}
|
||||||
|
catch (ApiException ex)
|
||||||
|
{
|
||||||
|
var exe = await ex.GetContentAsAsync<ApiResult>();
|
||||||
|
Snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Snackbar.Add(e.Message, Severity.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsProcessing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -52,6 +52,25 @@
|
||||||
</ItemTemplate>
|
</ItemTemplate>
|
||||||
</MudAutocomplete>
|
</MudAutocomplete>
|
||||||
|
|
||||||
|
<MudAutocomplete @bind-Value="@ViewModel.SelectedHospital"
|
||||||
|
ToStringFunc="dto => dto.Name"
|
||||||
|
SearchFunc="@ViewModel.SearchHospital"
|
||||||
|
T="HospitalSDto" Label="بیمارستان" Variant="Variant.Outlined">
|
||||||
|
<ProgressIndicatorInPopoverTemplate>
|
||||||
|
<MudList Clickable="false">
|
||||||
|
<MudListItem>
|
||||||
|
<div class="flex flex-row w-full mx-auto">
|
||||||
|
<MudProgressCircular class="my-auto mr-1 -ml-4" Size="Size.Small" Indeterminate="true" />
|
||||||
|
<p class="font-bold my-1 mx-auto text-md">منتظر بمانید</p>
|
||||||
|
</div>
|
||||||
|
</MudListItem>
|
||||||
|
</MudList>
|
||||||
|
</ProgressIndicatorInPopoverTemplate>
|
||||||
|
<ItemTemplate Context="e">
|
||||||
|
<p>@e.Name</p>
|
||||||
|
</ItemTemplate>
|
||||||
|
</MudAutocomplete>
|
||||||
|
|
||||||
<MudAutocomplete T="SectionSDto" Label="بخش فعلی" Variant="Variant.Outlined"
|
<MudAutocomplete T="SectionSDto" Label="بخش فعلی" Variant="Variant.Outlined"
|
||||||
ToStringFunc="dto => dto.Name"
|
ToStringFunc="dto => dto.Name"
|
||||||
SearchFunc="@ViewModel.SearchSection"
|
SearchFunc="@ViewModel.SearchSection"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using DocuMed.Domain.Entities.City;
|
using DocuMed.Domain.Entities.City;
|
||||||
|
using DocuMed.Domain.Entities.Hospitals;
|
||||||
using Mapster;
|
using Mapster;
|
||||||
|
|
||||||
namespace DocuMed.PWA.Pages;
|
namespace DocuMed.PWA.Pages;
|
||||||
|
@ -18,10 +19,12 @@ public class ProfilePageViewModel(
|
||||||
|
|
||||||
public List<CitySDto> Cities { get; private set; } = new List<CitySDto>();
|
public List<CitySDto> Cities { get; private set; } = new List<CitySDto>();
|
||||||
public List<UniversitySDto> Universities { get; private set; } = new List<UniversitySDto>();
|
public List<UniversitySDto> Universities { get; private set; } = new List<UniversitySDto>();
|
||||||
|
public List<HospitalSDto> Hospitals { get; private set; } = new List<HospitalSDto>();
|
||||||
public List<SectionSDto> Sections { get; private set; } = new List<SectionSDto>();
|
public List<SectionSDto> Sections { get; private set; } = new List<SectionSDto>();
|
||||||
public SectionSDto? SelectedSection { get; set; }
|
public SectionSDto? SelectedSection { get; set; }
|
||||||
public CitySDto? SelectedCity { get; set; }
|
public CitySDto? SelectedCity { get; set; }
|
||||||
public UniversitySDto? SelectedUni { get; set; }
|
public UniversitySDto? SelectedUni { get; set; }
|
||||||
|
public HospitalSDto? SelectedHospital { get; set; }
|
||||||
|
|
||||||
public readonly string Version = Assembly.GetAssembly(typeof(Program))?.GetName()?.Version?.ToString() ?? string.Empty;
|
public readonly string Version = Assembly.GetAssembly(typeof(Program))?.GetName()?.Version?.ToString() ?? string.Empty;
|
||||||
|
|
||||||
|
@ -37,12 +40,14 @@ public class ProfilePageViewModel(
|
||||||
{
|
{
|
||||||
SelectedUni = Universities.FirstOrDefault(u => u.Id == User.UniversityId);
|
SelectedUni = Universities.FirstOrDefault(u => u.Id == User.UniversityId);
|
||||||
SelectedCity = Cities.FirstOrDefault(c => c.Id == SelectedUni?.CityId);
|
SelectedCity = Cities.FirstOrDefault(c => c.Id == SelectedUni?.CityId);
|
||||||
if (SelectedUni != null)
|
if (SelectedHospital != null)
|
||||||
|
{
|
||||||
if (User.SectionId != Guid.Empty)
|
if (User.SectionId != Guid.Empty)
|
||||||
{
|
{
|
||||||
Sections = await RestWrapper.SectionRestApi.GetByUniversityAsync(SelectedUni.Id, token);
|
Sections = await RestWrapper.HospitalRestApi.GetSectionsAsync(SelectedHospital.Id, token);
|
||||||
SelectedSection = Sections.FirstOrDefault(s => s.Id == User.SectionId);
|
SelectedSection = Sections.FirstOrDefault(s => s.Id == User.SectionId);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await base.InitializeAsync();
|
await base.InitializeAsync();
|
||||||
|
@ -55,6 +60,7 @@ public class ProfilePageViewModel(
|
||||||
IsProcessing = true;
|
IsProcessing = true;
|
||||||
var token = await UserUtility.GetBearerTokenAsync();
|
var token = await UserUtility.GetBearerTokenAsync();
|
||||||
var request = User.Adapt<UserActionRequestDto>();
|
var request = User.Adapt<UserActionRequestDto>();
|
||||||
|
request.ProfileType = ProfileType.Student;
|
||||||
if (SelectedUni != null)
|
if (SelectedUni != null)
|
||||||
{
|
{
|
||||||
request.UniversityId = SelectedUni.Id;
|
request.UniversityId = SelectedUni.Id;
|
||||||
|
@ -66,6 +72,13 @@ public class ProfilePageViewModel(
|
||||||
User.SectionId = SelectedSection.Id;
|
User.SectionId = SelectedSection.Id;
|
||||||
User.SectionName = SelectedSection.Name;
|
User.SectionName = SelectedSection.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SelectedHospital != null)
|
||||||
|
{
|
||||||
|
request.HospitalId = SelectedHospital.Id;
|
||||||
|
User.HospitalId = SelectedHospital.Id;
|
||||||
|
User.HospitalName = SelectedHospital.Name;
|
||||||
|
}
|
||||||
await RestWrapper.UserRestApi.UpdateUserAsync(request, token);
|
await RestWrapper.UserRestApi.UpdateUserAsync(request, token);
|
||||||
await UserUtility.SetUserAsync(User);
|
await UserUtility.SetUserAsync(User);
|
||||||
Snackbar.Add("ویرایش حساب کاربری با موفقیت انجام شد", Severity.Success);
|
Snackbar.Add("ویرایش حساب کاربری با موفقیت انجام شد", Severity.Success);
|
||||||
|
@ -92,8 +105,6 @@ public class ProfilePageViewModel(
|
||||||
navigationManager.NavigateTo("");
|
navigationManager.NavigateTo("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public async Task<IEnumerable<CitySDto>> SearchCity(string city)
|
public async Task<IEnumerable<CitySDto>> SearchCity(string city)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -123,10 +134,10 @@ public class ProfilePageViewModel(
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (SelectedUni != null)
|
if (SelectedHospital != null)
|
||||||
{
|
{
|
||||||
var token = await UserUtility.GetBearerTokenAsync();
|
var token = await UserUtility.GetBearerTokenAsync();
|
||||||
Sections = await RestWrapper.SectionRestApi.GetByUniversityAsync(SelectedUni.Id, token);
|
Sections = await RestWrapper.HospitalRestApi.GetSectionsAsync(SelectedHospital.Id, token);
|
||||||
}
|
}
|
||||||
if (section.IsNullOrEmpty())
|
if (section.IsNullOrEmpty())
|
||||||
return Sections;
|
return Sections;
|
||||||
|
@ -169,4 +180,29 @@ public class ProfilePageViewModel(
|
||||||
return Universities;
|
return Universities;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public async Task<IEnumerable<HospitalSDto>> SearchHospital(string hospital)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (SelectedUni != null)
|
||||||
|
{
|
||||||
|
var token = await UserUtility.GetBearerTokenAsync();
|
||||||
|
Hospitals = await RestWrapper.UniversityRestApi.GetHospitalsAsync(SelectedUni.Id, token);
|
||||||
|
}
|
||||||
|
if (hospital.IsNullOrEmpty())
|
||||||
|
return Hospitals;
|
||||||
|
return Hospitals.Where(c => c.Name.Contains(hospital));
|
||||||
|
}
|
||||||
|
catch (ApiException ex)
|
||||||
|
{
|
||||||
|
var exe = await ex.GetContentAsAsync<ApiResult>();
|
||||||
|
Snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
|
||||||
|
return Hospitals;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Snackbar.Add(e.Message, Severity.Error);
|
||||||
|
return Hospitals;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace DocuMed.PWA.Services.RestServices;
|
||||||
|
|
||||||
|
public interface IAiRestApi
|
||||||
|
{
|
||||||
|
[Post("/chat")]
|
||||||
|
public Task<string> ChatAsync([Body]object request);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace DocuMed.PWA.Services.RestServices;
|
||||||
|
|
||||||
|
public interface IHospitalRestApi
|
||||||
|
{
|
||||||
|
[Get("/{hospitalId}/section")]
|
||||||
|
Task<List<SectionSDto>> GetSectionsAsync(Guid hospitalId, [Header("Authorization")] string authorization);
|
||||||
|
}
|
|
@ -12,4 +12,7 @@ public interface IRestWrapper
|
||||||
public IUserRestApi UserRestApi { get; }
|
public IUserRestApi UserRestApi { get; }
|
||||||
public IMedicalHistoryRestApi MedicalHistoryRestApi { get; }
|
public IMedicalHistoryRestApi MedicalHistoryRestApi { get; }
|
||||||
public IPatientRestApi PatientRestApi { get; }
|
public IPatientRestApi PatientRestApi { get; }
|
||||||
|
public IHospitalRestApi HospitalRestApi { get; }
|
||||||
|
public IUniversityRestApi UniversityRestApi { get; }
|
||||||
|
public IAiRestApi AiRestApi { get; }
|
||||||
}
|
}
|
|
@ -4,6 +4,4 @@ namespace DocuMed.PWA.Services.RestServices;
|
||||||
|
|
||||||
public interface ISectionRestApi : ICrudDtoApiRest<Section,SectionSDto,Guid>
|
public interface ISectionRestApi : ICrudDtoApiRest<Section,SectionSDto,Guid>
|
||||||
{
|
{
|
||||||
[Get("/university/{universityId}")]
|
|
||||||
Task<List<SectionSDto>> GetByUniversityAsync(Guid universityId, [Header("Authorization")] string authorization);
|
|
||||||
}
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace DocuMed.PWA.Services.RestServices;
|
||||||
|
|
||||||
|
public interface IUniversityRestApi
|
||||||
|
{
|
||||||
|
[Get("/{universityId}/hospital")]
|
||||||
|
Task<List<HospitalSDto>> GetHospitalsAsync(Guid universityId, [Header("Authorization")] string authorization);
|
||||||
|
}
|
|
@ -26,4 +26,7 @@ public class RestWrapper : IRestWrapper
|
||||||
public IUserRestApi UserRestApi => RestService.For<IUserRestApi>(Address.UserController, setting);
|
public IUserRestApi UserRestApi => RestService.For<IUserRestApi>(Address.UserController, setting);
|
||||||
public IMedicalHistoryRestApi MedicalHistoryRestApi => RestService.For<IMedicalHistoryRestApi>(Address.MedicalHistoryController);
|
public IMedicalHistoryRestApi MedicalHistoryRestApi => RestService.For<IMedicalHistoryRestApi>(Address.MedicalHistoryController);
|
||||||
public IPatientRestApi PatientRestApi => RestService.For<IPatientRestApi>(Address.PatientController,setting);
|
public IPatientRestApi PatientRestApi => RestService.For<IPatientRestApi>(Address.PatientController,setting);
|
||||||
|
public IHospitalRestApi HospitalRestApi => RestService.For<IHospitalRestApi>(Address.HospitalController, setting);
|
||||||
|
public IUniversityRestApi UniversityRestApi => RestService.For<IUniversityRestApi>(Address.UniversityController, setting);
|
||||||
|
public IAiRestApi AiRestApi => RestService.For<IAiRestApi>(Address.AiController, setting);
|
||||||
}
|
}
|
|
@ -20,6 +20,9 @@ module.exports = {
|
||||||
'6xl': '4rem',
|
'6xl': '4rem',
|
||||||
'7xl': '5rem'
|
'7xl': '5rem'
|
||||||
},
|
},
|
||||||
|
animation: {
|
||||||
|
'gradient': 'gradient 8s linear infinite',
|
||||||
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
"iranyekan": ["'iranyekan'"],
|
"iranyekan": ["'iranyekan'"],
|
||||||
},
|
},
|
||||||
|
|
|
@ -518,6 +518,15 @@ video {
|
||||||
.fixed {
|
.fixed {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
}
|
}
|
||||||
|
.absolute {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.relative {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.inset-\[-1000\%\] {
|
||||||
|
inset: -1000%;
|
||||||
|
}
|
||||||
.bottom-0 {
|
.bottom-0 {
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
}
|
}
|
||||||
|
@ -720,6 +729,9 @@ video {
|
||||||
.mt-auto {
|
.mt-auto {
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
}
|
}
|
||||||
|
.inline-block {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
.flex {
|
.flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
@ -853,6 +865,18 @@ video {
|
||||||
.basis-full {
|
.basis-full {
|
||||||
flex-basis: 100%;
|
flex-basis: 100%;
|
||||||
}
|
}
|
||||||
|
@keyframes spin {
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.animate-\[spin_2s_linear_infinite\] {
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
}
|
||||||
|
.cursor-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
.grid-cols-1 {
|
.grid-cols-1 {
|
||||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
@ -989,6 +1013,35 @@ video {
|
||||||
.bg-opacity-20 {
|
.bg-opacity-20 {
|
||||||
--tw-bg-opacity: 0.2;
|
--tw-bg-opacity: 0.2;
|
||||||
}
|
}
|
||||||
|
.bg-\[conic-gradient\(from_90deg_at_50\%_50\%\2c \#E2CBFF_0\%\2c \#393BB2_50\%\2c \#E2CBFF_100\%\)\] {
|
||||||
|
background-image: conic-gradient(from 90deg at 50% 50%,#E2CBFF 0%,#393BB2 50%,#E2CBFF 100%);
|
||||||
|
}
|
||||||
|
.bg-gradient-to-r {
|
||||||
|
background-image: linear-gradient(to right, var(--tw-gradient-stops));
|
||||||
|
}
|
||||||
|
.from-sky-600 {
|
||||||
|
--tw-gradient-from: #0284c7 var(--tw-gradient-from-position);
|
||||||
|
--tw-gradient-to: rgb(2 132 199 / 0) var(--tw-gradient-to-position);
|
||||||
|
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
||||||
|
}
|
||||||
|
.via-blue-500 {
|
||||||
|
--tw-gradient-to: rgb(59 130 246 / 0) var(--tw-gradient-to-position);
|
||||||
|
--tw-gradient-stops: var(--tw-gradient-from), #3b82f6 var(--tw-gradient-via-position), var(--tw-gradient-to);
|
||||||
|
}
|
||||||
|
.via-violet-500 {
|
||||||
|
--tw-gradient-to: rgb(139 92 246 / 0) var(--tw-gradient-to-position);
|
||||||
|
--tw-gradient-stops: var(--tw-gradient-from), #8b5cf6 var(--tw-gradient-via-position), var(--tw-gradient-to);
|
||||||
|
}
|
||||||
|
.to-fuchsia-400 {
|
||||||
|
--tw-gradient-to: #e879f9 var(--tw-gradient-to-position);
|
||||||
|
}
|
||||||
|
.to-violet-400 {
|
||||||
|
--tw-gradient-to: #a78bfa var(--tw-gradient-to-position);
|
||||||
|
}
|
||||||
|
.bg-clip-text {
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
.p-0 {
|
.p-0 {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
}
|
}
|
||||||
|
@ -1004,6 +1057,9 @@ video {
|
||||||
.p-5 {
|
.p-5 {
|
||||||
padding: 1.25rem;
|
padding: 1.25rem;
|
||||||
}
|
}
|
||||||
|
.p-\[1px\] {
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
.px-1 {
|
.px-1 {
|
||||||
padding-left: 0.25rem;
|
padding-left: 0.25rem;
|
||||||
padding-right: 0.25rem;
|
padding-right: 0.25rem;
|
||||||
|
@ -1133,6 +1189,10 @@ video {
|
||||||
.text-\[--color-primary\] {
|
.text-\[--color-primary\] {
|
||||||
color: var(--color-primary);
|
color: var(--color-primary);
|
||||||
}
|
}
|
||||||
|
.text-black {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(0 0 0 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
.text-blue-500 {
|
.text-blue-500 {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(59 130 246 / var(--tw-text-opacity));
|
color: rgb(59 130 246 / var(--tw-text-opacity));
|
||||||
|
@ -1157,6 +1217,9 @@ video {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(31 41 55 / var(--tw-text-opacity));
|
color: rgb(31 41 55 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
.text-transparent {
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
.text-white {
|
.text-white {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||||
|
@ -1172,6 +1235,11 @@ video {
|
||||||
}
|
}
|
||||||
.filter {
|
.filter {
|
||||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||||
|
}
|
||||||
|
.backdrop-blur-3xl {
|
||||||
|
--tw-backdrop-blur: blur(64px);
|
||||||
|
-webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
|
||||||
|
backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
@ -1359,11 +1427,35 @@ a, .btn-link {
|
||||||
border-color: rgb(20 184 166 / var(--tw-border-opacity));
|
border-color: rgb(20 184 166 / var(--tw-border-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.focus\:outline-none:focus {
|
||||||
|
outline: 2px solid transparent;
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.focus\:ring-2:focus {
|
||||||
|
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||||
|
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||||
|
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
.focus\:ring-slate-400:focus {
|
||||||
|
--tw-ring-opacity: 1;
|
||||||
|
--tw-ring-color: rgb(148 163 184 / var(--tw-ring-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.focus\:ring-teal-500:focus {
|
.focus\:ring-teal-500:focus {
|
||||||
--tw-ring-opacity: 1;
|
--tw-ring-opacity: 1;
|
||||||
--tw-ring-color: rgb(20 184 166 / var(--tw-ring-opacity));
|
--tw-ring-color: rgb(20 184 166 / var(--tw-ring-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.focus\:ring-offset-2:focus {
|
||||||
|
--tw-ring-offset-width: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.focus\:ring-offset-slate-50:focus {
|
||||||
|
--tw-ring-offset-color: #f8fafc;
|
||||||
|
}
|
||||||
|
|
||||||
.group:hover .group-hover\:text-\[--color-primary\] {
|
.group:hover .group-hover\:text-\[--color-primary\] {
|
||||||
color: var(--color-primary);
|
color: var(--color-primary);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue