21 changed files with 541 additions and 1 deletions
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,24 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net10.0</TargetFramework> |
||||
|
<AssemblyName>LINGYUN.Abp.ElsaNext.AI</AssemblyName> |
||||
|
<PackageId>LINGYUN.Abp.ElsaNext.AI</PackageId> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Elsa.AI.Copilot" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext\LINGYUN.Abp.ElsaNext.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,23 @@ |
|||||
|
using Elsa.Features.Services; |
||||
|
using LINGYUN.Abp.ElsaNext.AI.Extensions; |
||||
|
using Microsoft.Extensions.Configuration; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.ElsaNext.AI; |
||||
|
|
||||
|
[DependsOn(typeof(AbpElsaNextModule))] |
||||
|
public class AbpElsaNextAIModule : AbpModule |
||||
|
{ |
||||
|
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Configuration.GetSection("Elsa:AI"); |
||||
|
PreConfigure<IModule>(elsa => |
||||
|
{ |
||||
|
elsa.UseAbpAI(ai => |
||||
|
{ |
||||
|
ai.ConfigureOptions = options => configuration.GetSection("Host").Bind(options); |
||||
|
ai.ConfigureCopilotOptions = options => configuration.GetSection("Copilot").Bind(options); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using Elsa.Extensions; |
||||
|
using Elsa.Features.Services; |
||||
|
using LINGYUN.Abp.ElsaNext.AI.Features; |
||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.ElsaNext.AI.Extensions; |
||||
|
|
||||
|
public static class ModuleExtensions |
||||
|
{ |
||||
|
public static IModule UseAbpAI(this IModule module, Action<AbpAIFeature>? configure = null) |
||||
|
{ |
||||
|
return module.Use(configure); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
using Elsa.AI.Copilot.Options; |
||||
|
using Elsa.AI.Host.Features; |
||||
|
using Elsa.AI.Host.Options; |
||||
|
using Elsa.AI.Host.Services; |
||||
|
using Elsa.Extensions; |
||||
|
using Elsa.Features.Abstractions; |
||||
|
using Elsa.Features.Services; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.ElsaNext.AI.Features; |
||||
|
|
||||
|
public class AbpAIFeature(IModule module) : FeatureBase(module) |
||||
|
{ |
||||
|
public Action<AIHostOptions>? ConfigureOptions { get; set; } |
||||
|
public Action<CopilotOptions>? ConfigureCopilotOptions { get; set; } |
||||
|
public Action<AIToolEnablementService>? ConfigureToolEnablement { get; set; } |
||||
|
|
||||
|
public override void Configure() |
||||
|
{ |
||||
|
Module.AddFastEndpointsAssembly<AIFeature>(); |
||||
|
} |
||||
|
|
||||
|
public override void Apply() |
||||
|
{ |
||||
|
Services.AddAIHostServices(ConfigureOptions); |
||||
|
Services.AddCopilotAIProvider(ConfigureCopilotOptions); |
||||
|
if (ConfigureToolEnablement != null) |
||||
|
{ |
||||
|
Services.AddSingleton(ConfigureToolEnablement); |
||||
|
} |
||||
|
Module.AddFastEndpointsFromModule(); |
||||
|
} |
||||
|
|
||||
|
public AbpAIFeature EnableWorkflowProposalTools() |
||||
|
{ |
||||
|
ConfigureToolEnablement += enablement => |
||||
|
{ |
||||
|
enablement.Enable("workflows.proposeCreate"); |
||||
|
enablement.Enable("workflows.proposeUpdate"); |
||||
|
}; |
||||
|
return this; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
using Elsa.Studio.AI.Extensions; |
||||
|
using LINGYUN.Abp.ElsaNext.AI; |
||||
|
using LINGYUN.Abp.ElsaNext.Localization; |
||||
|
using LINGYUN.Abp.ElsaNext.Studio.AI.Blazor.Navigation; |
||||
|
using LINGYUN.Abp.ElsaNext.Studio.Blazor; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Routing; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.UI.Navigation; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace LINGYUN.Abp.ElsaNext.Studio.AI.Blazor; |
||||
|
|
||||
|
[DependsOn( |
||||
|
typeof(AbpElsaNextAIModule), |
||||
|
typeof(AbpElsaNextStudioBlazorModule))] |
||||
|
public class AbpElsaNextStudioAIBlazorModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Configuration.GetSection("Elsa:Studio"); |
||||
|
|
||||
|
Configure<AbpRouterOptions>(options => |
||||
|
{ |
||||
|
options.AdditionalAssemblies.Add(typeof(AbpElsaNextStudioAIBlazorModule).Assembly); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpNavigationOptions>(options => |
||||
|
{ |
||||
|
options.MenuContributors.Add(new ElsaStudioAIMenuContributor()); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpElsaNextStudioAIBlazorModule>("LINGYUN.Abp.ElsaNext.Studio.AI.Blazor"); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Get<ElsaNextResource>() |
||||
|
.AddVirtualJson("/Localization/Resources/AIBlazor"); |
||||
|
}); |
||||
|
var elsaNextStudioBlazoeOptions = context.Services.ExecutePreConfiguredActions<AbpElsaNextStudioBlazorOptions>(); |
||||
|
|
||||
|
context.Services.AddWeaverModule(elsaNextStudioBlazoeOptions.BackendApiConfig); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,31 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk.Razor"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net10.0</TargetFramework> |
||||
|
<Nullable>enable</Nullable> |
||||
|
<ImplicitUsings>enable</ImplicitUsings> |
||||
|
<AssemblyName>LINGYUN.Abp.ElsaNext.Studio.AI.Blazor</AssemblyName> |
||||
|
<PackageId>LINGYUN.Abp.ElsaNext.Studio.AI.Blazor</PackageId> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<Content Remove="Localization\Resources\AIBlazor\*.json" /> |
||||
|
<EmbeddedResource Include="Localization\Resources\AIBlazor\*.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Elsa.Studio.AI" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext.AI\LINGYUN.Abp.ElsaNext.AI.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.ElsaNext.Studio.Blazor\LINGYUN.Abp.ElsaNext.Studio.Blazor.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"culture": "en", |
||||
|
"texts": { |
||||
|
"Menu:AI": "AI", |
||||
|
"AI": "AI" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"culture": "zh-Hans", |
||||
|
"texts": { |
||||
|
"Menu:AI": "AI", |
||||
|
"AI": "AI" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
using LINGYUN.Abp.ElsaNext.Localization; |
||||
|
using LINGYUN.Abp.ElsaNext.Studio.Blazor.Navigation; |
||||
|
using Volo.Abp.UI.Navigation; |
||||
|
|
||||
|
namespace LINGYUN.Abp.ElsaNext.Studio.AI.Blazor.Navigation; |
||||
|
|
||||
|
public class ElsaStudioAIMenuContributor : IMenuContributor |
||||
|
{ |
||||
|
public Task ConfigureMenuAsync(MenuConfigurationContext context) |
||||
|
{ |
||||
|
if (context.Menu.Name == StandardMenus.Main) |
||||
|
{ |
||||
|
var menu = context.Menu; |
||||
|
var l = context.GetLocalizer<ElsaNextResource>(); |
||||
|
|
||||
|
var group = menu.GetMenuItemOrNull(ElsaStudioMenus.GroupName); |
||||
|
group?.AddItem(new ApplicationMenuItem( |
||||
|
ElsaStudioMenus.GroupName + ".AI", |
||||
|
l["Menu:AI"], |
||||
|
url: "/ai/weaver", |
||||
|
icon: "fa fa-openai", |
||||
|
order: 6)); |
||||
|
} |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
@page "/ai/weaver" |
||||
|
@attribute [Authorize] |
||||
|
@inherits StudioComponentBase |
||||
|
@using Elsa.Studio.AI.UI.Pages |
||||
|
|
||||
|
<HeadContent> |
||||
|
@* <link rel="stylesheet" href="_content/Elsa.Studio.AI/Elsa.Studio.AI.bundle.scp.css" /> *@ |
||||
|
<link rel="stylesheet" href="_content/LINGYUN.Abp.ElsaNext.Studio.AI.Blazor/weaver.css" /> |
||||
|
</HeadContent> |
||||
|
|
||||
|
<Weaver /> |
||||
@ -0,0 +1,5 @@ |
|||||
|
@using Microsoft.AspNetCore.Authorization |
||||
|
@using Microsoft.AspNetCore.Components.Web |
||||
|
@using Elsa.Studio.Components |
||||
|
@using Elsa.Studio.Localization |
||||
|
@using MudBlazor |
||||
@ -0,0 +1,196 @@ |
|||||
|
.weaver-page { |
||||
|
height: calc(100vh - 72px); |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 12px; |
||||
|
} |
||||
|
|
||||
|
.weaver-heading, |
||||
|
.weaver-thread-header, |
||||
|
.weaver-panel-title, |
||||
|
.weaver-composer-actions, |
||||
|
.weaver-tool, |
||||
|
.weaver-activity { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
gap: 8px; |
||||
|
} |
||||
|
|
||||
|
.weaver-workspace { |
||||
|
min-height: 0; |
||||
|
display: grid; |
||||
|
grid-template-columns: minmax(0, 1fr) 360px; |
||||
|
gap: 12px; |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.weaver-main, |
||||
|
.weaver-side, |
||||
|
.weaver-thread { |
||||
|
min-height: 0; |
||||
|
} |
||||
|
|
||||
|
.weaver-thread, |
||||
|
.weaver-panel { |
||||
|
border: 1px solid var(--mud-palette-lines-default); |
||||
|
border-radius: 8px; |
||||
|
background: var(--mud-palette-surface); |
||||
|
} |
||||
|
|
||||
|
.weaver-thread { |
||||
|
height: 100%; |
||||
|
display: grid; |
||||
|
grid-template-rows: auto minmax(0, 1fr) auto auto; |
||||
|
gap: 12px; |
||||
|
padding: 12px; |
||||
|
} |
||||
|
|
||||
|
.weaver-message-list, |
||||
|
.weaver-activity-list, |
||||
|
.weaver-tool-list { |
||||
|
min-height: 0; |
||||
|
overflow: auto; |
||||
|
} |
||||
|
|
||||
|
.weaver-message-list { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 10px; |
||||
|
} |
||||
|
|
||||
|
.weaver-message { |
||||
|
max-width: 78%; |
||||
|
border: 1px solid var(--mud-palette-lines-default); |
||||
|
border-radius: 8px; |
||||
|
padding: 10px 12px; |
||||
|
background: var(--mud-palette-background); |
||||
|
} |
||||
|
|
||||
|
.weaver-message.is-user { |
||||
|
align-self: flex-end; |
||||
|
background: var(--mud-palette-primary-hover); |
||||
|
} |
||||
|
|
||||
|
.weaver-message.is-assistant { |
||||
|
align-self: flex-start; |
||||
|
} |
||||
|
|
||||
|
.weaver-message-meta { |
||||
|
font-size: 0.72rem; |
||||
|
color: var(--mud-palette-text-secondary); |
||||
|
margin-bottom: 4px; |
||||
|
} |
||||
|
|
||||
|
.weaver-message-text { |
||||
|
white-space: pre-wrap; |
||||
|
} |
||||
|
|
||||
|
.weaver-empty { |
||||
|
margin: auto; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.weaver-composer { |
||||
|
border-top: 1px solid var(--mud-palette-lines-default); |
||||
|
padding-top: 10px; |
||||
|
display: grid; |
||||
|
gap: 8px; |
||||
|
} |
||||
|
|
||||
|
.weaver-attachments { |
||||
|
min-height: 28px; |
||||
|
flex-wrap: wrap; |
||||
|
} |
||||
|
|
||||
|
.weaver-agent-select { |
||||
|
width: 160px; |
||||
|
} |
||||
|
|
||||
|
.weaver-context-kind { |
||||
|
width: 190px; |
||||
|
} |
||||
|
|
||||
|
.weaver-reference-input { |
||||
|
width: 220px; |
||||
|
} |
||||
|
|
||||
|
.weaver-side { |
||||
|
display: grid; |
||||
|
grid-template-rows: auto minmax(160px, 1fr) minmax(120px, 1fr) auto; |
||||
|
gap: 12px; |
||||
|
} |
||||
|
|
||||
|
.weaver-panel { |
||||
|
padding: 12px; |
||||
|
overflow: auto; |
||||
|
} |
||||
|
|
||||
|
.weaver-capability-grid { |
||||
|
display: grid; |
||||
|
grid-template-columns: 1fr 1fr; |
||||
|
gap: 8px; |
||||
|
margin-top: 10px; |
||||
|
} |
||||
|
|
||||
|
.weaver-capability-pill { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 6px; |
||||
|
border: 1px solid var(--mud-palette-lines-default); |
||||
|
border-radius: 6px; |
||||
|
padding: 6px 8px; |
||||
|
font-size: 0.82rem; |
||||
|
} |
||||
|
|
||||
|
.weaver-capability-pill.is-enabled { |
||||
|
color: var(--mud-palette-success); |
||||
|
} |
||||
|
|
||||
|
.weaver-capability-pill.is-disabled { |
||||
|
color: var(--mud-palette-text-secondary); |
||||
|
} |
||||
|
|
||||
|
.weaver-activity-list, |
||||
|
.weaver-tool-list { |
||||
|
display: grid; |
||||
|
gap: 8px; |
||||
|
margin-top: 10px; |
||||
|
} |
||||
|
|
||||
|
.weaver-activity, |
||||
|
.weaver-tool, |
||||
|
.weaver-proposal { |
||||
|
border: 1px solid var(--mud-palette-lines-default); |
||||
|
border-radius: 8px; |
||||
|
padding: 8px; |
||||
|
} |
||||
|
|
||||
|
@media (max-width: 960px) { |
||||
|
.weaver-page { |
||||
|
height: auto; |
||||
|
} |
||||
|
|
||||
|
.weaver-workspace { |
||||
|
grid-template-columns: 1fr; |
||||
|
} |
||||
|
|
||||
|
.weaver-side { |
||||
|
grid-template-rows: none; |
||||
|
} |
||||
|
|
||||
|
.weaver-message { |
||||
|
max-width: 100%; |
||||
|
} |
||||
|
|
||||
|
.weaver-composer-actions { |
||||
|
align-items: stretch; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.weaver-agent-select, |
||||
|
.weaver-context-kind, |
||||
|
.weaver-reference-input { |
||||
|
width: 100%; |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue