Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
fd675a1
Sync main to dev (#444)
e06084 Jul 2, 2026
398089c
feat: DatasetSqlArgs添加engine_args属性
shijinpjlab Jul 6, 2026
f704458
🎨 Auto-format code with pre-commit
actions-user Jul 6, 2026
b14f7c7
Merge pull request #445 from shijinpjlab/dev_0706
shijinpjlab Jul 6, 2026
d94c9cd
feat: score实时更新
shijinpjlab Jul 10, 2026
a2933d0
feat: ci update
shijinpjlab Jul 10, 2026
8c263a5
Merge pull request #447 from shijinpjlab/dev_0710
shijinpjlab Jul 10, 2026
0ba34f0
feat: SummaryModel增加type_count
shijinpjlab Jul 13, 2026
e902395
feat: refresh_type_ratio传参逻辑更新
shijinpjlab Jul 13, 2026
450c3d7
feat: summarize增加refresh_type_ratio参数
shijinpjlab Jul 13, 2026
555153e
Merge pull request #448 from shijinpjlab/dev_0710
shijinpjlab Jul 13, 2026
f3a1023
feat(retrieval): add search result quality evaluation
pekopoke Jul 14, 2026
da45cae
🎨 Auto-format code with pre-commit
actions-user Jul 14, 2026
fd889c1
feat(retrieval): add search result quality evaluation
pekopoke Jul 14, 2026
05f1728
feat(retrieval): add search result quality evaluation
pekopoke Jul 14, 2026
a34b7de
Merge remote-tracking branch 'origin/feature/lld-IR' into feature/lld-IR
pekopoke Jul 14, 2026
3f6b94b
feat(retrieval): add search result quality evaluation
pekopoke Jul 14, 2026
080cf85
feat(retrieval): add search result quality evaluation
pekopoke Jul 15, 2026
3f8a8f2
feat(retrieval): add search result quality evaluation
pekopoke Jul 16, 2026
2f8c271
feat(retrieval): add search result quality evaluation
pekopoke Jul 21, 2026
37fd391
Merge pull request #449 from pekopoke/feature/lld-IR
e06084 Jul 21, 2026
463e2e2
feat: update rule
shijinpjlab Jul 22, 2026
4d11f89
feat: 国标文本困惑程度 PPL
shijinpjlab Jul 23, 2026
e55f256
feat: 国标类型一致性
shijinpjlab Jul 24, 2026
7dd93dc
feat: ci修复
shijinpjlab Jul 24, 2026
8608631
🎨 Auto-format code with pre-commit
actions-user Jul 24, 2026
fcb11f0
Merge pull request #451 from shijinpjlab/dev_0722
shijinpjlab Jul 24, 2026
1983374
feat: 国标说明文档4个rule
shijinpjlab Jul 24, 2026
cdf1bb2
feat: md更新
shijinpjlab Jul 24, 2026
f0608d5
Merge remote-tracking branch 'upstream/dev' into dev_0722
shijinpjlab Jul 24, 2026
04e4563
feat: ci test
shijinpjlab Jul 24, 2026
9b213e4
🎨 Auto-format code with pre-commit
actions-user Jul 24, 2026
9099428
Merge pull request #452 from shijinpjlab/dev_0724
shijinpjlab Jul 24, 2026
636506b
feat: Lint不可以直接修改代码
shijinpjlab Jul 27, 2026
0581fd1
feat: 国标模型应用-内容时效性
shijinpjlab Jul 27, 2026
cdfc8c8
feat: md更新
shijinpjlab Jul 27, 2026
beb5a11
feat(retrieval): add end-to-end search result evaluation
pekopoke Jul 27, 2026
bc2e018
Merge remote-tracking branch 'upstream/dev' into feature/lld-IR
pekopoke Jul 27, 2026
ffe5b13
feat: lint
shijinpjlab Jul 27, 2026
479b956
feat: 国标类名
shijinpjlab Jul 27, 2026
6e797e5
feat: lint
shijinpjlab Jul 27, 2026
9843cc5
Merge pull request #454 from shijinpjlab/dev_0727
shijinpjlab Jul 27, 2026
2cabea7
feat: 支持md类型文件
shijinpjlab Jul 27, 2026
5477638
Merge pull request #455 from shijinpjlab/dev_0727_1610
shijinpjlab Jul 27, 2026
15e4d20
feat: 国标全部rule添加
shijinpjlab Jul 28, 2026
f9e41fe
feat: 国标目录
shijinpjlab Jul 28, 2026
d825e69
feat: 国标test
shijinpjlab Jul 28, 2026
29ca958
feat: 重构,抽出来基类
shijinpjlab Jul 28, 2026
030c77a
feat: 类名排序
shijinpjlab Jul 28, 2026
b50b6f6
feat: 重命名Rule_TC609_01_DocCompleteness
shijinpjlab Jul 28, 2026
dbc4e99
feat: 重命名Rule_TC609_Composite
shijinpjlab Jul 28, 2026
e098830
feat: 国标group优化
shijinpjlab Jul 28, 2026
f8065d0
feat: rename
shijinpjlab Jul 28, 2026
2efdc87
feat: lint
shijinpjlab Jul 28, 2026
1ffc140
Merge pull request #456 from shijinpjlab/dev_0728
shijinpjlab Jul 28, 2026
50bfb55
feat: 目录遍历,文件类型限制
shijinpjlab Jul 28, 2026
99f83af
Merge pull request #457 from shijinpjlab/dev_0728_1843
shijinpjlab Jul 28, 2026
3231266
feat: add token usage
e06084 Jul 29, 2026
abf2222
📚 Auto-update metrics documentation
actions-user Jul 29, 2026
d55c0ea
Merge pull request #459 from e06084/dev
e06084 Jul 29, 2026
9782209
feat: Rule_TC609_0201_FormatCompliance
shijinpjlab Jul 29, 2026
b0da972
feat: Rule_TC609_0201_FormatCompliance支持allow_extra
shijinpjlab Jul 29, 2026
9f4e782
feat: RuleUnsafeWords性能优化
shijinpjlab Jul 29, 2026
d5405b1
feat: 重写Rule_TC609_0203_AnnotationCompliance
shijinpjlab Jul 30, 2026
7c651be
feat: 重写Rule_TC609_0204_StructuralCompleteness
shijinpjlab Jul 30, 2026
3ee7267
feat: 重写Rule_TC609_0205_ContentAuthenticity
shijinpjlab Jul 30, 2026
1c8e1f0
feat: 重写Rule_TC609_0206_ContentConsistency
shijinpjlab Jul 30, 2026
9dfa8b0
feat: RuleWatermark优化,key-list为空报错
shijinpjlab Jul 30, 2026
69073e0
feat: Rule_TC609_0208_ContentCleanliness 传参
shijinpjlab Jul 30, 2026
8686785
feat: 无用init
shijinpjlab Jul 30, 2026
51af2dd
feat: lint
shijinpjlab Jul 30, 2026
c210a0b
Merge pull request #460 from shijinpjlab/dev_0729
shijinpjlab Jul 30, 2026
b7be72a
Merge pull request #453 from pekopoke/feature/lld-IR
e06084 Jul 30, 2026
8cd64e2
feat: Rule_TC609_0201_FormatCompliance 默认值
shijinpjlab Jul 31, 2026
08e2d64
fix: LLMPerspective: UnboundLocalError: cannot access local variable …
e06084 Jul 31, 2026
5d2f6bc
feat: Rule_TC609_0202_SafetyCompliance 默认的安全词
shijinpjlab Jul 31, 2026
147d581
fix
e06084 Jul 31, 2026
11e46b7
feat: Rule_TC609_0203_AnnotationCompliance 重写
shijinpjlab Jul 31, 2026
85eea67
feat: Rule_TC609_0204_StructuralCompleteness 默认值
shijinpjlab Jul 31, 2026
d90869f
feat: Rule_TC609_0205_ContentAuthenticity 重写
shijinpjlab Jul 31, 2026
d092d95
feat: Rule_TC609_0206_ContentConsistency 重写
shijinpjlab Jul 31, 2026
500dbaa
feat: Rule_TC609_0207_DataTypeConsistency 重写
shijinpjlab Jul 31, 2026
97092e6
feat: Rule_TC609_0208_ContentCleanliness 更新输入字段
shijinpjlab Jul 31, 2026
522e23a
feat: Rule_TC609_0202_SafetyCompliance 更新输入字段
shijinpjlab Jul 31, 2026
a5ed48f
feat: 国标 LLM 0101-0104
shijinpjlab Jul 31, 2026
a8ee1c0
fix: 移除全局 HF 镜像注入,改为文档按需指导
e06084 Jul 31, 2026
84b9dd3
Merge pull request #461 from e06084/dev
e06084 Jul 31, 2026
6590bec
fix: HHEM 回填 score 并修复示例格式化 None 崩溃
e06084 Jul 31, 2026
b2aa6bc
fix: 隔离 lmdeploy 并限制 transformers<4.49 以修复 HHEM 加载失败
e06084 Jul 31, 2026
42bd3d5
📚 Auto-update metrics documentation
actions-user Jul 31, 2026
970cc84
Merge pull request #462 from e06084/dev
e06084 Jul 31, 2026
2423152
feat: rule md更新,tc609 未支持,则不显示
shijinpjlab Aug 3, 2026
b90faf2
feat: lint
shijinpjlab Aug 3, 2026
eb4d024
Merge remote-tracking branch 'upstream/dev' into dev_0729
shijinpjlab Aug 3, 2026
a325a8d
feat: add perspective check example
e06084 Aug 3, 2026
3de0272
Merge pull request #465 from e06084/dev
e06084 Aug 3, 2026
444929e
feat: update test
shijinpjlab Aug 3, 2026
85993b0
feat: update test
shijinpjlab Aug 3, 2026
08ec1fe
Merge pull request #464 from shijinpjlab/dev_0729
shijinpjlab Aug 3, 2026
db594fb
feat: RuleHallucinationHHEM 底层模型改用 MiniCheck-Flan-T5-Large
e06084 Aug 4, 2026
9260291
📚 Auto-update metrics documentation
actions-user Aug 4, 2026
c616673
Merge pull request #466 from e06084/dev
e06084 Aug 4, 2026
e212cf0
feat: update setup v2.5.0
shijinpjlab Aug 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 5 additions & 30 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ name: Lint

on: [push, pull_request]

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
Expand Down Expand Up @@ -29,33 +32,5 @@ jobs:
run: |
python .github/scripts/check_imports.py

- name: Run pre-commit (auto-fix)
id: pre_commit_auto_fix
run: |
# 运行 pre-commit,允许自动修复,不因修复而失败
pre-commit run --all-files || true

- name: Check for changes
id: check_changes
run: |
if [[ -n $(git status --porcelain) ]]; then
echo "changed=true" >> $GITHUB_OUTPUT
echo "📝 Files were modified by pre-commit auto-fix"
else
echo "changed=false" >> $GITHUB_OUTPUT
echo "✅ No auto-fix changes"
fi

- name: Commit auto-fix changes
if: steps.check_changes.outputs.changed == 'true' && github.event_name == 'push'
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add -A
git commit -m "🎨 Auto-format code with pre-commit"
git push

- name: Run pre-commit (final check)
run: |
# 再次运行 pre-commit,这次如果有错误就真的失败
pre-commit run --all-files
- name: Run pre-commit
run: pre-commit run --all-files
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ dingo/
│ │ ├── rule/ ← Rule-based evaluators (80+ built-in)
│ │ │ ├── base.py ← BaseRule
│ │ │ ├── rule_common.py ← Common rules (text quality, format, PII, etc.)
│ │ │ ├── guobiao/
│ │ │ │ └── rule_tc609_quality.py ← TC609 quality metrics and placeholders
│ │ │ ├── rule_search_ranking.py ← IR ranking metrics (NDCG, MRR, Recall, Precision, MAP, HitRate)
│ │ │ └── utils/ ← Shared utilities (normalize, ngrams, etc.)
│ │ └── llm/ ← LLM-based evaluators
Expand Down
4 changes: 1 addition & 3 deletions dingo/config/input_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class DatasetSqlArgs(BaseModel):
port: str = ''
database: str = ''
connect_args: str = '' # 连接参数,如 ?charset=utf8mb4
engine_args: str = '' # SQLAlchemy 引擎参数,如 pool_recycle=1800&pool_pre_ping=true


class DatasetExcelArgs(BaseModel):
Expand Down Expand Up @@ -193,6 +194,3 @@ class InputArgs(BaseModel):
dataset: DatasetArgs = DatasetArgs()
executor: ExecutorArgs = ExecutorArgs()
evaluator: List[EvalPipline] = []

def __init__(self, **kwargs):
super().__init__(**kwargs)
17 changes: 17 additions & 0 deletions dingo/data/converter/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,23 @@ def _convert(raw: Union[str, Dict]):
return _convert


@BaseConverter.register("md")
class MarkdownConverter(BaseConverter):
"""Markdown file converter."""

def __init__(self):
super().__init__()

@classmethod
def convertor(cls, input_args: InputArgs) -> Callable:
def _convert(raw: Union[str, Dict]):
if isinstance(raw, Dict):
return Data(**raw)
return Data(**{"id": "", "content": str(raw)})

return _convert


@BaseConverter.register("jsonl")
class JsonLineConverter(BaseConverter):
"""Json line file converter."""
Expand Down
50 changes: 46 additions & 4 deletions dingo/data/datasource/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def to_dict(self) -> Dict[str, Any]:
"config_name": self.config_name,
}

def load(self, **kwargs) -> Generator[str, None, None]:
def load(self, **kwargs) -> Generator[Any, None, None]:
"""Load the local file dataset based on `LocalDataSource`.
Args:
kwargs: Additional keyword arguments used for loading the dataset.
Expand All @@ -51,10 +51,39 @@ def _find_all_files(self, path: str, file_list: List[str]):
for _f in os.listdir(path):
f = os.path.join(path, _f)
if os.path.isfile(f):
file_list.append(f)
if getattr(self.input_args.dataset, "format", None) == "jsonl":
if f.lower().endswith(".jsonl"):
file_list.append(f)
elif getattr(self.input_args.dataset, "format", None) == "json":
if f.lower().endswith(".json"):
file_list.append(f)
elif getattr(self.input_args.dataset, "format", None) == "md":
if f.lower().endswith(".md"):
file_list.append(f)
else:
file_list.append(f)
if os.path.isdir(f):
self._find_all_files(f, file_list)

@staticmethod
def _load_md_file(path: str) -> Dict[str, str]:
try:
with open(path, "r", encoding="utf-8") as md_file:
return {
"id": os.path.basename(path),
"content": md_file.read(),
}
except UnicodeDecodeError as decode_error:
raise RuntimeError(
f'Failed to read markdown file "{path}": Unsupported file encoding. '
f'Markdown files must be UTF-8 encoded. Original error: {str(decode_error)}'
)
except Exception as e:
raise RuntimeError(
f'Unexpected error reading markdown file "{path}": {str(e)}. '
f'Please check if the file exists and is readable.'
)

def _load_excel_file_xlsx(self, path: str) -> Generator[str, None, None]:
"""
Load an .xlsx Excel file and return its contents row by row as JSON strings.
Expand Down Expand Up @@ -377,7 +406,7 @@ def _load_excel_file_xls(self, path: str) -> Generator[str, None, None]:
if wb:
wb.release_resources()

def _load_local_file(self) -> Generator[str, None, None]:
def _load_local_file(self) -> Generator[Any, None, None]:
"""
Load a local file and return its contents.

Expand All @@ -390,14 +419,27 @@ def _load_local_file(self) -> Generator[str, None, None]:
raise RuntimeError(f'"{self.path}" is not a valid path')

f_list = []
input_is_file = os.path.isfile(self.path)
if os.path.exists(self.path) and os.path.isfile(self.path):
f_list = [self.path]
elif os.path.exists(self.path) and os.path.isdir(self.path):
self._find_all_files(self.path, f_list)

by_line = self.input_args.dataset.format not in ["json", "listjson", "mineru", "mineru_v2"]
by_line = self.input_args.dataset.format not in ["json", "listjson", "mineru", "mineru_v2", "md"]

for f in f_list:
if self.input_args.dataset.format == "md":
if f.lower().endswith(".md"):
yield self._load_md_file(f)
elif input_is_file:
raise RuntimeError(
f'Input file "{self.path}" is not a markdown file. '
f'Please provide a ".md" file or a directory containing ".md" files when dataset.format is "md".'
)
else:
continue
continue

# Check if file is CSV
if f.endswith('.csv'):
if self.input_args.dataset.format != 'csv':
Expand Down
142 changes: 117 additions & 25 deletions dingo/data/datasource/sql.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
from typing import Any, Dict, Generator, Optional
from urllib.parse import parse_qsl

from sqlalchemy import create_engine, text
from sqlalchemy.engine import Engine
from sqlalchemy.engine import URL, Engine

from dingo.config import InputArgs
from dingo.data.datasource.base import DataSource


@DataSource.register()
class SqlDataSource(DataSource):
_ENGINE_ARG_TYPES = {
"pool_pre_ping": "bool",
"pool_recycle": "int",
"pool_size": "int",
"max_overflow": "int",
"pool_timeout": "int",
}

def __init__(
self,
input_args: InputArgs = None,
Expand All @@ -33,37 +42,120 @@ def _get_engine(sql_config) -> Engine:
"must be set when using SQL datasource."
)

# 构建数据库连接URL
# SQLite 格式: sqlite:///path/to/database.db
# 其他数据库格式: dialect+driver://username:password@host:port/database
if sql_config.dialect.lower() == "sqlite":
driver_part = f"+{sql_config.driver}" if sql_config.driver else ""
connection_url = f"{sql_config.dialect}{driver_part}:///{sql_config.database}"
else:
# 对于非 SQLite 数据库,需要用户名、密码和主机
if not sql_config.username or not sql_config.host:
dialect = sql_config.dialect.lower()
query_args = SqlDataSource._parse_connect_args(sql_config.connect_args)

connection_url = SqlDataSource._build_connection_url(sql_config, query_args)

engine_kwargs: Dict[str, Any] = {"pool_pre_ping": True}
if dialect in {"mysql", "mariadb"}:
engine_kwargs["pool_recycle"] = 1800
engine_kwargs.update(SqlDataSource._parse_engine_args(sql_config.engine_args))

engine = create_engine(connection_url, **engine_kwargs)
return engine

@staticmethod
def _build_driver_name(sql_config) -> str:
return (
f"{sql_config.dialect}+{sql_config.driver}"
if sql_config.driver
else sql_config.dialect
)

@staticmethod
def _parse_connect_args(connect_args: str) -> Dict[str, str]:
return SqlDataSource._parse_query_arg_string(connect_args)

@staticmethod
def _parse_query_arg_string(raw_arg_string: str) -> Dict[str, str]:
if not raw_arg_string:
return {}
normalized = raw_arg_string.strip()
if normalized.startswith("?"):
normalized = normalized[1:]
if not normalized:
return {}
return {
key: value
for key, value in parse_qsl(normalized, keep_blank_values=False)
if key
}

@staticmethod
def _parse_bool_value(raw_value: str, key: str) -> bool:
normalized = raw_value.strip().lower()
if normalized == "true":
return True
if normalized == "false":
return False
raise RuntimeError(
f"SQL engine arg '{key}' expects 'true' or 'false', got: {raw_value}."
)

@staticmethod
def _parse_engine_args(engine_args: str) -> Dict[str, Any]:
raw_engine_args = SqlDataSource._parse_query_arg_string(engine_args)
if not raw_engine_args:
return {}

parsed_engine_args: Dict[str, Any] = {}
for key, raw_value in raw_engine_args.items():
expected_type = SqlDataSource._ENGINE_ARG_TYPES.get(key)
if expected_type is None:
allowed = ", ".join(sorted(SqlDataSource._ENGINE_ARG_TYPES.keys()))
raise RuntimeError(
f"For {sql_config.dialect}, username and host must be set."
f"Unsupported SQL engine arg '{key}'. Allowed keys: {allowed}."
)

driver_part = f"+{sql_config.driver}" if sql_config.driver else ""
port_part = f":{sql_config.port}" if sql_config.port else ""
password_part = f":{sql_config.password}" if sql_config.password else ""
if expected_type == "int":
try:
parsed_engine_args[key] = int(raw_value)
except ValueError as exc:
raise RuntimeError(
f"SQL engine arg '{key}' expects an integer value, got: {raw_value}."
) from exc
elif expected_type == "bool":
parsed_engine_args[key] = SqlDataSource._parse_bool_value(raw_value, key)

return parsed_engine_args

@staticmethod
def _parse_port(port: str) -> Optional[int]:
if not port:
return None
try:
return int(port)
except ValueError as exc:
raise RuntimeError("SQL connection parameter 'port' must be an integer.") from exc

connection_url = (
f"{sql_config.dialect}{driver_part}://"
f"{sql_config.username}{password_part}@"
f"{sql_config.host}{port_part}/{sql_config.database}"
@staticmethod
def _build_connection_url(sql_config, query_args: Dict[str, str]) -> URL:
driver_name = SqlDataSource._build_driver_name(sql_config)
query = query_args or None

if sql_config.dialect.lower() == "sqlite":
return URL.create(
drivername=driver_name,
database=sql_config.database,
query=query,
)

# 添加连接参数(如 ?charset=utf8mb4)
if sql_config.connect_args:
# 确保参数以 ? 开头
args_part = sql_config.connect_args if sql_config.connect_args.startswith('?') else f"?{sql_config.connect_args}"
connection_url = f"{connection_url}{args_part}"
# 对于非 SQLite 数据库,需要用户名、密码和主机
if not sql_config.username or not sql_config.host:
raise RuntimeError(
f"For {sql_config.dialect}, username and host must be set."
)

engine = create_engine(connection_url)
return engine
return URL.create(
drivername=driver_name,
username=sql_config.username,
password=sql_config.password or None,
host=sql_config.host,
port=SqlDataSource._parse_port(sql_config.port),
database=sql_config.database,
query=query,
)

@staticmethod
def get_source_type() -> str:
Expand Down
Loading
Loading