- Add modules: ai, audit, billing-usage, biometrics, branches, dashboard, feature-flags, invoices, mcp, mobile, notifications, partners, payment-terminals, products, profiles, purchases, reports, sales, storage, warehouses, webhooks, whatsapp - Add controllers, DTOs, entities, and services for each module - Add shared services and utilities Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
161 lines
4.5 KiB
TypeScript
161 lines
4.5 KiB
TypeScript
import {
|
|
Entity,
|
|
PrimaryGeneratedColumn,
|
|
Column,
|
|
CreateDateColumn,
|
|
UpdateDateColumn,
|
|
Index,
|
|
ManyToOne,
|
|
JoinColumn,
|
|
OneToMany,
|
|
} from 'typeorm';
|
|
import { AIModel } from './model.entity';
|
|
|
|
export type ConversationStatus = 'active' | 'archived' | 'deleted';
|
|
export type MessageRole = 'system' | 'user' | 'assistant' | 'function';
|
|
export type FinishReason = 'stop' | 'length' | 'function_call' | 'content_filter';
|
|
|
|
@Entity({ name: 'conversations', schema: 'ai' })
|
|
export class AIConversation {
|
|
@PrimaryGeneratedColumn('uuid')
|
|
id: string;
|
|
|
|
@Index()
|
|
@Column({ name: 'tenant_id', type: 'uuid' })
|
|
tenantId: string;
|
|
|
|
@Index()
|
|
@Column({ name: 'user_id', type: 'uuid' })
|
|
userId: string;
|
|
|
|
@Column({ name: 'title', type: 'varchar', length: 255, nullable: true })
|
|
title: string;
|
|
|
|
@Column({ name: 'summary', type: 'text', nullable: true })
|
|
summary: string;
|
|
|
|
@Column({ name: 'context_type', type: 'varchar', length: 50, nullable: true })
|
|
contextType: string;
|
|
|
|
@Column({ name: 'context_data', type: 'jsonb', default: {} })
|
|
contextData: Record<string, any>;
|
|
|
|
@Column({ name: 'model_id', type: 'uuid', nullable: true })
|
|
modelId: string;
|
|
|
|
@Column({ name: 'prompt_id', type: 'uuid', nullable: true })
|
|
promptId: string;
|
|
|
|
@Index()
|
|
@Column({ name: 'status', type: 'varchar', length: 20, default: 'active' })
|
|
status: ConversationStatus;
|
|
|
|
@Column({ name: 'is_pinned', type: 'boolean', default: false })
|
|
isPinned: boolean;
|
|
|
|
@Column({ name: 'message_count', type: 'int', default: 0 })
|
|
messageCount: number;
|
|
|
|
@Column({ name: 'total_tokens', type: 'int', default: 0 })
|
|
totalTokens: number;
|
|
|
|
@Column({ name: 'total_cost', type: 'decimal', precision: 10, scale: 4, default: 0 })
|
|
totalCost: number;
|
|
|
|
@Column({ name: 'metadata', type: 'jsonb', default: {} })
|
|
metadata: Record<string, any>;
|
|
|
|
@Column({ name: 'tags', type: 'text', array: true, default: [] })
|
|
tags: string[];
|
|
|
|
@Column({ name: 'last_message_at', type: 'timestamptz', nullable: true })
|
|
lastMessageAt: Date;
|
|
|
|
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
|
|
createdAt: Date;
|
|
|
|
@UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' })
|
|
updatedAt: Date;
|
|
|
|
@ManyToOne(() => AIModel, { onDelete: 'SET NULL' })
|
|
@JoinColumn({ name: 'model_id' })
|
|
model: AIModel;
|
|
|
|
@OneToMany(() => AIMessage, (message) => message.conversation)
|
|
messages: AIMessage[];
|
|
}
|
|
|
|
@Entity({ name: 'messages', schema: 'ai' })
|
|
export class AIMessage {
|
|
@PrimaryGeneratedColumn('uuid')
|
|
id: string;
|
|
|
|
@Index()
|
|
@Column({ name: 'conversation_id', type: 'uuid' })
|
|
conversationId: string;
|
|
|
|
@Index()
|
|
@Column({ name: 'tenant_id', type: 'uuid' })
|
|
tenantId: string;
|
|
|
|
@Column({ name: 'role', type: 'varchar', length: 20 })
|
|
role: MessageRole;
|
|
|
|
@Column({ name: 'content', type: 'text' })
|
|
content: string;
|
|
|
|
@Column({ name: 'function_name', type: 'varchar', length: 100, nullable: true })
|
|
functionName: string;
|
|
|
|
@Column({ name: 'function_arguments', type: 'jsonb', nullable: true })
|
|
functionArguments: Record<string, any>;
|
|
|
|
@Column({ name: 'function_result', type: 'jsonb', nullable: true })
|
|
functionResult: Record<string, any>;
|
|
|
|
@Column({ name: 'model_id', type: 'uuid', nullable: true })
|
|
modelId: string;
|
|
|
|
@Column({ name: 'model_response_id', type: 'varchar', length: 255, nullable: true })
|
|
modelResponseId: string;
|
|
|
|
@Column({ name: 'prompt_tokens', type: 'int', nullable: true })
|
|
promptTokens: number;
|
|
|
|
@Column({ name: 'completion_tokens', type: 'int', nullable: true })
|
|
completionTokens: number;
|
|
|
|
@Column({ name: 'total_tokens', type: 'int', nullable: true })
|
|
totalTokens: number;
|
|
|
|
@Column({ name: 'cost', type: 'decimal', precision: 10, scale: 6, nullable: true })
|
|
cost: number;
|
|
|
|
@Column({ name: 'latency_ms', type: 'int', nullable: true })
|
|
latencyMs: number;
|
|
|
|
@Column({ name: 'finish_reason', type: 'varchar', length: 30, nullable: true })
|
|
finishReason: FinishReason;
|
|
|
|
@Column({ name: 'metadata', type: 'jsonb', default: {} })
|
|
metadata: Record<string, any>;
|
|
|
|
@Column({ name: 'feedback_rating', type: 'int', nullable: true })
|
|
feedbackRating: number;
|
|
|
|
@Column({ name: 'feedback_text', type: 'text', nullable: true })
|
|
feedbackText: string;
|
|
|
|
@Index()
|
|
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
|
|
createdAt: Date;
|
|
|
|
@ManyToOne(() => AIConversation, (conversation) => conversation.messages, { onDelete: 'CASCADE' })
|
|
@JoinColumn({ name: 'conversation_id' })
|
|
conversation: AIConversation;
|
|
|
|
@ManyToOne(() => AIModel, { onDelete: 'SET NULL' })
|
|
@JoinColumn({ name: 'model_id' })
|
|
model: AIModel;
|
|
}
|