App-PythonToPerl

 view release on metacpan or  search on metacpan

lib/Python/Unknown.pm  view on Meta::CPAN

    my string::arrayref $stop_sequences = ['# Python to', 'Python:'];

    # DEV NOTE: shorten error sequences to speed up matching and allow for new or different wording
    my string::arrayref $error_sequences = [
        'Sorry, ',
#        'Sorry, as an AI language model, I cannot see any Python source code to translate. Can you please provide the code so I can assist you better?',
#        'Sorry, I cannot perform this task as the provided Python source code is incomplete and does not provide enough information to be translated accurately. Please provide the complete code.',
    ];

    # assemble "Python to Perl" message strings
    my string::hashref::arrayref $messages = [
        # DEV NOTE: save money by transmitting fewer tokens!
#        { 'role' => 'system',    'content' => 'You are a helpful assistant with detailed knowledge of the Perl and Python computer programming languages, as well as modern software development best practices.' },
#        { 'role' => 'user',      'content' => 'Translate the following Python source code to Perl:' . "\n" . $self->{python_source_code} . "\n" },
        { 'role' => 'user',      'content' => 'Translate this Python to Perl:' . "\n" . $self->{python_source_code} . "\n" },
    ];

print 'in Python::Unknown::python_preparsed_to_perl_source(), have $self->{python_source_code} =', "\n", $self->{python_source_code}, "\n";
print 'in Python::Unknown::python_preparsed_to_perl_source(), about to call python_preparsed_to_perl_source_api_call()...', "\n";

    # call OpenAI API
    my hashref $response = $self->python_preparsed_to_perl_source_api_call($openai, $stop_sequences, $messages);

print 'in Python::Unknown::python_preparsed_to_perl_source(), ret from call to python_preparsed_to_perl_source_api_call()', "\n";
#print 'in Python::Unknown::python_preparsed_to_perl_source(), received $response = ', Dumper($response), "\n";
#die 'TMP DEBUG, UNKNOWN';

# [[[ BEGIN FAILED API CALLS ]]]
# [[[ BEGIN FAILED API CALLS ]]]
# [[[ BEGIN FAILED API CALLS ]]]

    # handle HTTP response status codes returned from LWP::UserAgent
    if ((defined $EVAL_ERROR) and ($EVAL_ERROR ne '')) {

# NEED UPGRADE: accept any error code and just retry???
# NEED UPGRADE: accept any error code and just retry???
# NEED UPGRADE: accept any error code and just retry???

print 'in Python::Unknown::python_preparsed_to_perl_source(), received $EVAL_ERROR = \'', $EVAL_ERROR, '\'', "\n";

        # Error retrieving 'completions': 400 Bad Request
        if ($EVAL_ERROR =~ '400 Bad Request') {
            croak 'ERROR EPYUN013a: received HTTP response status code 400 (bad request) instead of OpenAI::API response, croaking', "\n", $EVAL_ERROR, "\n"; 
        }
        # Error retrieving 'completions': 429 Too Many Requests
        elsif ($EVAL_ERROR =~ '429 Too Many Requests') {
            carp 'WARNING WPYUN013b: received HTTP response status code 429 (too many requests) instead of OpenAI::API response, carping', "\n", $EVAL_ERROR, "\n"; 

            my integer $retries = 0;

            # backoff algorithm; increase sleep time and retry
            # https://help.openai.com/en/articles/5955604-how-can-i-solve-429-too-many-requests-errors
            # https://platform.openai.com/docs/guides/rate-limits/error-mitigation
            while ((defined $EVAL_ERROR) and ($EVAL_ERROR =~ '429 Too Many Requests')) {
print 'in Python::Unknown::python_preparsed_to_perl_source(), about to retry #', $retries, ' call python_preparsed_to_perl_source_api_call()...', "\n";
                $retries++;
                if ($retries >= $self->{retries_max}) {
                    croak 'ERROR EPYUN013b: received HTTP response status code 429 (too many requests) instead of OpenAI::API response, maximum retry limit ', $self->{retries_max}, ' reached, croaking'; 
                }

                # increase time to sleep by some percentage of current amount
                $self->{sleep_seconds} *= $self->{sleep_retry_multiplier};

print 'in Python::Unknown::python_preparsed_to_perl_source(), about to retry #', $retries, ' call sleep(', $self->{sleep_seconds}, ')...', "\n";
                # retry sleep before calling API
                sleep($self->{sleep_seconds});
print 'in Python::Unknown::python_preparsed_to_perl_source(), ret from retry #', $retries, ' call to sleep(', $self->{sleep_seconds}, ')', "\n";

                # retry call to OpenAI API
                $response = $self->python_preparsed_to_perl_source_api_call($openai, $messages);

print 'in Python::Unknown::python_preparsed_to_perl_source(), ret from retry #', $retries, ' call to python_preparsed_to_perl_source_api_call()', "\n";
#print 'in Python::Unknown::python_preparsed_to_perl_source(), received $response = ', Dumper($response), "\n";
#die 'TMP DEBUG, UNKNOWN 429 TOO MANY REQUESTS';
            }
        }
        # Error retrieving 'completions': 500 read timeout
        elsif ($EVAL_ERROR =~ '500 read timeout') {
            croak 'ERROR EPYUN013c: received HTTP response status code 500 (read timeout) instead of OpenAI::API response, croaking', "\n", $EVAL_ERROR, "\n"; 
# NEED SLEEP AND RETRY?
# NEED SLEEP AND RETRY?
# NEED SLEEP AND RETRY?
        }
        else {
            croak 'ERROR EPYUN013d: received unrecognized HTTP response status code instead of OpenAI::API response, croaking', "\n", $EVAL_ERROR, "\n"; 
        }
    }

print 'in Python::Unknown::python_preparsed_to_perl_source(), ret from call to OpenAI completions(), received $response =', "\n", Dumper($response), "\n";

    # DEV NOTE: sometimes the API returns an undefined or empty finish_reason, but still with valid 'text' field;
    # carp & return dummy code if translation ends for any other reason than reaching a legitimate 'stop' condition
    if (not defined $response) {
        croak 'ERROR EPYUN014a: received undefined OpenAI::API response, croaking'; 
    }
    elsif ((not exists $response->{choices}) or (not defined $response->{choices}) or
        (not defined $response->{choices}->[0])) {
        croak 'ERROR EPYUN014b: received non-existent or undefined OpenAI::API response choice, croaking'; 
    }
    else {
        # response choice is defined, check finish_reason and text
        if ((not exists $response->{choices}->[0]->{finish_reason}) or (not defined $response->{choices}->[0]->{finish_reason})) {
            carp 'WARNING WPYUN015a: received non-existent or undefined OpenAI::API response finish_reason, carping'; 
        }
        elsif ($response->{choices}->[0]->{finish_reason} ne 'stop') {
            carp 'WARNING WPYUN015b: received OpenAI::API response finish_reason \'', $response->{choices}->[0]->{finish_reason}, '\', expected \'stop\', carping';
        }

        if ((not exists $response->{choices}->[0]->{message}) or (not defined $response->{choices}->[0]->{message})) {
            croak 'ERROR EPYUN016a: received non-existent or undefined OpenAI::API response message, croaking'; 
        }
        elsif ((not exists $response->{choices}->[0]->{message}->{content}) or (not defined $response->{choices}->[0]->{message}->{content})) {
            croak 'ERROR EPYUN016b: received non-existent or undefined OpenAI::API response message content, croaking'; 
        }
        else {
            # retrieve Perl source code out of valid response choice
            $self->{perl_source_code} = $response->{choices}->[0]->{message}->{content};
        }
    }

    # translated Perl code must not start with any stop sequence,



( run in 2.196 seconds using v1.01-cache-2.11-cpan-13bb782fe5a )