Tinderbox and the OpenAI API

I created a demo file that implements a function using CURL to call the OpenAI API.
The first thing you have to do is create a free account at https://platform.openai.com.
Then you need to create an API key: OpenAI API
Copy the key into the OpenAI_Key attribute of the gPreferences note.

Then you are ready to test the OpenAI interface. Select one (or more) of the „myJsonX_raw“ notes and apply the „getKeywordWithAI“ stamp to the note. Wait a few seconds and you should see the keywords in the OpenAI_tags attribute of the selected note.

To retrieve keywords from a text is only one possible use case. The stamp „getKeywordWithAI“ has been created for this specific task: get the keywords of a text.

There is a 2nd Stamp called „getAnswerWithAI“ with a more universal approach. The results are always added to the note „debug“ (change that to your needs).
I created a prototype called „pOpenAI“ and all the demo notes („myJsonX_raw“) use this prototype. There are several attributes to control the OpenAI engine. The most important one is „OpenAI_task“. Here you specify what OpenAI should do for you. The better you define your task, the better the result will be. Possible options for this task are unlimited. For example „get the short bio of“ or „select all cities found in the following text“ or „correct the spelling of the following text“… The text of the note is the target of the task and will be delivered together to the OpenAI engine. So if you enter „get the short bio of“ into the „OpenAI_task“ attribute of a note, the text of this note should contain the name of the person you are looking for. It should be easy to adjust those inputs to your individual Tinderbox structure. The attribute „OpenAI_Max_Tokens“ is also important. A text will be broken into tokens by OpenAI. A token is more or less equal to a syllable. If you limit „OpenAI_Max_Tokens“ to 100 only 100 tokens will be processed. For a longer text you have to increase this value.

You find all the code needed in the note „cOpenAI“. I use CURL and the runCommand action code to communicate with the OpenAI API. The function „callOpenAI_db“ creates the CURL command for you. There should be no need to alter this function. You have to call the function with two parameters: the text to work with (the $Text of a note) and a type parameter. Use 1 if you like to extract keywords and 2 for anything else. See both stamps to get an example how to call the function.

The function „buildOpenAIPayload_db“ is the place where I add the parameters to be passed with the CURL command. And that’s the place where you should adjust the code to your specific needs. Everything else is just Tinderbox stuff like creating links or removing text from the returned data.

Have fun,
Detlef
OpenAI-Demo.tbx (294.1 KB)

7 Likes

This stamp doesn’t work for me. The second stamp does.

(I have a paid OpenAI account; and used the API key as instructed in the OP.)

works for me - just tried the demo again - it might take some time until the response returns a value. The result will be written into the “OpenAI_Tags” attribute of the selected note.

And it would be a concern if you pasted a demo that didn’t work for you :astonished:

I have a paid Open AI account, and I’ve generated API keys for Tana’s AI commands, that work wonderfully quick there. So, the issue is not with my account. It’s not with the keys I generated for Tinderbox. Then something else is wrong here.

try to add:

doDebugLog_db(curlRet);

into the function callOpenAI_db just one line after the curlRet = runCommand(curlCmd); line.
Now in the debug note you should see if there was an error in the connect with the OpenAI interface. It might take some time (seconds) until the CURL command returns a value.

Hi Detlef,

Not sure if Paul got his to work. Not working over here for either stamp.

Yes, I did create its own Open secret key and pasted into the gPreference OpenAI_key field as a value.

Regarding the added debug command.
I did that too… does not seem to show any error on my side.

for keyword stamp for myJson8_raw…here is what I am receiving in the debug text

Here is the myJson8_raw even after several minutes. Nothing changed.

HTH
Tom

Hi Tom,

That’s my returned value:

{“id”:“—”,“object”:“text_completion”,“created”:1686245201,“model”:“text-davinci-003”,“choices”:[{“text”:“\n\nZettelkasten, Commonplace Book, Tools for Thought, Note Taking, Productivity, Nicholas Luhmann, Niklas Luhmann, Slip Box, Index Cards, Subject Headings, Indexes”,“index”:0,“logprobs”:null,“finish_reason”:“stop”}],“usage”:{“prompt_tokens”:436,“completion_tokens”:45,“total_tokens”:481}}

Looks pretty the same to your returned data. The problem has to be within in the getJSONpartOpenAI_db function?! The OpenAI interface is running fine - no problem there.

I parse only the content of the “text” object in the JSON data.

Detlef

Here you go…

[{“text”:“\n\nZettelkasten, Commonplace Book, Tools for Thought, Note Taking, Productivity, Nicholas Luhmann, Niklas Luhmann, Slip Box, Index Cards, Subject Headings, Indexes”,“index”:0,“logprobs”:null,“finish_reason”:“stop”}],“usage”:{“prompt_tokens”:436,“completion_tokens”:45,“total_tokens”:481}}

Thanks for your work and contribution to the community, Detlef
Tom

1:1… :frowning:

Could you please replace the function getJSONpartOpenAI_db with:

function getJSONpartOpenAI_db(rawText, theType){
	// get rid of the first part with statistics
	// processes the data received by the OpenAI API
	var:string myCleanJSON  = rawText.replace("[^\{]*(\{.*)","$1");
	var:string myAttributes = myCleanJSON.json["choices"].at("text");

	// now starts the interpretation of the returned data
	myAttributes = myAttributes.replace("\n\n","\n");

	doDebugLog_db("STEP1" + myAttributes);
	if(theType == 1) {
		if(myAttributes.contains("Keywords:")) {
			// sometime OpenAI returns this format, sometimes it does not
			myAttributes = myAttributes.trim();
			myAttributes = myAttributes.replace("Keywords: ","");
			myAttributes = myAttributes.replace(", ","###");
		} else {
			if(!myAttributes.contains("\n-")) {
				myAttributes = myAttributes.trim();
				myAttributes = myAttributes.replace(", ","###");
				doDebugLog_db("STEP2" + myAttributes);
			} else {
				myAttributes = myAttributes.replace("\n-","###");
			}
		};
		var:list myAttlist = myAttributes.split("###");
	} else {
		var:string myAttlist = myAttributes;
	};

	return myAttlist;
};

and paste the debug output?

Should look like:

1686245751;myJson8_raw;  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  2067    0     0  100  2067      0   1675  0:00:01  0:00:01 --:--:--  1680
100  2067    0     0  100  2067      0    924  0:00:02  0:00:02 --:--:--   925
100  2067    0     0  100  2067      0    638  0:00:03  0:00:03 --:--:--   638
100  2495  100   428  100  2067    132    637  0:00:03  0:00:03 --:--:--   771
{"id":"cmpl-...","object":"text_completion","created":1686245748,"model":"text-davinci-003","choices":[{"text":"\n\nZettelkasten, Commonplace Book, Tools for Thought, Note Taking, Productivity, Nicholas Luhmann, Niklas Luhmann, Slip Box, Index Cards, Subject Headings, Indexes","index":0,"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":436,"completion_tokens":45,"total_tokens":481}}

1686245751;myJson8_raw;STEP1
Zettelkasten, Commonplace Book, Tools for Thought, Note Taking, Productivity, Nicholas Luhmann, Niklas Luhmann, Slip Box, Index Cards, Subject Headings, Indexes
1686245751;myJson8_raw;STEP2Zettelkasten###Commonplace Book###Tools for Thought###Note Taking###Productivity###Nicholas Luhmann###Niklas Luhmann###Slip Box###Index Cards###Subject Headings###Indexes
1686245751;myJson8_raw;Zettelkasten;Commonplace Book;Tools for Thought;Note Taking;Productivity;Nicholas Luhmann;Niklas Luhmann;Slip Box;Index Cards;Subject Headings;Indexes

hard to debug remote :wink:

could you please try again:

function getJSONpartOpenAI_db(rawText, theType){
	// get rid of the first part with statistics
	// processes the data received by the OpenAI API
	var:string myCleanJSON  = rawText.replace("[^\{]*(\{.*)","$1");
 	doDebugLog_db("STEP00" + myCleanJSON);

	var:string myAttributes = myCleanJSON.json["choices"].at("text");
	doDebugLog_db("STEP0" + myAttributes);


	// now starts the interpretation of the returned data
	myAttributes = myAttributes.replace("\n\n","\n");

	doDebugLog_db("STEP1" + myAttributes);
	if(theType == 1) {
		if(myAttributes.contains("Keywords:")) {
			// sometime OpenAI returns this format, sometimes it does not
			myAttributes = myAttributes.trim();
			myAttributes = myAttributes.replace("Keywords: ","");
			myAttributes = myAttributes.replace(", ","###");
		} else {
			if(!myAttributes.contains("\n-")) {
				myAttributes = myAttributes.trim();
				myAttributes = myAttributes.replace(", ","###");
				doDebugLog_db("STEP2" + myAttributes);
			} else {
				myAttributes = myAttributes.replace("\n-","###");
			}
		};
		var:list myAttlist = myAttributes.split("###");
	} else {
		var:string myAttlist = myAttributes;
	};

	return myAttlist;
};

you are fast - the first doDebugLug_db call should be doDebugLog_db(“STEP00” + myCleanJSON);

There is only one line of code between “Step00” and “Step0”:

var:string myCleanJSON = rawText.replace("[^\{]*(\{.*)","$1");

This line extracts the JSON part from the stats data in the head of the reply. If this goes wrong - all data has been removed.

Here is the way it looks on my side…is it wrong?

function getJSONpartOpenAI_db(rawText, theType){
// get rid of the first part with statistics
// processes the data received by the OpenAI API
var:string myCleanJSON = rawText.replace(“[^{]({.)”,“$1”);
doDebugLog_db(“STEP00” + myAttributes);
var:string myAttributes = myCleanJSON.json[“choices”].at(“text”);

doDebugLog_db("STEP0" + myAttributes);
// now starts the interpretation of the returned data
myAttributes = myAttributes.replace("\n\n","\n");

doDebugLog_db("STEP1" + myAttributes);
if(theType == 1) {
	if(myAttributes.contains("Keywords:")) {
		// sometime OpenAI returns this format, sometimes it does not
		myAttributes = myAttributes.trim();
		myAttributes = myAttributes.replace("Keywords: ","");
		myAttributes = myAttributes.replace(", ","###");
	} else {
		if(!myAttributes.contains("\n-")) {
			myAttributes = myAttributes.trim();
			myAttributes = myAttributes.replace(", ","###");
			doDebugLog_db("STEP2" + myAttributes);
		} else {
			myAttributes = myAttributes.replace("\n-","###");
		}
	};
	var:list myAttlist = myAttributes.split("###");
} else {
	var:string myAttlist = myAttributes;
};

return myAttlist;

};

I had a typo in my sample and corrected it while you were already using the code. I would like to see the value of the variable myCleanJSON and this is what you need to change:

var:string myCleanJSON = rawText.replace(“[^{]*({.* )”,“$1”);
doDebugLog_db(“STEP00” + myCleanJSON);

:wink:

Here is what I get.

1686256289;myJson8_raw;STEP00
1686256289;myJson8_raw;STEP0
1686256289;myJson8_raw;STEP1
1686256289;myJson8_raw;STEP2
1686256289;myJson8_raw;

nb: I even checked to make sure all quotes were straight rather than curly.

Tom

hmmmm…

from (in callOpenAI_db):

curlRet = runCommand(curlCmd);
doDebugLog_db(curlRet);

to the first command in getJSONpartOpenAI_db:

var:string myCleanJSON  = rawText.replace("[^\{]*(\{.*)","$1");
doDebugLog_db(“STEP00” + myCleanJSON);

The content get’s lost. If you use the following version “Step0” will return the data from OpenAI and “Step00” will not I assume. So the RegEx pattern that works on my machine doesn’t do it on yours or on @PaulWalters Mac… but there is nothing special in it?! I’m lost. I will redo the whole function within the next days. Thanks a lot for helping to find the bug!

function getJSONpartOpenAI_db(rawText, theType){
	// get rid of the first part with statistics
	// processes the data received by the OpenAI API
        doDebugLog_db(“STEP0” + rawText);
	var:string myCleanJSON  = rawText.replace("[^\{]*(\{.*)","$1");
        doDebugLog_db(“STEP00” + myCleanJSON);
	var:string myAttributes = myCleanJSON.json["choices"].at("text");

	// now starts the interpretation of the returned data
	myAttributes = myAttributes.replace("\n\n","\n");
	if(theType == 1) {
		if(myAttributes.contains("Keywords:")) {
			// sometime OpenAI returns this format, sometimes it does not
			myAttributes = myAttributes.trim();
			myAttributes = myAttributes.replace("Keywords: ","");
			myAttributes = myAttributes.replace(", ","###");
		} else {
			if(!myAttributes.contains("\n-")) {
				myAttributes = myAttributes.trim();
				myAttributes = myAttributes.replace(", ","###");
			} else {
				myAttributes = myAttributes.replace("\n-","###");
			}
		};
		var:list myAttlist = myAttributes.split("###");
	} else {
		var:string myAttlist = myAttributes;
	};

	return myAttlist;
};

Thanks to your version of my demo file I found the problem!

Take a look at the RegEx pattern in your file:

[^{]*({.* )

and this is the pattern I see in my version:

[^\{]*(\{.*)

The backslash escapes the curly bracket and is missing in your file. So the RegEx pattern will not work. I will paste a new version…

the new demo:

OpenAI-Demo2.tbx (269.8 KB)

1 Like

Ok, I think we are making progress.
I get the json now in the debug with the new file. see screenshot below

However, no tags are appearing in the note attributes from the json file as I expected after I applied the stamp to the note. See here

Tom