| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- """数据库迁移脚本"""
- import os
- import psycopg2
- from dotenv import load_dotenv
- load_dotenv()
- # 数据库连接配置
- DB_HOST = os.getenv("DB_HOST", "8.156.90.138")
- DB_PORT = os.getenv("DB_PORT", "5432")
- DB_USER = os.getenv("DB_USER", "AigcSpace_test")
- DB_PASSWORD = os.getenv("DB_PASSWORD", "pnk6FrPzYKmwHHjM")
- DB_NAME = os.getenv("DB_NAME", "aigcspace_test")
- def run_migration():
- """执行数据库迁移"""
- conn = psycopg2.connect(
- host=DB_HOST,
- port=DB_PORT,
- user=DB_USER,
- password=DB_PASSWORD,
- dbname=DB_NAME
- )
- conn.autocommit = False
- cur = conn.cursor()
- try:
- print("开始执行数据库迁移...")
- # ============================================
- # 1. models_new 表添加缺失字段
- # ============================================
- migrations = [
- # 添加缺失字段
- ("ALTER TABLE aigcspace.models_new ADD COLUMN IF NOT EXISTS group_name VARCHAR(100)", "添加 group_name 字段"),
- ("ALTER TABLE aigcspace.models_new ADD COLUMN IF NOT EXISTS encrypted_api_key TEXT", "添加 encrypted_api_key 字段"),
- ("ALTER TABLE aigcspace.models_new ADD COLUMN IF NOT EXISTS is_thinking BOOLEAN NOT NULL DEFAULT FALSE", "添加 is_thinking 字段"),
- ("ALTER TABLE aigcspace.models_new ADD COLUMN IF NOT EXISTS source_keys TEXT[]", "添加 source_keys 字段"),
- ("ALTER TABLE aigcspace.models_new ADD COLUMN IF NOT EXISTS normalized_keys TEXT[]", "添加 normalized_keys 字段"),
- ("ALTER TABLE aigcspace.models_new ADD COLUMN IF NOT EXISTS is_local BOOLEAN NOT NULL DEFAULT FALSE", "添加 is_local 字段"),
- ("ALTER TABLE aigcspace.models_new ADD COLUMN IF NOT EXISTS user_id VARCHAR(50)", "添加 user_id 字段"),
- ("ALTER TABLE aigcspace.models_new ADD COLUMN IF NOT EXISTS base_url VARCHAR(500)", "添加 base_url 字段"),
- ("ALTER TABLE aigcspace.models_new ADD COLUMN IF NOT EXISTS local_api_key VARCHAR(500)", "添加 local_api_key 字段"),
- ("ALTER TABLE aigcspace.models_new ADD COLUMN IF NOT EXISTS visibility VARCHAR(20) DEFAULT 'user'", "添加 visibility 字段"),
- # 添加索引
- ("CREATE INDEX IF NOT EXISTS idx_models_new_is_local ON aigcspace.models_new(is_local)", "创建 is_local 索引"),
- ("CREATE INDEX IF NOT EXISTS idx_models_new_group_name ON aigcspace.models_new(group_name)", "创建 group_name 索引"),
- ]
- for sql, desc in migrations:
- try:
- cur.execute(sql)
- print(f"✓ {desc}")
- except Exception as e:
- if "duplicate" in str(e).lower() or "already exists" in str(e).lower():
- print(f"○ {desc} (已存在,跳过)")
- else:
- print(f"✗ {desc}: {e}")
- # ============================================
- # 2. 创建可能缺失的表
- # ============================================
- tables = [
- # asr_recognition 表
- """CREATE TABLE IF NOT EXISTS aigcspace.asr_recognition (
- id SERIAL PRIMARY KEY,
- user_id VARCHAR(50) NOT NULL REFERENCES aigcspace.users(id) ON DELETE CASCADE,
- model VARCHAR(100) NOT NULL,
- audio_url VARCHAR(500),
- audio_base64 TEXT,
- language VARCHAR(20),
- enable_itn BOOLEAN DEFAULT FALSE,
- context TEXT,
- result_text TEXT NOT NULL,
- detected_language VARCHAR(20),
- emotion VARCHAR(20),
- duration INTEGER,
- input_tokens INTEGER DEFAULT 0,
- output_tokens INTEGER DEFAULT 0,
- bill NUMERIC(10,4) DEFAULT 0,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- )""",
- # asr_recognition_v2 表
- """CREATE TABLE IF NOT EXISTS aigcspace.asr_recognition_v2 (
- id SERIAL PRIMARY KEY,
- user_id VARCHAR(50) NOT NULL REFERENCES aigcspace.users(id) ON DELETE CASCADE,
- task_id VARCHAR(100) UNIQUE NOT NULL,
- model VARCHAR(100) NOT NULL,
- file_url VARCHAR(500) NOT NULL,
- status VARCHAR(20) DEFAULT 'PENDING',
- result_text TEXT,
- result_url VARCHAR(500),
- duration INTEGER,
- bill NUMERIC(10,4) DEFAULT 0,
- error_message TEXT,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- completed_at TIMESTAMP
- )""",
- # audio_synthesis_v2 表
- """CREATE TABLE IF NOT EXISTS aigcspace.audio_synthesis_v2 (
- id SERIAL PRIMARY KEY,
- user_id VARCHAR(50) NOT NULL REFERENCES aigcspace.users(id) ON DELETE CASCADE,
- task_id VARCHAR(100) UNIQUE NOT NULL,
- model VARCHAR(100) NOT NULL,
- voice VARCHAR(100) NOT NULL,
- text TEXT NOT NULL,
- audio_url VARCHAR(500),
- status VARCHAR(20) DEFAULT 'PENDING',
- duration NUMERIC(10,2),
- format VARCHAR(20) DEFAULT 'mp3',
- characters INTEGER,
- bill NUMERIC(10,4) DEFAULT 0,
- custom_name VARCHAR(200),
- error_message TEXT,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- completed_at TIMESTAMP
- )""",
- # voice_clone_v2 表
- """CREATE TABLE IF NOT EXISTS aigcspace.voice_clone_v2 (
- id SERIAL PRIMARY KEY,
- user_id VARCHAR(50) NOT NULL REFERENCES aigcspace.users(id) ON DELETE CASCADE,
- task_id VARCHAR(100) UNIQUE NOT NULL,
- voice_id VARCHAR(200),
- target_model VARCHAR(100) NOT NULL,
- prefix VARCHAR(20) NOT NULL,
- voice_name VARCHAR(50),
- audio_url VARCHAR(500),
- status VARCHAR(20) DEFAULT 'PENDING',
- bill NUMERIC(10,4) DEFAULT 0,
- error_message TEXT,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- completed_at TIMESTAMP
- )""",
- # long_text_audio 表
- """CREATE TABLE IF NOT EXISTS aigcspace.long_text_audio (
- id SERIAL PRIMARY KEY,
- user_id VARCHAR(50) NOT NULL REFERENCES aigcspace.users(id) ON DELETE CASCADE,
- task_id VARCHAR(100) UNIQUE NOT NULL,
- model VARCHAR(100) NOT NULL,
- voice VARCHAR(100) NOT NULL,
- text TEXT NOT NULL,
- text_length INTEGER NOT NULL,
- segment_count INTEGER DEFAULT 0,
- segments JSONB DEFAULT '[]',
- audio_url VARCHAR(500),
- status VARCHAR(20) DEFAULT 'PENDING',
- progress INTEGER DEFAULT 0,
- duration NUMERIC(10,2),
- format VARCHAR(20) DEFAULT 'mp3',
- bill NUMERIC(10,4) DEFAULT 0,
- custom_name VARCHAR(200),
- error_message TEXT,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- completed_at TIMESTAMP
- )""",
- # system_voice 表
- """CREATE TABLE IF NOT EXISTS aigcspace.system_voice (
- id SERIAL PRIMARY KEY,
- voice_id VARCHAR(100) UNIQUE NOT NULL,
- name VARCHAR(50) NOT NULL,
- trait VARCHAR(100),
- age VARCHAR(20),
- category VARCHAR(50),
- languages JSONB DEFAULT '[]',
- models JSONB DEFAULT '[]',
- ssml_support BOOLEAN DEFAULT FALSE,
- instruct_support BOOLEAN DEFAULT FALSE,
- timestamp_support BOOLEAN DEFAULT FALSE,
- is_active BOOLEAN DEFAULT TRUE,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- )""",
- # model_price_new 表
- """CREATE TABLE IF NOT EXISTS aigcspace.model_price_new (
- id SERIAL PRIMARY KEY,
- model_code VARCHAR(200) NOT NULL,
- label VARCHAR(200) NOT NULL,
- tier_min NUMERIC(20,2),
- tier_max NUMERIC(20,2),
- tier_unit VARCHAR(50),
- input_price_original NUMERIC(20,8) NOT NULL DEFAULT 0,
- output_price_original NUMERIC(20,8) NOT NULL DEFAULT 0,
- discount_rate NUMERIC(5,4) NOT NULL DEFAULT 1,
- discount_label VARCHAR(20),
- input_price_discounted NUMERIC(20,8) NOT NULL DEFAULT 0,
- output_price_discounted NUMERIC(20,8) NOT NULL DEFAULT 0,
- currency VARCHAR(10) NOT NULL DEFAULT 'CNY',
- unit VARCHAR(100) NOT NULL,
- display_multiplier INTEGER NOT NULL DEFAULT 1,
- source_url TEXT,
- crawled_at TIMESTAMP NOT NULL,
- is_active BOOLEAN NOT NULL DEFAULT TRUE,
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- )""",
- # crawler_sync_log 表
- """CREATE TABLE IF NOT EXISTS aigcspace.crawler_sync_log (
- id SERIAL PRIMARY KEY,
- crawler_version INTEGER NOT NULL,
- synced_at TIMESTAMP 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
- )""",
- # user_local_model_permission 表
- """CREATE TABLE IF NOT EXISTS aigcspace.user_local_model_permission (
- id SERIAL PRIMARY KEY,
- user_id VARCHAR(50) NOT NULL REFERENCES aigcspace.users(id) ON DELETE CASCADE,
- model_id INTEGER NOT NULL,
- granted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- granted_by VARCHAR(50),
- UNIQUE(user_id, model_id)
- )""",
- ]
- print("\n创建缺失的表...")
- for sql in tables:
- table_name = sql.split("aigcspace.")[1].split(" ")[0] if "aigcspace." in sql else "unknown"
- try:
- cur.execute(sql)
- print(f"✓ 表 {table_name} 就绪")
- except Exception as e:
- if "already exists" in str(e).lower():
- print(f"○ 表 {table_name} 已存在,跳过")
- else:
- print(f"✗ 表 {table_name}: {e}")
- # 提交事务
- conn.commit()
- print("\n✓ 迁移完成!")
- # 验证
- print("\n验证表结构...")
- cur.execute("""
- SELECT table_name FROM information_schema.tables
- WHERE table_schema = 'aigcspace' ORDER BY table_name
- """)
- tables = cur.fetchall()
- print(f"数据库中共有 {len(tables)} 张表:")
- for t in tables:
- print(f" - {t[0]}")
- except Exception as e:
- conn.rollback()
- print(f"\n✗ 迁移失败: {e}")
- raise
- finally:
- cur.close()
- conn.close()
- if __name__ == "__main__":
- run_migration()
|