The Problem

Clients need a quick way to infer where a photograph was taken without manually searching metadata or crowdsourcing. Existing tools either require manual prompt engineering or lack a programmable interface, creating friction for automated pipelines that need location context (e.g., content moderation, travel‑photo tagging).

What This Does

GeoIntel is a Python package that wraps Google’s Gemini API to generate a structured geo‑location guess from an image. The core logic lives in geointel/geointel.py (class GeoIntel with method locate) and is exposed through two entry points:

  • CLI (geointel/cli.py::main) – parses arguments, calls GeoIntel.locate, and prints or saves JSON.
  • Web UI (geointel/web_server.py::create_app) – serves the HTML template in geointel_ui_template/.

Supporting modules handle image handling (geointel/image_processor.py), API request construction (geointel/api_client.py), response parsing (geointel/response_parser.py), and logging (geointel/logger.py). Errors are centralized in geointel/exceptions.py.

How It Is Wired

Execution begins in geointel/__main__.py, which simply invokes geointel/cli.py::main (line 191). main builds an argparse parser, validates arguments (validate_output_path), and, for CLI mode, calls locate on a GeoIntel instance.

GeoIntel.locate (in geointel/geointel.py) does the following:

  1. Image validation – calls geointel/image_processor.py::is_url, validate_image_format, and _validate_size.
  2. Network request – forwards the image (or URL) to geointel/api_client.py::generate_content. This builds the request (_build_endpoint_url, _build_request_payload, _get_request_headers), sends it via requests.post, and extracts the raw text with _extract_response_text.
  3. Response handling – passes the raw Gemini reply to geointel/response_parser.py::parse_response, which cleans JSON (clean_json_string), validates fields (validate_location), and normalizes confidence (normalize_confidence). Errors may be raised as APIError, ResponseParsingError, or InvalidImageError.
  4. Result formattinggeointel/cli.py::display_results renders a colored confidence bar (get_confidence_color) and optionally writes JSON (save_results).

The only outbound side‑effects are the POST request to Gemini (via generate_content) and optional file write for --output. No database or persistent storage is used.

The import graph shows geointel/geointel.py as the most connected module (imports 6 others, instability 0.67). geointel/exceptions.py is a leaf with high fan‑in (imported by 7 modules), making it a stable error‑definition hub. The call graph highlights InvalidImageError and GeoIntel as hot spots (called from 4 and 3 places respectively), indicating where a change would have the widest blast radius.

How To Use It

# Install the package
pip install geointel

# Set the Gemini API key (required)
export GEMINI_API_KEY=your_key_here

CLI – Analyze a local file or URL:

geointel --image path/to/photo.jpg            # basic
geointel --image path/to/photo.jpg --output result.json
geointel --image https://example.com/img.png --context "Beach sunset" --guess "Malibu"

Web UI – Launch a local server:

geointel --web                 # default host 127.0.0.1:5000
geointel --web --host 0.0.0.0 --port 4000

Open the printed URL in a browser, upload an image, and view the interactive map.

Real‑World Use

A media‑monitoring service can call GeoIntel.locate(image_path="frame.jpg") inside its ingestion pipeline, store the returned locations array in a search index, and surface geo‑tags alongside article metadata. The SDK example in the README demonstrates this pattern.

Code Health & Issues

  • HIGH – No test suite – 14 source files, zero test files. No automated regression safety.
  • HIGH – No CI pipeline – No .github/workflows or other CI config; changes are not automatically built or tested.
  • MEDIUM – No dependency update bot – Only requirements.txt present; no Dependabot or Renovate configuration to keep libraries current.
  • MEDIUM – Deep nestingapi_client.py, response_parser.py, web_server.py have maximum indentation depth 8, making control flow hard to follow. Refactor with early returns or helper functions.
  • MEDIUM – Broad exception handlingapi_client.py and response_parser.py catch generic except: clauses, swallowing errors. Replace with specific exception types and proper logging.

Other hygiene notes: license file present, no lockfile, no Dockerfile, no committed secrets.

The Bottom Line

GeoIntel delivers a functional, easy‑to‑install CLI and web UI for AI‑based image geo‑location, with clear separation of concerns across modules. However, the lack of tests, CI, and precise error handling poses a risk for production adoption. It is suitable for prototyping or internal tools, but teams should invest in test coverage and CI before relying on it in critical workflows.