1
1
import json
2
2
import os
3
3
import re
4
+
5
+ from npiai_proto import api_pb2
4
6
from playwright .async_api import TimeoutError
5
7
from markdownify import MarkdownConverter
6
8
9
11
from npi .browser_app .navigator import Navigator
10
12
from npi .config import config
11
13
from npi .error .auth import UnauthorizedError
14
+ from npi .core .callback import callback
15
+ from npi .core .thread import Thread
12
16
from .schema import *
13
17
14
18
__SYSTEM_PROMPT__ = """
@@ -117,12 +121,12 @@ def __init__(self, llm=None, headless: bool = True):
117
121
118
122
self .register (Navigator (playwright = self .playwright ))
119
123
120
- async def start (self ):
124
+ async def start (self , thread : Thread = None ):
121
125
if not self ._started :
122
- await super ().start ()
123
- await self ._login ()
126
+ await super ().start (thread )
127
+ await self ._login (thread )
124
128
125
- async def _login (self ):
129
+ async def _login (self , thread : Thread ):
126
130
if os .path .exists (self .state_file ):
127
131
with open (self .state_file , 'r' ) as f :
128
132
state = json .load (f )
@@ -141,6 +145,19 @@ async def _login(self):
141
145
await self .playwright .page .get_by_test_id ('loginButton' ).click ()
142
146
await self .playwright .page .get_by_label ('Phone, email, or username' ).fill (self .creds .username )
143
147
await self .playwright .page .get_by_role ('button' , name = 'Next' ).click ()
148
+
149
+ # check if username(not email) is required
150
+ await self .playwright .page .wait_for_timeout (1000 )
151
+ username_input = self .playwright .page .get_by_test_id ("ocfEnterTextTextInput" )
152
+ if await username_input .count () != 0 :
153
+ username = await self ._request_username (thread )
154
+ await username_input .fill (username )
155
+ await self .playwright .page .get_by_test_id ("ocfEnterTextNextButton" ).click ()
156
+
157
+ await self .playwright .page .wait_for_timeout (1000 )
158
+ if await username_input .count () != 0 :
159
+ raise UnauthorizedError ('Unable to login to Twitter. Please try again with the correct credentials.' )
160
+
144
161
await self .playwright .page .get_by_label ('Password' , exact = True ).fill (self .creds .password )
145
162
await self .playwright .page .get_by_test_id ('LoginForm_Login_Button' ).click ()
146
163
await self .playwright .page .wait_for_url (__ROUTES__ ['home' ])
@@ -150,6 +167,26 @@ async def _login(self):
150
167
os .makedirs (save_dir , exist_ok = True )
151
168
await self .playwright .context .storage_state (path = self .state_file )
152
169
170
+ await thread .send_msg (callback .Callable ('Logged in to Twitter' ))
171
+
172
+ @staticmethod
173
+ async def _request_username (thread : Thread ) -> str :
174
+ if thread is None :
175
+ raise Exception ('`thread` must be provided to request username' )
176
+
177
+ cb = callback .Callable (
178
+ action = api_pb2 .ActionResponse (
179
+ type = api_pb2 .ActionType .HUMAN_FEEDBACK ,
180
+ human_feedback = api_pb2 .HumanFeedbackAction (
181
+ type = api_pb2 .HumanFeedbackActionType .INPUT ,
182
+ notice = 'Please enter your username (not email) to continue the login process.' ,
183
+ )
184
+ ),
185
+ )
186
+ cb .action .action_id = cb .id ()
187
+ await thread .send_msg (cb = cb )
188
+ return await cb .wait ()
189
+
153
190
@npi_tool
154
191
async def get_current_page (self ):
155
192
"""Get the title and url of the current page."""
0 commit comments