#!/bin/bash # ------------------------------------------------------------------ # Author: ChatGPT # Generated on: $(date '+%Y-%m-%d') # # This script recursively creates or updates a table-of-contents README # file in each non-hidden directory. The file is named "Folder Name - README.md". # # Each README includes: # - An author/date header. # - A header with the folder's name. # - An alphabetically sorted list of immediate subdirectories, with links # to that subdirectory’s own README. # - An alphabetically sorted list of immediate files (excluding the generated README). # - A "Summary" section with a short description generated by an LLM (using llama3.2:latest). # # Hidden directories (or any directory under a hidden parent such as .git) are skipped. # # The script only updates a README if the static content (header, subdirectories and files) # changes. The LLM summary output is excluded from the diff check. # # Progress is printed as "[x/y] Updated: {dir}" or "[x/y] No change: {dir}". # ------------------------------------------------------------------ # Set the base directory (change "." if necessary) base_dir="." # Build an array of directories to process. dirs=() while IFS= read -r -d '' dir; do # Skip directories that are hidden or inside a hidden parent (like .git) if [[ "$(basename "$dir")" == .* ]] || [[ "$dir" == *"/.git"* ]] || [[ "$dir" == *"/.obsidian"* ]] || [[ "$dir" == *"/src"* ]] || [[ "$dir" == *"/target"* ]]; then continue fi dirs+=( "$dir" ) done < <(find "$base_dir" -type d -print0) total=${#dirs[@]} count=0 for dir in "${dirs[@]}"; do count=$((count+1)) # For the top-level directory, use the actual name from $PWD; otherwise, use the directory's basename. if [ "$dir" = "$base_dir" ]; then base=$(basename "$PWD") else base=$(basename "$dir") fi # Define the path for the README file: "Folder Name - README.md" readme="$dir/${base} - README.md" # Create a temporary file to hold the new static content. tmp_static=$(mktemp) { echo "# Table of Contents for ${base}" echo "" } > "$tmp_static" ######################### # Process Subdirectories ######################### subdirs=() while IFS= read -r -d '' subdir; do sub_basename=$(basename "$subdir") if [ -n "$sub_basename" ]; then subdirs+=( "$sub_basename" ) fi done < <(find "$dir" -mindepth 1 -maxdepth 1 -type d ! -name '.*' -print0) if [ ${#subdirs[@]} -gt 0 ]; then mapfile -t sorted_subdirs < <(printf "%s\n" "${subdirs[@]}" | sort) echo "## Subdirectories" >> "$tmp_static" for sub in "${sorted_subdirs[@]}"; do # Link format: [[Subfolder/Subfolder - README]] line="- [[${sub}/${sub} - README]]" printf "%s\n" "$line" >> "$tmp_static" done echo "" >> "$tmp_static" fi ################# # Process Files ################# files=() while IFS= read -r -d '' file; do fbase=$(basename "$file") if [ -n "$fbase" ]; then files+=( "$fbase" ) fi done < <(find "$dir" -mindepth 1 -maxdepth 1 -type f ! -path "$readme" -print0) if [ ${#files[@]} -gt 0 ]; then mapfile -t sorted_files < <(printf "%s\n" "${files[@]}" | sort) echo "## Files" >> "$tmp_static" for f in "${sorted_files[@]}"; do line="- [[${f}]]" printf "%s\n" "$line" >> "$tmp_static" done echo "" >> "$tmp_static" fi # Determine if the static content has changed. static_changed=1 if [ -f "$readme" ]; then # Extract the static portion from the existing README (everything before "## Summary") existing_static=$(sed '/^## Summary/,$d' "$readme") new_static=$(cat "$tmp_static") if [ "$existing_static" = "$new_static" ]; then static_changed=0 fi fi if [ $static_changed -eq 0 ]; then #echo "[$count/$total] No change: $dir" rm "$tmp_static" continue fi ################# # Query LLM for Summary ################# echo "Creating summary..." # Define file extensions considered to be text-based. # You can easily edit this array to add or remove extensions. TEXT_EXTENSIONS=( "*.md" "*.rs" "*.hs" "*.py" "*.txt" "*.m" ) # Build an array of find conditions. # For each extension, we add "-iname " to the array. FIND_CONDITIONS=() for ext in "${TEXT_EXTENSIONS[@]}"; do FIND_CONDITIONS+=( -iname "$ext" -o ) done # Remove the last extra '-o' unset 'FIND_CONDITIONS[${#FIND_CONDITIONS[@]}-1]' # Now use find with these conditions. # Pull in the content of all markdown files in this folder (excluding the generated README) folder_md=$(find "$dir" -maxdepth 1 -type f \( "${FIND_CONDITIONS[@]}" \) ! -path "$readme" \ -exec sh -c 'for file; do echo "=======$file=========" cat "$file" echo "========end $file========" echo "" done' sh {} +) prompt="You are creating a description for a README file in my Obsidian notes database. Below you will find two items. Item number 1 is a table of contents of what is in the folder of the README file. Item number 2 is the contents of all of the text based files within that folder. Based on this information, create a description of what is inside the folder, as if you were telling yourself what is in there. Be concise, to the point, and do not excessively speculate. Your result will be put into a Markdown file, where you can use [[wikilinks]] and other markdown syntax. When you use the name of a file in a description, put it in a [[wikilink]]. Thanks! Item 1: $(cat "$tmp_static") Item 2: $folder_md" #echo "" #echo "Prompt:" #echo "=================" #echo $prompt #summary=$(/usr/local/bin/ollama run llama3.2 "$prompt") #echo "" #echo "Summary:" #echo "=================" #echo $summary # Build the full new content: static portion + summary section. { cat "$tmp_static" echo "## Summary" # echo "$summary" echo "" echo "Generated by llama3.2:latest" } > "$readme" rm "$tmp_static" echo "[$count/$total] Updated: $dir" done