Wikilinks to notes automatically

This script was worked on incrementally. I didn’t even know if what it currently does was possible. I just thought of what would be a good idea, and I tried to get the ai to write it. After several iterations, the script seems to be working as I had hoped. It’s actually very useful to me.
If i start on something else from scratch, i might try javascript.

1 Like

Well, there’s even a lot less JavaScript for Automation (JXA) code on the web, therefore I wouldn’t bet that AI would create better scripts or e.g. maybe return scripts that are (partially or completely) intended for browsers instead.

The next thing I want to do is to have it create “Heading Pages Database” instead of just Heading Pages…
But, I’m afraid something’s gonna break.
I haven’t tested if it updates the tags if the tags change after it goes through its first run…
I have noticed that often I have to ask ai to make the code run slower. For some reason, either the DT database, or some process doesn’t keep up with the script.

True, but for the examples I quoted JXA is not even required – all that is pure JavaScript. encodeURIComponent works everywhere, not only in browsers. And there are neither DOM nor windows methods required nor useful for the case at hand.

I still don’t use AI, so I can’t try that out. In any case, I don’t think it’s useful to post bad code. Even if it solves a problem, it sets a bad example and is not useful for learning how to code.

You can always close your eyes and scroll down while holding your breath.

better yet, in order to help future ai generations, or in fact help the forum as a whole you can write the code as it should be done with JXA (javascript)… maybe we can learn a thing or two.
Honestly, that would be a good idea.
I’m open to clarifying things about what the script does, or is intended to do, to make it easier.
I’m open to helping to the best of my abilities to get this done in javascript :slight_smile:

I have already written tons of JXA code. Here and elsewhere. Feel free to browse and comment. But I limit myself to translating those scripts that interest me personally.

There’s in fact nothing wrong with AppleScript BTW (just joking, but language wars don’t get us anywhere). What is wrong here is that people who can’t judge and have no experience coding in it might think that this kind of code is actually well written. Yes, I can close my eyes on it. But that is beyond the point. Published code should not only be working “somehow”, it should be written so that people can actually learn something useful from it.
This (and nearly everything I’ve seen coming from an A"I" in AppleScript) is not code people can learn something useful from. Not by your fault, of course.

This snippet, for example

-- Verify the link was added by checking the content again
  set updatedContent to plain text of wikiPage
  if updatedContent does not contain docLink then
   log "Warning: Failed to add link to " & (name of wikiPage)
  end if

is supposed to do what? If appending a string to the plain text property of a record would not work reliably, we’d have a very serious problem with the DT scripting interface. Which seems, after all the code written to it, very improbable. Mind you, it doesn’t do any harm except burning CPU cycles. But it still begs the question why it is there.

Then there’s

repeat with theRecord in selectedRecords
  if type of theRecord is in {markdown, txt, rtf, rtfd} then

twice in the script. Which should ring a bell: If I only need certain records, I should weed them out once at the top, not twice. Which one would probably do with a whose statement building a list containing only the desired records. No, it doesn’t do any harm except burning some more CPU cycles. But it’s bad style. As is

set hasWikilink to false
if theContent contains linkToFind then
  set hasWikilink to true
end if

which would be written more concisely and clearly as

set hasWikilink to (theContent contains linkToFind)

But even that is not needed, since we’re only interested in the case where hasWikilink is false. So, the variable is not needed, and one could simply write

if (theContent does not contain linkToFind) then
...
end if

Shorter code is often (not always) easier to read and understand and consequently to maintain. Also in this case: Instead of following the history of a useless variable, it’s immediately clear what the if is checking for.

1 Like

And that’s not a valid AppleScript command in DEVONthink either. The correction command is log message. It would only log in the script replies while running the code. Perhaps intended, perhaps not.

I think this is where we differ. I am using this script for my own purposes. I only posted it here because I know there are a lot of people interested in zettlekasten, and linking notes with ai.
As to the unnecessary code you mentioned, I’m not sure how much can be removed. Everything seems necessary and it’s a little more complicated than it looks. It’s actually one step in a multi step process.

Have you tried running the script?

All you need to test it is something like:

[[heading topic 1]]
[[heading topic 2]]

#tag1 #tag2 #tag 3

Here’s an example of what one of my notes looks like. All the stuff in the YAML section is ai generated from the note’s content.

Another script I run actually renames the note, and creates the tags in DT.

I have written code in several languages since over 40 years. To see how it works (or does not) does not require running it - at least not if it’s written in AppleScript.

And I’ve already explained why certain parts of the script are useless or overly complicated. All that is about logic and flow of the program. To see the short comings, understanding code suffices. Which LLMs of course do not.

I have tried some of your suggestions in the past, and they haven’t worked.

on encodeText(theText)
	set theTextEnc to ""
	repeat with theChar in theText
		set ASCIINum to ASCII number theChar
		if ASCIINum is 32 then
			set theTextEnc to theTextEnc & "%20"
		else if ((ASCIINum ≥ 48 and ASCIINum ≤ 57) or (ASCIINum ≥ 65 and ASCIINum ≤ 90) or (ASCIINum ≥ 97 and ASCIINum ≤ 122)) then
			set theTextEnc to theTextEnc & theChar
		else
			set hexList to {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}
			set theTextEnc to theTextEnc & "%" & item ((ASCIINum div 16) + 1) of hexList & item ((ASCIINum mod 16) + 1) of hexList
		end if
	end repeat
	return theTextEnc
end encodeText

use AppleScript version "2.4"
use scripting additions

tell application id "DNtp"
	try
		set theDB to current database
		if theDB is missing value then error "Please open a database first."
		
		set selectedRecords to selected records
		if (count of selectedRecords) is 0 then error "Please select some documents to process."
		
		-- Filter records once
		set filteredRecords to {}
		repeat with aRecord in selectedRecords
			if type of aRecord is in {markdown, txt, rtf, rtfd} then
				set end of filteredRecords to aRecord
			end if
		end repeat
		
		set headingsGroup to create location "/Heading Pages" in theDB
		
		repeat with theRecord in filteredRecords
			set theContent to plain text of theRecord
			
			-- Find wikilinks safely
			set AppleScript's text item delimiters to "[["
			set linkItems to text items of theContent
			set foundWikilinks to {}
			
			repeat with itemNum from 2 to count of linkItems
				set segment to item itemNum of linkItems
				if segment contains "]]" then
					set AppleScript's text item delimiters to "]]"
					set wikiLink to first text item of segment
					set AppleScript's text item delimiters to ""
					if wikiLink is not in foundWikilinks then
						set end of foundWikilinks to wikiLink
					end if
				end if
			end repeat
			
			-- Process wikilinks
			repeat with linkName in foundWikilinks
				set existingPages to search "name:" & linkName in headingsGroup
				if (count existingPages) > 0 then
					set wikiPage to item 1 of existingPages
				else
					set wikiPage to create record with {name:linkName, type:markdown, plain text:("# " & linkName & return & "## Documents referencing this heading" & return & return)} in headingsGroup
				end if
				
				set docLink to "- [" & (name of theRecord as string) & "](" & (reference URL of theRecord) & ")"
				
				-- Add tags if present
				set docTags to tags of theRecord
				if (count docTags) > 0 then
					set docLink to docLink & return & "  Tags: "
					repeat with aTag in docTags
						set encodedTag to my encodeText(aTag)
						set tagURL to "x-devonthink://search?query=tag:" & encodedTag
						set docLink to docLink & "[" & aTag & "](" & tagURL & ") "
					end repeat
				end if
				
				set plain text of wikiPage to (plain text of wikiPage & docLink & return)
			end repeat
		end repeat
		
		-- Clean orphaned references
		repeat with headingPage in children of headingsGroup
			set headingName to name of headingPage
			set pageContent to plain text of headingPage
			
			if pageContent does not contain "- [" then
				delete record headingPage
			end if
		end repeat
		
		set AppleScript's text item delimiters to {""}
	on error errMsg number errNum
		set AppleScript's text item delimiters to {""}
		display alert "Error" message errMsg
	end try
end tell

I even tried updating this code with your suggestions, but it doesn’t work…

As far as I’m concerned, applescript works with bubblegum and duct tape…

My code is currently working, so ugly as it is… I’ll settle for that…
If you want to fix this code that ain’t working but has been “improved” with your suggestions, give it a go. You might have better luck.

All you do is point out problems without offering any real help. If you’re not going to contribute anything meaningful, keep your comments to yourself. I don’t need your vague critiques — I need solutions. Maybe spend your 40 years of ‘experience’ actually fixing something for a change instead of just criticizing from the sidelines.

I read through most of this post but it is not clear to me what is the solution to the question:

Over time, I’ve accumulated a large number of these Wikilink categories. However, I don’t want to manually click each link in my notes to create the corresponding Wikilink pages.
Is there a way to automate this process? For example, could a script go through all my notes and automatically create the linked Wikilink pages for me?

Is this at a point where there can be summary solution to the problem?

Nothing changed in DEVONthink in regards to this. Why? Are you actually in need of such a thing? (PS: Answering ‘yes’ isn’t a guarantee of implementation. It’s information gathering.)

I’m not sure what you’re asking.
There are a couple of scripts.
My intent was to organize wikilink notes under a header.
To create notes from a wikilink all you have to do is click on the wikilink…

[quote=“anonny, post:1, topic:81878”]
Over time, I’ve accumulated a large number of these Wikilink categories. However, I don’t want to manually click each link in my notes to create the corresponding Wikilink pages.
[/quote].

I also have this. :up_arrow:

I also want this.:down_arrow:

Unfortunately the conversations within the post created noise that obscured for me an answer to the above question. My objective is to determine if a script to achieve the objective was identified. I am not a programmer.

I solved the problem I was trying to solve.
I’m not sure you have the same problem I did.
In short, since I’m using AI to help me enhance my notes by cataloguing them with some YAML info, and also creating wikilinks based on categories (like an index-- for example wikiling:dogs; wikilinks:cats) where that note fits, I had to find a way to quickly identify the notes that belong to X or Y cateogry.
That’s the problem I solved for myself.