{ Analytica Model OpenAI_API_lib, encoding="UTF-8" } SoftwareVersion 6.3.6 {!-60000|Attribute AcpStyles} LinkLibrary OpenAI_API_lib Title: OpenAI API lib (ver. 0.4) Description: A set of function to assist in using the OpenAI API for Large Language Models (LLMs).~ ~ These are useful:~ (a) To get a similarity embedding for snippet(s) of text.~ (b) To get a one-off completion to a prompt.~ (c) To manage a chat conversation.~ ~ To use these libraries, you must get an OpenAI API key directly from OpenAI.~ ~ This library requires the Analytica Enterprise edition or better. Author: Lonnie Chrisman, Ph.D.~ Lumina Decision Systems Date: Thu, Jul 20, 2023 12:00 PM NodeSize: 64,24 NodeInfo: 1,,,,,,,0,,,,,,0 DiagState: 2,85,7,1713,680,17,10 WindState: 2,741,222,739,453 FontStyle: Arial,15 FileInfo: 0,LinkLibrary OpenAI_API_lib,2,2,0,0,..\Src\AI Assistant Prototype\OpenAI API lib.ana Button Save_API_key_with_yo Title: Save API key with your model. NodeLocation: 224,226,1 NodeSize: 128,20 OnClick: if API_Key_for_OpenAI='' or API_Key_for_OpenAI=Null then Error("API key not entered");~ ~ If IsNull(isin of OpenAI_API_lib) then Error("Can't save with your model because no model is loaded -- this library has been opened directly.");~ ~ LocalAlias parentMod := isin of OpenAI_API_lib;~ Local existing := HandleFromIdentifier("OPENAI_API_KEY");~ LocalAlias v := if IsNull(existing) Then CreateNewObject(Constant, parentMod, "OpenAI API key", "OpenAI_API_Key") Else existing;~ v := API_Key_for_OpenAI;~ ShowWindow(v, 'OnDiagram')~ Button Save_API_key_in_env_ Title: Save API key in env var NodeLocation: 224,140,1 NodeSize: 128,20 OnClick: if API_Key_for_OpenAI='' or API_Key_for_OpenAI=Null then Error("API key not entered");~ Local existingKey := GetProcessInfo("env:OPENAI_API_KEY");~ Local ok := true;~ ~ if existingKey<>'' and existingKey<>Null and MsgBox("Your OPENAI_API_KEY environment variable is already set. Do you want to changed it?", 4, "Warning: Change it?")= /*No*/7 Then ~ ok := false;~ ~ if ok then~ Set_Env_Var("OPENAI_API_KEY", API_Key_for_OpenAI) Button Change_your_API_key Title: Change your API key NodeLocation: 224,298,1 NodeSize: 128,20 OnClick: InvalidateResult(API_Key_for_OpenAI);~ Local q := "(Please get an API key (Secret key) from OpenAI)"; ~ value of API_Key_for_OpenAI := AskMsgText(q,"Enter OpenAI API key");~ API_Key_for_OpenAI Text Te1460981395 Title: An OpenAI API Key is required... Description: ~ ...to use this library. You need to get your own API key from OpenAI. Once you have a key, you can:~ • Require the user to enter it each time she uses your model.~ • Save it in an environment variable named OPENAI_API_KEY. You won't have to re-enter again an this computer.~ ~ ~ ~ • Save it with your model. Your model users will never have to enter it, but their usage will get billed to your OpenAI account. ~ If you plan to post your model to ACP on Lumina's server, you'll need to use this option.~ ~ ~ ~ If you have previously entered a key and you need to change it, use this button: NodeLocation: 472,184,-1 NodeSize: 440,160 NodeInfo: 1,,,,1,1 NodeColor: 58981,65535,52427 Module Open_AI_lib_internal Title: Open AI lib internals Author: Lonnie Chrisman~ Lumina Decision Systems Date: Thu, Jul 20, 2023 2:09 PM NodeLocation: 1032,56,1 NodeSize: 64,24 DiagState: 2,99,45,1541,677,17,10 Constant Sys_Root_System32 Title: Sys_Root_System32 Definition: FileFullPath( "System32", GetProcessInfo("env:SystemRoot")) NodeLocation: 304,56,1 NodeSize: 88,24 Function Set_Env_Var( name, value : atom text) Title: Set Env Var Description: Sets a persistent user environment variable to the given value.~ ~ To remove the env var, use the empty text ("") for the value. Definition: if SelectText(AnalyticaEdition,1,3)="ACP" Then Error("Sorry, you cannot set an environment variable from a model running on ACP");~ ~ Local program := FileFullPath( "setx.exe", Sys_Root_System32 );~ RunConsoleProcess( program, f"setx ""{name}"" ""{value}""" ) NodeLocation: 488,56,1 NodeSize: 64,24 WindState: 2,539,329,720,350 Variable API_Key_for_OpenAI Title: API Key for OpenAI Description: To use this library, you must get an API key from OpenAI. This will require you to create an account with them and supply some credit card info. Using the APIs is not free, but it is extremely cheap for small-scale usage. ~ ~ Once you have an API key, you can provide to this library in one of two ways:~ (a) Set an environment variable named OPENAI_API_KEY.~ (b) Add a variable named OPENAI_API_KEY to your model and set it to a text value.~ ~ If you have done neither, the library will ask you for your key and will let you chose which method to use. (But it won't set it from within ACP).~ ~ Adding it to your model will allow users of your model to run with your key. This means their usage will show up on your OpenAI bill, but they won't have to get their own API key. Definition: if HandleFromIdentifier("OPENAI_API_KEY")<>Null Then~ Evaluate("OPENAI_API_KEY")~ else (~ Local envkey := GetProcessInfo("env:OPENAI_API_KEY");~ if envkey<>null then envkey else (~ /* Key is not set. Ask user to configure it. */~ Local q := "(Please get an API key (Secret key) from OpenAI)"; ~ AskMsgText(q,"Enter OpenAI API key");~ ) ~ ) NodeLocation: 120,56,1 NodeSize: 64,24 WindState: 2,98,82,1263,518 ValueState: 2,273,434,1028,353,,MIDM Index Ada_embedding Title: Ada embedding Description: This indexes the text embedding returned from the text-embedding-ada model. Definition: 1..1536 NodeLocation: 120,184,1 NodeSize: 64,24 Constant Text_embedding_model Title: Text embedding model name Definition: 'text-embedding-ada-002' NodeLocation: 120,120,1 NodeSize: 72,24 Index Rec_Embedding_for Title: Rec_Embedding_for Definition: ['model','input'] IndexVals: ['item 1'] NodeLocation: 120,256,1 NodeSize: 88,24 Variable OpenAI_headers Att_PrevIndexValue: ['Authorization','Content-type'] Title: OpenAI headers Definition: Table(Self)('Bearer ' & API_Key_for_OpenAI,'application/json') IndexVals: ['Authorization','Content-type'] NodeLocation: 312,120,1 NodeSize: 64,24 ValueState: 2,356,362,953,270,,MIDM ReformDef: [Undefined,Self] Variable OpenAI_header_text Title: OpenAI header text Definition: JoinText(f"{IndexValue(OpenAI_headers)}:{OpenAI_headers}",OpenAI_headers,Chr(13)) NodeLocation: 312,192,1 NodeSize: 64,24 ValueState: 2,372,378,761,220,,MIDM Constant OpenAI_Embedding_URL Title: OpenAI Embedding URL Definition: 'https://api.openai.com/v1/embeddings' NodeLocation: 480,120,1 NodeSize: 72,24 Function Embedding_resp_json( txt ) Title: Embedding response json Description: Returns the JSON response from a call to get the similarity embedding for text. Definition: Local inds := IndexesOf(txt);~ Local flat := Flatten(if txt=null then 'Null' else txt,...inds);~ Local req := MakeJson(Array( Rec_Embedding_for, ~ [Text_embedding_model,\flat]));~ Local resp := ReadFromURL( OpenAI_Embedding_URL, method:'POST', httpHeaders: OpenAI_header_text, httpContent: req );~ ParseJSON(resp) NodeLocation: 328,264,1 NodeSize: 80,24 WindState: 2,355,78,1220,436 Variable OAL_Avail_model_resp Title: Available models response Definition: ReadFromURL( OpenAI_Models_URL, 'GET', httpHeaders:OpenAI_header_text ) NodeLocation: 664,192,1 NodeSize: 72,24 ValueState: 2,380,82,601,569,,MIDM Constant OpenAI_Models_URL Title: OpenAI Models URL Definition: 'https://api.openai.com/v1/models' NodeLocation: 664,120,1 NodeSize: 64,24 Index OpenAI_Model_Name Title: OpenAI Model Name Definition: ComputedBy(OAL_Avail_Models) NodeLocation: 848,120,1 NodeSize: 64,24 ValueState: 2,52,58,620,704,,MIDM Aliases: Alias Al125226643 Variable OAL_Avail_Models Title: Available Models Definition: Local r := #ParseJSON(OAL_Avail_model_resp)[.Member='data'];~ LocalIndex I := 1..size(r,listLen:true);~ Local data := #Slice(r,I);~ LocalIndex models := Slice(data[.member='id'],CopyIndex(I));~ OpenAI_Model_Name := SortIndex(models);~ Local res := data[I=@Models][Models=OpenAI_Model_Name];~ if res.Member='permission' then Slice(#res,1) else res~ NodeLocation: 848,192,1 NodeSize: 64,24 ValueState: 2,128,13,1353,687,,MIDM Aliases: FormNode Fo89320851 ReformVal: [Sys_LocalIndex('Member'),OpenAI_Model_Name] Att_ResultSliceState: [Self,1,OpenAI_Model_Name,1,Sys_LocalIndex('Member'),1] {!40300|Att_SlicerPopupSize: 227,32} Index OpenAI_Function_Item Title: OpenAI Function Item Definition: ['name','description','parameters'] NodeLocation: 1008,120,1 NodeSize: 64,24 ValueState: 2,22,594,416,303,,MIDM Constant OpenAI_Chat_URL Title: OpenAI Chat URL Definition: 'https://api.openai.com/v1/chat/completions' NodeLocation: 664,56,1 NodeSize: 64,24 Index Chat_API_field Att_PrevIndexValue: ['model','messages','functions','function_call','temperature','top_p','n','stop','max_tokens','presence_penalty','frequency_penalty','user'] Title: Chat API field Definition: ['model','messages','functions','function_call','temperature','top_p','n','stop','max_tokens','presence_penalty','frequency_penalty','user'] NodeLocation: 120,480,1 NodeSize: 64,24 WindState: 2,2060,192,720,350 Function Chat_Message_history( messages : text orNull all [Chat_index] ;~ role : text [Chat_index] ;~ Chat_index : Index ;~ ~ functionName : optional [ Chat_index ] = null ;~ functionCall : optional reference orNull [Chat_index] = null~ ) Title: Chat_Message_history Definition: Table(Chat_message_field)(role,messages,functionName,functionCall) NodeLocation: 496,408,1 NodeSize: 96,24 WindState: 2,231,34,994,713 DefnState: 2,203,868,416,303,0,DFNM ReformDef: [Undefined,Chat_message_field] Index Chat_message_field Att_PrevIndexValue: ['role','content','name','function_call'] Title: Chat message field Definition: ['role','content','name','function_call'] NodeLocation: 288,480,1 NodeSize: 64,24 Function Chat_record( conversation ;~ modelName : text atom ;~ functions : optional ... Object;~ ~ temperature : optional nonNegative atom;~ top_p : optional positive atom;~ ~ Completion_index : optional Index ;~ stop_sequences : optional text ;~ ~ max_tokens : optional atom;~ presence_penalty, frequency_penalty : optional number atom~ ) Title: Chat record Description: Assembles the record that will be sent to the OpenAI API message for a chat completion.~ The result is a record on the Chat_API_field index.~ This is a helper for the implementation of Chat_completion(...).~ ~ «conversation» is the conversation history, usually obtained by calling Chat_Message_History(...).~ ~ For the remaining parameters, see Chat_completion's description. Definition: Table(Chat_API_field)(modelName,\conversation,API_Functions_Rec(...functions),Null,UndefToNull(temperature),UndefToNull(top_p),if IsNotSpecified(Completion_index) then Null else IndexLength(Completion_index),Null,UndefToNull(max_tokens),UndefToNull(presence_penalty),UndefToNull(frequency_penalty),GetProcessInfo('UserName')) NodeLocation: 672,408,1 NodeSize: 64,24 WindState: 2,1354,157,955,667 DefnState: 2,359,614,1087,557,0,DFNM ReformDef: [Undefined,Chat_API_field] Function Chat_completion_raw_( messages : text all [Chat_index] ;~ role : text [Chat_index] ;~ Chat_index : Index ;~ ~ modelName : text atom = 'gpt-3.5-turbo' ;~ ~ functions : optional ... Object;~ ~ temperature : optional nonNegative atom ;~ top_p : optional positive atom ;~ ~ Completion_index : optional Index ;~ stop_sequences : optional text ;~ ~ max_tokens : optional atom ;~ presence_penalty, frequency_penalty : optional number atom~ ) Title: Chat completion raw response Description: This returns the next response from in a Chat (ala ChatGPT) given the history of messages so far.~ ~ Required parameters:~ «messages» : The sequence of messages so far, in order, indexed by «Chat_index».~ «role» : Each message has a role, which must be one of 'system', 'user', 'assistant', or 'function'.~ «Chat_index»: Indexes the sequence of messages in the conversation~ ~ Return value:~ The raw parsed json response from the API call.~ ~ Optional parameters:~ «modelName»: The OpenAI model to use. It must support Chat. 'gpt-3.5', 'gpt-3.5-turbo' and 'gpt-4' are common choices.~ «functions» : One or more functions that the LLM can call during its completions.~ «temperature»: A value between 0 and 2. ~ Smaller values are more focused and deterministic, Higher values are more random. Default=1.~ «top_p»: A value 0function feature), this assembles and returns a record with the function description in the form desired by the API. The data is an Analytica record which can be directly converted to JSON using MakeJSON.~ Definition: Local proto := FindInText("^\s*\(\s*(?.*)\s*\)|(?.*)\s*$", parameters of (fn), subpattern:'a', return:'S');~ proto := TextReplace(proto,"\[\s*([\w_]+)\s*(,\s*[\w_]+\s*)*\]","",all:true,re:true); { Remove [I,J] decls to get rid of commas }~ proto := TextReplace(proto,":([^,;]+),",":\1;",all:true,re:true); { Make quantifier group separators consistent, always ; }~ ~ LocalIndex paramName := TextTrim(SplitText(paramNames of (fn),','));~ Local qualifiers := FindInText(f"\b{paramName}\b[^;:]*:\s*([^;]+)", proto, caseInsensitive:true, re:true, subpattern:1, return:'S');~ Local bRequired := FindInText("opt|=", qualifiers,re:true)=0 or qualifiers=null;~ Local dtype := FindInText("text|number",qualifiers,re:true,return:'S');~ dtype := TextReplace(dtype,"text","string");~ Local fnDesc := description of (fn);~ Local paramDeclSec := FindInText(RE_for_Parameters_in, Description of (fn), re:true, return:'S');~ Local reParamDesc := RE_for_one_param_des(paramName);~ Local desc := FindInText(reParamDesc, paramDeclSec, subpattern:'desc', return:'S' );~ Local enum := Enum_vals_for_fn_par(fn, paramName); /*to do */~ ~ ~ Array( Parameters_rec, [ ~ 'type':"object",~ 'properties':\Array(Param_rec, [dtype, desc, enum]),~ 'required':\Subset(bRequired)~ ])~ NodeLocation: 288,696,1 NodeSize: 72,24 WindState: 2,384,12,1775,784 Index Parameters_rec Title: Parameters rec Definition: ['type','properties','required'] NodeLocation: 120,752,1 NodeSize: 64,24 DisplayOutputs: Object Object, Object Function Function Remove_null_fields(json) Title: Remove null fields from json Description: Remove fields from textual json that have null value.~ {"a":5, "b":null}~ is legal json, but this changes it to~ {"a":5}~ The OpenAI API rejects requests will null fields. Definition: local json0 := TextReplace(json,"""content""\s*:\s*null","!!!###!!!",all:true, re:true);~ ~ Local json1 :=~ TextReplace(~ TextReplace(json0,',\s*"\w+":\s*null','',all:true,re:true),~ '{\s*"\w+":\s*null\s*,?','{',all:true,re:true~ );~ ~ TextReplace(json1,"!!!###!!!","""content"":null",all:true) NodeLocation: 952,408,1 NodeSize: 64,24 WindState: 2,555,191,720,559 Function Enum_vals_for_fn_par( h : handle atom; paramName : text atom) Title: Enum vals for fn param Description: Returns a set of enum values for a function parameter, if any, read from the Parameter Enumerations attribute. Definition: Local decl := ParameterEnumeration of (h);~ if not IsText(decl) then Null Else (~ Local enums := FindInText(f"{paramName}.*?((\R\t[^\r\n]*)+)",~ decl, caseInsensitive:true, re:true, subpattern:1, return:'S');~ Local items := TextTrim(FindInText("\t([^|]*)",enums,return:'S',re:true,~ subpattern:1,repeat:true));~ Local strVal := FindInText("^('(?.*)')|(""(?.*)"")$", items, re:true, return:'S', subpattern:'txt');~ ~ items := if strVal=Null then ParseNumber(items,items) else strVal;~ if IsNull(items) then null else \CopyIndex(items)~ ) NodeLocation: 448,696,1 NodeSize: 64,24 WindState: 2,98,82,827,350 DisplayOutputs: Object Object, Object Function Function API_Functions_Rec(functions : optional ... object) Title: API Functions Rec Description: From a function, or collection of functions, return a set describing the functions for the chat API. functions. Definition: if IsNotSpecified(functions) or size(functions)=0 then null else (~ LocalIndex fn := functions;~ {Remove parameter descriptions from the fn description. These are sent with each parameter}~ Local fnDesc := TextReplace(description of (fn), RE_for_Parameters_in, "", re:true); ~ ~ Local params := For f:=slice(functions,@fn) Do ~ \Make_Fn_Params_Rec(f); ~ ~ \Array(OpenAI_Function_Item, [~ identifier of (fn), ~ fnDesc, ~ params~ ])~ ) NodeLocation: 792,696,1 NodeSize: 64,24 WindState: 2,906,133,968,486 Function ExtractParamNameInds( rec : [Chat_API_field] ) Title: Extract ParamNames indexes Description: Given a Chat_API record, extract a list of handles to the ParamNames indexes that exist in the function declaration section. Definition: Local functions := rec[Chat_API_field='functions'];~ if not IsReference(functions) then [] else (~ Local rFnParams[] := (#functions)[OpenAI_Function_Item='parameters'];~ Local props := #(#rFnParams)[Parameters_rec='properties'];~ Handle(props.paramName)~ ) NodeLocation: 616,696,1 NodeSize: 88,24 WindState: 2,98,82,905,428 Function Chat_perform_fn_call( ~ responseChoice : reference atom;~ chatRec : [Chat_API_field] ;~ Chat_index : index~ ) Title: Chat perform fn call Description: Accepts one completion "choice" from the API's Chat response. This is a reference from the [.Member='choices'] field of the raw response from OpenAI. It returns a «ref» that can replace the original, after performing a function call if the API has ask for a function to be called. If the response is not a function call, the result is the same as the parameter passed. Definition: Local rec := #responseChoice;~ ~ if rec[.Member='finish_reason']<>'function_call' then~ responseChoice~ else (~ Local call := (#(#rec[.Member='message'])[.Member='function_call'])[.Member=Fn_Call_Schema];~ Local fnName := call[Fn_Call_Schema='name'];~ Local fn := HandleFromIdentifier(fnName);~ ~ if fn=null then ( ~ Error(f"OpenAI API tried to call {fnName}(...), which doesn't exist in the model.");~ );~ Local args := call[Fn_Call_Schema='arguments'];~ Local parsedArgs := Try( ~ ParseJSON(args),~ catch: { It is inconsistent. args is usually JSON, but sometimes, especially when it ~ hallucinates a python function args is not json, but just text }~ LocalIndex Member := ['expr'] Do Array(Member,[args])~ );~ Local callResult := Perform_callback(fn, parsedArgs, parsedArgs.Member);~ callResult := if IsText(callResult) then callResult else f"{callResult:G}";~ ~ Local (nextChatRec, hNextChatIndex) := Chat_rec_for_call_re( chatRec, Chat_index, call, callResult);~ LocalAlias nextChatIndex := hNextChatIndex;~ ~ Local raw := Chat_completion_raw0( nextChatRec, nextChatIndex);~ ~ Local nextResponseChoice := Slice(#raw[.Member='choices'],1);~ Chat_perform_fn_call(nextResponseChoice, nextChatRec, nextChatIndex )~ ) NodeLocation: 120,568,1 NodeSize: 64,24 WindState: 2,1791,15,1122,1167 Recursive: 1 Function Perform_callback( fn : handle atom ; args :all [ArgName] ; ArgName : Index ) Title: Perform callback Description: Calls the function with the given parameters, in a name-param calling style (every parameter is named). Definition: LocalIndex paramNames := SplitText(paramnames of (fn),',');~ Local argOfParam := @[ArgName=paramNames];~ Local positionalArgs :=~ if argOfParam=0 then Undefined else args[@ArgName=argOfParam];~ ~ Evaluate(fn,...positionalArgs) NodeLocation: 432,568,1 NodeSize: 64,24 WindState: 2,131,109,873,466 Function Chat_completion_raw0( chatRec : [Chat_API_field];~ Chat_index : Index ;~ ) Title: Chat completion raw0 response Description: This returns the next response from in a Chat (ala ChatGPT) given the history of messages so far.~ ~ Required parameters:~ «chatRec»: A record representation of a chat and its parameters. Obtained from Function Chat_record(...).~ «Chat_index»: Indexes the sequence of messages in the conversation~ ~ Return value:~ The raw parsed json response from the API call. Definition: Local fns := chatRec[Chat_API_field='functions'];~ Local indOrder := [Handle(Chat_index)];~ If IsReference(fns) then ~ indOrder := Concat(indOrder,[Handle((#fns).fn)]);~ ~ Local paramNamesInds := ExtractParamNameInds(chatRec);~ Local objs := Concat(ListOfHandles(Chat_message_field, OpenAI_Function_item, Parameters_rec),~ Concat(paramNamesInds,ListOfHandles(Param_rec,Fn_Call_schema)));~ ~ Local json := MakeJSON(chatRec, indexOrder:...indOrder, objects:...objs);~ { Remove null fields since the API barfs when they are present }~ json := Remove_null_fields(json);~ {ConsolePrint("Send to API"); ConsolePrint(json);}~ Local response := ReadFromURL( OpenAI_Chat_URL, method:'Post', httpHeaders:OpenAI_header_text, httpContent: json );~ {ConsolePrint("Received from API"); ConsolePrint(response );}~ ParseJSON(response) NodeLocation: 296,408,1 NodeSize: 80,24 WindState: 2,1923,12,1229,1180 Function Chat_rec_for_call_re( origChatRec : [Chat_API_field] ;~ origChatIndex : Index;~ function_call ;~ callResult ~ ) Title: Chat rec for call result Description: This takes the chatRec before a function callback was requested (i.e., the rec for the API call that requested a fn callback), along with the requested call and the result of the call, and assembles a chatRec that includes the result of the fn callback. This is the parsed version of the JSON that should be sent back to the API for it to continue processing. ~ ~ It adds two lines to the messages of the origChatRec.~ ~ The caller also needs to know the new chat index. A handle to this is returned as a second return value. Definition: Local n := IndexLength(origChatIndex);~ Local messages := #origChatRec[Chat_API_field='messages'];~ LocalIndex I / "Chat_index" := 1..n+2;~ Local newMessages := messages[@origChatIndex=I, defVal:null];~ Local fnName := function_call[Fn_Call_schema='name'];~ ~ newMessages[ I=n+1 ] := Array( Chat_message_field, [~ "assistant",~ Null,~ Null,~ \function_call ~ ]);~ ~ newMessages[ I=n+2 ] := Array( Chat_message_field, [~ "function",~ callResult,~ fnName, ~ Null~ ]);~ ~ Local res := if Chat_API_field='messages' then \newMessages else origChatRec;~ ~ MultiResult(~ res,~ Handle(I)~ ) NodeLocation: 288,568,1 NodeSize: 64,24 WindState: 2,306,69,1066,989 Index Fn_Call_schema Title: Fn Call schema Definition: ['name','arguments'] NodeLocation: 1008,208,1 NodeSize: 64,24 Constant OpenAI_Image_Gen_URL Title: OpenAI Image Gen URL Definition: 'https://api.openai.com/v1/images/generations' NodeLocation: 96,864,1 NodeSize: 64,24 Constant OpenAI_max_images Title: OpenAI max images at a time Definition: 10 NodeLocation: 248,864,1 NodeSize: 64,32 Index OA_Image_query_rec Title: OA Image query rec Definition: ['prompt','n','size','response_format','user'] NodeLocation: 408,864,1 NodeSize: 64,24 Function Make_image_rec( prompt ; n : positive atom ; size : text orNull atom ) Title: Make image rec Description: Returns query record for an image query.~ «prompt» should be either a since text or a 1-D list. Definition: Table(OA_Image_query_rec)(RefIfArray(prompt),n,size,'url',GetProcessInfo('UserName')) NodeLocation: 568,864,1 NodeSize: 64,24 WindState: 2,589,831,720,350 DefnState: 2,96,555,1025,484,0,DFNM Function RefIfArray(x) Title: RefIfArray Description: Returns x when x is a scalar, or \x when x is a list or array. Definition: if Size(IndexesOf(x))=0 then x else \x NodeLocation: 728,864,1 NodeSize: 64,24 Constant RE_for_Parameters_in Title: RE for Parameters in Description Definition: Local oneParamDesc := RE_for_one_param_des("\w+?");~ f"Parameters:?\s*\R([•*«\t][^\r\n]*\R)+" NodeLocation: 1336,112,1 NodeSize: 64,32 ValueState: 2,484,490,1121,293,,MIDM DisplayOutputs: Object Object, Object Function Function RE_for_one_param_des(name) Title: RE for one param desc Description: A regular expression for parsing the description of a single parameter with the given name from within a full Description. It looks for a line having one of these forms, each preceded by a newline:~ ~ * name: description~ • name: description~ «name»: description~ * «name»: description~ • «name»: description~ ~ When the description of the parameter has more than one line, it expects each subsequent line to be tab-indented (i.e., the first character must be a tab character).~ ~ The subpattern "desc" contains the full description, the subpattern "start" has the first line only, and the subpattern "rest" has the remaining lines, each tab indented. Typical usage:~ ~ FindInText( RE_for_one_param_des("x"), description of F, return:'S', subpattern:'desc' )~ Definition: Local bulletName := f"(?:[•|*]\s*{name})";~ Local nonBulletName := f"(?:«{name}»)";~ Local bothName := f"(?:[•|*]\s*«{name}»)";~ Local lineStart := "\R";~ Local nameDecl := f"{lineStart}({bulletName}|{nonBulletName}|{bothName}):\s*";~ Local start := "(?[^\r\n]*)"; { The first line of the description }~ Local indentedLine := "(?:\R\t+[^\r\n]+)";~ f"{nameDecl}(?{start}(?{indentedLine}*))";~ NodeLocation: 1344,200,1 NodeSize: 64,24 WindState: 2,31,92,720,571 Function python( expr : text) Description: GPT seems to hallucinate the existance of a function named python, which apparently is supposed to evaluate a python expression. This function handles such calls. GPT sometimes does this to perform arithmetic, so in some cases we might be able to process these fairly simply.~ ~ Attempts to evaluate simple expressions that transform obviously to Analytica expressions. More complex expressions will fail, and then it reports that there is no function named python. Definition: Local adj_expr := TextReplace(expr, ~ "(?\w+)\s*=(?[^\r\n]+(\R[\t\s]+[^\r\n]*)*)",~ "Local :=;",~ all:true, re:true );~ adj_expr := TextReplace(adj_expr,"**","^",all:true);~ Local result := Evaluate(adj_expr);~ if result=null ~ then "Error: There is no function named python. But do not appologize for this error."~ else result NodeLocation: 584,568,1 NodeSize: 64,24 WindState: 2,1325,75,720,639 Close Open_AI_lib_internal Library Similarity_embedding Title: Similarity embeddings Description: Author: Lonnie Chrisman~ Lumina Decision Systems Date: Thu, Jul 20, 2023 3:17 PM NodeLocation: 1032,144,1 NodeSize: 80,24 DiagState: 2,257,97,1278,598,17,10 Function Embedding_similarity( x,y : [ Ada_embedding] ) Title: Embedding similarity Description: Returns the similarity between two text embeddings (obtained using the Embedding_for function). Definition: Sum(x*y, Ada_embedding ) NodeLocation: 960,72,1 NodeSize: 64,24 WindState: 2,504,428,720,350 DisplayOutputs: Object Object, Object Variable Function Embedding_for( txt : text orNull ) Title: Embedding for Description: Returns the embedding for some txt. When an array of text is passed in, the embeddings are obtained in a single call to the OpenAI UI.~ ~ This also returns the number of prompt tokens in the request (2nd return value) and the total tokens (3rd return value). Definition: Local json := Embedding_resp_json(txt);~ Local inds := indexesOf(txt);~ Local flat_embeddings := ~ Local r[] := #json[.Member='data'] Do~ Slice(#(#r)[.Member='embedding'],@Ada_embedding);~ Local usage := #json[.Member='usage'];~ Local unflat := Unflatten(flat_embeddings, , ResultIndexes:...inds);~ unflat := if size(inds)=0 then Slice(unflat,1) else unflat;~ MultiResult(~ if txt=null then null else unflat,~ usage[.Member='prompt_tokens'],~ usage[.Member='total_tokens']~ ) NodeLocation: 816,72,1 NodeSize: 64,24 WindState: 2,565,53,932,561 DisplayOutputs: Object Object, Object Variable Module Ex_Open_AI_Lib Title: Examples Author: Lonnie Chrisman~ Lumina Decision Systems Date: Thu, Jul 20, 2023 3:17 PM NodeLocation: 816,152,1 NodeSize: 72,24 DiagState: 2,716,131,1100,421,17,10 Variable Ex_OAL_To_Encode Title: Array of text Definition: Table(Ex_OAL_I,Ex_OAL_J)(~ 'hello','there',~ 'world',Null,~ 'and','bar') NodeLocation: 296,80,1 NodeSize: 64,24 ValueState: 2,1936,732,416,303,,MIDM Variable Embeddings_for_text Title: Embeddings for text Definition: Local (emb,promptTokens,totalTokens) := Embedding_for(Ex_OAL_To_Encode); ~ ConsolePrint(f"prompt tokens={promptTokens}, total tokens={totalTokens}");~ emb NodeLocation: 296,160,1 NodeSize: 64,24 ValueState: 2,953,118,892,606,,MIDM ReformVal: [Ada_embedding,Sys_LocalIndex('I')] Att_ResultSliceState: [Ex_OAL_J,1,Ex_OAL_I,1,Ada_embedding,1] Variable Ex_OAL_Test_List Title: Embeddings for List of Text Definition: Embedding_for(['hello','world']) NodeLocation: 472,160,1 NodeSize: 72,24 Variable Test_scalar_text_emb Title: Test scalar text embeding Definition: Embedding_for('How is the time') NodeLocation: 472,80,1 NodeSize: 72,24 ValueState: 2,68,74,816,279,,MIDM Index Ex_OAL_I Title: I Definition: 1..3 NodeLocation: 112,72,1 NodeSize: 64,24 Index Ex_OAL_J Title: J Definition: 'j'&(1..2) NodeLocation: 112,136,1 NodeSize: 64,24 Index Ex_OAL_Rec Att_PrevIndexValue: ['Abraham Lincoln''s Gettysburg Address (1863)','Franklin D. Roosevelt''s First Inaugural Address (1933)','John F. Kennedy''s Inaugural Address (1961)','Lyndon B. Johnson''s ''We Shall Overcome'' Speech (1965)','Ronald Reagan''s ''Tear Down This Wall'' Speech (1987)'] Title: Speech name Definition: ["Abraham Lincoln's Gettysburg Address (1863)","Franklin D. Roosevelt's First Inaugural Address (1933)","John F. Kennedy's Inaugural Address (1961)","Lyndon B. Johnson's 'We Shall Overcome' Speech (1965)","Ronald Reagan's 'Tear Down This Wall' Speech (1987)"] NodeLocation: 112,256,1 NodeSize: 64,24 Variable Ex_OAL_Ref_Material Title: Presidential speech Definition: Table(Ex_OAL_Rec)('Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.','I am certain that my fellow Americans expect that on my induction into the Presidency I will address them with a candor and a decision which the present situation of our Nation impels. This is preeminently the time to speak the truth, the whole truth, frankly and boldly. Nor need we shrink from honestly facing conditions in our country today. This great Nation will endure as it has endured, will revive and will prosper.','We observe today not a victory of party, but a celebration of freedom—symbolizing an end, as well as a beginning—signifying renewal, as well as change. For I have sworn before you and Almighty God the same solemn oath our forebears prescribed nearly a century and three quarters ago.','I speak tonight for the dignity of man and the destiny of democracy. I urge every member of both parties, Americans of all religions and of all colors, from every section of this country, to join me in that cause.','Chancellor Kohl, Governing Mayor Diepgen, ladies and gentlemen: Twenty-four years ago, President John F. Kennedy visited Berlin, speaking to the people of this city and the world at the City Hall. Well, since then two other presidents have come, each in his turn, to Berlin. And today I, myself, make my second visit to your city.') NodeLocation: 112,320,1 NodeSize: 64,24 DefnState: 2,280,96,1233,433,0,DFNM {!40700|Att_CellFormat: CellFormats(CellEntry(0,0,1,0,0),CellFont('Calibri'),CellAlignment('Left'))} Decision EX_OAL_Search_query Title: Search queries Definition: ['Racial injustice','References to religion','Berlin, Germany','Americans should join together','87','Creating a new country','Our country will survive','To tell the truth','To face reality'] NodeLocation: 112,384,1 NodeSize: 64,24 Variable Ex_OAL_Speech_embedd Title: Speech embeddings Definition: Embedding_for(Ex_OAL_Ref_Material) NodeLocation: 296,280,1 NodeSize: 72,24 ValueState: 2,324,330,1240,303,,MIDM Variable Ex_OAL_Query_emb Title: Query embedding Definition: Embedding_for(EX_OAL_Search_query) NodeLocation: 296,360,1 NodeSize: 64,24 Variable Ex_OAL_Similarity_sp Title: Similarity of query to speech Definition: Embedding_similarity(Ex_OAL_Speech_embedd,Ex_OAL_Query_emb) NodeLocation: 520,288,1 NodeSize: 80,24 ValueState: 2,704,165,645,470,1,MIDM GraphSetup: Flip:8~ Att_GraphValueRange Ex_OAL_Similarity_sp:1,,,0,1 ReformVal: [Ex_OAL_Rec,EX_OAL_Search_query] Att_ResultSliceState: [EX_OAL_Search_query,1,EX_OAL_Search_query,2,Ex_OAL_Rec,1] Att_ColorRole: Null {!40600|Att_ClusterIndex: Null} Close Ex_Open_AI_Lib Text Te1936903827 Title: About similarity embeddings Description: ~ Similarity embeddings are used for finding the text records that are most similar in meaning to a given text. An embedding is a vector that represents the meaning of a block of text, and by computing the similarity between two vectors you arrive at a measure of how much the original text strings deal with the same topic.~ ~ For example, you might want to find a small set of web pages that most closely matches a search query. You could store the encodings for small blocks of text that appear on each web page, and then find the blocks of text with the highest similarity to the search query.~ ~ In the Examples module, take a look at the "Similarity of query to speech", which matches a query with text from the first paragraph of 5 famous US presidential speeches. Notice how the match doesn't require the words or phrases to be the same. For example, the query "87" strongly matches Lincoln's "Four score and seven years ago..."~ ~ The two main functions are:~ • Embedding_for( text ): Returns the embedding vector for text.~ • Embedding_similarity( X, Y ): Returns the similarity between two embedding vectors.~ ~ Let Embedding_similarity(X,Y) array abstract to measure similarity across a collection.~ ~ Note that an embedding vector will always be indexed by Ada_embedding -- this is the embedding dimension for the Ada model, OpenAI's model that is tuned for doing embeddings efficiently. NodeLocation: 376,280,-1 NodeSize: 304,240 NodeInfo: 1,,,,1,1 NodeColor: 52427,60621,65535 Close Similarity_embedding Alias Al125226643 Title: OpenAI Model Name NodeLocation: 1216,56,1 NodeSize: 64,24 Original: OpenAI_Model_Name Library OAL_Text_completions Title: Text completions Description: Author: Lonnie Chrisman~ Lumina Decision Systems Date: Fri, Jul 21, 2023 1:48 PM NodeLocation: 1032,224,1 NodeSize: 80,24 DiagState: 2,1282,23,1125,753,17,10 Function Chat_completion( messages : text all [Chat_index] ;~ role : text [Chat_index] ;~ Chat_index : Index ;~ ~ modelName : text atom = 'gpt-3.5-turbo' ;~ ~ functions : optional ... Object;~ ~ temperature : optional NonNegative atom ;~ top_p : optional positive atom ;~ ~ Completion_index : optional Index ;~ stop_sequences : optional text ;~ ~ max_tokens : optional atom ;~ presence_penalty, frequency_penalty : optional number atom ~ ) Title: Chat completion Description: This returns the next response from in a Chat (ala ChatGPT) given the history of messages so far.~ ~ Required parameters:~ «messages» : The sequence of messages so far, in order, indexed by «Chat_index».~ «role» : Each message has a role, which must be one of 'system', 'user', 'assistant', or 'function'.~ «Chat_index»: Indexes the sequence of messages in the conversation~ ~ Return values:~ 1. The main return value is the textual response (the content). ~ If «Completion_index» is specified, this is a set of completions indexed by «Completion_index».~ 2. The finish_reason. Usually Null, but may be "stop" if a stop_sequence is encountered.~ 3. Number of prompt tokens. This is the total number in all the messages.~ 4. Number of tokens in the completion.~ 5. A reference to the full parsed response from the server.~ ~ Optional parameters:~ «modelName»: The OpenAI model to use. It must support Chat. 'gpt-3.5', 'gpt-3.5-turbo' and 'gpt-4' are common choices.~ «functions» : One or more functions that the LLM can call during its completions.~ «temperature»: A value between 0 and 2. ~ Smaller values are more focused and deterministic, Higher values are more random. Default=1.~ «top_p»: A value 0