Skip to content

Commit 4416a44

Browse files
committed
v1.4.0: fix ~85 bugs (author disambiguation, rankings, rate limits), add HTML/map/tree/CSV exports, FWCI, CLI, and test suite
1 parent 363091e commit 4416a44

61 files changed

Lines changed: 13735 additions & 588 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/tests.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
jobs:
9+
test:
10+
runs-on: ubuntu-latest
11+
strategy:
12+
matrix:
13+
python-version: ['3.9', '3.11', '3.12']
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: actions/setup-python@v5
17+
with:
18+
python-version: ${{ matrix.python-version }}
19+
cache: pip
20+
- name: Install dependencies
21+
run: |
22+
python -m pip install --upgrade pip
23+
pip install -r requirements.txt pytest
24+
- name: Run tests
25+
env:
26+
PYTEST_DISABLE_PLUGIN_AUTOLOAD: '1'
27+
run: python -m pytest tests/ -v

.gitignore

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# User data — contains API keys, cached results, and settings. Never commit.
2+
.citationimpact/
3+
.CitationImpact/
4+
5+
# Python
6+
__pycache__/
7+
*.py[cod]
8+
*.egg-info/
9+
build/
10+
dist/
11+
.eggs/
12+
13+
# Tooling
14+
.pytest_cache/
15+
.mypy_cache/
16+
.ruff_cache/
17+
.coverage
18+
htmlcov/
19+
20+
# Environments
21+
.venv/
22+
venv/
23+
24+
# Editors / OS
25+
.vscode/
26+
.idea/
27+
.DS_Store
28+
29+
# Exported reports (generated output)
30+
impact_report_*.json

CHANGELOG.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# Changelog
2+
3+
## 1.4.0 (2026-07-13)
4+
5+
### New output formats
6+
- **CSV bundle** (`--format bundle`): writes `citing_papers.csv`, `authors.csv`
7+
(with country + match confidence), `venues.csv`, and `timeline.csv` into one
8+
directory for spreadsheet analysis.
9+
- **Citation tree**: interactive terminal tree (menu option 8, groupable by
10+
year / venue / institution) and a plain-text export (`--format tree`).
11+
- **HTML report** (`--format html`): a single self-contained HTML file with
12+
stat tiles, citation timeline chart, world map of citing institutions,
13+
citation-intent chart with context quotes, scholar/venue tables, and a
14+
collapsible citation tree. Works offline, light/dark aware.
15+
16+
### International reach
17+
- Citing authors' institution **countries** are now captured from OpenAlex
18+
(ISO codes on every author, a per-country breakdown in results, a
19+
"cited across N countries" grant statement, country column in exports).
20+
21+
### Reliability
22+
- Live end-to-end testing caught and fixed a crash: OpenAlex returns explicit
23+
`null` for `summary_stats` / `last_known_institutions` / `affiliations` on
24+
some records; all parsing sites are now null-safe (regression-tested).
25+
- `max_citations` is clamped to Semantic Scholar's 1000-limit in API mode
26+
instead of failing with HTTP 400.
27+
- Full-diff regression audit confirmed and fixed 10 defects introduced during
28+
the sprint, including: Google Scholar citation IDs leaking from one analysis
29+
into the next; OpenAlex title lookups breaking on commas (filter injection);
30+
author dedup creating "chimera" entries (one person's identity with another's
31+
h-index); Rich-markup crashes on citation text containing bracket tokens
32+
(e.g. `[/INST]`, `[sic]`); scripted `-o -` output polluted by progress
33+
prints (now on stderr); explicit `--h-index-threshold 0` being ignored;
34+
12-letter surnames misread as Google Scholar IDs.
35+
- Data-quality safeguards: correct Semantic Scholar request pacing with an API
36+
key (was 40 req/s against a ~1 req/s allowance, causing silent mass
37+
failures), `Retry-After` honored on 429s, per-run API-failure tracking with a
38+
visible "data may be incomplete" banner in the UI and all report formats, and
39+
degraded results are no longer written to the 7-day cache. The alarm is
40+
proportional: a few transient failures produce a note, not the banner.
41+
- **Batch author fetching**: citing-author profiles are now fetched from
42+
Semantic Scholar's batch endpoint (one request for up to 500 authors instead
43+
of one per author), then enriched via OpenAlex as before — analyses make an
44+
order of magnitude fewer requests and survive strict rate limits.
45+
- **Adaptive throttle**: consecutive rate-limit failures automatically slow
46+
request pacing (up to 8×) and recover on success. OpenAlex now runs at half
47+
its polite-pool allowance by default; set your email in Settings to join the
48+
polite pool (dramatically more reliable than anonymous access).
49+
50+
## 1.3.1 (2026-07-12)
51+
52+
### Author disambiguation overhaul (fixes reported same-name mix-ups)
53+
Addresses the reported issue where authors sharing a name could be mistaken
54+
for each other. Author resolution is now **ID-first with evidence-verified
55+
fallbacks**:
56+
57+
- Every resolved author profile carries a `match_confidence` provenance:
58+
`id` (unique Semantic Scholar / Google Scholar identifier), `verified`
59+
(name search corroborated by the candidate's publication list), or
60+
`name` (unverified name-only match).
61+
- Name-keyed author-cache hits are now **gated**: a cached profile that
62+
merely shares an author's name is only reused when its stored publications
63+
contain the citing paper. Unverifiable name hits are rejected rather than
64+
trusted.
65+
- **Browse Other Authors by name** now shows a disambiguation picker
66+
(name, affiliation, h-index, paper count from Semantic Scholar author
67+
search) instead of silently using the first same-named hit.
68+
- The UI marks each author with ✓ (ID-matched), ≈ (verified), or ? (name-only,
69+
may be a different person), with a legend; the summary shows
70+
"Author profiles: N ID-matched, N verified, N name-only", and the Markdown
71+
export gains a Match column.
72+
- Exports now use the configured h-index threshold in their labels instead of
73+
a hardcoded "≥ 20".
74+
75+
## 1.3.0 (2026-07-12)
76+
77+
### New features
78+
- **Field-normalized impact (FWCI)**: analyses now fetch the Field-Weighted
79+
Citation Impact and field citation percentile from OpenAlex (1.0 = world
80+
average for the same field/year), shown in the overview, grant summary,
81+
impact statements, and exports. Degrades gracefully when unavailable.
82+
- **Self-citation detection**: every analysis now reports how many citations
83+
are independent of the original authors (matched by Semantic Scholar author
84+
ID, falling back to name compatibility) — the number grant reviewers ask for.
85+
- **"How Your Work Is Used"**: new drill-down (option 7) showing the citation
86+
intent distribution (methodology / background / result) and sample in-text
87+
context quotes from citing papers.
88+
- **Report exporter** (`citationimpact/export.py`): export analyses as
89+
grant-ready **Markdown**, **LaTeX** (appendix-ready section), **CSV** (all
90+
citing papers), **BibTeX**, or JSON — from the results screen (`e`) or the CLI.
91+
- **Non-interactive CLI** (`citationimpact/cli.py`): script the tool without
92+
menus — `citation-impact analyze "Paper title" --format markdown -o report.md`,
93+
`citation-impact cache list|clear`, `citation-impact --version`.
94+
Running `./citation-impact` with no arguments still opens the interactive UI.
95+
- **Test suite**: 200+ pytest tests covering exporters, models, categorization,
96+
rankings, caches, analyzer logic, clients, UI helpers, and the CLI.
97+
- **CI**: GitHub Actions workflow running the suite on Python 3.9–3.12.
98+
99+
### Bug fixes (72 verified defects, found by multi-agent audit)
100+
Highlights — full details in git history:
101+
- **Institution misclassification (critical)**: substring matching classified
102+
Princeton/Cincinnati as *Industry* (`'inc'`), and any "Department of …",
103+
Newcastle, or NIST-like affiliation as *Government* (`'epa'`, `'cas'`,
104+
`'nist'` substrings). Now word-boundary matched.
105+
- **Wrong university credit**: fuzzy matchers gave "National University" NUS's
106+
Top-10 rank and matched arbitrary superstring venues; QS range ranks
107+
(601-610 etc., 60% of the file) were silently dropped; ICORE junk strings
108+
("Unranked", "TBR") were surfaced as ranks.
109+
- **Dead features revived**: methodological citations (S2 returns lowercase
110+
intents), Crossref citation-count/venue merging (key mismatch/unreachable
111+
branch), S2 DOI enrichment (externalIds never requested), ORCID fallback
112+
(wrong class name + list/dict mismatch), DBLP author publications
113+
(nonexistent endpoint), GS-only papers yielding 0 citations in
114+
comprehensive mode.
115+
- **Crashes fixed**: google_scholar mode signature mismatches, unified
116+
search_paper on zero-score results, null citationCounts, ORCID null-name
117+
records, QS range-rank parsing, None affiliations.
118+
- **Correctness**: author dedup no longer merges distinct authors (first-initial
119+
guard) and no longer loses repeat citers' papers; publication-overlap cache
120+
matching no longer attributes co-authors' profiles to each other; author-profile
121+
cache no longer merges same-name researchers; grant statements no longer
122+
conflate author counts with university counts and respect the configured
123+
h-index threshold; citation URLs no longer dropped by an operator-precedence
124+
bug; "recent citations" now really spans 2 years.
125+
- **Robustness**: config writes are atomic (API keys can't be destroyed by a
126+
failed save); connection errors are retried; cache expiry handles unlink
127+
races; UTF-8 enforced for profile files; shared client no longer reused
128+
across data-source switches (stale-mode analyses); browse-author-by-name
129+
works in API mode; Selenium clients are tracked and closed.
130+
131+
### Packaging & hygiene
132+
- `setup.py` console entry point referenced a nonexistent module; now installs
133+
working `citation-impact` / `citationimpact-ui` commands; version
134+
single-sourced from `citationimpact/__init__.py` (was 0.1.0 vs 1.2.0).
135+
- Added `pyproject.toml`, `.gitignore` (the `.citationimpact/` folder holding
136+
plaintext API keys was previously trackable), and untracked committed
137+
`__pycache__` files.
138+
139+
## 1.2.0
140+
141+
- Prior release (see git history).

README.md

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,18 @@ I built CitationImpact to answer these questions automatically. Instead of manua
3030
CitationImpact analyzes your research citations and generates **grant-ready impact statements**:
3131

3232
- 📋 **Grant Impact Summary** – Copy-ready statements for proposals & tenure files
33+
- 🆔 **ID-first author matching** – Unique Semantic Scholar/Google Scholar IDs with publication-verified fallbacks; every author is marked ✓ ID-matched, ≈ verified, or ? name-only so you can trust the numbers
34+
- 🌍 **Field-normalized impact** – FWCI & citation percentile from OpenAlex ("cited 4.2× the world average for its field")
35+
- 🙋 **Self-citation detection** – Reports what % of citations are independent of the original authors
36+
- 💬 **How your work is used** – Citation intent breakdown (methodology/background/result) with in-text quotes
3337
- 🏆 **Highly-Cited Papers** – Papers with 100+ citations that cite YOUR work
3438
- 👥 **High-profile scholars** – Prominent researchers (by h-index & total citations) citing your work
3539
- 🏛️ **Institution breakdown** – Universities (with QS/US News rankings), Industry, Government
3640
- 📚 **Venue quality** – Top-tier journals/conferences (CORE, CCF, h-index rankings)
3741
- 📈 **Citation velocity** – Track your impact over time with timeline visualization
3842
- 🔗 **Clickable links** – Every author and paper is linked to their profile
3943
- 💾 **Smart caching** – Never wait twice for the same analysis (user-controlled refresh)
44+
- 📤 **Grant-ready exports** – Markdown, LaTeX, CSV, BibTeX, JSON (interactive or via CLI)
4045

4146
---
4247

@@ -56,6 +61,14 @@ pip install -r requirements.txt
5661

5762
That's it! The interactive menu will guide you through the rest.
5863

64+
Prefer scripting? There's a non-interactive mode too:
65+
66+
```bash
67+
./citation-impact analyze "Your Paper Title" --format markdown -o report.md
68+
./citation-impact analyze "Your Paper Title" --format latex -o - # print to stdout
69+
./citation-impact cache list
70+
```
71+
5972
<p align="center">
6073
<img src="assets/Screenshot1-start.png" alt="Main Menu" width="700"/>
6174
</p>
@@ -91,9 +104,9 @@ That's it! The interactive menu will guide you through the rest.
91104
Want to analyze papers by someone else?
92105

93106
1. Select **"3. 👤 Browse Other Authors"**
94-
2. Enter their **Semantic Scholar ID** or **Google Scholar ID**
95-
3. Pick a paper from the list
96-
4. Analyze it with one click
107+
2. Enter their **Semantic Scholar ID** or **Google Scholar ID** (most accurate), or just their name
108+
3. If several researchers share that name, pick the right one from the candidate list (shown with affiliation, h-index, and paper count)
109+
4. Pick a paper from the list and analyze it with one click
97110

98111
**Pro tip:** Save your own author ID in Settings so "My Papers" works instantly!
99112

@@ -198,6 +211,34 @@ Example output:
198211
- Explore citation contexts
199212
- **Adaptive tables** – automatically fit your terminal width
200213

214+
### 💾 Export Formats
215+
Press `e` on any results screen (or use `--format` on the CLI) to export:
216+
217+
| Format | Best for |
218+
|--------|----------|
219+
| **HTML** (`.html`) | Shareable one-file report: charts, **world map** of citing countries, citation tree — works offline, light/dark |
220+
| **Markdown** (`.md`) | Pasting into docs, GitHub, Notion |
221+
| **LaTeX** (`.tex`) | Grant appendices – drop straight into your proposal |
222+
| **CSV** (`.csv`) | All citing papers, one row each, for spreadsheets |
223+
| **CSV bundle** (`bundle`) | Complete data dump: papers, authors, venues, timeline as separate CSVs |
224+
| **BibTeX** (`.bib`) | Reference managers (Zotero, JabRef) |
225+
| **Tree** (`.txt`) | Plain-text citation tree grouped by year |
226+
| **JSON** (`.json`) | Further scripting and analysis |
227+
228+
Reports are written to `.citationimpact/exports/` by default.
229+
230+
### 🌳 Citation Tree
231+
Menu option **8** shows every citing paper as an expandable tree — group by
232+
**year**, **venue**, or **institution type** with one keypress, every title
233+
clickable.
234+
235+
### 🛡️ Data-Quality Guarantees
236+
- If API requests fail mid-analysis (rate limits, network), the report says so
237+
with a visible **"data may be incomplete"** banner — in the terminal, HTML,
238+
Markdown, and LaTeX outputs — and the incomplete result is **not cached**.
239+
- Citation counts from different sources (Semantic Scholar vs OpenAlex) are
240+
reconciled and flagged when they disagree by more than 10%.
241+
201242
---
202243

203244
## Configuration
@@ -246,12 +287,38 @@ Cache is stored in `.citationimpact/` in your project folder. You can view stati
246287

247288
---
248289

290+
## Command-Line Mode (Scripting)
291+
292+
Everything works without the interactive menu — great for scripts and cron jobs:
293+
294+
```bash
295+
# Analyze a paper and write a grant-ready Markdown report
296+
./citation-impact analyze "Your Paper Title" --format markdown -o report.md
297+
298+
# LaTeX section for a grant appendix, printed to stdout
299+
./citation-impact analyze "Your Paper Title" --format latex -o -
300+
301+
# CSV of every citing paper / BibTeX of every citing paper
302+
./citation-impact analyze "Your Paper Title" -f csv -o citations.csv
303+
./citation-impact analyze "Your Paper Title" -f bibtex -o citations.bib
304+
305+
# Override settings per run
306+
./citation-impact analyze "Your Paper Title" --max-citations 200 --data-source api --no-cache
307+
308+
# Cache management
309+
./citation-impact cache list
310+
./citation-impact cache clear --days 30
311+
```
312+
313+
Running `./citation-impact` with no arguments opens the interactive menu as always.
314+
249315
## Python API
250316

251-
If you prefer scripting:
317+
If you prefer Python:
252318

253319
```python
254320
from citationimpact import analyze_paper_impact
321+
from citationimpact.export import export_report
255322

256323
result = analyze_paper_impact(
257324
paper_title="Your Paper Title",
@@ -266,6 +333,10 @@ print(f"Top-tier venues: {result['venues']['top_tier_percentage']:.1f}%")
266333

267334
for scholar in result['high_profile_scholars'][:5]:
268335
print(f"- {scholar['name']} (h={scholar['h_index']}) - {scholar['affiliation']}")
336+
337+
# Export in any format: markdown, latex, csv, bibtex, json
338+
path = export_report(result, 'markdown')
339+
print(f"Report saved to {path}")
269340
```
270341

271342
---
@@ -423,6 +494,8 @@ CitationImpact/
423494
│ │ └── _index.json # Publication-based author matching index
424495
│ └── publications_cache/ # My Papers list (permanent until refresh)
425496
├── citationimpact/ # Source code
497+
│ ├── cli.py # Non-interactive command-line interface
498+
│ ├── export.py # Report exporters (Markdown/LaTeX/CSV/BibTeX/JSON)
426499
│ ├── core/ # Analysis engine
427500
│ ├── clients/ # API clients
428501
│ │ ├── unified.py # Semantic Scholar + OpenAlex
@@ -440,8 +513,22 @@ CitationImpact/
440513
├── data/ # Ranking datasets
441514
│ ├── university_rankings/ # QS, US News data
442515
│ └── venues_rankings/ # CORE, CCF, iCORE data
516+
├── tests/ # Pytest suite (run: python -m pytest)
517+
```
518+
519+
---
520+
521+
## Development
522+
523+
```bash
524+
pip install -r requirements.txt pytest
525+
526+
# Run the test suite (plugin autoload disabled to avoid system plugin conflicts)
527+
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest
443528
```
444529

530+
Tests run automatically on GitHub Actions (Python 3.9–3.12) for every push and PR.
531+
445532
---
446533

447534
## Troubleshooting
@@ -544,8 +631,9 @@ Found a bug? Have an idea? Open an issue or PR!
544631

545632
**Areas for contribution:**
546633
- Additional ranking sources (THE, ARWU, etc.)
547-
- Export formats (PDF, LaTeX, CSV)
634+
- More export formats (PDF, DOCX)
548635
- Web interface
636+
- Whole-career portfolio analysis (all papers at once)
549637
- Better citation context analysis
550638

551639
---

citation-impact

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ project_root = os.path.dirname(os.path.abspath(__file__))
1515
sys.path.insert(0, project_root)
1616

1717
try:
18-
from citationimpact.ui.app import main
19-
main()
18+
from citationimpact.cli import main
19+
sys.exit(main())
2020
except ImportError as e:
2121
print("\n" + "="*70)
2222
print("ERROR: Required dependencies not installed!")

citationimpact/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
# Config
4343
from .config import ConfigManager, get_config_manager
4444

45-
__version__ = '1.2.0'
45+
__version__ = '1.4.0'
4646
__all__ = [
4747
# Main API
4848
'analyze_paper_impact',

0 commit comments

Comments
 (0)