| """Language / script detection → region inference. |
| |
| Detects the script of OCR'd text and infers candidate countries/regions. |
| Pure stdlib — uses Unicode code-point ranges. |
| """ |
|
|
| from __future__ import annotations |
|
|
| from typing import List |
|
|
|
|
| def detect_script(text: str) -> str: |
| """Detect the dominant script in a text string. |
| |
| Returns one of: 'latin', 'cyrillic', 'arabic', 'cjk', 'hangul', |
| 'devanagari', 'thai', 'hebrew', 'greek', 'unknown'. |
| """ |
| if not text: |
| return "unknown" |
|
|
| counts: dict[str, int] = {} |
| for ch in text: |
| cp = ord(ch) |
| if 0x0041 <= cp <= 0x024F or 0x1E00 <= cp <= 0x1EFF: |
| counts["latin"] = counts.get("latin", 0) + 1 |
| elif 0x0400 <= cp <= 0x04FF: |
| counts["cyrillic"] = counts.get("cyrillic", 0) + 1 |
| elif 0x0600 <= cp <= 0x06FF or 0x0750 <= cp <= 0x077F: |
| counts["arabic"] = counts.get("arabic", 0) + 1 |
| elif 0x4E00 <= cp <= 0x9FFF or 0x3400 <= cp <= 0x4DBF: |
| counts["cjk"] = counts.get("cjk", 0) + 1 |
| elif 0xAC00 <= cp <= 0xD7AF: |
| counts["hangul"] = counts.get("hangul", 0) + 1 |
| elif 0x0900 <= cp <= 0x097F: |
| counts["devanagari"] = counts.get("devanagari", 0) + 1 |
| elif 0x0E00 <= cp <= 0x0E7F: |
| counts["thai"] = counts.get("thai", 0) + 1 |
| elif 0x0590 <= cp <= 0x05FF: |
| counts["hebrew"] = counts.get("hebrew", 0) + 1 |
| elif 0x0370 <= cp <= 0x03FF: |
| counts["greek"] = counts.get("greek", 0) + 1 |
|
|
| if not counts: |
| return "unknown" |
| return max(counts, key=counts.get) |
|
|
|
|
| def script_to_regions(script: str) -> List[dict]: |
| """Map a script to candidate countries/regions with confidence. |
| |
| Returns a list of {"country": str, "confidence": float}. |
| """ |
| mapping = { |
| "latin": [ |
| {"country": "United States", "confidence": 0.15}, |
| {"country": "United Kingdom", "confidence": 0.15}, |
| {"country": "France", "confidence": 0.1}, |
| {"country": "Germany", "confidence": 0.1}, |
| {"country": "Spain", "confidence": 0.1}, |
| {"country": "Italy", "confidence": 0.1}, |
| {"country": "Brazil", "confidence": 0.1}, |
| {"country": "Mexico", "confidence": 0.1}, |
| ], |
| "cyrillic": [ |
| {"country": "Russia", "confidence": 0.4}, |
| {"country": "Ukraine", "confidence": 0.15}, |
| {"country": "Belarus", "confidence": 0.1}, |
| {"country": "Bulgaria", "confidence": 0.1}, |
| {"country": "Serbia", "confidence": 0.1}, |
| ], |
| "arabic": [ |
| {"country": "Saudi Arabia", "confidence": 0.15}, |
| {"country": "Egypt", "confidence": 0.15}, |
| {"country": "Iraq", "confidence": 0.1}, |
| {"country": "Algeria", "confidence": 0.1}, |
| {"country": "Morocco", "confidence": 0.1}, |
| {"country": "United Arab Emirates", "confidence": 0.1}, |
| ], |
| "cjk": [ |
| {"country": "China", "confidence": 0.5}, |
| {"country": "Taiwan", "confidence": 0.15}, |
| {"country": "Japan", "confidence": 0.1}, |
| ], |
| "hangul": [ |
| {"country": "South Korea", "confidence": 0.7}, |
| {"country": "North Korea", "confidence": 0.1}, |
| ], |
| "devanagari": [ |
| {"country": "India", "confidence": 0.6}, |
| {"country": "Nepal", "confidence": 0.15}, |
| ], |
| "thai": [ |
| {"country": "Thailand", "confidence": 0.85}, |
| ], |
| "hebrew": [ |
| {"country": "Israel", "confidence": 0.8}, |
| ], |
| "greek": [ |
| {"country": "Greece", "confidence": 0.8}, |
| {"country": "Cyprus", "confidence": 0.1}, |
| ], |
| "unknown": [], |
| } |
| return mapping.get(script, []) |
|
|
|
|
| def text_to_country_hints(text: str) -> List[dict]: |
| """Detect country hints from text content (script + keywords). |
| |
| Returns a list of {"source": "script"|"keyword", "value": str, |
| "country": str, "confidence": float}. |
| """ |
| if not text: |
| return [] |
|
|
| hints: list[dict] = [] |
|
|
| |
| script = detect_script(text) |
| for region in script_to_regions(script): |
| hints.append({ |
| "source": "script", |
| "value": script, |
| "country": region["country"], |
| "confidence": region["confidence"], |
| }) |
|
|
| |
| text_lower = text.lower() |
| keyword_map = { |
| "united states": ("United States", 0.6), |
| "u.s.a": ("United States", 0.5), |
| "london": ("United Kingdom", 0.7), |
| "paris": ("France", 0.7), |
| "berlin": ("Germany", 0.7), |
| "tokyo": ("Japan", 0.7), |
| "beijing": ("China", 0.7), |
| "moscow": ("Russia", 0.7), |
| "sydney": ("Australia", 0.7), |
| "cairo": ("Egypt", 0.7), |
| "mumbai": ("India", 0.7), |
| } |
| for keyword, (country, conf) in keyword_map.items(): |
| if keyword in text_lower: |
| hints.append({ |
| "source": "keyword", |
| "value": keyword, |
| "country": country, |
| "confidence": conf, |
| }) |
|
|
| return hints |
|
|