Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

40 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

VendorLens

Automated KYB & Vendor Due Diligence β€” Desktop Application

VendorLens fans out to 12+ intelligence APIs in parallel, extracts adverse findings with Google Gemini AI, and surfaces risk across sanctions, litigation, media, and identity verification β€” all in a local Electron desktop app backed by FastAPI and MySQL.


Stack

Layer Technology
Desktop app Electron 42 Β· React 19 Β· TypeScript Β· Vite Β· Tailwind CSS 4
Backend Python 3.11 Β· FastAPI Β· asyncio Β· BackgroundTasks
Database MySQL 9.x Β· SQLAlchemy ORM Β· pymysql
AI Google Gemini 2.0 Flash (google-genai)
India KYC AuthBridge (GSTIN Β· PAN Β· MSME Β· Court Β· Sanctions)

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  VendorLens Desktop App                      β”‚
β”‚           Electron 42 Β· React 19 Β· TypeScript                β”‚
β”‚                                                              β”‚
β”‚  IntakeForm  ──▢  ScanSelector  ──▢  Dashboard              β”‚
β”‚  (manual / xlsx)   (quick / deep)   (5-tab report)          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚  HTTP Β· localhost:8000
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    FastAPI Backend                            β”‚
β”‚           Python 3.11 Β· asyncio Β· BackgroundTasks            β”‚
β”‚                                                              β”‚
β”‚  POST /intake        POST /scan        GET /scan/{id}/status β”‚
β”‚  POST /intake/excel                    GET /scan/{id}/report β”‚
β””β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚                              β”‚
β”Œβ”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  MySQL 9.x   β”‚    β”‚  External API Layer (asyncio.gather)  β”‚
β”‚  4 tables    β”‚    β”‚  12+ providers Β· ~30 concurrent tasks β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                         β”‚
                             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                             β”‚   Gemini 2.0 Flash     β”‚
                             β”‚  findings + risk scoresβ”‚
                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Data Flow

Vendor Input  (manual form  OR  .xlsx batch upload)
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Phase 1 Β· Parallel API Fan-out (~30 concurrent tasks)  β”‚
β”‚                                                         β”‚
β”‚  Corporate      Sanctions       News & Adverse Media    β”‚
β”‚  OpenCorp       OpenSanctions   GDELT Β· NewsAPI Β· Serperβ”‚
β”‚                                                         β”‚
β”‚  Domain Intel   Address         India / AuthBridge      β”‚
β”‚  WHOIS Β· SSL    GooglePlaces    GSTIN Β· PAN Β· MSME      β”‚
β”‚  Microlink      Wikipedia       Court Β· Defaulting Dir  β”‚
β”‚                                 Global Sanctions Β· Emailβ”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό  (India vendors only)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Phase 2 Β· Alternate-name Enrichment                    β”‚
β”‚  GSTIN β†’ registered trade names β†’ full search re-run   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Gemini 2.0 Flash β€” Findings Extraction                 β”‚
β”‚  findings[]  Β·  section_analysis{}  Β·  article_scores[]β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό
             Risk Report β†’ MySQL β†’ Dashboard

Prerequisites

Tool Version Notes
Python 3.11+ 3.12 supported
Node.js 20 LTS+ For frontend & Electron
MySQL 8.0+ or 9.x Tables auto-created on first run
Git any

Setup

Step 1 β€” MySQL

Windows (user-local ZIP install, no admin required)

# Extract MySQL ZIP to C:\Users\<you>\Apps\mysql-9.x-winx64
# Initialize data directory (first time only):
C:\Users\<you>\Apps\mysql-9.x-winx64\bin\mysqld.exe --initialize-insecure --defaults-file="C:\Users\<you>\Apps\mysql-9.x-winx64\my.ini"

# Start MySQL (from project root):
.\start-mysql.ps1

# Set password + create database (first time only):
mysql -u root --connect-expired-password -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'vendorlens_dev'; FLUSH PRIVILEGES; CREATE DATABASE IF NOT EXISTS vendorlens CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

macOS

brew install mysql
brew services start mysql
mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'vendorlens_dev'; FLUSH PRIVILEGES; CREATE DATABASE IF NOT EXISTS vendorlens CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

Step 2 β€” Backend

Windows

cd backend
python -m venv venv
.\venv\Scripts\activate
pip install -r requirements.txt

copy .env.example .env
# Open .env and fill in your API keys

uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

macOS / Linux

cd backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

cp .env.example .env
# Open .env and fill in your API keys

uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload

Step 3 β€” Frontend

Open a second terminal. Backend must be running on port 8000 first.

Windows

cd frontend
npm install
npm run dev             # Vite dev server β†’ http://localhost:5173

# To run as Electron desktop app (third terminal):
npx electron .

macOS / Linux

cd frontend
npm install
npm run dev             # Vite dev server β†’ http://localhost:5173

# To run as Electron desktop app (third terminal):
npx electron .

Mock mode β€” Set MOCK_API_CALLS=true in backend/.env to run scans without consuming API credits. Returns realistic randomized findings for UI development.


Environment File (backend/.env)

Copy from backend/.env.example and fill in your keys.

# ── Database
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD=vendorlens_dev
MYSQL_DB=vendorlens

# ── Required APIs
GEMINI_API_KEY=your_key
OPENSANCTIONS_API_KEY=your_key
SERPER_API_KEY=your_key
NEWS_API_KEY=your_key

# ── Optional APIs
OPENCORPORATES_API_KEY=
GOOGLE_MAPS_API_KEY=
MICROLINK_API_KEY=

# ── India only (AuthBridge)
AUTHBRIDGE_API_KEY=your_key
AUTHBRIDGE_API_SECRET=your_secret

# ── Dev
MOCK_API_CALLS=false
GEMINI_MODEL=gemini-2.0-flash

API Keys

Env Var Provider Status Purpose
GEMINI_API_KEY Google AI Studio (AIza…) or Vertex AI express mode (AQ.Ab…) Required LLM findings extraction & risk synthesis. The transport is auto-detected from the key prefix; set GEMINI_API_BACKEND=studio|vertex to force it.
OPENSANCTIONS_API_KEY OpenSanctions Required Sanctions & PEP screening
SERPER_API_KEY Serper.dev Required Adverse web, reviews, profile, news
NEWS_API_KEY NewsAPI.org Required Adverse media + regulatory news
OPENCORPORATES_API_KEY OpenCorporates Optional Company registry (140+ jurisdictions)
GOOGLE_MAPS_API_KEY Google Cloud Optional Address & operational status
MICROLINK_API_KEY Microlink Optional Domain metadata (free tier available)
Wikipedia API Wikimedia Free Always active β€” no key needed
AUTHBRIDGE_API_KEY AuthBridge India only GSTIN Β· PAN Β· MSME verification
AUTHBRIDGE_API_SECRET AuthBridge India only Court Β· Defaulting Director Β· Global Sanctions Β· Email

Note β€” All AuthBridge endpoint paths in backend/app/api/endpoints.py are marked # CONFIRM with AuthBridge docs. Verify each path against your plan's API documentation before going live.


Project Structure

Project_1/
β”‚
β”œβ”€β”€ start-mysql.ps1              ← Windows user-local MySQL launcher
β”œβ”€β”€ docker-compose.yml           ← Docker config (future use)
β”‚
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ .env                     ← your credentials (gitignored)
β”‚   β”œβ”€β”€ .env.example             ← template for above
β”‚   β”œβ”€β”€ requirements.txt
β”‚   β”œβ”€β”€ Dockerfile               ← future Docker deployment
β”‚   └── app/
β”‚       β”œβ”€β”€ main.py              ← FastAPI app, routes, scan workflow
β”‚       β”œβ”€β”€ api/
β”‚       β”‚   └── endpoints.py     ← all API client classes
β”‚       β”œβ”€β”€ core/
β”‚       β”‚   β”œβ”€β”€ database.py      ← SQLAlchemy engine (MySQL + pymysql)
β”‚       β”‚   └── models.py        ← ORM models (4 tables)
β”‚       └── services/
β”‚           β”œβ”€β”€ data_aggregator.py  ← Phase 1+2 parallel API fan-out
β”‚           β”œβ”€β”€ llm_service.py      ← Gemini 2.0 Flash integration
β”‚           └── token_manager.py
β”‚
β”œβ”€β”€ frontend/
β”‚   β”œβ”€β”€ package.json
β”‚   β”œβ”€β”€ vite.config.ts
β”‚   β”œβ”€β”€ electron/
β”‚   β”‚   └── main.ts              ← Electron entry point
β”‚   └── src/
β”‚       β”œβ”€β”€ App.tsx              ← Router: / β†’ /scan/:id β†’ /dashboard/:id
β”‚       └── components/
β”‚           β”œβ”€β”€ IntakeForm.tsx   ← vendor input form + Excel upload
β”‚           β”œβ”€β”€ ScanSelector.tsx ← quick / deep scan choice
β”‚           β”œβ”€β”€ Dashboard.tsx    ← top-level report view + polling
β”‚           └── dashboard/
β”‚               β”œβ”€β”€ OverviewTab.tsx    ← risk summary + source heatmap
β”‚               β”œβ”€β”€ FindingsTab.tsx    ← adverse findings list
β”‚               β”œβ”€β”€ NewsTab.tsx        ← AI-scored articles
β”‚               β”œβ”€β”€ WebTab.tsx         ← domain, reviews, places
β”‚               └── IndiaTab.tsx       ← AuthBridge checks (India)
β”‚
β”œβ”€β”€ inputs/
β”‚   └── VendorLens_Intake_Template.xlsx   ← Excel template for batch
β”‚
└── docs/
    β”œβ”€β”€ VendorLens_PRD_Techincal.md
    └── KEYS.md

Database Schema

vendor_inputs β€” intake records

Column Type Notes
input_id UUID PK auto-generated
legal_name VARCHAR(255) indexed
website_domain VARCHAR(255)
jurisdiction_country VARCHAR(10) e.g. IN, US
tax_identifier VARCHAR(100) GSTIN for India
pan_number VARCHAR(50) India
msmed_certificate_number VARCHAR(100) India
director_names JSON array of strings
corporate_email_domain VARCHAR(255) used for email verification
source_method VARCHAR(10) manual or excel

kyb_scans β€” scan jobs

Column Type Notes
scan_id UUID PK
input_id FK β†’ vendor_inputs
scan_type VARCHAR quick or deep
status VARCHAR PENDING Β· COMPLETED Β· ERROR
overall_risk_level VARCHAR LOW Β· MEDIUM Β· HIGH Β· CRITICAL
risk_score INTEGER 0–100
raw_data_summary JSON full aggregated report

adverse_findings β€” risk findings

Column Type Notes
finding_id UUID PK
scan_id FK β†’ kyb_scans
category VARCHAR sanctions_match Β· news_adverse Β· regulatory_issue …
severity VARCHAR critical Β· high Β· medium Β· low
confidence_score INTEGER 0–100
source_tool VARCHAR originating API
recommended_action VARCHAR

scan_subjects β€” screened entities

Column Type Notes
subject_id UUID PK
scan_id FK β†’ kyb_scans
subject_type VARCHAR entity Β· director Β· founder
is_pep BOOLEAN Politically Exposed Person flag

Dashboard Tabs

Tab Visible Contents
Overview Always Overall risk level, finding count, per-source relevance/criticality heatmap
Findings Always Structured adverse findings sorted by severity with source citations
News & Media Always All articles from GDELT Β· NewsAPI Β· Serper with Gemini relevance scores
Web & Reviews Always Domain intel (WHOIS, SSL, Microlink), Google Places, review excerpts, Wikipedia
AuthBridge Checks India only Email verification Β· Global Sanctions Β· Court records Β· Defaulting Director Β· GSTIN/PAN/MSME

API Endpoints

Method Path Description
POST /intake Submit a single vendor (JSON body)
POST /intake/excel Upload a batch .xlsx file
POST /scan Trigger scan for an existing input_id
GET /scan/{id}/status Poll scan status
GET /scan/{id}/report Retrieve full risk report

Scan Modes

Mode Sources Phase 2 Enrichment Duration
Quick Sanctions Β· GDELT Β· Serper adverse No ~15 s
Deep All 12+ sources + India checks Yes (if GSTIN present) 30–60 s

Useful Commands

Run tests

# Windows
cd backend && .\venv\Scripts\activate && pytest tests/

# macOS
cd backend && source venv/bin/activate && pytest tests/

Smoke-test backend imports

python -c "from app.main import app; print('OK')"

Type-check frontend

cd frontend && npx tsc --noEmit

Production frontend build

cd frontend && npm run build

Docker (Future Deployment)

backend/Dockerfile and docker-compose.yml are included but require WSL2 and admin access β€” not available on standard office laptops. Use the native setup above for local development. The Docker configuration is ready for IT-managed server or cloud deployment.

# Future: deploy with Docker Compose
cp backend/.env.example backend/.env  # fill in keys
docker compose up --build
# Backend:  http://localhost:8000
# MySQL:    port 3306 (internal)

Excel Intake Template

Use inputs/VendorLens_Intake_Template.xlsx for batch uploads. Column mapping is flexible β€” headers are matched by keyword, not exact name.

Column Recognized Aliases
legal_name name, supplier, vendor name
website_domain domain, website
jurisdiction_country country
tax_identifier tax no, gstin
pan_number pan, pan no
director_names directors, board
founder_ceo_name ceo, founder
corporate_email_domain email domain

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages