160 lines
6.7 KiB
Python
160 lines
6.7 KiB
Python
import json
|
||
import os
|
||
from datetime import datetime
|
||
from pathlib import Path
|
||
from .database import SessionLocal, init_db
|
||
from .models import Topic, User, Case, LLMConfig, SystemConfig
|
||
import bcrypt
|
||
|
||
# 计算项目根目录(backend/app/initial_data.py -> 上升3层到 yu-zhi-ran)
|
||
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||
if os.getenv('PROJECT_ROOT'):
|
||
PROJECT_ROOT = Path(os.getenv('PROJECT_ROOT'))
|
||
TOPICS_FILE = PROJECT_ROOT / "automation" / "data" / "sustainability_topics.json"
|
||
CASES_FILE = PROJECT_ROOT / "automation" / "data" / "initial_cases.json"
|
||
|
||
# 从环境变量读取管理员配置
|
||
DEFAULT_ADMIN_USERNAME = os.getenv('DEFAULT_ADMIN_USERNAME', 'admin')
|
||
DEFAULT_ADMIN_PASSWORD = os.getenv('DEFAULT_ADMIN_PASSWORD', 'admin123')
|
||
|
||
def import_initial_data():
|
||
db = SessionLocal()
|
||
try:
|
||
# 1. 导入选题数据
|
||
if db.query(Topic).count() == 0:
|
||
if __import__('os').path.exists(TOPICS_FILE):
|
||
topics = json.loads(open(TOPICS_FILE, encoding='utf-8').read())
|
||
# 去重:保留每个 ID 最后出现的记录
|
||
seen = {}
|
||
for t in topics:
|
||
seen[t['id']] = t
|
||
unique_topics = list(seen.values())
|
||
for t in unique_topics:
|
||
topic = Topic(
|
||
id=t['id'],
|
||
title=t['title'],
|
||
field=t['field'],
|
||
format=t.get('format'),
|
||
core_concept=t.get('core_concept'),
|
||
audience_pain=t.get('audience_pain'),
|
||
unique_angle=t.get('unique_angle'),
|
||
priority=t.get('priority'),
|
||
priority_score=t.get('priority_score', 0),
|
||
total_score=t.get('total_score'),
|
||
status=t.get('status', 'pending'),
|
||
cases=t.get('cases', []),
|
||
source_file=t.get('source_file'),
|
||
ready_at=datetime.strptime(t['ready_at'], '%Y-%m-%d').date() if t.get('ready_at') else None,
|
||
published_at=datetime.strptime(t['published_at'], '%Y-%m-%d').date() if t.get('published_at') else None,
|
||
compliance_score=t.get('compliance_score'),
|
||
platform_urls=t.get('platform_urls', {})
|
||
)
|
||
db.add(topic)
|
||
db.commit()
|
||
print(f"✅ 导入 {len(unique_topics)} 个选题到数据库(去重后)")
|
||
else:
|
||
print(f"⚠️ 选题文件不存在: {TOPICS_FILE}")
|
||
else:
|
||
print("数据库已有选题数据,跳过导入")
|
||
|
||
|
||
# 3. 导入案例数据(如果为空)
|
||
if db.query(Case).count() == 0:
|
||
if __import__('os').path.exists(CASES_FILE):
|
||
cases_data = json.loads(open(CASES_FILE, encoding='utf-8').read())
|
||
for c in cases_data:
|
||
case = Case(
|
||
id=c['id'],
|
||
title=c['title'],
|
||
field=c['field'],
|
||
summary=c['summary'],
|
||
key_metrics=c.get('key_metrics'),
|
||
date=c.get('date'),
|
||
source=c['source'],
|
||
source_url=c.get('source_url'),
|
||
credibility_rating=c.get('credibility_rating'),
|
||
china_applicability=c.get('china_applicability')
|
||
)
|
||
db.add(case)
|
||
db.commit()
|
||
print(f"✅ 导入 {len(cases_data)} 条案例")
|
||
else:
|
||
print(f"⚠️ 案例文件不存在: {CASES_FILE}")
|
||
|
||
# 4. 插入 LLM 默认配置
|
||
if db.query(LLMConfig).count() == 0:
|
||
default_llm = LLMConfig(
|
||
name="default_expand",
|
||
system_prompt="你是一个专业的内容创作者。",
|
||
user_prompt_template="""你是一个专业的内容创作者,风格精炼、直接、切中要点。请将以下大纲扩展为完整的文章章节,要求如下:
|
||
|
||
### 选题信息
|
||
标题:{topic.get('title')}
|
||
领域:{topic.get('field')}
|
||
核心观点:{topic.get('core_concept', '')}
|
||
受众痛点:{topic.get('audience_pain', '')}
|
||
独特视角:{topic.get('unique_angle', '')}
|
||
|
||
### 当前章节
|
||
## {section_title}
|
||
{section_content}
|
||
|
||
### 输出要求
|
||
- 以 "## {section_title}" 开始
|
||
- 字数:200-300 字(精炼为主)
|
||
- 语言:直白、有冲击力,避免空洞套话
|
||
- 使用 Markdown 格式
|
||
- 每个论点配具体案例或数据支撑
|
||
- 确保与整体文章调性一致
|
||
|
||
直接输出完整 Markdown 章节(包括标题和正文)。""",
|
||
temperature=0.8,
|
||
max_tokens=1000,
|
||
model="stepfun-ai/step-3.5-flash",
|
||
is_active=True
|
||
)
|
||
db.add(default_llm)
|
||
db.commit()
|
||
print("✅ 插入默认 LLM 配置")
|
||
|
||
# 5. 插入系统配置默认值
|
||
default_system_configs = [
|
||
{"key": "collector_enabled", "value": "false", "description": "是否启用采集器"},
|
||
{"key": "scheduler_interval", "value": "daily", "description": "调度间隔:daily/hourly/weekly"},
|
||
]
|
||
for cfg in default_system_configs:
|
||
if db.query(SystemConfig).filter(SystemConfig.key == cfg["key"]).first() is None:
|
||
db.add(SystemConfig(**cfg))
|
||
db.commit()
|
||
print("✅ 插入默认系统配置")
|
||
|
||
# 2. 创建默认管理员用户(bcrypt 哈希)
|
||
admin_exists = db.query(User).filter(User.username == DEFAULT_ADMIN_USERNAME).first()
|
||
if not admin_exists:
|
||
hashed = bcrypt.hashpw(DEFAULT_ADMIN_PASSWORD.encode('utf-8'), bcrypt.gensalt())
|
||
admin = User(
|
||
username=DEFAULT_ADMIN_USERNAME,
|
||
password_hash=hashed.decode('utf-8'),
|
||
role="admin"
|
||
)
|
||
db.add(admin)
|
||
db.commit()
|
||
print(f"✅ 创建默认管理员: {DEFAULT_ADMIN_USERNAME}")
|
||
else:
|
||
# 如果管理员已存在但密码为空,更新为默认密码的哈希
|
||
if not admin_exists.password_hash:
|
||
hashed = bcrypt.hashpw(DEFAULT_ADMIN_PASSWORD.encode('utf-8'), bcrypt.gensalt())
|
||
admin_exists.password_hash = hashed.decode('utf-8')
|
||
db.commit()
|
||
print(f"✅ 更新管理员密码")
|
||
print(f"管理员已存在: {DEFAULT_ADMIN_USERNAME}")
|
||
except Exception as e:
|
||
print(f"初始化失败: {e}")
|
||
db.rollback()
|
||
finally:
|
||
db.close()
|
||
|
||
if __name__ == "__main__":
|
||
init_db()
|
||
import_initial_data()
|