feat(ai): add ADR-036 unified OCR architecture and frontend test coverage
CI / CD Pipeline / build (push) Failing after 6m24s
CI / CD Pipeline / deploy (push) Has been skipped

- Add ADR-036 unified OCR architecture (typhoon-ocr via Ollama)
- Extend AI execution profiles for OCR sandbox configuration
- Add comprehensive frontend test coverage (components, hooks, services)
- Add backend test coverage for document-numbering services
- Update OCR sidecar with typhoon-ocr integration
- Add AI policy service and execution profile management
- Update AGENTS.md and architecture documentation
This commit is contained in:
2026-06-14 06:34:07 +07:00
parent e3503b6a77
commit 7e8f4859cd
108 changed files with 33914 additions and 339 deletions
@@ -1,6 +1,7 @@
// File: backend/src/modules/ai/entities/ai-execution-profile.entity.ts
// Change Log:
// - 2026-06-11: Initial creation of AiExecutionProfile entity for AI execution profiles
// - 2026-06-13: ADR-036 — เพิ่ม canonicalModel และรองรับ nullable OCR params
import {
Column,
@@ -19,17 +20,20 @@ export class AiExecutionProfile {
@Column({ name: 'profile_name', unique: true, length: 50 })
profileName!: string;
@Column({ name: 'canonical_model', length: 20, default: 'np-dms-ai' })
canonicalModel!: 'np-dms-ai' | 'np-dms-ocr';
@Column({ type: 'decimal', precision: 4, scale: 3 })
temperature!: number;
@Column({ name: 'top_p', type: 'decimal', precision: 4, scale: 3 })
topP!: number;
@Column({ name: 'max_tokens', type: 'int' })
maxTokens!: number;
@Column({ name: 'max_tokens', type: 'int', nullable: true })
maxTokens!: number | null;
@Column({ name: 'num_ctx', type: 'int' })
numCtx!: number;
@Column({ name: 'num_ctx', type: 'int', nullable: true })
numCtx!: number | null;
@Column({ name: 'repeat_penalty', type: 'decimal', precision: 5, scale: 3 })
repeatPenalty!: number;
@@ -0,0 +1,51 @@
// File: backend/src/modules/ai/entities/ai-sandbox-profile.entity.ts
// Change Log:
// - 2026-06-13: ADR-036 — เพิ่ม sandbox draft profile entity สำหรับ AI parameter tuning
import {
Column,
CreateDateColumn,
Entity,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
/** Entity สำหรับเก็บ draft parameters ที่ admin ทดลองก่อน Apply to Production */
@Entity('ai_sandbox_profiles')
export class AiSandboxProfile {
@PrimaryGeneratedColumn()
id!: number;
@Column({ name: 'profile_name', unique: true, length: 50 })
profileName!: string;
@Column({ name: 'canonical_model', length: 20, default: 'np-dms-ai' })
canonicalModel!: 'np-dms-ai' | 'np-dms-ocr';
@Column({ type: 'decimal', precision: 4, scale: 3 })
temperature!: number;
@Column({ name: 'top_p', type: 'decimal', precision: 4, scale: 3 })
topP!: number;
@Column({ name: 'max_tokens', type: 'int', nullable: true })
maxTokens!: number | null;
@Column({ name: 'num_ctx', type: 'int', nullable: true })
numCtx!: number | null;
@Column({ name: 'repeat_penalty', type: 'decimal', precision: 5, scale: 3 })
repeatPenalty!: number;
@Column({ name: 'keep_alive_seconds', type: 'int' })
keepAliveSeconds!: number;
@Column({ name: 'updated_by', type: 'int', nullable: true })
updatedBy?: number | null;
@CreateDateColumn({ name: 'created_at' })
createdAt!: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt!: Date;
}