-- model-asynch 核心表(pgsql)
-- 1) asynch_models：模型配置
-- 2) asynch_task：异步任务
-- 3) logs_model_op：操作日志(统计用)
-- 4) logs_model_stat：按天模型请求统计(限流/监控用)

-- =========================
-- 1) asynch_models
-- =========================
CREATE TABLE IF NOT EXISTS asynch_models (
    -- 基础字段
    id                         BIGINT PRIMARY KEY,                 -- 主键ID(非自增)
    tenant_id                  BIGINT NOT NULL DEFAULT 0,          -- 租户ID
    creator                    VARCHAR(64) NOT NULL,               -- 创建人
    created_at                 TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
    updater                    VARCHAR(64) NOT NULL,               -- 更新人
    updated_at                 TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
    deleted_at                 TIMESTAMP(6),                       -- 删除时间(软删)
    -- 业务字段
    model_name                 VARCHAR(128) NOT NULL,              -- 模型名称
    model_type                SMALLINT NOT NULL DEFAULT 0,        -- 模型类型
    base_url                   VARCHAR(256) NOT NULL,              -- 模型地址
    http_method                VARCHAR(8) NOT NULL DEFAULT 'POST', -- 请求方式 GET/POST
    head_msg                   VARCHAR(1024) DEFAULT '',           -- 请求头绑定(支持多个,逗号分隔)示例 X-API:xxx,operation:true
    is_private                 SMALLINT NOT NULL DEFAULT 0,        -- 是否私有化 0-私有 1-公共
    enabled                    SMALLINT NOT NULL DEFAULT 1,        -- 是否启用 0停用 1-启用
    is_chat_model              SMALLINT NOT NULL DEFAULT 0,        -- 是否为对话模型 0-否 1-是
    is_owner              SMALLINT NOT NULL DEFAULT 99,        -- 1=当前用户创建的，0=超级管理员的
    api_key                    VARCHAR(256) NOT NULL DEFAULT '',   -- 调用凭证,密钥
    prompt                     TEXT NOT NULL DEFAULT '',           -- 提示词内容(文本)
    form_json                  JSONB NOT NULL DEFAULT '{}'::jsonb, -- 表单结构(用于前端渲染)
    request_mapping            JSONB NOT NULL DEFAULT '{}'::jsonb  -- 请求映射
    response_mapping           JSONB NOT NULL DEFAULT '{}'::jsonb, -- 返回映射
    response_body              JSONB NOT NULL DEFAULT '{}'::jsonb, -- 返回主体
    max_concurrency            INT NOT NULL DEFAULT 10,            -- 单模型最大并发
    queue_limit                INT NOT NULL DEFAULT 1000,          -- 排队上限(近似控制)
    timeout_seconds            INT NOT NULL DEFAULT 600,           -- 调用模型服务超时(秒)
    expected_seconds           INT NOT NULL DEFAULT 600,           -- 模型预计执行时间(秒)
    retry_times                SMALLINT NOT NULL DEFAULT 3,        -- 失败重试次数
    retry_queue_max_seconds    INT NOT NULL DEFAULT 600,           -- 失败重试最大排队时间(秒 0=插队到队首；>0=排队超过该时间后插队，否则仍到队尾)
    auto_clean_seconds         INT NOT NULL DEFAULT 86400,         -- 已下载(state=4 后的保留时间(秒)，到期清理)
    remark                     TEXT DEFAULT ''                     -- 备注
    response_token_field              VARCHAR(128) NOT NULL DEFAULT '';   -- 响应中消耗token的字段映射
    operator_name              VARCHAR(64) NOT NULL DEFAULT '',    -- 运营商名称
    token_config               JSONB NOT NULL DEFAULT '{
    "zh_ratio": 1.0,
    "en_ratio": 1.3,
    "space_ratio": 0.1,
    "punctuation_ratio": 0.1,
    "max_window_size": 8192,
    "reserve_ratio": 0.2,
    "min_reserve": 512,
}'::jsonb  -- Token配置
    extend_mapping              JSONB NOT NULL DEFAULT '{}'::jsonb,
    query_config                JSONB NOT NULL DEFAULT '{}'::jsonb;
    );
CREATE UNIQUE INDEX IF NOT EXISTS uk_asynch_models_tenant_creator_chat ON asynch_models(tenant_id, creator) WHERE is_chat_model = 1 AND deleted_at IS NULL;
CREATE UNIQUE INDEX IF NOT EXISTS uk_asynch_models_tenant_model_name ON asynch_models(tenant_id, creator, model_name);
CREATE INDEX IF NOT EXISTS idx_asynch_models_tenant_id ON asynch_models(tenant_id);
CREATE INDEX IF NOT EXISTS idx_asynch_models_model_name ON asynch_models(model_name);
CREATE INDEX IF NOT EXISTS idx_asynch_models_model_type ON asynch_models(model_type);
CREATE INDEX IF NOT EXISTS idx_asynch_models_enabled ON asynch_models(enabled);
CREATE INDEX IF NOT EXISTS idx_asynch_models_deleted_at ON asynch_models(deleted_at);

COMMENT ON TABLE asynch_models IS '模型配置表';
COMMENT ON COLUMN asynch_models.id IS '主键ID(非自增)';
COMMENT ON COLUMN asynch_models.tenant_id IS '租户ID';
COMMENT ON COLUMN asynch_models.creator IS '创建人';
COMMENT ON COLUMN asynch_models.created_at IS '创建时间';
COMMENT ON COLUMN asynch_models.updater IS '更新人';
COMMENT ON COLUMN asynch_models.updated_at IS '更新时间';
COMMENT ON COLUMN asynch_models.deleted_at IS '删除时间(软删)';

COMMENT ON COLUMN asynch_models.model_name IS '模型名称';
COMMENT ON COLUMN asynch_models.model_type IS '模型类型';
COMMENT ON COLUMN asynch_models.base_url IS '模型地址';
COMMENT ON COLUMN asynch_models.http_method IS '请求方式 GET/POST';
COMMENT ON COLUMN asynch_models.head_msg IS '请求头绑定(支持多个,逗号分隔)示例 X-API:xxx,operation:true';
COMMENT ON COLUMN asynch_models.is_private IS '是否私有化 0-私有 1-公共';
COMMENT ON COLUMN asynch_models.enabled IS '是否启用 0停用 1-启用';
COMMENT ON COLUMN asynch_models.is_chat_model IS '是否为对话模型 0-否 1-是';
COMMENT ON COLUMN asynch_models.is_owner IS '1=当前用户创建的，0=超级管理员的';
COMMENT ON COLUMN asynch_models.api_key IS '调用凭证,密钥';
COMMENT ON COLUMN asynch_models.prompt IS '提示词内容(文本)';
COMMENT ON COLUMN asynch_models.form_json IS '表单结构(用于前端渲染，也用于后端校验)';
COMMENT ON COLUMN asynch_models.request_mapping IS '请求映射';
COMMENT ON COLUMN asynch_models.response_mapping IS '返回映射';
COMMENT ON COLUMN asynch_models.response_body IS '返回主体';
COMMENT ON COLUMN asynch_models.max_concurrency IS '单模型最大并发';
COMMENT ON COLUMN asynch_models.queue_limit IS '排队上限(近似控制)';
COMMENT ON COLUMN asynch_models.timeout_seconds IS '调用模型服务超时(秒)';
COMMENT ON COLUMN asynch_models.expected_seconds IS '模型预计执行时间(秒)';
COMMENT ON COLUMN asynch_models.retry_times IS '失败重试次数';
COMMENT ON COLUMN asynch_models.retry_queue_max_seconds IS '失败重试最大排队时间(秒 0=插队到队首；>0=排队超过该时间后插队，否则仍到队尾)';
COMMENT ON COLUMN asynch_models.auto_clean_seconds IS '已下载(state=4 后的保留时间(秒)，到期清理)';
COMMENT ON COLUMN asynch_models.remark IS '备注';
COMMENT ON COLUMN asynch_models.response_token_field IS '响应中消耗token的字段映射';
COMMENT ON COLUMN asynch_models.operator_name IS '运营商名称';
COMMENT ON COLUMN asynch_models.extend_mapping IS '附加映射（请求时候额外字段）';
COMMENT ON COLUMN asynch_models.query_config IS '查询结果配置（通过task_id查询结果相关配置）';
COMMENT ON COLUMN asynch_models.token_config IS '{
  "zh_ratio": 1.0,          // 中文字符→token系数
  "en_ratio": 1.3,          // 英文单词→token系数
  "space_ratio": 0.1,       // 空格系数
  "punctuation_ratio": 0.1, // 标点系数
  "max_window_size": 8192,  // 模型最大窗口
  "reserve_ratio": 0.2,     // 预留回复空间比例
  "min_reserve": 512,       // 最少预留token数
}';


-- =========================
-- 2) asynch_task
-- =========================
CREATE TABLE IF NOT EXISTS asynch_task (
    -- 基础字段
    id                         BIGINT PRIMARY KEY,                 -- 主键ID(非自增)
    tenant_id                  BIGINT NOT NULL DEFAULT 0,          -- 租户ID
    creator                    VARCHAR(64) NOT NULL,               -- 创建人
    created_at                 TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 创建时间
    updater                    VARCHAR(64) NOT NULL,               -- 更新人
    updated_at                 TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 更新时间
    deleted_at                 TIMESTAMP(6),                       -- 删除时间(软删)

    -- 业务字段
    model_name                 VARCHAR(128) NOT NULL,              -- 模型名称
    task_id                    VARCHAR(64) NOT NULL,               -- 任务ID(对外返回)
    biz_name                   VARCHAR(128) NOT NULL DEFAULT '',   -- 业务名称(调用方模块/系统)
    callback_url               VARCHAR(512) DEFAULT '',            -- 回调地址(可选，用于后续业务通知)
    model_key                  VARCHAR(1024) DEFAULT '',           -- 动态请求头(用于覆盖/补充模型配置 head_msg)，如 X-API-Key:xxx
    state                      SMALLINT NOT NULL DEFAULT 0,        -- 0排队中/1执行中/2成功/3失败/4已下载
    oss_file                   VARCHAR(512) DEFAULT '',            -- 结果文件OSS地址
    file_type                  VARCHAR(32) DEFAULT '',             -- 文件类型(mp3/mp4/png/...)
    file_size                  BIGINT NOT NULL DEFAULT 0,          -- 文件大小(字节)
    error_msg                  TEXT DEFAULT '',                    -- 错误信息
    started_at                 TIMESTAMP,                          -- 开始执行时间
    finished_at                TIMESTAMP,                          -- 执行结束时间
    duration_seconds           BIGINT NOT NULL DEFAULT 0,          -- 耗时(秒)：从创建到完成(成功/失败)整体耗时
    expire_at                  TIMESTAMP,                          -- state=4 后写入，用于清理
    retry_count                INT NOT NULL DEFAULT 0,             -- 已重试次数(不含首次)
    enqueue_at                 TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 入队时间(用于排队顺序)
    phase                      SMALLINT NOT NULL DEFAULT 0,        -- 0模型阶段/1OSS阶段
    tmp_file                   TEXT DEFAULT '',                    -- 临时结果文件路径(phase=1 时仅重试 OSS 上传)
    input_ref                  TEXT DEFAULT '',                    -- 输入引用(如OSS/业务资源ID等)
    request_payload            JSONB,                              -- 请求参数(可选)
    text_result                TEXT DEFAULT '',                    -- 文本类结果(可选，支持直接回调)
    epicycle_id                VARCHAR(64) DEFAULT '',             -- 轮次ID
    expend_tokens              BIGINT NOT NULL DEFAULT 0           -- 消耗 token 数
);

CREATE UNIQUE INDEX IF NOT EXISTS uk_asynch_task_tenant_task_id ON asynch_task(tenant_id, task_id);
CREATE INDEX IF NOT EXISTS idx_asynch_task_tenant_id ON asynch_task(tenant_id);
CREATE INDEX IF NOT EXISTS idx_asynch_task_model_name ON asynch_task(model_name);
CREATE INDEX IF NOT EXISTS idx_asynch_task_biz_name ON asynch_task(biz_name);
CREATE INDEX IF NOT EXISTS idx_asynch_task_model_key ON asynch_task(model_key);
CREATE INDEX IF NOT EXISTS idx_asynch_task_state ON asynch_task(state);
CREATE INDEX IF NOT EXISTS idx_asynch_task_enqueue_at ON asynch_task(enqueue_at);
CREATE INDEX IF NOT EXISTS idx_asynch_task_updated_at ON asynch_task(updated_at);
CREATE INDEX IF NOT EXISTS idx_asynch_task_expire_at ON asynch_task(expire_at);
CREATE INDEX IF NOT EXISTS idx_asynch_task_deleted_at ON asynch_task(deleted_at);
CREATE INDEX IF NOT EXISTS idx_asynch_task_epicycle_id ON asynch_task(epicycle_id);
CREATE INDEX IF NOT EXISTS idx_asynch_task_expend_tokens ON asynch_task(expend_tokens);

COMMENT ON TABLE asynch_task IS '异步任务表';
COMMENT ON COLUMN asynch_task.id IS '主键ID(非自增)';
COMMENT ON COLUMN asynch_task.tenant_id IS '租户ID';
COMMENT ON COLUMN asynch_task.creator IS '创建人';
COMMENT ON COLUMN asynch_task.created_at IS '创建时间';
COMMENT ON COLUMN asynch_task.updater IS '更新人';
COMMENT ON COLUMN asynch_task.updated_at IS '更新时间';
COMMENT ON COLUMN asynch_task.deleted_at IS '删除时间(软删)';
COMMENT ON COLUMN asynch_task.model_name IS '模型名称';
COMMENT ON COLUMN asynch_task.task_id IS '任务ID(对外返回)';
COMMENT ON COLUMN asynch_task.biz_name IS '业务名称(调用方模块/系统)';
COMMENT ON COLUMN asynch_task.callback_url IS '回调地址(可选，用于后续业务通知)';
COMMENT ON COLUMN asynch_task.model_key IS '动态请求头(用于覆盖/补充模型配置 head_msg)，如 X-API-Key:xxx';
COMMENT ON COLUMN asynch_task.state IS '0排队中/1执行中/2成功/3失败/4已下载';
COMMENT ON COLUMN asynch_task.oss_file IS '结果文件OSS地址';
COMMENT ON COLUMN asynch_task.file_type IS '文件类型(mp3/mp4/png/...)';
COMMENT ON COLUMN asynch_task.file_size IS '文件大小(字节)';
COMMENT ON COLUMN asynch_task.error_msg IS '错误信息';
COMMENT ON COLUMN asynch_task.started_at IS '开始执行时间';
COMMENT ON COLUMN asynch_task.finished_at IS '执行结束时间';
COMMENT ON COLUMN asynch_task.duration_seconds IS '耗时(秒)：从创建到完成(成功/失败)整体耗时';
COMMENT ON COLUMN asynch_task.expire_at IS 'state=4 后写入，用于清理';
COMMENT ON COLUMN asynch_task.retry_count IS '已重试次数(不含首次)';
COMMENT ON COLUMN asynch_task.enqueue_at IS '入队时间(用于排队顺序)';
COMMENT ON COLUMN asynch_task.phase IS '执行阶段 模型阶段/1OSS阶段(模型已成功,等待上传OSS)';
COMMENT ON COLUMN asynch_task.tmp_file IS '临时结果文件路径(phase=1 时仅重试 OSS 上传)';
COMMENT ON COLUMN asynch_task.input_ref IS '输入引用(如OSS/业务资源ID等)';
COMMENT ON COLUMN asynch_task.request_payload IS '请求参数(可选,JSON)';
COMMENT ON COLUMN asynch_task.text_result IS '文本类结果(可选，支持直接回调)';
COMMENT ON COLUMN asynch_task.epicycle_id IS '轮次ID(用于标识同一轮次的任务)';
COMMENT ON COLUMN asynch_task.expend_tokens IS '消耗 token 数';



-- =========================
-- 3) logs_model_op
-- =========================
CREATE TABLE IF NOT EXISTS logs_model_op (
    -- 基础字段
    id BIGINT PRIMARY KEY,
    tenant_id BIGINT NOT NULL DEFAULT 0,
    creator VARCHAR(64) NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updater VARCHAR(64) NOT NULL,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP(6),
    -- 基础审计信息
    ip VARCHAR(64) DEFAULT '',
    user_agent VARCHAR(256) DEFAULT '',
    api_path VARCHAR(256) DEFAULT '',
    http_method VARCHAR(16) DEFAULT '',
    -- 业务信息
    biz_name VARCHAR(128) NOT NULL DEFAULT '', -- 调用方业务模块/系统
    model_name VARCHAR(128) NOT NULL DEFAULT '',
    task_id VARCHAR(64) NOT NULL DEFAULT '',
    -- 统计字段
    op_type VARCHAR(64) NOT NULL DEFAULT 'createTask', -- 操作类型(默认创建任务)
    success SMALLINT NOT NULL DEFAULT 1, -- 1成功/0失败
    error_msg TEXT DEFAULT '',
    cost_ms BIGINT NOT NULL DEFAULT 0, -- 耗时(毫秒)
    -- 请求/响应 JSON(用于后期统计分析)
    request_payload JSONB,
    response_payload JSONB
);

CREATE INDEX IF NOT EXISTS idx_logs_model_op_tenant_time ON logs_model_op(tenant_id, created_at);
CREATE INDEX IF NOT EXISTS idx_logs_model_op_model_name ON logs_model_op(model_name);
CREATE INDEX IF NOT EXISTS idx_logs_model_op_biz_name ON logs_model_op(biz_name);
CREATE INDEX IF NOT EXISTS idx_logs_model_op_task_id ON logs_model_op(task_id);
CREATE INDEX IF NOT EXISTS idx_logs_model_op_op_type ON logs_model_op(op_type);
CREATE INDEX IF NOT EXISTS idx_logs_model_op_deleted_at ON logs_model_op(deleted_at);

COMMENT ON TABLE logs_model_op IS '操作记录日志表(创建任务等，用于统计)';
COMMENT ON COLUMN logs_model_op.id IS '主键ID(非自增)';
COMMENT ON COLUMN logs_model_op.tenant_id IS '租户ID';
COMMENT ON COLUMN logs_model_op.creator IS '创建人';
COMMENT ON COLUMN logs_model_op.created_at IS '创建时间';
COMMENT ON COLUMN logs_model_op.updater IS '更新人';
COMMENT ON COLUMN logs_model_op.updated_at IS '更新时间';
COMMENT ON COLUMN logs_model_op.deleted_at IS '删除时间(软删)';
COMMENT ON COLUMN logs_model_op.ip IS '客户端IP';
COMMENT ON COLUMN logs_model_op.user_agent IS 'User-Agent';
COMMENT ON COLUMN logs_model_op.api_path IS '接口路径';
COMMENT ON COLUMN logs_model_op.http_method IS 'HTTP方法';
COMMENT ON COLUMN logs_model_op.biz_name IS '业务名称(调用方模块/系统)';
COMMENT ON COLUMN logs_model_op.model_name IS '模型名称';
COMMENT ON COLUMN logs_model_op.task_id IS '任务ID';
COMMENT ON COLUMN logs_model_op.op_type IS '操作类型(如 createTask/getTaskResult/getTaskBatch 等)';
COMMENT ON COLUMN logs_model_op.success IS '是否成功：1成功/0失败';
COMMENT ON COLUMN logs_model_op.error_msg IS '错误信息(失败时)';
COMMENT ON COLUMN logs_model_op.cost_ms IS '耗时(毫秒)';
COMMENT ON COLUMN logs_model_op.request_payload IS '请求 JSON';
COMMENT ON COLUMN logs_model_op.response_payload IS '响应 JSON';


-- =========================
-- 4) logs_model_stat
-- =========================
CREATE TABLE IF NOT EXISTS logs_model_stat (
    day DATE NOT NULL,                     -- 天(YYYY-MM-DD)
    tenant_id BIGINT NOT NULL DEFAULT 0,   -- 租户ID
    creator VARCHAR(64) NOT NULL DEFAULT '', -- 创建人
    model_name VARCHAR(128) NOT NULL DEFAULT '', -- 模型名称
    request_count BIGINT NOT NULL DEFAULT 0, -- 请求次数
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY(day, tenant_id, creator, model_name)
);

-- 便于时间段/租户/人/模型过滤
CREATE INDEX IF NOT EXISTS idx_logs_model_stat_tenant_day ON logs_model_stat(tenant_id, day);
CREATE INDEX IF NOT EXISTS idx_logs_model_stat_day ON logs_model_stat(day);
CREATE INDEX IF NOT EXISTS idx_logs_model_stat_model_name ON logs_model_stat(model_name);
CREATE INDEX IF NOT EXISTS idx_logs_model_stat_creator ON logs_model_stat(creator);

COMMENT ON TABLE logs_model_stat IS '按天模型请求统计(用于限流/监控)';
COMMENT ON COLUMN logs_model_stat.day IS '天(YYYY-MM-DD)';
COMMENT ON COLUMN logs_model_stat.tenant_id IS '租户ID';
COMMENT ON COLUMN logs_model_stat.creator IS '创建人';
COMMENT ON COLUMN logs_model_stat.model_name IS '模型名称';
COMMENT ON COLUMN logs_model_stat.request_count IS '请求次数';
COMMENT ON COLUMN logs_model_stat.created_at IS '创建时间';
COMMENT ON COLUMN logs_model_stat.updated_at IS '更新时间';
