BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
smackerz1988
Pyrite | Level 9

I’m currently working on integrating the OpenAI API into SAS using PROC HTTP. I’m attempting to make a POST request to the Chat Completions API but I consistently encounter a rate limit error (HTTP 429) on every single attempt.

 

 

/* Body of the POST request */
filename in temp;
data _null_;
    file in;
    put '{"model": "gpt-3.5-turbo", "messages": [{"role": "user", "content": "' "&FinalPrompt." '"}]}';
run;

/* Send the request */
filename resp temp;
proc http 
    method = "POST"
    url    = "https://api.openai.com/v1/chat/completions"
    ct     = "application/json"
    in     = in
    out    = resp;
    headers "Authorization" = "Bearer &api_key.";           
run;

/* Print the response */
data _null_;
    infile resp;
    input;
    put _infile_;
run;

I always receive the following error, regardless of how infrequent or spaced out the requests are:

 

HTTP 429: Rate limit exceeded

What I’ve Tried So Far:

  1. API Key: I’ve verified that my API key is working.
  2. Spacing Out Requests: Even when I run the requests manually with long delays in between, I still hit the rate limit on every attempt even though it is 3.5 and I have a paid subscription.
  3. Retry Logic: I attempted implementing retry logic with exponential backoff, but it hasn’t resolved the issue either.
1 ACCEPTED SOLUTION

Accepted Solutions
smackerz1988
Pyrite | Level 9

I think what the issue is that i haven't used this macro since mid 2023 and since then OpenAI API is much more restrictive now than it was then so I need to upgrade my OpenAI API account on top of my chatgpt paid subscription. As this code used to work fine as is. If anyone has a personal API_KEY you can put it as a %let statement at the start of this code and run this version of my  macro on your end to  and see if you get the same thing 

%let api_key = sk-XXXXXXXX
data Prompts;
    length code $ 16 description $ 1024;
    do code="optimize","clean","efficient","fast","readable"; 
        description="I want you to act as a code optimizer in SAS. {Describe problem with current code, if possible.} 
                     Can you make the code {optimize/clean/efficient/fast/readable}? {Insert Code}";
        output;
    end;
    code="explain"; 
    description="I want you to act as a code explainer in SAS. I don't understand this function. 
                 Can you please explain what it does, and provide an example? {Insert Code}";
	 output;
	 code="debug"; 
    description="I want you to be a SAS programmer, here is a piece of SAS code {Insert Code}
                 — I am getting the following error {Insert Error}. What is the reason for the bug?";
    output;
run;


%macro chatgpt(api_key=, print=true, out=, parameter=, insert_code=, describe_code=, insert_error=) / minoperator mindelimiter=' ';
    /* Use superq to avoid macro quoting issues */
    %let parameter = %superq(parameter);
    %let insert_code = %superq(insert_code);	 
    %let describe_code = %superq(describe_code);
	 %let insert_error = %superq(insert_error);
    %let out = %upcase(&out.);
    %let print = %upcase(&print.);

    /* Error checking */

    /* There must be an API key */
    %if(%bquote(&api_key.) =) %then %do;
        %put ERROR: No API key supplied.;
        %abort;
    %end;

    /* Print must be a valid value */
    %if(NOT (&print. IN TRUE FALSE YES NO 1 0 LOG)) %then %do;
        %put ERROR: Invalid value for print. Expected TRUE, FALSE, YES, NO, 1, 0, or LOG.;
        %abort;
    %end;

    /* Check that the Prompts dataset exists */
    %if NOT %sysfunc(exist(work.Prompts)) %then %do;
        %put ERROR: Dataset work.Prompts does not exist!;
        %goto EndOfMacro;
    %end;

    /* If the parameter is missing, show help information */
    %if %superq(PARAMETER) = %then %do;
        %put NOTE: This is a help info for macro &sysmacroname..;
        %put NOTE- The PARAMETER parameter allows only the following values for actions:;
        options nosource;
        data _null_;
            set Prompts;
            by description notsorted;
            if first.description then
                put "NOTE- " @;
            put code @;
            if last.description then 
                put " is for: " / @7 description/;
        run;
        options nosource;
        %goto EndOfMacro;
    %end;

    /* Check that the specified parameter is valid */
    options nosource nonotes;
    proc sql noprint;
        select code into :list_of_codes separated by " " from work.Prompts;
    quit;
    options source notes;

    %if NOT (%superq(PARAMETER) in (&list_of_codes.)) %then %do;
        %put ERROR: The PARAMETER parameter has an invalid value!;
        %goto EndOfMacro;
    %end;

    /* Print the prompt message */
    options nosource;
    data _null_;
        set Prompts;
        where code = symget('parameter');
        insert_code = symget('insert_code');
		  insert_error = symget('insert_error');
        describe_code = symget('describe_code');
        length Prompt $ 32767;
        Prompt = prxchange('s/\{Describe problem with current code, if possible\.\}/'||strip(describe_code)||'/io', -1, description);
        Prompt = prxchange('s/\{Insert Code\}/'||strip(insert_code)||'/io', -1, Prompt);
		  Prompt = prxchange('s/\{Insert Error\}/'||strip(insert_error)||'/io', -1, Prompt);
        Prompt = prxchange('s/\{optimize\/clean\/efficient\/fast\/readable\}/'||strip(code)||'/io', -1, Prompt);
        put "THE PROMPT:";
        put Prompt /;
    run;
    options nosource;

    /* If no output dataset is supplied, use __temp__ */
    %if(&out. =) %then %let outdata = __temp__;
    %else %let outdata = &out.;


    /* Body of the POST request */
    filename in temp;

  options nosource;
    data _null_;
    file in;
    put "{";
    put '"model": "gpt-3.5-turbo", "messages": [{"role": "user", "content": ' """&parameter.""" '}, 
    {"role": "user", "content": ' """&insert_code.""" '},{"role": "user", "content": ' """&insert_error.""" '},
    {"role": "user", "content": ' """&describe_code.""" '}]';
    put "}";
    run;


    /* Reference that file as IN= parm in PROC HTTP POST */
    filename resp "%sysfunc(getoption(WORK))/echo.json";

    /* Send the request and payload */
    proc http 
        method = "POST"
        url    = "https://api.openai.com/v1/chat/completions"
        ct     = "application/json"
        in     = in
        out    = resp;
        headers "Authorization" = "Bearer &api_key.";
    run;    
    

    /* Check the status code */
    %if(&SYS_PROCHTTP_STATUS_CODE. NE 200) %then %do;
        %put An error occurred. HTTP &SYS_PROCHTTP_STATUS_CODE.: &SYS_PROCHTTP_STATUS_PHRASE;
        %abort;
    %end;
 
    /* Tell SAS to parse the JSON response */
    libname response JSON fileref=resp;

    /* Format JSON in presentable format */
    data &outdata. ;
        set response.choices_message;
            do row=1 to max(1,countw(content,'0A'x));
                outvar=scan(content,row,'0A'x);
                output;
            end;
        drop content;
    run;  

/*    libname response clear;*/

    /* Output to either ODS or the log */
    %if(&print. IN TRUE YES 1) %then %do;
        proc report data= &outdata. ;
            column outvar;
            define outvar / display "" style(column)=[cellwidth=6in fontsize=10pt asis=ON];
        run;
    %end;
        %else %if(&print. = LOG) %then %do;
            data _null_;
                 rc = jsonpp('resp','log');
            run;
        %end;

    /* Remove temporary data */
    %if(&out. =) %then %do;
        proc datasets lib=work nolist;
            delete &outdata.;
        quit;
    %end;
%EndOfMacro:
%mend;

%chatgpt(api_key=&api_key.,print=true, out=, parameter= explain, insert_code={proc fcmp});

 

View solution in original post

2 REPLIES 2
smackerz1988
Pyrite | Level 9

I think what the issue is that i haven't used this macro since mid 2023 and since then OpenAI API is much more restrictive now than it was then so I need to upgrade my OpenAI API account on top of my chatgpt paid subscription. As this code used to work fine as is. If anyone has a personal API_KEY you can put it as a %let statement at the start of this code and run this version of my  macro on your end to  and see if you get the same thing 

%let api_key = sk-XXXXXXXX
data Prompts;
    length code $ 16 description $ 1024;
    do code="optimize","clean","efficient","fast","readable"; 
        description="I want you to act as a code optimizer in SAS. {Describe problem with current code, if possible.} 
                     Can you make the code {optimize/clean/efficient/fast/readable}? {Insert Code}";
        output;
    end;
    code="explain"; 
    description="I want you to act as a code explainer in SAS. I don't understand this function. 
                 Can you please explain what it does, and provide an example? {Insert Code}";
	 output;
	 code="debug"; 
    description="I want you to be a SAS programmer, here is a piece of SAS code {Insert Code}
                 — I am getting the following error {Insert Error}. What is the reason for the bug?";
    output;
run;


%macro chatgpt(api_key=, print=true, out=, parameter=, insert_code=, describe_code=, insert_error=) / minoperator mindelimiter=' ';
    /* Use superq to avoid macro quoting issues */
    %let parameter = %superq(parameter);
    %let insert_code = %superq(insert_code);	 
    %let describe_code = %superq(describe_code);
	 %let insert_error = %superq(insert_error);
    %let out = %upcase(&out.);
    %let print = %upcase(&print.);

    /* Error checking */

    /* There must be an API key */
    %if(%bquote(&api_key.) =) %then %do;
        %put ERROR: No API key supplied.;
        %abort;
    %end;

    /* Print must be a valid value */
    %if(NOT (&print. IN TRUE FALSE YES NO 1 0 LOG)) %then %do;
        %put ERROR: Invalid value for print. Expected TRUE, FALSE, YES, NO, 1, 0, or LOG.;
        %abort;
    %end;

    /* Check that the Prompts dataset exists */
    %if NOT %sysfunc(exist(work.Prompts)) %then %do;
        %put ERROR: Dataset work.Prompts does not exist!;
        %goto EndOfMacro;
    %end;

    /* If the parameter is missing, show help information */
    %if %superq(PARAMETER) = %then %do;
        %put NOTE: This is a help info for macro &sysmacroname..;
        %put NOTE- The PARAMETER parameter allows only the following values for actions:;
        options nosource;
        data _null_;
            set Prompts;
            by description notsorted;
            if first.description then
                put "NOTE- " @;
            put code @;
            if last.description then 
                put " is for: " / @7 description/;
        run;
        options nosource;
        %goto EndOfMacro;
    %end;

    /* Check that the specified parameter is valid */
    options nosource nonotes;
    proc sql noprint;
        select code into :list_of_codes separated by " " from work.Prompts;
    quit;
    options source notes;

    %if NOT (%superq(PARAMETER) in (&list_of_codes.)) %then %do;
        %put ERROR: The PARAMETER parameter has an invalid value!;
        %goto EndOfMacro;
    %end;

    /* Print the prompt message */
    options nosource;
    data _null_;
        set Prompts;
        where code = symget('parameter');
        insert_code = symget('insert_code');
		  insert_error = symget('insert_error');
        describe_code = symget('describe_code');
        length Prompt $ 32767;
        Prompt = prxchange('s/\{Describe problem with current code, if possible\.\}/'||strip(describe_code)||'/io', -1, description);
        Prompt = prxchange('s/\{Insert Code\}/'||strip(insert_code)||'/io', -1, Prompt);
		  Prompt = prxchange('s/\{Insert Error\}/'||strip(insert_error)||'/io', -1, Prompt);
        Prompt = prxchange('s/\{optimize\/clean\/efficient\/fast\/readable\}/'||strip(code)||'/io', -1, Prompt);
        put "THE PROMPT:";
        put Prompt /;
    run;
    options nosource;

    /* If no output dataset is supplied, use __temp__ */
    %if(&out. =) %then %let outdata = __temp__;
    %else %let outdata = &out.;


    /* Body of the POST request */
    filename in temp;

  options nosource;
    data _null_;
    file in;
    put "{";
    put '"model": "gpt-3.5-turbo", "messages": [{"role": "user", "content": ' """&parameter.""" '}, 
    {"role": "user", "content": ' """&insert_code.""" '},{"role": "user", "content": ' """&insert_error.""" '},
    {"role": "user", "content": ' """&describe_code.""" '}]';
    put "}";
    run;


    /* Reference that file as IN= parm in PROC HTTP POST */
    filename resp "%sysfunc(getoption(WORK))/echo.json";

    /* Send the request and payload */
    proc http 
        method = "POST"
        url    = "https://api.openai.com/v1/chat/completions"
        ct     = "application/json"
        in     = in
        out    = resp;
        headers "Authorization" = "Bearer &api_key.";
    run;    
    

    /* Check the status code */
    %if(&SYS_PROCHTTP_STATUS_CODE. NE 200) %then %do;
        %put An error occurred. HTTP &SYS_PROCHTTP_STATUS_CODE.: &SYS_PROCHTTP_STATUS_PHRASE;
        %abort;
    %end;
 
    /* Tell SAS to parse the JSON response */
    libname response JSON fileref=resp;

    /* Format JSON in presentable format */
    data &outdata. ;
        set response.choices_message;
            do row=1 to max(1,countw(content,'0A'x));
                outvar=scan(content,row,'0A'x);
                output;
            end;
        drop content;
    run;  

/*    libname response clear;*/

    /* Output to either ODS or the log */
    %if(&print. IN TRUE YES 1) %then %do;
        proc report data= &outdata. ;
            column outvar;
            define outvar / display "" style(column)=[cellwidth=6in fontsize=10pt asis=ON];
        run;
    %end;
        %else %if(&print. = LOG) %then %do;
            data _null_;
                 rc = jsonpp('resp','log');
            run;
        %end;

    /* Remove temporary data */
    %if(&out. =) %then %do;
        proc datasets lib=work nolist;
            delete &outdata.;
        quit;
    %end;
%EndOfMacro:
%mend;

%chatgpt(api_key=&api_key.,print=true, out=, parameter= explain, insert_code={proc fcmp});

 

smackerz1988
Pyrite | Level 9

Please let me know if you get the same message!. I'm writing a paper on this macro so need to make sure my code is still valid. 

CFC_SAS_Communities_400x225.jpg

Call for content now open!

It's your turn to help shape SAS Innovate 2027. Share your expertise and inspire the SAS community.

Submit your proposal →

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 2 replies
  • 3809 views
  • 3 likes
  • 1 in conversation