Feature: Implement Captcha - Success
acheong08 opened this issue · comments
if soup.find('img', alt='captcha'):
print(f"{Fore.RED}[OpenAI][5] {Fore.RED}Captcha detected")
svg_captcha = soup.find('img', alt='captcha')['src'].split(',')[1]
decoded_svg = base64.decodebytes(svg_captcha.encode("ascii"))
# Convert decoded svg to png
drawing = svg2rlg(BytesIO(decoded_svg))
# Better quality
renderPM.drawToFile(drawing, "captcha.png", fmt="PNG", dpi=300)
print(f"{Fore.GREEN}[OpenAI][5] {Fore.WHITE}Captcha saved to {Fore.GREEN}captcha.png"
+ f" {Fore.WHITE}in the current directory")
# Wait.
captcha_input = input(f"{Fore.GREEN}[OpenAI][5] {Fore.WHITE}Please solve the captcha and "
f"press enter to continue: ")
if captcha_input:
print(f"{Fore.GREEN}[OpenAI][5] {Fore.WHITE}Continuing...")
self._part_six(state=state, captcha=captcha_input)
else:
raise Exceptions.PyChatGPTException("[OpenAI][5] You didn't enter anything.")
else:
print(f"{Fore.GREEN}[OpenAI][5] {Fore.GREEN}No captcha detected")
self._part_six(state=state, captcha=None)
Translate this to use requests and regex
Stage 1: Success. Captcha svg has been detected. Now need to save to disk somehow
Stage 2: Success. Saved to .svg file
Complete! Login with captcha successful
Any chances that we get a sneaky captcha_solver
parameter to the login
method now that the captcha infrastructure is in place 😄 ? The parameter would receive a method that can be executed if provided.
One could wrap up a solver method like this:
from twocaptcha import TwoCaptcha
def captcha_solver(image_path):
api = TwoCaptcha('API_KEY')
result = solver.normal(image_path, caseSensitive=1)
return result['code']
Then you could run it here:
# Better quality
renderPM.drawToFile(drawing, "captcha.png", fmt="PNG", dpi=300)
print(f"{Fore.GREEN}[OpenAI][5] {Fore.WHITE}Captcha saved to {Fore.GREEN}captcha.png"
+ f" {Fore.WHITE}in the current directory")
if captcha_solver:
await captcha_input = captcha_solver('captcha.png')
else:
...
Some captcha solving APIs and ML models will block until they have a result, others don't. It would be up to the developer to write the method in such a way that it guarantees that the execution only continues once it has the result to return be it in the synchronous or asynchronous version of the library.
Another thing that I think is important is that we keep the login information somewhere in order to keep that info between executions. Let's say all relevant information is stored in the state
variable, a simple solution would be to serialize it to a file like this:
import pickle
with open('./state.pck', 'wb') as file:
pickle.dump(state, file, protocol=pickle.HIGHEST_PROTOCOL)
If the data is just a simple dictionary, you could as well just dump it to a JSON. The format doesn't really matter as long as you're able to keep the information safe. Another possibility would be to return the state object/dictionary on the login
method so developers can store it however they want and provide it to the login
method on the next time it is called using an auth_state
parameter. If this parameter is provided the login
method then checks if the information is still valid. If it's not, just restart the login process. If it is, renew it (if necessary) and return the updated object.
If the state object suffers alterations during the program execution (for example, if you're required to refresh tokens every now and then) please offer a get_state
method that developers can use to dump the state at the end of the execution in order to have the latest version of it so we don't have to keep repeating the login steps between executions.
EDIT: If I can say so, letting developers deal with storing the state information is probably the best way. As developers are currently required to save the conversation thread themselves so they can make sure the AI remembers context in future evocations, storing the auth information should be trivial.
Any chances that we get a sneaky captcha_solver parameter to the login method now that the captcha infrastructure is in place smile ? The parameter would receive a method that can be executed if provided.
Edit: I found a way. Let me look through it
Example from ChatGPT:
# Define a function that takes another function as an argument
def apply_function(func, arg):
# Call the function that was passed as an argument, passing it the specified argument
return func(arg)
# Define a function that takes a single argument and returns its square
def square(x):
return x * x
# Call the `apply_function()` function, passing it the `square()` function and the argument 2
result = apply_function(square, 2)
# Print the result
print(result) # Output: 4
If I can say so, letting developers deal with storing the state information is probably the best way. As developers are currently required to save the conversation thread themselves so they can make sure the AI remembers context in future evocations, storing the auth information should be trivial.
I'm a but confused about this part. Could you explain?
Another thing that I think is important is that we keep the login information somewhere in order to keep that info between executions. Let's say all relevant information is stored in the state variable, a simple solution would be to serialize it to a file like this:
Rather than writing to a file from the library itself, I think it would be better to return a serialized object which can be saved by the user. I want to minimize file read/writes in the library. (Captcha is the exception because I can't find any other way)
I am writing the captcha solver param now and the example
Also, moving this to OpenAIAuth repo
@alexandreteles I have added the feature you requested. You can now pass an object into the Chatbot class which contains a solve_captcha
function. This will run if not null with raw_svg being a param input
I'll look into the implementation when I have some free time later today. Raw svg is fine, if the captcha solver needs something different wand-py will do the conversion magic.
Do you plan on adding support for this on the async version as well?
Do you plan on adding support for this on the async version as well?
The async version is maintained by @Harry-Jing so it'll take some time to implement there
If I can say so, letting developers deal with storing the state information is probably the best way. As developers are currently required to save the conversation thread themselves so they can make sure the AI remembers context in future evocations, storing the auth information should be trivial.
I'm a but confused about this part. Could you explain?
When /src/asyncChatGPT/asyncChatGPT.py:351 calls the begin method from OpenAIAuth.py
it receives back a session_token
that is then internally stored in the object and can be refreshed, if required, by calling the refresh_session method.
This means that developers can access the token and store it for posterior use by just accessing the attribute and storing it however they prefer. What I was trying to suggest here although I did a terrible job at it (it was like 5 in the morning, I beg your pardon) is the following:
- Add a way to provide a session token to the
Chatbot
- Check if the session token is still valid
- If it's not, renew it
- If renewing failed, run the authentication pipeline again
This should allow developers to keep session information between runs, lowering the login attempts necessary during development and deployment.
At this moment I think this is more about ChatGPT
than OpenAIAuth
but I'm posting my answer here to preserve the context. Please let me know if I wasn't clear enough once again, English isn't my first language so I can be a bit unclear sometimes 😄
EDIT: the async library works like a charm, thank you!
I see. I will try to do some refactoring today to simplify the logic and allow the sessions to be saved.
Add a way to provide a session token to the Chatbot
Check if the session token is still valid
If it's not, renew it
If renewing failed, run the authentication pipeline again
This was done in the revChatGPT package
Add a way to provide a session token to the Chatbot
Check if the session token is still valid
If it's not, renew it
If renewing failed, run the authentication pipeline againThis was done in the revChatGPT package
Would you mind sharing which attributes contain the relevant information at runtime?
Chatbot.config
contains all relevant authentication details. (session token, access token, email, password) while Chatbot.conversation_id_prev_queue
contains a list of previous conversation ids and Chatbot.parent_id_prev_queue
contains the list for previous message ids