resumereaderapi 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alpha Quantum
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ include LICENSE
2
+ include README.md
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.1
2
+ Name: resumereaderapi
3
+ Version: 1.0.0
4
+ Summary: Python client for the Resume Reader API: parse PDF, DOCX and scanned resumes into 114 structured JSON fields, and normalize job titles, skills and locations.
5
+ Home-page: https://www.resumereaderapi.com
6
+ Author: Alpha Quantum
7
+ Author-email: info@alpha-quantum.com
8
+ License: MIT
9
+ Project-URL: Homepage, https://www.resumereaderapi.com
10
+ Project-URL: Documentation, https://www.resumereaderapi.com/api-v2.php
11
+ Project-URL: Source, https://github.com/explainableaixai/resumereaderapi
12
+ Project-URL: Mirror, https://gitlab.com/url-classifications/resumereaderapi
13
+ Project-URL: Pricing, https://www.resumereaderapi.com/pricing.php
14
+ Description: # resumereaderapi (Python)
15
+
16
+ Resume parser client for Python. Hand it a PDF, a DOCX, a scan or raw text and get structured candidate data back as a dictionary.
17
+
18
+ Needs `requests`. Python 3.7 and later.
19
+
20
+ ```bash
21
+ pip install resumereaderapi
22
+ ```
23
+
24
+ ## Why use a hosted resume parser
25
+
26
+ Writing regular expressions for CVs is a trap. Layouts vary, languages vary, and half the documents are scans. A hosted resume parser gives you one stable shape no matter what the candidate uploaded.
27
+
28
+ The service behind this package is the [resume parser](https://www.resumereaderapi.com/) from Alpha Quantum. It returns 114 fields and marks missing facts as `None` instead of guessing.
29
+
30
+ ## Parse in three lines
31
+
32
+ ```python
33
+ from resumereaderapi import ResumeReader
34
+
35
+ rr = ResumeReader("YOUR_API_KEY")
36
+ data = rr.parse_file("cv.pdf")
37
+
38
+ print(data["resume"]["contact"]["emails"])
39
+ print(data["remaining_credits"])
40
+ ```
41
+
42
+ ## Calls
43
+
44
+ ```python
45
+ rr.parse_text(text, field_names=None, exclude_sensitive=False, anonymize=False,
46
+ max_pages=None, sections=None, language=None)
47
+ rr.parse_file(path, ...same options...)
48
+ rr.parse_url(https_url, ...same options...)
49
+
50
+ rr.normalize_titles(["Sr. SWE II"])
51
+ rr.normalize_skills(["K8s", "JS"])
52
+ rr.normalize_locations(["NYC"])
53
+ ```
54
+
55
+ Normalizer methods batch in groups of 100 and return `{"results": [...], "credits_used": float, "remaining_credits": float}`.
56
+
57
+ ## Skill normalization in practice
58
+
59
+ Candidates write the same skill ten ways. `JS`, `Javascript` and `java script` should be one filter value.
60
+
61
+ ```python
62
+ raw = ["JS", "Javascript", "Python 3.11", "py", "MS Excel", "n/a"]
63
+ out = rr.normalize_skills(raw)
64
+ for item in out["results"]:
65
+ print(item["input"], "->", item["normalized_skill"], item["skill_type"])
66
+ ```
67
+
68
+ Junk entries such as "n/a" come back with `normalized_skill` set to `None`. See the [skill normalization](https://www.resumereaderapi.com/normalization/skills.php) page for fifty real examples.
69
+
70
+ ## Anonymize before a human sees the CV
71
+
72
+ ```python
73
+ data = rr.parse_file(
74
+ "cv.docx",
75
+ anonymize=True,
76
+ exclude_sensitive=True,
77
+ )
78
+ ```
79
+
80
+ Names, contact values and sensitive fields become placeholders such as `[NAME]` and `[EMAIL]`. This is the base of a blind review process, covered under [CV anonymization](https://www.resumereaderapi.com/use-cases/cv-anonymization.php).
81
+
82
+ ## Handle errors
83
+
84
+ ```python
85
+ from resumereaderapi import ResumeReaderError
86
+
87
+ try:
88
+ rr.parse_file(path)
89
+ except ResumeReaderError as exc:
90
+ if exc.status == 402:
91
+ print("buy more credits")
92
+ elif exc.status in (413, 422):
93
+ print("bad document:", exc)
94
+ else:
95
+ raise
96
+ ```
97
+
98
+ ## Example: into a DataFrame
99
+
100
+ ```python
101
+ import pandas as pd
102
+ from pathlib import Path
103
+
104
+ rows = []
105
+ for p in Path("cvs").glob("*.pdf"):
106
+ r = rr.parse_file(str(p))["resume"]
107
+ rows.append({
108
+ "name": r["contact"]["full_name"],
109
+ "city": r["contact"]["address"]["city"],
110
+ "title": (r["career"]["current_position"] or {}).get("title"),
111
+ "years": r["career"]["total_experience_years"],
112
+ "skills": ", ".join(r["skills"]["technical"]),
113
+ })
114
+
115
+ pd.DataFrame(rows).to_csv("candidates.csv", index=False)
116
+ ```
117
+
118
+ ## Example: Flask upload endpoint
119
+
120
+ ```python
121
+ from flask import Flask, request, jsonify
122
+ import tempfile, os
123
+
124
+ app = Flask(__name__)
125
+
126
+ @app.post("/parse")
127
+ def parse():
128
+ f = request.files["cv"]
129
+ with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(f.filename)[1]) as tmp:
130
+ f.save(tmp.name)
131
+ try:
132
+ return jsonify(rr.parse_file(tmp.name)["resume"])
133
+ finally:
134
+ os.unlink(tmp.name)
135
+ ```
136
+
137
+ ## Questions
138
+
139
+ **What file types?** PDF, DOCX, TXT, RTF, HTML, ODT, spreadsheets and images including scanned PDFs.
140
+
141
+ **Is there a limit per call?** 10 MB, 20 pages and about 30,000 tokens.
142
+
143
+ **Does it work in French?** Pass `field_names="fr"` for French keys. Values keep the language of the resume.
144
+
145
+ MIT license. Contact: info@alpha-quantum.com
146
+
147
+ Keywords: resume parser,cv parser,resume parsing api,resume to json,ats,recruiting,hr tech,job title normalization,skill normalization,location normalization,ocr,cv anonymization
148
+ Platform: UNKNOWN
149
+ Classifier: Development Status :: 5 - Production/Stable
150
+ Classifier: Intended Audience :: Developers
151
+ Classifier: License :: OSI Approved :: MIT License
152
+ Classifier: Programming Language :: Python :: 3
153
+ Classifier: Programming Language :: Python :: 3.7
154
+ Classifier: Programming Language :: Python :: 3.12
155
+ Classifier: Topic :: Office/Business
156
+ Classifier: Topic :: Text Processing
157
+ Requires-Python: >=3.7
158
+ Description-Content-Type: text/markdown
@@ -0,0 +1,132 @@
1
+ # resumereaderapi (Python)
2
+
3
+ Resume parser client for Python. Hand it a PDF, a DOCX, a scan or raw text and get structured candidate data back as a dictionary.
4
+
5
+ Needs `requests`. Python 3.7 and later.
6
+
7
+ ```bash
8
+ pip install resumereaderapi
9
+ ```
10
+
11
+ ## Why use a hosted resume parser
12
+
13
+ Writing regular expressions for CVs is a trap. Layouts vary, languages vary, and half the documents are scans. A hosted resume parser gives you one stable shape no matter what the candidate uploaded.
14
+
15
+ The service behind this package is the [resume parser](https://www.resumereaderapi.com/) from Alpha Quantum. It returns 114 fields and marks missing facts as `None` instead of guessing.
16
+
17
+ ## Parse in three lines
18
+
19
+ ```python
20
+ from resumereaderapi import ResumeReader
21
+
22
+ rr = ResumeReader("YOUR_API_KEY")
23
+ data = rr.parse_file("cv.pdf")
24
+
25
+ print(data["resume"]["contact"]["emails"])
26
+ print(data["remaining_credits"])
27
+ ```
28
+
29
+ ## Calls
30
+
31
+ ```python
32
+ rr.parse_text(text, field_names=None, exclude_sensitive=False, anonymize=False,
33
+ max_pages=None, sections=None, language=None)
34
+ rr.parse_file(path, ...same options...)
35
+ rr.parse_url(https_url, ...same options...)
36
+
37
+ rr.normalize_titles(["Sr. SWE II"])
38
+ rr.normalize_skills(["K8s", "JS"])
39
+ rr.normalize_locations(["NYC"])
40
+ ```
41
+
42
+ Normalizer methods batch in groups of 100 and return `{"results": [...], "credits_used": float, "remaining_credits": float}`.
43
+
44
+ ## Skill normalization in practice
45
+
46
+ Candidates write the same skill ten ways. `JS`, `Javascript` and `java script` should be one filter value.
47
+
48
+ ```python
49
+ raw = ["JS", "Javascript", "Python 3.11", "py", "MS Excel", "n/a"]
50
+ out = rr.normalize_skills(raw)
51
+ for item in out["results"]:
52
+ print(item["input"], "->", item["normalized_skill"], item["skill_type"])
53
+ ```
54
+
55
+ Junk entries such as "n/a" come back with `normalized_skill` set to `None`. See the [skill normalization](https://www.resumereaderapi.com/normalization/skills.php) page for fifty real examples.
56
+
57
+ ## Anonymize before a human sees the CV
58
+
59
+ ```python
60
+ data = rr.parse_file(
61
+ "cv.docx",
62
+ anonymize=True,
63
+ exclude_sensitive=True,
64
+ )
65
+ ```
66
+
67
+ Names, contact values and sensitive fields become placeholders such as `[NAME]` and `[EMAIL]`. This is the base of a blind review process, covered under [CV anonymization](https://www.resumereaderapi.com/use-cases/cv-anonymization.php).
68
+
69
+ ## Handle errors
70
+
71
+ ```python
72
+ from resumereaderapi import ResumeReaderError
73
+
74
+ try:
75
+ rr.parse_file(path)
76
+ except ResumeReaderError as exc:
77
+ if exc.status == 402:
78
+ print("buy more credits")
79
+ elif exc.status in (413, 422):
80
+ print("bad document:", exc)
81
+ else:
82
+ raise
83
+ ```
84
+
85
+ ## Example: into a DataFrame
86
+
87
+ ```python
88
+ import pandas as pd
89
+ from pathlib import Path
90
+
91
+ rows = []
92
+ for p in Path("cvs").glob("*.pdf"):
93
+ r = rr.parse_file(str(p))["resume"]
94
+ rows.append({
95
+ "name": r["contact"]["full_name"],
96
+ "city": r["contact"]["address"]["city"],
97
+ "title": (r["career"]["current_position"] or {}).get("title"),
98
+ "years": r["career"]["total_experience_years"],
99
+ "skills": ", ".join(r["skills"]["technical"]),
100
+ })
101
+
102
+ pd.DataFrame(rows).to_csv("candidates.csv", index=False)
103
+ ```
104
+
105
+ ## Example: Flask upload endpoint
106
+
107
+ ```python
108
+ from flask import Flask, request, jsonify
109
+ import tempfile, os
110
+
111
+ app = Flask(__name__)
112
+
113
+ @app.post("/parse")
114
+ def parse():
115
+ f = request.files["cv"]
116
+ with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(f.filename)[1]) as tmp:
117
+ f.save(tmp.name)
118
+ try:
119
+ return jsonify(rr.parse_file(tmp.name)["resume"])
120
+ finally:
121
+ os.unlink(tmp.name)
122
+ ```
123
+
124
+ ## Questions
125
+
126
+ **What file types?** PDF, DOCX, TXT, RTF, HTML, ODT, spreadsheets and images including scanned PDFs.
127
+
128
+ **Is there a limit per call?** 10 MB, 20 pages and about 30,000 tokens.
129
+
130
+ **Does it work in French?** Pass `field_names="fr"` for French keys. Values keep the language of the resume.
131
+
132
+ MIT license. Contact: info@alpha-quantum.com
@@ -0,0 +1,4 @@
1
+ from .client import ResumeReader, ResumeReaderError
2
+
3
+ __all__ = ["ResumeReader", "ResumeReaderError"]
4
+ __version__ = "1.0.0"
@@ -0,0 +1,108 @@
1
+ """Client for the Resume Reader API (https://www.resumereaderapi.com)."""
2
+ import base64
3
+ import os
4
+ from typing import Any, Dict, Iterable, List, Optional
5
+
6
+ import requests
7
+
8
+ __version__ = "1.0.0"
9
+ BASE = "https://www.resumereaderapi.com/api/"
10
+
11
+ STATUS_TEXT = {
12
+ 400: "Missing or invalid input",
13
+ 401: "Invalid API key",
14
+ 402: "Insufficient credits, nothing was billed",
15
+ 413: "Document beyond 20 pages, about 30,000 tokens or 10 MB, nothing was billed",
16
+ 422: "File could not be read as a resume",
17
+ 429: "Rate limit exceeded, 30 requests per 60 seconds per IP",
18
+ }
19
+
20
+
21
+ class ResumeReaderError(Exception):
22
+ """The HTTP status is always 200, so errors come from the status field of the JSON body."""
23
+
24
+ def __init__(self, status: int, message: str, body: Optional[dict] = None):
25
+ super().__init__("[%s] %s" % (status, message))
26
+ self.status = status
27
+ self.body = body or {}
28
+
29
+
30
+ class ResumeReader:
31
+ def __init__(self, api_key: str, schema_version: int = 2, timeout: float = 120.0,
32
+ session: Optional[requests.Session] = None):
33
+ if not api_key:
34
+ raise ValueError("An API key is required")
35
+ self.api_key = api_key
36
+ self.schema_version = schema_version
37
+ self.timeout = timeout
38
+ self.session = session or requests.Session()
39
+ self.session.headers["User-Agent"] = "resumereaderapi-python/%s (+https://www.resumereaderapi.com)" % __version__
40
+
41
+ def _post(self, endpoint: str, payload: Dict[str, Any]) -> Dict[str, Any]:
42
+ resp = self.session.post(BASE + endpoint, json=payload, timeout=self.timeout)
43
+ try:
44
+ body = resp.json()
45
+ except ValueError:
46
+ raise ResumeReaderError(resp.status_code, "Response was not JSON")
47
+ status = body.get("status", 200) if isinstance(body, dict) else 200
48
+ if status != 200:
49
+ raise ResumeReaderError(status, STATUS_TEXT.get(status) or body.get("message", "API error"), body)
50
+ return body
51
+
52
+ def _parse(self, source: Dict[str, Any], field_names: Optional[str], exclude_sensitive: bool,
53
+ anonymize: bool, max_pages: Optional[int], sections: Optional[List[str]],
54
+ language: Optional[str]) -> Dict[str, Any]:
55
+ payload = {"api_key": self.api_key, "schema_version": self.schema_version}
56
+ payload.update(source)
57
+ if field_names:
58
+ payload["field_names"] = field_names
59
+ if exclude_sensitive:
60
+ payload["exclude_sensitive"] = True
61
+ if anonymize:
62
+ payload["anonymize"] = True
63
+ if max_pages:
64
+ payload["max_pages"] = max_pages
65
+ if sections:
66
+ payload["sections"] = sections
67
+ if language:
68
+ payload["language"] = language
69
+ return self._post("parse.php", payload)
70
+
71
+ def parse_text(self, text: str, field_names: Optional[str] = None, exclude_sensitive: bool = False,
72
+ anonymize: bool = False, max_pages: Optional[int] = None,
73
+ sections: Optional[List[str]] = None, language: Optional[str] = None) -> Dict[str, Any]:
74
+ return self._parse({"text": text}, field_names, exclude_sensitive, anonymize, max_pages, sections, language)
75
+
76
+ def parse_file(self, path: str, field_names: Optional[str] = None, exclude_sensitive: bool = False,
77
+ anonymize: bool = False, max_pages: Optional[int] = None,
78
+ sections: Optional[List[str]] = None, language: Optional[str] = None) -> Dict[str, Any]:
79
+ with open(path, "rb") as fh:
80
+ encoded = base64.b64encode(fh.read()).decode("ascii")
81
+ source = {"file_base64": encoded, "filename": os.path.basename(path)}
82
+ return self._parse(source, field_names, exclude_sensitive, anonymize, max_pages, sections, language)
83
+
84
+ def parse_url(self, file_url: str, field_names: Optional[str] = None, exclude_sensitive: bool = False,
85
+ anonymize: bool = False, max_pages: Optional[int] = None,
86
+ sections: Optional[List[str]] = None, language: Optional[str] = None) -> Dict[str, Any]:
87
+ return self._parse({"file_url": file_url}, field_names, exclude_sensitive, anonymize, max_pages, sections, language)
88
+
89
+ def _normalize(self, endpoint: str, key: str, items: Iterable[str]) -> Dict[str, Any]:
90
+ values = [items] if isinstance(items, str) else list(items)
91
+ results: List[Dict[str, Any]] = []
92
+ used = 0.0
93
+ remaining = None
94
+ for i in range(0, len(values), 100):
95
+ body = self._post(endpoint, {"api_key": self.api_key, key: values[i:i + 100]})
96
+ results.extend(body.get("results", []))
97
+ used += body.get("credits_used", 0)
98
+ remaining = body.get("remaining_credits", remaining)
99
+ return {"results": results, "credits_used": round(used, 4), "remaining_credits": remaining}
100
+
101
+ def normalize_titles(self, titles: Iterable[str]) -> Dict[str, Any]:
102
+ return self._normalize("normalize_title.php", "titles", titles)
103
+
104
+ def normalize_skills(self, skills: Iterable[str]) -> Dict[str, Any]:
105
+ return self._normalize("normalize_skills.php", "skills", skills)
106
+
107
+ def normalize_locations(self, locations: Iterable[str]) -> Dict[str, Any]:
108
+ return self._normalize("normalize_locations.php", "locations", locations)
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.1
2
+ Name: resumereaderapi
3
+ Version: 1.0.0
4
+ Summary: Python client for the Resume Reader API: parse PDF, DOCX and scanned resumes into 114 structured JSON fields, and normalize job titles, skills and locations.
5
+ Home-page: https://www.resumereaderapi.com
6
+ Author: Alpha Quantum
7
+ Author-email: info@alpha-quantum.com
8
+ License: MIT
9
+ Project-URL: Homepage, https://www.resumereaderapi.com
10
+ Project-URL: Documentation, https://www.resumereaderapi.com/api-v2.php
11
+ Project-URL: Source, https://github.com/explainableaixai/resumereaderapi
12
+ Project-URL: Mirror, https://gitlab.com/url-classifications/resumereaderapi
13
+ Project-URL: Pricing, https://www.resumereaderapi.com/pricing.php
14
+ Description: # resumereaderapi (Python)
15
+
16
+ Resume parser client for Python. Hand it a PDF, a DOCX, a scan or raw text and get structured candidate data back as a dictionary.
17
+
18
+ Needs `requests`. Python 3.7 and later.
19
+
20
+ ```bash
21
+ pip install resumereaderapi
22
+ ```
23
+
24
+ ## Why use a hosted resume parser
25
+
26
+ Writing regular expressions for CVs is a trap. Layouts vary, languages vary, and half the documents are scans. A hosted resume parser gives you one stable shape no matter what the candidate uploaded.
27
+
28
+ The service behind this package is the [resume parser](https://www.resumereaderapi.com/) from Alpha Quantum. It returns 114 fields and marks missing facts as `None` instead of guessing.
29
+
30
+ ## Parse in three lines
31
+
32
+ ```python
33
+ from resumereaderapi import ResumeReader
34
+
35
+ rr = ResumeReader("YOUR_API_KEY")
36
+ data = rr.parse_file("cv.pdf")
37
+
38
+ print(data["resume"]["contact"]["emails"])
39
+ print(data["remaining_credits"])
40
+ ```
41
+
42
+ ## Calls
43
+
44
+ ```python
45
+ rr.parse_text(text, field_names=None, exclude_sensitive=False, anonymize=False,
46
+ max_pages=None, sections=None, language=None)
47
+ rr.parse_file(path, ...same options...)
48
+ rr.parse_url(https_url, ...same options...)
49
+
50
+ rr.normalize_titles(["Sr. SWE II"])
51
+ rr.normalize_skills(["K8s", "JS"])
52
+ rr.normalize_locations(["NYC"])
53
+ ```
54
+
55
+ Normalizer methods batch in groups of 100 and return `{"results": [...], "credits_used": float, "remaining_credits": float}`.
56
+
57
+ ## Skill normalization in practice
58
+
59
+ Candidates write the same skill ten ways. `JS`, `Javascript` and `java script` should be one filter value.
60
+
61
+ ```python
62
+ raw = ["JS", "Javascript", "Python 3.11", "py", "MS Excel", "n/a"]
63
+ out = rr.normalize_skills(raw)
64
+ for item in out["results"]:
65
+ print(item["input"], "->", item["normalized_skill"], item["skill_type"])
66
+ ```
67
+
68
+ Junk entries such as "n/a" come back with `normalized_skill` set to `None`. See the [skill normalization](https://www.resumereaderapi.com/normalization/skills.php) page for fifty real examples.
69
+
70
+ ## Anonymize before a human sees the CV
71
+
72
+ ```python
73
+ data = rr.parse_file(
74
+ "cv.docx",
75
+ anonymize=True,
76
+ exclude_sensitive=True,
77
+ )
78
+ ```
79
+
80
+ Names, contact values and sensitive fields become placeholders such as `[NAME]` and `[EMAIL]`. This is the base of a blind review process, covered under [CV anonymization](https://www.resumereaderapi.com/use-cases/cv-anonymization.php).
81
+
82
+ ## Handle errors
83
+
84
+ ```python
85
+ from resumereaderapi import ResumeReaderError
86
+
87
+ try:
88
+ rr.parse_file(path)
89
+ except ResumeReaderError as exc:
90
+ if exc.status == 402:
91
+ print("buy more credits")
92
+ elif exc.status in (413, 422):
93
+ print("bad document:", exc)
94
+ else:
95
+ raise
96
+ ```
97
+
98
+ ## Example: into a DataFrame
99
+
100
+ ```python
101
+ import pandas as pd
102
+ from pathlib import Path
103
+
104
+ rows = []
105
+ for p in Path("cvs").glob("*.pdf"):
106
+ r = rr.parse_file(str(p))["resume"]
107
+ rows.append({
108
+ "name": r["contact"]["full_name"],
109
+ "city": r["contact"]["address"]["city"],
110
+ "title": (r["career"]["current_position"] or {}).get("title"),
111
+ "years": r["career"]["total_experience_years"],
112
+ "skills": ", ".join(r["skills"]["technical"]),
113
+ })
114
+
115
+ pd.DataFrame(rows).to_csv("candidates.csv", index=False)
116
+ ```
117
+
118
+ ## Example: Flask upload endpoint
119
+
120
+ ```python
121
+ from flask import Flask, request, jsonify
122
+ import tempfile, os
123
+
124
+ app = Flask(__name__)
125
+
126
+ @app.post("/parse")
127
+ def parse():
128
+ f = request.files["cv"]
129
+ with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(f.filename)[1]) as tmp:
130
+ f.save(tmp.name)
131
+ try:
132
+ return jsonify(rr.parse_file(tmp.name)["resume"])
133
+ finally:
134
+ os.unlink(tmp.name)
135
+ ```
136
+
137
+ ## Questions
138
+
139
+ **What file types?** PDF, DOCX, TXT, RTF, HTML, ODT, spreadsheets and images including scanned PDFs.
140
+
141
+ **Is there a limit per call?** 10 MB, 20 pages and about 30,000 tokens.
142
+
143
+ **Does it work in French?** Pass `field_names="fr"` for French keys. Values keep the language of the resume.
144
+
145
+ MIT license. Contact: info@alpha-quantum.com
146
+
147
+ Keywords: resume parser,cv parser,resume parsing api,resume to json,ats,recruiting,hr tech,job title normalization,skill normalization,location normalization,ocr,cv anonymization
148
+ Platform: UNKNOWN
149
+ Classifier: Development Status :: 5 - Production/Stable
150
+ Classifier: Intended Audience :: Developers
151
+ Classifier: License :: OSI Approved :: MIT License
152
+ Classifier: Programming Language :: Python :: 3
153
+ Classifier: Programming Language :: Python :: 3.7
154
+ Classifier: Programming Language :: Python :: 3.12
155
+ Classifier: Topic :: Office/Business
156
+ Classifier: Topic :: Text Processing
157
+ Requires-Python: >=3.7
158
+ Description-Content-Type: text/markdown
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ setup.py
5
+ resumereaderapi/__init__.py
6
+ resumereaderapi/client.py
7
+ resumereaderapi.egg-info/PKG-INFO
8
+ resumereaderapi.egg-info/SOURCES.txt
9
+ resumereaderapi.egg-info/dependency_links.txt
10
+ resumereaderapi.egg-info/requires.txt
11
+ resumereaderapi.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ requests>=2.20.0
@@ -0,0 +1 @@
1
+ resumereaderapi
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,38 @@
1
+ import pathlib
2
+ from setuptools import setup, find_packages
3
+
4
+ README = (pathlib.Path(__file__).parent / "README.md").read_text(encoding="utf-8")
5
+
6
+ setup(
7
+ name="resumereaderapi",
8
+ version="1.0.0",
9
+ description="Python client for the Resume Reader API: parse PDF, DOCX and scanned resumes into 114 structured JSON fields, and normalize job titles, skills and locations.",
10
+ long_description=README,
11
+ long_description_content_type="text/markdown",
12
+ author="Alpha Quantum",
13
+ author_email="info@alpha-quantum.com",
14
+ url="https://www.resumereaderapi.com",
15
+ project_urls={
16
+ "Homepage": "https://www.resumereaderapi.com",
17
+ "Documentation": "https://www.resumereaderapi.com/api-v2.php",
18
+ "Source": "https://github.com/explainableaixai/resumereaderapi",
19
+ "Mirror": "https://gitlab.com/url-classifications/resumereaderapi",
20
+ "Pricing": "https://www.resumereaderapi.com/pricing.php",
21
+ },
22
+ license="MIT",
23
+ packages=find_packages(exclude=("tests", "test")),
24
+ python_requires=">=3.7",
25
+ install_requires=["requests>=2.20.0"],
26
+ keywords=["resume parser", "cv parser", "resume parsing api", "resume to json", "ats", "recruiting", "hr tech",
27
+ "job title normalization", "skill normalization", "location normalization", "ocr", "cv anonymization"],
28
+ classifiers=[
29
+ "Development Status :: 5 - Production/Stable",
30
+ "Intended Audience :: Developers",
31
+ "License :: OSI Approved :: MIT License",
32
+ "Programming Language :: Python :: 3",
33
+ "Programming Language :: Python :: 3.7",
34
+ "Programming Language :: Python :: 3.12",
35
+ "Topic :: Office/Business",
36
+ "Topic :: Text Processing",
37
+ ],
38
+ )