-- ===================================================== -- 最终版模型表结构 -- models_new : 模型主表 -- model_price_new : 价格表(对应爬虫 parsed_prices / discounted_prices) -- crawler_sync_log: 爬虫同步版本记录 -- ===================================================== DROP TABLE IF EXISTS aigcspace.model_price_new CASCADE; DROP TABLE IF EXISTS aigcspace.models_new CASCADE; DROP TABLE IF EXISTS aigcspace.crawler_sync_log CASCADE; -- ===================================================== -- 1. 模型主表 -- ===================================================== CREATE TABLE aigcspace.models_new ( id SERIAL PRIMARY KEY, model_code VARCHAR(200) NOT NULL UNIQUE, -- 爬虫自动更新字段 description TEXT, display_tags TEXT[], input_modalities TEXT[], output_modalities TEXT[], features JSONB, rate_limits JSONB, tool_call_prices JSONB, raw_prices JSONB, -- models[].prices 原始结构,供前端展示用 source_url TEXT, crawled_at TIMESTAMP, -- 分类(由爬虫 input/output_modalities 自动推断,管理员可覆盖) -- 0=LLM,1=多模态,2=TTS,3=STT,4=图像生成,5=视频生成,6=图像编辑,7=Embedding,8=Rerank categories INTEGER[] NOT NULL DEFAULT '{}', -- 管理员手动配置字段(爬虫不覆盖) display_name VARCHAR(255), img TEXT, supplier VARCHAR(100) NOT NULL DEFAULT 'Qwen', tag1 VARCHAR(100), tag2 VARCHAR(100), keywords TEXT, custom_description TEXT, is_featured BOOLEAN NOT NULL DEFAULT false, is_show_enabled BOOLEAN NOT NULL DEFAULT true, is_api_enabled BOOLEAN NOT NULL DEFAULT false, is_search BOOLEAN NOT NULL DEFAULT false, is_thinking BOOLEAN NOT NULL DEFAULT false, source_keys TEXT[], normalized_keys TEXT[], -- 本地模型字段 is_local BOOLEAN NOT NULL DEFAULT false, user_id VARCHAR(50) REFERENCES aigcspace.users(id), base_url VARCHAR(500), local_api_key VARCHAR(500), visibility VARCHAR(20) DEFAULT 'user', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); COMMENT ON TABLE aigcspace.models_new IS '模型主表'; COMMENT ON COLUMN aigcspace.models_new.raw_prices IS 'models[].prices 原始结构,供前端详情页展示完整价格子项'; COMMENT ON COLUMN aigcspace.models_new.categories IS '多分类数组:0=LLM,1=多模态,2=TTS,3=STT,4=图像生成,5=视频生成,6=图像编辑,7=Embedding,8=Rerank'; -- ===================================================== -- 2. 价格表 -- 直接对应爬虫 parsed_prices(原价)+ discounted_prices(折扣价) -- 每个 model_code + label 一条记录 -- ===================================================== CREATE TABLE aigcspace.model_price_new ( id SERIAL PRIMARY KEY, model_code VARCHAR(200) NOT NULL, -- 对应 parsed_prices / discounted_prices 的 label 字段 -- 例:'语音合成'、'input<=32k'、'视频生成(720P)' label VARCHAR(200) NOT NULL, -- 阶梯范围(来自 parsed_prices 的 tier_min/tier_max/tier_unit) tier_min NUMERIC(20, 2), tier_max NUMERIC(20, 2), tier_unit VARCHAR(50), -- tokens / seconds / images / characters -- 原价(来自 parsed_prices 的 input_price / output_price) input_price_original NUMERIC(20, 8) NOT NULL DEFAULT 0, output_price_original NUMERIC(20, 8) NOT NULL DEFAULT 0, -- 折扣价(来自 discounted_prices 的 input_price / output_price) input_price_discounted NUMERIC(20, 8) NOT NULL DEFAULT 0, output_price_discounted NUMERIC(20, 8) NOT NULL DEFAULT 0, -- 折扣率(来自 discounted_prices 的 discount 字段,如 0.8) discount_rate NUMERIC(5, 4) NOT NULL DEFAULT 1.0000, -- 折扣标签(由 discount_rate 计算,如 '8折',无折扣时为 NULL) discount_label VARCHAR(20), -- 单位信息 currency VARCHAR(10) NOT NULL DEFAULT 'CNY', unit VARCHAR(100) NOT NULL DEFAULT '', -- 计价基数:元/百万tokens=1000000,元/秒或元/张=1 display_multiplier INTEGER NOT NULL DEFAULT 1, source_url TEXT, crawled_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, is_active BOOLEAN NOT NULL DEFAULT true, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); COMMENT ON TABLE aigcspace.model_price_new IS '价格表:对应爬虫 parsed_prices(原价)+ discounted_prices(折扣价)'; COMMENT ON COLUMN aigcspace.model_price_new.label IS '价格标签,对应爬虫 parsed_prices.label'; COMMENT ON COLUMN aigcspace.model_price_new.input_price_original IS '原价输入,来自 parsed_prices.input_price'; COMMENT ON COLUMN aigcspace.model_price_new.output_price_original IS '原价输出,来自 parsed_prices.output_price'; COMMENT ON COLUMN aigcspace.model_price_new.input_price_discounted IS '折扣价输入,来自 discounted_prices.input_price'; COMMENT ON COLUMN aigcspace.model_price_new.output_price_discounted IS '折扣价输出,来自 discounted_prices.output_price'; COMMENT ON COLUMN aigcspace.model_price_new.discount_rate IS '折扣率 0~1,来自 discounted_prices.discount,如 0.8'; COMMENT ON COLUMN aigcspace.model_price_new.discount_label IS '折扣标签,如 "8折",discount_rate=1 时为 NULL'; COMMENT ON COLUMN aigcspace.model_price_new.display_multiplier IS '计价基数:元/百万tokens=1000000,元/秒或元/张=1'; COMMENT ON COLUMN aigcspace.model_price_new.is_active IS '是否为当前生效版本'; -- ===================================================== -- 3. 爬虫同步版本记录表 -- ===================================================== CREATE TABLE aigcspace.crawler_sync_log ( id SERIAL PRIMARY KEY, crawler_version INTEGER NOT NULL, synced_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, model_count INTEGER NOT NULL DEFAULT 0, price_count INTEGER NOT NULL DEFAULT 0, status VARCHAR(20) NOT NULL DEFAULT 'success', error_message TEXT ); COMMENT ON TABLE aigcspace.crawler_sync_log IS '爬虫同步版本记录'; COMMENT ON COLUMN aigcspace.crawler_sync_log.crawler_version IS '爬虫全局版本号'; -- ===================================================== -- 4. 索引 -- ===================================================== CREATE INDEX idx_models_new_categories ON aigcspace.models_new USING GIN(categories); CREATE INDEX idx_models_new_supplier ON aigcspace.models_new(supplier); CREATE INDEX idx_models_new_is_show_enabled ON aigcspace.models_new(is_show_enabled); CREATE INDEX idx_models_new_is_api_enabled ON aigcspace.models_new(is_api_enabled); CREATE INDEX idx_models_new_is_local ON aigcspace.models_new(is_local); CREATE INDEX idx_models_new_crawled_at ON aigcspace.models_new(crawled_at); CREATE INDEX idx_models_new_display_tags ON aigcspace.models_new USING GIN(display_tags); CREATE INDEX idx_models_new_source_keys ON aigcspace.models_new USING GIN(source_keys); CREATE INDEX idx_model_price_model_code ON aigcspace.model_price_new(model_code); CREATE INDEX idx_model_price_label ON aigcspace.model_price_new(label); CREATE INDEX idx_model_price_active ON aigcspace.model_price_new(model_code, is_active) WHERE is_active = true; CREATE INDEX idx_crawler_sync_log_version ON aigcspace.crawler_sync_log(crawler_version);