leadminer 0.1.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.
- leadminer-0.1.0/PKG-INFO +8 -0
- leadminer-0.1.0/campaigns.py +52 -0
- leadminer-0.1.0/classes.py +18 -0
- leadminer-0.1.0/database.py +148 -0
- leadminer-0.1.0/help.py +47 -0
- leadminer-0.1.0/leadminer.egg-info/PKG-INFO +8 -0
- leadminer-0.1.0/leadminer.egg-info/SOURCES.txt +15 -0
- leadminer-0.1.0/leadminer.egg-info/dependency_links.txt +1 -0
- leadminer-0.1.0/leadminer.egg-info/entry_points.txt +2 -0
- leadminer-0.1.0/leadminer.egg-info/requires.txt +4 -0
- leadminer-0.1.0/leadminer.egg-info/top_level.txt +8 -0
- leadminer-0.1.0/main.py +37 -0
- leadminer-0.1.0/output.py +66 -0
- leadminer-0.1.0/pyproject.toml +29 -0
- leadminer-0.1.0/search.py +89 -0
- leadminer-0.1.0/setup.cfg +4 -0
- leadminer-0.1.0/setup_cmd.py +30 -0
leadminer-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import database
|
|
2
|
+
from database import *
|
|
3
|
+
from dotenv import load_dotenv, set_key, get_key
|
|
4
|
+
import os
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def campaign(command: str =typer.Argument(...), option: str | None = typer.Argument(None)):
|
|
9
|
+
|
|
10
|
+
if command == "create":
|
|
11
|
+
#check valid name
|
|
12
|
+
|
|
13
|
+
make_campaign(option)
|
|
14
|
+
|
|
15
|
+
elif command == "select":
|
|
16
|
+
campaign_id = get_campaign_id(option)
|
|
17
|
+
if campaign_id:
|
|
18
|
+
load_dotenv(".env")
|
|
19
|
+
set_key(".env", "ACTIVE_CAMPAIGN_NAME", option)
|
|
20
|
+
set_key(".env", "ACTIVE_CAMPAIGN_ID", str(campaign_id))
|
|
21
|
+
else:
|
|
22
|
+
print("That campaign does not exist")
|
|
23
|
+
|
|
24
|
+
elif command == "list":
|
|
25
|
+
if option:
|
|
26
|
+
campaign_id = get_campaign_id(option)
|
|
27
|
+
if campaign_id:
|
|
28
|
+
#handle listing the data from campaign
|
|
29
|
+
list_campaign_data(option)
|
|
30
|
+
else:
|
|
31
|
+
print("That campaign does not exist")
|
|
32
|
+
else:
|
|
33
|
+
# list all the campaigns
|
|
34
|
+
list_campaigns()
|
|
35
|
+
|
|
36
|
+
elif command == "remove":
|
|
37
|
+
campaign_id = get_campaign_id(option)
|
|
38
|
+
if campaign_id:
|
|
39
|
+
# remove the campaign
|
|
40
|
+
remove_campaign(option)
|
|
41
|
+
else: print("That campaign does not exist")
|
|
42
|
+
|
|
43
|
+
elif command == "disconnect":
|
|
44
|
+
load_dotenv(".env")
|
|
45
|
+
exists = get_key(".env", "ACTIVE_CAMPAIGN_NAME")
|
|
46
|
+
if exists:
|
|
47
|
+
set_key(".env", "ACTIVE_CAMPAIGN_NAME", "")
|
|
48
|
+
set_key(".env", "ACTIVE_CAMPAIGN_ID", "")
|
|
49
|
+
else: print("You are not currently connected to a campaign")
|
|
50
|
+
|
|
51
|
+
else:
|
|
52
|
+
print(f"\"{option}\" is not a recognised command")
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""place["id"],
|
|
2
|
+
place["displayName"]["text"],
|
|
3
|
+
place["formattedAddress"],
|
|
4
|
+
place.get("rating"),
|
|
5
|
+
place.get("userRatingCount"),"""
|
|
6
|
+
from numbers import Real
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Lead:
|
|
10
|
+
def __init__(self, place_id: str, name: str, address: str, phone: str, website: str, rating: float, reviews: int):
|
|
11
|
+
self.placeId: str = place_id
|
|
12
|
+
self.name: str = name
|
|
13
|
+
self.address: str = address
|
|
14
|
+
self.phone: str = phone
|
|
15
|
+
self.website: str = website
|
|
16
|
+
self.rating: float = rating
|
|
17
|
+
self.reviews: int = reviews
|
|
18
|
+
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import sqlite3
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import classes
|
|
4
|
+
|
|
5
|
+
from output import output_cli
|
|
6
|
+
|
|
7
|
+
database_path = Path.home() / ".leadminer" / "leadminer.db"
|
|
8
|
+
|
|
9
|
+
def sort_database():
|
|
10
|
+
database_path.parent.mkdir(exist_ok=True)
|
|
11
|
+
connection = sqlite3.connect(database_path)
|
|
12
|
+
return connection
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def make_tables():
|
|
16
|
+
connection = sort_database()
|
|
17
|
+
cursor = connection.cursor()
|
|
18
|
+
|
|
19
|
+
cursor.execute("""
|
|
20
|
+
CREATE TABLE IF NOT EXISTS campaigns (
|
|
21
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
22
|
+
name TEXT UNIQUE
|
|
23
|
+
)
|
|
24
|
+
""")
|
|
25
|
+
|
|
26
|
+
cursor.execute("""
|
|
27
|
+
CREATE TABLE IF NOT EXISTS leads (
|
|
28
|
+
place_id TEXT PRIMARY KEY,
|
|
29
|
+
name TEXT,
|
|
30
|
+
address TEXT,
|
|
31
|
+
website TEXT,
|
|
32
|
+
phone TEXT,
|
|
33
|
+
rating REAL,
|
|
34
|
+
reviews INTEGER,
|
|
35
|
+
campaign_id INTEGER,
|
|
36
|
+
FOREIGN KEY (campaign_id) REFERENCES campaigns(id)
|
|
37
|
+
)
|
|
38
|
+
""")
|
|
39
|
+
|
|
40
|
+
connection.commit()
|
|
41
|
+
connection.close()
|
|
42
|
+
|
|
43
|
+
def make_campaign(name: str):
|
|
44
|
+
connection = sort_database()
|
|
45
|
+
cursor = connection.cursor()
|
|
46
|
+
|
|
47
|
+
cursor.execute(
|
|
48
|
+
"INSERT INTO campaigns (name) VALUES (?)",
|
|
49
|
+
(name,)
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
connection.commit()
|
|
53
|
+
connection.close()
|
|
54
|
+
|
|
55
|
+
def remove_campaign(name: str):
|
|
56
|
+
connection = sort_database()
|
|
57
|
+
cursor = connection.cursor()
|
|
58
|
+
|
|
59
|
+
cursor.execute(
|
|
60
|
+
"DELETE FROM campaigns WHERE name = ?", (name,)
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
connection.commit()
|
|
64
|
+
connection.close()
|
|
65
|
+
|
|
66
|
+
def list_campaigns():
|
|
67
|
+
connection = sort_database()
|
|
68
|
+
cursor = connection.cursor()
|
|
69
|
+
|
|
70
|
+
cursor.execute(
|
|
71
|
+
"SELECT name from campaigns"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
rows = cursor.fetchall()
|
|
75
|
+
|
|
76
|
+
for row in rows:
|
|
77
|
+
print(row[0])
|
|
78
|
+
|
|
79
|
+
connection.close()
|
|
80
|
+
|
|
81
|
+
def get_campaign_id(name: str):
|
|
82
|
+
connection = sort_database()
|
|
83
|
+
cursor = connection.cursor()
|
|
84
|
+
|
|
85
|
+
cursor.execute(
|
|
86
|
+
"SELECT id FROM campaigns WHERE name = ?",
|
|
87
|
+
(name,)
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
result = cursor.fetchone()
|
|
91
|
+
connection.close()
|
|
92
|
+
|
|
93
|
+
if result is not None:
|
|
94
|
+
return result[0]
|
|
95
|
+
else:
|
|
96
|
+
return None
|
|
97
|
+
|
|
98
|
+
def save_lead(place, campaign_name):
|
|
99
|
+
|
|
100
|
+
campaign_id = get_campaign_id(campaign_name)
|
|
101
|
+
connection = sort_database()
|
|
102
|
+
cursor = connection.cursor()
|
|
103
|
+
|
|
104
|
+
cursor.execute("""
|
|
105
|
+
INSERT OR IGNORE INTO leads
|
|
106
|
+
(place_id, name, address, phone, website, rating, reviews, campaign_id)
|
|
107
|
+
VALUES (?,?,?,?,?,?,?,?)
|
|
108
|
+
""", (
|
|
109
|
+
place.placeId,
|
|
110
|
+
place.name,
|
|
111
|
+
place.address,
|
|
112
|
+
place.phone,
|
|
113
|
+
place.website,
|
|
114
|
+
place.rating,
|
|
115
|
+
place.reviews,
|
|
116
|
+
campaign_id
|
|
117
|
+
))
|
|
118
|
+
|
|
119
|
+
connection.commit()
|
|
120
|
+
connection.close()
|
|
121
|
+
|
|
122
|
+
def list_campaign_data(name: str):
|
|
123
|
+
connection = sort_database()
|
|
124
|
+
cursor = connection.cursor()
|
|
125
|
+
|
|
126
|
+
cursor.execute("""
|
|
127
|
+
SELECT leads.name, leads.address, leads.phone, leads.website, leads.rating, leads.reviews
|
|
128
|
+
FROM leads
|
|
129
|
+
JOIN campaigns ON leads.campaign_id = campaigns.id
|
|
130
|
+
WHERE campaigns.name = ?
|
|
131
|
+
""", (name,))
|
|
132
|
+
|
|
133
|
+
rows = cursor.fetchall()
|
|
134
|
+
output = []
|
|
135
|
+
for row in rows:
|
|
136
|
+
row_name = row[0]
|
|
137
|
+
row_address = row[1]
|
|
138
|
+
row_phone = row[2]
|
|
139
|
+
row_site = row[3]
|
|
140
|
+
row_rating = row[4]
|
|
141
|
+
row_reviews = row[5]
|
|
142
|
+
temp = classes.Lead("n/a", row_name, row_address, row_phone, row_site, row_rating, row_reviews)
|
|
143
|
+
output.append(temp)
|
|
144
|
+
output_cli(output)
|
|
145
|
+
|
|
146
|
+
connection.close()
|
|
147
|
+
|
|
148
|
+
make_tables()
|
leadminer-0.1.0/help.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
def help():
|
|
2
|
+
print("""
|
|
3
|
+
Search
|
|
4
|
+
|
|
5
|
+
Used to search for businesses.
|
|
6
|
+
|
|
7
|
+
Default Usage:
|
|
8
|
+
search <business-type> <area> for default search e.g. \"search Barber London\"
|
|
9
|
+
Additional Filters:
|
|
10
|
+
- website (y / n)
|
|
11
|
+
- min-rating (0-5)
|
|
12
|
+
- max-rating (0-5)
|
|
13
|
+
- min-reviews
|
|
14
|
+
- max-reviews
|
|
15
|
+
- output-format (cli / csv)
|
|
16
|
+
Examples:
|
|
17
|
+
search electrician london --output-format csv
|
|
18
|
+
search restaurant croydon --website n
|
|
19
|
+
search cafe manchester --min-rating 0 --max-rating 3
|
|
20
|
+
|
|
21
|
+
Campaigns
|
|
22
|
+
|
|
23
|
+
Used to store businesses that you've found under categories
|
|
24
|
+
|
|
25
|
+
Create campaign:
|
|
26
|
+
campaign create <name>
|
|
27
|
+
Select campaign (searches will be stored under this campaign):
|
|
28
|
+
campaign select <name>
|
|
29
|
+
Stop storing searches:
|
|
30
|
+
campaign disconnect
|
|
31
|
+
Delete campaign:
|
|
32
|
+
campaign remove <name>
|
|
33
|
+
List all campaigns:
|
|
34
|
+
campaign list
|
|
35
|
+
List all data within a campaign:
|
|
36
|
+
campaign list <name>
|
|
37
|
+
|
|
38
|
+
Setup
|
|
39
|
+
|
|
40
|
+
Set API key:
|
|
41
|
+
setup key <api_key>
|
|
42
|
+
Learn how to find your API key:
|
|
43
|
+
setup key
|
|
44
|
+
Set limit of businesses returned to you per search:
|
|
45
|
+
setup limit <limit>
|
|
46
|
+
|
|
47
|
+
""")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
campaigns.py
|
|
2
|
+
classes.py
|
|
3
|
+
database.py
|
|
4
|
+
help.py
|
|
5
|
+
main.py
|
|
6
|
+
output.py
|
|
7
|
+
pyproject.toml
|
|
8
|
+
search.py
|
|
9
|
+
setup_cmd.py
|
|
10
|
+
leadminer.egg-info/PKG-INFO
|
|
11
|
+
leadminer.egg-info/SOURCES.txt
|
|
12
|
+
leadminer.egg-info/dependency_links.txt
|
|
13
|
+
leadminer.egg-info/entry_points.txt
|
|
14
|
+
leadminer.egg-info/requires.txt
|
|
15
|
+
leadminer.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
leadminer-0.1.0/main.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from dotenv import load_dotenv, set_key
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from search import search
|
|
7
|
+
from output import output
|
|
8
|
+
from setup_cmd import setup
|
|
9
|
+
from help import help
|
|
10
|
+
from campaigns import campaign
|
|
11
|
+
|
|
12
|
+
def nit():
|
|
13
|
+
# check that .env exists otherwise create
|
|
14
|
+
if not os.path.exists(".env"):
|
|
15
|
+
Path(".env").touch()
|
|
16
|
+
|
|
17
|
+
load_dotenv(".env")
|
|
18
|
+
|
|
19
|
+
searchLimit = os.getenv("LIMIT")
|
|
20
|
+
places_api_key = os.getenv("API_KEY")
|
|
21
|
+
|
|
22
|
+
# if no limit set
|
|
23
|
+
if searchLimit is None:
|
|
24
|
+
set_key(".env", "LIMIT", "100")
|
|
25
|
+
|
|
26
|
+
app = typer.Typer()
|
|
27
|
+
|
|
28
|
+
# search
|
|
29
|
+
app.command()(search)
|
|
30
|
+
app.command()(output)
|
|
31
|
+
app.command()(help)
|
|
32
|
+
app.command()(campaign)
|
|
33
|
+
app.command()(setup)
|
|
34
|
+
|
|
35
|
+
nit()
|
|
36
|
+
if __name__ == "__main__":
|
|
37
|
+
app()
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import csv
|
|
2
|
+
import rich
|
|
3
|
+
from rich.table import Table
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
def output_cli(leads):
|
|
8
|
+
console = Console()
|
|
9
|
+
|
|
10
|
+
table = Table(title="Leads")
|
|
11
|
+
|
|
12
|
+
table.add_column("Name", style="cyan")
|
|
13
|
+
table.add_column("Address", style="green")
|
|
14
|
+
table.add_column("Phone")
|
|
15
|
+
table.add_column("Website")
|
|
16
|
+
table.add_column("Rating")
|
|
17
|
+
table.add_column("Reviews")
|
|
18
|
+
|
|
19
|
+
for lead in leads:
|
|
20
|
+
table.add_row(
|
|
21
|
+
lead.name,
|
|
22
|
+
lead.address,
|
|
23
|
+
str(lead.phone or ""),
|
|
24
|
+
str(lead.website or ""),
|
|
25
|
+
str(lead.rating or ""),
|
|
26
|
+
str(lead.reviews or "")
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
console.print(table)
|
|
30
|
+
|
|
31
|
+
def output_csv(leads, filename="leads.csv"):
|
|
32
|
+
|
|
33
|
+
export_dir = Path.home() / ".leadminer" / "exports"
|
|
34
|
+
export_dir.mkdir(exist_ok=True)
|
|
35
|
+
|
|
36
|
+
filepath = export_dir / filename
|
|
37
|
+
|
|
38
|
+
with open(filepath, "w", newline="") as f:
|
|
39
|
+
writer = csv.writer(f)
|
|
40
|
+
|
|
41
|
+
writer.writerow([
|
|
42
|
+
"name",
|
|
43
|
+
"address",
|
|
44
|
+
"phone",
|
|
45
|
+
"website",
|
|
46
|
+
"rating",
|
|
47
|
+
"reviews"
|
|
48
|
+
])
|
|
49
|
+
|
|
50
|
+
for lead in leads:
|
|
51
|
+
writer.writerow([
|
|
52
|
+
lead.name,
|
|
53
|
+
lead.address,
|
|
54
|
+
lead.phone,
|
|
55
|
+
lead.website,
|
|
56
|
+
lead.rating,
|
|
57
|
+
lead.reviews
|
|
58
|
+
])
|
|
59
|
+
print(f"Exported CSV to {filepath}")
|
|
60
|
+
|
|
61
|
+
def output(option: str, leads):
|
|
62
|
+
if option == "csv":
|
|
63
|
+
output_csv(leads)
|
|
64
|
+
|
|
65
|
+
elif option == "cli":
|
|
66
|
+
output_cli(leads)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=69", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "leadminer"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "CLI tool for finding local business leads"
|
|
9
|
+
dependencies = [
|
|
10
|
+
"requests",
|
|
11
|
+
"python-dotenv",
|
|
12
|
+
"rich",
|
|
13
|
+
"typer"
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[project.scripts]
|
|
17
|
+
leadminer = "main:app"
|
|
18
|
+
|
|
19
|
+
[tool.setuptools]
|
|
20
|
+
py-modules = [
|
|
21
|
+
"main",
|
|
22
|
+
"search",
|
|
23
|
+
"output",
|
|
24
|
+
"setup_cmd",
|
|
25
|
+
"help",
|
|
26
|
+
"campaigns",
|
|
27
|
+
"database",
|
|
28
|
+
"classes",
|
|
29
|
+
]
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import requests, os
|
|
2
|
+
from dotenv import load_dotenv, get_key
|
|
3
|
+
import classes
|
|
4
|
+
from database import save_lead
|
|
5
|
+
import output as output_functions
|
|
6
|
+
|
|
7
|
+
url = "https://places.googleapis.com/v1/places:searchText"
|
|
8
|
+
|
|
9
|
+
load_dotenv(".env")
|
|
10
|
+
searchLimit = os.getenv("LIMIT")
|
|
11
|
+
places_api_key = os.getenv("API_KEY")
|
|
12
|
+
|
|
13
|
+
def search(
|
|
14
|
+
business_type: str,
|
|
15
|
+
location: str,
|
|
16
|
+
website: str = "a",
|
|
17
|
+
min_rating: float = 0,
|
|
18
|
+
max_rating: float = 5,
|
|
19
|
+
limit: int | None = searchLimit,
|
|
20
|
+
min_reviews: int = 0,
|
|
21
|
+
max_reviews: int = 999999999,
|
|
22
|
+
output_format: str = "cli",
|
|
23
|
+
api_key: str | None = places_api_key):
|
|
24
|
+
|
|
25
|
+
# print(limit, api_key)
|
|
26
|
+
|
|
27
|
+
all_good = True
|
|
28
|
+
while all_good:
|
|
29
|
+
if api_key is None:
|
|
30
|
+
print("You have not set an API key, please set one using 'setup key <api_key>'")
|
|
31
|
+
all_good = False
|
|
32
|
+
if limit is None:
|
|
33
|
+
print("You have not set a search limit, please set one using 'setup limit <limit>'")
|
|
34
|
+
all_good = False
|
|
35
|
+
|
|
36
|
+
query = f"{business_type} in {location}"
|
|
37
|
+
|
|
38
|
+
headers = {
|
|
39
|
+
"Content-Type": "application/json",
|
|
40
|
+
"X-Goog-Api-Key": api_key,
|
|
41
|
+
"X-Goog-FieldMask": "places.id,places.displayName,places.formattedAddress,places.rating,places.userRatingCount,places.websiteUri,places.nationalPhoneNumber"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
data = {
|
|
45
|
+
"textQuery": query,
|
|
46
|
+
"pageSize": limit
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
response = requests.post(url, headers=headers, json=data)
|
|
50
|
+
results = response.json()
|
|
51
|
+
|
|
52
|
+
object_results = []
|
|
53
|
+
campaign_active = get_key(".env", "ACTIVE_CAMPAIGN_NAME")
|
|
54
|
+
|
|
55
|
+
for place in results["places"]:
|
|
56
|
+
place_id = place["id"]
|
|
57
|
+
place_name = place["displayName"]["text"]
|
|
58
|
+
place_address = place["formattedAddress"]
|
|
59
|
+
place_rating = place.get("rating")
|
|
60
|
+
place_reviews = place.get("userRatingCount")
|
|
61
|
+
websiteUrl = place.get("websiteUri")
|
|
62
|
+
place_phone = place.get("nationalPhoneNumber")
|
|
63
|
+
|
|
64
|
+
temp = classes.Lead(place_id, place_name, place_address, place_phone, websiteUrl, place_rating, place_reviews)
|
|
65
|
+
object_results.append(temp)
|
|
66
|
+
output = []
|
|
67
|
+
|
|
68
|
+
for lead in object_results:
|
|
69
|
+
valid = True
|
|
70
|
+
if not (website == "a" or (website == "y" and lead.website) or (website == "n" and not lead.website)):
|
|
71
|
+
valid = False
|
|
72
|
+
if min_rating > lead.rating:
|
|
73
|
+
valid = False
|
|
74
|
+
if max_rating < lead.rating:
|
|
75
|
+
valid = False
|
|
76
|
+
if min_reviews > lead.reviews:
|
|
77
|
+
valid = False
|
|
78
|
+
if max_reviews < lead.reviews:
|
|
79
|
+
valid = False
|
|
80
|
+
if valid:
|
|
81
|
+
output.append(lead)
|
|
82
|
+
if campaign_active:
|
|
83
|
+
save_lead(lead, campaign_active)
|
|
84
|
+
|
|
85
|
+
if output_format == "cli":
|
|
86
|
+
output_functions.output_cli(output)
|
|
87
|
+
elif output_format == "csv":
|
|
88
|
+
output_functions.output_csv(output)
|
|
89
|
+
all_good = False
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from dotenv import load_dotenv, set_key
|
|
3
|
+
|
|
4
|
+
# setup command
|
|
5
|
+
# setup places api key
|
|
6
|
+
# set max limit
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def setup(choice: str = typer.Argument(...), value: str | None = typer.Argument(None)):
|
|
11
|
+
|
|
12
|
+
if choice == "key" and value:
|
|
13
|
+
set_key(".env", "API_KEY", value)
|
|
14
|
+
elif choice == "limit":
|
|
15
|
+
set_key(".env", "LIMIT", value)
|
|
16
|
+
|
|
17
|
+
elif choice == "key" and not value:
|
|
18
|
+
print("""
|
|
19
|
+
To use leadminer, you need a Google Places API key.
|
|
20
|
+
|
|
21
|
+
1. Go to this link, sign in, and click "enable":
|
|
22
|
+
https://console.cloud.google.com/apis/library/places-backend.googleapis.com
|
|
23
|
+
|
|
24
|
+
2. Create an API key:
|
|
25
|
+
https://console.cloud.google.com/apis/credentials
|
|
26
|
+
|
|
27
|
+
3. Copy the key and run:
|
|
28
|
+
leadminer setup key <YOUR_API_KEY>
|
|
29
|
+
""")
|
|
30
|
+
|