<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: PROC HTTP to connect to CHATGPT in SAS error in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/PROC-HTTP-to-connect-to-CHATGPT-in-SAS-error/m-p/944829#M370182</link>
    <description>&lt;P&gt;I think what the issue is that i haven't used this macro since mid 2023 and since then&amp;nbsp;OpenAI API is much more restrictive now than it was then so I need to upgrade my&amp;nbsp;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&amp;nbsp; macro on your end to&amp;nbsp; and see if you get the same thing&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let api_key = sk-XXXXXXXX&lt;/CODE&gt;&lt;/PRE&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;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(&amp;amp;out.);
    %let print = %upcase(&amp;amp;print.);

    /* Error checking */

    /* There must be an API key */
    %if(%bquote(&amp;amp;api_key.) =) %then %do;
        %put ERROR: No API key supplied.;
        %abort;
    %end;

    /* Print must be a valid value */
    %if(NOT (&amp;amp;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 &amp;amp;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 (&amp;amp;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(&amp;amp;out. =) %then %let outdata = __temp__;
    %else %let outdata = &amp;amp;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": ' """&amp;amp;parameter.""" '}, 
    {"role": "user", "content": ' """&amp;amp;insert_code.""" '},{"role": "user", "content": ' """&amp;amp;insert_error.""" '},
    {"role": "user", "content": ' """&amp;amp;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 &amp;amp;api_key.";
    run;    
    

    /* Check the status code */
    %if(&amp;amp;SYS_PROCHTTP_STATUS_CODE. NE 200) %then %do;
        %put An error occurred. HTTP &amp;amp;SYS_PROCHTTP_STATUS_CODE.: &amp;amp;SYS_PROCHTTP_STATUS_PHRASE;
        %abort;
    %end;
 
    /* Tell SAS to parse the JSON response */
    libname response JSON fileref=resp;

    /* Format JSON in presentable format */
    data &amp;amp;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(&amp;amp;print. IN TRUE YES 1) %then %do;
        proc report data= &amp;amp;outdata. ;
            column outvar;
            define outvar / display "" style(column)=[cellwidth=6in fontsize=10pt asis=ON];
        run;
    %end;
        %else %if(&amp;amp;print. = LOG) %then %do;
            data _null_;
                 rc = jsonpp('resp','log');
            run;
        %end;

    /* Remove temporary data */
    %if(&amp;amp;out. =) %then %do;
        proc datasets lib=work nolist;
            delete &amp;amp;outdata.;
        quit;
    %end;
%EndOfMacro:
%mend;

%chatgpt(api_key=&amp;amp;api_key.,print=true, out=, parameter= explain, insert_code={proc fcmp});&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Sat, 21 Sep 2024 20:33:32 GMT</pubDate>
    <dc:creator>smackerz1988</dc:creator>
    <dc:date>2024-09-21T20:33:32Z</dc:date>
    <item>
      <title>PROC HTTP to connect to CHATGPT in SAS error</title>
      <link>https://communities.sas.com/t5/SAS-Programming/PROC-HTTP-to-connect-to-CHATGPT-in-SAS-error/m-p/944828#M370181</link>
      <description>&lt;P&gt;I’m currently working on integrating the OpenAI API into SAS using &lt;CODE&gt;PROC HTTP&lt;/CODE&gt;. I’m attempting to make a POST request to the &lt;CODE&gt;Chat Completions API&lt;/CODE&gt; but I consistently encounter a &lt;STRONG&gt;rate limit error (HTTP 429)&lt;/STRONG&gt; on every single attempt.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;/* Body of the POST request */
filename in temp;
data _null_;
    file in;
    put '{"model": "gpt-3.5-turbo", "messages": [{"role": "user", "content": "' "&amp;amp;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 &amp;amp;api_key.";           
run;

/* Print the response */
data _null_;
    infile resp;
    input;
    put _infile_;
run;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;I &lt;STRONG&gt;always&lt;/STRONG&gt; receive the following error, regardless of how infrequent or spaced out the requests are:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;HTTP 429: Rate limit exceeded
&lt;/PRE&gt;
&lt;H3&gt;What I’ve Tried So Far:&lt;/H3&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;STRONG&gt;API Key&lt;/STRONG&gt;: I’ve verified that my API key is working.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Spacing Out Requests&lt;/STRONG&gt;: 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.&lt;/LI&gt;
&lt;LI&gt;&lt;STRONG&gt;Retry Logic&lt;/STRONG&gt;: I attempted implementing retry logic with exponential backoff, but it hasn’t resolved the issue either.&lt;/LI&gt;
&lt;/OL&gt;</description>
      <pubDate>Sat, 21 Sep 2024 17:55:56 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/PROC-HTTP-to-connect-to-CHATGPT-in-SAS-error/m-p/944828#M370181</guid>
      <dc:creator>smackerz1988</dc:creator>
      <dc:date>2024-09-21T17:55:56Z</dc:date>
    </item>
    <item>
      <title>Re: PROC HTTP to connect to CHATGPT in SAS error</title>
      <link>https://communities.sas.com/t5/SAS-Programming/PROC-HTTP-to-connect-to-CHATGPT-in-SAS-error/m-p/944829#M370182</link>
      <description>&lt;P&gt;I think what the issue is that i haven't used this macro since mid 2023 and since then&amp;nbsp;OpenAI API is much more restrictive now than it was then so I need to upgrade my&amp;nbsp;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&amp;nbsp; macro on your end to&amp;nbsp; and see if you get the same thing&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let api_key = sk-XXXXXXXX&lt;/CODE&gt;&lt;/PRE&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;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(&amp;amp;out.);
    %let print = %upcase(&amp;amp;print.);

    /* Error checking */

    /* There must be an API key */
    %if(%bquote(&amp;amp;api_key.) =) %then %do;
        %put ERROR: No API key supplied.;
        %abort;
    %end;

    /* Print must be a valid value */
    %if(NOT (&amp;amp;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 &amp;amp;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 (&amp;amp;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(&amp;amp;out. =) %then %let outdata = __temp__;
    %else %let outdata = &amp;amp;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": ' """&amp;amp;parameter.""" '}, 
    {"role": "user", "content": ' """&amp;amp;insert_code.""" '},{"role": "user", "content": ' """&amp;amp;insert_error.""" '},
    {"role": "user", "content": ' """&amp;amp;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 &amp;amp;api_key.";
    run;    
    

    /* Check the status code */
    %if(&amp;amp;SYS_PROCHTTP_STATUS_CODE. NE 200) %then %do;
        %put An error occurred. HTTP &amp;amp;SYS_PROCHTTP_STATUS_CODE.: &amp;amp;SYS_PROCHTTP_STATUS_PHRASE;
        %abort;
    %end;
 
    /* Tell SAS to parse the JSON response */
    libname response JSON fileref=resp;

    /* Format JSON in presentable format */
    data &amp;amp;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(&amp;amp;print. IN TRUE YES 1) %then %do;
        proc report data= &amp;amp;outdata. ;
            column outvar;
            define outvar / display "" style(column)=[cellwidth=6in fontsize=10pt asis=ON];
        run;
    %end;
        %else %if(&amp;amp;print. = LOG) %then %do;
            data _null_;
                 rc = jsonpp('resp','log');
            run;
        %end;

    /* Remove temporary data */
    %if(&amp;amp;out. =) %then %do;
        proc datasets lib=work nolist;
            delete &amp;amp;outdata.;
        quit;
    %end;
%EndOfMacro:
%mend;

%chatgpt(api_key=&amp;amp;api_key.,print=true, out=, parameter= explain, insert_code={proc fcmp});&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Sat, 21 Sep 2024 20:33:32 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/PROC-HTTP-to-connect-to-CHATGPT-in-SAS-error/m-p/944829#M370182</guid>
      <dc:creator>smackerz1988</dc:creator>
      <dc:date>2024-09-21T20:33:32Z</dc:date>
    </item>
    <item>
      <title>Re: PROC HTTP to connect to CHATGPT in SAS error</title>
      <link>https://communities.sas.com/t5/SAS-Programming/PROC-HTTP-to-connect-to-CHATGPT-in-SAS-error/m-p/944840#M370187</link>
      <description>&lt;P&gt;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.&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Sun, 22 Sep 2024 11:37:31 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/PROC-HTTP-to-connect-to-CHATGPT-in-SAS-error/m-p/944840#M370187</guid>
      <dc:creator>smackerz1988</dc:creator>
      <dc:date>2024-09-22T11:37:31Z</dc:date>
    </item>
  </channel>
</rss>

