-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
200 lines (164 loc) · 7.77 KB
/
main.py
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
189
190
191
192
193
194
195
196
197
198
199
200
from aiogram import Bot, Dispatcher, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.types import ReplyKeyboardMarkup, ReplyKeyboardRemove
from aiogram.utils import executor
from aiogram.utils.exceptions import TelegramAPIError
from dotenv import load_dotenv
import os
from chatgpt import generate_task_for_ai, analyze_task
load_dotenv()
bot = Bot(token=os.getenv("BOT_TOKEN"))
LOCATIONS = int(os.getenv("LOCATIONS_NUM"))
CHECK_LISTS = int(os.getenv("CHECK_LISTS_NUM"))
storage = MemoryStorage()
dp = Dispatcher(bot, storage=storage)
class UserChecklist(StatesGroup):
location_selection = State()
checklist_entry = State()
comment_input = State()
photo_upload = State()
@dp.message_handler(commands=["start"], state="*")
async def start_checklist(message: types.Message):
"""
Handles the '/start' command and starts the checklist process.
Args:
message (types.Message): The incoming message object.
"""
await message.reply("Let's start the checklist. Please select a location:")
await list_locations(message)
async def list_locations(message: types.Message):
"""
Lists the available locations for the checklist.
Args:
message (types.Message): The incoming message object.
"""
await UserChecklist.location_selection.set()
keyboard = ReplyKeyboardMarkup(resize_keyboard=True)
locations = [f"Location {i + 1}" for i in range(0, LOCATIONS)]
keyboard.add(*locations)
await message.answer("Choose a location:", reply_markup=keyboard)
@dp.message_handler(state=UserChecklist.location_selection)
async def process_location(message: types.Message, state: FSMContext):
"""
Processes the selected location and updates the state.
Args:
message (types.Message): The incoming message object.
state (FSMContext): The current state of the conversation.
"""
await state.update_data(chosen_location=message.text)
await message.answer(f"You have selected: {message.text}", reply_markup=ReplyKeyboardRemove())
await UserChecklist.checklist_entry.set()
await start_checklist_process(message, state)
async def start_checklist_process(message: types.Message, state: FSMContext):
"""
Starts the checklist process and presents the first entry.
Args:
message (types.Message): The incoming message object.
state (FSMContext): The current state of the conversation.
"""
await message.answer("Starting the checklist process. Please answer each entry.")
await process_checklist_entry(message, state, 1)
async def process_checklist_entry(message: types.Message, state: FSMContext, entry_number: int):
"""
Presents the current checklist entry and updates the state.
Args:
message (types.Message): The incoming message object.
state (FSMContext): The current state of the conversation.
entry_number (int): The number of the current checklist entry.
"""
await state.update_data(current_entry=entry_number)
keyboard = ReplyKeyboardMarkup(resize_keyboard=True)
keyboard.add("All clear", "Leave a comment")
await message.answer(f"Checklist entry {entry_number}: Is everything clear?", reply_markup=keyboard)
@dp.message_handler(lambda message: message.text in ["All clear", "Leave a comment"],
state=UserChecklist.checklist_entry)
async def check_clearance(message: types.Message, state: FSMContext):
"""
Handles the user's response to the checklist entry.
Args:
message (types.Message): The incoming message object.
state (FSMContext): The current state of the conversation.
"""
user_data = await state.get_data()
entry_number = user_data["current_entry"]
if message.text == "Leave a comment":
await UserChecklist.comment_input.set()
await message.answer(f"Please provide a comment for entry {entry_number}:")
else:
if entry_number < CHECK_LISTS:
await process_checklist_entry(message, state, entry_number + 1)
else:
await finalize_checklist(message, state)
@dp.message_handler(state=UserChecklist.comment_input)
async def process_comment(message: types.Message, state: FSMContext):
"""
Processes the user's comment and updates the state.
Args:
message (types.Message): The incoming message object.
state (FSMContext): The current state of the conversation.
"""
user_data = await state.get_data()
entry_number = user_data["current_entry"]
await state.update_data({f"comment_entry_{entry_number}": message.text})
await UserChecklist.photo_upload.set()
keyboard = ReplyKeyboardMarkup(resize_keyboard=True)
keyboard.add("/Skip")
await message.answer(
f"Please upload a photo related to your comment for entry {entry_number}, or skip to continue without one.",
reply_markup=keyboard)
@dp.message_handler(commands=["Skip"], state=UserChecklist.photo_upload)
async def skip_photo(message: types.Message, state: FSMContext):
"""
Skips the photo upload and continues with the checklist.
Args:
message (types.Message): The incoming message object.
state (FSMContext): The current state of the conversation.
"""
await UserChecklist.checklist_entry.set()
await message.answer("Skipping photo upload. Continuing with the checklist.")
await process_checklist_entry(message, state, (await state.get_data()).get("current_entry", 1) + 1)
@dp.message_handler(content_types=["photo"], state=UserChecklist.photo_upload)
async def process_photo(message: types.Message, state: FSMContext):
"""
Processes the uploaded photo and updates the state.
Args:
message (types.Message): The incoming message object.
state (FSMContext): The current state of the conversation.
"""
try:
photo_file = await bot.get_file(message.photo[-1].file_id)
photo_url = f"https://api.telegram.org/file/bot{os.getenv('BOT_TOKEN')}/{photo_file.file_path}"
user_data = await state.get_data()
entry_number = user_data["current_entry"]
await state.update_data({f"photo_entry_{entry_number}": photo_url})
await UserChecklist.checklist_entry.set()
await message.answer("Photo uploaded successfully. Continuing with the checklist.")
await process_checklist_entry(message, state, entry_number + 1)
except TelegramAPIError:
await message.reply("There was an issue with the Telegram API. Please try again.")
except FileNotFoundError:
await message.reply("The photo file was not found. Please try again.")
async def finalize_checklist(message: types.Message, state: FSMContext):
"""
Finalizes the checklist process and performs any necessary cleanup.
Args:
message (types.Message): The incoming message object.
state (FSMContext): The current state of the conversation.
"""
await message.answer("Checklist completed. Thank you for your input.")
user_data = await state.get_data()
report = generate_task_for_ai(user_data)
photos = {f"check list {i + 1}": user_data.get(f"photo_entry_{i + 1}")
for i in range(CHECK_LISTS)
if f"photo_entry_{i + 1}" in user_data}
finish_report = await analyze_task(report, photos=photos)
if finish_report:
await message.answer("Answer: " + finish_report)
else:
await message.answer("The report could not be parsed.")
await state.finish()
await list_locations(message)
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)