From 34246d8a62820180fb6c638d6fa7a191f4d4b76f Mon Sep 17 00:00:00 2001 From: chenchun Date: Fri, 26 Dec 2025 18:29:47 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 OpenApiService.GenerateContentAsync 的 isAsync 查询参数及其分支处理(不再在该接口直接创建并返回 ImageStore 任务 Id)。 - 保留 alt=sse 的代理处理逻辑。 - 在 ImageStoreTaskAggregateRoot 中新增字段: - Prompt:提示词(大文本) - ReferenceImageUrls:参考图 URL 列表(JSON 存储) - 兼容性提示:接口去掉了 isAsync 参数,调用方需相应调整异步任务创建流程。 --- Yi.Abp.Net8/CLAUDE.md | 129 ++++++++++++++++++ .../Services/OpenApiService.cs | 15 +- .../Chat/ImageStoreTaskAggregateRoot.cs | 12 ++ 3 files changed, 142 insertions(+), 14 deletions(-) create mode 100644 Yi.Abp.Net8/CLAUDE.md diff --git a/Yi.Abp.Net8/CLAUDE.md b/Yi.Abp.Net8/CLAUDE.md new file mode 100644 index 00000000..c0f43769 --- /dev/null +++ b/Yi.Abp.Net8/CLAUDE.md @@ -0,0 +1,129 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +Yi.Abp.Net8 is a modular, multi-tenant SaaS platform built on ABP Framework 8.3.4 with .NET 8.0. It uses **SqlSugar** (not EF Core) as the ORM and follows Domain-Driven Design (DDD) principles. The platform includes AI/ML features (chat, models, agents, token tracking), RBAC, forum, messaging, and digital collectibles modules. + +## Architecture + +### Solution Structure + +``` +Yi.Abp.Net8/ +├── src/ # Main application host +│ └── Yi.Abp.Web/ # ASP.NET Core 8.0 Web Host (port 19001) +├── framework/ # Framework layer (shared infrastructure) +│ ├── Yi.Framework.Core # Core utilities, JSON handling +│ ├── Yi.Framework.SqlSugarCore # SqlSugar ORM abstraction (v5.1.4.197-preview22) +│ ├── Yi.Framework.SqlSugarCore.Abstractions # Repository interfaces +│ ├── Yi.Framework.AspNetCore # ASP.NET Core extensions +│ ├── Yi.Framework.AspNetCore.Authentication.OAuth # QQ, Gitee OAuth +│ ├── Yi.Framework.Ddd.Application # DDD application base classes +│ ├── Yi.Framework.BackgroundWorkers.Hangfire # Job scheduling +│ ├── Yi.Framework.Caching.FreeRedis # Redis caching +│ └── Yi.Framework.SemanticKernel # AI/ML integration +├── module/ # Business modules (each follows 5-layer DDD pattern) +│ ├── ai-hub/ # AI services (chat, models, sessions, agents) +│ ├── rbac/ # Role-Based Access Control (core auth/authz) +│ ├── bbs/ # Forum/community +│ ├── chat-hub/ # Real-time messaging +│ ├── audit-logging/ # Audit trail tracking +│ ├── code-gen/ # Code generation +│ ├── tenant-management/ # Multi-tenancy support +│ ├── digital-collectibles/ # NFT/digital assets +│ └── ai-stock/ # AI-powered stock analysis +├── test/ # Unit tests (xUnit + NSubstitute + Shouldly) +├── client/ # HTTP API clients +└── tool/ # Development utilities +``` + +### Module Structure (DDD Layers) + +Each module follows this pattern: + +``` +module/[feature]/ +├── [Feature].Domain.Shared/ # Constants, enums, shared DTOs +├── [Feature].Domain/ # Entities, aggregates, domain services +├── [Feature].Application.Contracts/ # Service interfaces, DTOs +├── [Feature].Application/ # Application services (implementations) +└── [Feature].SqlSugarCore/ # Repository implementations, DbContext +``` + +**Dependency Flow:** Application → Domain + Application.Contracts → Domain.Shared → Framework + +### Module Registration + +All modules are registered in `src/Yi.Abp.Web/YiAbpWebModule.cs`. When adding a new module: + +1. Add `DependsOn` attribute in `YiAbpWebModule` +2. Add conventional controller in `PreConfigureServices`: +```csharp +options.ConventionalControllers.Create(typeof(YiFramework[Feature]ApplicationModule).Assembly, + option => option.RemoteServiceName = "[service-name]"); +``` + +### API Routing + +All API routes use the unified prefix: `/api/app/{service-name}/{controller}/{action}` + +Registered service names: +- `default` - Main application services +- `rbac` - Authentication, authorization, user/role management +- `ai-hub` - AI chat, models, sessions, agents +- `bbs` - Forum posts and comments +- `chat-hub` - Real-time messaging +- `tenant-management` - Multi-tenant configuration +- `code-gen` - Code generation utilities +- `digital-collectibles` - NFT/digital assets +- `ai-stock` - Stock analysis + +## Database + +**ORM:** SqlSugar (NOT Entity Framework Core) + +**Configuration** (`appsettings.json`): +```json +"DbConnOptions": { + "Url": "DataSource=yi-abp-dev.db", + "DbType": "Sqlite", // Sqlite, Mysql, Sqlserver, Oracle, PostgreSQL + "EnabledCodeFirst": true, // Auto-create tables + "EnabledDbSeed": true, // Auto-seed data + "EnabledSaasMultiTenancy": true +} +``` + +**Multi-tenancy:** Tenant isolation via `HeaderTenantResolveContributor` (NOT cookie-based). Tenant is resolved from `__tenant` header. + +## Key Technologies + +| Component | Technology | +|-----------|-----------| +| Framework | ABP 8.3.4 | +| .NET Version | .NET 8.0 | +| ORM | SqlSugar 5.1.4.197-preview22 | +| Authentication | JWT Bearer + Refresh Tokens | +| OAuth | QQ, Gitee | +| Caching | FreeRedis (optional) | +| Background Jobs | Hangfire (in-memory or Redis) | +| Logging | Serilog (daily rolling files) | +| Testing | xUnit + NSubstitute + Shouldly | +| Container | Autofac | + +## Important Notes + +- **JSON Serialization:** Uses Microsoft's `System.Text.Json`, NOT Newtonsoft.Json. Date format handled via `DatetimeJsonConverter`. +- **Multi-tenancy:** Tenant resolved from `__tenant` header, NOT cookies. +- **Rate Limiting:** Disabled in development, enabled in production (1000 req/60s sliding window). +- **Swagger:** Available at `/swagger` in development. +- **Hangfire Dashboard:** Available at `/hangfire` (requires JWT authorization). +- **Background Workers:** Disabled in development (`AbpBackgroundWorkerOptions.IsEnabled = false`). + +## Development Workflow + +1. **Branch:** Main branch is `abp`, current development branch is `ai-hub`. +2. **Commit Convention:** Chinese descriptive messages with prefixes (`feat:`, `fix:`, `style:`). +3. **Testing:** Run `dotnet test` before committing. +4. **Building:** Use `dotnet build --no-restore` for faster builds after initial restore. diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs index 5b150cb1..ccb05089 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs @@ -261,13 +261,11 @@ public class OpenApiService : ApplicationService /// 生成-Gemini (尊享服务专用) /// /// - /// /// /// /// [HttpPost("openApi/v1beta/models/{modelId}:{action:regex(^(generateContent|streamGenerateContent)$)}")] public async Task GenerateContentAsync([FromBody] JsonElement input, - [FromQuery] bool isAsync, [FromRoute] string modelId, [FromQuery] string? alt, CancellationToken cancellationToken) { @@ -298,18 +296,7 @@ public class OpenApiService : ApplicationService throw new UserFriendlyException("尊享token包用量不足,请先购买尊享token包"); } - //如果异步,直接走job处理进行存储 - if (isAsync) - { - var task = new ImageStoreTaskAggregateRoot(); - await _imageStoreRepository.InsertAsync(task); - await _httpContextAccessor.HttpContext.Response.WriteAsJsonAsync(new - { - Id = task.Id - }, cancellationToken); - //todo 发送job,参数怎么办?需要先全存下来吗?全存下来,就要解析全部提示词 和 附件内容了 - - } + //ai网关代理httpcontext if (alt == "sse") { diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Chat/ImageStoreTaskAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Chat/ImageStoreTaskAggregateRoot.cs index cd26ab8e..b30f29c1 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Chat/ImageStoreTaskAggregateRoot.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Chat/ImageStoreTaskAggregateRoot.cs @@ -7,6 +7,18 @@ namespace Yi.Framework.AiHub.Domain.Entities.Chat; [SugarTable("Ai_ImageStoreTask")] public class ImageStoreTaskAggregateRoot : FullAuditedAggregateRoot { + /// + /// 提示词 + /// + [SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString)] + public string Prompt { get; set; } + + /// + /// 参考图Url + /// + [SugarColumn(IsJson = true)] + public List ReferenceImageUrls { get; set; } + /// /// 图片绝对路径 ///