rongo1
commited on
Commit
·
c609854
1
Parent(s):
dae9b98
fix
Browse files- .gitignore +7 -1
- README.md +69 -10
- app.py +1 -1
- env.example +8 -1
- google.py → google_funcs.py +20 -0
.gitignore
CHANGED
@@ -11,6 +11,10 @@ venv/
|
|
11 |
# Environment variables
|
12 |
.env
|
13 |
|
|
|
|
|
|
|
|
|
14 |
# IDE
|
15 |
.vscode/
|
16 |
.idea/
|
@@ -39,4 +43,6 @@ Thumbs.db
|
|
39 |
|
40 |
# Logs
|
41 |
*.log
|
42 |
-
business_card_extractor.log
|
|
|
|
|
|
11 |
# Environment variables
|
12 |
.env
|
13 |
|
14 |
+
# Google Drive authentication files
|
15 |
+
token.pickle
|
16 |
+
google_token_base64.txt
|
17 |
+
|
18 |
# IDE
|
19 |
.vscode/
|
20 |
.idea/
|
|
|
43 |
|
44 |
# Logs
|
45 |
*.log
|
46 |
+
business_card_extractor.log
|
47 |
+
|
48 |
+
convert_token_to_base64.py
|
README.md
CHANGED
@@ -11,25 +11,26 @@ pinned: false
|
|
11 |
|
12 |
# Business Card Data Extractor 💼
|
13 |
|
14 |
-
An AI-powered tool that extracts structured data from business card images using Google's Gemini AI. Upload business card images and get organized data exported to Excel files.
|
15 |
|
16 |
## Features
|
17 |
|
18 |
- **Batch Processing**: Process multiple business cards at once (up to 5 per batch)
|
19 |
- **AI Model Selection**: Choose between Gemini 2.5 Flash (fast) or Gemini 2.5 Pro (accuracy)
|
|
|
20 |
- **Excel Export**: Get data in two formats:
|
21 |
- Current session results
|
22 |
- Cumulative database (appends across sessions)
|
23 |
- **Smart Data Extraction**: Extracts name, company, title, emails, phones, address, website
|
24 |
-
- **
|
25 |
|
26 |
## How to Use
|
27 |
|
28 |
-
1. **
|
29 |
2. **Upload Images**: Select up to 5 business card images
|
30 |
3. **Choose Model**: Select Gemini model (Flash for speed, Pro for accuracy)
|
31 |
4. **Process**: Click "Extract Business Card Data"
|
32 |
-
5. **
|
33 |
|
34 |
## Supported Data Fields
|
35 |
|
@@ -42,12 +43,70 @@ An AI-powered tool that extracts structured data from business card images using
|
|
42 |
- **Website**: Company website URL
|
43 |
- **Processing Info**: Timestamp, model used, filename
|
44 |
|
45 |
-
##
|
46 |
|
47 |
-
|
48 |
-
-
|
49 |
-
-
|
50 |
|
51 |
-
|
|
|
|
|
|
|
52 |
|
53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
# Business Card Data Extractor 💼
|
13 |
|
14 |
+
An AI-powered tool that extracts structured data from business card images using Google's Gemini AI. Upload business card images and get organized data exported to Excel files with automatic Google Drive storage.
|
15 |
|
16 |
## Features
|
17 |
|
18 |
- **Batch Processing**: Process multiple business cards at once (up to 5 per batch)
|
19 |
- **AI Model Selection**: Choose between Gemini 2.5 Flash (fast) or Gemini 2.5 Pro (accuracy)
|
20 |
+
- **Google Drive Storage**: Automatic upload to organized Drive folders
|
21 |
- **Excel Export**: Get data in two formats:
|
22 |
- Current session results
|
23 |
- Cumulative database (appends across sessions)
|
24 |
- **Smart Data Extraction**: Extracts name, company, title, emails, phones, address, website
|
25 |
+
- **Direct Links**: Access files directly through Google Drive URLs
|
26 |
|
27 |
## How to Use
|
28 |
|
29 |
+
1. **Setup**: Complete the setup process below (one-time)
|
30 |
2. **Upload Images**: Select up to 5 business card images
|
31 |
3. **Choose Model**: Select Gemini model (Flash for speed, Pro for accuracy)
|
32 |
4. **Process**: Click "Extract Business Card Data"
|
33 |
+
5. **Access Files**: Download temporary copies or access permanent files via Google Drive links
|
34 |
|
35 |
## Supported Data Fields
|
36 |
|
|
|
43 |
- **Website**: Company website URL
|
44 |
- **Processing Info**: Timestamp, model used, filename
|
45 |
|
46 |
+
## Setup Instructions
|
47 |
|
48 |
+
### 1. Google Gemini API
|
49 |
+
- Get your API key from: https://aistudio.google.com/
|
50 |
+
- Set as environment variable: `Gemini_API`
|
51 |
|
52 |
+
### 2. Google Drive API Setup
|
53 |
+
1. **Create Google Cloud Project**:
|
54 |
+
- Go to https://console.cloud.google.com/
|
55 |
+
- Create a new project or select an existing one
|
56 |
|
57 |
+
2. **Enable Google Drive API**:
|
58 |
+
- In the Google Cloud Console, go to "APIs & Services" > "Library"
|
59 |
+
- Search for "Google Drive API" and enable it
|
60 |
+
|
61 |
+
3. **Create OAuth 2.0 Credentials**:
|
62 |
+
- Go to "APIs & Services" > "Credentials"
|
63 |
+
- Click "+ CREATE CREDENTIALS" > "OAuth client ID"
|
64 |
+
- Select "Desktop application"
|
65 |
+
- Download the JSON file
|
66 |
+
- Extract `client_id` and `client_secret` from the JSON
|
67 |
+
|
68 |
+
4. **Set Environment Variables**:
|
69 |
+
```bash
|
70 |
+
GOOGLE_CLIENT_ID=your_client_id_here
|
71 |
+
GOOGLE_CLIENT_SECRET=your_client_secret_here
|
72 |
+
```
|
73 |
+
|
74 |
+
### 3. Local Development Setup
|
75 |
+
1. **Install Dependencies**:
|
76 |
+
```bash
|
77 |
+
pip install -r requirements.txt
|
78 |
+
```
|
79 |
+
|
80 |
+
2. **Run Locally First**:
|
81 |
+
```bash
|
82 |
+
python app.py
|
83 |
+
```
|
84 |
+
- Complete the OAuth flow in your browser
|
85 |
+
- This creates `token.pickle` file
|
86 |
+
|
87 |
+
### 4. Deployment Setup (Hugging Face Spaces, etc.)
|
88 |
+
1. **Generate Token for Deployment**:
|
89 |
+
```bash
|
90 |
+
python convert_token_to_base64.py
|
91 |
+
```
|
92 |
+
- This converts `token.pickle` to a base64 string
|
93 |
+
|
94 |
+
2. **Set Environment Variables** in your deployment platform:
|
95 |
+
```bash
|
96 |
+
Gemini_API=your_gemini_api_key
|
97 |
+
GOOGLE_CLIENT_ID=your_google_client_id
|
98 |
+
GOOGLE_CLIENT_SECRET=your_google_client_secret
|
99 |
+
GOOGLE_TOKEN_BASE64=your_base64_encoded_token
|
100 |
+
```
|
101 |
+
|
102 |
+
## Google Drive Folders
|
103 |
+
- **📁 Exports**: https://drive.google.com/drive/folders/1k5iP4egzLrGJwnHkMhxt9bAkaCiieojO
|
104 |
+
- **🖼️ Images**: https://drive.google.com/drive/folders/1gd280IqcAzpAFTPeYsZjoBUOU9S7Zx3c
|
105 |
+
|
106 |
+
## Technical Details
|
107 |
+
|
108 |
+
- **Image Formats**: JPG, JPEG, PNG, WEBP, BMP
|
109 |
+
- **Maximum File Size**: 10MB per image
|
110 |
+
- **Batch Processing**: Up to 5 cards per API call
|
111 |
+
- **Storage**: Automatic upload to Google Drive
|
112 |
+
- **Models**: Gemini 2.5 Flash (fast) / Pro (accurate)
|
app.py
CHANGED
@@ -13,7 +13,7 @@ import sys
|
|
13 |
import tempfile
|
14 |
|
15 |
# Import Google Drive functionality
|
16 |
-
from
|
17 |
|
18 |
# Configure logging
|
19 |
logging.basicConfig(
|
|
|
13 |
import tempfile
|
14 |
|
15 |
# Import Google Drive functionality
|
16 |
+
from google_funcs import get_drive_service, upload_excel_to_exports_folder, upload_image_to_images_folder, list_files_in_folder
|
17 |
|
18 |
# Configure logging
|
19 |
logging.basicConfig(
|
env.example
CHANGED
@@ -15,7 +15,14 @@ Gemini_API=your_gemini_api_key_here
|
|
15 |
GOOGLE_CLIENT_ID=your_google_client_id_here
|
16 |
GOOGLE_CLIENT_SECRET=your_google_client_secret_here
|
17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
# Examples:
|
19 |
# Gemini_API=AIzaSyBxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
20 |
# GOOGLE_CLIENT_ID=1234567890-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com
|
21 |
-
# GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxxxxxxxxxxx
|
|
|
|
15 |
GOOGLE_CLIENT_ID=your_google_client_id_here
|
16 |
GOOGLE_CLIENT_SECRET=your_google_client_secret_here
|
17 |
|
18 |
+
# Google Drive Token (Required for deployment environments)
|
19 |
+
# Generate this by running the app locally first, then use convert_token_to_base64.py
|
20 |
+
# For local development: Leave this empty (token.pickle will be created automatically)
|
21 |
+
# For deployment: Set this to the base64 encoded token string
|
22 |
+
GOOGLE_TOKEN_BASE64=your_base64_encoded_token_here
|
23 |
+
|
24 |
# Examples:
|
25 |
# Gemini_API=AIzaSyBxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
26 |
# GOOGLE_CLIENT_ID=1234567890-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com
|
27 |
+
# GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxxxxxxxxxxx
|
28 |
+
# GOOGLE_TOKEN_BASE64=gASVxwAAAAAAAAB9cQAoWBYAAABhY2Nlc3NfdG9rZW4... (very long string)
|
google.py → google_funcs.py
RENAMED
@@ -1,5 +1,6 @@
|
|
1 |
import os
|
2 |
import pickle
|
|
|
3 |
from google.auth.transport.requests import Request
|
4 |
from google_auth_oauthlib.flow import InstalledAppFlow
|
5 |
from googleapiclient.discovery import build
|
@@ -26,6 +27,22 @@ TOKEN_PICKLE_FILE = 'token.pickle'
|
|
26 |
def get_drive_service():
|
27 |
"""Authenticates with Google and returns a Drive service object."""
|
28 |
creds = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
# The file token.pickle stores the user's access and refresh tokens.
|
30 |
if os.path.exists(TOKEN_PICKLE_FILE):
|
31 |
with open(TOKEN_PICKLE_FILE, 'rb') as token:
|
@@ -34,11 +51,13 @@ def get_drive_service():
|
|
34 |
# If there are no (valid) credentials available, let the user log in.
|
35 |
if not creds or not creds.valid:
|
36 |
if creds and creds.expired and creds.refresh_token:
|
|
|
37 |
creds.refresh(Request())
|
38 |
else:
|
39 |
if not CLIENT_ID or not CLIENT_SECRET:
|
40 |
raise ValueError("GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET environment variables are required")
|
41 |
|
|
|
42 |
# Use client_config dictionary instead of a client_secret.json file
|
43 |
client_config = {
|
44 |
"installed": {
|
@@ -55,6 +74,7 @@ def get_drive_service():
|
|
55 |
# Save the credentials for the next run
|
56 |
with open(TOKEN_PICKLE_FILE, 'wb') as token:
|
57 |
pickle.dump(creds, token)
|
|
|
58 |
|
59 |
return build('drive', 'v3', credentials=creds)
|
60 |
|
|
|
1 |
import os
|
2 |
import pickle
|
3 |
+
import base64
|
4 |
from google.auth.transport.requests import Request
|
5 |
from google_auth_oauthlib.flow import InstalledAppFlow
|
6 |
from googleapiclient.discovery import build
|
|
|
27 |
def get_drive_service():
|
28 |
"""Authenticates with Google and returns a Drive service object."""
|
29 |
creds = None
|
30 |
+
|
31 |
+
# --- NEW CODE FOR DEPLOYMENT ENVIRONMENTS ---
|
32 |
+
# If token file doesn't exist, try to create it from environment variable
|
33 |
+
if not os.path.exists(TOKEN_PICKLE_FILE):
|
34 |
+
encoded_token = os.environ.get('GOOGLE_TOKEN_BASE64')
|
35 |
+
if encoded_token:
|
36 |
+
logger.info("Found token in environment variable. Recreating token.pickle file.")
|
37 |
+
try:
|
38 |
+
decoded_token = base64.b64decode(encoded_token)
|
39 |
+
with open(TOKEN_PICKLE_FILE, "wb") as token_file:
|
40 |
+
token_file.write(decoded_token)
|
41 |
+
logger.info("Successfully recreated token.pickle from environment variable")
|
42 |
+
except Exception as e:
|
43 |
+
logger.error(f"Failed to decode token from environment variable: {e}")
|
44 |
+
# --- END OF NEW CODE ---
|
45 |
+
|
46 |
# The file token.pickle stores the user's access and refresh tokens.
|
47 |
if os.path.exists(TOKEN_PICKLE_FILE):
|
48 |
with open(TOKEN_PICKLE_FILE, 'rb') as token:
|
|
|
51 |
# If there are no (valid) credentials available, let the user log in.
|
52 |
if not creds or not creds.valid:
|
53 |
if creds and creds.expired and creds.refresh_token:
|
54 |
+
logger.info("Refreshing expired credentials")
|
55 |
creds.refresh(Request())
|
56 |
else:
|
57 |
if not CLIENT_ID or not CLIENT_SECRET:
|
58 |
raise ValueError("GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET environment variables are required")
|
59 |
|
60 |
+
logger.info("Starting OAuth flow for new credentials")
|
61 |
# Use client_config dictionary instead of a client_secret.json file
|
62 |
client_config = {
|
63 |
"installed": {
|
|
|
74 |
# Save the credentials for the next run
|
75 |
with open(TOKEN_PICKLE_FILE, 'wb') as token:
|
76 |
pickle.dump(creds, token)
|
77 |
+
logger.info("Saved new credentials to token.pickle")
|
78 |
|
79 |
return build('drive', 'v3', credentials=creds)
|
80 |
|