diff --git a/.gitignore b/.gitignore index 95f4ea3..b246617 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# 运行时产物与环境 +# 运行时产物与环境 node_modules dist/ .venv/ @@ -43,5 +43,17 @@ paper_writer_service/paper.db-shm paper_writer_service/paper.db-wal paper_writer_service/paper.log +# review_service 运行时产物(不入库) +review_service/review.db +review_service/review.db-wal +review_service/review.db-shm +review_service/review.log +review_service/data/reformat_jobs/ +# 期刊种子 journals.json 是源码:顶层 **/data/ 会误伤 review_service/data/,显式放行 +!review_service/data/ +review_service/tools/tectonic +review_service/data/tectonic-cache/ +review_service/data/format_cache/ + # 部署方案文档(含主机凭据,不入库) docs/DEPLOY_PAPER_176.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..2303d46 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,54 @@ +# AGENTS.md —— 协作约束(科研审稿模块) + +## 项目背景 + +本项目(PlantAI-rag-new)是植物基因组学文献知识工作台,拥有自研 RAG 与知识库 +(Qdrant + Neo4j + vstore)。2026-10 起新增「科研投稿与智能审稿助手」功能 +(审稿周期/期刊分析/期刊推荐/投稿前自审/审稿意见辅助/格式检查)。 + +## 审稿模块(review_service)约束 —— 必须遵守 + +1. **所有审稿相关新代码只允许写在 `review_service/` 目录下新增**。 + - 服务自身:FastAPI 独立进程,端口 8100(模式同 `paper_writer_service` 8097 / `bioflow_service` 8098)。 + - 环境变量前缀统一 `REVIEW_`;LLM 凭据复用 `DOCGEN_LLM_*` 裸键(回退链见 `review_service/app/services/llm.py`)。 +2. **BFF(`sdk/`)层只允许条件注册代理路由**: + - 允许的全部改动 = `sdk/app/config.py` 增加 `review_enabled` / `review_service_url` 等开关键 + + `sdk/app/main.py` 按开关 `include_router(review_proxy.router)` + + 新文件 `sdk/app/routers/review_proxy.py`(反代实现)。 + - **严禁**修改 sdk 下其他 router/service/db 的任何既有逻辑。 +3. **严禁修改现有 RAG 核心与既有服务代码**,包括但不限于: + - `agent/`(qa 8091 / methodology 8092 / legacy-rag 8093) + - `vstore/`(8094,审稿服务只经 HTTP 只读消费其 `/api/vstore/*` 接口) + - `paper_writer_service/`、`bioflow_service/`、`bioflow_kernel/` + - `ui/`(前端入口另行按 UI_SPEC 流程评审) + - `knowledge/`、`kb-libraries/`、`tooling/`(依赖锁另议) +4. **依赖纪律**:审稿服务只使用统一 venv(`tooling/requirements.lock`)中已有的库 + (fastapi / httpx / pydantic-settings 等)。如确需新增全局依赖, + 须先更新 `tooling/requirements.lock` 并经人工确认。 +5. **上游对接只读**:PDF 解析走 vstore 8094(`POST /api/vstore/ingest` + + `GET/DELETE /api/vstore/documents/{id}`);LLM 走 DeepSeek OpenAI 兼容接口; + 后续期刊数据/期刊推荐等子功能同样以新 service + 新路由在 `review_service/` 内扩展。 +6. **format_check 例外**:format_check 允许用 pymupdf 本地解档获取版式元数据 + (字体/边距/行距/页数),因为 vstore 只回文本不返回版式信息。正文提取仍走 vstore。 + +## 目录速览(审稿模块) + +``` +review_service/ +├── app/main.py # FastAPI 入口(/health + 挂载业务路由) +├── app/config.py # pydantic-settings(REVIEW_ 前缀) +├── app/routers/presubmit.py # POST /api/review/presubmit(自审稿报告) +├── app/routers/format_check.py # POST /api/review/format-check(版式与规范检查) +├── app/services/llm.py # DeepSeek httpx 封装(complete_text/complete_json) +├── app/services/paper_parse.py # PDF → 纯文本(经 vstore 解析接口) +├── app/services/format_check.py# 版式规则引擎(pymupdf/docx 本地解档 + 规则检查) +├── restart.sh # 8100 重启脚本 +└── pytest.ini +``` + +## 启动 + +```bash +cd review_service && bash restart.sh # 默认 8100,venv 从 ../plantai-rag-new-venv 推导 +# BFF 开关:sdk/.env 加 REVIEW_ENABLED=1 后 bff_restart(反代 /api/review/*) +``` diff --git a/review_service/.env.example b/review_service/.env.example new file mode 100644 index 0000000..197247e --- /dev/null +++ b/review_service/.env.example @@ -0,0 +1,27 @@ +# review_service/.env.example —— 运行时配置模板 +# 用法: cp .env.example .env 后填写(.env 已被仓库 .gitignore 忽略,勿提交) +# restart.sh 会 `set -a; source .env` 导出给 uvicorn 进程。 + +# ---- LLM(DeepSeek;REVIEW_LLM_* 优先 → DOCGEN_LLM_* 回退 → 内置默认,见 services/llm.py)---- +# 最简做法:从部署树抄一行即可复用同一把 key: +# grep '^DOCGEN_LLM_API_KEY=' /home/xzq/5090/teamWorkspace/zh/PlantAI-rag-new/sdk/.env >> .env +REVIEW_LLM_BASE_URL=https://api.deepseek.com/v1 +REVIEW_LLM_API_KEY= +REVIEW_LLM_MODEL=deepseek-chat +#REVIEW_LLM_TIMEOUT=300 + +# ---- 上游(只读消费)---- +#REVIEW_VSTORE_BASE_URL=http://127.0.0.1:8094 +#REVIEW_METHODOLOGY_BASE_URL=http://127.0.0.1:8092 # 预留(MinerU 重链路,当前未用) + +# ---- PDF 解析(经 vstore)---- +#REVIEW_PARSE_TIMEOUT=180 # ingest→取文→清理 总读超时(秒) +#REVIEW_PARSE_DELETE_AFTER=1 # 1=解析后删除 vstore 临时文档(0=保留便于排查) + +# ---- 自审稿 ---- +#REVIEW_PRESUBMIT_READ_TIMEOUT=360 # LLM 长调用读超时(秒) +#REVIEW_MAX_TEXT_CHARS=60000 # 送 LLM 的正文截断上限 +#REVIEW_MAX_PDF_BYTES=52428800 # 上传 PDF 上限 50MB + +# ---- 服务(restart.sh 读取)---- +#REVIEW_BIND_HOST=127.0.0.1 diff --git a/review_service/__init__.py b/review_service/__init__.py new file mode 100644 index 0000000..4a7865b --- /dev/null +++ b/review_service/__init__.py @@ -0,0 +1,7 @@ +"""review_service —— 科研投稿与智能审稿助手(8100)。 + +独立部署树(模式同 paper_writer_service 8097 / bioflow_service 8098): +- BFF(sdk 8090) 经 routers/review_proxy.py 条件反代 /api/review/*(REVIEW_ENABLED)。 +- 上游只读消费:vstore 8094(PDF 解析)、DeepSeek(LLM,REVIEW_LLM_*/DOCGEN_LLM_*)。 +- 约束见根目录 AGENTS.md:审稿相关新代码只允许落在本目录。 +""" diff --git a/review_service/app/__init__.py b/review_service/app/__init__.py new file mode 100644 index 0000000..e701edd --- /dev/null +++ b/review_service/app/__init__.py @@ -0,0 +1 @@ +"""review 服务(8100)应用包。""" diff --git a/review_service/app/config.py b/review_service/app/config.py new file mode 100644 index 0000000..780fbfb --- /dev/null +++ b/review_service/app/config.py @@ -0,0 +1,105 @@ +"""config.py —— review 服务(8100)环境变量驱动配置(pydantic-settings)。 + +全部键可用环境变量覆盖(前缀 REVIEW_)。LLM 沿用 docgen 的裸键模式: +优先 REVIEW_LLM_*,回退 DOCGEN_LLM_*(与 paper_writer_service 共享同一套 +DeepSeek 凭据,由 services/llm.py 直接读 os.environ)。零硬编码宿主路径。 +""" +from __future__ import annotations + +from functools import lru_cache +from pathlib import Path + +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class Settings(BaseSettings): + model_config = SettingsConfigDict( + env_file=".env", + env_file_encoding="utf-8", + extra="ignore", + env_prefix="REVIEW_", + ) + + app_name: str = "plantai-review-service" + version: str = "0.1.0" + + # ---- 上游(只读消费;不修改 vstore/methodology 任何代码)---- + # vstore 8094:POST /api/vstore/ingest + GET/DELETE /api/vstore/documents/{id} + # (pymupdf 段落解析,同步秒级;methodology 8092 的 MinerU 链路是 + # 分钟级异步 job,不适配同步自审稿,仅预留地址供后续扩展) + vstore_base_url: str = "http://127.0.0.1:8094" + methodology_base_url: str = "http://127.0.0.1:8092" + + # ---- PDF 解析 ---- + parse_timeout: float = 180.0 # vstore ingest→fetch→delete 读超时(秒) + parse_delete_after: bool = True # 解析完成后删除 vstore 临时文档(不污染私有库) + + # ---- 自审稿(presubmit)---- + presubmit_read_timeout: float = 360.0 # LLM 长调用读超时(秒) + max_text_chars: int = 60000 # 送 LLM 的正文截断上限(约 3 万汉字/6 万字符) + max_pdf_bytes: int = 50 * 1024 * 1024 # 上传 PDF 上限 50MB(对齐 extraction FR-EXTRACT-004) + + # ---- 期刊情报与投稿推荐(recommend)---- + db_path: str = "review.db" # 独立 SQLite(相对 review_service/;REVIEW_DB_PATH 覆盖) + journals_seed_path: str = "data/journals/journals.json" # 种子(相对 review_service/) + vstore_match_timeout: float = 30.0 # scope 入库/向量检索读超时(秒) + recommend_read_timeout: float = 60.0 # LLM 重排读超时(秒) + recommend_query_chars: int = 3000 # 送 vstore 的检索 query 截断(防嵌入模型超长) + recommend_scope_top_k: int = 10 # search-chunks top_k(vstore 上限 20) + + # ---- 论文重排版(reformat,P1:.tex 源码级变换,不编译)---- + max_tex_bytes: int = 2 * 1024 * 1024 # 上传 .tex 上限 2MB(PDF 的 50MB 不适用) + reformat_dir: str = "data/reformat_jobs" # 产物落盘(相对 review_service/) + + # ---- LaTeX 编译 PDF(compile,P3:tectonic 单文件二进制)---- + tectonic_path: str = "tools/tectonic" # 相对 review_service/;也可绝对路径 + tectonic_cache_dir: str = "data/tectonic-cache" # 宏包缓存(部署时预热,运行期只读命中) + compile_timeout_s: float = 60.0 # 单次编译墙钟上限,超时整进程组 kill + max_compile_pdf_bytes: int = 50 * 1024 * 1024 # 产物 PDF 上限 50MB + compile_queue_limit: int = 5 # 等待槽位上限(>5 → QUEUE_FULL 429) + compile_retention_days: int = 7 # 编译产物保留天数(后台清扫) + + @property + def _service_root(self) -> "Path": + # review_service/app/config.py → review_service/(相对本文件定位,不依赖 cwd) + return Path(__file__).resolve().parent.parent + + @property + def db_path_abs(self) -> "Path": + # 绝对 db_path 会被 Path 除法原样返回;相对路径落在 review_service/ 下 + return self._service_root / self.db_path + + @property + def journals_seed_abs(self) -> "Path": + return self._service_root / self.journals_seed_path + + @property + def reformat_dir_abs(self) -> "Path": + p = Path(self.reformat_dir) + return p if p.is_absolute() else self._service_root / p + + @property + def tectonic_abs(self) -> "Path": + p = Path(self.tectonic_path) + return p if p.is_absolute() else self._service_root / p + + @property + def tectonic_cache_abs(self) -> "Path": + p = Path(self.tectonic_cache_dir) + return p if p.is_absolute() else self._service_root / p + + @property + def vstore_base(self) -> str: + return self.vstore_base_url.rstrip("/") + + @property + def methodology_base(self) -> str: + return self.methodology_base_url.rstrip("/") + + +@lru_cache(maxsize=1) +def get_settings() -> Settings: + return Settings() + + +settings = get_settings() diff --git a/review_service/app/db.py b/review_service/app/db.py new file mode 100644 index 0000000..1c312a8 --- /dev/null +++ b/review_service/app/db.py @@ -0,0 +1,191 @@ +"""app/db.py —— review 服务独立 SQLite(aiosqlite + WAL,无 ORM):journals 表。 + +- 单连接 + asyncio 写锁(模式对齐 paper_writer_service/bioflow,但表结构与种子 + 逻辑为本模块自研);路径默认 review_service/review.db(REVIEW_DB_PATH 覆盖)。 +- 种子:data/journals/journals.json → journals 表(幂等 upsert,vstore_doc_id 列 + 永不被种子覆盖——该列记录 scope_desc 在 vstore 8094 的 document_id)。 +- 只在 review_service/ 内使用,不触碰 BFF/生产服务数据库。 +""" +from __future__ import annotations + +import asyncio +import json +from pathlib import Path +from typing import Any, Iterable + +import aiosqlite + +from .config import get_settings + +_SCHEMA = """ +CREATE TABLE IF NOT EXISTS journals ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + scope_desc TEXT NOT NULL, + impact_factor REAL, + review_time_weeks REAL, + acceptance_rate REAL, + submission_deadline TEXT, + official_url TEXT, + last_updated TEXT NOT NULL, + vstore_doc_id TEXT +); +""" + +# 种子 upsert 列(刻意不含 vstore_doc_id:种子刷新不得清掉向量库映射) +_SEED_COLS = ( + "id", + "name", + "scope_desc", + "impact_factor", + "review_time_weeks", + "acceptance_rate", + "submission_deadline", + "official_url", + "last_updated", +) +_UPSERT_SQL = ( + "INSERT INTO journals (" + ", ".join(_SEED_COLS) + ") VALUES (" + + ", ".join("?" for _ in _SEED_COLS) + ") " + + "ON CONFLICT(id) DO UPDATE SET " + + ", ".join(f"{c}=excluded.{c}" for c in _SEED_COLS if c != "id") +) + + +class SeedError(Exception): + """种子文件缺失/损坏(journals.json 不可读)。""" + + +class Database: + """aiosqlite 单连接封装(WAL;写串行化)。""" + + def __init__(self, path: str | Path | None = None) -> None: + self._path: Path | None = Path(path) if path is not None else None + self._conn: aiosqlite.Connection | None = None + self._lock = asyncio.Lock() + + @property + def path(self) -> Path: + if self._path is None: + self._path = get_settings().db_path_abs + return self._path + + def set_path(self, path: str | Path) -> None: + """测试注入:在进入 TestClient lifespan 之前预置库路径(须尚未 connect)。""" + if self._conn is not None: + raise RuntimeError("Database 已连接,无法再改路径(先 close_db())") + self._path = Path(path) + + @property + def connected(self) -> bool: + return self._conn is not None + + async def connect(self) -> None: + self.path.parent.mkdir(parents=True, exist_ok=True) + self._conn = await aiosqlite.connect(self.path) + self._conn.row_factory = aiosqlite.Row + await self._conn.execute("PRAGMA journal_mode=WAL") + await self._conn.execute("PRAGMA busy_timeout=5000") + await self._conn.executescript(_SCHEMA) + await self._conn.commit() + + async def close(self) -> None: + if self._conn is not None: + await self._conn.close() + self._conn = None + + @property + def conn(self) -> aiosqlite.Connection: + if self._conn is None: + raise RuntimeError("Database 未初始化:先 await init_db()") + return self._conn + + async def fetchall(self, sql: str, params: Iterable[Any] = ()) -> list[dict[str, Any]]: + async with self.conn.execute(sql, tuple(params)) as cur: + rows = await cur.fetchall() + return [dict(r) for r in rows] + + async def fetchone(self, sql: str, params: Iterable[Any] = ()) -> dict[str, Any] | None: + async with self.conn.execute(sql, tuple(params)) as cur: + row = await cur.fetchone() + return dict(row) if row is not None else None + + async def execute(self, sql: str, params: Iterable[Any] = ()) -> int: + async with self._lock: + cur = await self.conn.execute(sql, tuple(params)) + await self._conn.commit() # type: ignore[union-attr] + return cur.lastrowid or 0 + + async def executemany(self, sql: str, seq: list[tuple[Any, ...]]) -> None: + async with self._lock: + await self.conn.executemany(sql, seq) + await self._conn.commit() # type: ignore[union-attr] + + +db = Database() + + +async def init_db(path: str | Path | None = None) -> None: + """幂等初始化:已连接则跳过(测试可在 lifespan 前 set_path 注入路径)。""" + if path is not None: + db.set_path(path) + if db.connected: + return + await db.connect() + + +async def close_db() -> None: + await db.close() + + +def set_path(path: str | Path) -> None: + """同步注入库路径(测试 fixture 用;须在 init_db 之前调用)。""" + db.set_path(path) + + +async def ensure_journals_seeded() -> int: + """装载种子期刊(幂等)。返回 journals 表行数。""" + row = await db.fetchone("SELECT COUNT(*) AS c FROM journals") + if row and int(row["c"]) > 0: + return int(row["c"]) + + seed_file = get_settings().journals_seed_abs + try: + payload = json.loads(Path(seed_file).read_text(encoding="utf-8")) + except FileNotFoundError as exc: + raise SeedError(f"期刊种子文件不存在:{seed_file}") from exc + except (OSError, ValueError) as exc: + raise SeedError(f"期刊种子文件不可读:{exc}") from exc + + journals = payload.get("journals") if isinstance(payload, dict) else None + if not isinstance(journals, list) or not journals: + raise SeedError(f"期刊种子文件缺少 journals 数组:{seed_file}") + + rows: list[tuple[Any, ...]] = [] + for item in journals: + if not isinstance(item, dict) or not item.get("id") or not item.get("name"): + continue + rows.append(tuple(item.get(c) for c in _SEED_COLS)) + if not rows: + raise SeedError(f"期刊种子文件无有效条目:{seed_file}") + + await db.executemany(_UPSERT_SQL, rows) + return len(rows) + + +async def list_journals() -> list[dict[str, Any]]: + """全部期刊(impact_factor 降序,NULL 靠后)。""" + return await db.fetchall( + "SELECT * FROM journals ORDER BY impact_factor DESC, name ASC" + ) + + +async def get_journal(journal_id: str) -> dict[str, Any] | None: + return await db.fetchone("SELECT * FROM journals WHERE id = ?", (journal_id,)) + + +async def set_vstore_doc_id(journal_id: str, doc_id: str) -> None: + """记录 scope_desc 在 vstore 的 document_id(向量白名单检索用)。""" + await db.execute( + "UPDATE journals SET vstore_doc_id = ? WHERE id = ?", (doc_id, journal_id) + ) diff --git a/review_service/app/main.py b/review_service/app/main.py new file mode 100644 index 0000000..b130fcc --- /dev/null +++ b/review_service/app/main.py @@ -0,0 +1,90 @@ +"""main.py —— review 服务应用入口(uvicorn 入口)。 + +- 独立部署树 review_service/(科研投稿与智能审稿助手,端口 8100)。 +- 端点:/health(GET,BFF 探活反代)+ /api/review/*(自审稿等业务路由)。 +- 不依赖 BFF/生产服务(8090 等绝不探测/连接);上游仅消费 vstore 8094。 +""" +from __future__ import annotations + +import logging +from contextlib import asynccontextmanager + +import httpx +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + +from .config import get_settings +from .db import close_db, init_db +from .routers import ( + compile, + conferences, + format_check, + journal_directory, + journals, + presubmit, + reformat, +) + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +def create_app() -> FastAPI: + settings = get_settings() + app = FastAPI(title=settings.app_name, version=settings.version) + + app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=False, + allow_methods=["*"], + allow_headers=["*"], + ) + + @asynccontextmanager + async def _lifespan(_app: FastAPI): + # journals 推荐依赖独立 SQLite:启动即建表(幂等;测试可先 set_path 注入 + # tmp 路径,本函数沿用注入路径) + await init_db() + # 编译产物过期清扫:启动跑一次(失败不阻塞启动) + try: + from .services.latex_compile import sweep_expired + sweep_expired() + except Exception: # noqa: BLE001 + logger.warning("compile sweep 启动清扫失败(忽略)", exc_info=True) + try: + yield + finally: + await close_db() + + app.router.lifespan_context = _lifespan + + @app.get("/health") + async def health() -> dict[str, object]: + vstore_ok = False + vstore_error: str | None = None + try: + async with httpx.AsyncClient(timeout=2.0) as client: + resp = await client.get(f"{settings.vstore_base}/api/vstore/health") + resp.raise_for_status() + vstore_ok = bool(resp.json().get("ok")) + except Exception as exc: # noqa: BLE001 + vstore_error = str(exc) + return { + "ok": True, + "status": "ok" if vstore_ok else "degraded", + "upstreams": {"vstore": {"connected": vstore_ok, "error": vstore_error}}, + "version": settings.version, + } + + app.include_router(presubmit.router) + app.include_router(journals.router) + app.include_router(format_check.router) + app.include_router(conferences.router) + app.include_router(journal_directory.router) + app.include_router(reformat.router) + app.include_router(compile.router) + return app + + +app = create_app() diff --git a/review_service/app/routers/__init__.py b/review_service/app/routers/__init__.py new file mode 100644 index 0000000..f026b28 --- /dev/null +++ b/review_service/app/routers/__init__.py @@ -0,0 +1 @@ +"""review 服务路由包。""" diff --git a/review_service/app/routers/compile.py b/review_service/app/routers/compile.py new file mode 100644 index 0000000..86d61ea --- /dev/null +++ b/review_service/app/routers/compile.py @@ -0,0 +1,184 @@ +"""routers/compile.py —— LaTeX 编译 PDF(P3a:tectonic)。 + +端点: + POST /api/review/compile multipart:file(.tex 可选) | job_id(可选,二选一) + → {ok, compile_id, pdf_url, log_url, meta} + GET /api/review/compile/{cid} 编译元信息(meta.json) + GET /api/review/compile/{cid}/pdf output.pdf(FileResponse) + GET /api/review/compile/{cid}/log output.log(text/plain) + +信封:业务错误 = HTTP 200 + {ok:false,error:{code,message,detail?,degraded:false}} +(QUEUE_FULL 例外:HTTP 429 + 同款信封体,前端仍按 ok/error 单一口径处理)。 +detail = log 尾 200 行(COMPILE_FAILED / TIMEOUT)。 +""" +from __future__ import annotations + +import json +import logging +import re +import uuid +from pathlib import Path +from typing import Any + +from fastapi import APIRouter, File, Form, UploadFile +from fastapi.responses import FileResponse, JSONResponse, PlainTextResponse +from pydantic import BaseModel + +from ..config import get_settings +from ..services import latex_compile as lc +from ..services.latex_compile import ( + CompileError, + QueueFullError, + ToolUnavailableError, +) + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/review", tags=["review-compile"]) + +_CID_RE = re.compile(r"^[0-9a-f]{12}$") + + +class CompileResponse(BaseModel): + ok: bool + compile_id: str | None = None + pdf_url: str | None = None + log_url: str | None = None + meta: dict[str, Any] | None = None + error: dict[str, Any] | None = None + + +def _error(code: str, message: str, detail: str = "") -> CompileResponse: + err: dict[str, Any] = {"code": code, "message": message, "degraded": False} + if detail: + err["detail"] = detail + return CompileResponse(ok=False, error=err) + + +def _jobs_root() -> Path: + d = get_settings().reformat_dir_abs + d.mkdir(parents=True, exist_ok=True) + return d + + +@router.post("/compile", response_model=CompileResponse) +async def compile_tex( + file: UploadFile | None = File(None, description="LaTeX 源码(.tex,与 job_id 二选一)"), + job_id: str = Form("", description="P1 重排版任务 id(优先于 file)"), +) -> CompileResponse: + settings = get_settings() + + # ---- 输入解析:job_id 优先,否则直接上传的 .tex ---- + jid = (job_id or "").strip() + if jid: + if not _CID_RE.fullmatch(jid): + return _error("VALIDATION", "job_id 格式非法(应为 12 位 hex)") + src = _jobs_root() / f"{jid}.tex" + if not src.is_file(): + return _error("VALIDATION", "job_id 对应的重排版结果不存在,请重新排版") + try: + source = src.read_text("utf-8") + except UnicodeDecodeError: + return _error("VALIDATION", "任务源码不是合法 UTF-8") + anchor_id = jid + else: + if file is None: + return _error("VALIDATION", "必须提供 file(.tex)或 job_id") + filename = file.filename or "paper.tex" + if Path(filename).name != filename or ".." in filename: + return _error("VALIDATION", "非法文件名") + if not filename.lower().endswith(".tex"): + return _error("VALIDATION", "仅支持 .tex 文件") + content = await file.read() + if not content: + return _error("VALIDATION", "上传文件为空") + if len(content) > settings.max_tex_bytes: + return _error("VALIDATION", "源码超过 2MB 上限") + try: + source = content.decode("utf-8") + except UnicodeDecodeError: + return _error("VALIDATION", "源码必须为 UTF-8 编码") + anchor_id = uuid.uuid4().hex[:12] + + # ---- 编译(隔离目录;失败信封带 log 尾)---- + lc.prepare_input(anchor_id, source) + try: + result = await lc.compile_tex(anchor_id) + except ToolUnavailableError as exc: + return _error("TOOL_UNAVAILABLE", str(exc)) + except QueueFullError as exc: + return JSONResponse( + status_code=429, + content={ + "ok": False, + "compile_id": None, "pdf_url": None, "log_url": None, "meta": None, + "error": {"code": "QUEUE_FULL", "message": str(exc), "degraded": False}, + }, + ) + except CompileError as exc: + return _error(exc.code, str(exc), detail=exc.log_tail) + + meta_path = lc.compile_dir(anchor_id) / "meta.json" + try: + meta = json.loads(meta_path.read_text("utf-8")) + except (OSError, ValueError): + meta = {"compile_id": anchor_id, "seconds": result["seconds"]} + return CompileResponse( + ok=True, + compile_id=anchor_id, + pdf_url=f"/api/review/compile/{anchor_id}/pdf", + log_url=f"/api/review/compile/{anchor_id}/log", + meta=meta, + ) + + +def _cid_dir(cid: str) -> Path | None: + if not _CID_RE.fullmatch(cid or ""): + return None + d = lc.compile_dir(cid) + return d if d.is_dir() else None + + +@router.get("/compile/{compile_id}", response_model=CompileResponse) +async def get_compile(compile_id: str) -> CompileResponse: + cdir = _cid_dir(compile_id) + meta_path = cdir / "meta.json" if cdir else None + if meta_path is None or not meta_path.is_file(): + return _error("NOT_FOUND", "编译任务不存在或已过期,请重新编译") + try: + meta = json.loads(meta_path.read_text("utf-8")) + except (OSError, ValueError): + return _error("NOT_FOUND", "编译产物损坏,请重新编译") + return CompileResponse( + ok=True, + compile_id=compile_id, + pdf_url=f"/api/review/compile/{compile_id}/pdf", + log_url=f"/api/review/compile/{compile_id}/log", + meta=meta, + ) + + +@router.get("/compile/{compile_id}/pdf", response_model=None) +async def download_compile_pdf(compile_id: str) -> FileResponse | JSONResponse: + cdir = _cid_dir(compile_id) + pdf = cdir / "output.pdf" if cdir else None + if pdf is None or not pdf.is_file(): + return JSONResponse( + status_code=200, + content={"ok": False, "error": { + "code": "NOT_FOUND", "message": "PDF 不存在或已过期", "degraded": False}}, + ) + return FileResponse(pdf, media_type="application/pdf", filename=f"{compile_id}.pdf") + + +@router.get("/compile/{compile_id}/log", response_model=None) +async def download_compile_log(compile_id: str) -> PlainTextResponse | JSONResponse: + cdir = _cid_dir(compile_id) + log = cdir / "output.log" if cdir else None + if log is None or not log.is_file(): + return JSONResponse( + status_code=200, + content={"ok": False, "error": { + "code": "NOT_FOUND", "message": "日志不存在或已过期", "degraded": False}}, + ) + return PlainTextResponse(log.read_text("utf-8", errors="replace")) diff --git a/review_service/app/routers/conferences.py b/review_service/app/routers/conferences.py new file mode 100644 index 0000000..fb81b4b --- /dev/null +++ b/review_service/app/routers/conferences.py @@ -0,0 +1,209 @@ +"""routers/conferences.py —— 会议投稿时间线(只读静态种子)。 + +- GET /api/review/conferences?domain=&ccf=&upcoming_days=180 + data/journals/conferences.json → 过滤/排序 → 列表 + meta。 +- 数据诚实性铁律:每条会议必须带 deadline_source ∈ {placeholder, official}、 + last_verified 与 deadline_confidence ∈ {high, medium, low},缺失/非法条目加载时 + 跳过并记日志(宁缺毋造);本端点无任何生成日期的逻辑,日期只来自种子常量。 + v2 共 27/27 全 placeholder,meta.data_source_note 显式声明占位与置信度, + 由前端渲染「⚠ 日期待核验」及置信度提示。 +- 过滤语义:domain 对 domain_tags 精确匹配(大小写不敏感);ccf ∈ {A,B,C}; + upcoming_days=0 不过滤,>0 仅保留 deadline_full_paper ∈ [UTC now, now+N 天], + 缺失/不可解析截稿日期在过滤开启时排除。排序:deadline_full_paper 升序, + 缺失/不可解析恒排最后。 +- 只读无写接口;文件不可读 → ok=false + DATA_UNAVAILABLE 信封;参数非法 → + VALIDATION 信封(均 HTTP 200,对齐本服务"错误信封永远 200"约定)。 +- 静态文件首次请求加载进内存(lru_cache),进程内 O(1);不触碰 SQLite/BFF。 +""" +from __future__ import annotations + +import json +import logging +from datetime import datetime, timedelta, timezone +from functools import lru_cache +from pathlib import Path +from typing import Any + +from fastapi import APIRouter +from pydantic import BaseModel + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/review", tags=["review-conferences"]) + +# review_service/app/routers/ → parents[2] = review_service(对齐 format_check 写法) +_CONFERENCES_PATH = ( + Path(__file__).resolve().parents[2] / "data" / "journals" / "conferences.json" +) + +_CCF_OK = frozenset({"A", "B", "C"}) +_REQUIRED = ("id", "name", "deadline_source", "last_verified", "deadline_confidence") +_CONFIDENCE_OK = frozenset({"high", "medium", "low"}) +_SOURCE_NOTE = ( + "会议截稿/通知日期首版均为占位数据(deadline_source=placeholder)," + "接入官方渠道前须人工核验;deadline_confidence 标注日期置信度" + "(high=官方已公布/历年极稳定,medium=按历年规律推算,low=待核验);" + "所有时间按 AoE (UTC-12) 时区。" +) + + +# ---- 请求/响应模型 ---- + +class ConferenceItem(BaseModel): + """会议公开字段(种子全字段白名单;未知键丢弃)。""" + id: str + name: str + full_name: str = "" + domain_tags: list[str] = [] + application_tags: list[str] = [] + ccf_rank: str | None = None + deadline_abstract: str | None = None + deadline_full_paper: str | None = None + notification_date: str | None = None + conference_date: str | None = None + location: str | None = None + official_url: str | None = None + timezone_note: str | None = None + deadline_source: str + last_verified: str + deadline_confidence: str = "" + + +class ConferencesResponse(BaseModel): + ok: bool + items: list[ConferenceItem] = [] + meta: dict[str, Any] | None = None + error: dict[str, Any] | None = None + + +def _error(code: str, message: str) -> ConferencesResponse: + return ConferencesResponse( + ok=False, items=[], meta=None, + error={"code": code, "message": message, "degraded": False}, + ) + + +# ---- 种子加载(首次调用读盘,进程内缓存)---- + +@lru_cache(maxsize=1) +def _load_conferences() -> list[dict[str, Any]] | None: + """读 conferences.json → 合法会议列表;文件不可读 → None(DATA_UNAVAILABLE)。""" + try: + payload = json.loads(_CONFERENCES_PATH.read_text("utf-8")) + except (OSError, ValueError) as exc: + logger.warning("conferences: 种子文件不可读 %s: %s", _CONFERENCES_PATH, exc) + return None + raw = payload.get("conferences") if isinstance(payload, dict) else None + if not isinstance(raw, list): + logger.warning("conferences: 种子缺少 conferences 数组:%s", _CONFERENCES_PATH) + return None + items: list[dict[str, Any]] = [] + for conf in raw: + if not isinstance(conf, dict): + continue + missing = [k for k in _REQUIRED if not conf.get(k)] + if missing: + logger.warning("conferences: 条目缺字段 %s(id=%s),跳过", missing, conf.get("id")) + continue + if conf.get("deadline_source") not in ("placeholder", "official"): + logger.warning( + "conferences: deadline_source 非法(id=%s),跳过", conf.get("id") + ) + continue + if str(conf.get("deadline_confidence") or "").strip().lower() not in _CONFIDENCE_OK: + logger.warning( + "conferences: deadline_confidence 非法(id=%s),跳过", conf.get("id") + ) + continue + items.append(conf) + return items + + +def _parse_deadline(value: Any) -> datetime | None: + """截稿时间 → aware datetime(naive 视为 UTC);非法 → None。""" + if not isinstance(value, str) or not value.strip(): + return None + try: + dt = datetime.fromisoformat(value.strip()) + except ValueError: + return None + return dt.replace(tzinfo=timezone.utc) if dt.tzinfo is None else dt + + +# ---- GET /api/review/conferences ---- + +@router.get("/conferences", response_model=ConferencesResponse) +async def conferences_list( + domain: str = "", + ccf: str = "", + upcoming_days: int = 180, +) -> ConferencesResponse: + """只读:会议投稿时间线(无写/删/改接口)。 + + - ?domain= 对 domain_tags 精确匹配(大小写不敏感),空=不过滤; + - ?ccf= ccf_rank ∈ A/B/C,空=不过滤,非法值 → VALIDATION 信封; + - ?upcoming_days= int≥0,默认 180;0=不过滤,>0 仅保留截稿在 + [UTC now, now+N 天] 内的会议,负数 → VALIDATION 信封; + - 排序按 deadline_full_paper 升序,缺失/不可解析恒排最后; + - 空结果 → items=[] + meta.count=0(HTTP 200,不报错)。 + """ + ccf_norm = (ccf or "").strip().upper() + if ccf_norm and ccf_norm not in _CCF_OK: + return _error("VALIDATION", f"不支持的 ccf={ccf!r},可选:A / B / C") + if upcoming_days < 0: + return _error( + "VALIDATION", f"upcoming_days 必须 ≥ 0,收到 {upcoming_days}" + ) + + all_items = _load_conferences() + if all_items is None: + return _error("DATA_UNAVAILABLE", "会议种子数据不可读,请联系管理员") + + items = list(all_items) + + dom = (domain or "").strip().casefold() + if dom: + items = [ + c for c in items + if any( + str(t).strip().casefold() == dom + for t in (c.get("domain_tags") or []) + ) + ] + if ccf_norm: + items = [ + c for c in items + if str(c.get("ccf_rank") or "").strip().upper() == ccf_norm + ] + if upcoming_days > 0: + now = datetime.now(timezone.utc) + limit = now + timedelta(days=upcoming_days) + items = [ + c for c in items + if (dl := _parse_deadline(c.get("deadline_full_paper"))) is not None + and now <= dl <= limit + ] + + def _sort_key(c: dict[str, Any]) -> tuple[bool, datetime]: + dl = _parse_deadline(c.get("deadline_full_paper")) + if dl is None: + return (True, datetime.max.replace(tzinfo=timezone.utc)) + return (False, dl) + + items.sort(key=_sort_key) + + out = [ConferenceItem(**c) for c in items] + verified = max( + (str(c.get("last_verified") or "") for c in all_items), default="" + ) + meta: dict[str, Any] = { + "count": len(out), + "last_verified": verified or None, + "data_source_note": _SOURCE_NOTE, + "query": { + "domain": (domain or "").strip(), + "ccf": ccf_norm, + "upcoming_days": upcoming_days, + }, + } + return ConferencesResponse(ok=True, items=out, meta=meta, error=None) diff --git a/review_service/app/routers/format_check.py b/review_service/app/routers/format_check.py new file mode 100644 index 0000000..e6a467e --- /dev/null +++ b/review_service/app/routers/format_check.py @@ -0,0 +1,81 @@ +"""routers/format_check.py —— 版式与规范检查(POST /api/review/format-check)。 + +纯规则引擎(services/format_check.py):PDF/Word 本地解档取版式元数据 + +journals.json 规则集(format_rules_default + 每条 format_rules 带 rules_source)。 +无 LLM / 无 vstore,同步执行通常 <1s;恒 200 + {ok, checks, summary, meta|error} 信封。 +""" +from __future__ import annotations + +import logging + +from fastapi import APIRouter, File, Form, UploadFile +from pydantic import BaseModel + +from ..config import get_settings +from ..services import format_check + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/review", tags=["review-format"]) + + +class CheckItem(BaseModel): + key: str + name: str + status: str # pass | warn | fail + detail: str + suggestion: str = "" + + +class FormatCheckResponse(BaseModel): + ok: bool + checks: list[CheckItem] | None = None + summary: dict[str, int] | None = None + meta: dict[str, object] | None = None + error: dict[str, object] | None = None + + +def _error(code: str, message: str, *, degraded: bool = False) -> FormatCheckResponse: + return FormatCheckResponse( + ok=False, error={"code": code, "message": message, "degraded": degraded}, + ) + + +@router.post("/format-check", response_model=FormatCheckResponse) +async def format_check_endpoint( + file: UploadFile = File(..., description="待检查的 PDF / Word(.docx) / LaTeX(.tex) 文档"), + target_journal: str = Form("", description="目标期刊(可选,传 journals 的 id)"), +) -> FormatCheckResponse: + settings = get_settings() + + filename = file.filename or "" + low = filename.lower() + if low.endswith(".pdf"): + kind = "pdf" + elif low.endswith(".docx"): + kind = "docx" + elif low.endswith(".tex"): + kind = "tex" + else: + return _error("VALIDATION", "仅支持 PDF / Word(.docx)/ LaTeX(.tex)文件") + + content = await file.read() + if not content: + return _error("VALIDATION", "上传文件为空") + if len(content) > settings.max_pdf_bytes: + return _error("VALIDATION", "上传文件超过 50MB 上限") + + try: + result = format_check.check_document(content, kind, (target_journal or "").strip()) + except format_check.FormatCheckError as exc: + logger.warning("format-check: 解档失败:%s", exc) + return _error("PARSE_FAILED", str(exc)) + + meta = dict(result.get("meta") or {}) + meta["filename"] = filename + return FormatCheckResponse( + ok=True, + checks=[CheckItem(**c) for c in result["checks"]], + summary=result["summary"], + meta=meta, + ) diff --git a/review_service/app/routers/journal_directory.py b/review_service/app/routers/journal_directory.py new file mode 100644 index 0000000..113ddcc --- /dev/null +++ b/review_service/app/routers/journal_directory.py @@ -0,0 +1,280 @@ +"""routers/journal_directory.py —— 期刊目录浏览(1056 本,只读分页)。 + +- GET /api/review/journals/directory:journal_directory 表(scripts/import_journals.py + 导入的 v4 目录:2025 中科院分区 + 2025 JIF(2026 年 JCR 发布)+ 年报 2025 版 + (中文统计年 2024)+ 官网网址/核对状态)→ 过滤/排序/分页 → 列表 + meta。 +- 与 GET /journals(journals.json 精选 5 本,供 FormatPanel 下拉/recommend 语义)物理 + 分离(方案 A);本端点绝不读写 journals 表,recommend/journal_kb/journal_rank 零触碰。 +- 读路径只 SELECT;表由导入脚本拥有(db.py 零改动);表不存在 → data_imported=false + 优雅降级(HTTP 200 空列表)。 + +读时归一化(拍板细节 1-3,均在 API 层做,不动脚本/DB 原值): + 细节1 lang=zh → cas_partition 恒 null + cas_partition_note="不按中科院分区口径列示"; + 细节2 jif_note 源文本映射(v4 值域已是用户可读文本,旧值映射保留兜底); + 细节3 缺值即矛盾清零:en 且 jif=null → jif_source_url=null。 + (zh 的 IF 载体是 composite/comprehensive,其 jif_source_url 本恒 null。) + 决策2:响应不下发"来源"文本字段(partition_source/jif_source/data_source_label + 已移除);jif_source_url/data_source_url 保留供展开行链接。 + 决策4(来源展示优化):partition_source_url 不再下发——DB 原值分毫未动 + (仍 SELECT * 读出后被模型丢弃),响应改为常量字段 partition_source_note + 文案,前端以灰色说明文字替代原"分区来源"超链接。 + 新增 official_check_status / jcr_release_year。 +""" +from __future__ import annotations + +import json +import logging +import sqlite3 +from typing import Any + +from fastapi import APIRouter +from pydantic import BaseModel + +from ..db import db + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/review", tags=["review-directory"]) + +_LANGS = frozenset({"en", "zh"}) +# 排序列白名单(列名不可参数化 → 白名单防注入) +_FIELDS = frozenset({ + "name", + "jif", + "composite_impact_factor", + "comprehensive_impact_factor", + "research_direction", + "cas_partition", +}) +_ORDERS = frozenset({"asc", "desc"}) +_PARTS = {"1": "1区", "2": "2区", "3": "3区", "4": "4区"} +_MAX_SIZE = 200 + +# 细节2:源核对状态 → 用户可读 note +_JIF_NOTE_MAP = { + "源表标N/A": "未被2024 JCR收录", + "所用年度来源未检得": "本次汇编未查到,建议查阅最新 JCR", +} +_ZH_PART_NOTE = "不按中科院分区口径列示" +# 决策4:分区来源改为常量说明文案(不下发 partition_source_url;DB 原值不动) +_PARTITION_SOURCE_NOTE = ( + "2025 中科院官方表(2026 年起停更;官方入口 fenqubiao.com 需机构登录)" +) + +_NOTE_EN = ( + "分区:2025年中科院公开表(多表比对,2026年起停止更新);" + "JIF:2025年度指标(2026年JCR发布,两份公开汇编一致或已核对出版社官方指标);" + "整理日期2026-10-10。空白=来源未给值≠0;研究方向/期刊标记/文章类型为导航标签,非官方评级。" +) +_NOTE_ZH = ( + "指标:国内自然科学期刊年报2025版(统计年2024,official,含复合/综合IF两口径);" + "中文期刊不按中科院分区口径列示;国内IF与JIF统计源不同,不可混排。" +) +_UNIMPORTED_NOTE = "目录数据未导入(请先运行 scripts/import_journals.py)" + + +# ---- 响应模型 ---- + +class DirectoryItem(BaseModel): + """目录公开字段(DB 全列白名单;imported_at 等内部列丢弃)。""" + id: str + lang: str + name: str + research_direction: str | None = None + cas_partition: str | None = None + cas_partition_note: str | None = None + cas_partition_year: int | None = None + jif: float | None = None + jif_year: int | None = None + jif_note: str | None = None + jif_check_status: str | None = None + composite_impact_factor: float | None = None + comprehensive_impact_factor: float | None = None + metric_year: int | None = None + metric_report_year: int | None = None + metric_caliber: str | None = None + annual_report_page: int | None = None + top_flag: str | None = None + publisher_series: str | None = None + journal_mark: str | None = None + article_type: str | None = None + issn: str | None = None + eissn: str | None = None + jcr_disciplines: list[str] = [] + supplement_note: str | None = None + evidence_note: str | None = None + official_url: str | None = None + official_check_status: str | None = None + jcr_release_year: int | None = None + jif_source_url: str | None = None + partition_source_note: str = _PARTITION_SOURCE_NOTE # 决策4:常量,替代分区来源链接 + data_source_url: str | None = None + + +class DirectoryResponse(BaseModel): + ok: bool + items: list[DirectoryItem] = [] + meta: dict[str, Any] | None = None + error: dict[str, Any] | None = None + + +def _error(code: str, message: str) -> DirectoryResponse: + return DirectoryResponse( + ok=False, items=[], meta=None, + error={"code": code, "message": message, "degraded": False}, + ) + + +# ---- 读时归一化(拍板细节 1-3)---- + +def _present(raw: dict[str, Any], lang: str) -> dict[str, Any]: + d = dict(raw) + # jcr_disciplines:JSON 数组字符串 → list + jcr = d.get("jcr_disciplines") + if jcr: + try: + parsed = json.loads(jcr) + d["jcr_disciplines"] = parsed if isinstance(parsed, list) else [] + except (TypeError, ValueError): + d["jcr_disciplines"] = [] + else: + d["jcr_disciplines"] = [] + + # 细节2:jif_note 源文本 → 用户可读 + note = d.get("jif_note") + if note in _JIF_NOTE_MAP: + d["jif_note"] = _JIF_NOTE_MAP[note] + + # 细节1:zh 分区归一(DB 原值"不按此口径列示"只留在库里) + if lang == "zh": + d["cas_partition"] = None + d["cas_partition_note"] = _ZH_PART_NOTE + + # 细节3:缺值 → 来源链接清零(消除 null 值却挂来源链接的矛盾; + # 分区来源链接已按决策4 移出响应,改为常量 partition_source_note) + if lang == "en": + if d.get("jif") is None: + d["jif_source_url"] = None + return d + + +def _escape_like(s: str) -> str: + return s.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_") + + +# ---- GET /api/review/journals/directory ---- + +@router.get("/journals/directory", response_model=DirectoryResponse) +async def journals_directory( + lang: str = "en", + domain: str = "", + cas_partition: str = "", + q: str = "", + page: int = 1, + size: int = 50, + field: str = "", + order: str = "", +) -> DirectoryResponse: + """只读:期刊目录分页浏览(无写接口)。 + + - ?lang=en|zh(默认 en;**强制单语,保证国际/中文永不混排**); + - ?domain= 研究方向精确匹配;?cas_partition=1|2|3|4(仅 lang=en,zh 忽略); + - ?q= 期刊名模糊(ASCII 大小写不敏感);?page≥1 ?size 1-200(默认 50); + - ?field= 排序白名单(name/jif/composite_impact_factor/ + comprehensive_impact_factor/research_direction/cas_partition),?order=asc|desc; + 未传 field → 默认排序 en=jif 降序 / zh=复合IF 降序(NULL 恒排最后); + - 参数非法 → VALIDATION 信封;表不存在 → data_imported=false 空列表(HTTP 200)。 + """ + lang_n = (lang or "").strip().lower() + if lang_n not in _LANGS: + return _error("VALIDATION", f"不支持的 lang={lang!r},可选:en / zh") + if page < 1: + return _error("VALIDATION", f"page 必须 ≥ 1,收到 {page}") + if size < 1 or size > _MAX_SIZE: + return _error("VALIDATION", f"size 必须在 1-{_MAX_SIZE},收到 {size}") + field_n = (field or "").strip() + if field_n and field_n not in _FIELDS: + return _error( + "VALIDATION", + f"不支持的 field={field!r},可选:{', '.join(sorted(_FIELDS))}", + ) + order_n = (order or "").strip().lower() + if order_n and order_n not in _ORDERS: + return _error("VALIDATION", f"不支持的 order={order!r},可选:asc / desc") + part_q = (cas_partition or "").strip() + if part_q: + part_q = _PARTS.get(part_q, _PARTS.get(part_q.rstrip("区").strip(), "")) + if not part_q: + return _error( + "VALIDATION", + f"不支持的 cas_partition={cas_partition!r},可选:1 / 2 / 3 / 4", + ) + + # 过滤条件(白名单拼接;参数全部占位符) + where = ["lang = ?"] + params: list[Any] = [lang_n] + domain_n = (domain or "").strip() + if domain_n: + where.append("research_direction = ?") + params.append(domain_n) + if part_q and lang_n == "en": # zh 不分区:忽略(meta 回显) + where.append("cas_partition = ?") + params.append(part_q) + q_n = (q or "").strip() + if q_n: + where.append("name LIKE ? ESCAPE '\\'") + params.append(f"%{_escape_like(q_n)}%") + where_sql = " AND ".join(where) + + # 排序(列名出自白名单;NULL 恒排最后) + if field_n: + dir_sql = "DESC" if order_n == "desc" else "ASC" + order_sql = f"{field_n} IS NULL, {field_n} {dir_sql}" + else: + col = "jif" if lang_n == "en" else "composite_impact_factor" + order_sql = f"{col} IS NULL, {col} DESC" + + try: + total_row = await db.fetchone( + f"SELECT COUNT(*) AS c FROM journal_directory WHERE {where_sql}", params # noqa: S608 + ) + total = int(total_row["c"]) if total_row else 0 + rows = await db.fetchall( + f"SELECT * FROM journal_directory WHERE {where_sql} " # noqa: S608 + f"ORDER BY {order_sql} LIMIT ? OFFSET ?", + [*params, size, (page - 1) * size], + ) + dom_rows = await db.fetchall( + "SELECT research_direction AS d, COUNT(*) AS c FROM journal_directory " + "WHERE lang = ? AND research_direction IS NOT NULL " + "GROUP BY 1 ORDER BY c DESC, d ASC", + [lang_n], + ) + except sqlite3.OperationalError as exc: + # 表不存在(脚本未跑)→ 优雅降级,HTTP 200 + logger.warning("journal_directory: 表不可用(目录未导入?): %s", exc) + return DirectoryResponse( + ok=True, items=[], + meta={ + "total": 0, "page": page, "size": size, "lang": lang_n, + "domain": domain_n, "cas_partition": part_q, "q": q_n, + "domains": [], "data_source_note": _UNIMPORTED_NOTE, + "data_imported": False, + }, + error=None, + ) + + items = [DirectoryItem(**_present(dict(r), lang_n)) for r in rows] + meta: dict[str, Any] = { + "total": total, + "page": page, + "size": size, + "lang": lang_n, + "domain": domain_n, + "cas_partition": part_q if lang_n == "en" else "", + "q": q_n, + "domains": [r["d"] for r in dom_rows if r["d"]], + "data_source_note": _NOTE_EN if lang_n == "en" else _NOTE_ZH, + "data_imported": True, + } + return DirectoryResponse(ok=True, items=items, meta=meta, error=None) diff --git a/review_service/app/routers/journals.py b/review_service/app/routers/journals.py new file mode 100644 index 0000000..16d3036 --- /dev/null +++ b/review_service/app/routers/journals.py @@ -0,0 +1,354 @@ +"""routers/journals.py —— 期刊情报与智能投稿推荐。 + +- GET /api/review/journals 只读:journals 表全量列表(?field=/&order= 排序), + meta 含 count / last_updated / data_source_note。无任何写接口;空表返回 + 空数组 + meta.count=0(HTTP 200,绝不 500)。 +- POST /api/review/recommend 智能投稿推荐:vstore 向量匹配(摘要 vs + scope_desc,白名单检索)→ LLM 按 id 白名单重排(幻觉期刊丢弃、缺漏规则 + 补位)→ 三档输出:挑战型 / 适配型 / 稳妥型,附匹配理由与风险提示。 + +降级哲学(同 presubmit):向量失败 → 全量候选 + vector_ok=false; +LLM 失败 → 规则分档 + llm_ok=false;推荐永不 5xx。仅入参非法返回 +VALIDATION 错误信封(HTTP 200,与本服务其余端点一致)。 +""" +from __future__ import annotations + +import json +import logging +from functools import lru_cache +from pathlib import Path +from typing import Any, Literal + +from fastapi import APIRouter +from pydantic import BaseModel, Field + +from ..config import get_settings +from ..db import SeedError, ensure_journals_seeded, list_journals +from ..services import journal_kb, journal_rank, llm + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/review", tags=["review-journals"]) + + +# ---- 请求/响应模型 ---- + +class Preferences(BaseModel): + max_review_weeks: float | None = Field(default=None, ge=1, le=104) + min_impact_factor: float | None = Field(default=None, ge=0, le=200) + tier_focus: Literal["all", "challenge", "fit", "safe"] = "all" + + +class RecommendRequest(BaseModel): + abstract: str + preferences: Preferences = Preferences() + + +class JournalItem(BaseModel): + id: str + name: str + impact_factor: float | None = None + review_time_weeks: float | None = None + acceptance_rate: float | None = None + official_url: str | None = None + similarity: float | None = None + tier: str + match_reason: str + risk_note: str + + +class TierBox(BaseModel): + label: str + items: list[JournalItem] + + +class RecommendResponse(BaseModel): + ok: bool + tiers: dict[str, TierBox] | None = None + meta: dict[str, Any] | None = None + error: dict[str, Any] | None = None + + +# ---- GET /api/review/journals(只读列表)---- + +class JournalBrief(BaseModel): + """期刊公开字段(journals 表全列;不含 vstore_doc_id 内部映射)。 + + 标签/分区 6 字段不进 SQLite:GET 时按 id 从 journals.json 内存缓存合并; + JSON 缺该 id → 空数组/null 默认值。 + """ + id: str + name: str + scope_desc: str = "" + impact_factor: float | None = None + review_time_weeks: float | None = None + acceptance_rate: float | None = None + submission_deadline: str | None = None + official_url: str | None = None + last_updated: str = "" + scope_tags: list[str] = [] + application_tags: list[str] = [] + cas_partition: str | None = None + jcr_quartile: str | None = None + partition_source: str | None = None + cross_domain: list[str] = [] + + +class JournalsListResponse(BaseModel): + ok: bool + items: list[JournalBrief] = [] + meta: dict[str, Any] | None = None + error: dict[str, Any] | None = None + + +# ?field= 排序白名单(列名无法参数化,白名单防注入;非法值 → VALIDATION 信封) +_SORT_FIELDS = frozenset({ + "id", + "name", + "impact_factor", + "review_time_weeks", + "acceptance_rate", + "last_updated", +}) +_DATA_SOURCE_NOTE = ( + "IF/审稿周期为公开近似值,acceptance_rate 为 null 表示暂无公开数据,需人工核验。" + "CAS/JCR 分区为首版占位数据,需核验。" +) + +# journals.json 新增字段(标签/分区;刻意不进 SQLite,见 C-2 方案) +_TAG_FIELDS = ( + "scope_tags", + "application_tags", + "cas_partition", + "jcr_quartile", + "partition_source", + "cross_domain", +) + + +@lru_cache(maxsize=1) +def _load_tag_extras() -> dict[str, dict[str, Any]]: + """journals.json 标签/分区字段 → {id: {6 新字段}}。 + + 首次请求读盘后进程内缓存,后续 GET O(1) 按 id 合并(不做每请求磁盘 IO)。 + JSON 缺该 id → 合并时用空数组/null 默认;文件不可读 → 空 dict 降级(不 500)。 + """ + seed = get_settings().journals_seed_abs + try: + payload = json.loads(Path(seed).read_text("utf-8")) + except (OSError, ValueError) as exc: + logger.warning("journals: 标签扩展文件不可读,合并降级为默认值:%s", exc) + return {} + raw = payload.get("journals") if isinstance(payload, dict) else None + if not isinstance(raw, list): + return {} + out: dict[str, dict[str, Any]] = {} + for j in raw: + if isinstance(j, dict) and j.get("id"): + out[str(j["id"])] = {k: j.get(k) for k in _TAG_FIELDS} + return out + + +def _tag_fields(extra: dict[str, Any] | None) -> dict[str, Any]: + """缓存条目 → JournalBrief 关键字参数(JSON 缺该 id → 空数组/null 默认)。""" + ex = extra or {} + return { + "scope_tags": list(ex.get("scope_tags") or []), + "application_tags": list(ex.get("application_tags") or []), + "cas_partition": ex.get("cas_partition"), + "jcr_quartile": ex.get("jcr_quartile"), + "partition_source": ex.get("partition_source"), + "cross_domain": list(ex.get("cross_domain") or []), + } + + +def _sort_rows(rows: list[dict[str, Any]], field: str, order: str) -> list[dict[str, Any]]: + """按白名单字段排序;NULL 恒排最后;次序不稳定时按 db 默认序(稳定排序保留)。""" + present = [r for r in rows if r.get(field) is not None] + missing = [r for r in rows if r.get(field) is None] + present.sort(key=lambda r: r.get(field), reverse=(order == "desc")) + return present + missing + + +def _list_error(message: str) -> JournalsListResponse: + return JournalsListResponse( + ok=False, items=[], meta=None, + error={"code": "VALIDATION", "message": message, "degraded": False}, + ) + + +@router.get("/journals", response_model=JournalsListResponse) +async def journals_list( + field: str = "name", + order: str = "asc", +) -> JournalsListResponse: + """只读:journals 表全量列表(无写/删/改接口)。 + + - ?field= 排序字段白名单:id/name/impact_factor/review_time_weeks/ + acceptance_rate/last_updated,默认 name; + - ?order=asc|desc,默认 asc; + - 空表 → items=[] + meta.count=0(HTTP 200,不报错)。种子装载由 + POST /recommend 首次调用幂等完成,本端点严格只读。 + """ + col = (field or "").strip() + if col not in _SORT_FIELDS: + return _list_error( + f"不支持的排序字段 field={field!r},可选:{', '.join(sorted(_SORT_FIELDS))}" + ) + ord_norm = (order or "asc").strip().lower() + if ord_norm not in ("asc", "desc"): + return _list_error(f"不支持的排序方向 order={order!r},可选:asc, desc") + + rows = await list_journals() + rows = _sort_rows(rows, col, ord_norm) + + tag_extras = _load_tag_extras() + items = [ + JournalBrief( + id=str(r.get("id") or ""), + name=str(r.get("name") or ""), + scope_desc=str(r.get("scope_desc") or ""), + impact_factor=r.get("impact_factor"), + review_time_weeks=r.get("review_time_weeks"), + acceptance_rate=r.get("acceptance_rate"), + submission_deadline=r.get("submission_deadline"), + official_url=r.get("official_url"), + last_updated=str(r.get("last_updated") or ""), + **_tag_fields(tag_extras.get(str(r.get("id") or ""))), + ) + for r in rows + ] + latest = max((str(r.get("last_updated") or "") for r in rows), default="") + meta: dict[str, Any] = { + "count": len(items), + "last_updated": latest or None, + "data_source_note": _DATA_SOURCE_NOTE, + } + return JournalsListResponse(ok=True, items=items, meta=meta, error=None) + + +def _error(code: str, message: str, *, degraded: bool = False) -> RecommendResponse: + return RecommendResponse( + ok=False, tiers=None, meta=None, + error={"code": code, "message": message, "degraded": degraded}, + ) + + +def _item_sort_key(it: JournalItem) -> tuple[int, float, float]: + return ( + 1 if it.similarity is None else 0, + -(it.similarity or 0.0), + -(it.impact_factor or 0.0), + ) + + +def _apply_soft_preferences(item: JournalItem, prefs: Preferences) -> None: + """软偏好:不满足只加风险提示,不删条目。""" + weeks = item.review_time_weeks + if prefs.max_review_weeks is not None and weeks is not None and weeks > prefs.max_review_weeks: + prefix = f"⚠ 审稿约 {weeks:g} 周,超出你 {prefs.max_review_weeks:g} 周的周期偏好;" + item.risk_note = prefix + ("无" if item.risk_note == "无" else item.risk_note) + inf = item.impact_factor + if prefs.min_impact_factor is not None: + if inf is None: + item.risk_note = "⚠ 影响因子未收录,无法确认满足你的要求;" + item.risk_note + elif inf < prefs.min_impact_factor: + prefix = f"⚠ 影响因子 {inf:g} 低于你 {prefs.min_impact_factor:g} 的要求;" + item.risk_note = prefix + ("无" if item.risk_note == "无" else item.risk_note) + + +@router.post("/recommend", response_model=RecommendResponse) +async def recommend(req: RecommendRequest) -> RecommendResponse: + settings = get_settings() + + # ---- 入参校验(手动,错误信封与本服务其余端点一致)---- + abstract = (req.abstract or "").strip() + if len(abstract) < 50: + return _error("VALIDATION", "abstract 至少需要 50 个字符(请提供摘要或正文片段)") + if len(abstract) > 20000: + return _error("VALIDATION", "abstract 超过 20000 字符上限") + + prefs = req.preferences + + # ---- 种子 + 期刊元数据 ---- + try: + await ensure_journals_seeded() + journals = await list_journals() + except SeedError as exc: + logger.error("recommend: 种子装载失败:%s", exc) + return _error("SEED_UNAVAILABLE", str(exc), degraded=True) + if not journals: + return _error("SEED_UNAVAILABLE", "期刊库为空", degraded=True) + + # ---- ① vstore 向量匹配(摘要 vs scope_desc)---- + try: + candidates, vector_ok = await journal_kb.match(abstract, journals) + except journal_kb.MatchError as exc: + logger.warning("recommend: 向量匹配降级:%s", exc) + candidates, vector_ok = [], False + if not candidates: + # 无有效语义分 → 全量候选(similarity=None),LLM 仍可按 scope 文本重排 + candidates = [{"journal": j, "similarity": None} for j in journals] + vector_ok = False + + # ---- ② LLM 重排(id 白名单硬校验)---- + prefs_dict = prefs.model_dump(exclude_none=True) + llm_ok = True + dropped = 0 + repaired = 0 + try: + rankings, dropped, repaired = await journal_rank.rerank(abstract, candidates, prefs_dict) + except (llm.LLMError, journal_rank.RankError, ValueError) as exc: + # ValueError:complete_json 最终 json.loads 修复仍失败(同 presubmit 宽容口径) + logger.warning("recommend: LLM 重排降级为规则分档:%s", exc) + rankings = journal_rank.fallback_rankings(candidates) + llm_ok = False + + # ---- ③ 三档组装(名称/指标全部来自 DB,不采信 LLM 文本)---- + by_id = {str(c["journal"]["id"]): c for c in candidates} + tiers: dict[str, list[JournalItem]] = {t: [] for t in journal_rank.TIERS} + for r in rankings: + cand = by_id.get(r.journal_id) + if cand is None: + continue + j = cand["journal"] + sim = cand.get("similarity") + item = JournalItem( + id=str(j["id"]), + name=str(j.get("name") or j["id"]), + impact_factor=j.get("impact_factor"), + review_time_weeks=j.get("review_time_weeks"), + acceptance_rate=j.get("acceptance_rate"), + official_url=j.get("official_url"), + similarity=round(float(sim), 4) if sim is not None else None, + tier=r.tier, + match_reason=r.match_reason, + risk_note=r.risk_note, + ) + _apply_soft_preferences(item, prefs) + tiers.setdefault(r.tier, []).append(item) + + # 档内排序:相似度(None 靠后)→ 影响因子 + for box in tiers.values(): + box.sort(key=_item_sort_key) + + # tier_focus:软展示聚焦(默认 all;聚焦时其余档 items 置空,label 保留) + out_tiers: dict[str, TierBox] = {} + for t in journal_rank.TIERS: + items = tiers.get(t, []) + if prefs.tier_focus != "all" and t != prefs.tier_focus: + items = [] + out_tiers[t] = TierBox(label=journal_rank.TIER_LABELS[t], items=items) + + meta: dict[str, Any] = { + "model": llm._llm_config()["model"], + "vector_ok": vector_ok, + "llm_ok": llm_ok, + "seed_count": len(journals), + "candidate_count": len(candidates), + "dropped_hallucinated": dropped, + "repaired": repaired, + "preferences": prefs_dict, + "abstract_chars": len(abstract), + } + return RecommendResponse(ok=True, tiers=out_tiers, meta=meta, error=None) diff --git a/review_service/app/routers/presubmit.py b/review_service/app/routers/presubmit.py new file mode 100644 index 0000000..f15b69e --- /dev/null +++ b/review_service/app/routers/presubmit.py @@ -0,0 +1,87 @@ +"""routers/presubmit.py —— 投稿前自审稿(POST /api/review/presubmit)。 + +流程:上传 PDF → paper_parse(vstore 8094 解析)→ LLM 结构化审稿 +(DeepSeek json_object,System Prompt 为植物基因组学六维专属清单, +见 services/self_review.py)→ 归一化为 SelfReviewReport。 +""" +from __future__ import annotations + +import logging + +from fastapi import APIRouter, File, Form, UploadFile +from pydantic import BaseModel + +from ..config import get_settings +from ..services import llm, paper_parse, self_review + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/review", tags=["review-presubmit"]) + + +class PresubmitResponse(BaseModel): + ok: bool + report: self_review.SelfReviewReport | None = None + error: dict[str, object] | None = None + meta: dict[str, object] | None = None + + +def _error(code: str, message: str, *, degraded: bool = False) -> PresubmitResponse: + return PresubmitResponse( + ok=False, report=None, + error={"code": code, "message": message, "degraded": degraded}, + ) + + +@router.post("/presubmit", response_model=PresubmitResponse) +async def presubmit_review( + file: UploadFile = File(..., description="待审稿 PDF"), + target_journal: str = Form("", description="目标期刊(可选,影响格式类意见)"), +) -> PresubmitResponse: + settings = get_settings() + + filename = file.filename or "paper.pdf" + if not filename.lower().endswith(".pdf"): + return _error("VALIDATION", "仅支持 PDF 文件") + + content = await file.read() + if not content: + return _error("VALIDATION", "上传文件为空") + if len(content) > settings.max_pdf_bytes: + return _error("VALIDATION", "PDF 超过 50MB 上限") + + # ---- 解析(vstore 8094)---- + try: + text = await paper_parse.parse_pdf_bytes(content, filename=filename) + except paper_parse.ParseError as exc: + logger.warning("presubmit: 解析失败:%s", exc) + return _error("PARSE_FAILED", str(exc), degraded=True) + + truncated = len(text) > settings.max_text_chars + feed_text = text[: settings.max_text_chars] + + # ---- LLM 结构化自审(植物基因组学六维清单)---- + try: + payload = await llm.complete_json( + self_review.SYSTEM_PROMPT, + self_review.build_user_prompt(feed_text, (target_journal or "").strip()), + temperature=0.2, + max_tokens=8000, + timeout=settings.presubmit_read_timeout, + ) + except llm.LLMError as exc: + logger.error("presubmit: LLM 审稿失败:%s", exc) + return _error("UPSTREAM_DOWN", f"审稿模型调用失败:{exc}", degraded=True) + + report = self_review.coerce_report(payload) + return PresubmitResponse( + ok=True, + report=report, + meta={ + "filename": filename, + "target_journal": (target_journal or "").strip(), + "text_chars": len(feed_text), + "truncated": truncated, + "model": llm._llm_config()["model"], + }, + ) diff --git a/review_service/app/routers/reformat.py b/review_service/app/routers/reformat.py new file mode 100644 index 0000000..a5b835f --- /dev/null +++ b/review_service/app/routers/reformat.py @@ -0,0 +1,165 @@ +"""routers/reformat.py —— 论文自动排版 P1(.tex 源码级重排版,不编译)。 + +端点: + POST /api/review/reformat multipart 上传 .tex + target_journal → + 修改后源码 + 逐行 diff 报告(job 落盘) + GET /api/review/reformat/{id} 取完整报告(重启后仍在) + GET /api/review/reformat/{id}/file 下载修改后的 .tex + +信封与其余 review 端点一致:业务错误 = HTTP 200 + {ok:false,error:{code,message,degraded:false}}, +前端经 review.js unwrap 归一为 ApiError。本次改动无上游依赖(零 LLM/零 vstore), +degraded 恒 false。 +""" +from __future__ import annotations + +import hashlib +import json +import logging +import re +import uuid +from datetime import datetime, timezone +from pathlib import Path +from typing import Any + +from fastapi import APIRouter, File, Form, UploadFile +from fastapi.responses import FileResponse, JSONResponse +from pydantic import BaseModel + +from ..config import get_settings +from ..services.reformat import ReformatError, reformat_tex, resolve_rules + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/review", tags=["review-reformat"]) + +_JOB_ID_RE = re.compile(r"^[0-9a-f]{12}$") +_ENGINE = "reformat-p1/1.0" + + +class ReformatResponse(BaseModel): + ok: bool + job_id: str | None = None + modified_tex: str | None = None + changes: list[dict[str, Any]] | None = None + warnings: list[dict[str, Any]] | None = None + meta: dict[str, Any] | None = None + error: dict[str, Any] | None = None + + +def _error(code: str, message: str) -> ReformatResponse: + return ReformatResponse( + ok=False, + error={"code": code, "message": message, "degraded": False}, + ) + + +def _jobs_dir() -> Path: + d = get_settings().reformat_dir_abs + d.mkdir(parents=True, exist_ok=True) + return d + + +@router.post("/reformat", response_model=ReformatResponse) +async def reformat( + file: UploadFile = File(..., description="LaTeX 源码(.tex 单文件)"), + target_journal: str = Form("", description="目标期刊 id/名称,或 default=通用规则"), +) -> ReformatResponse: + settings = get_settings() + + # ---- 入参校验(拍板 5:只收 .tex,docx/pdf 走 format-check 审核不重排)---- + filename = file.filename or "paper.tex" + if not filename.lower().endswith(".tex"): + return _error("VALIDATION", "仅支持 .tex 文件(docx/pdf 请走格式审核)") + target = (target_journal or "").strip() + if not target: + return _error("VALIDATION", "必须指定目标期刊(或选择「通用规则」)") + + content = await file.read() + if not content: + return _error("VALIDATION", "上传文件为空") + if len(content) > settings.max_tex_bytes: + return _error("VALIDATION", "源码超过 2MB 上限") + try: + source = content.decode("utf-8") + except UnicodeDecodeError: + return _error("VALIDATION", "源码必须为 UTF-8 编码") + + # ---- 规则解析(journals.json / format_cache / journal_directory 只读回链)---- + resolved = await resolve_rules(target) + + # ---- 变换(纯规则引擎;结构畸形 → PARSER_FAILED)---- + try: + result = reformat_tex(source, resolved["rules"]) + except ReformatError as exc: + logger.warning("reformat: 结构守卫拒收 %s: %s", filename, exc) + return _error(exc.code, str(exc)) + + # ---- 落盘(.tex + .json 报告;重启后 GET 仍可用)---- + job_id = uuid.uuid4().hex[:12] + base = _jobs_dir() + (base / f"{job_id}.tex").write_text(result["modified_tex"], encoding="utf-8") + + meta: dict[str, Any] = { + "journal_id": resolved["journal_id"], + "journal_name": resolved["journal_name"], + "rules": resolved["rules"], + "rules_source": resolved["rules_source"], + "rules_note": resolved["rules_note"], + "filename": filename, + "original_sha256": hashlib.sha256(content).hexdigest(), + "engine": _ENGINE, + "generated_at": datetime.now(timezone.utc).isoformat(timespec="seconds"), + } + payload = { + "ok": True, + "job_id": job_id, + "modified_tex": result["modified_tex"], + "changes": result["changes"], + "warnings": result["warnings"], + "meta": meta, + } + (base / f"{job_id}.json").write_text( + json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8" + ) + logger.info( + "reformat: %s → job %s(%d 处修改, %d 条提示, 规则 %s)", + filename, job_id, + sum(1 for c in result["changes"] if c["action"] == "modified"), + sum(1 for c in result["changes"] if c["action"] == "warning"), + resolved["rules_source"], + ) + return ReformatResponse(**payload) + + +def _load_job(job_id: str) -> dict[str, Any] | None: + if not _JOB_ID_RE.fullmatch(job_id or ""): + return None + path = _jobs_dir() / f"{job_id}.json" + try: + payload = json.loads(path.read_text("utf-8")) + except (OSError, ValueError): + return None + return payload if isinstance(payload, dict) and payload.get("ok") else None + + +_NOT_FOUND = {"ok": False, "error": {"code": "NOT_FOUND", + "message": "任务不存在或已过期,请重新上传源码", + "degraded": False}} + + +@router.get("/reformat/{job_id}", response_model=ReformatResponse) +async def get_reformat_job(job_id: str) -> ReformatResponse: + payload = _load_job(job_id) + if payload is None: + return _error("NOT_FOUND", "任务不存在或已过期,请重新上传源码") + return ReformatResponse(**payload) + + +@router.get("/reformat/{job_id}/file", response_model=None) +async def download_reformat_file(job_id: str) -> FileResponse | JSONResponse: + """下载修改后的 .tex;缺件/非法 id → 200 信封(前端单一错误口径)。""" + valid = bool(_JOB_ID_RE.fullmatch(job_id or "")) + tex = _jobs_dir() / f"{job_id}.tex" if valid else None + if tex is None or not tex.is_file(): + return JSONResponse(status_code=200, content=_NOT_FOUND) + return FileResponse(tex, media_type="application/x-tex", filename=f"{job_id}.tex") diff --git a/review_service/app/services/__init__.py b/review_service/app/services/__init__.py new file mode 100644 index 0000000..da95dd6 --- /dev/null +++ b/review_service/app/services/__init__.py @@ -0,0 +1 @@ +"""review 服务服务层包。""" diff --git a/review_service/app/services/format_check.py b/review_service/app/services/format_check.py new file mode 100644 index 0000000..a14070a --- /dev/null +++ b/review_service/app/services/format_check.py @@ -0,0 +1,788 @@ +"""services/format_check.py —— 版式与规范规则引擎(⑤ 论文排版与规范)。 + +纯规则、无 LLM、无 vstore、同步执行(通常 <1s): +- PDF → pymupdf 本地解档(AGENTS.md 约束 6 例外:vstore 只回文本,字体/边距/ + 行距/页数等版式元数据拿不到;正文提取仍走 vstore,本服务不碰正文语义); +- Word → python-docx(页边距/行距精确,页数取 docProps/app.xml 的 ); +- 规则集 → data/journals/journals.json: + 顶层 format_rules_default(通用默认值,rules_source="default") + 每条目可选 format_rules(按期刊覆盖,必须带 rules_source: placeholder|official|default) + ⚠ 诚实原则:不知道期刊真实投稿指南 → 该条只写 {"rules_source": "placeholder"}, + 所有具体数字回退 default 通用值,绝不编造期刊专属数字。 + +输出:{checks[{name,key,status,detail,suggestion}], summary{pass,warn,fail}, meta{...}} +status ∈ pass|warn|fail。参考文献样式宽容化:仅"明确不符"(如 [J] 标引但规则要求 APA) +才 fail,"疑似但不确定/检测不到"一律 warn,避免误伤。 +""" +from __future__ import annotations + +import io +import json +import re +import statistics +import zipfile +from pathlib import Path +from typing import Any + +import fitz # pymupdf(venv 已装 1.28.x) +from docx import Document +from docx.shared import Length + +# review_service/app/services/ → parents[2] = review_service +_JOURNALS_PATH = Path(__file__).resolve().parents[2] / "data" / "journals" / "journals.json" + +_MAX_SCAN_PAGES = 80 # 版式扫描页数上限(正文/字体/边距;稿件通常远小于此) +_MAX_REFS_SCAN = 40 # 从文末向前找参考文献标题的页数窗口 +_MAX_PARAS = 8000 # docx 段落扫描上限 +_PT_TO_MM = 25.4 / 72.0 +_EMU_TO_MM = 1.0 / 36000.0 + +_HEADING_RE = re.compile( + r"^\s*(references|bibliography|literature cited|works cited|参考文献|文献)\s*[::]?\s*$", + re.IGNORECASE, +) +_FIG_RE = re.compile(r"(?im)^\s*(figure|fig\.?|图)\s*\d+") +_TAB_RE = re.compile(r"(?im)^\s*(table|表)\s*\d+") +_GB_TAG_RE = re.compile(r"\[[A-Z]{1,3}\d*\]") # [J] [M] [D] [C] …(GB/T 7714 标引) +_PAREN_YEAR_RE = re.compile(r"\((?:19|20)\d{2}\)") # (2024) 作者-年份制 +_BRACKET_NUM_RE = re.compile(r"^\[\d+\]") # [1] 编号制 +_DOI_RE = re.compile(r"doi:?\.?org|doi:\s*1\.", re.IGNORECASE) + +_STYLE_LABEL = { + "gb7714": "GB/T 7714", + "author_year": "作者-年份制(类 APA)", + "numbered": "编号制(顺序编码)", + "unknown": "无法确定", +} + + +class FormatCheckError(Exception): + """解档/规则加载失败(路由器转 PARSE_FAILED)。""" + + +# ---------------------------------------------------------------- 规则集加载 + +def load_ruleset(target_journal: str) -> tuple[dict[str, Any], dict[str, Any]]: + """返回 (rules, ruleset_meta)。target_journal 传 id 或 name 均可;未知 → default。""" + try: + data = json.loads(_JOURNALS_PATH.read_text("utf-8")) + except Exception as exc: # noqa: BLE001 + raise FormatCheckError(f"规则集加载失败:{exc}") from exc + + default = data.get("format_rules_default") or {} + jid = (target_journal or "").strip() + entry = None + if jid: + for j in data.get("journals") or []: + if j.get("id") == jid or j.get("name") == jid: + entry = j + break + + if entry is None: + rules = dict(default) + meta = { + "journal_id": None, + "journal_name": None, + "ruleset_source": "default", + "rules_source": str(default.get("rules_source", "default")), + } + else: + journal_rules = entry.get("format_rules") or {} + rules = {**default, **journal_rules} + meta = { + "journal_id": entry.get("id"), + "journal_name": entry.get("name"), + "ruleset_source": "journal", + # 占位规则(无官方核验)→ 前端黄字提示 + "rules_source": str(journal_rules.get("rules_source", "placeholder")), + } + rules.setdefault("rules_source", "default") + return rules, meta + + +# ---------------------------------------------------------------- PDF 解档(pymupdf) + +def _norm_font(name: str) -> str: + n = (name or "").split("+")[-1].strip() + return n or "unknown" + + +def extract_profile_pdf(data: bytes) -> dict[str, Any]: + try: + doc = fitz.open(stream=data, filetype="pdf") + except Exception as exc: # noqa: BLE001 + raise FormatCheckError(f"PDF 解档失败:{exc}") from exc + if getattr(doc, "needs_pass", False): + doc.close() + raise FormatCheckError("PDF 已加密,无法解析") + + pages_total = doc.page_count + scan = min(pages_total, _MAX_SCAN_PAGES) + margin_rows: list[tuple[float, float, float, float]] = [] # t r b l (mm) + font_w: dict[str, int] = {} + size_w: dict[float, int] = {} + ratios: list[float] = [] + img_ids: set[int] = set() + fig_caps = tab_caps = 0 + + for pno in range(scan): + page = doc[pno] + rect = page.rect + blocks = page.get_text("blocks") + content = [b for b in blocks if b[4].strip()] + if content: + left = min(b[0] for b in content) + top = min(b[1] for b in content) + right = rect.width - max(b[2] for b in content) + bottom = rect.height - max(b[3] for b in content) + margin_rows.append( + ( + max(0.0, top) * _PT_TO_MM, + max(0.0, right) * _PT_TO_MM, + max(0.0, bottom) * _PT_TO_MM, + max(0.0, left) * _PT_TO_MM, + ) + ) + + for img in page.get_images(full=True): + img_ids.add(img[0]) + + text = page.get_text() + fig_caps += len(_FIG_RE.findall(text)) + tab_caps += len(_TAB_RE.findall(text)) + + d = page.get_text("dict") + for block in d.get("blocks", []): + if block.get("type") != 0: + continue + line_meta: list[tuple[float, float]] = [] # (基线 y, 字号) + for line in block.get("lines", []): + spans = [s for s in line.get("spans", []) if s.get("text", "").strip()] + if not spans: + continue + row_size = max(s.get("size", 0.0) for s in spans) + if row_size <= 0: + continue + for s in spans: + size = round(float(s.get("size", 0.0)), 1) + chars = len(s.get("text", "")) + if size > 0: + norm = _norm_font(s.get("font", "")) + font_w[norm] = font_w.get(norm, 0) + chars + size_w[size] = size_w.get(size, 0) + chars + # 行距基准用 span.origin 基线 y,不用 bbox 顶缘:bbox 顶随字形高低 + # 漂移,表格/图注等同基线并列文本会产出假性小 delta,混入中位数会把 + # 行距拉成 0.1x 的不可能值。 + origin = spans[0].get("origin") + line_meta.append((origin[1] if origin else line["bbox"][1], row_size)) + for i in range(1, len(line_meta)): + delta = line_meta[i][0] - line_meta[i - 1][0] + size = line_meta[i][1] + # 行距倍数 = 相邻行基线 y 差 / 当前行字号; + # 过滤物理不可能值:<0.5(行重叠/同基线并列表格)、>4.0(异常结构) + ratio = delta / size + if 0.5 <= ratio <= 4.0: + ratios.append(ratio) + + refs_text, refs_found = _find_refs_pdf(doc, pages_total) + doc.close() + + if margin_rows: + med = [statistics.median(col) for col in zip(*margin_rows)] + margins = {"top": med[0], "right": med[1], "bottom": med[2], "left": med[3]} + else: + margins = None + + return { + "source_kind": "pdf", + "pages": pages_total, + "margins_mm": margins, + "font_weights": font_w, + "size_weights": size_w, + "line_spacing_median": statistics.median(ratios) if ratios else None, + "figures": max(len(img_ids), fig_caps), + "tables": tab_caps, + "refs_text": refs_text, + "refs_found": refs_found, + } + + +def _find_refs_pdf(doc: "fitz.Document", pages_total: int) -> tuple[str | None, bool]: + """从文末向前找参考文献标题行;找到 → 标题行至文末文本;找不到 → (None, False)。""" + buf: list[str] = [] + start = max(0, pages_total - _MAX_REFS_SCAN) + for pno in range(pages_total - 1, start - 1, -1): + page_text = doc[pno].get_text() + lines = page_text.splitlines() + for idx in range(len(lines) - 1, -1, -1): + if _HEADING_RE.match(lines[idx].strip()): + tail = "\n".join(lines[idx + 1:]) + joined = "\n".join([tail] + buf).strip() + return (joined if len(joined) >= 50 else None), bool(joined) + buf.insert(0, page_text) + return None, False + + +# ---------------------------------------------------------------- Word 解档(python-docx) + +def _docx_app_pages(data: bytes) -> int | None: + try: + with zipfile.ZipFile(io.BytesIO(data)) as zf: + xml = zf.read("docProps/app.xml").decode("utf-8", "ignore") + m = re.search(r"(\d+)", xml) + return int(m.group(1)) if m else None + except Exception: # noqa: BLE001 + return None + + +def extract_profile_docx(data: bytes) -> dict[str, Any]: + try: + doc = Document(io.BytesIO(data)) + except Exception as exc: # noqa: BLE001 + raise FormatCheckError(f"Word 文件解析失败:{exc}") from exc + + side_lists: dict[str, list[float]] = {"top": [], "right": [], "bottom": [], "left": []} + for sec in doc.sections: + for k, v in ( + ("top", sec.top_margin), + ("right", sec.right_margin), + ("bottom", sec.bottom_margin), + ("left", sec.left_margin), + ): + if v is not None: + side_lists[k].append(float(v) * _EMU_TO_MM) + margins = None + if all(side_lists.values()): + margins = {k: statistics.median(v) for k, v in side_lists.items()} + + try: + normal = doc.styles["Normal"].font + default_name = normal.name + default_size = float(normal.size.pt) if normal.size is not None else None + except Exception: # noqa: BLE001 + default_name, default_size = None, None + + font_w: dict[str, int] = {} + size_w: dict[float, int] = {} + ratios: list[float] = [] + fig_caps = tab_caps = 0 + paras = doc.paragraphs + scan_count = min(len(paras), _MAX_PARAS) + + for i in range(scan_count): + para = paras[i] + text = para.text + if not text.strip(): + continue + ls = para.paragraph_format.line_spacing + if isinstance(ls, Length): + # 精确行距(exactly)以 EMU 存储,Length 是 int 子类——直接当倍数会得出 + # 十万级的假值;用正文默认字号换算成倍数 + if default_size: + r = float(ls.pt) / default_size + if 0.5 <= r <= 4.0: + ratios.append(r) + elif isinstance(ls, (int, float)) and not isinstance(ls, bool) and ls > 0: + r = float(ls) # multiple 行距本身就是倍数 + if 0.5 <= r <= 4.0: + ratios.append(r) + if _FIG_RE.match(text): + fig_caps += 1 + elif _TAB_RE.match(text): + tab_caps += 1 + for run in para.runs: + if not run.text: + continue + name = run.font.name or default_name or "unknown" + pt = run.font.size.pt if run.font.size is not None else default_size + chars = len(run.text) + font_w[str(name)] = font_w.get(str(name), 0) + chars + if pt: + size_w[round(float(pt), 1)] = size_w.get(round(float(pt), 1), 0) + chars + + # 参考文献节:标题段落之后全部文本 + refs_text, refs_found = None, False + for i, para in enumerate(paras): + if _HEADING_RE.match((para.text or "").strip()): + tail = "\n".join(p.text for p in paras[i + 1:] if (p.text or "").strip()) + if len(tail) >= 50: + refs_text, refs_found = tail, True + break + + return { + "source_kind": "docx", + "pages": _docx_app_pages(data), # Word 未记录 → None(检查项降级为 warn) + "margins_mm": margins, + "font_weights": font_w, + "size_weights": size_w, + "line_spacing_median": statistics.median(ratios) if ratios else None, + "figures": max(len(doc.inline_shapes), fig_caps), + "tables": max(len(doc.tables), tab_caps), + "refs_text": refs_text, + "refs_found": refs_found, + } + + +# ---------------------------------------------------------------- LaTeX 解档(正则+状态机,零新依赖) +# +# 决策前提:只做"解析 + 检查 + 建议代码片段",不自动改写 LaTeX(用户可能有自定义宏, +# 自动改写会引错;LaTeX 应由用户自己编辑)。不引入 pylatexenc/texsoup。 + +# 会相互覆盖的字体类宏包:≥2 个同时引入 → warn(times + mathptmx 类冲突) +_TEX_FONT_PKGS = {"times", "mathptmx", "newtx", "newpx", "txfonts", "pxfonts", "mathpazo"} + + +def _strip_tex_comments(src: str) -> str: + r"""去行内 % 注释(r-string,避免 \% 被解释为转义序列)。""" + return re.sub(r"(? dict[str, float] | None: + """\\usepackage[...]{geometry} 或 \\geometry{...} → {边: mm}(可缺边,检查端容缺)。""" + m = re.search(r"\\usepackage\s*\[([^\]]*)\]\s*\{\s*geometry\s*\}", src) + if not m: + m = re.search(r"\\geometry\s*\{([^}]*)\}", src) + if not m: + return None + opts = m.group(1) + + def to_mm(val: str) -> float | None: + mm = re.match(r"\s*([\d.]+)\s*(mm|cm|in|pt)?\s*$", val) + if not mm: + return None + x = float(mm.group(1)) + unit = mm.group(2) or "pt" # geometry 裸数字按 TeX 惯例为 pt + return {"mm": x, "cm": x * 10, "in": x * 25.4, "pt": x * 25.4 / 72.0}[unit] + + kv = {} + for pair in opts.split(","): + if "=" in pair: + k, v = pair.split("=", 1) + kv[k.strip().lower()] = v.strip() + out: dict[str, float] = {} + if "margin" in kv: + v = to_mm(kv["margin"]) + if v is not None: + return {"top": v, "right": v, "bottom": v, "left": v} + for k in ("top", "right", "bottom", "left"): + if k in kv: + v = to_mm(kv[k]) + if v is not None: + out[k] = v + if "inner" in kv: + v = to_mm(kv["inner"]) + if v is not None: + out.setdefault("left", v) + if "outer" in kv: + v = to_mm(kv["outer"]) + if v is not None: + out.setdefault("right", v) + return out or None + + +def extract_tex_profile(data: bytes) -> dict[str, Any]: + """正则 + 轻量状态机解析 .tex 源文件 → 与 DocProfile 同构(+tex 扩展字段)。""" + try: + text = data.decode("utf-8") + except UnicodeDecodeError: + text = data.decode("latin-1", errors="replace") + src = _strip_tex_comments(text) + + # \documentclass[10pt,a4paper]{article} + m_cls = re.search(r"\\documentclass\s*(?:\[[^\]]*\])?\s*\{\s*([\w*]+)\s*\}", src) + cls = m_cls.group(1) if m_cls else None + m_opt = re.search(r"\\documentclass\s*\[([^\]]*)\]", src) + cls_opts = m_opt.group(1) if m_opt else "" + m_pt = re.search(r"(\d+)\s*pt", cls_opts) + # 标准类未写选项时 LaTeX 默认 10pt;无 documentclass → None(检查项降级 warn) + fontsize = int(m_pt.group(1)) if m_pt else (10 if cls else None) + paper = "a4paper" if "a4paper" in cls_opts else ("letterpaper" if "letterpaper" in cls_opts else None) + + # \usepackage 列表(支持 {a,b} 逗号多包) + packages: list[str] = [] + for m in re.finditer(r"\\usepackage\s*(?:\[[^\]]*\])?\s*\{\s*([^}]+?)\s*\}", src): + packages += [p.strip().lower() for p in m.group(1).split(",") if p.strip()] + + # 行距:\linespread{...} 或 \setstretch{...}(值直接按"行距倍数"口径评估—— + # 按步骤4 规格:低于 min_line_spacing 即 fail;LaTeX 实际倍数还含 baselinestretch + # 的字号比,本引擎取显式设置值做保守判定) + line_spread: float | None = None + m = re.search(r"\\linespread\s*\{\s*([\d.]+)\s*\}", src) + if not m: + m = re.search(r"\\setstretch\s*\{\s*([\d.]+)\s*\}", src) + if m: + line_spread = float(m.group(1)) + + # 页边距(geometry) + margins = _parse_geometry(src) + + # 计数 + figures = len(re.findall(r"\\begin\s*\{\s*figure\*?\s*\}", src)) + tables = len(re.findall(r"\\begin\s*\{\s*table\*?\s*\}", src)) + cites = len(re.findall(r"\\cite\w*\s*\{", src)) + + # 参考文献:\bibliography{...}(BibTeX)/ \printbibliography(biblatex)/ thebibliography + has_bibtex = bool(re.search(r"\\bibliography\s*\{", src)) + has_printbib = bool(re.search(r"\\printbibliography", src)) + has_thebib = bool(re.search(r"\\begin\s*\{\s*thebibliography\s*\}", src)) + has_bibstyle = bool(re.search(r"\\bibliographystyle\s*\{", src)) # BibTeX 必需;biblatex 不需要 + has_bib = has_bibtex or has_printbib or has_thebib + refs_text: str | None = None + m_bib = re.search(r"\\begin\s*\{\s*thebibliography\s*\}[\s\S]*?\\end\s*\{\s*thebibliography\s*\}", src) + if m_bib: + refs_text = m_bib.group(0) + + # 宏表(\newcommand{\xxx} / \renewcommand)——用于解析准确性(识别自定义宏) + macros = re.findall(r"\\(?:new|re)command\s*\{\s*\\(\w+)\s*\}", src) + + # 匿名评审命令探测(规则集 anonymous:true 时检查) + m_anon = re.search(r"\\(?:anonymi[sz]e|anon\b|hideauthor|ifdoubleblind)", src, re.IGNORECASE) + + return { + "source_kind": "tex", + "pages": None, # LaTeX 源文件页数需编译后才有 → 检查项降级 warn(宽容化) + "margins_mm": margins, + "font_weights": {}, + "size_weights": {float(fontsize): 100} if fontsize else {}, + "line_spacing_median": line_spread, + "figures": figures, + "tables": tables, + "refs_text": refs_text, + "refs_found": has_bib, + "tex": { + "class": cls, + "fontsize_pt": fontsize, + "paper": paper, + "packages": packages, + "cites": cites, + "macros": macros, + "anon_cmd": m_anon.group(0) if m_anon else None, + "bib_bibtex": has_bibtex, + "bib_style": has_bibstyle, + }, + } + + +# ---------------------------------------------------------------- 参考文献样式检测 + +def detect_refs_style(text: str | None) -> tuple[str, str]: + """宽容化检测:返回 (detected, sample_line)。含糊 → unknown(后续只 warn)。""" + if not text: + return "unknown", "" + lines = [l.strip() for l in text.splitlines() if l.strip()][:40] + if not lines: + return "unknown", "" + n = len(lines) + gb = sum(1 for l in lines if _GB_TAG_RE.search(l)) + year = sum(1 for l in lines if _PAREN_YEAR_RE.search(l)) + num = sum(1 for l in lines if _BRACKET_NUM_RE.match(l)) + doi = sum(1 for l in lines if _DOI_RE.search(l)) + sample = lines[0][:80] + + if gb / n >= 0.4: + return "gb7714", sample + if num / n >= 0.4 and year / n < 0.3: + return "numbered", sample + if year / n >= 0.3 or doi / n >= 0.3: + return "author_year", sample + return "unknown", sample + + +# ---------------------------------------------------------------- 检查项构建 + +def _chk(key: str, name: str, status: str, detail: str, suggestion: str = "") -> dict[str, str]: + return {"key": key, "name": name, "status": status, "detail": detail, "suggestion": suggestion} + + +def _check_pages(profile: dict[str, Any], rules: dict[str, Any]) -> dict[str, str]: + limit = int(rules.get("max_pages", 10)) + pages = profile.get("pages") + kind = profile.get("source_kind") or "doc" + if pages is None: + # 宽容化:Word/LaTeX 页数缺失绝不 fail + if kind == "tex": + return _chk( + "pages", "页数", "warn", + f"LaTeX 源无法直接统计页数(规则上限 {limit} 页),需编译后核对", + "编译后确认(如 xelatex main.tex)总页数 ≤ 上限", + ) + return _chk( + "pages", "页数", "warn", + "Word 未记录页数,请自行核对", + f"在 Word 中按 Ctrl+End 查看总页数,或导出 PDF 后重查(规则上限 {limit} 页)", + ) + if pages <= limit: + return _chk("pages", "页数", "pass", f"共 {pages} 页,规则上限 {limit} 页") + return _chk( + "pages", "页数", "fail", f"共 {pages} 页,超出规则上限 {limit} 页", + f"压缩至 ≤{limit} 页,或将方法/图表移入补充材料", + ) + + +def _check_fonts(profile: dict[str, Any], rules: dict[str, Any]) -> dict[str, str]: + min_font = float(rules.get("min_font_pt", 9)) + # LaTeX:字号来自 \documentclass 选项(10/11/12pt,粒度粗) + if profile.get("source_kind") == "tex": + tex = profile.get("tex") or {} + cls = tex.get("class") or "documentclass" + fs = tex.get("fontsize_pt") + pkgs = tex.get("packages") or [] + font_pkgs = sorted(p for p in pkgs if p in _TEX_FONT_PKGS or p in ("helvet", "courier", "charter", "fourier")) + detail = ( + f"\\documentclass 选项字号 {fs}pt(类 {cls});" + f"字体宏包:{'、'.join(font_pkgs) if font_pkgs else '未引入'}" + + (f";纸张 {tex['paper']}" if tex.get("paper") else "") + ) + if fs is None: + return _chk("fonts", "字体字号", "warn", detail + "\n建议:\n \\documentclass[11pt]{article}", "补充 \\documentclass 声明") + if fs < min_font: + # LaTeX 粒度粗 → 按步骤4 规格降为 warn(非 fail) + return _chk( + "fonts", "字体字号", "warn", detail + f"\n建议:\n \\documentclass[11pt]{{{cls}}}", + f"正文字号低于下限 {min_font:.0f}pt,请改用 11pt/12pt 选项", + ) + return _chk("fonts", "字体字号", "pass", detail) + + size_w: dict[float, int] = profile.get("size_weights") or {} + font_w: dict[str, int] = profile.get("font_weights") or {} + if not size_w: + return _chk("fonts", "字体字号", "warn", "未能提取字体信息", "确认文档含可选中文本(扫描件无法检查字体)") + min_font = float(rules.get("min_font_pt", 9)) + max_fonts = int(rules.get("max_fonts", 6)) + total = sum(size_w.values()) + body_pt = max(size_w, key=size_w.get) + body_ratio = int(size_w[body_pt] / total * 100) + distinct = len(font_w) + top_fonts = sorted(font_w.items(), key=lambda kv: -kv[1])[:3] + top_text = "、".join(f"{k}({v}字)" for k, v in top_fonts) + detail = f"主要字号 {body_pt}pt(约 {body_ratio}%),共 {distinct} 种字体;高频字体:{top_text}" + if body_pt < min_font: + return _chk( + "fonts", "字体字号", "fail", detail, + f"将正文字号提高至 ≥{min_font}pt(当前主字号 {body_pt}pt)", + ) + if distinct > max_fonts: + return _chk( + "fonts", "字体字号", "warn", detail, + f"字体种类偏多({distinct} > {max_fonts}),建议全文统一为 1–2 种正文字体", + ) + return _chk("fonts", "字体字号", "pass", detail) + + +def _check_margins(profile: dict[str, Any], rules: dict[str, Any]) -> dict[str, str]: + limit = float(rules.get("min_margin_mm", 15)) + margins = profile.get("margins_mm") + # LaTeX:页边距来自 geometry;低于下限按步骤4 规格给 warn(非 fail),附建议片段 + if profile.get("source_kind") == "tex": + if not margins: + return _chk( + "margins", "页边距", "warn", + "未通过 geometry 设置页边距(按类默认评估)" + + f"\n建议:\n \\usepackage[margin=25mm]{{geometry}}", + "在导言区显式声明页边距", + ) + lo = min(margins.values()) + detail = f"geometry 页边距最小 {lo:.0f}mm(" + "、".join(f"{k}{v:.0f}" for k, v in margins.items()) + f"),规则下限 {limit:.0f}mm" + if lo < limit: + return _chk( + "margins", "页边距", "warn", + detail + f"\n建议:\n \\usepackage[margin={limit:.0f}mm]{{geometry}}", + f"调大页边距至 ≥{limit:.0f}mm", + ) + return _chk("margins", "页边距", "pass", detail) + if not margins: + return _chk("margins", "页边距", "warn", "未能提取页边距信息", "检查文档是否含可定位文本") + vals = [margins.get(k) for k in ("top", "right", "bottom", "left")] + vals = [v for v in vals if v is not None] + if not vals: + return _chk("margins", "页边距", "warn", "未能提取页边距信息", "检查文档是否含可定位文本") + t, r = margins.get("top"), margins.get("right") + b, l = margins.get("bottom"), margins.get("left") + lo = min(vals) + sides = "、".join( + f"{name}{v:.0f}" for name, v in (("上", t), ("右", r), ("下", b), ("左", l)) if v is not None + ) + detail = f"四边最小 {lo:.0f}mm({sides}),规则下限 {limit:.0f}mm" + if lo >= limit: + return _chk("margins", "页边距", "pass", detail) + if lo >= limit * 0.8: + return _chk("margins", "页边距", "warn", detail, f"将页边距调大至 ≥{limit:.0f}mm") + return _chk("margins", "页边距", "fail", detail, f"页边距过小,请调至 ≥{limit:.0f}mm(版式设置)") + + +def _check_spacing(profile: dict[str, Any], rules: dict[str, Any]) -> dict[str, str]: + lo = float(rules.get("min_line_spacing", 1.15)) + ratio = profile.get("line_spacing_median") + # LaTeX:\linespread/\setstretch 显式设置值;低于下限按步骤4 规格直接 fail + if profile.get("source_kind") == "tex": + if ratio is None: + return _chk( + "spacing", "行距", "pass", + "未显式设置 \\linespread/\\setstretch,LaTeX 类默认约 1.2 倍(如 10pt→12pt baselineskip)", + ) + detail = f"\\linespread/\\setstretch = {ratio:.2f},规则下限 {lo:.2f}" + if ratio < lo: + return _chk( + "spacing", "行距", "fail", + detail + f"\n建议:\n \\linespread{{{lo:.2f}}} % 或 \\setstretch{{{lo:.2f}}}(导言区)", + "在导言区调大行距设置", + ) + return _chk("spacing", "行距", "pass", detail) + if ratio is None: + return _chk("spacing", "行距", "warn", "未能提取行距信息", "确认段落使用固定/多倍行距设置") + lo = float(rules.get("min_line_spacing", 1.15)) + detail = f"正文中位行距约 {ratio:.2f} 倍,规则下限 {lo:.2f} 倍" + if ratio >= lo: + return _chk("spacing", "行距", "pass", detail) + if ratio >= lo * 0.9: + return _chk("spacing", "行距", "warn", detail, f"段落行距设为 ≥{lo:.2f} 倍(如 1.5 倍行距)") + return _chk("spacing", "行距", "fail", detail, f"行距过密,请设为 ≥{lo:.2f} 倍行距") + + +def _check_figures(profile: dict[str, Any], rules: dict[str, Any]) -> dict[str, str]: + figures = int(profile.get("figures") or 0) + tables = int(profile.get("tables") or 0) + min_f = int(rules.get("min_figures", 1)) + detail = f"检测到图 {figures} 张、表 {tables} 个(图注/表注正则 + 内嵌对象启发式)" + if figures >= min_f: + return _chk("figures", "图表数量", "pass", detail) + # 启发式检测不可靠 → 低于阈值只 warn 不 fail + return _chk( + "figures", "图表数量", "warn", detail, + f"常规研究论文建议 ≥{min_f} 图;若为综述/短文可忽略(本项为启发式检测)", + ) + + +# 仅"明确不符"才 fail 的 (expected, detected) 组合(宽容化:其余含糊组合一律 warn) +_REF_FAIL_PAIRS = { + ("apa", "gb7714"), # 找到 [J] 标引但规则要求 APA + ("gb7714", "author_year"), # 无 [J] 标引的作者-年份制,但规则要求 GB/T 7714 + ("apa", "numbered"), # 编号制引文但规则要求 APA +} + + +def _check_refs(profile: dict[str, Any], rules: dict[str, Any]) -> dict[str, str]: + expected = str(rules.get("refs_style", "apa")).lower() + exp_label = _STYLE_LABEL.get(expected, expected) + if not profile.get("refs_found"): + return _chk( + "refs", "参考文献格式", "warn", + "未找到参考文献节(References/参考文献 / \\bibliography / thebibliography)", + "确认存在参考文献声明后重查", + ) + if profile.get("source_kind") == "tex": + tex = profile.get("tex") or {} + # BibTeX:\bibliography 存在但缺 \bibliographystyle → warn(样式引擎未知) + if tex.get("bib_bibtex") and not tex.get("bib_style"): + return _chk( + "refs", "参考文献格式", "warn", + f"规则要求 {exp_label};检测到 \\bibliography 但缺少 \\bibliographystyle(BibTeX 无法确定引用样式)" + + "\n建议:\n \\bibliographystyle{plain} % 按期刊/模板指定实际样式", + "在 \\bibliography 前补 \\bibliographystyle", + ) + if not profile.get("refs_text"): + # 条目在 .bbl/编译产物,源文件无文本 → 宽容化只 warn + return _chk( + "refs", "参考文献格式", "warn", + f"规则要求 {exp_label};检测到参考文献声明(条目由编译生成,源文件无条目文本)", + "编译后核对参考文献条目样式", + ) + detected, sample = detect_refs_style(profile.get("refs_text")) + det_label = _STYLE_LABEL[detected] + detail = f"规则要求 {exp_label};检测到 {det_label};样例:{sample}" + # 宽容化:仅"明确不符"(_REF_FAIL_PAIRS)才 fail;含糊/不确定一律 warn + if (expected, detected) in _REF_FAIL_PAIRS: + return _chk("refs", "参考文献格式", "fail", detail, f"按 {exp_label} 调整全部文献条目(可用文献管理工具一键转换)") + if detected == "unknown": + return _chk("refs", "参考文献格式", "warn", detail, f"请人工核对是否符合 {exp_label}") + if expected == "gb7714" and detected == "numbered": + return _chk("refs", "参考文献格式", "warn", detail, "GB/T 7714 顺序编码制也用编号,需人工确认条目含 [J] 等类型标引") + if expected == "author-year-journal" and detected in ("gb7714", "numbered"): + return _chk("refs", "参考文献格式", "warn", detail, f"请对照期刊投稿指南核对是否符合 {exp_label}") + return _chk("refs", "参考文献格式", "pass", detail) + + +def _check_font_packages(profile: dict[str, Any], rules: dict[str, Any]) -> dict[str, str]: + """LaTeX 特有:多个相互覆盖的字体宏包(times + mathptmx 类)→ warn。""" + pkgs = set((profile.get("tex") or {}).get("packages") or []) + clash = sorted(pkgs & _TEX_FONT_PKGS) + if len(clash) >= 2: + detail = ( + f"检测到多个相互覆盖的字体宏包:{'、'.join(clash)}(后加载者覆盖前者,易产生冲突)" + + "\n建议:\n %只保留一套字体方案,例如:\n \\usepackage{newtx} % newtxtext + newtxmath 一体" + ) + return _chk("fontpkgs", "字体包兼容", "warn", detail, "移除重复/冲突的字体宏包,只保留一套") + return _chk( + "fontpkgs", "字体包兼容", "pass", + "字体宏包:" + ("、".join(clash) if clash else "未引入冲突类字体包"), + ) + + +def _check_anonymous(profile: dict[str, Any], rules: dict[str, Any]) -> dict[str, str]: + """LaTeX 特有且规则集 anonymous:true 时才出:源文件需含匿名处理命令。""" + tex = profile.get("tex") or {} + cmd = tex.get("anon_cmd") + if cmd: + return _chk("anonymous", "匿名评审", "pass", f"检测到匿名处理命令 {cmd}") + return _chk( + "anonymous", "匿名评审", "warn", + "规则要求匿名评审,源文件未检测到匿名处理命令" + + "\n建议:\n %隐去作者/致谢/自引,或定义匿名宏:\n \\newcommand{\\anon}[1]{[ANON]}", + "按期刊要求对作者信息做匿名处理", + ) + + +def build_checks(profile: dict[str, Any], rules: dict[str, Any]) -> list[dict[str, str]]: + checks = [ + _check_pages(profile, rules), + _check_fonts(profile, rules), + _check_margins(profile, rules), + _check_spacing(profile, rules), + ] + if profile.get("source_kind") == "tex": + checks.append(_check_font_packages(profile, rules)) + checks.append(_check_figures(profile, rules)) + checks.append(_check_refs(profile, rules)) + if profile.get("source_kind") == "tex" and rules.get("anonymous"): + checks.append(_check_anonymous(profile, rules)) + return checks + + +# ---------------------------------------------------------------- 入口 + +def check_document(data: bytes, kind: str, target_journal: str) -> dict[str, Any]: + """kind ∈ pdf|docx|tex。返回 {checks, summary, meta}(filename 由路由器补入 meta)。""" + if kind == "pdf": + profile = extract_profile_pdf(data) + elif kind == "docx": + profile = extract_profile_docx(data) + elif kind == "tex": + profile = extract_tex_profile(data) + else: + raise FormatCheckError(f"不支持的文件类型:{kind}") + + rules, ruleset_meta = load_ruleset(target_journal) + checks = build_checks(profile, rules) + summary = {"pass": 0, "warn": 0, "fail": 0} + for c in checks: + summary[c["status"]] = summary.get(c["status"], 0) + 1 + + detected, _ = detect_refs_style(profile.get("refs_text")) if profile.get("refs_found") else ("unknown", "") + meta = { + **ruleset_meta, + "file_type": kind, + "pages": profile.get("pages"), + "refs_style_expected": str(rules.get("refs_style", "apa")).lower(), + "refs_style_detected": detected, + } + if kind == "tex": + tex = profile.get("tex") or {} + meta["tex"] = { + "class": tex.get("class"), + "fontsize_pt": tex.get("fontsize_pt"), + "paper": tex.get("paper"), + "packages": tex.get("packages"), + "cites": tex.get("cites"), + "macros": (tex.get("macros") or [])[:10], + } + return {"checks": checks, "summary": summary, "meta": meta} diff --git a/review_service/app/services/format_extractor.py b/review_service/app/services/format_extractor.py new file mode 100644 index 0000000..05a5c1e --- /dev/null +++ b/review_service/app/services/format_extractor.py @@ -0,0 +1,232 @@ +"""services/format_extractor.py —— 投稿指南 → 格式规则 JSON(LLM 抽取,第一批)。 + +- 调 services/llm.py 的 complete_json(DeepSeek json_object + 修复重试,零新依赖) +- Prompt = 「格式规则抽取器」模板:目标字段与 journals.json format_rules_default + 同构(max_pages / min_font_pt / min_margin_mm / min_line_spacing / min_figures / + max_fonts / refs_style / anonymous),强制每字段带 source_quotes + confidence +- 诚实原则:正文没写 → null,绝不编造(与 format_check 诚实原则一致) +- 解析/校验失败 → {"ok": False, "error": ...} + +返回: + 成功 {"ok": True, "rules": {...}, "source_quotes": {...}, + "confidence": {...}, "notes": str, "raw": LLM原始JSON, "error": None} + 失败 {"ok": False, "error": "...", 其余键为 None} +source_url 由调用方(scripts/fetch_format_rules.py)在落盘时补入结果文件。 +""" +from __future__ import annotations + +import logging +import re +from typing import Any + +from .llm import LLMError, complete_json + +logger = logging.getLogger(__name__) + +# 「格式规则抽取器」模板(system prompt) +_SYSTEM = """你是「格式规则抽取器」:从期刊官方投稿指南的 Markdown 正文中抽取格式规则,供投稿排版检查引擎使用。 + +# 目标字段(rules 对象,严格用以下字段名) +- max_pages:正文页数上限(整数;原文无明确上限 → null) +- min_font_pt:最小字号(数字,单位 pt;原文若用 cm/mm/inch 给出则换算为 pt) +- min_margin_mm:最小页边距(数字,单位 mm;原文若用 inch 给出则 ×25.4 换算) +- min_line_spacing:最小行距倍数(数字;如 "double-spaced" → 2.0,"1.5 spacing" → 1.5) +- min_figures:研究论文最少图数(整数;无明确要求 → null) +- max_fonts:全文最多字体种类(整数;无明确要求 → null) +- refs_style:参考文献样式,枚举 apa | gb7714 | author_year | numbered | vancouver | mla | chicago | other(无法判断 → null) +- anonymous:是否要求匿名/双盲评审(true / false / null) + +# 凭证(强制) +- 每个非 null 字段必须给 source_quotes[字段名]:从正文【逐字】摘录的 1-3 句原文, + 不改写、不翻译、不丢掉含关键数字的句子。 +- source_quotes["_general"]:整体最有凭证价值的 1-3 条原文摘录。 +- confidence:{"overall": 0-1, "per_field": {"字段名": 0-1}}。 + 直接原文命中 ≥0.9;单位换算 0.6-0.9;靠上下文推断 <0.6。 + +# 诚实原则 +- 正文没写到的字段一律 null,绝不用常识或训练记忆补值。 +- 单位换算允许做,但该字段 confidence 不得超过 0.9。 +- 换算过程、拿不准的点、页面疑似不完整,写进 notes。 + +# 输出 +只输出一个 JSON 对象,不要代码块、不要解释文字: +{"rules": {"max_pages": null, "min_font_pt": null, "min_margin_mm": null, + "min_line_spacing": null, "min_figures": null, "max_fonts": null, + "refs_style": null, "anonymous": null}, + "source_quotes": {"字段名": ["原文1", "..."], "_general": ["原文1", "..."]}, + "confidence": {"overall": 0.0, "per_field": {"字段名": 0.0}}, + "notes": "一句话说明抽取依据与不确定点"}""" + +_USER_TMPL = """期刊:{journal_name} + +=== 官方投稿指南正文(Markdown,已截断) === +{markdown}""" + +_RULE_INT_KEYS = ("max_pages", "min_figures", "max_fonts") +_REFS_ALLOWED = {"apa", "gb7714", "author_year", "numbered", "vancouver", + "mla", "chicago", "other"} +_REFS_ALIAS = { + "apa-7": "apa", "apa7": "apa", "apa 7th": "apa", "apa_7th": "apa", + "harvard": "author_year", "author-year": "author_year", "authoryear": "author_year", + "gb/t 7714": "gb7714", "gb/t-7714": "gb7714", "gb7714-2015": "gb7714", + "gb/t7714": "gb7714", "chicago author-date": "chicago", +} + + +# 字符串值带显式单位时的目标单位换算表(LLM 若回传原文单位的兜底;无单位=数值即目标单位) +_UNIT_TO_MM = {"mm": 1.0, "cm": 10.0, "in": 25.4, "inch": 25.4, "inches": 25.4, "pt": 25.4 / 72} +_UNIT_TO_PT = {"pt": 1.0, "mm": 72 / 25.4, "cm": 72 / 2.54, "in": 72.0, "inch": 72.0, "inches": 72.0} + + +def _to_int(v: Any) -> int | None: + if isinstance(v, bool) or v is None: + return None + if isinstance(v, int): + return v + if isinstance(v, float): + return int(round(v)) + if isinstance(v, str): + m = re.search(r"-?\d+", v) + if m: + return int(m.group(0)) + return None + + +def _to_float(v: Any, units: dict[str, float] | None = None) -> float | None: + if isinstance(v, bool) or v is None: + return None + if isinstance(v, (int, float)): + return float(v) + if isinstance(v, str): + m = re.search(r"(-?\d+(?:\.\d+)?)\s*([a-zA-Z]+)?", v) + if not m: + return None + x = float(m.group(1)) + unit = (m.group(2) or "").lower() + if units and unit: + factor = units.get(unit) + if factor is None: + return None # 未知单位不猜 + x *= factor + return x + return None + + +def _to_bool(v: Any) -> bool | None: + if isinstance(v, bool): + return v + if isinstance(v, (int, float)) and not isinstance(v, bool): + if v in (0, 1): + return bool(v) + if isinstance(v, str): + low = v.strip().lower() + if low in ("true", "yes", "required"): + return True + if low in ("false", "no", "not required"): + return False + return None + + +def _norm_refs(v: Any) -> str | None: + if not isinstance(v, str) or not v.strip(): + return None + low = v.strip().lower() + low = _REFS_ALIAS.get(low, low) + return low if low in _REFS_ALLOWED else "other" + + +def _norm_conf(v: Any) -> float | None: + if isinstance(v, bool) or not isinstance(v, (int, float)): + return None + return max(0.0, min(1.0, float(v))) + + +def _normalize(raw: dict[str, Any]) -> dict[str, Any]: + """白名单归一:类型错的值置 null(宁缺勿错,raw 全量保留在结果里)。""" + src = raw.get("rules") + src = src if isinstance(src, dict) else {} + rules: dict[str, Any] = {} + for k in _RULE_INT_KEYS: + rules[k] = _to_int(src.get(k)) + rules["min_font_pt"] = _to_float(src.get("min_font_pt"), _UNIT_TO_PT) + rules["min_margin_mm"] = _to_float(src.get("min_margin_mm"), _UNIT_TO_MM) + rules["min_line_spacing"] = _to_float(src.get("min_line_spacing")) + rules["refs_style"] = _norm_refs(src.get("refs_style")) + rules["anonymous"] = _to_bool(src.get("anonymous")) + + sq_src = raw.get("source_quotes") + sq_src = sq_src if isinstance(sq_src, dict) else {} + quotes: dict[str, list[str]] = {} + for key, val in sq_src.items(): + if key != "_general" and key not in rules: + continue + items = val if isinstance(val, list) else [val] + cleaned = [str(x).strip() for x in items if isinstance(x, (str, int, float)) + and str(x).strip()] + if cleaned: + quotes[key] = cleaned + + conf_src = raw.get("confidence") + conf_src = conf_src if isinstance(conf_src, dict) else {} + pf_src = conf_src.get("per_field") + pf_src = pf_src if isinstance(pf_src, dict) else {} + per_field: dict[str, float] = {} + for k, v in pf_src.items(): + c = _norm_conf(v) + if c is not None and (k in rules or k == "_general"): + per_field[k] = c + overall = _norm_conf(conf_src.get("overall")) + if overall is None and per_field: + overall = sum(per_field.values()) / len(per_field) + confidence = {"overall": overall, "per_field": per_field} + + notes = raw.get("notes") + return { + "rules": rules, + "source_quotes": quotes, + "confidence": confidence, + "notes": str(notes) if notes else "", + } + + +def _validation_error(norm: dict[str, Any]) -> str | None: + """强制凭证:任一非 null 字段缺 source_quotes → 拒收(ok=False)。""" + missing = [k for k, v in norm["rules"].items() + if v is not None and k not in norm["source_quotes"]] + if missing: + return f"LLM 输出缺少非 null 字段的 source_quotes:{', '.join(missing)}" + if not norm["source_quotes"].get("_general"): + return "LLM 输出缺少 source_quotes._general 整体引证" + if any(v is not None for v in norm["rules"].values()): + return None + return "LLM 未抽出任何非 null 字段(rules 全空)" + + +async def extract_format_rules(markdown: str, journal_name: str) -> dict: + """markdown(≤30000 字符)+ 期刊名 → 抽取结果(schema 见模块 docstring)。""" + if not markdown or not markdown.strip(): + return {"ok": False, "error": "markdown 为空", "rules": None, + "source_quotes": None, "confidence": None, "notes": None, "raw": None} + user = _USER_TMPL.format(journal_name=journal_name, markdown=markdown) + try: + raw = await complete_json(_SYSTEM, user, temperature=0.1, max_tokens=8000) + except LLMError as exc: + return {"ok": False, "error": f"LLM 调用失败:{exc}", "rules": None, + "source_quotes": None, "confidence": None, "notes": None, "raw": None} + if not isinstance(raw, dict): + return {"ok": False, "error": f"LLM 输出非 JSON 对象:{type(raw).__name__}", + "rules": None, "source_quotes": None, "confidence": None, + "notes": None, "raw": None} + + norm = _normalize(raw) + err = _validation_error(norm) + if err: + logger.warning("[extract] %s 校验失败:%s", journal_name, err) + return {"ok": False, "error": err, "rules": None, + "source_quotes": norm["source_quotes"], "confidence": norm["confidence"], + "notes": norm["notes"], "raw": raw} + filled = sum(1 for v in norm["rules"].values() if v is not None) + logger.info("[extract] %s → 8 字段中 %d 个非 null", journal_name, filled) + return {"ok": True, "error": None, "rules": norm["rules"], + "source_quotes": norm["source_quotes"], + "confidence": norm["confidence"], "notes": norm["notes"], "raw": raw} diff --git a/review_service/app/services/format_fetcher.py b/review_service/app/services/format_fetcher.py new file mode 100644 index 0000000..1710d8e --- /dev/null +++ b/review_service/app/services/format_fetcher.py @@ -0,0 +1,356 @@ +"""services/format_fetcher.py —— 投稿指南页面抓取(格式规则自动获取·第一批)。 + +约束(用户拍板 2026-10-10): +- 零新依赖:httpx + beautifulsoup4(venv 已装 4.15.0,用户明确指定使用; + lxml 6.1.2 在 requirements.lock 内,作 bs4 解析器) +- 同域限速 ≥ 2s(robots.txt 与正文请求共用计时器) +- 抓正文前先 GET /robots.txt,命中 Disallow → ok=False 跳过 +- UA: "PlantAI-RAG-Bot/1.0 (+contact: admin@example.com)" +- 只提取正文(去导航/页脚/脚本),截断至 30000 字符 + +返回固定四键:{"ok": bool, "markdown": str, "error": str | None, "fetched_at": str} +""" +from __future__ import annotations + +import asyncio +import logging +import re +import time +from datetime import datetime, timezone +from urllib.parse import urlparse + +import httpx +from bs4 import BeautifulSoup, NavigableString + +logger = logging.getLogger(__name__) + +USER_AGENT = "PlantAI-RAG-Bot/1.0 (+contact: admin@example.com)" +TIMEOUT = 30.0 +MAX_CHARS = 30_000 +MIN_INTERVAL_PER_HOST = 2.0 # 同域请求间隔 ≥ 2s(robots 与正文共用) +_MIN_TEXT_CHARS = 200 # 正文短于此 → 疑似 JS 渲染/反爬页 +_HEADERS = { + "User-Agent": USER_AGENT, + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Accept-Language": "en-US,en;q=0.9", +} + +# 同域限速:host → 上次请求完成时刻(monotonic) +_last_hit: dict[str, float] = {} +_throttle_lock = asyncio.Lock() + + +def _now_iso() -> str: + return datetime.now(timezone.utc).isoformat(timespec="seconds") + + +def _fail(error: str) -> dict: + return {"ok": False, "markdown": "", "error": error, "fetched_at": _now_iso()} + + +async def _throttle(host: str) -> None: + """同域串行 + ≥2s 间隔(全局锁:本批抓取量小,简单可靠优先)。""" + async with _throttle_lock: + now = time.monotonic() + wait = _last_hit.get(host, now) + MIN_INTERVAL_PER_HOST - now + if wait > 0: + await asyncio.sleep(wait) + _last_hit[host] = time.monotonic() + + +# ---------------------------------------------------------------- robots.txt + +def _parse_robots(text: str) -> list[tuple[list[str], list[tuple[str, str]]]]: + """→ [(agents, [(kind, pattern)...]), ...](连续 UA 行同组;规则行后出现 UA=新组)。""" + groups: list[tuple[list[str], list[tuple[str, str]]]] = [] + agents: list[str] = [] + rules: list[tuple[str, str]] = [] + for raw in text.splitlines(): + line = raw.split("#", 1)[0].strip() + if not line or ":" not in line: + continue + key, _, value = line.partition(":") + key, value = key.strip().lower(), value.strip() + if key == "user-agent": + if agents and rules: # 上一组已出规则 → 当前 UA 行开新组 + groups.append((agents, rules)) + agents, rules = [], [] + agents.append(value) + elif key in ("allow", "disallow"): + if not agents: # 无前置 UA 的规则按 * 组处理 + agents = ["*"] + rules.append((key, value)) + if agents: + groups.append((agents, rules)) + return groups + + +def _robots_path_allowed(groups, path: str) -> tuple[bool, str]: + """最长匹配决胜(同长 Allow 优先;`$` 结尾=精确匹配;空 Disallow 跳过)。""" + + def matched_by(pat: str) -> bool: + if pat.endswith("$"): + return path == pat[:-1] + return path.startswith(pat) + + token = "plantai-rag-bot" + matched = [rules for agents, rules in groups + if any(token in a.lower() for a in agents)] + if not matched: + matched = [rules for agents, rules in groups + if any(a.lower() == "*" for a in agents)] + if not matched: + return True, "robots.txt 无匹配组(本 bot 不受限)" + + best_len, best_allow, best_pat = -1, False, "" + for rules in matched: + for kind, pat in rules: + if not pat: # "Disallow:" 空值 = 放行一切(该组无需处理) + continue + if not matched_by(pat): + continue + length = len(pat) + allow = kind == "allow" + if length > best_len or (length == best_len and allow and not best_allow): + best_len, best_allow, best_pat = length, allow, pat + if best_len < 0: + return True, "robots.txt 允许(无路径匹配)" + if best_allow: + return True, f"robots.txt Allow 命中({best_pat})" + return False, f"robots.txt Disallow 命中({best_pat})" + + +async def _robots_allows(client: httpx.AsyncClient, url: str) -> tuple[bool, str]: + p = urlparse(url) + robots_url = f"{p.scheme}://{p.netloc}/robots.txt" + await _throttle(p.netloc.lower()) + try: + resp = await client.get(robots_url, headers=_HEADERS) + except httpx.HTTPError as exc: + return True, f"robots.txt 获取失败({type(exc).__name__}),按允许处理" + if resp.status_code != 200: + return True, f"robots.txt HTTP {resp.status_code},按允许处理" + groups = _parse_robots(resp.text) + return _robots_path_allowed(groups, p.path or "/") + + +# ---------------------------------------------------------------- 正文提取 + +_STRIP_TAGS = ("script", "style", "noscript", "iframe", "form", "nav", + "footer", "aside", "button", "select", "textarea", "input", "svg") +_STRIP_ROLES = ("navigation", "contentinfo", "complementary", "search") +# 正文容器候选(按优先级;首个文本 ≥500 字符者胜出) +_CONTENT_SELECTORS = ( + "main", "article", '[role="main"]', "#content", "#main", "#main-content", + ".article-body", "#article-body", ".article__body", ".hub-article-body", + ".page-content", ".main-content", ".content-area", +) +_CHALLENGE_MARKERS = ("just a moment", "attention required", "captcha", + "access denied", "ddos protection", "verify you are human") + + +def _decode_html(resp: httpx.Response) -> str: + """header charset → → utf-8(errors=replace),防 OUP/Wiley 无 header 乱码。""" + enc = None + m = re.search(r"charset=([\w.-]+)", resp.headers.get("content-type", ""), re.I) + if m: + enc = m.group(1) + if not enc: + m = re.search(rb"""charset\s*=\s*["']?([\w.-]+)""", resp.content[:4096], re.I) + if m: + enc = m.group(1).decode("ascii", "ignore") + try: + return resp.content.decode(enc or "utf-8", errors="replace") + except LookupError: + return resp.content.decode("utf-8", errors="replace") + + +def _squeeze(s: str) -> str: + """行内空白压缩 + 去空行(保留单换行)。""" + lines = [re.sub(r"[ \t\r\f\v]+", " ", line).strip() for line in s.split("\n")] + return "\n".join(line for line in lines if line) + + +def _inline(el) -> str: + """行内渲染:a→md链接 / strong→** / em→* / code→` / br→换行;跳过列表与图片。""" + parts: list[str] = [] + for child in el.children: + name = getattr(child, "name", None) + if name is None: # NavigableString + parts.append(str(child)) + continue + if name in ("ul", "ol", "img", "picture", "figure"): + continue + if name == "a": + href = (child.get("href") or "").strip() + txt = _inline(child).strip() + if not txt: + continue + parts.append(f"[{txt}]({href})" if href.startswith(("http://", "https://")) else txt) + elif name in ("strong", "b"): + parts.append(f"**{_inline(child)}**") + elif name in ("em", "i"): + parts.append(f"*{_inline(child)}*") + elif name == "code": + parts.append(f"`{_inline(child).strip()}`") + elif name == "br": + parts.append("\n") + else: + parts.append(_inline(child)) + return "".join(parts) + + +def _list_md(el, ordered: bool) -> str: + lines: list[str] = [] + idx = 1 + for li in el.find_all("li", recursive=False): + # li 文本不含嵌套列表(嵌套列表随后缩进输出) + buf = [] + for child in li.children: + if getattr(child, "name", None) in ("ul", "ol"): + continue + buf.append(_inline(child) if getattr(child, "name", None) else str(child)) + txt = " ".join("".join(buf).split()) + if txt: + lines.append(f"{idx}. {txt}" if ordered else f"- {txt}") + idx += 1 + for nested in li.find_all(("ul", "ol"), recursive=False): + sub = _list_md(nested, nested.name == "ol") + if sub: + lines.extend(" " + line for line in sub.split("\n")) + return "\n".join(lines) + + +def _table_md(table) -> str | None: + rows: list[list[str]] = [] + for tr in table.find_all("tr"): + cells = [" ".join(_squeeze(_inline(c)).split()) + for c in tr.find_all(("td", "th"))] + if cells: + rows.append(cells) + if not rows: + return None + out = ["| " + " | ".join(rows[0]) + " |"] + if table.find("th"): # 首行含表头 → 补分隔行(合法 GFM 表) + out.append("| " + " | ".join(["---"] * len(rows[0])) + " |") + out += ["| " + " | ".join(r) + " |" for r in rows[1:]] + return "\n".join(out) + + +def _blocks(el, out: list[str]) -> None: + for child in el.children: + name = getattr(child, "name", None) + if name is None: # 裸文本 + txt = _squeeze(str(child)) + if txt: + out.append(txt) + continue + if name in _STRIP_TAGS: + continue + if name in ("h1", "h2", "h3", "h4", "h5", "h6"): + txt = " ".join(_squeeze(_inline(child)).split()) + if txt: + out.append("#" * int(name[1]) + " " + txt) + elif name == "p": + txt = _squeeze(_inline(child)) + if txt: + out.append(txt) + elif name in ("ul", "ol"): + md = _list_md(child, name == "ol") + if md: + out.append(md) + elif name == "table": + md = _table_md(child) + if md: + out.append(md) + elif name == "blockquote": + txt = _squeeze(_inline(child)) + if txt: + out.append("\n".join("> " + line for line in txt.split("\n"))) + elif name == "pre": + code = child.get_text().strip("\n") + if code.strip(): + out.append("```\n" + code + "\n```") + elif name == "hr": + out.append("---") + else: # div/section/article/main/figure/dl/details/… 容器递归 + _blocks(child, out) + + +def _html_to_markdown(html: str) -> tuple[str, str | None]: + """→ (markdown, error)。选正文容器 → 去壳 → DOM 递归转 Markdown。""" + soup = BeautifulSoup(html, "lxml") # lxml 在 lock 内;缺时 bs4 自动回退 html.parser + + title = (soup.title.get_text() if soup.title else "") or "" + for tag in soup.find_all(_STRIP_TAGS): + tag.decompose() + for tag in soup.find_all(attrs={"role": _STRIP_ROLES}): + tag.decompose() + + container = None + fallback_hits = [] + for sel in _CONTENT_SELECTORS: + for node in soup.select(sel): + text_len = len(node.get_text(" ", strip=True)) + fallback_hits.append((text_len, node)) + if text_len >= 500: + container = node + break + if container is not None: + break + if container is None: + if fallback_hits: + container = max(fallback_hits, key=lambda x: x[0])[1] + else: + container = soup.body or soup + + blocks: list[str] = [] + _blocks(container, blocks) + md = "\n\n".join(blocks) + + probe = (title + " " + md[:500]).lower() + marker = next((m for m in _CHALLENGE_MARKERS if m in probe), None) + if marker: + return "", f"疑似反爬/挑战页(命中 {marker!r},title={title[:80]!r})" + if len(md) < _MIN_TEXT_CHARS: + return "", f"正文提取过短({len(md)} < {_MIN_TEXT_CHARS} 字符),疑似 JS 渲染或空壳页" + if len(md) > MAX_CHARS: + md = md[:MAX_CHARS - 1] + "…" + return md, None + + +# ---------------------------------------------------------------- 入口 + +async def fetch_submission_guidelines(url: str) -> dict: + """抓投稿指南页面 → 正文 Markdown。 + + 流程:robots.txt 检查(≥2s 限速)→ 禁止即跳过 → GET 正文(≥2s 限速) + → 状态/类型校验 → 正文提取 → 截断 30000 字符。 + """ + parsed = urlparse(url) + if parsed.scheme not in ("http", "https") or not parsed.netloc: + return _fail(f"非法 URL:{url!r}") + host = parsed.netloc.lower() + + async with httpx.AsyncClient(follow_redirects=True, timeout=TIMEOUT) as client: + allowed, robots_reason = await _robots_allows(client, url) + if not allowed: + logger.info("[fetch] robots 禁止,跳过 %s(%s)", url, robots_reason) + return _fail(robots_reason) + + await _throttle(host) + try: + resp = await client.get(url, headers=_HEADERS) + except httpx.HTTPError as exc: + return _fail(f"请求失败({type(exc).__name__}):{exc}") + if resp.status_code != 200: + return _fail(f"HTTP {resp.status_code}") + ctype = resp.headers.get("content-type", "") + if "html" not in ctype and "xhtml" not in ctype: + return _fail(f"非 HTML 响应:{ctype or '无 Content-Type'}") + + markdown, err = _html_to_markdown(_decode_html(resp)) + if err: + return _fail(f"{err}(robots: {robots_reason})") + logger.info("[fetch] %s → %d 字符(robots: %s)", url, len(markdown), robots_reason) + return {"ok": True, "markdown": markdown, "error": None, "fetched_at": _now_iso()} diff --git a/review_service/app/services/journal_kb.py b/review_service/app/services/journal_kb.py new file mode 100644 index 0000000..b64c210 --- /dev/null +++ b/review_service/app/services/journal_kb.py @@ -0,0 +1,223 @@ +"""services/journal_kb.py —— 期刊 scope_desc → vstore 入库 + 向量匹配(只读消费 8094)。 + +链路(全部复用 vstore 既有 API,零改动): +1. ensure_scope_docs:各期刊 scope_desc 以 .txt 入库(category=journal_scope, + name=期刊名),document_id 回写 journals.vstore_doc_id(幂等:已有 id 不重灌)。 +2. match:GET /api/vstore/search-chunks?q=<摘要截断>&doc_ids=&top_k=N + → 按 doc_id 映射回期刊,取该期刊最高 chunk 分数为 similarity。 +3. 自愈:白名单命中 0 条 → GET /documents/{id} 探活 → 失效的重灌(vstore 去重 + 语义下同内容重灌会换 doc_id,需回写)→ 重试一次 → 仍 0 视为语义低相似。 + +错误语义:连通性/上游异常抛 MatchError(路由降级为全量候选); +返回 ([], False) 表示检索成功但无有效匹配(路由同样降级)。 +""" +from __future__ import annotations + +import logging +from typing import Any + +import httpx + +from ..config import get_settings +from ..db import set_vstore_doc_id + +logger = logging.getLogger(__name__) + +SCOPE_CATEGORY = "journal_scope" + + +class MatchError(Exception): + """vstore 向量匹配失败(不可达/响应异常)。""" + + +def _timeout() -> httpx.Timeout: + t = get_settings().vstore_match_timeout + return httpx.Timeout(connect=5.0, read=t, write=t, pool=5.0) + + +def _err_body(resp: httpx.Response) -> str: + try: + payload = resp.json() + except ValueError: + return (resp.text or "").strip()[:500] or "(空响应体)" + if isinstance(payload, dict): + err = payload.get("error") + if isinstance(err, dict) and err.get("message"): + return str(err["message"]) + if isinstance(err, str): + return err + return str(payload)[:500] + + +async def _ingest_scope(client: httpx.AsyncClient, base: str, journal: dict[str, Any]) -> str: + """单本期刊 scope_desc 入库,返回 document_id。""" + content = str(journal.get("scope_desc") or "").strip() + if not content: + raise MatchError(f"期刊 scope_desc 为空:{journal.get('id')}") + jid = str(journal.get("id") or "") + try: + resp = await client.post( + f"{base}/api/vstore/ingest", + files={"file": (f"{jid}.txt", content.encode("utf-8"), "text/plain")}, + data={ + "name": str(journal.get("name") or jid), + "category": SCOPE_CATEGORY, + "description": "review_service 期刊范围种子(scope_desc 向量匹配)", + }, + ) + except httpx.HTTPError as exc: + raise MatchError(f"vstore 不可达({base}):{exc}") from exc + if resp.status_code >= 400: + raise MatchError(f"vstore ingest 失败(HTTP {resp.status_code}):{_err_body(resp)}") + try: + payload = resp.json() + except ValueError as exc: + raise MatchError(f"vstore ingest 响应非 JSON:{exc}") from exc + if not isinstance(payload, dict) or not payload.get("ok"): + raise MatchError( + str((payload.get("error") or {}).get("message") if isinstance(payload, dict) else "") or "vstore ingest 失败" + ) + doc_id = str((payload.get("item") or {}).get("document_id") or "") + if not doc_id: + raise MatchError("vstore ingest 响应缺少 document_id") + return doc_id + + +async def ensure_scope_docs(journals: list[dict[str, Any]]) -> list[dict[str, Any]]: + """补齐缺失的 scope 入库映射(就地回写 vstore_doc_id 并持久到 DB)。""" + settings = get_settings() + missing = [j for j in journals if not j.get("vstore_doc_id")] + if not missing: + return journals + async with httpx.AsyncClient(timeout=_timeout()) as client: + for j in missing: + try: + doc_id = await _ingest_scope(client, settings.vstore_base, j) + except MatchError as exc: + # 单本失败不阻断其余(该期刊将不进白名单,由路由降级兜底) + logger.warning("journal_kb: scope 入库失败(%s):%s", j.get("id"), exc) + continue + j["vstore_doc_id"] = doc_id + await set_vstore_doc_id(str(j["id"]), doc_id) + return journals + + +async def _search( + client: httpx.AsyncClient, base: str, query: str, doc_ids: list[str] +) -> list[dict[str, Any]]: + """chunk 级白名单检索。连通/上游错误抛 MatchError。""" + if not doc_ids: + # doc_ids 为空时 vstore 侧等于不过滤 → 会命中用户私有库,必须拦死 + raise MatchError("白名单为空,拒绝全库检索") + try: + resp = await client.get( + f"{base}/api/vstore/search-chunks", + params={ + "q": query, + "top_k": get_settings().recommend_scope_top_k, + "doc_ids": ",".join(doc_ids), + }, + ) + except httpx.HTTPError as exc: + raise MatchError(f"vstore search-chunks 不可达:{exc}") from exc + if resp.status_code >= 400: + raise MatchError(f"vstore search-chunks 失败(HTTP {resp.status_code}):{_err_body(resp)}") + try: + payload = resp.json() + except ValueError as exc: + raise MatchError(f"vstore search-chunks 响应非 JSON:{exc}") from exc + if not isinstance(payload, dict) or not payload.get("ok"): + raise MatchError( + str((payload.get("error") or {}).get("message") if isinstance(payload, dict) else "") or "vstore search-chunks 失败" + ) + items = payload.get("items") + return items if isinstance(items, list) else [] + + +async def _doc_alive(client: httpx.AsyncClient, base: str, doc_id: str) -> bool: + try: + resp = await client.get(f"{base}/api/vstore/documents/{doc_id}") + except httpx.HTTPError: + return False + if resp.status_code != 200: + return False + try: + payload = resp.json() + except ValueError: + return False + return bool(isinstance(payload, dict) and payload.get("ok")) + + +async def _refresh_dead_docs( + client: httpx.AsyncClient, base: str, journals: list[dict[str, Any]] +) -> None: + """白名单 0 命中时探活:失效文档重灌并回写新 id。""" + for j in journals: + doc_id = str(j.get("vstore_doc_id") or "") + if not doc_id or await _doc_alive(client, base, doc_id): + continue + try: + new_id = await _ingest_scope(client, base, j) + except MatchError as exc: + logger.warning("journal_kb: scope 重灌失败(%s):%s", j.get("id"), exc) + continue + j["vstore_doc_id"] = new_id + await set_vstore_doc_id(str(j["id"]), new_id) + + +async def match( + abstract: str, journals: list[dict[str, Any]] +) -> tuple[list[dict[str, Any]], bool]: + """摘要 vs scope_desc 向量匹配。 + + 返回 (candidates, vector_ok);candidates 元素: + {"journal": , "similarity": float} + 按 similarity 降序。MatchError → 路由降级;([], False) → 语义低相似。 + """ + settings = get_settings() + query = abstract.strip()[: settings.recommend_query_chars] + if not query: + return [], False + + await ensure_scope_docs(journals) + whitelisted = [j for j in journals if j.get("vstore_doc_id")] + if not whitelisted: + raise MatchError("无任何期刊 scope 入库成功(vstore_doc_id 为空)") + + doc_map = {str(j["vstore_doc_id"]): j for j in whitelisted} + timeout = _timeout() + async with httpx.AsyncClient(timeout=timeout) as client: + items = await _search(client, settings.vstore_base, query, list(doc_map)) + if not items: + await _refresh_dead_docs(client, settings.vstore_base, whitelisted) + doc_map = {str(j["vstore_doc_id"]): j for j in whitelisted if j.get("vstore_doc_id")} + if not doc_map: + return [], False + items = await _search(client, settings.vstore_base, query, list(doc_map)) + + # 聚合:每本期刊取最高 chunk 分 + best: dict[str, float] = {} + for item in items: + if not isinstance(item, dict): + continue + j = doc_map.get(str(item.get("doc_id") or "")) + if j is None: + continue + try: + score = float(item.get("score")) + except (TypeError, ValueError): + continue + jid = str(j["id"]) + if jid not in best or score > best[jid]: + best[jid] = score + if not best: + return [], False + + by_id = {str(j["id"]): j for j in journals} + candidates = [ + {"journal": by_id[jid], "similarity": score} + for jid, score in best.items() + if jid in by_id + ] + candidates.sort(key=lambda c: c["similarity"], reverse=True) + return candidates, bool(candidates) diff --git a/review_service/app/services/journal_rank.py b/review_service/app/services/journal_rank.py new file mode 100644 index 0000000..d478369 --- /dev/null +++ b/review_service/app/services/journal_rank.py @@ -0,0 +1,210 @@ +"""services/journal_rank.py —— LLM 重排 + 幻觉防护 + 三档归类。 + +职责: +1. rerank:把带语义分的候选期刊(来自 journal_kb)+ 用户偏好交给 LLM, + 要求按 id 白名单返回 {rankings:[{id, tier, match_reason, risk_note}]}。 +2. validate:硬校验——白名单外 id 丢弃(幻觉拦截);tier 非法/LLM 缺漏的 + 期刊按规则补位(绝不因 LLM 输出丢失候选期刊);期刊名称/指标一律不采信 + LLM,最终展示全部用 DB 字段(防止改名型幻觉)。 +3. fallback_rankings:LLM 不可用时的确定性规则分档(按 impact_factor)。 + +三档语义:challenge 挑战型(高影响/慢审稿)、fit 适配型(均衡)、 +safe 稳妥型(快速/门槛低)。 +""" +from __future__ import annotations + +import json +from dataclasses import dataclass +from typing import Any + +from ..config import get_settings +from . import llm + +TIERS = ("challenge", "fit", "safe") +TIER_LABELS = { + "challenge": "挑战型(高影响因子/慢审稿)", + "fit": "适配型(中等影响/周期适中)", + "safe": "稳妥型(快速发表/门槛较低)", +} + +# 规则分档阈值(近似值,可后续配置化) +_CHALLENGE_MIN_IF = 9.0 +_SAFE_MAX_IF = 4.0 + +# tier 同义词归一(LLM 偶发中文标签) +_TIER_ALIASES = { + "挑战": "challenge", + "挑战型": "challenge", + "高风险": "challenge", + "适配": "fit", + "适配型": "fit", + "稳妥": "safe", + "稳妥型": "safe", + "低风险": "safe", +} + +SYSTEM_PROMPT = """你是学术投稿推荐专家(植物基因组学方向)。根据给定候选期刊、论文摘要与用户偏好,为**每一个**候选期刊输出推荐分档与理由。 + +硬规则(违反即视为无效输出): +1. id 白名单:只能使用输入 candidates 中出现的 id;绝对禁止添加、替换或臆造列表之外的任何期刊。 +2. 每个输入 id 恰好输出一次,不得遗漏、不得重复;期刊名称等元数据由系统填充,你只输出 id。 +3. tier 只能取 challenge | fit | safe: + - challenge(挑战型):高影响因子、审稿较慢或竞争激烈的期刊 + - fit(适配型):影响力与发表周期均衡、与论文契合的期刊 + - safe(稳妥型):审稿较快、门槛较低、命中概率较高的期刊 +4. match_reason:中文,1-2 句,结合摘要的研究主题与该刊 scope_desc 及指标(如有 similarity 一并参考),说明为何匹配/不匹配。 +5. risk_note:中文,1-2 句,指出投稿风险(超出用户偏好、IF 门槛偏高、范围匹配偏弱、审稿周期长等);无明显风险写「无」。 +6. 用户 preferences 为软约束:不满足偏好的期刊仍必须输出,并在 risk_note 中明确说明。 +7. 不确定时宁可保守陈述,禁止编造统计数据(录用率、审稿天数等)。 + +输出:仅一个 JSON 对象,格式: +{"rankings":[{"id":"...","tier":"challenge","match_reason":"...","risk_note":"..."}]} +不要输出任何 JSON 之外的内容。""" + + +class RankError(Exception): + """LLM 输出形态异常(无法按 JSON 解析/结构非法)。""" + + +@dataclass +class Ranking: + journal_id: str + tier: str + match_reason: str + risk_note: str + + +def rule_tier(journal: dict[str, Any]) -> str: + """确定性分档规则(LLM 缺漏/不可用时兜底)。""" + inf = journal.get("impact_factor") + weeks = journal.get("review_time_weeks") + if isinstance(inf, (int, float)): + if inf >= _CHALLENGE_MIN_IF: + return "challenge" + if inf <= _SAFE_MAX_IF: + return "safe" + elif isinstance(weeks, (int, float)) and weeks <= 4: + return "safe" + return "fit" + + +def build_user_prompt( + abstract: str, + candidates: list[dict[str, Any]], + preferences: dict[str, Any], +) -> str: + """候选 + 偏好 + 摘要 → 用户消息(JSON)。""" + payload = { + "abstract": abstract.strip()[:4000], + "preferences": preferences or {}, + "candidates": [ + { + "id": str(c["journal"]["id"]), + "name": str(c["journal"].get("name") or ""), + "impact_factor": c["journal"].get("impact_factor"), + "review_time_weeks": c["journal"].get("review_time_weeks"), + "acceptance_rate": c["journal"].get("acceptance_rate"), + "similarity": c.get("similarity"), + "scope_desc": str(c["journal"].get("scope_desc") or "")[:400], + } + for c in candidates + ], + } + return json.dumps(payload, ensure_ascii=False) + + +def _normalize_tier(raw: Any) -> str | None: + tier = str(raw or "").strip().lower() + tier = _TIER_ALIASES.get(str(raw or "").strip(), tier) + return tier if tier in TIERS else None + + +def validate_rankings( + payload: Any, candidates: list[dict[str, Any]] +) -> tuple[list[Ranking], int, int]: + """校验 LLM 输出。 + + 返回 (rankings, dropped_hallucinated, repaired): + - 白名单外 id / 重复 id → 丢弃并计数(repaired 中重复不计); + - tier 非法、LLM 缺漏的 id → 按规则补位(repaired 计数)。 + """ + if not isinstance(payload, dict) or not isinstance(payload.get("rankings"), list): + raise RankError("LLM 输出缺少 rankings 数组") + + by_id = {str(c["journal"]["id"]): c["journal"] for c in candidates} + input_ids = list(by_id) + seen: set[str] = set() + rankings: list[Ranking] = [] + dropped = 0 + repaired = 0 + + for entry in payload["rankings"]: + if not isinstance(entry, dict): + dropped += 1 + continue + jid = str(entry.get("id") or "").strip() + if jid in seen: + continue + if jid not in by_id: + dropped += 1 # 幻觉期刊:绝不进输出 + continue + seen.add(jid) + tier = _normalize_tier(entry.get("tier")) + if tier is None: + tier = rule_tier(by_id[jid]) + repaired += 1 + reason = str(entry.get("match_reason") or "").strip() or "基于期刊范围与指标的匹配" + risk = str(entry.get("risk_note") or "").strip() or "无" + rankings.append(Ranking(journal_id=jid, tier=tier, match_reason=reason, risk_note=risk)) + + for jid in input_ids: + if jid in seen: + continue + rankings.append( + Ranking( + journal_id=jid, + tier=rule_tier(by_id[jid]), + match_reason="LLM 未给出该期刊条目,已按影响因子/周期规则补位", + risk_note="未提供(LLM 输出缺漏,规则兜底)", + ) + ) + repaired += 1 + return rankings, dropped, repaired + + +async def rerank( + abstract: str, + candidates: list[dict[str, Any]], + preferences: dict[str, Any], +) -> tuple[list[Ranking], int, int]: + """LLM 重排 + 校验。LLMError / RankError 上抛(路由降级为规则分档)。""" + settings = get_settings() + payload = await llm.complete_json( + SYSTEM_PROMPT, + build_user_prompt(abstract, candidates, preferences), + temperature=0.2, + max_tokens=3000, + timeout=settings.recommend_read_timeout, + ) + return validate_rankings(payload, candidates) + + +def fallback_rankings(candidates: list[dict[str, Any]]) -> list[Ranking]: + """LLM 不可用时的确定性分档(不丢任何候选期刊)。""" + rankings: list[Ranking] = [] + for c in candidates: + j = c["journal"] + inf = j.get("impact_factor") + weeks = j.get("review_time_weeks") + rankings.append( + Ranking( + journal_id=str(j["id"]), + tier=rule_tier(j), + match_reason=( + f"规则分档:影响因子 {inf if inf is not None else '未收录'}、" + f"审稿约 {weeks if weeks is not None else '未收录'} 周" + ), + risk_note="LLM 不可用,本条按影响因子/周期规则估算", + ) + ) + return rankings diff --git a/review_service/app/services/latex_compile.py b/review_service/app/services/latex_compile.py new file mode 100644 index 0000000..b396769 --- /dev/null +++ b/review_service/app/services/latex_compile.py @@ -0,0 +1,236 @@ +"""services/latex_compile.py —— tectonic 编译 .tex → PDF(P3a)。 + +隔离与安全(对齐设计清单): + 1. 一编译一目录:{reformat_dir}/{anchor_id}/compile/(input.tex/output.pdf/output.log/meta.json) + 2. 文件名永不落盘:用户文件名只做后缀校验,写入一律 input.tex + 3. tectonic --untrusted(官方旗标:禁用已知不安全特性,含 shell escape 路径) + 4. 子进程 start_new_session + 超时 killpg(SIGKILL)(整进程组) + 5. 单槽队列:asyncio.Lock + pending 计数,超出 compile_queue_limit → QueueFullError + 6. 产物 PDF > max_compile_pdf_bytes → 删文件 + OutputTooLargeError + 7. 启动/每次编译前机会性清扫 retention_days 天前的 job 目录(只删 12 位 hex 锚点目录) + +tectonic 二进制缺失 → ToolUnavailableError(路由层回安装指引)。 +""" +from __future__ import annotations + +import asyncio +import json +import logging +import os +import re +import shutil +import signal +import time +from datetime import datetime, timezone +from pathlib import Path +from typing import Any + +from ..config import get_settings + +logger = logging.getLogger(__name__) + +_ANCHOR_ID_RE = re.compile(r"^[0-9a-f]{12}$") +_ENGINE = "tectonic-p3/0.17.0" +_LOG_TAIL_LINES = 200 + +# 单槽并发控制(进程内;重启归零可接受——本服务无持久队列需求) +_lock = asyncio.Lock() +_pending = 0 + + +class CompileError(Exception): + """编译失败(含 log 尾)。code ∈ {COMPILE_FAILED, TIMEOUT, OUTPUT_TOO_LARGE}。""" + + def __init__(self, code: str, message: str, log_tail: str = "") -> None: + super().__init__(message) + self.code = code + self.log_tail = log_tail + + +class QueueFullError(Exception): + """等待槽位超限。""" + + +class ToolUnavailableError(Exception): + """tectonic 二进制缺失/不可执行。""" + + +def _tectonic_bin() -> Path: + return get_settings().tectonic_abs + + +def _ensure_tool() -> Path: + bin_path = _tectonic_bin() + if not (bin_path.is_file() and os.access(bin_path, os.X_OK)): + raise ToolUnavailableError( + f"tectonic 未安装({bin_path})。" + "请执行:cd review_service && bash tools/install_tectonic.sh" + ) + return bin_path + + +def _log_tail(path: Path, lines: int = _LOG_TAIL_LINES) -> str: + try: + text = path.read_text("utf-8", errors="replace") + except OSError: + return "" + return "\n".join(text.splitlines()[-lines:]) + + +def compile_dir(anchor_id: str) -> Path: + """{reformat_dir}/{anchor_id}/compile/(存在性由调用方按需 mkdir)。""" + return get_settings().reformat_dir_abs / anchor_id / "compile" + + +def prepare_input(anchor_id: str, source: str) -> Path: + """写入隔离目录 input.tex;返回其路径。""" + cdir = compile_dir(anchor_id) + cdir.mkdir(parents=True, exist_ok=True) + input_tex = cdir / "input.tex" + input_tex.write_text(source, encoding="utf-8") + return input_tex + + +async def compile_tex(anchor_id: str) -> dict[str, Any]: + """同步编译 anchor 的 input.tex(须先 prepare_input)。 + + → {compile_id: anchor_id, pdf_path, log_path, seconds, pdf_bytes} + 失败抛 CompileError / QueueFullError / ToolUnavailableError。 + """ + global _pending + settings = get_settings() + _ensure_tool() # 快速失败:不占队列 + sweep_expired() + + if _pending >= settings.compile_queue_limit: + raise QueueFullError( + f"编译队列已满({_pending} 个任务排队),请稍后重试" + ) + _pending += 1 + try: + async with _lock: + return await _run_once(anchor_id) + finally: + _pending -= 1 + + +async def _run_once(anchor_id: str) -> dict[str, Any]: + settings = get_settings() + cdir = compile_dir(anchor_id) + input_tex = cdir / "input.tex" + pdf_path = cdir / "output.pdf" + log_path = cdir / "output.log" + if not input_tex.is_file(): + raise CompileError("COMPILE_FAILED", "编译输入不存在,请重新上传源码") + + env = dict(os.environ) + env["TECTONIC_CACHE_DIR"] = str(settings.tectonic_cache_abs) + cmd = [ + str(_tectonic_bin()), "-X", "compile", input_tex.name, + "--untrusted", "--keep-logs", "--outdir", ".", + ] + started = time.monotonic() + try: + proc = await asyncio.create_subprocess_exec( + *cmd, cwd=cdir, env=env, + stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT, + start_new_session=True, + ) + try: + await asyncio.wait_for( + proc.communicate(), timeout=settings.compile_timeout_s + ) + except asyncio.TimeoutError: + _kill_group(proc) + try: + await asyncio.wait_for(proc.wait(), timeout=5.0) + except asyncio.TimeoutError: + pass + log_path.write_text(_log_tail(log_path) + "\n[timeout] 编译超时,进程已终止", + encoding="utf-8") + raise CompileError( + "TIMEOUT", + f"编译超过 {settings.compile_timeout_s:g} 秒未完成,已终止", + _log_tail(log_path), + ) from None + except FileNotFoundError as exc: + raise ToolUnavailableError(f"tectonic 不可执行:{exc}") from exc + finally: + seconds = round(time.monotonic() - started, 2) + + # tectonic --keep-logs 把日志写在 cwd 的 input.log + produced_log = cdir / "input.log" + if produced_log.is_file(): + shutil.move(str(produced_log), str(log_path)) + if not log_path.is_file(): + log_path.write_text("", encoding="utf-8") + + produced_pdf = cdir / "input.pdf" + if not produced_pdf.is_file(): + raise CompileError( + "COMPILE_FAILED", + "编译失败(未产出 PDF),请查看日志定位 LaTeX 错误", + _log_tail(log_path), + ) + pdf_bytes = produced_pdf.stat().st_size + if pdf_bytes > settings.max_compile_pdf_bytes: + produced_pdf.unlink(missing_ok=True) + raise CompileError( + "OUTPUT_TOO_LARGE", + f"产出 PDF 超过 {settings.max_compile_pdf_bytes // (1024 * 1024)}MB 上限,已删除", + _log_tail(log_path), + ) + produced_pdf.rename(pdf_path) + + meta = { + "compile_id": anchor_id, + "engine": _ENGINE, + "seconds": seconds, + "pdf_bytes": pdf_bytes, + "returncode": 0, + "compiled_at": datetime.now(timezone.utc).isoformat(timespec="seconds"), + } + (cdir / "meta.json").write_text( + json.dumps(meta, ensure_ascii=False, indent=2), encoding="utf-8" + ) + logger.info("compile: %s → PDF %d bytes, %.2fs", anchor_id, pdf_bytes, seconds) + return { + "compile_id": anchor_id, + "pdf_path": pdf_path, + "log_path": log_path, + "seconds": seconds, + "pdf_bytes": pdf_bytes, + } + + +def _kill_group(proc: asyncio.subprocess.Process) -> None: + try: + os.killpg(os.getpgid(proc.pid), signal.SIGKILL) + except (ProcessLookupError, PermissionError, OSError): + try: + proc.kill() + except ProcessLookupError: + pass + + +def sweep_expired() -> int: + """删除 mtime 超 retention_days 的 12-hex 锚点目录(编译产物+P1 落盘一并清)。""" + settings = get_settings() + base = settings.reformat_dir_abs + if not base.is_dir(): + return 0 + cutoff = time.time() - settings.compile_retention_days * 86400 + removed = 0 + for child in base.iterdir(): + if not child.is_dir() or not _ANCHOR_ID_RE.fullmatch(child.name): + continue + try: + if child.stat().st_mtime < cutoff: + shutil.rmtree(child, ignore_errors=True) + removed += 1 + except OSError: + continue + if removed: + logger.info("compile sweep: 清理 %d 个过期任务目录(>%d 天)", + removed, settings.compile_retention_days) + return removed diff --git a/review_service/app/services/llm.py b/review_service/app/services/llm.py new file mode 100644 index 0000000..06c8e43 --- /dev/null +++ b/review_service/app/services/llm.py @@ -0,0 +1,203 @@ +"""services/llm.py —— LLM 调用(httpx 裸调 DeepSeek,模式同 paper_writer_service)。 + +- complete_text(system, user, *, temperature=0.3, max_tokens=8000, timeout=None) -> str +- complete_json(...)(response_format json_object + 一次 JSON 修复重试) +- 4 次尝试(1.5s / 3s / 6s 指数退避,429 / 5xx / 超时) +- env 键(优先 REVIEW_LLM_*,回退 DOCGEN_LLM_*,再回退内置默认): + *_LLM_BASE_URL / *_LLM_API_KEY / *_LLM_MODEL / *_LLM_TIMEOUT +""" +from __future__ import annotations + +import asyncio +import json +import logging +import os +from typing import Any + +import httpx + +logger = logging.getLogger(__name__) + +DEFAULT_LLM_BASE_URL = "https://api.deepseek.com/v1" +DEFAULT_LLM_MODEL = "deepseek-chat" +DEFAULT_LLM_TIMEOUT = 300.0 +BACKOFF_SECONDS = (1.5, 3.0, 6.0) +MAX_ATTEMPTS = 4 + + +class LLMError(Exception): + """LLM 调用失败(重试尽/响应异常)。""" + + +def _env(keys: tuple[str, ...], default: str = "") -> str: + for key in keys: + val = os.environ.get(key) + if val: + return val + return default + + +def _llm_config() -> dict[str, Any]: + return { + "base_url": _env( + ("REVIEW_LLM_BASE_URL", "DOCGEN_LLM_BASE_URL"), DEFAULT_LLM_BASE_URL + ).rstrip("/"), + "api_key": _env(("REVIEW_LLM_API_KEY", "DOCGEN_LLM_API_KEY"), ""), + "model": _env(("REVIEW_LLM_MODEL", "DOCGEN_LLM_MODEL"), DEFAULT_LLM_MODEL), + "timeout": float( + _env(("REVIEW_LLM_TIMEOUT", "DOCGEN_LLM_TIMEOUT"), str(DEFAULT_LLM_TIMEOUT)) + ), + } + + +def _extract_text(payload: dict[str, Any]) -> str: + try: + choices = payload.get("choices") or [] + if choices: + content = choices[0].get("message", {}).get("content") + if isinstance(content, str): + return content + if isinstance(content, list): + return "".join( + str(c.get("text", "")) if isinstance(c, dict) else str(c) for c in content + ) + except Exception: + pass + return "" + + +async def _chat_once( + client: httpx.AsyncClient, + cfg: dict[str, Any], + system: str, + user: str, + *, + temperature: float, + max_tokens: int, + json_mode: bool, + timeout: float | None, +) -> str: + headers = {"Content-Type": "application/json"} + if cfg["api_key"]: + headers["Authorization"] = f"Bearer {cfg['api_key']}" + body: dict[str, Any] = { + "model": cfg["model"], + "messages": [ + {"role": "system", "content": system}, + {"role": "user", "content": user}, + ], + "temperature": temperature, + "max_tokens": max_tokens, + } + if json_mode: + body["response_format"] = {"type": "json_object"} + resp = await client.post( + f"{cfg['base_url']}/chat/completions", + headers=headers, + json=body, + timeout=timeout if timeout is not None else cfg["timeout"], + ) + resp.raise_for_status() + payload = resp.json() + if not isinstance(payload, dict): + raise LLMError("LLM 响应形态异常(非 JSON 对象)") + text = _extract_text(payload) + if not text: + raise LLMError("LLM 响应缺少 choices[0].message.content") + return text + + +async def _complete( + system: str, + user: str, + *, + temperature: float, + max_tokens: int, + json_mode: bool, + timeout: float | None, +) -> str: + cfg = _llm_config() + last_exc: BaseException | None = None + async with httpx.AsyncClient() as client: + for attempt in range(MAX_ATTEMPTS): + try: + return await _chat_once( + client, cfg, system, user, + temperature=temperature, max_tokens=max_tokens, json_mode=json_mode, + timeout=timeout, + ) + except LLMError: + raise + except (httpx.HTTPStatusError, httpx.HTTPError, httpx.TimeoutException) as exc: + last_exc = exc + status = getattr(getattr(exc, "response", None), "status_code", None) + retryable = status is None or status == 429 or status >= 500 + if not retryable or attempt == MAX_ATTEMPTS - 1: + raise LLMError(f"LLM 调用失败(HTTP {status or '网络'}):{exc}") from exc + await asyncio.sleep(BACKOFF_SECONDS[min(attempt, len(BACKOFF_SECONDS) - 1)]) + raise LLMError(f"LLM 调用失败:{last_exc}") + + +async def complete_text( + system: str, + user: str, + *, + temperature: float = 0.3, + max_tokens: int = 8000, + timeout: float | None = None, +) -> str: + """文本补全。失败抛 LLMError。""" + return await _complete( + system, user, temperature=temperature, max_tokens=max_tokens, json_mode=False, + timeout=timeout, + ) + + +def _repair_json(text: str) -> str: + text = text.strip() + if text.startswith("```"): + text = text.strip("`") + if text.lower().startswith("json"): + text = text[4:] + text = text.strip() + if not text: + raise LLMError("LLM 返回空内容") + if text.startswith("{"): + return text + start = text.find("{") + end = text.rfind("}") + if start >= 0 and end > start: + return text[start:end + 1] + raise LLMError("LLM 输出中未找到 JSON 对象") + + +async def complete_json( + system: str, + user: str, + *, + temperature: float = 0.3, + max_tokens: int = 8000, + timeout: float | None = None, +) -> dict[str, Any]: + """JSON 补全(json_object + 一次修复重试)。""" + text = await _complete( + system, user, temperature=temperature, max_tokens=max_tokens, json_mode=True, + timeout=timeout, + ) + try: + return json.loads(text) + except ValueError: + pass + text2 = await _complete( + system + "\n(重要:你的回答必须是单个合法 JSON 对象,不要输出其他任何内容)", + user, + temperature=temperature, + max_tokens=max_tokens, + json_mode=True, + timeout=timeout, + ) + try: + return json.loads(text2) + except ValueError: + repaired = _repair_json(text2) + return json.loads(repaired) diff --git a/review_service/app/services/paper_parse.py b/review_service/app/services/paper_parse.py new file mode 100644 index 0000000..cb7c3f5 --- /dev/null +++ b/review_service/app/services/paper_parse.py @@ -0,0 +1,139 @@ +"""paper_parse.py —— PDF → 纯文本(经 vstore 8094 现有解析接口,零改动复用)。 + +链路(全部只读消费 vstore 既有 API,不修改 vstore 代码): +1. POST {vstore}/api/vstore/ingest multipart file(vstore 内部 pymupdf 解析) +2. GET {vstore}/api/vstore/documents/{doc_id} → document.paragraphs 拼接纯文本 +3. DELETE {vstore}/api/vstore/documents/{doc_id} (临时解析件 best-effort 清理, + REVIEW_PARSE_DELETE_AFTER=0 可关闭——保留文档便于人工排查) + +为何不用 methodology 8092:其 /extract-upload 是 MinerU 分钟级异步 job +(MinerU 子进程 + LLM 抽取两阶段),不适配同步自审稿;vstore 段落解析秒级 +返回,满足 presubmit 场景。methodology 地址在 config 中预留供后续扩展。 +""" +from __future__ import annotations + +import logging +from typing import Any + +import httpx + +from ..config import get_settings + +logger = logging.getLogger(__name__) + + +class ParseError(Exception): + """PDF 解析失败(上游不可达/响应异常/空文本)。""" + + +async def parse_pdf(path: str) -> str: + """接收 PDF 文件路径,返回拼接后的纯文本。失败抛 ParseError。""" + try: + with open(path, "rb") as fh: + file_bytes = fh.read() + except OSError as exc: + raise ParseError(f"读取 PDF 失败:{exc}") from exc + return await parse_pdf_bytes(file_bytes, filename=str(path).rsplit("/", 1)[-1] or "paper.pdf") + + +async def parse_pdf_bytes(file_bytes: bytes, filename: str = "paper.pdf") -> str: + """接收 PDF 字节流,返回拼接后的纯文本。失败抛 ParseError。""" + if not file_bytes: + raise ParseError("PDF 内容为空") + + settings = get_settings() + base = settings.vstore_base + timeout = httpx.Timeout( + connect=5.0, read=settings.parse_timeout, write=settings.parse_timeout, pool=5.0 + ) + + async with httpx.AsyncClient(timeout=timeout) as client: + # ---- 1) ingest(vstore 内部 pymupdf 解析 + 嵌入 + 加密落盘)---- + try: + resp = await client.post( + f"{base}/api/vstore/ingest", + files={"file": (filename, file_bytes, "application/pdf")}, + data={ + "name": filename, + "category": "review_presubmit", + "description": "review_service 临时解析件", + }, + ) + except httpx.HTTPError as exc: + raise ParseError(f"vstore 不可达({base}):{exc}") from exc + + if resp.status_code >= 400: + # 读上游错误体(信封 JSON 或裸文本),区分“不可达”与“上游报错” + raise ParseError(f"vstore ingest 失败(HTTP {resp.status_code}):{_err_body(resp)}") + + try: + payload = resp.json() + except ValueError as exc: + raise ParseError(f"vstore ingest 响应非 JSON:{exc}") from exc + + if not isinstance(payload, dict) or not payload.get("ok"): + message = _err_message(payload) or "vstore ingest 失败" + raise ParseError(message) + doc_id = str((payload.get("item") or {}).get("document_id") or "") + if not doc_id: + raise ParseError("vstore ingest 响应缺少 document_id") + + # ---- 2) 取明文全文(paragraphs 拼接)+ 3) 清理临时件 ---- + try: + text = await _fetch_text(client, base, doc_id) + finally: + if settings.parse_delete_after: + await _best_effort_delete(client, base, doc_id) + + text = text.strip() + if not text: + raise ParseError("PDF 解析结果为空(可能是扫描件/图片型 PDF,vstore 无 OCR)") + return text + + +async def _fetch_text(client: httpx.AsyncClient, base: str, doc_id: str) -> str: + """取 vstore 文档明文并按段落拼接纯文本。""" + try: + resp = await client.get(f"{base}/api/vstore/documents/{doc_id}") + except httpx.HTTPError as exc: + raise ParseError(f"vstore 取文档失败({doc_id}):{exc}") from exc + if resp.status_code >= 400: + raise ParseError( + f"vstore 取文档失败({doc_id},HTTP {resp.status_code}):{_err_body(resp)}" + ) + try: + payload = resp.json() + except ValueError as exc: + raise ParseError(f"vstore 取文档响应非 JSON({doc_id}):{exc}") from exc + if not isinstance(payload, dict) or not payload.get("ok"): + raise ParseError(_err_message(payload) or f"vstore 取文档失败({doc_id})") + + document: dict[str, Any] = payload.get("document") or {} + paragraphs = document.get("paragraphs") or [] + return "\n".join(str(p) for p in paragraphs if str(p).strip()) + + +async def _best_effort_delete(client: httpx.AsyncClient, base: str, doc_id: str) -> None: + try: + await client.delete(f"{base}/api/vstore/documents/{doc_id}") + except Exception: # noqa: BLE001 - 清理失败不阻断(文档级 secure_delete 已尽力) + logger.warning("paper_parse: vstore 临时文档清理失败(%s)", doc_id, exc_info=True) + + +def _err_message(payload: Any) -> str: + if isinstance(payload, dict): + err = payload.get("error") + if isinstance(err, dict): + return str(err.get("message") or "") + if isinstance(err, str): + return err + return "" + + +def _err_body(resp: httpx.Response) -> str: + """上游错误体:优先 JSON 信封 message,回退裸文本(截断 500 字符)。""" + try: + payload = resp.json() + except ValueError: + return (resp.text or "").strip()[:500] or "(空响应体)" + return _err_message(payload) or str(payload)[:500] diff --git a/review_service/app/services/reformat.py b/review_service/app/services/reformat.py new file mode 100644 index 0000000..c241eff --- /dev/null +++ b/review_service/app/services/reformat.py @@ -0,0 +1,553 @@ +r"""services/reformat.py —— P1 论文重排版(.tex 源码级规则变换,不编译)。 + +链路:resolve_rules(三级规则解析)→ reformat_tex(4 变换器 + 结构守卫) + → 路由层落盘 data/reformat_jobs/{job_id}.tex/.json。 +纯规则、零 LLM、零执行用户内容、不碰 docx/pdf(那两个只在 FormatPanel 审核)。 + +拍板(用户 4 点确认,2026-10-10): +1. changes[] 每条带 rule_key ∈ {font_pt, margin, line_spacing, bib_style}、 + action ∈ {modified, inserted, warning}(P1 只产生 modified/warning, + inserted 留给后续阶段);前端按 rule_key 着色、按 action 计数。 +2. 保守插入策略:命令/选项缺失一律【不改源码】→ changes 里 action=warning, + reason 附"建议手动添加"的代码片段;warning 不计入"已修改"计数。 + (warnings[] 顶层数组只放结构级提示,如多处 \documentclass。) +3. target_journal 必填;"default"= 通用规则(min_font_pt=11, min_margin_mm=20, + min_line_spacing=1.5, refs_style=apa),前端下拉首项即通用。 +4. P1 仅 .tex;结构畸形宁拒不猜(PARSER_FAILED)。 + +铁律: +① 只在违反规则时改(合规零触碰 → 重跑幂等,changes=[]) +② 只收紧不放松:字号/行距/边距只调大、绝不调小 +③ 每条修改必须能回答"为什么":reason 带原值/目标值/规则 + +规则解析链(resolve_rules): + "default" → 内置通用规则 + journals.json id/name 命中 → data/format_cache/{id}.json ok → fetched + → 否则 format_rules 非 placeholder → official + → 否则通用规则 + 占位说明 + 形如 "en:xxx"/"zh:xxx"(journal_directory)→ 只读查目录拿 name → 回链上一步 + 其他字符串(期刊名) → 回链 journals.json → 未中 → 通用 + 未匹配说明 +""" +from __future__ import annotations + +import json +import re +from pathlib import Path +from typing import Any + +# review_service/app/services/ → parents[2] = review_service/ +_ROOT = Path(__file__).resolve().parents[2] +_SEED_PATH = _ROOT / "data" / "journals" / "journals.json" +_CACHE_DIR = _ROOT / "data" / "format_cache" + +_EPS = 1e-9 + +# 通用规则(拍板 3:与 journals.json format_rules_default 的 9/15/1.15 不同, +# 这是重排版自己的"通用规则"口径,勿混用) +RULES_DEFAULT: dict[str, Any] = { + "rules_source": "default", + "max_pages": 10, + "min_font_pt": 11, + "min_margin_mm": 20.0, + "min_line_spacing": 1.5, + "min_figures": 1, + "max_fonts": 6, + "refs_style": "apa", + "anonymous": None, +} + +# 参考文献样式 → 经典 .bst(均为发行版基础件)。 +# 修正(2026-10-10):author_year 旧映射 plain 是错的——plain.bst 是编号制 [1]; +# author-year 制应映射 apalike.bst(Author, 2020)。apa 同理。 +REFS_BST_MAP: dict[str, str] = { + "apa": "apalike", + "author_year": "apalike", + "numbered": "unsrt", + "vancouver": "unsrt", + "gb7714": "gb7714", +} +# biblatex 工作流的 style= 建议名(与 .bst 是两套体系) +BIBLATEX_STYLE_MAP: dict[str, str] = { + "apa": "apa", + "author_year": "authoryear", + "numbered": "numeric", + "vancouver": "numeric", + "gb7714": "gb7714", +} + +_DOCCLASS_RE = re.compile(r"(\\documentclass)\s*(\[[^\]]*\])?\s*\{([^}]*)\}") +_PKG_RE = re.compile(r"\\(?:usepackage|RequirePackage)\s*(\[[^\]]*\])?\s*\{([^}]*)\}") +_SPACING_RE = re.compile(r"\\(?:linespread|setstretch)\s*\{\s*(\d+(?:\.\d+)?)\s*\}") +_BIBSTYLE_RE = re.compile(r"\\bibliographystyle\s*\{\s*([^}]+?)\s*\}") +_PT_RE = re.compile(r"(\d+(?:\.\d+)?)\s*pt\b") +_BEGIN_DOC_RE = re.compile(r"\\begin\s*\{\s*document\s*\}") +_BIBLATEX_RE = re.compile(r"\\(?:printbibliography|addbibresource)") + +_MM_FACTORS = {"mm": 1.0, "cm": 10.0, "in": 25.4, "inch": 25.4, "pt": 25.4 / 72.0} +_SIDE_KEYS = ("left", "right", "top", "bottom") +_MARGIN_ATTRS = ("margin", "hmargin", "vmargin", "left", "right", "top", "bottom", + "inner", "outer") + + +class ReformatError(Exception): + """结构畸形无法安全处理(code: PARSER_FAILED)。""" + + def __init__(self, code: str, message: str) -> None: + super().__init__(message) + self.code = code + + +# ================================================================ 规则解析链 + +def _seed_entries() -> list[dict[str, Any]]: + try: + data = json.loads(_SEED_PATH.read_text("utf-8")) + entries = data.get("journals") + return [e for e in entries if isinstance(e, dict)] if isinstance(entries, list) else [] + except (OSError, ValueError): + return [] + + +def _find_seed(text: str) -> dict[str, Any] | None: + low = text.strip().casefold() + if not low: + return None + for e in _seed_entries(): + if str(e.get("id", "")).casefold() == low or str(e.get("name", "")).casefold() == low: + return e + return None + + +def _cache_rules(journal_id: str) -> dict[str, Any] | None: + """data/format_cache/{id}.json(抓取+LLM 抽取产物);ok=false/缺失 → None。""" + try: + payload = json.loads((_CACHE_DIR / f"{journal_id}.json").read_text("utf-8")) + except (OSError, ValueError): + return None + if not isinstance(payload, dict) or not payload.get("ok"): + return None + rules = payload.get("format_rules") + return rules if isinstance(rules, dict) and rules.get("rules_source") else None + + +def _merged(rules: dict[str, Any]) -> dict[str, Any]: + """专属规则叠加在通用规则上(缺失键/显式 null 保留——fetched 的 null 是诚实未知)。""" + return {**RULES_DEFAULT, **rules} + + +async def _directory_name(journal_id: str) -> str | None: + """journal_directory id → name(只读;表未连/不存在 → None,绝不抛错)。""" + try: + from ..db import db # 惰性导入:resolver 可在无 lifespan 的测试中工作 + row = await db.fetchone( + "SELECT name FROM journal_directory WHERE id = ?", (journal_id,) + ) + return str(row["name"]) if row and row.get("name") else None + except Exception: # noqa: BLE001 —— 查不到/未连接都按未匹配处理 + return None + + +async def resolve_rules(target: str) -> dict[str, Any]: + """→ {journal_id, journal_name, rules, rules_source, rules_note}(永不失败)。""" + target = (target or "").strip() + + if target == "default": + return { + "journal_id": "default", + "journal_name": "通用规则", + "rules": dict(RULES_DEFAULT), + "rules_source": "default", + "rules_note": "通用规则(APA + 通用论文规范)", + } + + display_name = target + entry = _find_seed(target) + if entry is None and ":" in target: + # journal_directory id(en:0028-0836 / zh:slug)→ 目录查 name → 再回链种子 + name = await _directory_name(target) + if name: + display_name = name + entry = _find_seed(name) + elif entry is None: + display_name = target # 直接当期刊名回链 + + if entry is not None: + jid = str(entry.get("id") or "") + jname = str(entry.get("name") or display_name) + cached = _cache_rules(jid) + if cached: + return { + "journal_id": jid, "journal_name": jname, "rules": _merged(cached), + "rules_source": "fetched", + "rules_note": "该刊规则来自官网抓取 + LLM 抽取(data/format_cache,待人工核验)", + } + fr = entry.get("format_rules") if isinstance(entry.get("format_rules"), dict) else {} + if fr and fr.get("rules_source") not in (None, "placeholder", "default"): + return { + "journal_id": jid, "journal_name": jname, "rules": _merged(fr), + "rules_source": str(fr.get("rules_source")), + "rules_note": "journals.json 期刊专属规则", + } + return { + "journal_id": jid, "journal_name": jname, "rules": dict(RULES_DEFAULT), + "rules_source": "default", + "rules_note": f"「{jname}」在 journals.json 中仅有占位规则(placeholder),已用通用规则", + } + + return { + "journal_id": None, + "journal_name": display_name or target, + "rules": dict(RULES_DEFAULT), + "rules_source": "default", + "rules_note": f"未匹配到「{display_name or target}」的专属格式规则,已用通用规则", + } + + +# ================================================================ 变换器工具 + +def _change(line_no: int, original: str, modified: str, reason: str, + rule_key: str, action: str) -> dict[str, Any]: + return { + "line": line_no, + "original": original.rstrip("\n"), + "modified": modified.rstrip("\n"), + "reason": reason, + "rule_key": rule_key, + "action": action, + } + + +def _warning_change(line_no: int, original: str, reason: str, rule_key: str) -> dict[str, Any]: + return _change(line_no, original, "", reason, rule_key, "warning") + + +def _parse_mm(raw: str) -> float | None: + """geometry 长度值 → mm;裸数字按 TeX 惯例 pt(同 format_check 先例);未知 → None。""" + m = re.fullmatch(r"\s*(\d+(?:\.\d+)?)\s*([A-Za-z]*)\s*", raw or "") + if not m: + return None + unit = (m.group(2) or "pt").lower() + factor = _MM_FACTORS.get(unit) + if factor is None: + return None + return float(m.group(1)) * factor + + +def _fmt(v: float) -> str: + return f"{v:g}" + + +# ================================================================ ① 字号 font_pt + +def _transform_font(lines: list[str], orig: list[str], rules: dict[str, Any], + doc_idx: int) -> list[dict[str, Any]]: + min_pt = rules.get("min_font_pt") + if min_pt is None: + return [] + min_pt = float(min_pt) + line = lines[doc_idx] + m = _DOCCLASS_RE.search(line) + if not m: # 守卫已保证,理论不可达 + return [] + opts = m.group(2) # "[...]" 或 None + cls = m.group(3).strip() + opts_inner = opts[1:-1] if opts else "" + pt_m = _PT_RE.search(opts_inner) + + if pt_m is None: + # 拍板 2:选项缺失不自动加 → warning + 建议片段 + if opts_inner: + suggestion = f"\\documentclass[{opts_inner}, {_fmt(min_pt)}pt]{{{cls}}}" + else: + suggestion = f"\\documentclass[{_fmt(min_pt)}pt]{{{cls}}}" + return [_warning_change( + doc_idx + 1, orig[doc_idx], + f"未检测到字号选项,无法核验正文字号(目标下限 {_fmt(min_pt)}pt)," + f"建议手动声明:{suggestion}", + "font_pt", + )] + + cur = float(pt_m.group(1)) + if cur >= min_pt - _EPS: + return [] + target = next((s for s in (10, 11, 12) if s >= min_pt - _EPS), min_pt) + new_inner = opts_inner[:pt_m.start(1)] + _fmt(target) + opts_inner[pt_m.end(1):] + new_line = line[:m.start(2) + 1] + new_inner + line[m.start(2) + 1 + len(opts_inner):] + lines[doc_idx] = new_line + return [_change( + doc_idx + 1, orig[doc_idx], new_line, + f"正文字号 {_fmt(cur)}pt 低于目标下限 {_fmt(min_pt)}pt,改为 {_fmt(target)}pt", + "font_pt", "modified", + )] + + +# ================================================================ ② 页边距 margin + +def _find_geometry(lines: list[str]) -> tuple[int, re.Match] | None: + for i, line in enumerate(lines): + for m in _PKG_RE.finditer(line): + pkgs = [p.strip().lower() for p in m.group(2).split(",")] + if "geometry" in pkgs: + return i, m + return None + + +def _patch_attr(line: str, key: str, new_val: str) -> str: + """geometry 选项里 key=old → key=new(首个匹配)。 + + 值止于 `,` 或 `]`——绝不能吞掉 `]{geometry}` 尾巴(否则下一轮就找不到 + geometry 宏包,破坏幂等)。key 带 \\b 防 hmargin/margin 互撞。 + """ + return re.sub(rf"(\b{key}\s*=\s*)([^,\]]+)", lambda m: m.group(1) + new_val, + line, count=1) + + +def _transform_margin(lines: list[str], orig: list[str], rules: dict[str, Any], + doc_idx: int) -> list[dict[str, Any]]: + min_mm = rules.get("min_margin_mm") + if min_mm is None: + return [] + min_mm = float(min_mm) + out: list[dict[str, Any]] = [] + found = _find_geometry(lines) + + if found is None: + return [_warning_change( + doc_idx + 1, orig[doc_idx], + f"未检测到 geometry 宏包,无法核验页边距(目标下限 {_fmt(min_mm)}mm)," + f"建议手动添加:\\usepackage[margin={_fmt(min_mm)}mm]{{geometry}}" + f"(置于 \\documentclass 之后)", + "margin", + )] + + gi, gm = found + opts = gm.group(1) + if opts is None: + # \usepackage{geometry} 裸用 → 建议加选项(拍板 2 不自动改) + return [_warning_change( + gi + 1, orig[gi], + f"geometry 未设置边距选项,无法核验页边距(目标下限 {_fmt(min_mm)}mm)," + f"建议手动改为:\\usepackage[margin={_fmt(min_mm)}mm]{{geometry}}", + "margin", + )] + opts_inner = opts[1:-1] + attrs: dict[str, str] = {} + for part in opts_inner.split(","): + if "=" in part: + k, _, v = part.partition("=") + attrs[k.strip().lower()] = v.strip() + + present = [k for k in _MARGIN_ATTRS if k in attrs] + if not present: + return [_warning_change( + gi + 1, orig[gi], + f"geometry 未设置边距相关选项(目标下限 {_fmt(min_mm)}mm)," + f"建议在现有选项中添加:margin={_fmt(min_mm)}mm", + "margin", + )] + + # 逐边解析提供者(side > h/vmargin > margin;inner/outer 单独按自身长度评) + def provider_for(side: str) -> str | None: + if side in attrs: + return side + if side in ("left", "right") and "hmargin" in attrs: + return "hmargin" + if side in ("top", "bottom") and "vmargin" in attrs: + return "vmargin" + if "margin" in attrs: + return "margin" + if side in ("left", "right") and "inner" in attrs: + return "inner" # 见下:inner/outer 单独评估,此处不按边处理 + if side in ("left", "right") and "outer" in attrs: + return "outer" + return None + + patch_keys: dict[str, str] = {} # attr → 新值(同键只抬一次) + reasons: list[str] = [] + unresolved: list[str] = [] + + for side in _SIDE_KEYS: + pkey = provider_for(side) + if pkey in ("inner", "outer"): + continue # 由下方 inner/outer 评估负责 + if pkey is None: + unresolved.append(side) + continue + mm = _parse_mm(attrs.get(pkey, "")) + if mm is None: + unresolved.append(side) + continue + if mm < min_mm - _EPS and pkey not in patch_keys: + patch_keys[pkey] = f"{_fmt(min_mm)}mm" + reasons.append(f"页边距 {side}({_fmt(mm)}mm) 低于下限 {_fmt(min_mm)}mm → {_fmt(min_mm)}mm") + + for key in ("inner", "outer"): + if key in attrs: + mm = _parse_mm(attrs[key]) + if mm is None: + unresolved.append(key) + elif mm < min_mm - _EPS and key not in patch_keys: + patch_keys[key] = f"{_fmt(min_mm)}mm" + reasons.append(f"页边距 {key}({_fmt(mm)}mm) 低于下限 {_fmt(min_mm)}mm → {_fmt(min_mm)}mm") + + out: list[dict[str, Any]] = [] + if patch_keys: + new_line = lines[gi] + for key, val in patch_keys.items(): + new_line = _patch_attr(new_line, key, val) + lines[gi] = new_line + out.append(_change( + gi + 1, orig[gi], new_line, ";".join(reasons), "margin", "modified", + )) + + if unresolved: + uniq = "、".join(dict.fromkeys(unresolved)) + out.append(_warning_change( + gi + 1, orig[gi], + f"geometry 未设置/无法解析 {uniq} 边(沿用类默认,无法核验)," + f"建议显式声明:{uniq}={_fmt(min_mm)}mm", + "margin", + )) + return out + + +# ================================================================ ③ 行距 line_spacing + +def _transform_spacing(lines: list[str], orig: list[str], rules: dict[str, Any], + doc_idx: int) -> list[dict[str, Any]]: + min_ls = rules.get("min_line_spacing") + if min_ls is None: + return [] + min_ls = float(min_ls) + + # 只看导言区(\begin{document} 之前);正文中的 \setstretch 是局部覆盖,不碰 + end = len(lines) + for i, line in enumerate(lines): + if _BEGIN_DOC_RE.search(line): + end = i + break + records: list[tuple[int, re.Match]] = [] + for i in range(end): + for m in _SPACING_RE.finditer(lines[i]): + records.append((i, m)) + + if not records: + return [_warning_change( + doc_idx + 1, orig[doc_idx], + f"未在导言区检测到 \\linespread 或 \\setstretch,无法核验行距" + f"(目标下限 {_fmt(min_ls)}),建议手动添加到导言区:" + f"\\linespread{{{_fmt(min_ls)}}}", + "line_spacing", + )] + + i, m = records[-1] # 最后一次出现者生效(LaTeX 后设覆盖前设) + cur = float(m.group(1)) + if cur >= min_ls - _EPS: + return [] + new_line = lines[i][:m.start(1)] + _fmt(min_ls) + lines[i][m.end(1):] + lines[i] = new_line + return [_change( + i + 1, orig[i], new_line, + f"行距 {_fmt(cur)} 低于目标下限 {_fmt(min_ls)},改为 {_fmt(min_ls)}", + "line_spacing", "modified", + )] + + +# ================================================================ ④ 参考文献 bib_style + +def _transform_bib(lines: list[str], orig: list[str], rules: dict[str, Any], + doc_idx: int) -> list[dict[str, Any]]: + style = str(rules.get("refs_style") or "").strip().lower() + if not style: + # 规则未提供已确认的 refs_style(如 Frontiers 两种制式并存待核实): + # 绝不猜测改写用户样式——保持原样 + warning 提示(拍板 2026-10-10) + return [_warning_change( + doc_idx + 1, orig[doc_idx], + "该刊引用风格未确认,未改动 \\bibliographystyle;" + "建议人工核实期刊投稿指南后再调整", + "bib_style", + )] + + m = next((mm for line in lines if (mm := _BIBSTYLE_RE.search(line))), None) + if m is not None: + i = next(idx for idx, line in enumerate(lines) if _BIBSTYLE_RE.search(line)) + cur = m.group(1).strip() + if style not in REFS_BST_MAP: + return [_warning_change( + i + 1, orig[i], + f"目标参考文献样式 {style} 无对应标准 .bst,未替换" + f"(当前 \\bibliographystyle{{{cur}}}),请按目标期刊模板手动选择样式", + "bib_style", + )] + target = REFS_BST_MAP[style] + if cur.casefold() == target.casefold(): + return [] + new_line = lines[i][:m.start(1)] + target + lines[i][m.end(1):] + lines[i] = new_line + hint = "(需 gbt7714 宏包)" if target == "gb7714" else "" + return [_change( + i + 1, orig[i], new_line, + f"参考文献样式要求 {style}:\\bibliographystyle{{{cur}}} → {{{target}}}{hint}", + "bib_style", "modified", + )] + + has_biblatex = any(_BIBLATEX_RE.search(line) for line in lines) + if has_biblatex: + suggest = BIBLATEX_STYLE_MAP.get(style, style) + return [_warning_change( + doc_idx + 1, orig[doc_idx], + f"检测到 biblatex 工作流(未找到 \\bibliographystyle)," + f"请在 \\printbibliography 选项中手动配置:style={suggest}(对应 {style})", + "bib_style", + )] + + if style in REFS_BST_MAP: + target = REFS_BST_MAP[style] + return [_warning_change( + doc_idx + 1, orig[doc_idx], + f"未检测到 \\bibliographystyle,建议手动添加:\\bibliographystyle{{{target}}}" + f"(对应 {style})", + "bib_style", + )] + return [_warning_change( + doc_idx + 1, orig[doc_idx], + f"未检测到 \\bibliographystyle,目标样式 {style} 无标准 .bst 映射," + f"请按期刊模板手动配置", + "bib_style", + )] + + +# ================================================================ 入口 + +def reformat_tex(source: str, rules: dict[str, Any]) -> dict[str, Any]: + """源码 + 规则 → {modified_tex, changes[], warnings[]}。 + + 结构守卫:0 处 \\documentclass → ReformatError(PARSER_FAILED); + >1 处 → 只处理第一处 + warnings 补 MULTI_DOCUMENTCLASS。 + """ + lines = source.splitlines(keepends=True) + doc_idxs = [i for i, line in enumerate(lines) if _DOCCLASS_RE.search(line)] + if not doc_idxs: + raise ReformatError( + "PARSER_FAILED", + "未找到 \\documentclass{...}:无法确定主文档" + "(P1 不支持由 \\input 拆分的多文件工程,请上传完整单文件源码)", + ) + warnings: list[dict[str, str]] = [] + if len(doc_idxs) > 1: + warnings.append({ + "code": "MULTI_DOCUMENTCLASS", + "message": f"检测到 {len(doc_idxs)} 处 \\documentclass," + f"仅处理第一处(第 {doc_idxs[0] + 1} 行)", + }) + doc_idx = doc_idxs[0] + orig = list(lines) # 纯净快照:所有 change.original 取自这里 + + changes: list[dict[str, Any]] = [] + changes += _transform_font(lines, orig, rules, doc_idx) + changes += _transform_margin(lines, orig, rules, doc_idx) + changes += _transform_spacing(lines, orig, rules, doc_idx) + changes += _transform_bib(lines, orig, rules, doc_idx) + changes.sort(key=lambda c: c["line"]) + + return {"modified_tex": "".join(lines), "changes": changes, "warnings": warnings} diff --git a/review_service/app/services/self_review.py b/review_service/app/services/self_review.py new file mode 100644 index 0000000..0def3bd --- /dev/null +++ b/review_service/app/services/self_review.py @@ -0,0 +1,155 @@ +"""services/self_review.py —— 植物基因组学专属自审稿(System Prompt + 报告模型)。 + +六大领域维度检查清单硬编码在 SYSTEM_PROMPT(发给 DeepSeek): +1. 基因组组装质量(N50/L50/BUSCO 完整格式/Hi-C 挂载率,缺项即 Major) +2. 基因注释可靠性(MAKER/AUGUSTUS 流程、RNA-seq 证据、基因数与已知范围一致性) +3. 比较基因组学与进化(Bootstrap/后验概率、OrthoFinder 等直系同源策略) +4. 数据可用性合规(SRA/BioProject + 组装/GFF3 Accession,缺失即 Major) +5. 统计与实验设计(GWAS/QTL 样本量·多重校正·群体结构;转录组生物学重复) +6. 伦理与合规·植物特异性(凭证标本 voucher、ABS 惠益分享声明) + +Major/Minor 每条必须给 Evidence(论文章节位置或具体指标数值),由 coerce +宽容归一化(缺失补空串,不丢条目)。 +""" +from __future__ import annotations + +from pydantic import BaseModel, Field + +RECOMMENDATIONS = ("accept", "minor_revision", "major_revision", "reject") + +SYSTEM_PROMPT = """你是一位植物基因组学领域资深审稿人,长期为 Plant Cell、Nature Plants、 +Genome Biology、Molecular Plant、Plant Journal 等期刊审稿。请对用户提供的论文正文做 +投稿前自审(pre-submission self review),严格按以下六个植物基因组学专属维度逐项检查, +输出结构化审稿意见。所有条目使用中文撰写(专业术语、指标名、工具名保留英文)。 + +【维度一:基因组组装质量】必查指标: +- contig N50 / scaffold N50 / L50(报了哪个要写明哪个) +- BUSCO 完整度:必须按完整格式报告——例如 + "Complete 95.3% [S:93.1%, D:2.2%], Missing 4.7%, n=1614 (embryophyta_odb10)" + (含 Complete/Single-copy/Duplicated/Missing 四项与数据集版本、n 值) +- Hi-C 挂载率(anchoring rate,chromosome-level 比例)及挂载到染色体的 scaffold 比例 +判定规则:若论文只报 N50 而未报 BUSCO 完整度或 Hi-C 挂载率(组装类论文),直接列为 +Major Weakness。同时检查组装是否为 pseudo-chromosome 级别、污染评估(如 k-mer/coverage +检查)与 gap 比例。 + +【维度二:基因注释可靠性】检查: +- 是否使用标准注释流程(MAKER、AUGUSTUS、BRAKER、GeMoMa、EVidenceModeler 等),参数与版本是否交代 +- 是否有转录组证据支持:RNA-seq(组织/时期/物种内或近缘种)比对支撑比例,或蛋白同源证据 +- 基因数量是否与该物种已知基因数范围一致(如水稻 ~37-40k、拟南芥 ~27k、玉米 ~39-45k、 + 小麦 ~107k、大豆 ~46k;近缘种偏差过大须说明);有无转座元件基因误注释的排查 +- 注释质量评估:BRAKER/AED 分值、BUSCO 在蛋白集上的复核 + +【维度三:比较基因组学与进化】检查: +- 系统发育树:每个节点必须标注 Bootstrap 支持率(建议 ≥1000 次重复)或贝叶斯后验概率; + 未标注或仅"高/低支持"的描述 → Major 或 Minor(视严重程度) +- 直系同源基因鉴定策略是否说明清楚:OrthoFinder/OrthoMCL/RBX 等工具、版本、参数、 + 聚类阈值(inflation/coverage)、single-copy 标记基因的筛选方式 +- 分子进化分析是否规范:dN/dS 检验方法与多重校正、共线性(synteny)分析参数、 + 分化时间估算是否校准(化石/二次校准点) + +【维度四:数据可用性合规——极其重要】必查: +- 原始测序数据是否上传 NCBI SRA / BioProject(或 ENA/DDBJ),是否给出 Accession 号 + (PRJNA/PRJEB/ SRP 开头) +- 基因组组装是否有 GenBank/ENA accession(GCA_/GCF_),GFF3 注释文件、蛋白/CDS 文件 + 是否有可公开获取的位置(仓库 accession 或补充数据链接) +- 转录组数据是否同样有 SRA accession +判定规则:组装/注释类论文若缺失上述任何一环,直接列为 Major Weakness。 + +【维度五:统计与实验设计】检查: +- GWAS/QTL 定位:样本量/群体大小是否充分;多重检验校正是否明确(Bonferroni/FDR/ + permutation 阈值/PCA 显著性水平);群体结构控制(PCA、亲缘关系矩阵 K、分层分析) + 是否交代;表型测量描述是否充分 +- 转录组分析:生物学重复数量(≥3 为底线)、差异分析工具(DESeq2/edgeR 等)与 + 校正方法、批次效应处理、|log2FC| 与 padj 阈值 +- 其他统计:t 检验/ANOVA 是否满足前提、重复类型(生物学 vs 技术重复)写明与否 + +【维度六:伦理与合规(植物特异性)】检查: +- 野生植物材料:是否提供凭证标本(voucher specimen)信息——标本馆编号、存放机构、 + 采集地点(GPS)与采集许可;无凭证标本的野生资源取样 → Major 或 Minor(视用途) +- 遗传资源获取与惠益分享(ABS)合规性:是否声明符合《名古屋议定书》/本国遗传资源 + 获取条例(如中国《生物安全法》/《种子法》相关条款)、是否说明材料来源与授权 +- 农业转基因/基因编辑材料的合规声明(若涉及) + +输出要求(必须输出单个 JSON 对象,不要输出其他任何内容): +{ + "summary": "总体评价(3-5 句,须点明论文类型与所适用的维度)", + "major_weaknesses": [{"title": "...", "detail": "...", "evidence": "...", "suggestion": "..."}], + "minor_weaknesses": [{"title": "...", "detail": "...", "evidence": "...", "suggestion": "..."}], + "presentation_format": [{"title": "...", "detail": "...", "evidence": "...", "suggestion": "..."}], + "questions_for_authors": ["..."], + "recommendation": "major_revision" +} + +硬性规则: +1. major_weaknesses 3-8 条、minor_weaknesses 3-8 条;上述维度中命中的硬性判定规则 + (组装缺 BUSCO/挂载率、缺数据 Accession)必须出现。 +2. **每条 major_weaknesses 的 evidence 字段必填**:必须引用论文的具体章节位置 + (如 "Methods 2.1"、"Table 2"、"Results 第 3 段"、"Data Availability 一句话未见") + 或具体指标数值(如 "仅报 scaffold N50=42.6 Mb,未提供 BUSCO 与 Hi-C 挂载率")。 + evidence 严禁编造:引用不到具体位置时,写明"正文未见相关报告"。 +3. minor_weaknesses/presentation_format 的 evidence 尽量给出,无法定位时可留空字符串。 +4. 论文不涉及的维度(如纯 RNA-seq 论文不谈组装)在 summary 中说明并跳过,不硬凑条目。 +5. recommendation 只能是 accept / minor_revision / major_revision / reject 之一, + 缺失关键合规项(维度四)时通常不高于 major_revision。 +6. presentation_format 覆盖:图表规范(图注含单位/误差棒说明)、参考文献格式、 + 字数与结构、英文语法(若投英文刊)。 +""" + + +class WeaknessItem(BaseModel): + title: str + detail: str = "" + evidence: str = "" + suggestion: str = "" + + +class SelfReviewReport(BaseModel): + summary: str = "" + major_weaknesses: list[WeaknessItem] = Field(default_factory=list) + minor_weaknesses: list[WeaknessItem] = Field(default_factory=list) + presentation_format: list[WeaknessItem] = Field(default_factory=list) + questions_for_authors: list[str] = Field(default_factory=list) + recommendation: str = "major_revision" + + +def build_user_prompt(text: str, target_journal: str) -> str: + header = f"目标期刊:{target_journal}\n\n" if target_journal else "" + return f"{header}论文正文:\n\n{text}" + + +def _coerce_items(raw: object) -> list[WeaknessItem]: + items: list[WeaknessItem] = [] + if not isinstance(raw, list): + return items + for entry in raw: + if isinstance(entry, str) and entry.strip(): + items.append(WeaknessItem(title=entry.strip())) + elif isinstance(entry, dict): + title = str(entry.get("title") or "").strip() + detail = str(entry.get("detail") or "").strip() + if not title and not detail: + continue + items.append(WeaknessItem( + title=title or "(未命名)", + detail=detail, + evidence=str(entry.get("evidence") or "").strip(), + suggestion=str(entry.get("suggestion") or "").strip(), + )) + return items + + +def coerce_report(payload: dict) -> SelfReviewReport: + questions = payload.get("questions_for_authors") or [] + if not isinstance(questions, list): + questions = [] + recommendation = str(payload.get("recommendation") or "").strip().lower() + if recommendation not in RECOMMENDATIONS: + recommendation = "major_revision" + return SelfReviewReport( + summary=str(payload.get("summary") or "").strip(), + major_weaknesses=_coerce_items(payload.get("major_weaknesses")), + minor_weaknesses=_coerce_items(payload.get("minor_weaknesses")), + presentation_format=_coerce_items(payload.get("presentation_format")), + questions_for_authors=[str(q).strip() for q in questions if str(q).strip()], + recommendation=recommendation, + ) diff --git a/review_service/data/journals/conferences.json b/review_service/data/journals/conferences.json new file mode 100644 index 0000000..f29e0f8 --- /dev/null +++ b/review_service/data/journals/conferences.json @@ -0,0 +1,493 @@ +{ + "version": 2, + "updated": "2026-10-10", + "notes": "会议种子数据 v2。deadline_source=placeholder 表示日期为首版占位数据(按各会议公开周期窗口/历年规律填写,未经官方渠道逐条核验),接入官方数据源前须人工核验;严禁以 AI 推测日期替代核验。deadline_confidence 标注日期置信度:high=官方已公布或历年极稳定;medium=按历年规律区间推算;low=新一届尚未公告或历届波动大,待核验。ccf_rank 按 CCF 推荐目录(第七版,2026-03 发布)标注,非目录内会议为 null(含全部生物信息/植物类会议)。timezone_note 默认 AoE (UTC-12)。首版不做自动同步。", + "conferences": [ + { + "id": "naacl-2027", + "name": "NAACL 2027", + "full_name": "North American Chapter of the Association for Computational Linguistics", + "domain_tags": ["AI/ML", "自然语言处理"], + "application_tags": ["交叉学科"], + "ccf_rank": "B", + "deadline_abstract": null, + "deadline_full_paper": "2026-10-12T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-06-01 ~ 2027-06-05", + "location": "San Francisco, California, USA", + "official_url": "https://www.naacl.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "high" + }, + { + "id": "coling-2027", + "name": "COLING 2027", + "full_name": "International Conference on Computational Linguistics", + "domain_tags": ["AI/ML", "自然语言处理"], + "application_tags": ["交叉学科"], + "ccf_rank": "B", + "deadline_abstract": null, + "deadline_full_paper": "2026-10-12T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-05-09 ~ 2027-05-14", + "location": "Macau SAR, China", + "official_url": null, + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "medium" + }, + { + "id": "www-2027", + "name": "WWW 2027", + "full_name": "The Web Conference (ACM WWW)", + "domain_tags": ["AI/ML", "数据挖掘"], + "application_tags": ["交叉学科"], + "ccf_rank": "A", + "deadline_abstract": "2026-10-18T23:59:59+00:00", + "deadline_full_paper": "2026-10-25T23:59:59+00:00", + "notification_date": "2027-01-04", + "conference_date": "2027-05-10 ~ 2027-05-14", + "location": "Dublin, Ireland", + "official_url": "https://www2027.thewebconf.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "high" + }, + { + "id": "recomb-2027", + "name": "RECOMB 2027", + "full_name": "International Conference on Research in Computational Molecular Biology", + "domain_tags": ["生物信息学"], + "application_tags": ["交叉学科"], + "ccf_rank": null, + "deadline_abstract": "2026-11-06T23:59:59+00:00", + "deadline_full_paper": "2026-11-13T23:59:59+00:00", + "notification_date": "2027-02-01", + "conference_date": "2027-04-25 ~ 2027-04-28", + "location": "TBD(待官方公布)", + "official_url": "https://recomb.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "medium" + }, + { + "id": "cvpr-2027", + "name": "CVPR 2027", + "full_name": "IEEE/CVF Conference on Computer Vision and Pattern Recognition", + "domain_tags": ["AI/ML", "计算机视觉"], + "application_tags": ["交叉学科"], + "ccf_rank": "A", + "deadline_abstract": "2026-11-10T23:59:59+00:00", + "deadline_full_paper": "2026-11-16T23:59:59+00:00", + "notification_date": "2027-02-25", + "conference_date": "2027-06-20 ~ 2027-06-25", + "location": "Seattle, USA", + "official_url": "https://cvpr.thecvf.com/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "high" + }, + { + "id": "wsdm-2027", + "name": "WSDM 2027", + "full_name": "International Conference on Web Search and Data Mining", + "domain_tags": ["AI/ML", "数据挖掘"], + "application_tags": ["交叉学科"], + "ccf_rank": "B", + "deadline_abstract": null, + "deadline_full_paper": "2026-11-17T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-02-15 ~ 2027-02-19", + "location": "Hong Kong SAR, China", + "official_url": "https://www.wsdm-conference.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "high" + }, + { + "id": "pag-2027", + "name": "PAG 2027", + "full_name": "Plant & Animal Genome Conference", + "domain_tags": ["植物/农学", "基因组学"], + "application_tags": ["种业", "分子育种"], + "ccf_rank": null, + "deadline_abstract": "2026-11-30T23:59:59+00:00", + "deadline_full_paper": "2026-12-15T23:59:59+00:00", + "notification_date": "2027-01-05", + "conference_date": "2027-01-08 ~ 2027-01-12", + "location": "San Diego, USA", + "official_url": "https://www.intlpag.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "medium" + }, + { + "id": "acl-2027", + "name": "ACL 2027", + "full_name": "Annual Meeting of the Association for Computational Linguistics", + "domain_tags": ["AI/ML", "自然语言处理"], + "application_tags": ["交叉学科"], + "ccf_rank": "A", + "deadline_abstract": null, + "deadline_full_paper": "2027-01-04T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-08-20 ~ 2027-08-22", + "location": "Kyoto, Japan", + "official_url": "https://2027.aclweb.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "high" + }, + { + "id": "plantbio-2027", + "name": "Plant Biology 2027", + "full_name": "ASPB Annual Meeting — Plant Biology", + "domain_tags": ["植物/农学", "分子生物学"], + "application_tags": ["分子育种"], + "ccf_rank": null, + "deadline_abstract": "2027-01-08T23:59:59+00:00", + "deadline_full_paper": "2027-01-08T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-07(待官方公布)", + "location": "Albuquerque, New Mexico, USA", + "official_url": "https://plantbiology.aspb.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "high" + }, + { + "id": "ijcai-2027", + "name": "IJCAI 2027", + "full_name": "International Joint Conference on Artificial Intelligence", + "domain_tags": ["AI/ML"], + "application_tags": ["交叉学科"], + "ccf_rank": "B", + "deadline_abstract": "2027-01-11T23:59:59+00:00", + "deadline_full_paper": "2027-01-18T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-08-07 ~ 2027-08-17", + "location": "Kyoto, Japan / Hengqin, China", + "official_url": "https://www.ijcai.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "medium" + }, + { + "id": "sigir-2027", + "name": "SIGIR 2027", + "full_name": "ACM SIGIR Conference on Research and Development in Information Retrieval", + "domain_tags": ["AI/ML", "信息检索"], + "application_tags": ["交叉学科"], + "ccf_rank": "A", + "deadline_abstract": "2027-01-14T23:59:59+00:00", + "deadline_full_paper": "2027-01-21T23:59:59+00:00", + "notification_date": "2027-04-05", + "conference_date": "2027-07-20 ~ 2027-07-24", + "location": "San Jose, California, USA", + "official_url": "https://sigir2027.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "high" + }, + { + "id": "icml-2027", + "name": "ICML 2027", + "full_name": "International Conference on Machine Learning", + "domain_tags": ["AI/ML", "深度学习"], + "application_tags": ["交叉学科"], + "ccf_rank": "A", + "deadline_abstract": "2027-01-15T23:59:59+00:00", + "deadline_full_paper": "2027-01-22T23:59:59+00:00", + "notification_date": "2027-05-01", + "conference_date": "2027-07-19 ~ 2027-07-25", + "location": "TBD(待官方公布)", + "official_url": "https://icml.cc/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "medium" + }, + { + "id": "chil-2027", + "name": "CHIL 2027", + "full_name": "ACM Conference on Health, Inference, and Learning", + "domain_tags": ["AI/ML", "健康医疗"], + "application_tags": ["交叉学科"], + "ccf_rank": null, + "deadline_abstract": "2027-01-15T23:59:59+00:00", + "deadline_full_paper": "2027-01-29T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-06(待官方公布)", + "location": "TBD(待官方公布)", + "official_url": "https://dl.acm.org/conference/chil", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "low" + }, + { + "id": "kdd-2027", + "name": "KDD 2027 (Cycle 2)", + "full_name": "ACM SIGKDD Conference on Knowledge Discovery and Data Mining", + "domain_tags": ["AI/ML", "数据挖掘"], + "application_tags": ["交叉学科"], + "ccf_rank": "A", + "deadline_abstract": "2027-01-31T23:59:59+00:00", + "deadline_full_paper": "2027-02-07T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-08-01 ~ 2027-08-05", + "location": "San Jose, California, USA", + "official_url": "https://kdd2027.kdd.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "medium" + }, + { + "id": "ismb-eccb-2027", + "name": "ISMB/ECCB 2027", + "full_name": "Intelligent Systems for Molecular Biology / European Conference on Computational Biology", + "domain_tags": ["生物信息学"], + "application_tags": ["交叉学科"], + "ccf_rank": null, + "deadline_abstract": "2027-02-12T23:59:59+00:00", + "deadline_full_paper": "2027-02-19T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-07-18 ~ 2027-07-22", + "location": "Copenhagen, Denmark", + "official_url": "https://www.iscb.org/ismbeccb2027/home", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "medium" + }, + { + "id": "ipmbc-2027", + "name": "IPMB 2027", + "full_name": "International Congress on Plant Molecular Biology (14th)", + "domain_tags": ["植物/农学", "分子生物学"], + "application_tags": ["分子育种"], + "ccf_rank": null, + "deadline_abstract": "2027-02-15T23:59:59+00:00", + "deadline_full_paper": "2027-02-22T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-07(待官方公布)", + "location": "Wuhan, China", + "official_url": "https://www.ipmb2027.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "low" + }, + { + "id": "uai-2027", + "name": "UAI 2027", + "full_name": "Conference on Uncertainty in Artificial Intelligence", + "domain_tags": ["AI/ML"], + "application_tags": ["交叉学科"], + "ccf_rank": "B", + "deadline_abstract": null, + "deadline_full_paper": "2027-02-24T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-08-16 ~ 2027-08-20", + "location": "TBD(待官方公布)", + "official_url": "https://www.auai.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "medium" + }, + { + "id": "miccai-2027", + "name": "MICCAI 2027", + "full_name": "International Conference on Medical Image Computing and Computer-Assisted Intervention", + "domain_tags": ["AI/ML", "医学影像"], + "application_tags": ["交叉学科"], + "ccf_rank": null, + "deadline_abstract": "2027-02-11T23:59:59+00:00", + "deadline_full_paper": "2027-02-25T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-09-26 ~ 2027-10-01", + "location": "Auckland, New Zealand", + "official_url": "https://miccai.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "medium" + }, + { + "id": "iccv-2027", + "name": "ICCV 2027", + "full_name": "IEEE/CVF International Conference on Computer Vision", + "domain_tags": ["AI/ML", "计算机视觉"], + "application_tags": ["交叉学科"], + "ccf_rank": "A", + "deadline_abstract": "2027-02-26T23:59:59+00:00", + "deadline_full_paper": "2027-03-05T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-10-02 ~ 2027-10-08", + "location": "Hong Kong SAR, China", + "official_url": null, + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "medium" + }, + { + "id": "bosc-2027", + "name": "BOSC 2027", + "full_name": "Bioinformatics Open Source Conference", + "domain_tags": ["生物信息学"], + "application_tags": ["交叉学科"], + "ccf_rank": null, + "deadline_abstract": null, + "deadline_full_paper": "2027-03-26T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-07-18 ~ 2027-07-22", + "location": "Copenhagen, Denmark", + "official_url": "https://openbioinformatics.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "low" + }, + { + "id": "acm-bcb-2027", + "name": "ACM-BCB 2027", + "full_name": "ACM Conference on Bioinformatics, Computational Biology and Health Informatics", + "domain_tags": ["生物信息学", "AI/ML"], + "application_tags": ["交叉学科"], + "ccf_rank": null, + "deadline_abstract": "2027-04-16T23:59:59+00:00", + "deadline_full_paper": "2027-04-23T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-08(待官方公布)", + "location": "TBD(待官方公布)", + "official_url": "https://acm-bcb.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "medium" + }, + { + "id": "ieee-bibm-2027", + "name": "IEEE BIBM 2027", + "full_name": "IEEE International Conference on Bioinformatics and Bioengineering", + "domain_tags": ["生物信息学"], + "application_tags": ["交叉学科"], + "ccf_rank": null, + "deadline_abstract": "2027-05-07T23:59:59+00:00", + "deadline_full_paper": "2027-05-14T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-11(待官方公布)", + "location": "TBD(待官方公布)", + "official_url": null, + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "low" + }, + { + "id": "emnlp-2027", + "name": "EMNLP 2027", + "full_name": "Conference on Empirical Methods in Natural Language Processing", + "domain_tags": ["AI/ML", "自然语言处理"], + "application_tags": ["交叉学科"], + "ccf_rank": "B", + "deadline_abstract": "2027-05-14T23:59:59+00:00", + "deadline_full_paper": "2027-05-21T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-11(待官方公布)", + "location": "TBD(待官方公布)", + "official_url": null, + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "low" + }, + { + "id": "neurips-2027", + "name": "NeurIPS 2027", + "full_name": "Conference on Neural Information Processing Systems", + "domain_tags": ["AI/ML", "深度学习"], + "application_tags": ["交叉学科"], + "ccf_rank": "A", + "deadline_abstract": "2027-05-14T23:59:59+00:00", + "deadline_full_paper": "2027-05-21T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-12(待官方公布)", + "location": "TBD(待官方公布)", + "official_url": "https://neurips.cc/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "medium" + }, + { + "id": "psb-2028", + "name": "PSB 2028", + "full_name": "Pacific Symposium on Biocomputing", + "domain_tags": ["生物信息学"], + "application_tags": ["交叉学科"], + "ccf_rank": null, + "deadline_abstract": null, + "deadline_full_paper": "2027-07-01T23:59:59+00:00", + "notification_date": null, + "conference_date": "2028-01(待官方公布)", + "location": "TBD(待官方公布)", + "official_url": "https://psb.stanford.edu/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "low" + }, + { + "id": "pag-europe-2027", + "name": "PAG Europe 2027", + "full_name": "Plant & Animal Genome Conference Europe", + "domain_tags": ["植物/农学", "基因组学"], + "application_tags": ["种业", "分子育种"], + "ccf_rank": null, + "deadline_abstract": null, + "deadline_full_paper": "2027-07-09T23:59:59+00:00", + "notification_date": null, + "conference_date": "2027-10(待官方公布)", + "location": "TBD(待官方公布)", + "official_url": null, + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "low" + }, + { + "id": "aaai-2028", + "name": "AAAI 2028", + "full_name": "AAAI Conference on Artificial Intelligence", + "domain_tags": ["AI/ML"], + "application_tags": ["交叉学科"], + "ccf_rank": "A", + "deadline_abstract": "2027-07-20T23:59:59+00:00", + "deadline_full_paper": "2027-07-27T23:59:59+00:00", + "notification_date": null, + "conference_date": "2028-02(待官方公布)", + "location": "TBD(待官方公布)", + "official_url": "https://aaai.org/", + "timezone_note": "AoE (UTC-12)", + "deadline_source": "placeholder", + "last_verified": "2026-10-10", + "deadline_confidence": "medium" + } + ] +} diff --git a/review_service/data/journals/import_report.txt b/review_service/data/journals/import_report.txt new file mode 100644 index 0000000..fda2154 --- /dev/null +++ b/review_service/data/journals/import_report.txt @@ -0,0 +1,61 @@ +journals directory 导入对账报告 +生成时间: 2026-10-10T15:37:11 +源文件: /home/xzq/5090/teamWorkspace/wjq/PlantAI-RAG-new-latest/PlantAI-rag-new/review_service/data/journals/source_v4.xlsx(193386 bytes) +阶段: 完成 + +=== 计数 === +读取有效行: 国际 779 / 中文 277 / 合计 1056 +成功: 1056 跳过(名称空): 0 失败: 0 +写入后 count(*): en=779 zh=277 total=1056 +期望: en=779 zh=277 total=1056 → ✓ 相符 + +=== 分区分布(国际)=== +1区 233 / 2区 214 / 3区 181 / 4区 134 / 空白 17 +分区空白(→null 无note): 17 +分区未检得(→null + note): 0 + +=== JIF 缺失 13 条(jif=null + note=核对状态)=== + - eLife [2025 JIF未检得/未给值] + - Heliyon [2025 JIF未检得/未给值] + - Australian Journal of Crop Science [2025 JIF未检得/未给值] + - International Journal of Agriculture and Biology [2025 JIF未检得/未给值] + - Journal of Agriculture and Rural Development in the Tropics and Subtropics [2025 JIF未检得/未给值] + - Fruits [2025 JIF未检得/未给值] + - RANGELAND JOURNAL [2025 JIF未检得/未给值] + - Science of The Total Environment [2025 JIF未检得/未给值] + - Chemosphere [2025 JIF未检得/未给值] + - Environmental Science and Pollution Research [2025 JIF未检得/未给值] + - Bioengineered [2025 JIF未检得/未给值] + - Cell Biomaterials [2025 JIF未检得/未给值] + - National Science Open [2025 JIF未检得/未给值] + +=== 中文复合IF 缺失 0 条 === + +=== 分区未检得 期刊名 === + (无——源表以空白表示未检得,见上方'分区空白') + +=== 重复 id 冲突(应为空)=== + (无) + +=== id 策略 === +ISSN 型: 692 条 slug 型: 364 条 + +=== 来源超链接 === +国际 JIF来源: 779/779 分区来源: 762/779 中文数据来源: 277/277 + +=== 结构迁移(ALTER TABLE,幂等)=== + 本次加列: official_check_status, jcr_release_year + 已存在跳过: official_url + +=== 官网映射(决策:official_source 不入库)=== + 识别列: 官网网址 + official_url 填充: 1053/1056 official_check_status 填充: 1056/1056 + jcr_release_year 填充: 779(仅国际=2026;中文表无此列→null) + 官网缺失 3 条(official_url=null,前端显示「—」不生成链接): + - [zh] 中国食用菌 + - [zh] 水土保持应用技术 + - [zh] 粮食与饲料工业 + +=== 幂等性验证 === + 第二次 upsert 后 count 不变: ✓ 通过 + diff --git a/review_service/data/journals/journals.json b/review_service/data/journals/journals.json new file mode 100644 index 0000000..fa98908 --- /dev/null +++ b/review_service/data/journals/journals.json @@ -0,0 +1,172 @@ +{ + "version": 1, + "updated": "2026-10-10", + "notes": "植物基因组学领域种子期刊。acceptance_rate 无公开权威数据一律为 null(不编造);impact_factor / review_time_weeks 为公开 JCR/期刊官网常识近似值,以 last_updated 标注刷新时间,接入真实数据源前需人工核验。scope_desc 为英文范围描述,供 vstore 向量匹配使用。 format_rules_default 为通用默认规则(rules_source=default);精选 5 本 format_rules 已于 2026-10-10 按各刊官网投稿指南人工核验填入(rules_source=official,附 source_url / last_verified / notes),官网未规定的字段一律 null 不猜测。 新增标签字段(不进 SQLite,接口按 id 从本文件合并):scope_tags / application_tags / cross_domain 按 scope_desc 归类的标签;cas_partition / jcr_quartile 为占位(partition_source=placeholder),核实不确定的一律 null、不猜测,接入真实分区数据前需人工核验。 精选列表已更换为本环境可访问官网的 5 本(Genome Biology / BMC Plant Biology / Molecular Plant / Frontiers in Plant Science / Rice);原 OUP/Wiley/Springer 4 本(The Plant Cell / The Plant Journal / Theoretical and Applied Genetics / The Plant Genome)移出精选,仍保留在 journal_directory 1056 条全量目录中。", + "format_rules_default": { + "rules_source": "default", + "max_pages": 10, + "min_font_pt": 9, + "min_margin_mm": 15, + "min_line_spacing": 1.15, + "min_figures": 1, + "max_fonts": 6, + "refs_style": "apa" + }, + "journals": [ + { + "id": "genome-biology", + "name": "Genome Biology", + "scope_desc": "High-impact open-access journal for genome-scale research across all organisms, including genome assembly and annotation, comparative and evolutionary genomics, computational methods, single-cell and multi-omics studies, and reproducible bioinformatics.", + "impact_factor": 10.1, + "review_time_weeks": 4.0, + "acceptance_rate": null, + "submission_deadline": null, + "official_url": "https://genomebiology.biomedcentral.com", + "last_updated": "2026-10-09", + "scope_tags": ["基因组学", "生物信息学", "多组学", "计算生物学"], + "application_tags": ["基础研究", "算法与方法"], + "cas_partition": "1区", + "jcr_quartile": "Q1", + "partition_source": "placeholder", + "cross_domain": ["进化生物学", "单细胞组学"], + "format_rules": { + "max_pages": null, + "min_font_pt": null, + "min_margin_mm": null, + "min_line_spacing": 2.0, + "max_fonts": null, + "min_figures": null, + "refs_style": "vancouver", + "anonymous": false, + "rules_source": "official", + "source_url": "https://genomebiology.biomedcentral.com/submission-guidelines", + "last_verified": "2026-10-10", + "notes": "官网要求双倍行距('Use double-line spacing')、行页码编号;参考文献 'Journal abbreviations follow Index Medicus/MEDLINE'(顺序编号制→vancouver);BMC 出版社 policy 页明确 single-anonymous(审稿人知道作者身份,作者无需匿名);字号/边距/页数上限该页未规定。BMC editorial policy 辅助来源:https://www.biomedcentral.com/getpublished/editorial-policies" + } + }, + { + "id": "bmc-plant-biology", + "name": "BMC Plant Biology", + "scope_desc": "Open-access journal covering all aspects of plant biology, from molecular and cellular studies to the physiology and ecology of whole plants and communities, including plant-microbe interactions, biotechnology and applied plant science.", + "impact_factor": null, + "review_time_weeks": null, + "acceptance_rate": null, + "submission_deadline": null, + "official_url": "https://bmcplantbiol.biomedcentral.com", + "last_updated": "2026-10-10", + "scope_tags": ["植物生物学", "分子生物学", "逆境生物学", "植物-微生物互作"], + "application_tags": ["基础研究"], + "cas_partition": null, + "jcr_quartile": null, + "partition_source": "placeholder", + "cross_domain": ["植物生物技术"], + "format_rules": { + "max_pages": null, + "min_font_pt": null, + "min_margin_mm": null, + "min_line_spacing": 2.0, + "max_fonts": null, + "min_figures": null, + "refs_style": "vancouver", + "anonymous": false, + "rules_source": "official", + "source_url": "https://bmcplantbiol.biomedcentral.com/submission-guidelines", + "last_verified": "2026-10-10", + "notes": "同 BMC 系列模板页:双倍行距+行页码编号;参考文献 MEDLINE 缩写(→vancouver);BMC 系列 editorial policy 为 single-anonymous(作者无需匿名);字号/边距/页数上限该页未规定。" + } + }, + { + "id": "molecular-plant", + "name": "Molecular Plant", + "scope_desc": "High-impact journal for fundamental and translational plant science at the molecular level, covering genomics, cell and developmental biology, signal transduction, stress and metabolic responses, and plant biotechnology.", + "impact_factor": null, + "review_time_weeks": null, + "acceptance_rate": null, + "submission_deadline": null, + "official_url": "https://www.cell.com/molecular-plant", + "last_updated": "2026-10-10", + "scope_tags": ["分子生物学", "基因组学", "多组学"], + "application_tags": ["基础研究", "分子育种"], + "cas_partition": null, + "jcr_quartile": null, + "partition_source": "placeholder", + "cross_domain": ["植物生物技术"], + "format_rules": { + "max_pages": null, + "min_font_pt": 12, + "min_margin_mm": null, + "min_line_spacing": 1.5, + "max_fonts": null, + "min_figures": null, + "refs_style": "author_year", + "anonymous": null, + "rules_source": "official", + "source_url": "https://www.cell.com/molecular-plant/authors", + "last_verified": "2026-10-10", + "notes": "官网作者指南(本环境 cell.com 403,依据作者浏览器核对摘录):正文 12 point 字号、1.5 行距,参考文献 'cited in the text by name and year in parentheses'(作者-年份制→author_year);页数上限/边距/图表下限/匿名审稿政策该摘录未覆盖→null" + } + }, + { + "id": "frontiers-in-plant-science", + "name": "Frontiers in Plant Science", + "scope_desc": "Open-access journal spanning fundamental and applied plant sciences: molecular and cellular mechanisms, physiology, ecology, evolution, and applications in agriculture and biotechnology.", + "impact_factor": null, + "review_time_weeks": null, + "acceptance_rate": null, + "submission_deadline": null, + "official_url": "https://www.frontiersin.org/journals/plant-science", + "last_updated": "2026-10-10", + "scope_tags": ["植物生物学", "分子生物学", "生理学", "生态学"], + "application_tags": ["基础研究"], + "cas_partition": null, + "jcr_quartile": null, + "partition_source": "placeholder", + "cross_domain": ["农业科学"], + "format_rules": { + "max_pages": null, + "min_font_pt": null, + "min_margin_mm": null, + "min_line_spacing": 1.0, + "max_fonts": null, + "min_figures": null, + "refs_style": null, + "anonymous": null, + "rules_source": "official", + "source_url": "https://www.frontiersin.org/journals/plant-science/for-authors/author-guidelines", + "last_verified": "2026-10-10", + "notes": "官网 author-guidelines:'The entire document should be single-spaced and must contain page and line numbers'(单倍行距→1.0);页数按 Article types 页 word count 而非数字页限→max_pages=null;字号/边距/图表下限该页未规定。Frontiers 为 open peer review;官网未明文规定作者是否匿名,建议人工核实 review-guidelines 页。Frontiers 官网明确两种制式并存:Harvard (author-date) 或 Vancouver (numbered),具体到 Plant Science 需查 help center(当前抓取失败),建议人工核实 https://www.frontiersin.org/help/" + } + }, + { + "id": "rice", + "name": "Rice", + "scope_desc": "Open-access journal publishing research on all aspects of rice science, from molecular biology and genetics to breeding, physiology, ecology and production systems, with relevance to cereal crop improvement.", + "impact_factor": null, + "review_time_weeks": null, + "acceptance_rate": null, + "submission_deadline": null, + "official_url": "https://thericejournal.springeropen.com", + "last_updated": "2026-10-10", + "scope_tags": ["水稻", "作物基因组学", "遗传育种"], + "application_tags": ["基础研究", "分子育种", "种业"], + "cas_partition": null, + "jcr_quartile": null, + "partition_source": "placeholder", + "cross_domain": ["作物科学"], + "format_rules": { + "max_pages": null, + "min_font_pt": null, + "min_margin_mm": null, + "min_line_spacing": 2.0, + "max_fonts": null, + "min_figures": null, + "refs_style": "vancouver", + "anonymous": false, + "rules_source": "official", + "source_url": "https://thericejournal.springeropen.com/submission-guidelines", + "last_verified": "2026-10-10", + "notes": "SpringerOpen 系列模板页:'Use double-line spacing'(双倍行距→2.0)、行页码编号;参考文献 'Journal abbreviations follow Index Medicus/MEDLINE'(→vancouver);审稿明文 single-anonymous(审稿人知道作者身份,作者无需匿名);字号/边距/页数上限/图表下限该页未规定。" + } + } + ] +} diff --git a/review_service/data/journals/smoke/1_default_en.json b/review_service/data/journals/smoke/1_default_en.json new file mode 100644 index 0000000..18badb5 --- /dev/null +++ b/review_service/data/journals/smoke/1_default_en.json @@ -0,0 +1,1903 @@ +{ + "ok": true, + "items": [ + { + "id": "en:1740-1526", + "lang": "en", + "name": "NATURE REVIEWS MICROBIOLOGY", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 103.3, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1740-1526", + "eissn": "1740-1534", + "jcr_disciplines": [ + "MICROBIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1474-1776", + "lang": "en", + "name": "NATURE REVIEWS DRUG DISCOVERY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 101.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1474-1776", + "eissn": "1474-1784", + "jcr_disciplines": [ + "BIOTECHNOLOGY & APPLIED MICROBIOLOGY(SCIE)", + "PHARMACOLOGY & PHARMACY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1471-0072", + "lang": "en", + "name": "NATURE REVIEWS MOLECULAR CELL BIOLOGY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 90.2, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1471-0072", + "eissn": "1471-0080", + "jcr_disciplines": [ + "CELL BIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-4774", + "lang": "en", + "name": "Nature Reviews Clinical Oncology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 83.2, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-4774", + "eissn": "1759-4782", + "jcr_disciplines": [ + "ONCOLOGY(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-reviews-earth-environment", + "lang": "en", + "name": "Nature Reviews Earth & Environment", + "research_direction": "生态环境与保护", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 71.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": null, + "eissn": "2662-138X", + "jcr_disciplines": [ + "ENVIRONMENTAL SCIENCES(SCIE)", + "GEOSCIENCES, MULTIDISCIPLINARY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1474-175X", + "lang": "en", + "name": "NATURE REVIEWS CANCER", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 66.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1474-175X", + "eissn": "1474-1768", + "jcr_disciplines": [ + "ONCOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1474-1733", + "lang": "en", + "name": "NATURE REVIEWS IMMUNOLOGY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 60.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1474-1733", + "eissn": "1474-1741", + "jcr_disciplines": [ + "IMMUNOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2056-676X", + "lang": "en", + "name": "Nature Reviews Disease Primers", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 60.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "2056-676X", + "eissn": "2056-676X", + "jcr_disciplines": [ + "MEDICINE, GENERAL & INTERNAL(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-reviews-methods-primers", + "lang": "en", + "name": "Nature Reviews Methods Primers", + "research_direction": "遗传组学与计算生物", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 56.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": null, + "eissn": "2662-8449", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1471-0056", + "lang": "en", + "name": "NATURE REVIEWS GENETICS", + "research_direction": "遗传组学与计算生物", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 52.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1471-0056", + "eissn": "1471-0064", + "jcr_disciplines": [ + "GENETICS & HEREDITY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-reviews-chemistry", + "lang": "en", + "name": "Nature Reviews Chemistry", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 51.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": null, + "eissn": "2397-3358", + "jcr_disciplines": [ + "CHEMISTRY, MULTIDISCIPLINARY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-5045", + "lang": "en", + "name": "Nature Reviews Gastroenterology & Hepatology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 51.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-5045", + "eissn": "1759-5053", + "jcr_disciplines": [ + "GASTROENTEROLOGY & HEPATOLOGY(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1078-8956", + "lang": "en", + "name": "NATURE MEDICINE", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 50.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1078-8956", + "eissn": "1546-170X", + "jcr_disciplines": [ + "BIOCHEMISTRY & MOLECULAR BIOLOGY(SCIE)", + "CELL BIOLOGY(SCIE)", + "MEDICINE, RESEARCH & EXPERIMENTAL(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:0028-0836", + "lang": "en", + "name": "NATURE", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 48.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "经典专业刊", + "article_type": "研究/方法/综合", + "issn": "0028-0836", + "eissn": "1476-4687", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:0036-8075", + "lang": "en", + "name": "SCIENCE", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 45.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Science / AAAS", + "journal_mark": "经典专业刊", + "article_type": "研究/方法/综合", + "issn": "0036-8075", + "eissn": "1095-9203", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1535-6108", + "lang": "en", + "name": "CANCER CELL", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 44.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1535-6108", + "eissn": "1878-3686", + "jcr_disciplines": [ + "CELL BIOLOGY(SCIE)", + "ONCOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-5002", + "lang": "en", + "name": "Nature Reviews Cardiology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 44.2, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-5002", + "eissn": "1759-5010", + "jcr_disciplines": [ + "CARDIAC & CARDIOVASCULAR SYSTEMS(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:0092-8674", + "lang": "en", + "name": "CELL", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 42.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "经典专业刊", + "article_type": "研究/方法/综合", + "issn": "0092-8674", + "eissn": "1097-4172", + "jcr_disciplines": [ + "BIOCHEMISTRY & MOLECULAR BIOLOGY(SCIE)", + "CELL BIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-5029", + "lang": "en", + "name": "Nature Reviews Endocrinology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 42.3, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-5029", + "eissn": "1759-5037", + "jcr_disciplines": [ + "ENDOCRINOLOGY & METABOLISM(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1087-0156", + "lang": "en", + "name": "NATURE BIOTECHNOLOGY", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 41.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1087-0156", + "eissn": "1546-1696", + "jcr_disciplines": [ + "BIOTECHNOLOGY & APPLIED MICROBIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-5061", + "lang": "en", + "name": "Nature Reviews Nephrology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 39.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-5061", + "eissn": "1759-507X", + "jcr_disciplines": [ + "UROLOGY & NEPHROLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-reviews-bioengineering", + "lang": "en", + "name": "Nature Reviews Bioengineering", + "research_direction": "微生物真菌与生物技术", + "cas_partition": null, + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 37.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "未检得", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": null, + "eissn": "2731-6092", + "jcr_disciplines": [ + "ENGINEERING, BIOMEDICAL(ESCI)", + "MATERIALS SCIENCE, BIOMATERIALS(ESCI)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": null, + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2542-4351", + "lang": "en", + "name": "Joule", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 35.4, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2542-4351", + "eissn": "2542-4351", + "jcr_disciplines": [ + "CHEMISTRY, PHYSICAL(SCIE)", + "ENERGY & FUELS(SCIE)", + "MATERIALS SCIENCE, MULTIDISCIPLINARY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-4790", + "lang": "en", + "name": "Nature Reviews Rheumatology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 32.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-4790", + "eissn": "1759-4804", + "jcr_disciplines": [ + "RHEUMATOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1548-7091", + "lang": "en", + "name": "NATURE METHODS", + "research_direction": "遗传组学与计算生物", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 32.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1548-7091", + "eissn": "1548-7105", + "jcr_disciplines": [ + "BIOCHEMICAL RESEARCH METHODS(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1550-4131", + "lang": "en", + "name": "Cell Metabolism", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 30.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1550-4131", + "eissn": "1932-7420", + "jcr_disciplines": [ + "CELL BIOLOGY(SCIE)", + "ENDOCRINOLOGY & METABOLISM(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1061-4036", + "lang": "en", + "name": "NATURE GENETICS", + "research_direction": "遗传组学与计算生物", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 29.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1061-4036", + "eissn": "1546-1718", + "jcr_disciplines": [ + "GENETICS & HEREDITY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-cancer", + "lang": "en", + "name": "Nature Cancer", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 28.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2662-1347", + "jcr_disciplines": [ + "ONCOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1529-2908", + "lang": "en", + "name": "NATURE IMMUNOLOGY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 27.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1529-2908", + "eissn": "1529-2916", + "jcr_disciplines": [ + "IMMUNOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2470-9476", + "lang": "en", + "name": "Science Robotics", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 27.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Science / AAAS", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2470-9476", + "eissn": "2470-9476", + "jcr_disciplines": [ + "ROBOTICS(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1758-678X", + "lang": "en", + "name": "Nature Climate Change", + "research_direction": "生态环境与保护", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 27.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1758-678X", + "eissn": "1758-6798", + "jcr_disciplines": [ + "ENVIRONMENTAL SCIENCES(SCIE)", + "ENVIRONMENTAL STUDIES(SSCI)", + "METEOROLOGY & ATMOSPHERIC SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2398-9629", + "lang": "en", + "name": "Nature Sustainability", + "research_direction": "生态环境与保护", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 27.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2398-9629", + "eissn": "2398-9629", + "jcr_disciplines": [ + "ENVIRONMENTAL SCIENCES(SCIE)", + "ENVIRONMENTAL STUDIES(SSCI)", + "GREEN & SUSTAINABLE SCIENCE & TECHNOLOGY(SSCI)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2157-846X", + "lang": "en", + "name": "Nature Biomedical Engineering", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 26.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2157-846X", + "eissn": "2157-846X", + "jcr_disciplines": [ + "ENGINEERING, BIOMEDICAL(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1471-003X", + "lang": "en", + "name": "NATURE REVIEWS NEUROSCIENCE", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 26.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1471-003X", + "eissn": "1471-0048", + "jcr_disciplines": [ + "NEUROSCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1543-5008", + "lang": "en", + "name": "Annual Review of Plant Biology", + "research_direction": "植物科学与分子育种", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 26.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1543-5008", + "eissn": "1545-2123", + "jcr_disciplines": [ + "PLANT SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1074-7613", + "lang": "en", + "name": "Immunity", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 26.3, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1074-7613", + "eissn": "1097-4180", + "jcr_disciplines": [ + "IMMUNOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1001-0602", + "lang": "en", + "name": "CELL RESEARCH", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 25.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1001-0602", + "eissn": "1748-7838", + "jcr_disciplines": [ + "CELL BIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2666-6758", + "lang": "en", + "name": "Innovation", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 25.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2666-6758", + "eissn": "2666-6758", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(ESCI)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1560-2745", + "lang": "en", + "name": "FUNGAL DIVERSITY", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 24.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1560-2745", + "eissn": "1878-9129", + "jcr_disciplines": [ + "MYCOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1674-2052", + "lang": "en", + "name": "Molecular Plant", + "research_direction": "植物科学与分子育种", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 24.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1674-2052", + "eissn": "1752-9867", + "jcr_disciplines": [ + "BIOCHEMISTRY & MOLECULAR BIOLOGY(SCIE)", + "PLANT SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-water", + "lang": "en", + "name": "Nature Water", + "research_direction": "生态环境与保护", + "cas_partition": null, + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 24.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "未检得", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2731-6084", + "jcr_disciplines": [ + "ENVIRONMENTAL SCIENCES(ESCI)", + "WATER RESOURCES(ESCI)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": null, + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-food", + "lang": "en", + "name": "Nature Food", + "research_direction": "食品营养与安全", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 21.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2662-1355", + "jcr_disciplines": [ + "FOOD SCIENCE & TECHNOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2095-9273", + "lang": "en", + "name": "Science Bulletin", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 21.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2095-9273", + "eissn": "2095-9281", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1360-1385", + "lang": "en", + "name": "TRENDS IN PLANT SCIENCE", + "research_direction": "植物科学与分子育种", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 20.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1360-1385", + "eissn": "1878-4372", + "jcr_disciplines": [ + "PLANT SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-metabolism", + "lang": "en", + "name": "Nature Metabolism", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 20.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2522-5812", + "jcr_disciplines": [ + "ENDOCRINOLOGY & METABOLISM(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1610-3653", + "lang": "en", + "name": "Environmental Chemistry Letters", + "research_direction": "生态环境与保护", + "cas_partition": "2区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 20.4, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "否", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1610-3653", + "eissn": "1610-3661", + "jcr_disciplines": [ + "CHEMISTRY, MULTIDISCIPLINARY(SCIE)", + "ENGINEERING, ENVIRONMENTAL(SCIE)", + "ENVIRONMENTAL SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1934-5909", + "lang": "en", + "name": "Cell Stem Cell", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 20.4, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1934-5909", + "eissn": "1875-9777", + "jcr_disciplines": [ + "CELL & TISSUE ENGINEERING(SCIE)", + "CELL BIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1097-6256", + "lang": "en", + "name": "NATURE NEUROSCIENCE", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 20.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1097-6256", + "eissn": "1546-1726", + "jcr_disciplines": [ + "NEUROSCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:0165-6147", + "lang": "en", + "name": "TRENDS IN PHARMACOLOGICAL SCIENCES", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 19.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "0165-6147", + "eissn": "1873-3735", + "jcr_disciplines": [ + "PHARMACOLOGY & PHARMACY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2451-9294", + "lang": "en", + "name": "Chem", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 19.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2451-9294", + "eissn": "2451-9294", + "jcr_disciplines": [ + "CHEMISTRY, MULTIDISCIPLINARY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + } + ], + "meta": { + "total": 779, + "page": 1, + "size": 50, + "lang": "en", + "domain": "", + "cas_partition": "", + "q": "", + "domains": [ + "细胞分子发育与生理", + "生态环境与保护", + "微生物真菌与生物技术", + "农学作物与种质", + "遗传组学与计算生物", + "植物科学与分子育种", + "水产渔业与海洋生物", + "食品营养与安全", + "植物保护与昆虫", + "畜牧动物营养与繁殖", + "土壤肥料与地球生物化学", + "林业木材与草业", + "兽医与寄生虫", + "综合与交叉", + "园艺果树与采后" + ], + "data_source_note": "分区:2025年中科院公开表(official);JIF:2024 JCR,由2025版JCR发布(official);整理日期2026-10-10。空白=来源未给值≠0;研究方向/期刊标记/文章类型为导航标签,非官方评级。", + "data_imported": true + }, + "error": null +} \ No newline at end of file diff --git a/review_service/data/journals/smoke/2_lang_zh.json b/review_service/data/journals/smoke/2_lang_zh.json new file mode 100644 index 0000000..e6c6576 --- /dev/null +++ b/review_service/data/journals/smoke/2_lang_zh.json @@ -0,0 +1,1779 @@ +{ + "ok": true, + "items": [ + { + "id": "zh:自然资源学报", + "lang": "zh", + "name": "自然资源学报", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 10.773, + "comprehensive_impact_factor": 7.725, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:地理学报", + "lang": "zh", + "name": "地理学报", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 9.926, + "comprehensive_impact_factor": 7.412, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:中国人口-资源与环境", + "lang": "zh", + "name": "中国人口·资源与环境", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 9.53, + "comprehensive_impact_factor": 6.957, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 154, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=154" + }, + { + "id": "zh:地理研究", + "lang": "zh", + "name": "地理研究", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 7.661, + "comprehensive_impact_factor": 5.5, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:资源科学", + "lang": "zh", + "name": "资源科学", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 6.731, + "comprehensive_impact_factor": 4.962, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:地理科学", + "lang": "zh", + "name": "地理科学", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 6.614, + "comprehensive_impact_factor": 4.698, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:地理科学进展", + "lang": "zh", + "name": "地理科学进展", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 6.513, + "comprehensive_impact_factor": 4.532, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:生态学报", + "lang": "zh", + "name": "生态学报", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 6.473, + "comprehensive_impact_factor": 4.412, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:土壤学报", + "lang": "zh", + "name": "土壤学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 6.361, + "comprehensive_impact_factor": 4.262, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:环境科学", + "lang": "zh", + "name": "环境科学", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 6.137, + "comprehensive_impact_factor": 4.34, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 154, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=154" + }, + { + "id": "zh:长江流域资源与环境", + "lang": "zh", + "name": "长江流域资源与环境", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 5.364, + "comprehensive_impact_factor": 3.609, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 154, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=154" + }, + { + "id": "zh:应用生态学报", + "lang": "zh", + "name": "应用生态学报", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 5.047, + "comprehensive_impact_factor": 3.296, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:中国生态农业学报-中英文", + "lang": "zh", + "name": "中国生态农业学报(中英文)", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 5.034, + "comprehensive_impact_factor": 3.311, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:环境科学研究", + "lang": "zh", + "name": "环境科学研究", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.848, + "comprehensive_impact_factor": 3.716, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 155, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=155" + }, + { + "id": "zh:农业现代化研究", + "lang": "zh", + "name": "农业现代化研究", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.842, + "comprehensive_impact_factor": 3.032, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 87, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=87" + }, + { + "id": "zh:遥感学报", + "lang": "zh", + "name": "遥感学报", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.799, + "comprehensive_impact_factor": 3.257, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 44, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=44" + }, + { + "id": "zh:农业机械学报", + "lang": "zh", + "name": "农业机械学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.696, + "comprehensive_impact_factor": 3.037, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:水土保持研究", + "lang": "zh", + "name": "水土保持研究", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.651, + "comprehensive_impact_factor": 3.002, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:植物营养与肥料学报", + "lang": "zh", + "name": "植物营养与肥料学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.634, + "comprehensive_impact_factor": 3.17, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:农业资源与环境学报", + "lang": "zh", + "name": "农业资源与环境学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.531, + "comprehensive_impact_factor": 2.88, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 87, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=87" + }, + { + "id": "zh:生态学杂志", + "lang": "zh", + "name": "生态学杂志", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.444, + "comprehensive_impact_factor": 2.907, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:草业学报", + "lang": "zh", + "name": "草业学报", + "research_direction": "林学木材与草业", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.361, + "comprehensive_impact_factor": 2.903, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 96, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=96" + }, + { + "id": "zh:水土保持学报", + "lang": "zh", + "name": "水土保持学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.35, + "comprehensive_impact_factor": 2.863, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:植物生态学报", + "lang": "zh", + "name": "植物生态学报", + "research_direction": "综合与生命科学", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.325, + "comprehensive_impact_factor": 3.063, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:干旱区研究", + "lang": "zh", + "name": "干旱区研究", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.234, + "comprehensive_impact_factor": 3.019, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 46, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=46" + }, + { + "id": "zh:湖泊科学", + "lang": "zh", + "name": "湖泊科学", + "research_direction": "水产渔业与海洋生物", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.222, + "comprehensive_impact_factor": 3.009, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 146, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=146" + }, + { + "id": "zh:农业工程学报", + "lang": "zh", + "name": "农业工程学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.125, + "comprehensive_impact_factor": 3.04, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:干旱区地理", + "lang": "zh", + "name": "干旱区地理", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.03, + "comprehensive_impact_factor": 2.699, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:中国水稻科学", + "lang": "zh", + "name": "中国水稻科学", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.024, + "comprehensive_impact_factor": 2.887, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 91, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=91" + }, + { + "id": "zh:草地学报", + "lang": "zh", + "name": "草地学报", + "research_direction": "林学木材与草业", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.007, + "comprehensive_impact_factor": 2.893, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 96, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=96" + }, + { + "id": "zh:食品科学", + "lang": "zh", + "name": "食品科学", + "research_direction": "食品科学营养与安全", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.002, + "comprehensive_impact_factor": 2.806, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 138, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=138" + }, + { + "id": "zh:作物学报", + "lang": "zh", + "name": "作物学报", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.968, + "comprehensive_impact_factor": 2.735, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 91, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=91" + }, + { + "id": "zh:中国草地学报", + "lang": "zh", + "name": "中国草地学报", + "research_direction": "林学木材与草业", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.915, + "comprehensive_impact_factor": 2.805, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 96, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=96" + }, + { + "id": "zh:土壤通报", + "lang": "zh", + "name": "土壤通报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.849, + "comprehensive_impact_factor": 2.571, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:中国农业科学", + "lang": "zh", + "name": "中国农业科学", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.804, + "comprehensive_impact_factor": 2.673, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 87, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=87" + }, + { + "id": "zh:中国环境科学", + "lang": "zh", + "name": "中国环境科学", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.741, + "comprehensive_impact_factor": 2.694, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 155, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=155" + }, + { + "id": "zh:生态环境学报", + "lang": "zh", + "name": "生态环境学报", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.668, + "comprehensive_impact_factor": 2.693, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:中国沙漠", + "lang": "zh", + "name": "中国沙漠", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.639, + "comprehensive_impact_factor": 2.611, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:中南林业科技大学学报", + "lang": "zh", + "name": "中南林业科技大学学报", + "research_direction": "林学木材与草业", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.594, + "comprehensive_impact_factor": 2.56, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 94, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=94" + }, + { + "id": "zh:中国科学-生命科学", + "lang": "zh", + "name": "中国科学:生命科学", + "research_direction": "综合与生命科学", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.488, + "comprehensive_impact_factor": 2.236, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:中国农业大学学报", + "lang": "zh", + "name": "中国农业大学学报", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.478, + "comprehensive_impact_factor": 2.188, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 87, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=87" + }, + { + "id": "zh:生物多样性", + "lang": "zh", + "name": "生物多样性", + "research_direction": "综合与生命科学", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.451, + "comprehensive_impact_factor": 2.646, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:菌物学报", + "lang": "zh", + "name": "菌物学报", + "research_direction": "综合与生命科学", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.392, + "comprehensive_impact_factor": 2.697, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:中国农业气象", + "lang": "zh", + "name": "中国农业气象", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.355, + "comprehensive_impact_factor": 2.541, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:动物营养学报", + "lang": "zh", + "name": "动物营养学报", + "research_direction": "畜牧兽医与动物营养", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.352, + "comprehensive_impact_factor": 2.429, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 96, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=96" + }, + { + "id": "zh:土壤", + "lang": "zh", + "name": "土壤", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.351, + "comprehensive_impact_factor": 2.372, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:林产工业", + "lang": "zh", + "name": "林产工业", + "research_direction": "林学木材与草业", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.319, + "comprehensive_impact_factor": 2.901, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 140, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=140" + }, + { + "id": "zh:农业环境科学学报", + "lang": "zh", + "name": "农业环境科学学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.316, + "comprehensive_impact_factor": 2.25, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 155, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=155" + }, + { + "id": "zh:环境保护", + "lang": "zh", + "name": "环境保护", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.296, + "comprehensive_impact_factor": 2.218, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 155, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=155" + }, + { + "id": "zh:水土保持通报", + "lang": "zh", + "name": "水土保持通报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.17, + "comprehensive_impact_factor": 2.225, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + } + ], + "meta": { + "total": 277, + "page": 1, + "size": 50, + "lang": "zh", + "domain": "", + "cas_partition": "", + "q": "", + "domains": [ + "农学作物与种质", + "生态环境与自然资源", + "综合与生命科学", + "畜牧兽医与动物营养", + "食品科学营养与安全", + "水产渔业与海洋生物", + "土壤肥料与农业环境", + "林学木材与草业", + "园艺果树与茶学", + "植物保护与昆虫" + ], + "data_source_note": "指标:国内自然科学期刊年报2024版(统计年2023,official,含复合/综合IF两口径);中文期刊不按中科院分区口径列示;国内IF与JIF统计源不同,不可混排。", + "data_imported": true + }, + "error": null +} \ No newline at end of file diff --git a/review_service/data/journals/smoke/3_q_nature.json b/review_service/data/journals/smoke/3_q_nature.json new file mode 100644 index 0000000..fe8c79c --- /dev/null +++ b/review_service/data/journals/smoke/3_q_nature.json @@ -0,0 +1,1716 @@ +{ + "ok": true, + "items": [ + { + "id": "en:1740-1526", + "lang": "en", + "name": "NATURE REVIEWS MICROBIOLOGY", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 103.3, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1740-1526", + "eissn": "1740-1534", + "jcr_disciplines": [ + "MICROBIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1474-1776", + "lang": "en", + "name": "NATURE REVIEWS DRUG DISCOVERY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 101.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1474-1776", + "eissn": "1474-1784", + "jcr_disciplines": [ + "BIOTECHNOLOGY & APPLIED MICROBIOLOGY(SCIE)", + "PHARMACOLOGY & PHARMACY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1471-0072", + "lang": "en", + "name": "NATURE REVIEWS MOLECULAR CELL BIOLOGY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 90.2, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1471-0072", + "eissn": "1471-0080", + "jcr_disciplines": [ + "CELL BIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-4774", + "lang": "en", + "name": "Nature Reviews Clinical Oncology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 83.2, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-4774", + "eissn": "1759-4782", + "jcr_disciplines": [ + "ONCOLOGY(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-reviews-earth-environment", + "lang": "en", + "name": "Nature Reviews Earth & Environment", + "research_direction": "生态环境与保护", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 71.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": null, + "eissn": "2662-138X", + "jcr_disciplines": [ + "ENVIRONMENTAL SCIENCES(SCIE)", + "GEOSCIENCES, MULTIDISCIPLINARY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1474-175X", + "lang": "en", + "name": "NATURE REVIEWS CANCER", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 66.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1474-175X", + "eissn": "1474-1768", + "jcr_disciplines": [ + "ONCOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1474-1733", + "lang": "en", + "name": "NATURE REVIEWS IMMUNOLOGY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 60.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1474-1733", + "eissn": "1474-1741", + "jcr_disciplines": [ + "IMMUNOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2056-676X", + "lang": "en", + "name": "Nature Reviews Disease Primers", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 60.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "2056-676X", + "eissn": "2056-676X", + "jcr_disciplines": [ + "MEDICINE, GENERAL & INTERNAL(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-reviews-methods-primers", + "lang": "en", + "name": "Nature Reviews Methods Primers", + "research_direction": "遗传组学与计算生物", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 56.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": null, + "eissn": "2662-8449", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1471-0056", + "lang": "en", + "name": "NATURE REVIEWS GENETICS", + "research_direction": "遗传组学与计算生物", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 52.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1471-0056", + "eissn": "1471-0064", + "jcr_disciplines": [ + "GENETICS & HEREDITY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-reviews-chemistry", + "lang": "en", + "name": "Nature Reviews Chemistry", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 51.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": null, + "eissn": "2397-3358", + "jcr_disciplines": [ + "CHEMISTRY, MULTIDISCIPLINARY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-5045", + "lang": "en", + "name": "Nature Reviews Gastroenterology & Hepatology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 51.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-5045", + "eissn": "1759-5053", + "jcr_disciplines": [ + "GASTROENTEROLOGY & HEPATOLOGY(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1078-8956", + "lang": "en", + "name": "NATURE MEDICINE", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 50.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1078-8956", + "eissn": "1546-170X", + "jcr_disciplines": [ + "BIOCHEMISTRY & MOLECULAR BIOLOGY(SCIE)", + "CELL BIOLOGY(SCIE)", + "MEDICINE, RESEARCH & EXPERIMENTAL(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:0028-0836", + "lang": "en", + "name": "NATURE", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 48.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "经典专业刊", + "article_type": "研究/方法/综合", + "issn": "0028-0836", + "eissn": "1476-4687", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-5002", + "lang": "en", + "name": "Nature Reviews Cardiology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 44.2, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-5002", + "eissn": "1759-5010", + "jcr_disciplines": [ + "CARDIAC & CARDIOVASCULAR SYSTEMS(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-5029", + "lang": "en", + "name": "Nature Reviews Endocrinology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 42.3, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-5029", + "eissn": "1759-5037", + "jcr_disciplines": [ + "ENDOCRINOLOGY & METABOLISM(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1087-0156", + "lang": "en", + "name": "NATURE BIOTECHNOLOGY", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 41.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1087-0156", + "eissn": "1546-1696", + "jcr_disciplines": [ + "BIOTECHNOLOGY & APPLIED MICROBIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-5061", + "lang": "en", + "name": "Nature Reviews Nephrology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 39.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-5061", + "eissn": "1759-507X", + "jcr_disciplines": [ + "UROLOGY & NEPHROLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-reviews-bioengineering", + "lang": "en", + "name": "Nature Reviews Bioengineering", + "research_direction": "微生物真菌与生物技术", + "cas_partition": null, + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 37.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "未检得", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": null, + "eissn": "2731-6092", + "jcr_disciplines": [ + "ENGINEERING, BIOMEDICAL(ESCI)", + "MATERIALS SCIENCE, BIOMATERIALS(ESCI)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": null, + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-4790", + "lang": "en", + "name": "Nature Reviews Rheumatology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 32.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-4790", + "eissn": "1759-4804", + "jcr_disciplines": [ + "RHEUMATOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1548-7091", + "lang": "en", + "name": "NATURE METHODS", + "research_direction": "遗传组学与计算生物", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 32.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1548-7091", + "eissn": "1548-7105", + "jcr_disciplines": [ + "BIOCHEMICAL RESEARCH METHODS(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1061-4036", + "lang": "en", + "name": "NATURE GENETICS", + "research_direction": "遗传组学与计算生物", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 29.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1061-4036", + "eissn": "1546-1718", + "jcr_disciplines": [ + "GENETICS & HEREDITY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-cancer", + "lang": "en", + "name": "Nature Cancer", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 28.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2662-1347", + "jcr_disciplines": [ + "ONCOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1529-2908", + "lang": "en", + "name": "NATURE IMMUNOLOGY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 27.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1529-2908", + "eissn": "1529-2916", + "jcr_disciplines": [ + "IMMUNOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1758-678X", + "lang": "en", + "name": "Nature Climate Change", + "research_direction": "生态环境与保护", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 27.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1758-678X", + "eissn": "1758-6798", + "jcr_disciplines": [ + "ENVIRONMENTAL SCIENCES(SCIE)", + "ENVIRONMENTAL STUDIES(SSCI)", + "METEOROLOGY & ATMOSPHERIC SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2398-9629", + "lang": "en", + "name": "Nature Sustainability", + "research_direction": "生态环境与保护", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 27.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2398-9629", + "eissn": "2398-9629", + "jcr_disciplines": [ + "ENVIRONMENTAL SCIENCES(SCIE)", + "ENVIRONMENTAL STUDIES(SSCI)", + "GREEN & SUSTAINABLE SCIENCE & TECHNOLOGY(SSCI)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2157-846X", + "lang": "en", + "name": "Nature Biomedical Engineering", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 26.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2157-846X", + "eissn": "2157-846X", + "jcr_disciplines": [ + "ENGINEERING, BIOMEDICAL(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1471-003X", + "lang": "en", + "name": "NATURE REVIEWS NEUROSCIENCE", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 26.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1471-003X", + "eissn": "1471-0048", + "jcr_disciplines": [ + "NEUROSCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-water", + "lang": "en", + "name": "Nature Water", + "research_direction": "生态环境与保护", + "cas_partition": null, + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 24.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "未检得", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2731-6084", + "jcr_disciplines": [ + "ENVIRONMENTAL SCIENCES(ESCI)", + "WATER RESOURCES(ESCI)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": null, + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-food", + "lang": "en", + "name": "Nature Food", + "research_direction": "食品营养与安全", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 21.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2662-1355", + "jcr_disciplines": [ + "FOOD SCIENCE & TECHNOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-metabolism", + "lang": "en", + "name": "Nature Metabolism", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 20.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2522-5812", + "jcr_disciplines": [ + "ENDOCRINOLOGY & METABOLISM(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1097-6256", + "lang": "en", + "name": "NATURE NEUROSCIENCE", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 20.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1097-6256", + "eissn": "1546-1726", + "jcr_disciplines": [ + "NEUROSCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1465-7392", + "lang": "en", + "name": "NATURE CELL BIOLOGY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 19.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1465-7392", + "eissn": "1476-4679", + "jcr_disciplines": [ + "CELL BIOLOGY(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-aging", + "lang": "en", + "name": "Nature Aging", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 19.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2662-8465", + "jcr_disciplines": [ + "CELL BIOLOGY(SCIE)", + "GERIATRICS & GERONTOLOGY(SCIE)", + "NEUROSCIENCES(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2058-5276", + "lang": "en", + "name": "Nature Microbiology", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 19.4, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2058-5276", + "eissn": "2058-5276", + "jcr_disciplines": [ + "MICROBIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1752-0894", + "lang": "en", + "name": "Nature Geoscience", + "research_direction": "生态环境与保护", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 16.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1752-0894", + "eissn": "1752-0908", + "jcr_disciplines": [ + "GEOSCIENCES, MULTIDISCIPLINARY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1754-2189", + "lang": "en", + "name": "Nature Protocols", + "research_direction": "遗传组学与计算生物", + "cas_partition": "2区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 16.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1754-2189", + "eissn": "1750-2799", + "jcr_disciplines": [ + "BIOCHEMICAL RESEARCH METHODS(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2397-3374", + "lang": "en", + "name": "Nature Human Behaviour", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 15.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2397-3374", + "eissn": "2397-3374", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)", + "NEUROSCIENCES(SCIE)", + "PSYCHOLOGY, EXPERIMENTAL(SSCI)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-communications", + "lang": "en", + "name": "Nature Communications", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 15.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2041-1723", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-4812", + "lang": "en", + "name": "Nature Reviews Urology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 14.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-4812", + "eissn": "1759-4820", + "jcr_disciplines": [ + "UROLOGY & NEPHROLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2397-334X", + "lang": "en", + "name": "Nature Ecology & Evolution", + "research_direction": "生态环境与保护", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 14.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2397-334X", + "eissn": "2397-334X", + "jcr_disciplines": [ + "ECOLOGY(SCIE)", + "EVOLUTIONARY BIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1552-4450", + "lang": "en", + "name": "Nature Chemical Biology", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 13.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1552-4450", + "eissn": "1552-4469", + "jcr_disciplines": [ + "BIOCHEMISTRY & MOLECULAR BIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2055-026X", + "lang": "en", + "name": "Nature Plants", + "research_direction": "植物科学与分子育种", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 13.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2055-026X", + "eissn": "2055-0278", + "jcr_disciplines": [ + "PLANT SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1545-9993", + "lang": "en", + "name": "NATURE STRUCTURAL & MOLECULAR BIOLOGY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 10.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1545-9993", + "eissn": "1545-9985", + "jcr_disciplines": [ + "BIOCHEMISTRY & MOLECULAR BIOLOGY(SCIE)", + "BIOPHYSICS(SCIE)", + "CELL BIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-mental-health", + "lang": "en", + "name": "Nature Mental Health", + "research_direction": "细胞分子发育与生理", + "cas_partition": null, + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 8.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "未检得", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2731-6076", + "jcr_disciplines": [ + "PSYCHIATRY(ESCI)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": null, + "data_source_label": "JIF来源", + "data_source_url": null + } + ], + "meta": { + "total": 45, + "page": 1, + "size": 50, + "lang": "en", + "domain": "", + "cas_partition": "", + "q": "nature", + "domains": [ + "细胞分子发育与生理", + "生态环境与保护", + "微生物真菌与生物技术", + "农学作物与种质", + "遗传组学与计算生物", + "植物科学与分子育种", + "水产渔业与海洋生物", + "食品营养与安全", + "植物保护与昆虫", + "畜牧动物营养与繁殖", + "土壤肥料与地球生物化学", + "林业木材与草业", + "兽医与寄生虫", + "综合与交叉", + "园艺果树与采后" + ], + "data_source_note": "分区:2025年中科院公开表(official);JIF:2024 JCR,由2025版JCR发布(official);整理日期2026-10-10。空白=来源未给值≠0;研究方向/期刊标记/文章类型为导航标签,非官方评级。", + "data_imported": true + }, + "error": null +} \ No newline at end of file diff --git a/review_service/data/journals/smoke/4_partition1_en.json b/review_service/data/journals/smoke/4_partition1_en.json new file mode 100644 index 0000000..ea51ea9 --- /dev/null +++ b/review_service/data/journals/smoke/4_partition1_en.json @@ -0,0 +1,1901 @@ +{ + "ok": true, + "items": [ + { + "id": "en:1740-1526", + "lang": "en", + "name": "NATURE REVIEWS MICROBIOLOGY", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 103.3, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1740-1526", + "eissn": "1740-1534", + "jcr_disciplines": [ + "MICROBIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1474-1776", + "lang": "en", + "name": "NATURE REVIEWS DRUG DISCOVERY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 101.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1474-1776", + "eissn": "1474-1784", + "jcr_disciplines": [ + "BIOTECHNOLOGY & APPLIED MICROBIOLOGY(SCIE)", + "PHARMACOLOGY & PHARMACY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1471-0072", + "lang": "en", + "name": "NATURE REVIEWS MOLECULAR CELL BIOLOGY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 90.2, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1471-0072", + "eissn": "1471-0080", + "jcr_disciplines": [ + "CELL BIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-4774", + "lang": "en", + "name": "Nature Reviews Clinical Oncology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 83.2, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-4774", + "eissn": "1759-4782", + "jcr_disciplines": [ + "ONCOLOGY(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-reviews-earth-environment", + "lang": "en", + "name": "Nature Reviews Earth & Environment", + "research_direction": "生态环境与保护", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 71.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": null, + "eissn": "2662-138X", + "jcr_disciplines": [ + "ENVIRONMENTAL SCIENCES(SCIE)", + "GEOSCIENCES, MULTIDISCIPLINARY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1474-175X", + "lang": "en", + "name": "NATURE REVIEWS CANCER", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 66.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1474-175X", + "eissn": "1474-1768", + "jcr_disciplines": [ + "ONCOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1474-1733", + "lang": "en", + "name": "NATURE REVIEWS IMMUNOLOGY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 60.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1474-1733", + "eissn": "1474-1741", + "jcr_disciplines": [ + "IMMUNOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2056-676X", + "lang": "en", + "name": "Nature Reviews Disease Primers", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 60.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "2056-676X", + "eissn": "2056-676X", + "jcr_disciplines": [ + "MEDICINE, GENERAL & INTERNAL(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-reviews-methods-primers", + "lang": "en", + "name": "Nature Reviews Methods Primers", + "research_direction": "遗传组学与计算生物", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 56.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": null, + "eissn": "2662-8449", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1471-0056", + "lang": "en", + "name": "NATURE REVIEWS GENETICS", + "research_direction": "遗传组学与计算生物", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 52.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1471-0056", + "eissn": "1471-0064", + "jcr_disciplines": [ + "GENETICS & HEREDITY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-reviews-chemistry", + "lang": "en", + "name": "Nature Reviews Chemistry", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 51.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": null, + "eissn": "2397-3358", + "jcr_disciplines": [ + "CHEMISTRY, MULTIDISCIPLINARY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-5045", + "lang": "en", + "name": "Nature Reviews Gastroenterology & Hepatology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 51.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-5045", + "eissn": "1759-5053", + "jcr_disciplines": [ + "GASTROENTEROLOGY & HEPATOLOGY(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1078-8956", + "lang": "en", + "name": "NATURE MEDICINE", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 50.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1078-8956", + "eissn": "1546-170X", + "jcr_disciplines": [ + "BIOCHEMISTRY & MOLECULAR BIOLOGY(SCIE)", + "CELL BIOLOGY(SCIE)", + "MEDICINE, RESEARCH & EXPERIMENTAL(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:0028-0836", + "lang": "en", + "name": "NATURE", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 48.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "经典专业刊", + "article_type": "研究/方法/综合", + "issn": "0028-0836", + "eissn": "1476-4687", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:0036-8075", + "lang": "en", + "name": "SCIENCE", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 45.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Science / AAAS", + "journal_mark": "经典专业刊", + "article_type": "研究/方法/综合", + "issn": "0036-8075", + "eissn": "1095-9203", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1535-6108", + "lang": "en", + "name": "CANCER CELL", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 44.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1535-6108", + "eissn": "1878-3686", + "jcr_disciplines": [ + "CELL BIOLOGY(SCIE)", + "ONCOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-5002", + "lang": "en", + "name": "Nature Reviews Cardiology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 44.2, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-5002", + "eissn": "1759-5010", + "jcr_disciplines": [ + "CARDIAC & CARDIOVASCULAR SYSTEMS(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:0092-8674", + "lang": "en", + "name": "CELL", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 42.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "经典专业刊", + "article_type": "研究/方法/综合", + "issn": "0092-8674", + "eissn": "1097-4172", + "jcr_disciplines": [ + "BIOCHEMISTRY & MOLECULAR BIOLOGY(SCIE)", + "CELL BIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-5029", + "lang": "en", + "name": "Nature Reviews Endocrinology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 42.3, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-5029", + "eissn": "1759-5037", + "jcr_disciplines": [ + "ENDOCRINOLOGY & METABOLISM(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1087-0156", + "lang": "en", + "name": "NATURE BIOTECHNOLOGY", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 41.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1087-0156", + "eissn": "1546-1696", + "jcr_disciplines": [ + "BIOTECHNOLOGY & APPLIED MICROBIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-5061", + "lang": "en", + "name": "Nature Reviews Nephrology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 39.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-5061", + "eissn": "1759-507X", + "jcr_disciplines": [ + "UROLOGY & NEPHROLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2542-4351", + "lang": "en", + "name": "Joule", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 35.4, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2542-4351", + "eissn": "2542-4351", + "jcr_disciplines": [ + "CHEMISTRY, PHYSICAL(SCIE)", + "ENERGY & FUELS(SCIE)", + "MATERIALS SCIENCE, MULTIDISCIPLINARY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1759-4790", + "lang": "en", + "name": "Nature Reviews Rheumatology", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 32.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1759-4790", + "eissn": "1759-4804", + "jcr_disciplines": [ + "RHEUMATOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1548-7091", + "lang": "en", + "name": "NATURE METHODS", + "research_direction": "遗传组学与计算生物", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 32.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1548-7091", + "eissn": "1548-7105", + "jcr_disciplines": [ + "BIOCHEMICAL RESEARCH METHODS(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1550-4131", + "lang": "en", + "name": "Cell Metabolism", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 30.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1550-4131", + "eissn": "1932-7420", + "jcr_disciplines": [ + "CELL BIOLOGY(SCIE)", + "ENDOCRINOLOGY & METABOLISM(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1061-4036", + "lang": "en", + "name": "NATURE GENETICS", + "research_direction": "遗传组学与计算生物", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 29.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1061-4036", + "eissn": "1546-1718", + "jcr_disciplines": [ + "GENETICS & HEREDITY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-cancer", + "lang": "en", + "name": "Nature Cancer", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 28.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2662-1347", + "jcr_disciplines": [ + "ONCOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1529-2908", + "lang": "en", + "name": "NATURE IMMUNOLOGY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 27.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1529-2908", + "eissn": "1529-2916", + "jcr_disciplines": [ + "IMMUNOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2470-9476", + "lang": "en", + "name": "Science Robotics", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 27.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Science / AAAS", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2470-9476", + "eissn": "2470-9476", + "jcr_disciplines": [ + "ROBOTICS(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1758-678X", + "lang": "en", + "name": "Nature Climate Change", + "research_direction": "生态环境与保护", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 27.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1758-678X", + "eissn": "1758-6798", + "jcr_disciplines": [ + "ENVIRONMENTAL SCIENCES(SCIE)", + "ENVIRONMENTAL STUDIES(SSCI)", + "METEOROLOGY & ATMOSPHERIC SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2398-9629", + "lang": "en", + "name": "Nature Sustainability", + "research_direction": "生态环境与保护", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 27.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2398-9629", + "eissn": "2398-9629", + "jcr_disciplines": [ + "ENVIRONMENTAL SCIENCES(SCIE)", + "ENVIRONMENTAL STUDIES(SSCI)", + "GREEN & SUSTAINABLE SCIENCE & TECHNOLOGY(SSCI)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2157-846X", + "lang": "en", + "name": "Nature Biomedical Engineering", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 26.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2157-846X", + "eissn": "2157-846X", + "jcr_disciplines": [ + "ENGINEERING, BIOMEDICAL(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1471-003X", + "lang": "en", + "name": "NATURE REVIEWS NEUROSCIENCE", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 26.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1471-003X", + "eissn": "1471-0048", + "jcr_disciplines": [ + "NEUROSCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1543-5008", + "lang": "en", + "name": "Annual Review of Plant Biology", + "research_direction": "植物科学与分子育种", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 26.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1543-5008", + "eissn": "1545-2123", + "jcr_disciplines": [ + "PLANT SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1074-7613", + "lang": "en", + "name": "Immunity", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 26.3, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1074-7613", + "eissn": "1097-4180", + "jcr_disciplines": [ + "IMMUNOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1001-0602", + "lang": "en", + "name": "CELL RESEARCH", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 25.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1001-0602", + "eissn": "1748-7838", + "jcr_disciplines": [ + "CELL BIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2666-6758", + "lang": "en", + "name": "Innovation", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 25.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2666-6758", + "eissn": "2666-6758", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(ESCI)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1560-2745", + "lang": "en", + "name": "FUNGAL DIVERSITY", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 24.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1560-2745", + "eissn": "1878-9129", + "jcr_disciplines": [ + "MYCOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1674-2052", + "lang": "en", + "name": "Molecular Plant", + "research_direction": "植物科学与分子育种", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 24.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1674-2052", + "eissn": "1752-9867", + "jcr_disciplines": [ + "BIOCHEMISTRY & MOLECULAR BIOLOGY(SCIE)", + "PLANT SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-food", + "lang": "en", + "name": "Nature Food", + "research_direction": "食品营养与安全", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 21.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2662-1355", + "jcr_disciplines": [ + "FOOD SCIENCE & TECHNOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2095-9273", + "lang": "en", + "name": "Science Bulletin", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 21.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2095-9273", + "eissn": "2095-9281", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1360-1385", + "lang": "en", + "name": "TRENDS IN PLANT SCIENCE", + "research_direction": "植物科学与分子育种", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 20.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "1360-1385", + "eissn": "1878-4372", + "jcr_disciplines": [ + "PLANT SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-metabolism", + "lang": "en", + "name": "Nature Metabolism", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 20.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2522-5812", + "jcr_disciplines": [ + "ENDOCRINOLOGY & METABOLISM(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1934-5909", + "lang": "en", + "name": "Cell Stem Cell", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 20.4, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1934-5909", + "eissn": "1875-9777", + "jcr_disciplines": [ + "CELL & TISSUE ENGINEERING(SCIE)", + "CELL BIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1097-6256", + "lang": "en", + "name": "NATURE NEUROSCIENCE", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 20.0, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1097-6256", + "eissn": "1546-1726", + "jcr_disciplines": [ + "NEUROSCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:0165-6147", + "lang": "en", + "name": "TRENDS IN PHARMACOLOGICAL SCIENCES", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 19.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "综述为主", + "issn": "0165-6147", + "eissn": "1873-3735", + "jcr_disciplines": [ + "PHARMACOLOGY & PHARMACY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2451-9294", + "lang": "en", + "name": "Chem", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 19.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2451-9294", + "eissn": "2451-9294", + "jcr_disciplines": [ + "CHEMISTRY, MULTIDISCIPLINARY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1465-7392", + "lang": "en", + "name": "NATURE CELL BIOLOGY", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 19.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1465-7392", + "eissn": "1476-4679", + "jcr_disciplines": [ + "CELL BIOLOGY(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-aging", + "lang": "en", + "name": "Nature Aging", + "research_direction": "细胞分子发育与生理", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 19.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2662-8465", + "jcr_disciplines": [ + "CELL BIOLOGY(SCIE)", + "GERIATRICS & GERONTOLOGY(SCIE)", + "NEUROSCIENCES(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2058-5276", + "lang": "en", + "name": "Nature Microbiology", + "research_direction": "微生物真菌与生物技术", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 19.4, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2058-5276", + "eissn": "2058-5276", + "jcr_disciplines": [ + "MICROBIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + } + ], + "meta": { + "total": 233, + "page": 1, + "size": 50, + "lang": "en", + "domain": "", + "cas_partition": "1区", + "q": "", + "domains": [ + "细胞分子发育与生理", + "生态环境与保护", + "微生物真菌与生物技术", + "农学作物与种质", + "遗传组学与计算生物", + "植物科学与分子育种", + "水产渔业与海洋生物", + "食品营养与安全", + "植物保护与昆虫", + "畜牧动物营养与繁殖", + "土壤肥料与地球生物化学", + "林业木材与草业", + "兽医与寄生虫", + "综合与交叉", + "园艺果树与采后" + ], + "data_source_note": "分区:2025年中科院公开表(official);JIF:2024 JCR,由2025版JCR发布(official);整理日期2026-10-10。空白=来源未给值≠0;研究方向/期刊标记/文章类型为导航标签,非官方评级。", + "data_imported": true + }, + "error": null +} \ No newline at end of file diff --git a/review_service/data/journals/smoke/5_domain.json b/review_service/data/journals/smoke/5_domain.json new file mode 100644 index 0000000..6e738a6 --- /dev/null +++ b/review_service/data/journals/smoke/5_domain.json @@ -0,0 +1,815 @@ +{ + "ok": true, + "items": [ + { + "id": "en:0028-0836", + "lang": "en", + "name": "NATURE", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 48.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "经典专业刊", + "article_type": "研究/方法/综合", + "issn": "0028-0836", + "eissn": "1476-4687", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:0036-8075", + "lang": "en", + "name": "SCIENCE", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 45.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Science / AAAS", + "journal_mark": "经典专业刊", + "article_type": "研究/方法/综合", + "issn": "0036-8075", + "eissn": "1095-9203", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:0092-8674", + "lang": "en", + "name": "CELL", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 42.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "经典专业刊", + "article_type": "研究/方法/综合", + "issn": "0092-8674", + "eissn": "1097-4172", + "jcr_disciplines": [ + "BIOCHEMISTRY & MOLECULAR BIOLOGY(SCIE)", + "CELL BIOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2666-6758", + "lang": "en", + "name": "Innovation", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 25.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2666-6758", + "eissn": "2666-6758", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(ESCI)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2095-9273", + "lang": "en", + "name": "Science Bulletin", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 21.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2095-9273", + "eissn": "2095-9281", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2095-5138", + "lang": "en", + "name": "National Science Review", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 17.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2095-5138", + "eissn": "2053-714X", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:nature-communications", + "lang": "en", + "name": "Nature Communications", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 15.7, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2041-1723", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:advanced-science", + "lang": "en", + "name": "Advanced Science", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 14.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2198-3844", + "jcr_disciplines": [ + "CHEMISTRY, MULTIDISCIPLINARY(SCIE)", + "MATERIALS SCIENCE, MULTIDISCIPLINARY(SCIE)", + "NANOSCIENCE & NANOTECHNOLOGY(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2375-2548", + "lang": "en", + "name": "Science Advances", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 12.5, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Science / AAAS", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2375-2548", + "eissn": "2375-2548", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2096-5168", + "lang": "en", + "name": "Research", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 10.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已按Clarivate勘误更新", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "Science Partner Journals(合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2096-5168", + "eissn": "2639-5274", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": "2024 JIF采用2025-10-15官方重载修订值。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://journalcitationreports.zendesk.com/hc/en-gb/articles/36310787349521-2025", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:0027-8424", + "lang": "en", + "name": "PROCEEDINGS OF THE NATIONAL ACADEMY OF SCIENCES OF THE UNITED STATES OF AMERICA", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 9.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "经典专业刊", + "article_type": "研究/方法/综合", + "issn": "0027-8424", + "eissn": "1091-6490", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:scientific-data", + "lang": "en", + "name": "Scientific Data", + "research_direction": "综合与交叉", + "cas_partition": "2区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 6.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "否", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2052-4463", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:iscience", + "lang": "en", + "name": "iScience", + "research_direction": "综合与交叉", + "cas_partition": "2区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 4.1, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "否", + "publisher_series": "Cell Press(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2589-0042", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2047-217X", + "lang": "en", + "name": "GigaScience", + "research_direction": "综合与交叉", + "cas_partition": "2区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 3.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "否", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2047-217X", + "eissn": "2047-217X", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2045-2322", + "lang": "en", + "name": "Scientific Reports", + "research_direction": "综合与交叉", + "cas_partition": "3区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 3.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "否", + "publisher_series": "Nature Portfolio(含合作刊)", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2045-2322", + "eissn": "2045-2322", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:pnas-nexus", + "lang": "en", + "name": "PNAS Nexus", + "research_direction": "综合与交叉", + "cas_partition": "3区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 3.8, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "否", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2752-6542", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(ESCI)", + "SOCIAL SCIENCES, INTERDISCIPLINARY(ESCI)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:heliyon", + "lang": "en", + "name": "Heliyon", + "research_direction": "综合与交叉", + "cas_partition": "4区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 3.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "否", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": null, + "eissn": "2405-8440", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2054-5703", + "lang": "en", + "name": "Royal Society Open Science", + "research_direction": "综合与交叉", + "cas_partition": "3区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 2.9, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "否", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2054-5703", + "eissn": "2054-5703", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:1932-6203", + "lang": "en", + "name": "PLoS One", + "research_direction": "综合与交叉", + "cas_partition": "3区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 2.6, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "否", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "1932-6203", + "eissn": "1932-6203", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2167-8359", + "lang": "en", + "name": "PeerJ", + "research_direction": "综合与交叉", + "cas_partition": "3区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": 2.4, + "jif_year": 2024, + "jif_note": null, + "jif_check_status": "已匹配公开汇编", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "否", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2167-8359", + "eissn": "2167-8359", + "jcr_disciplines": [ + "MULTIDISCIPLINARY SCIENCES(SCIE)" + ], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": "official", + "jif_source_url": "https://github.com/yongqianxiao/share_repo/blob/master/JCR/2024JCR%E5%AE%8C%E6%95%B4%E7%89%88%EF%BC%882025.6.18%E5%8F%91%E5%B8%83%EF%BC%89.xlsx", + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + }, + { + "id": "en:2050-084X", + "lang": "en", + "name": "eLife", + "research_direction": "综合与交叉", + "cas_partition": "1区", + "cas_partition_note": null, + "cas_partition_year": 2025, + "jif": null, + "jif_year": 2024, + "jif_note": "未被2024 JCR收录", + "jif_check_status": "源表标N/A", + "composite_impact_factor": null, + "comprehensive_impact_factor": null, + "metric_year": null, + "metric_report_year": null, + "metric_caliber": null, + "annual_report_page": null, + "top_flag": "是", + "publisher_series": "其他", + "journal_mark": "领域期刊/新兴刊", + "article_type": "研究/方法/综合", + "issn": "2050-084X", + "eissn": "2050-084X", + "jcr_disciplines": [ + "BIOLOGY(ESCI)" + ], + "supplement_note": "源表2024 JIF为N/A;不可用历史IF代填。", + "evidence_note": null, + "official_url": null, + "partition_source": "official", + "jif_source": null, + "jif_source_url": null, + "partition_source_url": "https://huaxue.hebtu.edu.cn/a/2025/09/23/A5A5BBD96F6B4410B87B6D4C43BDFD63.html", + "data_source_label": "JIF来源", + "data_source_url": null + } + ], + "meta": { + "total": 21, + "page": 1, + "size": 50, + "lang": "en", + "domain": "综合与交叉", + "cas_partition": "", + "q": "", + "domains": [ + "细胞分子发育与生理", + "生态环境与保护", + "微生物真菌与生物技术", + "农学作物与种质", + "遗传组学与计算生物", + "植物科学与分子育种", + "水产渔业与海洋生物", + "食品营养与安全", + "植物保护与昆虫", + "畜牧动物营养与繁殖", + "土壤肥料与地球生物化学", + "林业木材与草业", + "兽医与寄生虫", + "综合与交叉", + "园艺果树与采后" + ], + "data_source_note": "分区:2025年中科院公开表(official);JIF:2024 JCR,由2025版JCR发布(official);整理日期2026-10-10。空白=来源未给值≠0;研究方向/期刊标记/文章类型为导航标签,非官方评级。", + "data_imported": true + }, + "error": null +} \ No newline at end of file diff --git a/review_service/data/journals/smoke/6_zh_composite_desc.json b/review_service/data/journals/smoke/6_zh_composite_desc.json new file mode 100644 index 0000000..e6c6576 --- /dev/null +++ b/review_service/data/journals/smoke/6_zh_composite_desc.json @@ -0,0 +1,1779 @@ +{ + "ok": true, + "items": [ + { + "id": "zh:自然资源学报", + "lang": "zh", + "name": "自然资源学报", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 10.773, + "comprehensive_impact_factor": 7.725, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:地理学报", + "lang": "zh", + "name": "地理学报", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 9.926, + "comprehensive_impact_factor": 7.412, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:中国人口-资源与环境", + "lang": "zh", + "name": "中国人口·资源与环境", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 9.53, + "comprehensive_impact_factor": 6.957, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 154, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=154" + }, + { + "id": "zh:地理研究", + "lang": "zh", + "name": "地理研究", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 7.661, + "comprehensive_impact_factor": 5.5, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:资源科学", + "lang": "zh", + "name": "资源科学", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 6.731, + "comprehensive_impact_factor": 4.962, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:地理科学", + "lang": "zh", + "name": "地理科学", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 6.614, + "comprehensive_impact_factor": 4.698, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:地理科学进展", + "lang": "zh", + "name": "地理科学进展", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 6.513, + "comprehensive_impact_factor": 4.532, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:生态学报", + "lang": "zh", + "name": "生态学报", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 6.473, + "comprehensive_impact_factor": 4.412, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:土壤学报", + "lang": "zh", + "name": "土壤学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 6.361, + "comprehensive_impact_factor": 4.262, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:环境科学", + "lang": "zh", + "name": "环境科学", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 6.137, + "comprehensive_impact_factor": 4.34, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 154, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=154" + }, + { + "id": "zh:长江流域资源与环境", + "lang": "zh", + "name": "长江流域资源与环境", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 5.364, + "comprehensive_impact_factor": 3.609, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 154, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=154" + }, + { + "id": "zh:应用生态学报", + "lang": "zh", + "name": "应用生态学报", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 5.047, + "comprehensive_impact_factor": 3.296, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:中国生态农业学报-中英文", + "lang": "zh", + "name": "中国生态农业学报(中英文)", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 5.034, + "comprehensive_impact_factor": 3.311, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:环境科学研究", + "lang": "zh", + "name": "环境科学研究", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.848, + "comprehensive_impact_factor": 3.716, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 155, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=155" + }, + { + "id": "zh:农业现代化研究", + "lang": "zh", + "name": "农业现代化研究", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.842, + "comprehensive_impact_factor": 3.032, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 87, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=87" + }, + { + "id": "zh:遥感学报", + "lang": "zh", + "name": "遥感学报", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.799, + "comprehensive_impact_factor": 3.257, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 44, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=44" + }, + { + "id": "zh:农业机械学报", + "lang": "zh", + "name": "农业机械学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.696, + "comprehensive_impact_factor": 3.037, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:水土保持研究", + "lang": "zh", + "name": "水土保持研究", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.651, + "comprehensive_impact_factor": 3.002, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:植物营养与肥料学报", + "lang": "zh", + "name": "植物营养与肥料学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.634, + "comprehensive_impact_factor": 3.17, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:农业资源与环境学报", + "lang": "zh", + "name": "农业资源与环境学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.531, + "comprehensive_impact_factor": 2.88, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 87, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=87" + }, + { + "id": "zh:生态学杂志", + "lang": "zh", + "name": "生态学杂志", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.444, + "comprehensive_impact_factor": 2.907, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:草业学报", + "lang": "zh", + "name": "草业学报", + "research_direction": "林学木材与草业", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.361, + "comprehensive_impact_factor": 2.903, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 96, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=96" + }, + { + "id": "zh:水土保持学报", + "lang": "zh", + "name": "水土保持学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.35, + "comprehensive_impact_factor": 2.863, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:植物生态学报", + "lang": "zh", + "name": "植物生态学报", + "research_direction": "综合与生命科学", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.325, + "comprehensive_impact_factor": 3.063, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:干旱区研究", + "lang": "zh", + "name": "干旱区研究", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.234, + "comprehensive_impact_factor": 3.019, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 46, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=46" + }, + { + "id": "zh:湖泊科学", + "lang": "zh", + "name": "湖泊科学", + "research_direction": "水产渔业与海洋生物", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.222, + "comprehensive_impact_factor": 3.009, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 146, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=146" + }, + { + "id": "zh:农业工程学报", + "lang": "zh", + "name": "农业工程学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.125, + "comprehensive_impact_factor": 3.04, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:干旱区地理", + "lang": "zh", + "name": "干旱区地理", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.03, + "comprehensive_impact_factor": 2.699, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:中国水稻科学", + "lang": "zh", + "name": "中国水稻科学", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.024, + "comprehensive_impact_factor": 2.887, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 91, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=91" + }, + { + "id": "zh:草地学报", + "lang": "zh", + "name": "草地学报", + "research_direction": "林学木材与草业", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.007, + "comprehensive_impact_factor": 2.893, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 96, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=96" + }, + { + "id": "zh:食品科学", + "lang": "zh", + "name": "食品科学", + "research_direction": "食品科学营养与安全", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 4.002, + "comprehensive_impact_factor": 2.806, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 138, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=138" + }, + { + "id": "zh:作物学报", + "lang": "zh", + "name": "作物学报", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.968, + "comprehensive_impact_factor": 2.735, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 91, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=91" + }, + { + "id": "zh:中国草地学报", + "lang": "zh", + "name": "中国草地学报", + "research_direction": "林学木材与草业", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.915, + "comprehensive_impact_factor": 2.805, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 96, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=96" + }, + { + "id": "zh:土壤通报", + "lang": "zh", + "name": "土壤通报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.849, + "comprehensive_impact_factor": 2.571, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:中国农业科学", + "lang": "zh", + "name": "中国农业科学", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.804, + "comprehensive_impact_factor": 2.673, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 87, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=87" + }, + { + "id": "zh:中国环境科学", + "lang": "zh", + "name": "中国环境科学", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.741, + "comprehensive_impact_factor": 2.694, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 155, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=155" + }, + { + "id": "zh:生态环境学报", + "lang": "zh", + "name": "生态环境学报", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.668, + "comprehensive_impact_factor": 2.693, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:中国沙漠", + "lang": "zh", + "name": "中国沙漠", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.639, + "comprehensive_impact_factor": 2.611, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 51, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=51" + }, + { + "id": "zh:中南林业科技大学学报", + "lang": "zh", + "name": "中南林业科技大学学报", + "research_direction": "林学木材与草业", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.594, + "comprehensive_impact_factor": 2.56, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 94, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=94" + }, + { + "id": "zh:中国科学-生命科学", + "lang": "zh", + "name": "中国科学:生命科学", + "research_direction": "综合与生命科学", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.488, + "comprehensive_impact_factor": 2.236, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:中国农业大学学报", + "lang": "zh", + "name": "中国农业大学学报", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.478, + "comprehensive_impact_factor": 2.188, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 87, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=87" + }, + { + "id": "zh:生物多样性", + "lang": "zh", + "name": "生物多样性", + "research_direction": "综合与生命科学", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.451, + "comprehensive_impact_factor": 2.646, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:菌物学报", + "lang": "zh", + "name": "菌物学报", + "research_direction": "综合与生命科学", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.392, + "comprehensive_impact_factor": 2.697, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 52, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=52" + }, + { + "id": "zh:中国农业气象", + "lang": "zh", + "name": "中国农业气象", + "research_direction": "农学作物与种质", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.355, + "comprehensive_impact_factor": 2.541, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:动物营养学报", + "lang": "zh", + "name": "动物营养学报", + "research_direction": "畜牧兽医与动物营养", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.352, + "comprehensive_impact_factor": 2.429, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 96, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=96" + }, + { + "id": "zh:土壤", + "lang": "zh", + "name": "土壤", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.351, + "comprehensive_impact_factor": 2.372, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + }, + { + "id": "zh:林产工业", + "lang": "zh", + "name": "林产工业", + "research_direction": "林学木材与草业", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.319, + "comprehensive_impact_factor": 2.901, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 140, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=140" + }, + { + "id": "zh:农业环境科学学报", + "lang": "zh", + "name": "农业环境科学学报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.316, + "comprehensive_impact_factor": 2.25, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 155, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=155" + }, + { + "id": "zh:环境保护", + "lang": "zh", + "name": "环境保护", + "research_direction": "生态环境与自然资源", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.296, + "comprehensive_impact_factor": 2.218, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 155, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=155" + }, + { + "id": "zh:水土保持通报", + "lang": "zh", + "name": "水土保持通报", + "research_direction": "土壤肥料与农业环境", + "cas_partition": null, + "cas_partition_note": "不按中科院分区口径列示", + "cas_partition_year": null, + "jif": null, + "jif_year": null, + "jif_note": null, + "jif_check_status": "已提取原表", + "composite_impact_factor": 3.17, + "comprehensive_impact_factor": 2.225, + "metric_year": 2023, + "metric_report_year": 2024, + "metric_caliber": "国内年报口径;不与JIF混排", + "annual_report_page": 90, + "top_flag": null, + "publisher_series": null, + "journal_mark": null, + "article_type": null, + "issn": null, + "eissn": null, + "jcr_disciplines": [], + "supplement_note": null, + "evidence_note": null, + "official_url": null, + "partition_source": null, + "jif_source": "official", + "jif_source_url": null, + "partition_source_url": null, + "data_source_label": "年报原页", + "data_source_url": "https://library.sut.edu.cn/WJSC/xkfw/tgzn/sjkslqklb/zhongguoxueshuqikanyingxiangyinzinianbao-zirankexue-2024.pdf#page=90" + } + ], + "meta": { + "total": 277, + "page": 1, + "size": 50, + "lang": "zh", + "domain": "", + "cas_partition": "", + "q": "", + "domains": [ + "农学作物与种质", + "生态环境与自然资源", + "综合与生命科学", + "畜牧兽医与动物营养", + "食品科学营养与安全", + "水产渔业与海洋生物", + "土壤肥料与农业环境", + "林学木材与草业", + "园艺果树与茶学", + "植物保护与昆虫" + ], + "data_source_note": "指标:国内自然科学期刊年报2024版(统计年2023,official,含复合/综合IF两口径);中文期刊不按中科院分区口径列示;国内IF与JIF统计源不同,不可混排。", + "data_imported": true + }, + "error": null +} \ No newline at end of file diff --git a/review_service/data/journals/smoke/7_size500.json b/review_service/data/journals/smoke/7_size500.json new file mode 100644 index 0000000..e425f2b --- /dev/null +++ b/review_service/data/journals/smoke/7_size500.json @@ -0,0 +1,10 @@ +{ + "ok": false, + "items": [], + "meta": null, + "error": { + "code": "VALIDATION", + "message": "size 必须在 1-200,收到 500", + "degraded": false + } +} \ No newline at end of file diff --git a/review_service/data/journals/smoke/8_lang_xx.json b/review_service/data/journals/smoke/8_lang_xx.json new file mode 100644 index 0000000..be5e3a9 --- /dev/null +++ b/review_service/data/journals/smoke/8_lang_xx.json @@ -0,0 +1,10 @@ +{ + "ok": false, + "items": [], + "meta": null, + "error": { + "code": "VALIDATION", + "message": "不支持的 lang='xx',可选:en / zh", + "degraded": false + } +} \ No newline at end of file diff --git a/review_service/data/journals/source.xlsx b/review_service/data/journals/source.xlsx new file mode 100644 index 0000000..d40050c Binary files /dev/null and b/review_service/data/journals/source.xlsx differ diff --git a/review_service/data/journals/source_v4.xlsx b/review_service/data/journals/source_v4.xlsx new file mode 100644 index 0000000..070cfd1 Binary files /dev/null and b/review_service/data/journals/source_v4.xlsx differ diff --git a/review_service/pytest.ini b/review_service/pytest.ini new file mode 100644 index 0000000..1f69640 --- /dev/null +++ b/review_service/pytest.ini @@ -0,0 +1,6 @@ +[pytest] +python_files = test_*.py +pythonpath = . +markers = + review_unit: 审稿服务单元测试 +asyncio_mode = auto diff --git a/review_service/restart.sh b/review_service/restart.sh new file mode 100755 index 0000000..80b522d --- /dev/null +++ b/review_service/restart.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# restart.sh —— REVIEW 服务重启脚本(8100;不触碰生产服务 8090/8091/8092/8093/8094/8097/8098)。 +# 用法: restart.sh [python] [port] +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# 默认 venv:本机统一 venv 固定路径(原先 $REPO_ROOT/../ 推导在本工作区不存在) +PYTHON="${1:-/home/xzq/5090/teamWorkspace/zh/plantai-rag-new-venv/bin/python}" +PORT="${2:-8100}" +HOST="${REVIEW_BIND_HOST:-127.0.0.1}" + +[[ -x "$PYTHON" ]] || { echo "Python not found: $PYTHON" >&2; exit 2; } + +APP_MODULE="app.main:app" +if command -v lsof >/dev/null 2>&1; then + PID="$(lsof -ti tcp:"$PORT" -sTCP:LISTEN 2>/dev/null || true)" + if [[ -n "$PID" ]]; then + echo "[restart] 停止 $PORT 旧进程 pid=$PID" + kill $PID 2>/dev/null || true + sleep 2 + fi +fi + +cd "$SCRIPT_DIR" +# 加载运行时配置(.env 不入 git):services/llm.py 直接读 REVIEW_LLM_*/DOCGEN_LLM_* +# 裸键,paper_parse.py 读 REVIEW_*——需 set -a 显式导出(同 paper_writer_service 先例)。 +set -a +[ -f .env ] && source .env +set +a +echo "[restart] 启动审稿服务 :$PORT($PYTHON)" +nohup "$PYTHON" -m uvicorn "$APP_MODULE" --host "$HOST" --port "$PORT" \ + > "$SCRIPT_DIR/review.log" 2>&1 & +echo "[restart] 完成;日志 review_service/review.log" diff --git a/review_service/scripts/README.md b/review_service/scripts/README.md new file mode 100644 index 0000000..c1f8d81 --- /dev/null +++ b/review_service/scripts/README.md @@ -0,0 +1,17 @@ +# scripts/ —— 离线工具(不被 app/ 服务代码引用,独立 CLI) + +## fetch_format_rules.py —— 投稿指南自动抓取(探索性,第一批) + +- 依赖:venv 已装的 httpx + beautifulsoup4 4.15.0(用户拍板 2026-10-10); + 解析器 lxml 6.1.2 在 `tooling/requirements.lock` 内。 +- 用法与流程见 `fetch_format_rules.py` 模块 docstring(CLI 一次一本期刊)。 +- 产物:`data/format_cache/{journal_id}.json`(运行产物,已 gitignore,不入库)。 + +### 现状(2026-10-10) + +OUP / Wiley / Cell 官网对本运行环境返回 403,自动抓取路线失败; +Genome Biology / BMC Plant Biology / Frontiers / Rice 可抓但 LLM 抽取结果 +仍需人工对照官网。当前 `journals.json` 中 5 本精选期刊的 `format_rules` +为**人工核验官网原文后写入**(`rules_source=official` + `source_url` + +`last_verified`),**不是**本脚本产物。本工具保留作为后续换网络环境 / +换可达站点后的重跑手段。 diff --git a/review_service/scripts/fetch_format_rules.py b/review_service/scripts/fetch_format_rules.py new file mode 100644 index 0000000..4b5dd3a --- /dev/null +++ b/review_service/scripts/fetch_format_rules.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +"""scripts/fetch_format_rules.py —— 格式规则自动获取(第一批,人工核验用 CLI)。 + +用法(在 review_service/ 下): + /home/xzq/5090/teamWorkspace/zh/plantai-rag-new-venv/bin/python \ + scripts/fetch_format_rules.py + +流程: + 1. fetch_submission_guidelines(url) # robots.txt + 同域 ≥2s 限速 + 正文转 Markdown + 2. extract_format_rules(markdown, journal_name) # DeepSeek 抽取(llm.py) + 3. 存 data/format_cache/{journal_id}.json(失败也存,便于批量对账) + 4. 打印完整结果 JSON 供人工核验 + +凭证:结果文件顶层 source_url(步骤 1 的实际抓取地址)+ source_quotes(LLM +逐字引证,按字段分组);非 null 字段缺引证 → 抽取判失败(ok=false)。 + +约束(第一批):只跑指定 3 本;不触 API / 前端 / journals.json(format_rules 只读 +查名,不写回)。journal_name 优先取 data/journals/journals.json 的 name(只读)。 +""" +from __future__ import annotations + +import asyncio +import json +import os +import re +import sys +from datetime import datetime, timezone +from pathlib import Path + +_ROOT = Path(__file__).resolve().parents[1] # review_service/ +sys.path.insert(0, str(_ROOT)) + +_JOURNALS_JSON = _ROOT / "data" / "journals" / "journals.json" +_CACHE_DIR = _ROOT / "data" / "format_cache" + + +def _load_env() -> None: + """镜像 restart.sh 的 `set -a; source .env`:REVIEW_LLM_*/DOCGEN_LLM_* 裸键 + 由 services/llm.py 在每次调用时读 os.environ(不缓存),故调用前灌入即可。""" + env_path = _ROOT / ".env" + if not env_path.is_file(): + return + for raw in env_path.read_text("utf-8").splitlines(): + line = raw.strip() + if not line or line.startswith("#") or "=" not in line: + continue + if line.startswith("export "): + line = line[7:].strip() + key, _, val = line.partition("=") + os.environ.setdefault(key.strip(), val.strip().strip("\"'")) + + +def _journal_name(journal_id: str) -> str: + """journals.json 只读查名;查不到 → id 连字符转空格并首字母大写(LLM 上下文可读)。""" + try: + data = json.loads(_JOURNALS_JSON.read_text("utf-8")) + for j in data.get("journals") or []: + if j.get("id") == journal_id: + return str(j.get("name") or journal_id) + except Exception: # noqa: BLE001 + pass + return journal_id.replace("-", " ").title() + + +def main() -> int: + if len(sys.argv) != 3: + print("用法: fetch_format_rules.py ", file=sys.stderr) + return 2 + journal_id = re.sub(r"[^\w.-]", "_", sys.argv[1].strip()) + url = sys.argv[2].strip() + _load_env() + + from app.services.format_extractor import extract_format_rules + from app.services.format_fetcher import fetch_submission_guidelines + + async def run() -> tuple[dict, dict]: + fetched = await fetch_submission_guidelines(url) + print(f"[1/2] 抓取 {url} → ok={fetched['ok']}" + + (f",markdown={len(fetched['markdown'])} 字符" + if fetched["ok"] else f",error={fetched['error']}")) + if not fetched["ok"]: + return fetched, {"ok": False, "error": f"抓取失败:{fetched['error']}", + "rules": None, "source_quotes": None, + "confidence": None, "notes": None, "raw": None} + extracted = await extract_format_rules(fetched["markdown"], _journal_name(journal_id)) + if extracted["ok"]: + filled = sum(1 for v in extracted["rules"].values() if v is not None) + print(f"[2/2] LLM 抽取 → ok=True,8 字段中 {filled} 个非 null") + else: + print(f"[2/2] LLM 抽取 → ok=False,error={extracted['error']}") + return fetched, extracted + + fetched, extracted = asyncio.run(run()) + + result = { + "journal_id": journal_id, + "journal_name": _journal_name(journal_id), + "source_url": url, + "fetched_at": fetched.get("fetched_at"), + "extracted_at": datetime.now(timezone.utc).isoformat(timespec="seconds"), + "markdown_chars": len(fetched.get("markdown") or ""), + "ok": bool(extracted.get("ok")), + "error": extracted.get("error"), + "format_rules": ({**extracted["rules"], "rules_source": "fetched"} + if extracted.get("ok") else None), + "source_quotes": extracted.get("source_quotes"), + "confidence": extracted.get("confidence"), + "notes": extracted.get("notes"), + "raw_llm": extracted.get("raw"), + } + _CACHE_DIR.mkdir(parents=True, exist_ok=True) + out_path = _CACHE_DIR / f"{journal_id}.json" + out_path.write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", "utf-8") + + print(f"[save] {out_path.relative_to(_ROOT)}") + print("===== 完整结果(人工核验)=====") + print(json.dumps(result, ensure_ascii=False, indent=2)) + return 0 if result["ok"] else 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/review_service/scripts/import_journals.py b/review_service/scripts/import_journals.py new file mode 100644 index 0000000..aa1f980 --- /dev/null +++ b/review_service/scripts/import_journals.py @@ -0,0 +1,579 @@ +#!/usr/bin/env python3 +"""scripts/import_journals.py —— 期刊目录导入(source_v4.xlsx → SQLite journal_directory)。 + +数据流(本脚本独立拥有 journal_directory 表的 schema,app 层只读不建表): + openpyxl 非 read_only 加载(需要读 cell.hyperlink.target 来源链接) + → 「国际期刊」「中文期刊」两 sheet 按【列名】映射(不按索引,防列序漂移) + → 行级清洗(空→None 绝不填 0;分区数字→"N区";JCR学科→JSON 数组) + → 按 id 幂等 upsert(ON CONFLICT DO UPDATE,重跑 count 不变) + → 对账报告 data/journals/import_report.txt + +v4 源(2026-10-10):JIF=2025 统计年/2026 JCR 发布;中文 IF=2024 统计年/ +年报 2025 版;新增官网三列 + JCR发布年;JCR学科列改名「JCR学科(2024源表)」。 +旧文件 source.xlsx(v2)原样保留为回退点,勿覆盖。 + +schema 迁移(决策①,幂等 + 备份): + 既有表缺列 → PRAGMA table_info 探测后 ALTER TABLE ADD COLUMN,缺哪加哪、 + 重复跑不报错;跑前先 cp review.db review.db.bak-<日期>。 + 新增列:official_url / official_check_status / jcr_release_year。 + official_source 不入库(值全为字面量"官网来源",超链接=官网本身,无信息量)。 + +id 策略(拍板-补充1): + 有 ISSN → "{lang}:{ISSN原样(strip)}"(如 en:0028-0836) + 无 ISSN → "{lang}:{slug(name)}"(casefold + 非词字符折叠为连字符,保留 CJK) + 同 lang 内 id 冲突 → 报告冲突列表并【中止导入】(非零退出,不写库)。 + +"未检得"/空白 区分(拍板-补充2): + 分区空白 → cas_partition=NULL, cas_partition_note=NULL(前端 "—") + 分区"未检得" → cas_partition=NULL, cas_partition_note="未检得"(前端 "— ⓘ") + JIF 空 → jif=NULL + jif_note=核对状态原文(如"2025 JIF未检得/未给值") + 官网空(3 本中文刊未检得)→ official_url=NULL(前端 "—",不生成 ) + + 官网列:v4 已含「官网网址」列(国际 779 + 中文 274),按列名自动映射 + official_url;同时映射 官网核对状态 → official_check_status、 + JCR发布年 → jcr_release_year(仅国际;中文表无此列 → NULL)。 + +禁区:不 import app.*(db.py / recommend / services 零触碰);只用 stdlib sqlite3 + openpyxl。 +用法:python scripts/import_journals.py (cwd 任意;路径按本文件位置推导) +退出码:0 成功;1 id 冲突中止;2 源数据行数与口径不符;3 结构/文件错误。 +""" +from __future__ import annotations + +import json +import os +import re +import sqlite3 +import sys +import time +import unicodedata +from collections import Counter +from datetime import datetime +from pathlib import Path +from typing import Any + +import openpyxl + +# ---- 路径(review_service/scripts/ → parents[1] = review_service)---- +ROOT = Path(__file__).resolve().parents[1] +SOURCE_XLSX = ROOT / "data" / "journals" / "source_v4.xlsx" # v4;v2=source.xlsx 保留回退 +REPORT_TXT = ROOT / "data" / "journals" / "import_report.txt" + +SHEET_INTL = "国际期刊" +SHEET_ZH = "中文期刊" +EXPECT_INTL = 779 # 口径 sheet 声明(v4 不变) +EXPECT_ZH = 277 + +# 官网列(v4 实际列名「官网网址」在首位;其余为历史/备用别名) +OFFICIAL_URL_HEADERS = ("官网网址", "官网", "官方网址", "期刊官网") +# JCR 学科列别名:v4 改名「JCR学科(2024源表)」,v2 为「JCR学科(源表)」 +JCR_DISCIPLINE_HEADERS = ("JCR学科(2024源表)", "JCR学科(源表)") + +# 既有表缺列时的幂等迁移(决策①:缺哪加哪,重复跑不报错) +MIGRATE_COLS = ( + ("official_url", "TEXT"), + ("official_check_status", "TEXT"), + ("jcr_release_year", "INTEGER"), +) + +SCHEMA_SQL = """ +CREATE TABLE IF NOT EXISTS journal_directory ( + id TEXT PRIMARY KEY, + lang TEXT NOT NULL, + name TEXT NOT NULL, + research_direction TEXT, + cas_partition TEXT, + cas_partition_note TEXT, + cas_partition_year INTEGER, + jif REAL, + jif_year INTEGER, + jif_note TEXT, + jif_check_status TEXT, + composite_impact_factor REAL, + comprehensive_impact_factor REAL, + metric_year INTEGER, + metric_report_year INTEGER, + metric_caliber TEXT, + annual_report_page INTEGER, + top_flag TEXT, + publisher_series TEXT, + journal_mark TEXT, + article_type TEXT, + issn TEXT, + eissn TEXT, + jcr_disciplines TEXT, + supplement_note TEXT, + evidence_note TEXT, + official_url TEXT, + official_check_status TEXT, + jcr_release_year INTEGER, + partition_source TEXT, + jif_source TEXT, + jif_source_url TEXT, + partition_source_url TEXT, + data_source_label TEXT, + data_source_url TEXT, + imported_at TEXT +); +CREATE INDEX IF NOT EXISTS idx_dir_lang_name ON journal_directory(lang, name); +CREATE INDEX IF NOT EXISTS idx_dir_lang_jif ON journal_directory(lang, jif); +CREATE INDEX IF NOT EXISTS idx_dir_lang_cif ON journal_directory(lang, composite_impact_factor); +CREATE INDEX IF NOT EXISTS idx_dir_lang_part ON journal_directory(lang, cas_partition); +CREATE INDEX IF NOT EXISTS idx_dir_lang_domain ON journal_directory(lang, research_direction); +""" + +# upsert 列序(除 id 外全部 ON CONFLICT DO UPDATE) +COLS = ( + "lang", "name", "research_direction", "cas_partition", "cas_partition_note", + "cas_partition_year", "jif", "jif_year", "jif_note", "jif_check_status", + "composite_impact_factor", "comprehensive_impact_factor", "metric_year", + "metric_report_year", "metric_caliber", "annual_report_page", "top_flag", + "publisher_series", "journal_mark", "article_type", "issn", "eissn", + "jcr_disciplines", "supplement_note", "evidence_note", "official_url", + "official_check_status", "jcr_release_year", + "partition_source", "jif_source", "jif_source_url", "partition_source_url", + "data_source_label", "data_source_url", "imported_at", +) +UPSERT_SQL = ( + "INSERT INTO journal_directory (id, " + ", ".join(COLS) + ") VALUES (" + + ", ".join("?" for _ in range(len(COLS) + 1)) + ") " + + "ON CONFLICT(id) DO UPDATE SET " + + ", ".join(f"{c}=excluded.{c}" for c in COLS) +) + + +def migrate(conn: sqlite3.Connection) -> tuple[list[str], list[str]]: + """幂等加列(决策①):PRAGMA 探测现有列,缺哪个 ALTER ADD 哪个。""" + existing = {r[1] for r in conn.execute("PRAGMA table_info(journal_directory)")} + added: list[str] = [] + skipped: list[str] = [] + for col, decl in MIGRATE_COLS: + if col in existing: + skipped.append(col) + else: + conn.execute(f"ALTER TABLE journal_directory ADD COLUMN {col} {decl}") + added.append(col) + conn.commit() + return added, skipped + + +# ---- 清洗原语 ---- + +def text(v: Any) -> str | None: + """单元格 → strip 后的文本;空/纯空白 → None(绝不填 0/空串)。""" + if v is None: + return None + s = str(v).strip() + return s or None + + +def to_float(v: Any) -> float | None: + if v is None or (isinstance(v, str) and not v.strip()): + return None + try: + return float(v) + except (TypeError, ValueError): + return None + + +def to_int(v: Any) -> int | None: + f = to_float(v) + if f is None: + return None + return int(f) + + +def slugify(name: str) -> str: + """小写 + 非词字符折叠为连字符;\\w 含 CJK(中文期刊无 ISSN 时的 id 兜底)。""" + s = unicodedata.normalize("NFC", name.strip().casefold()) + s = re.sub(r"[^\w]+", "-", s, flags=re.UNICODE) + s = re.sub(r"-{2,}", "-", s) + return s.strip("-") + + +def make_id(lang: str, name: str, issn: str | None) -> str: + if issn: + return f"{lang}:{issn}" + return f"{lang}:{slugify(name)}" + + +def parse_partition(raw: Any) -> tuple[str | None, str | None]: + """分区 → (cas_partition, note)。数字 1-4 → 'N区';'未检得' → note;空白 → 双 None。""" + if raw is None: + return None, None + if isinstance(raw, (int, float)) and not isinstance(raw, bool): + n = int(raw) + if 1 <= n <= 4: + return f"{n}区", None + return None, None + s = str(raw).strip() + if not s: + return None, None + if "未检得" in s: + return None, "未检得" + m = re.fullmatch(r"([1-4])\s*区?", s) + if m: + return f"{m.group(1)}区", None + return s, None # 未知文本:原样保留(不丢信息) + + +def split_disciplines(raw: Any) -> str | None: + """'A(SCIE);B(SCIE)' → JSON 数组字符串。""" + s = text(raw) + if not s: + return None + parts = [p.strip() for p in s.split(";") if p.strip()] + return json.dumps(parts, ensure_ascii=False) if parts else None + + +def hyperlink_target(cell) -> str | None: + """超链接单元格 → target URL;无链接 → None(需要非 read_only 模式)。""" + try: + target = cell.hyperlink.target if cell.hyperlink is not None else None + except Exception: # noqa: BLE001 + return None + return text(target) + + +# ---- sheet 解析 ---- + +def header_index(ws) -> dict[str, int]: + headers = [text(c.value) for c in ws[1]] + return {h: i for i, h in enumerate(headers) if h is not None} + + +def read_intl(ws, imported_at: str, stats: dict) -> list[tuple]: + """国际期刊 sheet → 行元组(顺序同 COLS 前置 id)。""" + ix = header_index(ws) + for req in ("期刊名称", "研究方向", "中科院分区", "JIF影响因子"): + if req not in ix: + raise SystemExit(f"[结构错误] {SHEET_INTL} 缺列:{req}(实际列:{list(ix)})") + url_col = next((ix[h] for h in OFFICIAL_URL_HEADERS if h in ix), None) + jcr_hdr = next((h for h in JCR_DISCIPLINE_HEADERS if h in ix), None) + stats["official_url_detected"] = url_col is not None + if url_col is not None: + stats["official_url_headers"] = next(h for h in OFFICIAL_URL_HEADERS if h in ix) + + rows: list[tuple] = [] + for row in ws.iter_rows(min_row=2): + if not any(c.value is not None for c in row): + continue # 尾部幻影空行:不计入 skipped + name = text(row[ix["期刊名称"]].value) if ix["期刊名称"] < len(row) else None + if not name: + stats["skipped"] += 1 + continue + issn = text(row[ix["ISSN"]].value) if "ISSN" in ix else None + jif = to_float(row[ix["JIF影响因子"]].value) + check_status = text(row[ix["JIF核对状态"]].value) if "JIF核对状态" in ix else None + official_check = text(row[ix["官网核对状态"]].value) if "官网核对状态" in ix else None + jcr_year = to_int(row[ix["JCR发布年"]].value) if "JCR发布年" in ix else None + part, part_note = parse_partition(row[ix["中科院分区"]].value) + + # JIF 空 → note = 核对状态原文("未检得"/"源表标N/A" 等说明,拍板-补充2) + jif_note = check_status if jif is None else None + + jif_url = hyperlink_target(row[ix["JIF数据来源"]]) if "JIF数据来源" in ix else None + part_url = hyperlink_target(row[ix["分区数据来源"]]) if "分区数据来源" in ix else None + official = None + if url_col is not None and url_col < len(row): + official = text(row[url_col].value) or hyperlink_target(row[url_col]) + + rows.append(( + make_id("en", name, issn), "en", name, + text(row[ix["研究方向"]].value), + part, part_note, + to_int(row[ix["分区版本年"]].value) if "分区版本年" in ix else None, + jif, + to_int(row[ix["JIF统计年"]].value) if "JIF统计年" in ix else None, + jif_note, check_status, + None, None, None, None, None, None, + text(row[ix["Top(源表)"]].value) if "Top(源表)" in ix else None, + text(row[ix["出版系列"]].value) if "出版系列" in ix else None, + text(row[ix["期刊标记"]].value) if "期刊标记" in ix else None, + text(row[ix["文章类型"]].value) if "文章类型" in ix else None, + issn, + text(row[ix["eISSN"]].value) if "eISSN" in ix else None, + split_disciplines(row[ix[jcr_hdr]].value) if jcr_hdr else None, + text(row[ix["补充说明"]].value) if "补充说明" in ix else None, + text(row[ix["补充证据"]].value) if "补充证据" in ix else None, + official, + official_check, + jcr_year, + "official", "official", + jif_url, part_url, + text(row[ix["JIF数据来源"]].value) if "JIF数据来源" in ix else None, + None, # data_source_url(国际表来源即 jif/partition 两链接) + imported_at, + )) + # 统计 + stats["official_total"] += 1 + stats["official_filled"] += 1 if official else 0 + stats["official_check_filled"] += 1 if official_check else 0 + stats["jcr_filled"] += 1 if jcr_year else 0 + if not official: + stats["official_missing"].append(("en", name)) + if jif is None: + stats["jif_missing"].append((name, check_status or "")) + if part is None and part_note == "未检得": + stats["part_notfound"].append(name) + elif part is None: + stats["part_blank"].append(name) + stats["hl_jif"] += 1 if jif_url else 0 + stats["hl_part"] += 1 if part_url else 0 + stats["id_issn" if issn else "id_slug"] += 1 + return rows + + +def read_zh(ws, imported_at: str, stats: dict) -> list[tuple]: + """中文期刊 sheet → 行元组。""" + ix = header_index(ws) + for req in ("中文期刊名称", "复合影响因子", "综合影响因子"): + if req not in ix: + raise SystemExit(f"[结构错误] {SHEET_ZH} 缺列:{req}(实际列:{list(ix)})") + url_col = next((ix[h] for h in OFFICIAL_URL_HEADERS if h in ix), None) + stats["official_url_detected_zh"] = url_col is not None + + rows: list[tuple] = [] + for row in ws.iter_rows(min_row=2): + if not any(c.value is not None for c in row): + continue # 尾部幻影空行:不计入 skipped + name = text(row[ix["中文期刊名称"]].value) + if not name: + stats["skipped"] += 1 + continue + composite = to_float(row[ix["复合影响因子"]].value) + comprehensive = to_float(row[ix["综合影响因子"]].value) + check_status = text(row[ix["核对状态"]].value) if "核对状态" in ix else None + + src_label = text(row[ix["数据来源"]].value) if "数据来源" in ix else None + src_url = hyperlink_target(row[ix["数据来源"]]) if "数据来源" in ix else None + official = None + if url_col is not None and url_col < len(row): + official = text(row[url_col].value) or hyperlink_target(row[url_col]) + official_check = text(row[ix["官网核对状态"]].value) if "官网核对状态" in ix else None + + rows.append(( + make_id("zh", name, None), "zh", name, + text(row[ix["研究方向"]].value), + # 中文分区原样(常量"不按此口径列示"),不分区 → partition_source=None + text(row[ix["中科院分区"]].value) if "中科院分区" in ix else None, + None, # cas_partition_note:中文表无"未检得"语义(口径=不按此口径列示) + None, # cas_partition_year + None, None, None, check_status, + composite, comprehensive, + to_int(row[ix["指标统计年"]].value) if "指标统计年" in ix else None, + to_int(row[ix["年报版本年"]].value) if "年报版本年" in ix else None, + text(row[ix["指标口径"]].value) if "指标口径" in ix else None, + to_int(row[ix["年报PDF页码"]].value) if "年报PDF页码" in ix else None, + None, None, None, None, None, None, None, + text(row[ix["备注"]].value) if "备注" in ix else None, + None, # evidence_note(中文表无此列) + official, + official_check, + None, # jcr_release_year:中文表无 JCR 发布年列(前端中文 Tab 不显示) + None, # partition_source:中文不按中科院口径 + "official", # jif_source:国内年报(official) + None, None, + src_label, src_url, + imported_at, + )) + stats["official_total"] += 1 + stats["official_filled"] += 1 if official else 0 + stats["official_check_filled"] += 1 if official_check else 0 + if not official: + stats["official_missing"].append(("zh", name)) + if composite is None: + stats["cif_missing"].append((name, check_status or "")) + stats["hl_zh"] += 1 if src_url else 0 + stats["id_slug"] += 1 + return rows + + +# ---- 对账报告 ---- + +def build_report( + stage: str, + stats: dict, + counts: dict[str, int] | None, + conflicts: list[str], + idempotent_ok: bool | None, + exit_note: str = "", +) -> str: + L: list[str] = [] + L.append("journals directory 导入对账报告") + L.append(f"生成时间: {datetime.now().isoformat(timespec='seconds')}") + L.append(f"源文件: {SOURCE_XLSX}({SOURCE_XLSX.stat().st_size if SOURCE_XLSX.exists() else 0} bytes)") + L.append(f"阶段: {stage}") + L.append("") + L.append("=== 计数 ===") + L.append(f"读取有效行: 国际 {stats['read_intl']} / 中文 {stats['read_zh']} / 合计 {stats['read_intl'] + stats['read_zh']}") + L.append(f"成功: {stats['success']} 跳过(名称空): {stats['skipped']} 失败: {stats['failed']}") + if counts is not None: + L.append(f"写入后 count(*): en={counts.get('en', 0)} zh={counts.get('zh', 0)} total={counts.get('total', 0)}") + L.append(f"期望: en={EXPECT_INTL} zh={EXPECT_ZH} total={EXPECT_INTL + EXPECT_ZH} → {'✓ 相符' if counts.get('total') == EXPECT_INTL + EXPECT_ZH else '✗ 不符'}") + L.append("") + L.append("=== 分区分布(国际)===") + L.append(" / ".join(f"{k} {v}" for k, v in sorted(stats["part_dist"].items()))) + L.append(f"分区空白(→null 无note): {len(stats['part_blank'])}") + L.append(f"分区未检得(→null + note): {len(stats['part_notfound'])}") + L.append("") + L.append(f"=== JIF 缺失 {len(stats['jif_missing'])} 条(jif=null + note=核对状态)===") + for n, s in stats["jif_missing"]: + L.append(f" - {n} [{s}]") + L.append("") + L.append(f"=== 中文复合IF 缺失 {len(stats['cif_missing'])} 条 ===") + for n, s in stats["cif_missing"]: + L.append(f" - {n} [{s}]") + L.append("") + L.append("=== 分区未检得 期刊名 ===") + if stats["part_notfound"]: + for n in stats["part_notfound"]: + L.append(f" - {n}") + else: + L.append(" (无——源表以空白表示未检得,见上方'分区空白')") + L.append("") + L.append("=== 重复 id 冲突(应为空)===") + if conflicts: + for c in conflicts: + L.append(f" !! {c}") + else: + L.append(" (无)") + L.append("") + L.append("=== id 策略 ===") + L.append(f"ISSN 型: {stats['id_issn']} 条 slug 型: {stats['id_slug']} 条") + L.append("") + L.append("=== 来源超链接 ===") + L.append(f"国际 JIF来源: {stats['hl_jif']}/{stats['read_intl']} 分区来源: {stats['hl_part']}/{stats['read_intl']} 中文数据来源: {stats['hl_zh']}/{stats['read_zh']}") + L.append("") + L.append("=== 结构迁移(ALTER TABLE,幂等)===") + added = stats.get("migrated_cols") or [] + skipped = stats.get("migrated_skipped") or [] + L.append(f" 本次加列: {', '.join(added) if added else '无(列已齐)'}") + L.append(f" 已存在跳过: {', '.join(skipped) if skipped else '无'}") + L.append("") + L.append("=== 官网映射(决策:official_source 不入库)===") + L.append(f" 识别列: {stats.get('official_url_headers', '未识别')}") + tot = stats.get("official_total", 0) + L.append(f" official_url 填充: {stats.get('official_filled', 0)}/{tot}" + f" official_check_status 填充: {stats.get('official_check_filled', 0)}/{tot}") + L.append(f" jcr_release_year 填充: {stats.get('jcr_filled', 0)}(仅国际=2026;中文表无此列→null)") + missing = stats.get("official_missing") or [] + if missing: + L.append(f" 官网缺失 {len(missing)} 条(official_url=null,前端显示「—」不生成链接):") + for lg, n in missing: + L.append(f" - [{lg}] {n}") + else: + L.append(" 官网缺失: (无)") + L.append("") + L.append("=== 幂等性验证 ===") + if idempotent_ok is None: + L.append(" 未执行") + else: + L.append(f" 第二次 upsert 后 count 不变: {'✓ 通过' if idempotent_ok else '✗ 失败'}") + L.append("") + if exit_note: + L.append(f"!!! {exit_note}") + return "\n".join(L) + "\n" + + +# ---- 主流程 ---- + +def main() -> int: + if not SOURCE_XLSX.exists(): + print(f"[错误] 源文件不存在: {SOURCE_XLSX}", file=sys.stderr) + return 3 + + stats: dict[str, Any] = { + "read_intl": 0, "read_zh": 0, "success": 0, "skipped": 0, "failed": 0, + "jif_missing": [], "cif_missing": [], "part_blank": [], "part_notfound": [], + "part_dist": Counter(), "hl_jif": 0, "hl_part": 0, "hl_zh": 0, + "id_issn": 0, "id_slug": 0, "official_url_detected": False, + "migrated_cols": [], "migrated_skipped": [], + "official_total": 0, "official_filled": 0, "official_check_filled": 0, + "jcr_filled": 0, "official_missing": [], + } + imported_at = datetime.now().isoformat(timespec="seconds") + t0 = time.time() + + # 1) 读 Excel(非 read_only:要超链接) + try: + wb = openpyxl.load_workbook(SOURCE_XLSX, data_only=True) + except Exception as exc: # noqa: BLE001 + REPORT_TXT.write_text(build_report("读取失败", stats, None, [], None, str(exc)), encoding="utf-8") + print(f"[错误] 无法打开 Excel: {exc}", file=sys.stderr) + return 3 + if SHEET_INTL not in wb.sheetnames or SHEET_ZH not in wb.sheetnames: + msg = f"缺少 sheet:需要 {SHEET_INTL}/{SHEET_ZH},实际 {wb.sheetnames}" + REPORT_TXT.write_text(build_report("结构错误", stats, None, [], None, msg), encoding="utf-8") + print(f"[错误] {msg}", file=sys.stderr) + return 3 + + # 2) 解析 + rows_en = read_intl(wb[SHEET_INTL], imported_at, stats) + rows_zh = read_zh(wb[SHEET_ZH], imported_at, stats) + stats["read_intl"], stats["read_zh"] = len(rows_en), len(rows_zh) + for r in rows_en: + stats["part_dist"][r[4] or ("未检得" if r[5] else "空白")] += 1 + + # 3) 口径行数校验(不符 → 中止,不写库) + if len(rows_en) != EXPECT_INTL or len(rows_zh) != EXPECT_ZH: + note = (f"行数与口径不符:国际 {len(rows_en)}/{EXPECT_INTL}、" + f"中文 {len(rows_zh)}/{EXPECT_ZH},中止导入") + REPORT_TXT.write_text(build_report("行数校验失败", stats, None, [], None, note), encoding="utf-8") + print(f"[中止] {note}", file=sys.stderr) + return 2 + + # 4) id 冲突检测(同 lang 内重复 → 报告并中止) + ids = [r[0] for r in rows_en + rows_zh] + dup = [i for i, c in Counter(ids).items() if c > 1] + conflicts = [f"{i} × {Counter(ids)[i]}" for i in sorted(dup)] + if conflicts: + note = f"发现 {len(conflicts)} 个重复 id,中止导入(未写库)" + REPORT_TXT.write_text(build_report("id 冲突中止", stats, None, conflicts, None, note), encoding="utf-8") + print(f"[中止] {note}", file=sys.stderr) + for c in conflicts: + print(f" !! {c}", file=sys.stderr) + return 1 + + # 5) 写 SQLite(独立 stdlib 连接;表由本脚本创建,db.py 零触碰) + db_path = Path(os.environ.get("REVIEW_DB_PATH") or (ROOT / "review.db")) + if not db_path.is_absolute(): + db_path = ROOT / db_path + conn = sqlite3.connect(str(db_path)) + try: + conn.executescript(SCHEMA_SQL) + stats["migrated_cols"], stats["migrated_skipped"] = migrate(conn) + all_rows = rows_en + rows_zh + conn.executemany(UPSERT_SQL, all_rows) + conn.commit() + stats["success"] = len(all_rows) + + def count() -> dict[str, int]: + cur = conn.execute( + "SELECT lang, COUNT(*) FROM journal_directory GROUP BY lang") + d = {lang: n for lang, n in cur.fetchall()} + total = sum(d.values()) + return {"en": d.get("en", 0), "zh": d.get("zh", 0), "total": total} + + counts = count() + # 6) 幂等验证:同数据第二次 upsert → count 不变 + conn.executemany(UPSERT_SQL, all_rows) + conn.commit() + idempotent_ok = count() == counts + + # 分区分布来自实际库(防统计与写入脱节;未检得 note 单列) + stats["part_dist"] = Counter(dict(conn.execute( + "SELECT COALESCE(cas_partition, " + "CASE WHEN cas_partition_note='未检得' THEN '未检得' ELSE '空白' END), COUNT(*) " + "FROM journal_directory WHERE lang='en' GROUP BY 1").fetchall())) + + report = build_report("完成", stats, counts, conflicts, idempotent_ok) + REPORT_TXT.write_text(report, encoding="utf-8") + print(report) + print(f"[完成] 耗时 {time.time() - t0:.2f}s db={db_path} 报告={REPORT_TXT}") + return 0 + finally: + conn.close() + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/review_service/tests/test_compile.py b/review_service/tests/test_compile.py new file mode 100644 index 0000000..e761b26 --- /dev/null +++ b/review_service/tests/test_compile.py @@ -0,0 +1,228 @@ +"""tests/test_compile.py —— P3a LaTeX 编译单元/集成测试。 + +真实调用 tools/tectonic(宏包已预热缓存);二进制缺失时集成用例 skipif 跳过, +校验/队列/清扫等纯逻辑用例照常运行。 +运行: cd review_service && /bin/python -m pytest -q +""" +from __future__ import annotations + +import os +import time +from pathlib import Path + +import pytest +from fastapi.testclient import TestClient + +from app.config import get_settings +from app.main import app +from app.services import latex_compile as lc + +MINIMAL = "\\documentclass[11pt]{article}\n\\begin{document}\nhello p3\n\\end{document}\n" + +_TECTONIC_OK = get_settings().tectonic_abs.is_file() + +needs_tectonic = pytest.mark.skipif( + not _TECTONIC_OK, reason="tools/tectonic 未安装(bash tools/install_tectonic.sh)" +) + + +@pytest.fixture() +def client(tmp_path, monkeypatch): + settings = get_settings() + monkeypatch.setattr(settings, "reformat_dir", str(tmp_path / "jobs")) + # 缓存目录不注入 tmp:用部署预热好的 data/tectonic-cache(否则每次测试重拉 bundle) + monkeypatch.setattr(settings, "compile_timeout_s", 60.0) + monkeypatch.setattr(lc, "_pending", 0) + with TestClient(app) as c: + yield c + + +# ================================================================ 校验(无需 tectonic) + +def test_validation_no_input(client: TestClient): + r = client.post("/api/review/compile", data={}) + body = r.json() + assert r.status_code == 200 and body["ok"] is False + assert body["error"]["code"] == "VALIDATION" + + +def test_validation_bad_job_id(client: TestClient): + r = client.post("/api/review/compile", data={"job_id": "../evil"}) + assert r.json()["error"]["code"] == "VALIDATION" + + +def test_validation_job_not_found(client: TestClient): + r = client.post("/api/review/compile", data={"job_id": "0123456789ab"}) + assert r.json()["error"]["code"] == "VALIDATION" + + +def test_validation_path_traversal_filename(client: TestClient): + r = client.post( + "/api/review/compile", + files={"file": ("../evil.tex", b"x", "application/x-tex")}, + ) + assert r.json()["error"]["code"] == "VALIDATION" + + +def test_validation_non_tex(client: TestClient): + r = client.post( + "/api/review/compile", + files={"file": ("paper.pdf", b"x", "application/pdf")}, + ) + assert r.json()["error"]["code"] == "VALIDATION" + + +def test_validation_oversize(client: TestClient, monkeypatch): + monkeypatch.setattr(get_settings(), "max_tex_bytes", 10) + r = client.post( + "/api/review/compile", + files={"file": ("paper.tex", b"01234567890", "application/x-tex")}, + ) + assert r.json()["error"]["code"] == "VALIDATION" + + +# ================================================================ 编译(真实 tectonic) + +@needs_tectonic +def test_compile_happy_path(client: TestClient): + r = client.post( + "/api/review/compile", + files={"file": ("paper.tex", MINIMAL.encode(), "application/x-tex")}, + ) + body = r.json() + assert r.status_code == 200 and body["ok"] is True, body + cid = body["compile_id"] + assert len(cid) == 12 + + pdf = client.get(body["pdf_url"]) + assert pdf.status_code == 200 + assert pdf.headers["content-type"].startswith("application/pdf") + assert pdf.content[:5] == b"%PDF-" + + log = client.get(body["log_url"]) + assert log.status_code == 200 + assert "LaTeX2e" in log.text and "Output written" in log.text + + meta = client.get(f"/api/review/compile/{cid}") + assert meta.json()["ok"] is True + assert meta.json()["meta"]["pdf_bytes"] > 0 + + +@needs_tectonic +def test_compile_by_job_id(client: TestClient): + tex = ( + "\\documentclass[11pt]{article}\n\\begin{document}\nvia job\n\\end{document}\n" + ) + rf = client.post( + "/api/review/reformat", + files={"file": ("paper.tex", tex.encode(), "application/x-tex")}, + data={"target_journal": "default"}, + ).json() + assert rf["ok"] is True + r = client.post("/api/review/compile", data={"job_id": rf["job_id"]}) + body = r.json() + assert body["ok"] is True and body["compile_id"] == rf["job_id"] + pdf = client.get(body["pdf_url"]) + assert pdf.content[:5] == b"%PDF-" + + +@needs_tectonic +def test_compile_malicious_write18(client: TestClient, tmp_path): + canary = tmp_path / "canary_p3" + evil = ( + "\\documentclass{article}\n" + f"\\write18{{touch {canary}}}\n" + "\\begin{document}\nno shell please\n\\end{document}\n" + ) + r = client.post( + "/api/review/compile", + files={"file": ("evil.tex", evil.encode(), "application/x-tex")}, + ) + body = r.json() + # 系统无损即通过(信封 ok 与否均可):canary 绝不能出现 + assert not canary.exists(), r"\write18 竟然执行了!" + if body["ok"]: + pdf = client.get(body["pdf_url"]) + assert pdf.content[:5] == b"%PDF-" + else: + assert body["error"]["code"] in ("COMPILE_FAILED", "TIMEOUT") + + +@needs_tectonic +def test_compile_failed_returns_log_tail(client: TestClient): + bad = "\\documentclass{article}\n\\begin{document}\n\\undefinedcommandxyz\n" + r = client.post( + "/api/review/compile", + files={"file": ("bad.tex", bad.encode(), "application/x-tex")}, + ) + body = r.json() + assert body["ok"] is False + assert body["error"]["code"] == "COMPILE_FAILED" + assert "log" in body["error"]["message"].lower() or body["error"].get("detail") + + +@needs_tectonic +def test_compile_timeout(client: TestClient, monkeypatch): + monkeypatch.setattr(get_settings(), "compile_timeout_s", 5.0) + loop_tex = ( + "\\documentclass{article}\n\\begin{document}\n" + "\\count255=0\n\\loop\\iftrue\\advance\\count255 by 1\\repeat\n" + "\\end{document}\n" + ) + started = time.monotonic() + r = client.post( + "/api/review/compile", + files={"file": ("loop.tex", loop_tex.encode(), "application/x-tex")}, + ) + elapsed = time.monotonic() - started + body = r.json() + assert body["ok"] is False + assert body["error"]["code"] == "TIMEOUT" + assert elapsed < 15.0, f"超时回收过慢:{elapsed:.1f}s" + + +# ================================================================ 队列 / 清扫 + +def test_queue_full(client: TestClient, monkeypatch): + monkeypatch.setattr(lc, "_pending", 5) + monkeypatch.setattr(get_settings(), "compile_queue_limit", 5) + r = client.post( + "/api/review/compile", + files={"file": ("paper.tex", MINIMAL.encode(), "application/x-tex")}, + ) + assert r.status_code == 429 + body = r.json() + assert body["ok"] is False and body["error"]["code"] == "QUEUE_FULL" + + +def test_tool_unavailable(client: TestClient, monkeypatch): + monkeypatch.setattr(get_settings(), "tectonic_path", "tools/definitely-missing") + r = client.post( + "/api/review/compile", + files={"file": ("paper.tex", MINIMAL.encode(), "application/x-tex")}, + ) + assert r.status_code == 200 + assert r.json()["error"]["code"] == "TOOL_UNAVAILABLE" + assert "install_tectonic" in r.json()["error"]["message"] + + +def test_sweep_expired(tmp_path, monkeypatch): + settings = get_settings() + monkeypatch.setattr(settings, "reformat_dir", str(tmp_path / "jobs")) + base = tmp_path / "jobs" + stale = base / "aabbccddeeff" + stale.mkdir(parents=True) + (stale / "output.pdf").write_bytes(b"%PDF-fake") + old = time.time() - 8 * 86400 + os.utime(stale, (old, old)) + + fresh = base / "112233445566" + fresh.mkdir() + noise = base / "not-a-job" + noise.mkdir() + + removed = lc.sweep_expired() + assert removed == 1 + assert not stale.exists() + assert fresh.exists() + assert noise.exists() diff --git a/review_service/tests/test_presubmit.py b/review_service/tests/test_presubmit.py new file mode 100644 index 0000000..5d4a1de --- /dev/null +++ b/review_service/tests/test_presubmit.py @@ -0,0 +1,163 @@ +"""tests/test_presubmit.py —— presubmit 离线单元测试(mock 解析与 LLM,不依赖上游)。 + +覆盖:非 PDF 校验 / 报告归一化 / LLM 失败降级 / 解析失败降级 / 非法 recommendation 回退。 +运行: cd review_service && /bin/python -m pytest -q +""" +from __future__ import annotations + +import pytest +from fastapi.testclient import TestClient + +from app.main import app +from app.services import llm, paper_parse + +FAKE_PDF = b"%PDF-1.4 fake-bytes-for-test" + +LLM_PAYLOAD = { + "summary": "研究问题清晰,但统计与证据链存在重大缺口。", + "major_weaknesses": [ + { + "title": "统计方法不当", + "detail": "未做多重检验校正", + "evidence": "Methods 2.1 仅报 p<0.05,未见 FDR/Bonferroni", + "suggestion": "补充 FDR 校正", + }, + "纯字符串条目", # 宽容归一化:字符串 → WeaknessItem(title=...) + ], + # minor 故意不带 evidence 字段 → 归一化应补空串 + "minor_weaknesses": [{"detail": "缺少缩写表", "title": "缩写"}], + "presentation_format": [{"title": "图注不完整", "detail": "Fig.2 无单位", "suggestion": "补单位"}], + "questions_for_authors": ["群体结构如何校正?", ""], + "recommendation": "MAJOR_REVISION", # 应归一化为小写 +} + + +@pytest.fixture() +def client() -> TestClient: + return TestClient(app) + + +@pytest.fixture(autouse=True) +def _mock_upstreams(monkeypatch): + async def fake_parse(file_bytes: bytes, filename: str = "paper.pdf") -> str: + assert file_bytes == FAKE_PDF + return "论文正文……" * 10 + + async def fake_llm_json(system: str, user: str, **kwargs): + assert "论文正文" in user + return dict(LLM_PAYLOAD) + + async def boom_llm(*args, **kwargs): + raise llm.LLMError("余额不足") + + async def boom_parse(*args, **kwargs): + raise paper_parse.ParseError("PDF 解析结果为空") + + monkeypatch.setattr(paper_parse, "parse_pdf_bytes", fake_parse) + monkeypatch.setattr(llm, "complete_json", fake_llm_json) + yield + # monkeypatch 自动还原 + + +def _post(client: TestClient, filename: str, content: bytes, journal: str = ""): + data = {"target_journal": journal} if journal else {} + return client.post( + "/api/review/presubmit", + files={"file": (filename, content, "application/pdf")}, + data=data, + ) + + +def test_non_pdf_rejected(client: TestClient): + r = client.post( + "/api/review/presubmit", + files={"file": ("a.txt", b"x", "text/plain")}, + ) + body = r.json() + assert body["ok"] is False + assert body["error"]["code"] == "VALIDATION" + + +def test_empty_file_rejected(client: TestClient): + body = _post(client, "p.pdf", b"").json() + assert body["ok"] is False + assert body["error"]["code"] == "VALIDATION" + + +def test_normal_report_normalized(client: TestClient): + body = _post(client, "p.pdf", FAKE_PDF, journal="Plant Cell").json() + assert body["ok"] is True + report = body["report"] + # recommendation 大写 → 小写 + assert report["recommendation"] == "major_revision" + # 字符串条目宽容归一化 + assert len(report["major_weaknesses"]) == 2 + assert report["major_weaknesses"][1]["title"] == "纯字符串条目" + # Evidence 字段:有则透传,字符串条目/缺失则为空串 + assert report["major_weaknesses"][0]["evidence"] == "Methods 2.1 仅报 p<0.05,未见 FDR/Bonferroni" + assert report["major_weaknesses"][1]["evidence"] == "" + assert report["minor_weaknesses"][0]["evidence"] == "" + # 空问题剔除 + assert report["questions_for_authors"] == ["群体结构如何校正?"] + assert report["minor_weaknesses"] and report["presentation_format"] and report["summary"] + # meta 透传 + assert body["meta"]["target_journal"] == "Plant Cell" + assert body["meta"]["text_chars"] > 0 + assert body["meta"]["truncated"] is False + + +def test_llm_failure_degrades(client: TestClient, monkeypatch): + async def boom(*args, **kwargs): + raise llm.LLMError("余额不足") + + monkeypatch.setattr(llm, "complete_json", boom) + body = _post(client, "p.pdf", FAKE_PDF).json() + assert body["ok"] is False + assert body["error"]["code"] == "UPSTREAM_DOWN" + assert body["error"]["degraded"] is True + + +def test_parse_failure_degrades(client: TestClient, monkeypatch): + async def boom(*args, **kwargs): + raise paper_parse.ParseError("PDF 解析结果为空") + + monkeypatch.setattr(paper_parse, "parse_pdf_bytes", boom) + body = _post(client, "p.pdf", FAKE_PDF).json() + assert body["ok"] is False + assert body["error"]["code"] == "PARSE_FAILED" + assert body["error"]["degraded"] is True + + +def test_invalid_recommendation_falls_back(client: TestClient, monkeypatch): + async def weird(*args, **kwargs): + return {"summary": "x", "recommendation": "strong_accept", "major_weaknesses": "not-a-list"} + + monkeypatch.setattr(llm, "complete_json", weird) + body = _post(client, "p.pdf", FAKE_PDF).json() + assert body["ok"] is True + assert body["report"]["recommendation"] == "major_revision" + assert body["report"]["major_weaknesses"] == [] + + +def test_domain_system_prompt_wired(client: TestClient, monkeypatch): + """植物基因组学六维清单 + Evidence 规则必须注入 System Prompt。""" + captured: dict[str, str] = {} + + async def spy(system: str, user: str, **kwargs): + captured["system"] = system + return dict(LLM_PAYLOAD) + + monkeypatch.setattr(llm, "complete_json", spy) + body = _post(client, "p.pdf", FAKE_PDF, journal="Plant Cell").json() + assert body["ok"] is True + system = captured["system"] + for marker in ( + "BUSCO", "N50", "L50", "Hi-C", "挂载率", # 维度1 组装质量 + "MAKER", "AUGUSTUS", "RNA-seq", # 维度2 注释可靠性 + "Bootstrap", "OrthoFinder", # 维度3 比较基因组 + "SRA", "BioProject", "GFF3", "accession", # 维度4 数据合规 + "GWAS", "多重检验校正", "生物学重复", # 维度5 统计设计 + "凭证标本", "ABS", "惠益分享", # 维度6 伦理合规 + "evidence", "章节", # Evidence 硬性要求 + ): + assert marker in system, f"System Prompt 缺少领域标记: {marker}" diff --git a/review_service/tests/test_recommend.py b/review_service/tests/test_recommend.py new file mode 100644 index 0000000..569dfb6 --- /dev/null +++ b/review_service/tests/test_recommend.py @@ -0,0 +1,271 @@ +"""tests/test_recommend.py —— /api/review/recommend 离线单元测试。 + +mock vstore 向量匹配(journal_kb.match)与 LLM(llm.complete_json),不依赖上游。 +核心回归:LLM 幻觉期刊名绝不进输出(白名单 id 硬校验 + 名称一律取 DB)。 + +运行: cd review_service && /bin/python -m pytest -q +""" +from __future__ import annotations + +import asyncio + +import pytest +from fastapi.testclient import TestClient + +from app import db as db_mod +from app.main import app +from app.services import journal_kb, journal_rank, llm + +ABSTRACT = ( + "We report a chromosome-level genome assembly of wild rice Oryza rufipogon " + "using PacBio HiFi and Hi-C sequencing, annotate 38,412 protein-coding genes " + "with RNA-seq evidence, and perform comparative genomics and GWAS analyses " + "to reveal the evolutionary basis of agronomic traits in rice." +) + +SEED_NAMES = { + "Genome Biology", + "BMC Plant Biology", + "Molecular Plant", + "Frontiers in Plant Science", + "Rice", +} + +# 覆盖全部 5 本种子期刊的合法重排结果 +ALL_RANKINGS = [ + {"id": "genome-biology", "tier": "challenge", "match_reason": "组装与比较基因组学范围契合", "risk_note": "IF 门槛高"}, + {"id": "molecular-plant", "tier": "challenge", "match_reason": "分子机制研究契合", "risk_note": "竞争激烈"}, + {"id": "frontiers-in-plant-science", "tier": "fit", "match_reason": "植物生物学范围契合", "risk_note": "无"}, + {"id": "rice", "tier": "fit", "match_reason": "水稻基因组学契合", "risk_note": "无"}, + {"id": "bmc-plant-biology", "tier": "safe", "match_reason": "植物生物学全领域契合", "risk_note": "无"}, +] + + +def make_fake_match(scores: dict[str, float] | None = None, fail: bool = False): + async def fake(abstract: str, journals: list[dict]): + if fail: + raise journal_kb.MatchError("vstore 不可达(mock)") + out = [ + {"journal": j, "similarity": (scores or {}).get(str(j["id"]), 0.5)} + for j in journals + ] + return out, True + + return fake + + +def make_fake_llm(rankings: list[dict] | None = None, fail: bool = False, payload=None): + async def fake(system: str, user: str, **kwargs): + if fail: + raise llm.LLMError("余额不足(mock)") + if payload is not None: + return payload + return {"rankings": rankings if rankings is not None else []} + + return fake + + +@pytest.fixture() +def client(tmp_path, monkeypatch): + db_mod.set_path(tmp_path / "review_test.db") # 进 lifespan 前注入 tmp 路径 + monkeypatch.setattr(journal_kb, "match", make_fake_match()) + monkeypatch.setattr(llm, "complete_json", make_fake_llm(ALL_RANKINGS)) + with TestClient(app) as c: # CM 触发 lifespan:init_db(注入路径) + 收尾 close + yield c + + +def _all_items(body: dict) -> list[dict]: + items: list[dict] = [] + for tier in ("challenge", "fit", "safe"): + items.extend(body["tiers"][tier]["items"]) + return items + + +def test_recommend_happy_path(client: TestClient): + r = client.post("/api/review/recommend", json={"abstract": ABSTRACT}) + assert r.status_code == 200 + body = r.json() + assert body["ok"] is True + assert set(body["tiers"]) == {"challenge", "fit", "safe"} + assert "挑战型" in body["tiers"]["challenge"]["label"] + assert "适配型" in body["tiers"]["fit"]["label"] + assert "稳妥型" in body["tiers"]["safe"]["label"] + + items = _all_items(body) + assert len(items) == 5 + assert {it["name"] for it in items} == SEED_NAMES + for it in items: + assert it["match_reason"], f"缺少匹配理由:{it['name']}" + assert it["risk_note"], f"缺少风险提示:{it['name']}" + assert it["similarity"] == 0.5 + # 三档内容与 LLM 输出一致 + assert [it["name"] for it in body["tiers"]["challenge"]["items"]][0] == "Genome Biology" + assert body["tiers"]["safe"]["items"][0]["name"] == "BMC Plant Biology" + + meta = body["meta"] + assert meta["llm_ok"] is True and meta["vector_ok"] is True + assert meta["dropped_hallucinated"] == 0 + assert meta["seed_count"] == 5 + + +def test_seed_has_no_fabricated_acceptance_rate(client: TestClient): + """种子诚实性:无公开数据的 acceptance_rate 必须为 null。""" + body = client.post("/api/review/recommend", json={"abstract": ABSTRACT}).json() + for it in _all_items(body): + assert it["acceptance_rate"] is None, f"编造了录用率:{it['name']}" + + +def test_hallucinated_journal_dropped(client: TestClient, monkeypatch): + """LLM 幻觉期刊(白名单外 id)绝不进输出;缺漏期刊规则补位。""" + hallucinated = { + "id": "nature-genetics", + "tier": "challenge", + "match_reason": "幻觉期刊,输入列表中并不存在", + "risk_note": "x", + } + monkeypatch.setattr( + llm, + "complete_json", + make_fake_llm([hallucinated, ALL_RANKINGS[1]]), # 1 幻觉 + 1 真实,其余缺漏 + ) + body = client.post("/api/review/recommend", json={"abstract": ABSTRACT}).json() + assert body["ok"] is True + + items = _all_items(body) + raw = str(body) + assert "nature-genetics" not in raw and "Nature Genetics" not in raw + assert "幻觉期刊" not in raw # 幻觉条目的理由同样被丢弃 + assert {it["name"] for it in items} <= SEED_NAMES + assert len(items) == 5 # 4 本缺漏由规则补位,不丢候选 + assert body["meta"]["dropped_hallucinated"] == 1 + assert body["meta"]["repaired"] == 4 + + +def test_llm_name_tamper_ignored(client: TestClient, monkeypatch): + """LLM 篡改期刊名不采信:输出名称一律取 DB。""" + tampered = [ + {"id": "genome-biology", "tier": "fit", "name": "Fake Journal X", + "match_reason": "被篡改的名称", "risk_note": "无"} + ] + monkeypatch.setattr(llm, "complete_json", make_fake_llm(tampered)) + body = client.post("/api/review/recommend", json={"abstract": ABSTRACT}).json() + assert body["ok"] is True + raw = str(body) + assert "Fake Journal X" not in raw + gb = [it for it in _all_items(body) if it["id"] == "genome-biology"] + assert gb and gb[0]["name"] == "Genome Biology" + + +def test_llm_failure_fallback(client: TestClient, monkeypatch): + """LLM 失败 → 规则分档,推荐仍可用(永不 5xx)。""" + monkeypatch.setattr(llm, "complete_json", make_fake_llm(fail=True)) + body = client.post("/api/review/recommend", json={"abstract": ABSTRACT}).json() + assert body["ok"] is True + assert body["meta"]["llm_ok"] is False + items = _all_items(body) + assert len(items) == 5 + assert {it["name"] for it in items} == SEED_NAMES + # 规则分档:IF≥9 → challenge(仅 Genome Biology 10.1 有公开 IF) + challenge = {it["name"] for it in body["tiers"]["challenge"]["items"]} + assert challenge == {"Genome Biology"} + for it in items: + assert it["match_reason"] and it["risk_note"] + + +def test_vector_failure_degrades(client: TestClient, monkeypatch): + """向量匹配失败 → 全量候选 + similarity 为 null,不报错。""" + monkeypatch.setattr(journal_kb, "match", make_fake_match(fail=True)) + body = client.post("/api/review/recommend", json={"abstract": ABSTRACT}).json() + assert body["ok"] is True + assert body["meta"]["vector_ok"] is False + assert body["meta"]["candidate_count"] == 5 + items = _all_items(body) + assert len(items) == 5 + assert all(it["similarity"] is None for it in items) + + +def test_invalid_tier_repaired(client: TestClient, monkeypatch): + """非法 tier 按规则补位,不丢期刊。""" + bad = [ + {"id": "rice", "tier": "超越顶刊", "match_reason": "tier 非法", "risk_note": "无"}, + {"id": "genome-biology", "tier": "challenge", "match_reason": "合法", "risk_note": "无"}, + ] + monkeypatch.setattr(llm, "complete_json", make_fake_llm(bad)) + body = client.post("/api/review/recommend", json={"abstract": ABSTRACT}).json() + assert body["ok"] is True + assert len(_all_items(body)) == 5 + # rice 无公开 IF/周期 → 规则分档 fit + fit_ids = [it["id"] for it in body["tiers"]["fit"]["items"]] + assert "rice" in fit_ids + assert body["meta"]["repaired"] >= 1 + + +def test_short_abstract_validation(client: TestClient): + body = client.post("/api/review/recommend", json={"abstract": "too short"}).json() + assert body["ok"] is False + assert body["error"]["code"] == "VALIDATION" + assert body["tiers"] is None + + +def test_tier_focus_filters_other_tiers(client: TestClient): + body = client.post( + "/api/review/recommend", + json={"abstract": ABSTRACT, "preferences": {"tier_focus": "safe"}}, + ).json() + assert body["ok"] is True + assert body["tiers"]["challenge"]["items"] == [] + assert body["tiers"]["fit"]["items"] == [] + assert body["tiers"]["safe"]["items"] # 聚焦档保留 + assert body["meta"]["preferences"]["tier_focus"] == "safe" + + +def test_soft_preference_risk_note(client: TestClient): + """软偏好:超周期偏好只加风险提示,不删条目。""" + body = client.post( + "/api/review/recommend", + json={"abstract": ABSTRACT, "preferences": {"max_review_weeks": 3}}, + ).json() + assert body["ok"] is True + items = _all_items(body) + assert len(items) == 5 # 不删 + # Genome Biology 审稿约 4 周 > 3 周 → 带 ⚠ 提示 + gb = next(it for it in items if it["id"] == "genome-biology") + assert "超出你 3 周" in gb["risk_note"] + + +def test_seed_idempotent(tmp_path): + """种子装载幂等:连跑两次仍恰好 5 行,且不编造 acceptance_rate。""" + + async def work(): + await db_mod.init_db(tmp_path / "seed.db") + try: + await db_mod.ensure_journals_seeded() + await db_mod.ensure_journals_seeded() + return await db_mod.list_journals() + finally: + await db_mod.close_db() + + rows = asyncio.run(work()) + assert len(rows) == 5 + assert {r["id"] for r in rows} == { + "genome-biology", "bmc-plant-biology", "molecular-plant", + "frontiers-in-plant-science", "rice", + } + assert all(r["acceptance_rate"] is None for r in rows) + assert all(r["scope_desc"] for r in rows) + assert all(r["official_url"] for r in rows) + + +def test_rule_fallback_covers_all_tiers(): + """纯规则分档覆盖三档(不依赖 LLM 与网络)。""" + candidates = [ + {"journal": {"id": "plant-cell", "impact_factor": 11.6, "review_time_weeks": 6.0}, "similarity": None}, + {"journal": {"id": "plant-journal", "impact_factor": 7.2, "review_time_weeks": 5.0}, "similarity": None}, + {"journal": {"id": "plant-genome", "impact_factor": 3.3, "review_time_weeks": 4.0}, "similarity": None}, + ] + rankings = journal_rank.fallback_rankings(candidates) + assert {r.journal_id for r in rankings} == {"plant-cell", "plant-journal", "plant-genome"} + by_id = {r.journal_id: r.tier for r in rankings} + assert by_id["plant-cell"] == "challenge" + assert by_id["plant-journal"] == "fit" + assert by_id["plant-genome"] == "safe" diff --git a/review_service/tests/test_reformat.py b/review_service/tests/test_reformat.py new file mode 100644 index 0000000..4f7b4d0 --- /dev/null +++ b/review_service/tests/test_reformat.py @@ -0,0 +1,407 @@ +"""tests/test_reformat.py —— P1 论文重排版单元测试(离线,零 LLM/零网络/零磁盘污染)。 + +覆盖:规则解析链(default/种子占位/目录回链/抓取缓存/未匹配)+ 4 变换器 +(改/不改/保守 warning)+ 结构守卫 + 幂等 + API 信封(校验/落盘/GET/404)。 +运行: cd review_service && /bin/python -m pytest -q +""" +from __future__ import annotations + +import asyncio +import re + +import pytest +from fastapi.testclient import TestClient + +from app.main import app +from app.services import reformat as rf +from app.services.reformat import RULES_DEFAULT, ReformatError, reformat_tex, resolve_rules + +# 金样例:4 处违规(字号/边距/行距/样式),全部命令齐备 → 0 warning +GOLDEN = r"""\documentclass[10pt]{article} +\usepackage[margin=1in,top=10mm]{geometry} +\linespread{1.0} +\bibliographystyle{plain} +\begin{document} +Hello. +\end{document} +""" + +MINIMAL = "\\documentclass[11pt]{article}\n\\begin{document}\nx\n\\end{document}\n" + + +def _run(source: str, **rule_overrides): + rules = {**RULES_DEFAULT, **rule_overrides} + return reformat_tex(source, rules) + + +def _modified(changes): + return [c for c in changes if c["action"] == "modified"] + + +def _warnings(changes): + return [c for c in changes if c["action"] == "warning"] + + +def _by_key(changes, rule_key, action=None): + out = [c for c in changes if c["rule_key"] == rule_key + and (action is None or c["action"] == action)] + return out + + +# ================================================================ 规则解析链 + +def test_resolve_default(): + r = asyncio.run(resolve_rules("default")) + assert r["rules_source"] == "default" + assert r["rules"] == RULES_DEFAULT + assert r["rules"]["min_font_pt"] == 11 + assert r["rules"]["min_margin_mm"] == 20 + assert r["rules"]["min_line_spacing"] == 1.5 + assert r["rules"]["refs_style"] == "apa" + assert r["journal_id"] == "default" + + +def test_resolve_seed_name_official(): + r = asyncio.run(resolve_rules("Genome Biology")) + assert r["journal_id"] == "genome-biology" + assert r["rules_source"] == "official" + assert r["rules"]["min_line_spacing"] == 2.0 + assert r["rules"]["refs_style"] == "vancouver" + + +def test_resolve_seed_id(): + r = asyncio.run(resolve_rules("genome-biology")) + assert r["journal_id"] == "genome-biology" + assert r["rules_source"] == "official" + + +def test_resolve_unknown_name(): + r = asyncio.run(resolve_rules("Nonexistent Journal of Nowhere")) + assert r["rules_source"] == "default" + assert r["journal_id"] is None + assert "未匹配" in r["rules_note"] + + +def test_resolve_directory_id_backlink(monkeypatch): + async def fake_dir_name(journal_id: str): + return "Genome Biology" if journal_id.startswith("zh:") else None + + monkeypatch.setattr(rf, "_directory_name", fake_dir_name) + r = asyncio.run(resolve_rules("zh:some-slug")) + assert r["journal_id"] == "genome-biology" + + +def test_resolve_fetched_cache(monkeypatch): + monkeypatch.setattr(rf, "_cache_rules", lambda jid: { + "rules_source": "fetched", "min_font_pt": 10, "refs_style": "gb7714"}) + r = asyncio.run(resolve_rules("genome-biology")) + assert r["rules_source"] == "fetched" # 抓取缓存优先于 official + assert r["rules"]["min_font_pt"] == 10 # 专属覆盖通用 + assert r["rules"]["min_margin_mm"] == 20 # 缺失键保留通用 + assert r["rules"]["refs_style"] == "gb7714" + + +def test_resolve_official_format_rules(monkeypatch): + monkeypatch.setattr(rf, "_find_seed", lambda text: { + "id": "x-journal", "name": "X Journal", + "format_rules": {"rules_source": "official", "min_line_spacing": 1.3}}) + r = asyncio.run(resolve_rules("X Journal")) + assert r["rules_source"] == "official" + assert r["rules"]["min_line_spacing"] == 1.3 + + +# ================================================================ ① 字号 font_pt + +def test_font_modify_below_min(): + src = "\\documentclass[10pt]{article}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src) + font = _by_key(res["changes"], "font_pt") + assert len(font) == 1 + c = font[0] + assert c["action"] == "modified" + assert "[11pt]" in res["modified_tex"] and "[10pt]" not in res["modified_tex"] + assert "10pt" in c["original"] and "11pt" in c["modified"] + + +def test_font_compliant_untouched(): + res = _run(MINIMAL) + assert res["modified_tex"] == MINIMAL # warning 不改源码(拍板 2) + assert _by_key(res["changes"], "font_pt") == [] + + +def test_font_missing_option_is_warning(): + src = "\\documentclass[a4paper]{article}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src) + assert res["modified_tex"] == src # 拍板 2:绝不自动插入选项 + (c,) = _by_key(res["changes"], "font_pt") + assert c["action"] == "warning" + assert "\\documentclass[a4paper, 11pt]{article}" in c["reason"] + + +def test_font_min_above_standard_uses_min(): + src = "\\documentclass[12pt]{article}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src, min_font_pt=14) + assert "[14pt]" in res["modified_tex"] + + +# ================================================================ ② 页边距 margin + +def test_margin_bumps_hmargin_vmargin(): + src = "\\documentclass[11pt]{article}\n\\usepackage[hmargin=10mm,vmargin=15mm]{geometry}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src) + assert "hmargin=20mm" in res["modified_tex"] + assert "vmargin=20mm" in res["modified_tex"] + assert "]{geometry}" in res["modified_tex"] # 值替换不得吞掉包名尾巴 + margin = _by_key(res["changes"], "margin") + assert len(margin) == 1 # 同行多键合并一条 + assert "left" in margin[0]["reason"] and "top" in margin[0]["reason"] + + +def test_margin_per_side_only_bumps_violations(): + res = _run(GOLDEN) + (c,) = [x for x in res["changes"] if x["rule_key"] == "margin"] + assert c["action"] == "modified" + assert "top=20mm" in c["modified"] # top 10mm 违规 + assert "margin=1in" in c["modified"] # 1in=25.4mm 合规,不动 + + +def test_margin_compliant_untouched(): + src = "\\documentclass[11pt]{article}\n\\usepackage[margin=25mm]{geometry}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src) + assert res["modified_tex"] == src + + +def test_margin_no_geometry_is_warning(): + src = "\\documentclass[11pt]{article}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src) + assert res["modified_tex"] == src + (c,) = [x for x in res["changes"] if x["rule_key"] == "margin"] + assert c["action"] == "warning" + assert "\\usepackage[margin=20mm]{geometry}" in c["reason"] + + +def test_margin_geometry_without_margin_attrs_is_warning(): + src = "\\documentclass[11pt]{article}\n\\usepackage[scale=0.7]{geometry}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src) + assert res["modified_tex"] == src + (c,) = [x for x in res["changes"] if x["rule_key"] == "margin"] + assert c["action"] == "warning" + assert "margin=20mm" in c["reason"] + + +def test_margin_partial_sides_bump_and_warn(): + src = "\\documentclass[11pt]{article}\n\\usepackage[left=10mm]{geometry}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src) + assert "left=20mm" in res["modified_tex"] + assert "]{geometry}" in res["modified_tex"] + mod = _by_key(res["changes"], "margin", "modified") + warn = _by_key(res["changes"], "margin", "warning") + assert len(mod) == 1 and len(warn) == 1 + assert "right" in warn[0]["reason"] + + +# ================================================================ ③ 行距 line_spacing + +def test_spacing_modify(): + res = _run(GOLDEN) + (c,) = [x for x in res["changes"] if x["rule_key"] == "line_spacing"] + assert c["action"] == "modified" + assert "\\linespread{1.5}" in res["modified_tex"] + + +def test_spacing_ignores_body_override(): + src = ("\\documentclass[11pt]{article}\n\\linespread{1.5}\n\\begin{document}\n" + "\\setstretch{1.0}\nx\n\\end{document}\n") + res = _run(src) + assert res["modified_tex"] == src # 正文局部覆盖不碰(导言区已合规) + + +def test_spacing_missing_is_warning(): + src = "\\documentclass[11pt]{article}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src) + (c,) = [x for x in res["changes"] if x["rule_key"] == "line_spacing"] + assert c["action"] == "warning" + assert "\\linespread{1.5}" in c["reason"] + + +# ================================================================ ④ 参考文献 bib_style + +def test_bib_plain_to_apalike(): + res = _run(GOLDEN) + (c,) = [x for x in res["changes"] if x["rule_key"] == "bib_style"] + assert c["action"] == "modified" + assert "\\bibliographystyle{apalike}" in res["modified_tex"] + + +def test_bib_author_year_maps_apalike_not_plain(): + """回归(2026-10-10 修正):author_year 是姓名-年份制 → apalike,绝不映射编号制 plain。""" + src = "\\documentclass[11pt]{article}\n\\bibliographystyle{unsrt}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src, refs_style="author_year") + assert "\\bibliographystyle{apalike}" in res["modified_tex"] + assert "unsrt" not in res["modified_tex"].split("bibliographystyle")[1] + + +def test_bib_null_refs_style_warns_without_touching_source(): + """拍板(2026-10-10):refs_style=null(如 Frontiers 两种制式并存)→ 保持原样 + warning。""" + src = "\\documentclass[11pt]{article}\n\\bibliographystyle{unsrt}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src, refs_style=None) + assert res["modified_tex"] == src # 绝不猜测改写用户样式 + (c,) = _by_key(res["changes"], "bib_style") + assert c["action"] == "warning" + assert "未确认" in c["reason"] and "bibliographystyle" in c["reason"] + + +def test_bib_gb7714_hint(): + src = "\\documentclass[11pt]{article}\n\\bibliographystyle{plain}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src, refs_style="gb7714") + assert "\\bibliographystyle{gb7714}" in res["modified_tex"] + (c,) = _by_key(res["changes"], "bib_style") + assert "gbt7714" in c["reason"] + + +def test_bib_unmapped_style_is_warning(): + src = "\\documentclass[11pt]{article}\n\\bibliographystyle{plain}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src, refs_style="mla") + assert res["modified_tex"] == src + (c,) = _by_key(res["changes"], "bib_style") + assert c["action"] == "warning" and "mla" in c["reason"] + + +def test_bib_missing_is_warning(): + src = "\\documentclass[11pt]{article}\n\\begin{document}\nx\n\\end{document}\n" + res = _run(src) + (c,) = [x for x in res["changes"] if x["rule_key"] == "bib_style"] + assert c["action"] == "warning" + assert "\\bibliographystyle{apalike}" in c["reason"] + + +def test_bib_biblatex_workflow_is_warning(): + src = ("\\documentclass[11pt]{article}\n\\usepackage{biblatex}\n" + "\\begin{document}\n\\printbibliography\n\\end{document}\n") + res = _run(src) + (c,) = [x for x in res["changes"] if x["rule_key"] == "bib_style"] + assert c["action"] == "warning" + assert "style=apa" in c["reason"] + + +# ================================================================ 结构守卫 + 幂等 + +def test_parser_failed_without_documentclass(): + with pytest.raises(ReformatError) as ei: + _run("% just a fragment\n") + assert ei.value.code == "PARSER_FAILED" + + +def test_multi_documentclass_first_wins(): + src = ("\\documentclass[10pt]{article}\n\\begin{document}\n" + "\\documentclass[9pt]{book}\n\\end{document}\n") + res = _run(src) + assert [w["code"] for w in res["warnings"]] == ["MULTI_DOCUMENTCLASS"] + assert "[11pt]" in res["modified_tex"] + assert res["modified_tex"].count("\\documentclass") == 2 # 第二处不碰 + + +def test_idempotent_second_run_clean(): + first = _run(GOLDEN) + assert len(_modified(first["changes"])) == 4 + assert first["warnings"] == [] + second = _run(first["modified_tex"]) + assert second["changes"] == [] + assert second["modified_tex"] == first["modified_tex"] + + +def test_changes_sorted_and_fields_complete(): + res = _run(GOLDEN) + lines = [c["line"] for c in res["changes"]] + assert lines == sorted(lines) + for c in res["changes"]: + assert set(c) == {"line", "original", "modified", "reason", "rule_key", "action"} + + +# ================================================================ API(信封/落盘) + +def _post(client: TestClient, content: bytes, journal: str = "default", + filename: str = "paper.tex", **data): + if journal is not None: + data.setdefault("target_journal", journal) + return client.post("/api/review/reformat", + files={"file": (filename, content, "text/plain")}, data=data) + + +@pytest.fixture() +def client(tmp_path, monkeypatch): + jobs = tmp_path / "jobs" + + def fake_dir(): + jobs.mkdir(parents=True, exist_ok=True) + return jobs + + monkeypatch.setattr("app.routers.reformat._jobs_dir", fake_dir) + return TestClient(app) + + +def test_api_non_tex_rejected(client: TestClient): + body = _post(client, b"x", filename="a.pdf").json() + assert body["ok"] is False + assert body["error"]["code"] == "VALIDATION" + assert body["error"]["degraded"] is False + + +def test_api_missing_target_rejected(client: TestClient): + body = _post(client, GOLDEN.encode(), journal=None).json() + assert body["ok"] is False and body["error"]["code"] == "VALIDATION" + + +def test_api_empty_file_rejected(client: TestClient): + body = _post(client, b"").json() + assert body["ok"] is False and body["error"]["code"] == "VALIDATION" + + +def test_api_non_utf8_rejected(client: TestClient): + body = _post(client, b"\xff\xfe\x00bad").json() + assert body["ok"] is False and body["error"]["code"] == "VALIDATION" + + +def test_api_parser_failed_envelope(client: TestClient): + body = _post(client, b"% fragment, no documentclass").json() + assert body["ok"] is False and body["error"]["code"] == "PARSER_FAILED" + assert "documentclass" in body["error"]["message"] + + +def test_api_success_and_persist(client: TestClient): + body = _post(client, GOLDEN.encode()).json() + assert body["ok"] is True + assert re.fullmatch(r"[0-9a-f]{12}", body["job_id"]) + mod = _modified(body["changes"]) + assert len(mod) == 4 and body["warnings"] == [] + assert "\\documentclass[11pt]" in body["modified_tex"] + meta = body["meta"] + assert meta["rules_source"] == "default" + assert meta["rules"]["min_font_pt"] == 11 + assert meta["engine"] == "reformat-p1/1.0" + assert len(meta["original_sha256"]) == 64 + # 持久化:重启语义的 GET 回读同一 job + got = client.get(f"/api/review/reformat/{body['job_id']}").json() + assert got["ok"] and got["job_id"] == body["job_id"] + assert len(_modified(got["changes"])) == 4 + f = client.get(f"/api/review/reformat/{body['job_id']}/file") + assert f.status_code == 200 + assert "x-tex" in f.headers["content-type"] + assert "\\documentclass[11pt]" in f.text + + +def test_api_job_not_found(client: TestClient): + for path in ("/api/review/reformat/000000000000", + "/api/review/reformat/zzzz"): + body = client.get(path).json() + assert body["ok"] is False and body["error"]["code"] == "NOT_FOUND" + f = client.get("/api/review/reformat/000000000000/file") + assert f.status_code == 200 and f.json()["error"]["code"] == "NOT_FOUND" + + +def test_api_idempotent_reupload(client: TestClient): + first = _post(client, GOLDEN.encode()).json() + assert first["ok"] and len(_modified(first["changes"])) == 4 + second = _post(client, first["modified_tex"].encode()).json() + assert second["ok"] and second["changes"] == [] + assert second["modified_tex"] == first["modified_tex"] diff --git a/review_service/tools/README.md b/review_service/tools/README.md new file mode 100644 index 0000000..1c847d9 --- /dev/null +++ b/review_service/tools/README.md @@ -0,0 +1,13 @@ +# tools/ —— 编译器工具链(P3) + +## tectonic(LaTeX → PDF) + +- 单文件 musl 静态二进制,无 root、无系统 TeX Live 依赖;版本与 sha256 钉死在 + `install_tectonic.sh`(本目录二进制不入 git)。 +- 安装:`cd review_service && bash tools/install_tectonic.sh` + 部署树(zh)同一条命令;或直接 scp `tools/tectonic` + `data/tectonic-cache/`。 +- 宏包缓存:`data/tectonic-cache/`(环境变量 `REVIEW_TECTONIC_CACHE_DIR` 覆盖)。 + 首次编译会联网拉 bundle(~200MB),建议部署时用 hello.tex 预热: + `TECTONIC_CACHE_DIR=$PWD/data/tectonic-cache tools/tectonic -X compile hello.tex --untrusted` +- 安全:编译一律 `--untrusted`(tectonic 官方旗标,禁用已知不安全特性)+ + 运行于隔离工作目录 + 60s 超时整组 kill + 禁 shell escape。 diff --git a/review_service/tools/install_tectonic.sh b/review_service/tools/install_tectonic.sh new file mode 100644 index 0000000..0d05e9b --- /dev/null +++ b/review_service/tools/install_tectonic.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# install_tectonic.sh —— 一键安装/校验 tectonic 编译器(P3a)。 +# 幂等:已装且 sha256 匹配则直接退出 0。部署树(zh)同一条命令。 +# 用法:cd review_service && bash tools/install_tectonic.sh +set -euo pipefail + +TECTONIC_VERSION="0.17.0" +TECTONIC_TARBALL_SHA256="8533d07f9ccbd7a65824b9e0459041bca34af1eb33daba48f59215593753a3b7" +TECTONIC_BIN_SHA256="a98aa59ad5c1df39a6c9e56cbfc5088f2b11d6c179c0130b97998e4bd46a46da" +URL="https://github.com/tectonic-typesetting/tectonic/releases/download/tectonic%40${TECTONIC_VERSION}/tectonic-${TECTONIC_VERSION}-x86_64-unknown-linux-musl.tar.gz" + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BIN="${HERE}/tectonic" + +if [[ -x "$BIN" ]] && echo "$(sha256sum "$BIN" | cut -d' ' -f1)" = "$TECTONIC_BIN_SHA256"; then + echo "[install_tectonic] 已安装且校验通过:$BIN ($("$BIN" --version))" + exit 0 +fi + +tmp="$(mktemp -d)" +trap 'rm -rf "$tmp"' EXIT + +echo "[install_tectonic] 下载 tectonic ${TECTONIC_VERSION}(musl 静态版)…" +curl -fL --retry 3 -o "$tmp/tectonic.tar.gz" "$URL" + +echo "[install_tectonic] 校验 tarball sha256…" +echo "${TECTONIC_TARBALL_SHA256} $tmp/tectonic.tar.gz" | sha256sum -c - + +tar -xzf "$tmp/tectonic.tar.gz" -C "$tmp" tectonic +echo "[install_tectonic] 校验二进制 sha256…" +echo "${TECTONIC_BIN_SHA256} $tmp/tectonic" | sha256sum -c - + +install -m 0755 "$tmp/tectonic" "$BIN" +echo "[install_tectonic] 完成:$BIN ($("$BIN" --version))" +echo "[install_tectonic] 提示:首次真实编译会联网拉宏包 bundle(约 200MB)," +echo " 服务端 TECTONIC_CACHE_DIR 默认 data/tectonic-cache,建议部署时预热。" diff --git a/sdk/app/config.py b/sdk/app/config.py index caa9685..8a07ef1 100644 --- a/sdk/app/config.py +++ b/sdk/app/config.py @@ -81,6 +81,11 @@ class Settings(BaseSettings): paper_writer_url: str = "http://127.0.0.1:8097" paper_writer_read_timeout: float = 360.0 # write_paper_section 同步长调用读超时(秒) + # ---- 科研审稿服务(review_service 8100;REVIEW_ENABLED 为假时路由不注册)---- + review_enabled: bool = False + review_service_url: str = "http://127.0.0.1:8100" + review_read_timeout: float = 360.0 # presubmit 上传+LLM 长调用读超时(秒) + # ---- 生产形态:BFF 静态托管 ui/dist(ARCHITECTURE.md §3,M6 挂载)---- frontend_dist_dir: str = "ui/dist" # 生产形态:静态托管 ui/dist diff --git a/sdk/app/main.py b/sdk/app/main.py index d15fac9..1a5fdcd 100644 --- a/sdk/app/main.py +++ b/sdk/app/main.py @@ -26,6 +26,7 @@ from .routers import capabilities, docgen, extraction, figures, health, kg, lega from .routers import bioflow_proxy from .routers import paper from .routers import private_docs +from .routers import review_proxy from .upstream import close_client logging.basicConfig(level=logging.INFO) @@ -62,6 +63,8 @@ def create_app() -> FastAPI: app.include_router(bioflow_proxy.router) # 生信反代(BIOFLOW_ENABLED 开关,FR-BIO-028) if get_settings().paper_writer_enabled: app.include_router(paper.router) # 论文撰写(PAPER_WRITER_ENABLED 开关) + if get_settings().review_enabled: + app.include_router(review_proxy.router) # 科研审稿反代(REVIEW_ENABLED 开关) @app.exception_handler(RequestValidationError) async def _validation_handler(_: Request, exc: RequestValidationError) -> JSONResponse: diff --git a/sdk/app/routers/review_proxy.py b/sdk/app/routers/review_proxy.py new file mode 100644 index 0000000..6a14a5c --- /dev/null +++ b/sdk/app/routers/review_proxy.py @@ -0,0 +1,85 @@ +"""routers/review_proxy.py —— BFF 科研审稿反代(REVIEW_ENABLED 条件注册)。 + +- GET /api/review/health → 探活 review 服务 /health(离线返回 offline 标记, + 前端据此隐藏审稿入口;模式同 routers/paper.py)。 +- /api/review/{path:path} → 透明反代 review_service(8100);presubmit 为 + 上传+LLM 长调用,读超时取 settings.review_read_timeout。 +- REVIEW_ENABLED 为假时路由不注册(main.py 按开关 include,三形态部署)。 + +约束:本文件是 BFF 层对审稿模块的唯一新增面(新文件,不改既有路由逻辑)。 +review_service 失败统一 503 UPSTREAM_DOWN 信封(经 app.upstream.envelope)。 +""" +from __future__ import annotations + +import logging +from typing import Any + +import httpx +from fastapi import APIRouter, Request +from fastapi.responses import JSONResponse, Response + +from ..config import get_settings +from ..upstream import envelope + +logger = logging.getLogger(__name__) + +router = APIRouter(prefix="/api/review", tags=["review-proxy"]) + +PROXY_CONNECT_TIMEOUT = 5.0 + + +def _service_base() -> str: + return get_settings().review_service_url.rstrip("/") + + +@router.get("/health") +async def review_health() -> dict[str, Any]: + """探活反代 8100 /health;离线返回 offline 标记。""" + s = get_settings() + try: + async with httpx.AsyncClient(timeout=10.0) as client: + resp = await client.get(f"{s.review_service_url.rstrip('/')}/health") + resp.raise_for_status() + return resp.json() + except Exception: # noqa: BLE001 + return {"ok": False, "status": "offline"} + + +async def _proxy(request: Request, path: str) -> Any: + """httpx 透传反代(非 SSE;presubmit 长读超时);失败→503 信封。""" + s = get_settings() + base = _service_base() + url = f"{base}/api/review/{path.lstrip('/')}" + if request.url.query: + url = f"{url}?{request.url.query}" + body = await request.body() + headers = {k: v for k, v in request.headers.items() + if k.lower() not in ("host", "content-length", "connection")} + timeout = httpx.Timeout( + connect=PROXY_CONNECT_TIMEOUT, + read=s.review_read_timeout, + write=s.review_read_timeout, + pool=5.0, + ) + async with httpx.AsyncClient(timeout=timeout) as client: + try: + upstream = client.build_request( # build_request 是同步方法,返回 httpx.Request,不可 await + request.method, url, content=body, headers=headers + ) + resp = await client.send(upstream) + except httpx.HTTPError as exc: + logger.warning("review_proxy: 审稿服务不可达 %s: %s", url, exc) + payload, status = envelope( + "UPSTREAM_DOWN", message="审稿服务当前不可用,请稍后重试", + degraded=True, status=503, + ) + return JSONResponse(status_code=status, content=payload) + content = await resp.aread() + + media_type = resp.headers.get("content-type", "") or "application/json" + return Response(status_code=resp.status_code, content=content, media_type=media_type) + + +@router.api_route("/{path:path}", methods=["GET", "POST", "PUT", "PATCH", "DELETE"]) +async def proxy_all(path: str, request: Request) -> Any: + return await _proxy(request, path) diff --git a/ui/.gitignore b/ui/.gitignore index 677c9b7..11ee758 100644 --- a/ui/.gitignore +++ b/ui/.gitignore @@ -1,3 +1 @@ -# frontend/.gitignore(最小版,B1 可扩展) -node_modules/ -dist/ +.env.local diff --git a/ui/postcss.config.js b/ui/postcss.config.js new file mode 100644 index 0000000..b1c6ea4 --- /dev/null +++ b/ui/postcss.config.js @@ -0,0 +1 @@ +export default {} diff --git a/ui/src/App.vue b/ui/src/App.vue index 531d4b9..e475c09 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -1,11 +1,14 @@ - + diff --git a/ui/src/api/review.js b/ui/src/api/review.js new file mode 100644 index 0000000..e4419a1 --- /dev/null +++ b/ui/src/api/review.js @@ -0,0 +1,135 @@ +// api/review.js —— 科研审稿端点封装(BFF 8090 → review_service 8100) +// 相对路径 /api/review/* → vite proxy(vite.config.js bffTarget)→ BFF 反代(须 REVIEW_ENABLED=1)。 +// +// 错误契约适配:review_service 业务错误是 **HTTP 200 + {ok:false,error:{...}}** +// (VALIDATION/PARSE_FAILED/UPSTREAM_DOWN/SEED_UNAVAILABLE 均实测 200), +// 而 http.js 只对非 2xx 抛 ApiError —— 200 信封会正常 resolve。 +// unwrap() 把两条错误路径(200 信封 / 非 2xx http.js 抛出)归一成 ApiError, +// 调用方只需 catch + reviewErrorMessage(err) 一个口径。 +import { get, post, ApiError } from './http.js'; + +const BASE = '/api/review'; + +function unwrap(promise) { + return promise.then((payload) => { + if (payload && payload.ok === false && payload.error) { + const err = new ApiError(payload.error.message || '服务错误', { + code: payload.error.code || 'INTERNAL', + status: 200, + degraded: !!payload.error.degraded, + }); + if (payload.error.detail) err.detail = payload.error.detail; // 编译失败的 log 尾等 + throw err; + } + return payload; + }); +} + +/** ① GET /api/review/journals?field=&order= + * → {ok, items:[{id,name,scope_desc,impact_factor,review_time_weeks,acceptance_rate, + * submission_deadline,official_url,last_updated}], + * meta:{count,last_updated,data_source_note}} */ +export function getJournals(params = {}) { + return unwrap(get(`${BASE}/journals`, params)); +} + +/** ①' GET /api/review/journals/directory?lang=&domain=&cas_partition=&q=&page=&size=&field=&order= + * → {ok, items[{id,lang,name,research_direction,cas_partition,cas_partition_note, + * cas_partition_year,jif,jif_year,jif_note,jif_check_status,composite_impact_factor, + * comprehensive_impact_factor,metric_year,metric_report_year,metric_caliber, + * annual_report_page,top_flag,publisher_series,journal_mark,article_type,issn,eissn, + * jcr_disciplines[],supplement_note,evidence_note,official_url,partition_source, + * jif_source,jif_source_url,partition_source_url,data_source_label,data_source_url}], + * meta:{total,page,size,lang,domain,cas_partition,q,domains[], + * data_source_note,data_imported}} + * 1056 本目录(779 国际 + 277 中文);只读分页,lang 强制单语(en/zh 永不混排); + * cas_partition 仅 lang=en 过滤;field 排序白名单 name/jif/composite_impact_factor/ + * comprehensive_impact_factor/research_direction/cas_partition;缺值 source 已归零。 */ +export function getDirectory(params = {}) { + return unwrap(get(`${BASE}/journals/directory`, params)); +} + +/** ⑦' GET /api/review/conferences?domain=&ccf=&upcoming_days= + * → {ok, items:[{id,name,full_name,domain_tags,application_tags,ccf_rank, + * deadline_abstract,deadline_full_paper,notification_date,conference_date, + * location,official_url,timezone_note,deadline_source,last_verified}], + * meta:{count,last_verified,data_source_note,query}} + * 只读静态种子(全 placeholder);排序/过滤由后端做,upcoming_days=0 表示不过滤。 */ +export function getConferences(params = {}) { + return unwrap(get(`${BASE}/conferences`, params)); +} + +/** ③ POST /api/review/presubmit(multipart PDF)→ {ok, report, meta} + * FormData 自动 multipart(http.js 不设 Content-Type,浏览器带 boundary); + * opts 可传 {onUploadProgress, signal, timeout}(FormData+进度走 XHR 分支)。 + * 读超时沿用默认 600s(> BFF 360s),不先于上游自断。 */ +export function presubmit(formData, opts = {}) { + return unwrap(post(`${BASE}/presubmit`, formData, opts)); +} + +/** ② POST /api/review/recommend → {ok, tiers:[{tier,journals:[...]}], meta} */ +export function recommend(payload, opts = {}) { + return unwrap(post(`${BASE}/recommend`, payload, opts)); +} + +/** ⑤ POST /api/review/format-check(multipart PDF/Word) + * → {ok, checks:[{key,name,status,detail,suggestion}], summary:{pass,warn,fail}, + * meta:{filename,file_type,pages,ruleset_source,rules_source,journal_*, + * refs_style_expected,refs_style_detected}} + * 纯规则引擎,无 LLM,同步秒回(无需 onUploadProgress)。 */ +export function formatCheck(formData, opts = {}) { + return unwrap(post(`${BASE}/format-check`, formData, opts)); +} + +/** ⑥ POST /api/review/reformat(multipart .tex + target_journal) + * → {ok, job_id, modified_tex, + * changes:[{line,original,modified,reason,rule_key,action}], + * warnings:[{code,message}], // 仅结构级(如多处 \documentclass) + * meta:{journal_id,journal_name,rules,rules_source,rules_note,filename, + * original_sha256,engine,generated_at}} + * rule_key ∈ {font_pt,margin,line_spacing,bib_style}; + * action ∈ {modified,warning}(warning=缺插入点的保守建议,不计入已修改)。 + * 纯规则引擎,同步秒回;job 落盘 → GET `${BASE}/reformat/{id}` 可回读。 */ +export function reformatTex(formData, opts = {}) { + return unwrap(post(`${BASE}/reformat`, formData, opts)); +} + +/** P3a POST /api/review/compile(multipart:job_id 或 file 二选一,前端走 job_id) + * → {ok, compile_id, pdf_url, log_url, meta:{seconds,pdf_bytes,engine,compiled_at}} + * 错误信封:VALIDATION / TOOL_UNAVAILABLE / COMPILE_FAILED / TIMEOUT / OUTPUT_TOO_LARGE + * 为 HTTP 200 信封;QUEUE_FULL 为 HTTP 429 + 同款信封(http.js 抛非 2xx ApiError, + * 两者都归一成 ApiError)。COMPILE_FAILED/TIMEOUT 的 err.detail = log 尾 200 行。 + * 编译为单槽队列,耗时约 10-30 秒(默认 60s 上限)。 */ +export function compileTex(formData, opts = {}) { + return unwrap(post(`${BASE}/compile`, formData, opts)); +} + +/** ⑤ format-check 专用错误文案:解档/校验类 PARSE_FAILED/VALIDATION 用后端原话 + * (与 presubmit 的"扫描件"提示是不同语境,不能复用 CODE_HINTS),其余走统一口径。 */ +export function formatErrorMessage(err) { + if (err instanceof ApiError && (err.code === 'PARSE_FAILED' || err.code === 'VALIDATION') && err.message) { + return err.message; + } + return reviewErrorMessage(err); +} + +/** 后端 error.code → 用户可读提示。 + * null = 不覆盖、直接用后端 message(VALIDATION 入参问题后端原话更具体)。 */ +const CODE_HINTS = { + VALIDATION: null, + PARSE_FAILED: '论文解析失败:可能是扫描件/图片型 PDF,请换文本型 PDF。', + UPSTREAM_DOWN: '审稿模型暂时不可用,请稍后重试。', + SEED_UNAVAILABLE: '期刊库未就绪(种子数据缺失),请联系管理员。', + TIMEOUT: '请求超时,请稍后重试。', + NETWORK: '网络异常,请检查连接后重试。', +}; + +/** ApiError(或任意错误)→ 用户可读文案。degraded 由调用方读 err.degraded 走降级横幅样式。 */ +export function reviewErrorMessage(err) { + if (err instanceof ApiError) { + const hint = CODE_HINTS[err.code]; + if (hint) return hint; + if (err.message) return err.message; // VALIDATION 等:后端原话 + } + return '服务异常,请稍后重试'; +} diff --git a/ui/src/components/edu/EduSideNav.vue b/ui/src/components/edu/EduSideNav.vue new file mode 100644 index 0000000..4e89d4f --- /dev/null +++ b/ui/src/components/edu/EduSideNav.vue @@ -0,0 +1,114 @@ + + + + + + diff --git a/ui/src/components/edu/EduWorkspace.vue b/ui/src/components/edu/EduWorkspace.vue new file mode 100644 index 0000000..051a5c7 --- /dev/null +++ b/ui/src/components/edu/EduWorkspace.vue @@ -0,0 +1,62 @@ + + + + + + diff --git a/ui/src/components/edu/panels/CalendarPanel.vue b/ui/src/components/edu/panels/CalendarPanel.vue new file mode 100644 index 0000000..93100d6 --- /dev/null +++ b/ui/src/components/edu/panels/CalendarPanel.vue @@ -0,0 +1,418 @@ + + + + + + diff --git a/ui/src/components/edu/panels/FormatPanel.vue b/ui/src/components/edu/panels/FormatPanel.vue new file mode 100644 index 0000000..14f6db4 --- /dev/null +++ b/ui/src/components/edu/panels/FormatPanel.vue @@ -0,0 +1,495 @@ + + + + + + diff --git a/ui/src/components/edu/panels/JournalsPanel.vue b/ui/src/components/edu/panels/JournalsPanel.vue new file mode 100644 index 0000000..983a7ed --- /dev/null +++ b/ui/src/components/edu/panels/JournalsPanel.vue @@ -0,0 +1,779 @@ + + + + + + diff --git a/ui/src/components/edu/panels/PresubmitPanel.vue b/ui/src/components/edu/panels/PresubmitPanel.vue new file mode 100644 index 0000000..308c0a2 --- /dev/null +++ b/ui/src/components/edu/panels/PresubmitPanel.vue @@ -0,0 +1,614 @@ + + + + + + diff --git a/ui/src/components/edu/panels/RecommendPanel.vue b/ui/src/components/edu/panels/RecommendPanel.vue new file mode 100644 index 0000000..1bf6391 --- /dev/null +++ b/ui/src/components/edu/panels/RecommendPanel.vue @@ -0,0 +1,507 @@ + + + + + + diff --git a/ui/src/components/edu/panels/ReformatPanel.vue b/ui/src/components/edu/panels/ReformatPanel.vue new file mode 100644 index 0000000..dd049a2 --- /dev/null +++ b/ui/src/components/edu/panels/ReformatPanel.vue @@ -0,0 +1,812 @@ + + + + + + diff --git a/ui/src/components/edu/panels/ReportPanel.vue b/ui/src/components/edu/panels/ReportPanel.vue new file mode 100644 index 0000000..15dddf2 --- /dev/null +++ b/ui/src/components/edu/panels/ReportPanel.vue @@ -0,0 +1,420 @@ + + + + + + diff --git a/ui/src/components/edu/panels/TrackerPanel.vue b/ui/src/components/edu/panels/TrackerPanel.vue new file mode 100644 index 0000000..9181eb5 --- /dev/null +++ b/ui/src/components/edu/panels/TrackerPanel.vue @@ -0,0 +1,394 @@ + + + + + + diff --git a/ui/src/components/edu/panels/TrainingPanel.vue b/ui/src/components/edu/panels/TrainingPanel.vue new file mode 100644 index 0000000..8da7ff2 --- /dev/null +++ b/ui/src/components/edu/panels/TrainingPanel.vue @@ -0,0 +1,16 @@ + + + + + + diff --git a/ui/src/components/layout/TopBar.vue b/ui/src/components/layout/TopBar.vue index a2362d0..399b3a2 100644 --- a/ui/src/components/layout/TopBar.vue +++ b/ui/src/components/layout/TopBar.vue @@ -14,6 +14,7 @@ import { APP_NAME, STATUS_LABEL, T } from '../../i18n/labels.js'; import { BF } from '../../i18n/bioflow.js'; import { useThemeStore } from '../../stores/theme.js'; import { useBioflowStore } from '../../stores/bioflow.js'; +import { useAppStore } from '../../stores/app.js'; const props = defineProps({ /** 当前会话标题(无会话为 null → 显示「就绪」徽章) */ @@ -40,6 +41,9 @@ const bioflowStore = useBioflowStore(); const bioflowOnline = computed(() => bioflowStore.availability === 'online'); const bioflowStatus = computed(() => bioflowStore.availability); +/* ---------- 教育科研入口(步骤5;覆盖层视图切换 D1,同 themeStore 静态导入) ---------- */ +const appStore = useAppStore(); + /* ---------- B2/B3 store 数据(动态导入 + 空值守卫) ---------- */ const chatStore = ref(null); const benchStore = ref(null); @@ -160,6 +164,8 @@ const iconClose = ' 生信 + +