-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
188 lines (157 loc) · 6.49 KB
/
Copy pathmain.py
File metadata and controls
188 lines (157 loc) · 6.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
"""Main entry point for the Telegram Expense Tracker application."""
import os
import sys
from dotenv import load_dotenv
from pathlib import Path
from src.storage import LocalStorage
from src.core import ExpenseTrackerCore
from src.sync import GoogleSheetsSyncService
from src.llm import LLMService
from src.bot import TelegramBotHandler
def load_configuration():
"""
Load configuration from environment variables.
Returns:
dict: Configuration dictionary with required settings
Raises:
ValueError: If required environment variables are missing
"""
# Load environment variables from .env file
load_dotenv()
# Get required configuration
bot_token = os.getenv('TELEGRAM_BOT_TOKEN')
credentials_path = os.getenv('GOOGLE_CREDENTIALS_PATH', 'credentials.json')
data_file_path = os.getenv('DATA_FILE_PATH', 'data.json')
authorized_user_id = os.getenv('AUTHORIZED_USER_ID')
anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')
anthropic_model = os.getenv('ANTHROPIC_MODEL', 'claude-haiku-4-20250414')
# Validate required configuration
if not bot_token:
raise ValueError(
"TELEGRAM_BOT_TOKEN environment variable is required. "
"Please set it in your .env file."
)
# Check if credentials file exists
if not Path(credentials_path).exists():
print(f"⚠️ Warning: Google credentials file not found at {credentials_path}")
print(" Google Sheets sync will not be available until credentials are configured.")
return {
'bot_token': bot_token,
'credentials_path': credentials_path,
'data_file_path': data_file_path,
'authorized_user_id': authorized_user_id,
'anthropic_api_key': anthropic_api_key,
'anthropic_model': anthropic_model,
}
async def initialize_authorized_user(core: ExpenseTrackerCore, user_id: str):
"""
Initialize the authorized user if provided.
Args:
core: ExpenseTrackerCore instance
user_id: Telegram user ID to authorize
"""
if user_id:
# Check if user is already authorized
is_authorized = await core.is_authorized(user_id)
if not is_authorized:
print(f"📝 Authorizing user ID: {user_id}")
await core.authorize_user(user_id)
print("✅ User authorized successfully")
else:
print(f"✅ User ID {user_id} is already authorized")
def main():
"""
Main function to initialize and start the Telegram Expense Tracker bot.
This function:
1. Loads configuration from environment variables
2. Initializes LocalStorage for data persistence
3. Initializes ExpenseTrackerCore for business logic
4. Initializes GoogleSheetsSyncService for sync operations
5. Initializes TelegramBotHandler with all dependencies
6. Starts the bot polling
"""
try:
print("🚀 Initializing Telegram Expense Tracker...")
print()
# Load configuration
print("📋 Loading configuration...")
config = load_configuration()
print("✅ Configuration loaded")
print()
# Initialize LocalStorage
print(f"💾 Initializing local storage (file: {config['data_file_path']})...")
storage = LocalStorage(data_file=config['data_file_path'])
print("✅ Local storage initialized")
print()
# Initialize ExpenseTrackerCore
print("🧠 Initializing expense tracker core...")
core = ExpenseTrackerCore(storage=storage)
print("✅ Expense tracker core initialized")
print()
# Initialize authorized user if provided
if config['authorized_user_id']:
import asyncio
asyncio.run(initialize_authorized_user(core, config['authorized_user_id']))
print()
# Initialize GoogleSheetsSyncService
print(f"📊 Initializing Google Sheets sync service...")
try:
sync_service = GoogleSheetsSyncService(
credentials_file=config['credentials_path']
)
print("✅ Google Sheets sync service initialized")
except FileNotFoundError:
print("⚠️ Google Sheets sync service not available (credentials file not found)")
print(" The bot will work in local-only mode")
sync_service = None
except Exception as e:
print(f"⚠️ Google Sheets sync service initialization failed: {e}")
print(" The bot will work in local-only mode")
sync_service = None
print()
# Initialize LLM service
print("🧠 Initializing LLM service...")
llm_service = None
if config['anthropic_api_key']:
llm_service = LLMService(
api_key=config['anthropic_api_key'],
model=config['anthropic_model'],
)
print(f"✅ LLM service initialized (model: {config['anthropic_model']})")
else:
print("⚠️ ANTHROPIC_API_KEY not set — natural language input disabled")
print(" The bot will only accept CLI commands (q <command>)")
print()
# Initialize TelegramBotHandler
print("🤖 Initializing Telegram bot handler...")
bot_handler = TelegramBotHandler(
core=core,
sync_service=sync_service,
bot_token=config['bot_token'],
llm_service=llm_service,
)
print("✅ Telegram bot handler initialized")
print()
# Start bot polling
print("=" * 50)
print("✅ All components initialized successfully!")
print("=" * 50)
print()
bot_handler.run()
except ValueError as e:
print(f"❌ Configuration Error: {e}")
print()
print("Please check your .env file and ensure all required variables are set.")
print("See .env.example for reference.")
sys.exit(1)
except KeyboardInterrupt:
print()
print("🛑 Bot stopped by user")
sys.exit(0)
except Exception as e:
print(f"❌ Unexpected Error: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()