-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathflight.py
More file actions
318 lines (256 loc) · 13.2 KB
/
flight.py
File metadata and controls
318 lines (256 loc) · 13.2 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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
import subprocess
import asyncio
from pydantic import BaseModel
from dotenv import load_dotenv
from playwright.async_api import Page
from browser_use import Agent, BrowserSession, Controller, ActionResult, ChatAnthropic
from browser_use.browser import BrowserSession
load_dotenv()
SENSITIVE_DATA = {
"first_name": "JaeYoung",
"last_name": "Lee",
"email": "test@gmail.com",
"country": "대한민국",
"phone_number": "10-1234-5678", # 실제로는 01012345678 또는 12345678 형태로 입력될 수 있음
"gender": "남성", # '남성' 또는 '여성'
# 탑승객 정보
"birth_date": "2001-03-09", # YYYY-MM-DD 형식
"passenger_passport_number": "M123456789", # 여권 번호 예시
"passenger_passport_expire_date": "2030-12-31", # 여권 만료일 예시
}
try:
subprocess.run(["pkill", "-f", "chromium"], check=False)
subprocess.run(["pkill", "-f", "playwright"], check=False)
print("✅ chromium 및 playwright 프로세스 종료 완료")
except Exception as e:
print(f"⚠️ 종료 중 오류 발생: {e}")
class Flight(BaseModel) :
departure : str
arrival : str
departure_date : str
arrival_date : str
class Flights(BaseModel) :
flights : list[Flight]
controller = Controller(output_model=Flights)
@controller.action('Request user to manually enter payment information')
async def request_payment_input(field_type: str) -> ActionResult:
print(f"\n⚠️ 결제 정보 입력이 필요합니다")
print(f"📋 입력 필드: {field_type}")
print("🔒 보안을 위해 직접 브라우저에서 입력해주세요")
input("✅ 입력 완료 후 Enter를 눌러주세요...")
return ActionResult(
extracted_content="User manually entered payment information",
include_in_memory=False
)
def set_flight_search_info():
return """
※ 절대 새로고침(페이지 강제 새로고침)은 하지 마세요.
* 스크롤도 금지합니다.
1. [출발편 설정]
- agoda.com에 접속합니다.
- 상단 메뉴에서 "항공권"을 클릭합니다.
- "왕복"을 선택합니다.
- 다음 정보를 정확히 입력하고 알맞는 공항을 선택하세요.:
- 출발지: ICN
- 도착지: NRT
✅ **가는날과 오는날 날짜 확인 및 설정 (필수 조건)**
✈️ 현재 설정된 날짜가 다음과 일치하는지 반드시 먼저 확인하세요:
- 가는날: **2025년 8월 20일**
- 오는날: **2025년 8월 25일**
⚠️ 위 날짜가 **이미 설정되어 있다면** 절대 수정하지 마세요.
⚠️ 위 날짜가 **설정되어 있지 않은 경우에만** 아래 순서에 따라 변경하세요:
🔹 **가는날(2025년 8월 20일)** 설정 방법:
1) '가는날' 입력 필드를 클릭합니다.
2) **8월 20일** 날짜를 찾아 **딱 한 번만 클릭**합니다.
🔹 **오는날(2025년 8월 25일)** 설정 방법:
1) '가는날' 옆에 있는 '오는날'필드에 똑같이 2025년 8월 25일이 있으면 즉시 변경을 합니다.
1) **8월 25일** 날짜를 찾아 **딱 한 번만 클릭**합니다.
- 인원: 1명
- 좌석: 이코노미 클래스
- 위 항목들을 모두 정확히 입력한 후, **"검색" 버튼을 클릭**합니다.
"""
def go_travel():
return """
새로고침은 절대로 하지마.
계열사 선택 금지.
✅ 1. 티웨이항공 필터 적용 (반복 금지)
a. 좌측 필터 영역에서 '항공사' 섹션 찾기.
b. '항공사 n곳 모두 보기' 클릭은 딱 한 번만.
c. '티웨이항공' 체크박스 찾기 (안 보아면 스크롤 해서 찾기).
d. 딱 한 번만 클릭해서 체크하기.
e. 체크 상태로 바뀌면 다시 클릭 또는 해제 절대 금지.
f. 필터 적용 확인 (목록 내 항공사명과 체크박스 상태).
✅ 2. 필터 적용 결과 확인
a. 항공편 목록에 로딩 표시가 있으면 로딩이 끝날 때까지 대기합니다.
b. 모든 항공편이 '티웨이항공' 인지 확인합니다.
✅ 3. 최저가 항공편 선택
a. 필터링된 항공편 중 가장 저렴한 '티웨이항공' 항공편을 클릭합니다.
b. 조건 만족되면 '선택하기' 버튼 클릭
---------------------------------------------------
※ 새로고침(페이지 강제 재로딩)은 절대 하지 말 것.
※ 모든 이동은 페이지 내 UI 조작(클릭, 탭 전환 등)으로만 진행.
※ 필터 적용 시 중복 클릭 금지, 필터 상태 유지 철저.
"""
def come_travel():
return"""
새로고침은 절대로 하지마.
계열사 선택 금지.
✅ 1. 오는편 페이지 전환 확인
- 가는편 선택 후, 자동으로 오는편 페이지로 전환됩니다.
- 별도 탭 전환이나 추가 클릭 없이 진행됩니다.
✅ 2. 티웨이항공 필터 적용 (반복 금지)
a. 좌측 필터 영역에서 '항공사' 섹션 찾기.
b. '항공사 n곳 모두 보기' 클릭은 딱 한 번만.
c. '티웨이항공' 체크박스 찾기 (안 보아면 스크롤 해서 찾기).
d. 딱 한 번만 클릭해서 체크하기.
e. 체크 상태로 바뀌면 다시 클릭 또는 해제 절대 금지.
f. 필터 적용 확인 (목록 내 항공사명과 체크박스 상태).
✅ 3. 필터 적용 결과 확인
a. 항공편 목록에 로딩 표시가 있으면 로딩이 끝날 때까지 대기합니다.
b. 모든 항공편이 '티웨이항공' 또는 '티웨이항공'인지 확인합니다.
✅ 4. 최저가 항공편 선택
a. 필터링된 항공편 중 가장 저렴한 '티웨이항공' 항공편을 클릭합니다.
b. 조건 만족되면 '선택하기' 버튼 클릭
---------------------------------------------------
※ 새로고침(페이지 강제 재로딩)은 절대 하지 말 것.
※ 모든 이동은 페이지 내 UI 조작(클릭, 탭 전환 등)으로만 진행.
※ 필터 적용 시 중복 클릭 금지, 필터 상태 유지 철저.
"""
def user_info():
birth_year, birth_month, birth_day = SENSITIVE_DATA["birth_date"].split("-")
birth_month_numeric = str(int(birth_month))
birth_day_numeric = str(int(birth_day))
return f"""
## 예약 절차 진행 (정보 입력):
1. **연락처 정보 입력**: 연락처 정보 입력 섹션에 다음 정보를 입력
- '영문 이름(First Name)' 필드에 `first_name`을 입력
- '영문 성(Last Name)' 필드에 `last_name`을 입력
- '이메일 주소' 필드에 `email`을 입력
- '거주 국가/지역' 드롭다운 버튼을 클릭한 후, 드롭다운의 검색창에 `country`를 입력하고, 드롭다운 목록에 나타나는 `country` 항목 선택
- '전화번호' 필드에 `phone_number`를 입력
-빈칸이 있으면 그 항목 다시 입력하고 2번으로 이동
2. **페이지 스크롤**: 연락처 정보 입력 후, 웹 페이지 하단으로 스크롤하여 탑승객 정보 입력 섹션으로 이동
3. **탑승객 정보 (성인) 입력**: 이어서 탑승객 정보(성인) 섹션에 다음 정보를 입력
- **성별**: '성별' 항목에서 `gender` 값에 해당하는 성별 라디오 버튼을 한 번 클릭하여 선택 (예: `gender`가 "남성"이면 '남성' 라디오 버튼 클릭)
- **영문 이름 및 영문 중간 이름**: '영문 이름 & 영문 중간 이름' 필드에 `first_name`을 입력
- **영문 성**: '영문 성(Last Name)' 필드에 `last_name`을 입력
- **생년월일**: '생년월일' 섹션에 다음을 입력
- '년도' 입력 필드에 {birth_year}을 입력
- '월' 드롭다운 메뉴를 클릭하여 '{birth_month_numeric}월' 선택
- '일' 입력 필드에 {birth_day_numeric}을 입력
- **국적**: '국적' 드롭다운 버튼을 클릭한 후, 검색창에 'country' 입력하고, 드롭다운 목록에 나타나는 'country' 항목 선택
- 국가 텍스트 인식을 할 때 'country' 아닌 다른 나라가 있으면 다시 'country' 입력하고 클릭.
- **여권 섹션**: (**만약 여권 관련 정보 입력 항목 혹은 필드가 없다면 이 작업은 스킵**)
- '여권번호' 필드에 `passport_number`를 입력
- '여권 발행 국가' 드롭다운 버튼을 클릭한 후, 검색창에 `country`를 입력하고, 드롭다운 목록에 나타나는 `country` 항목 선택
- **여권 만료일**: '여권 만료일' 섹션에 다음을 입력
- '년도' 입력 필드에 `passport_expire_date`의 연도 부분을 입력
- '월' 드롭다운 버튼을 클릭하여 드롭다운 메뉴에서 `passport_expire_date`의 월 부분에 해당하는 라디오 버튼 또는 옵션을 한 번 클릭하여 선택
- '일' 입력 필드에 `passport_expire_date`의 일 부분을 입력
4. **최종 동의 및 진행**:
- "다음의 모든 항목에 동의합니다." 체크박스 딱 한번만 클릭
5. **부가서비스, 지원서비스 및 여행 보험**:
- 부가서비스, 지원서비스는 기본 옵션 선택
- 여행 보험은 사용하지 않음.
"""
def make_task_card_number():
return"""
1.request_payment_input("credit_card") 함수 호출
2. agent 종료
"""
extend_planner_message = f"""
REMEMBER the most important RULE:
Make decisions at each stage carefully, and once done correctly, never repeat the task.
If you find yourself setting the exact same 'Next goal' as the previous step, or performing the exact same action on the same element multiple times without the desired page change or a clear visual confirmation of success, critically re-evaluate:
1. Is the goal truly not achieved, or am I misinterpreting the page state? (e.g., Did the filter *actually* apply even if I didn't see a spinner? Is the checkbox *already* checked?)
2. Is the page still loading or updating from my previous action? Consider waiting a bit longer, especially if the task involves filtering or loading new content.
3. Did I click the correct element? Is there a more specific or reliable element I should target (e.g., a checkbox directly associated with the text, or an element with a unique ID)? Double-check the element's properties.
4. If an action is not working as expected after a couple of tries, do not repeat it endlessly. Re-assess the page, your understanding of the task, and consider a slightly different approach or element. For example, if clicking a checkbox isn't working, is there an "Apply" button I missed?
Avoid getting stuck in a loop. If a specific action on a specific element isn't working, repeating it won't help. Assume your previous action *might* have worked and look for evidence.
"""
FLIGHT_SEARCH = set_flight_search_info()
GO_FILTER = go_travel()
COME_FILTER = come_travel()
USER_INFO = user_info()
CARD = make_task_card_number()
llm = ChatAnthropic(
model="claude-sonnet-4-0",
)
reused_session = BrowserSession(
keep_alive=True,
wait_for_network_idle_page_load_time=1.0,
no_viewport=False,
window_size={"width": 1280, "height": 1100}
)
agent1 = Agent(
extend_system_message=extend_planner_message,
browser_session=reused_session,
task=FLIGHT_SEARCH,
llm=llm,
override_system_message="",
max_actions_per_step=1,
)
agent2 = Agent(
extend_system_message=extend_planner_message,
browser_session=reused_session,
task=GO_FILTER,
llm=llm,
override_system_message="",
max_actions_per_step=1,
)
agent3 = Agent(
extend_system_message=extend_planner_message,
browser_session=reused_session,
task=COME_FILTER,
llm=llm,
override_system_message="",
max_actions_per_step=1,
)
agent4 = Agent(
extend_system_message=extend_planner_message,
browser_session=reused_session,
task=USER_INFO,
llm=llm,
override_system_message="",
max_actions_per_step=1,
sensitive_data=SENSITIVE_DATA
)
agent5 = Agent(
extend_system_message=extend_planner_message,
browser_session=reused_session,
task=CARD,
llm=llm,
controller=controller,
override_system_message="",
max_actions_per_step=1,
)
async def main1():
await agent1.run(
max_steps=150,
)
async def main2():
await agent2.run(
max_steps=150,
)
async def main3():
await agent3.run(
max_steps=150,
)
async def main4():
await agent4.run(
max_steps=150,
)
async def main5():
await agent5.run(
max_steps=150,
)
async def main():
await reused_session.start()
await main1()
await main2()
await main3()
await main4()
await main5()
await reused_session.kill()
if __name__ == "__main__":
asyncio.run(main())