Tutto è testo

Perché la shell è il “posto” ideale per usare gli LLM

Facciamoci una risata

La vignetta “tar” di xkcd

C’è poco da ridere

  • cercare su stackexchange
  • cercare su google
  • cercare su reddit
  • chiedere all’amico psicotico
  • usare man

Ma ora c’è l’intelligenza artificiale

E non scoppiano più le bombe?

Quanti token il man di tar

man tar | ttok
9098

ttok è una utility del geniale Simon Willison

# quante linee
man tar | wc -l
991

# quante parole
man tar | wc -w
5194

E allora è poca roba

man tar | llm "come si usa il comando tar per estrarre il file appunti.tar.gz?
Scrivi soltanto il comando e commenta le opzioni"


```bash
tar -xzf appunti.tar.gz
```

*   `-x`: Specifica l'operazione di estrazione.
*   `-z`: Indica che l'archivio è compresso con gzip (il suffisso `.gz` lo suggerisce).
*   `-f appunti.tar.gz`: Specifica il nome del file archivio da estrarre.

E in stdout e stdin come sempre, c’è “soltanto” testo

graph TD
    A[Command1] -->|stdout| B((pipe))
    B -->|stdin| C[Command2]
    C -->|stdout| D((pipe))
    D -->|stdin| E[Command3]

llm (non i large language model)

(👏 a Simon Willison)

llm

LLM è un’utility a riga di comando e una libreria Python per interagire con modelli di linguaggio di grandi dimensioni (LLM) come quelli di OpenAI, Anthropic, Google, Meta e tanti altri, compresi quelli installati in locale.

È scritta in Python da quel genio di Simon Willison, il creatore di Datasette.

plugin

Esistono diversi plugin per llm. Con questi è possibile aggiungere modelli di LLM con cui interagire e/o attivare funzionalità aggiuntive.

I modelli

llm models


OpenAI Chat: gpt-4o (aliases: 4o)
OpenAI Chat: chatgpt-4o-latest (aliases: chatgpt-4o)
OpenAI Chat: gpt-4o-mini (aliases: 4o-mini)
OpenAI Chat: gpt-4o-audio-preview
OpenAI Chat: gpt-4o-audio-preview-2024-12-17
OpenAI Chat: gpt-4o-audio-preview-2024-10-01
OpenAI Chat: gpt-4o-mini-audio-preview
OpenAI Chat: gpt-4o-mini-audio-preview-2024-12-17
OpenAI Chat: gpt-4.1 (aliases: 4.1)
OpenAI Chat: gpt-4.1-mini (aliases: 4.1-mini)
OpenAI Chat: gpt-4.1-nano (aliases: 4.1-nano)
OpenAI Chat: gpt-3.5-turbo (aliases: 3.5, chatgpt)
OpenAI Chat: gpt-3.5-turbo-16k (aliases: chatgpt-16k, 3.5-16k)
OpenAI Chat: gpt-4 (aliases: 4, gpt4)
OpenAI Chat: gpt-4-32k (aliases: 4-32k)
OpenAI Chat: gpt-4-1106-preview
OpenAI Chat: gpt-4-0125-preview
OpenAI Chat: gpt-4-turbo-2024-04-09
OpenAI Chat: gpt-4-turbo (aliases: gpt-4-turbo-preview, 4-turbo, 4t)
OpenAI Chat: gpt-4.5-preview-2025-02-27
OpenAI Chat: gpt-4.5-preview (aliases: gpt-4.5)
OpenAI Chat: o1
OpenAI Chat: o1-2024-12-17
OpenAI Chat: o1-preview
OpenAI Chat: o1-mini
OpenAI Chat: o3-mini
OpenAI Chat: o3
OpenAI Chat: o4-mini
OpenAI Completion: gpt-3.5-turbo-instruct (aliases: 3.5-instruct, chatgpt-instruct)
OpenAI Chat: groq-openai-llama3
OpenAI Chat: groq-openai-llama3-8b
Perplexity: sonar-pro
Perplexity: sonar
Perplexity: sonar-pro-online
Perplexity: sonar-deep-research
Perplexity: sonar-reasoning-pro
Perplexity: sonar-reasoning
Perplexity: r1-1776
gpt4all: all-MiniLM-L6-v2-f16 - SBert, 43.76MB download, needs 1GB RAM
gpt4all: all-MiniLM-L6-v2 - SBert, 43.82MB download, needs 1GB RAM
gpt4all: nomic-embed-text-v1 - Nomic Embed Text v1, 261.58MB download, needs 1GB RAM
gpt4all: nomic-embed-text-v1 - Nomic Embed Text v1.5, 261.58MB download, needs 1GB RAM
gpt4all: Llama-3 - Llama 3.2 1B Instruct, 737.21MB download, needs 2GB RAM
gpt4all: qwen2-1_5b-instruct-q4_0 - Qwen2-1.5B-Instruct, 894.10MB download, needs 3GB RAM
gpt4all: DeepSeek-R1-Distill-Qwen-1 - DeepSeek-R1-Distill-Qwen-1.5B, 1019.29MB download, needs 3GB RAM
gpt4all: Llama-3 - Llama 3.2 3B Instruct, 1.79GB download, needs 4GB RAM
gpt4all: replit-code-v1_5-3b-newbpe-q4_0 - Replit, 1.82GB download, needs 4GB RAM
gpt4all: orca-mini-3b-gguf2-q4_0 - Mini Orca (Small), 1.84GB download, needs 4GB RAM
gpt4all: Phi-3-mini-4k-instruct - Phi-3 Mini Instruct, 2.03GB download, needs 4GB RAM
gpt4all: mpt-7b-chat - MPT Chat, 3.54GB download, needs 8GB RAM
gpt4all: orca-2-7b - Orca 2 (Medium), 3.56GB download, needs 8GB RAM
gpt4all: rift-coder-v0-7b-q4_0 - Rift coder, 3.56GB download, needs 8GB RAM
gpt4all: mpt-7b-chat-newbpe-q4_0 - MPT Chat, 3.64GB download, needs 8GB RAM
gpt4all: em_german_mistral_v01 - EM German Mistral, 3.83GB download, needs 8GB RAM
gpt4all: mistral-7b-instruct-v0 - Mistral Instruct, 3.83GB download, needs 8GB RAM
gpt4all: ghost-7b-v0 - Ghost 7B v0.9.1, 3.83GB download, needs 8GB RAM
gpt4all: Nous-Hermes-2-Mistral-7B-DPO - Nous Hermes 2 Mistral DPO, 3.83GB download, needs 8GB RAM
gpt4all: mistral-7b-openorca - Mistral OpenOrca, 3.83GB download, needs 8GB RAM
gpt4all: gpt4all-falcon-newbpe-q4_0 - GPT4All Falcon, 3.92GB download, needs 8GB RAM
gpt4all: qwen2 - Reasoner v1, 4.13GB download, needs 8GB RAM
gpt4all: DeepSeek-R1-Distill-Qwen-7B-Q4_0 - DeepSeek-R1-Distill-Qwen-7B, 4.14GB download, needs 8GB RAM
gpt4all: Meta-Llama-3 - Llama 3.1 8B Instruct 128k, 4.34GB download, needs 8GB RAM
gpt4all: Meta-Llama-3-8B-Instruct - Llama 3 8B Instruct, 4.34GB download, needs 8GB RAM
gpt4all: DeepSeek-R1-Distill-Llama-8B-Q4_0 - DeepSeek-R1-Distill-Llama-8B, 4.35GB download, needs 8GB RAM
gpt4all: gpt4all-13b-snoozy-q4_0 - Snoozy, 6.86GB download, needs 16GB RAM
gpt4all: wizardlm-13b-v1 - Wizard v1.2, 6.86GB download, needs 16GB RAM
gpt4all: orca-2-13b - Orca 2 (Full), 6.86GB download, needs 16GB RAM
gpt4all: nous-hermes-llama2-13b - Hermes, 6.86GB download, needs 16GB RAM
gpt4all: DeepSeek-R1-Distill-Qwen-14B-Q4_0 - DeepSeek-R1-Distill-Qwen-14B, 7.96GB download, needs 16GB RAM
gpt4all: starcoder-newbpe-q4_0 - Starcoder, 8.37GB download, needs 4GB RAM
GeminiPro: gemini-pro
GeminiPro: gemini-1.5-pro-latest
GeminiPro: gemini-1.5-flash-latest
GeminiPro: gemini-1.5-pro-001
GeminiPro: gemini-1.5-flash-001
GeminiPro: gemini-1.5-pro-002
GeminiPro: gemini-1.5-flash-002
GeminiPro: gemini-1.5-flash-8b-latest
GeminiPro: gemini-1.5-flash-8b-001
GeminiPro: gemini-exp-1114
GeminiPro: gemini-exp-1121
GeminiPro: gemini-exp-1206
GeminiPro: gemini-2.0-flash-exp
GeminiPro: learnlm-1.5-pro-experimental
GeminiPro: gemini-2.0-flash-thinking-exp-1219
GeminiPro: gemini-2.0-flash-thinking-exp-01-21
GeminiPro: gemini-2.0-flash
GeminiPro: gemini-2.0-pro-exp-02-05
GeminiPro: gemini-2.0-flash-lite
GeminiPro: gemma-3-27b-it
GeminiPro: gemini-2.5-pro-exp-03-25
GeminiPro: gemini-2.5-pro-preview-03-25
GeminiPro: gemini-2.5-flash-preview-04-17
GeminiPro: gemini-2.5-pro-preview-05-06
Anthropic Messages: anthropic/claude-3-opus-20240229
Anthropic Messages: anthropic/claude-3-opus-latest (aliases: claude-3-opus)
Anthropic Messages: anthropic/claude-3-sonnet-20240229 (aliases: claude-3-sonnet)
Anthropic Messages: anthropic/claude-3-haiku-20240307 (aliases: claude-3-haiku)
Anthropic Messages: anthropic/claude-3-5-sonnet-20240620
Anthropic Messages: anthropic/claude-3-5-sonnet-20241022
Anthropic Messages: anthropic/claude-3-5-sonnet-latest (aliases: claude-3.5-sonnet, claude-3.5-sonnet-latest)
Anthropic Messages: anthropic/claude-3-5-haiku-latest (aliases: claude-3.5-haiku)
Anthropic Messages: anthropic/claude-3-7-sonnet-20250219
Anthropic Messages: anthropic/claude-3-7-sonnet-latest (aliases: claude-3.7-sonnet, claude-3.7-sonnet-latest)
Ollama: nuextract:latest (aliases: nuextract)
OpenAI: openai/gpt-4o
OpenAI: openai/gpt-4o-mini
OpenAI: openai/gpt-4.5-preview
OpenAI: openai/gpt-4.5-preview-2025-02-27
OpenAI: openai/o3-mini
OpenAI: openai/o1-mini
OpenAI: openai/o1
OpenAI: openai/o1-pro
OpenAI: openai/gpt-4.1
OpenAI: openai/gpt-4.1-2025-04-14
OpenAI: openai/gpt-4.1-mini
OpenAI: openai/gpt-4.1-mini-2025-04-14
OpenAI: openai/gpt-4.1-nano
OpenAI: openai/gpt-4.1-nano-2025-04-14
OpenAI: openai/o3
OpenAI: openai/o3-2025-04-16
OpenAI: openai/o3-streaming
OpenAI: openai/o3-2025-04-16-streaming
OpenAI: openai/o4-mini
OpenAI: openai/o4-mini-2025-04-16
LLMGroq: groq/playai-tts-arabic
LLMGroq: groq/qwen-2.5-coder-32b
LLMGroq: groq/llama-3.3-70b-specdec
LLMGroq: groq/allam-2-7b
LLMGroq: groq/whisper-large-v3
LLMGroq: groq/llama-3.3-70b-versatile (aliases: groq-llama-3.3-70b)
LLMGroq: groq/qwen-2.5-32b
LLMGroq: groq/mistral-saba-24b
LLMGroq: groq/gemma2-9b-it (aliases: groq-gemma2)
LLMGroq: groq/whisper-large-v3-turbo
LLMGroq: groq/deepseek-r1-distill-llama-70b
LLMGroq: groq/meta-llama/llama-4-scout-17b-16e-instruct
LLMGroq: groq/llama-3.2-90b-vision-preview
LLMGroq: groq/llama-3.2-3b-preview
LLMGroq: groq/meta-llama/llama-4-maverick-17b-128e-instruct
LLMGroq: groq/llama3-8b-8192 (aliases: groq-llama3)
LLMGroq: groq/llama-guard-3-8b
LLMGroq: groq/llama3-70b-8192 (aliases: groq-llama3-70b)
LLMGroq: groq/qwen-qwq-32b
LLMGroq: groq/llama-3.2-1b-preview
LLMGroq: groq/llama-3.2-11b-vision-preview
LLMGroq: groq/distil-whisper-large-v3-en
LLMGroq: groq/deepseek-r1-distill-qwen-32b
LLMGroq: groq/llama-3.1-8b-instant (aliases: groq-llama3.1-8b)
LLMGroq: groq/playai-tts
Default: gemini-2.0-flash-exp

Testare modelli

for i in claude-3.5-sonnet gemini-2.0-flash-exp 4o; do
  llm "Dammi un nome per un convegno su Esplorare il rapporto tra Open Data e Intelligenza Artificiale. Un solo nome senza commenti"
done


Open Data AI: Convergenza e Innovazione

Open Data AI Summit

Open Data AI Convergence

Modelli: opzioni

GeminiPro: gemini/gemini-2.0-flash-exp (aliases: gemini-2.0-flash-exp)
  Options:
    code_execution: boolean
    temperature: float
    max_output_tokens: int
    top_p: float
    top_k: int
    json_object: boolean
    timeout: float
    google_search: boolean
  Attachment types:
    application/ogg, application/pdf, audio/aac, audio/aiff,
    audio/flac, audio/mp3, audio/mpeg, audio/ogg, audio/wav,
    image/heic, image/heif, image/jpeg, image/png, image/webp,
    text/csv, text/plain, video/3gpp, video/avi, video/mov, video/mp4,
    video/mpeg, video/mpg, video/quicktime, video/webm, video/wmv,
    video/x-flv
  Features:
  - streaming
  - schemas
  - tools
  - async
  Keys:
    key: gemini
    env_var: LLM_GEMINI_KEY

Modelli: opzioni

OpenAI Chat: gpt-4o (aliases: 4o)
  Options:
    temperature: float
      What sampling temperature to use, between 0 and 2. Higher values like
      0.8 will make the output more random, while lower values like 0.2 will
      make it more focused and deterministic.
    max_tokens: int
      Maximum number of tokens to generate.
    top_p: float
      An alternative to sampling with temperature, called nucleus sampling,
      where the model considers the results of the tokens with top_p
      probability mass. So 0.1 means only the tokens comprising the top 10%
      probability mass are considered. Recommended to use top_p or
      temperature but not both.
    frequency_penalty: float
      Number between -2.0 and 2.0. Positive values penalize new tokens based
      on their existing frequency in the text so far, decreasing the model's
      likelihood to repeat the same line verbatim.
    presence_penalty: float
      Number between -2.0 and 2.0. Positive values penalize new tokens based
      on whether they appear in the text so far, increasing the model's
      likelihood to talk about new topics.
    stop: str
      A string where the API will stop generating further tokens.
    logit_bias: dict, str
      Modify the likelihood of specified tokens appearing in the completion.
      Pass a JSON string like '{"1712":-100, "892":-100, "1489":-100}'
    seed: int
      Integer seed to attempt to sample deterministically
    json_object: boolean
      Output a valid JSON object {...}. Prompt must mention JSON.
  Attachment types:
    application/pdf, image/gif, image/jpeg, image/png, image/webp
  Features:
  - streaming
  - schemas
  - tools
  - async
  Keys:
    key: openai
    env_var: OPENAI_API_KEY

Torniamo alla shell

lsb_release -a

No LSB modules are available.
Distributor ID: Debian
Description:    Pengwin
Release:        12
Codename:       bookworm
llm "Quali i punti chiave del mio OS: $(lsb_release -a)"


I punti chiave del tuo sistema operativo, basati sulle informazioni fornite, sono:

*   **Distribuzione:** Debian
*   **Derivata:** Pengwin (una distribuzione specificamente progettata per l'uso con il sottosistema Windows per Linux, WSL)
*   **Versione:** 12
*   **Nome in codice:** Bookworm (il nome in codice per la versione 12 di Debian)

In sintesi, stai utilizzando **Pengwin**, una distribuzione Linux basata su **Debian 12 "Bookworm"**, ottimizzata per l'esecuzione all'interno di **WSL** (Windows Subsystem for Linux).

È markdown
👇👇👇

In sintesi, stai utilizzando Pengwin, una distribuzione Linux basata su Debian 12 “Bookworm”, ottimizzata per l’esecuzione all’interno di WSL (Windows Subsystem for Linux).

Il web è testo

curl -ksL "https://www.ilpost.it/" | llm "quali sono le categorie di notizie oggi più presenti?"


curl -ksL "https://www.ilpost.it/" | llm "estrai soltanto i titoli della sezione STORIE/IDEE"


curl -ksL "https://www.ilpost.it/" | llm "estrai soltanto i titoli che hanno a che fare con la Palestina"

Voglio testo strutturato

curl -ksL "https://www.ilpost.it/" | llm --schema-multi "titolo,url" "estrai soltanto i titoli che hanno a che fare con la Palestina"

Voglio generare testo strutturato

llm --schema-multi 'nome, citta, indirizzo,posti_a_sedere int' 'crea 5 ristoranti italiani'

Tutti i consiglieri comunali di Palermo

curl -kL "https://www.comune.palermo.it/amministrazione/unita_organizzativa/consiglio-comunale-3/" | \
llm --schema-multi "
nome: il nome del consigliere
ruolo: il ruolo
url: url della pagina del consigliere
sesso: m per maschio f per femmina NA per dubbio o inapplicabile
" --system 'estrai i dati dei consiglieri comunali presenti nella pagina web'

Per estrarre i dati:

llm logs -c --data

Gli schemi usati:

llm schemas

La versione full:

llm schemas --full

Riusare uno schema

curl -skL "https://www.comune.enna.it/amministrazione/unita-organizzativa/2/Consiglio-Comunale" | \
llm --schema ee32c10b164ff80e35f39a58dc32064f --system 'estrai i dati dei consiglieri comunali presenti nella pagina web'

Usare uno schema su un’immagine

llm -t consiglio_comunale -a https://aborruso.github.io/blackboard/html/consiglio_comunale_trento.png

Descriviamo una tabella

Senza frizioni

llm --schema-multi "nome
cognome
eta: inserisci l'età
data_nascita: inserisci la data di nascita in formato YYYY-MM-DD
" "crea una tabella con 5 persone" | jq -c '.items[]' | \
mlr --ijsonl --ocsv cat >persone.csv


llm -f frictionless-tab 'usa queste specifiche per descrivere questo csv' <persone.csv
{
  "profile": "tabular-data-package",
  "name": "people",
  "title": "People Data",
  "description": "A dataset containing information about people, including name, surname, date of birth, and age.",
  "resources": [
    {
      "profile": "tabular-data-resource",
      "name": "people-data",
      "path": "people.csv",
      "format": "csv",
      "mediatype": "text/csv",
      "encoding": "utf-8",
      "schema": {
        "fields": [
          {
            "name": "cognome",
            "title": "Surname",
            "type": "string"
          },
          {
            "name": "data_nascita",
            "title": "Date of Birth",
            "type": "date",
            "format": "YYYY-MM-DD"
          },
          {
            "name": "eta",
            "title": "Age",
            "type": "integer"
          },
          {
            "name": "nome",
            "title": "Name",
            "type": "string"
          }
        ]
      }
    }
  ]
}

Senza frizioni e per le persone

llm -c "e fammi anche la descrizion in markdown, la human readable utile per un readme.md, con una tabellina con nome campo, tipo campo, descrizione e valore di esempio. In italiano."


| Nome Campo     | Tipo Campo | Descrizione                                                                 | Valore di Esempio |
| :------------- | :--------- | :-------------------------------------------------------------------------- | :---------------- |
| `cognome`      | string     | Il cognome della persona.                                                   | Rossi             |
| `data_nascita` | date       | La data di nascita della persona (formato AAAA-MM-GG).                       | 1990-05-15        |
| `eta`          | integer    | L'età della persona.                                                        | 33                |
| `nome`         | string     | Il nome della persona.                                                      | Mario             |

Template

Sono file yaml

system: |
  Estrai gli indirizzi stradali da un testo dato e identifica i seguenti componenti: 1. Tipo di strada, 2. Nome della strada (Odonimo), 3. Numero Civico, 4. Codice di Avviamento Postale (CAP), e 5. Città. Ogni indirizzo estratto deve essere rappresentato come un oggetto JSON separato, in formato JSON Lines (una riga per ogni indirizzo). Includi tutti i componenti disponibili anche se alcuni mancano nel testo originale. Se nel testo sono presenti più strade, estrai una riga per ogni strada trovata.

  # Passaggi

  1. **Identifica i Pattern degli Indirizzi**: Cerca i pattern comuni degli indirizzi nel testo, che possono includere tutti o parte dei componenti.
  2. **Estrai i Componenti**:
     - **Tipo di Strada**: Ad esempio, "Via", "Viale", "Piazza".
     - **Nome della Strada (Odonimo)**: Il nome della strada, ad esempio "Roma".
     - **Numero Civico**: Il numero associato all'edificio, ad esempio "15".
     - **Codice di Avviamento Postale (CAP)**: Il codice postale dell'indirizzo, ad esempio "90100".
     - **Città**: La città associata all'indirizzo, ad esempio "Palermo".
  3. **Genera JSON**: Per ogni indirizzo identificato, crea un oggetto JSON con i componenti estratti.
  4. **Output JSON Lines**: Stampa ogni oggetto JSON su una nuova riga in formato JSON Lines per ciascun indirizzo trovato.

  # Formato di Output

  - Ogni indirizzo identificato deve essere un oggetto JSON con chiavi per ogni componente:
    ```json
    {"street_type": "Tipo di strada", "street_name": "Odonimo", "building_number": "Numero civico", "postal_code": "CAP", "city": "Città"}
    ```
  - Assicurati che ogni oggetto JSON sia stampato su una linea separata.
  - Includi i componenti quando disponibili; ometti o lascia vuote le stringhe per i componenti mancanti.
  - Non scrivere nessun commento, soltanto output jsonline e niente altro

  # Esempi

  **Input:**
  "Trova l'indirizzo Via Roma 15, 90100 Palermo in questo testo e il riferimento a Viale Mazzini."

  **Output:**
  ```
  {"street_type": "Via", "street_name": "Roma", "building_number": "15", "postal_code": "90100", "city": "Palermo"}
  {"street_type": "Viale", "street_name": "Mazzini"}
  ```

  # Note

  - Gestire variazioni nei formati degli indirizzi e informazioni incomplete.
  - L'estrazione deve essere robusta a variazioni comuni e errori nel testo di input.

In action

cat strade.txt

via libertà 12, palermo, 90141
Roma, via torino
Milano 20123
Largo degli abeti, Catania
cat strade.txt | llm "ecco un elenco di strade" -t strade


{"street_type": "via", "street_name": "libertà", "building_number": "12", "postal_code": "90141", "city": "palermo"}
{"street_type": "via", "street_name": "torino", "city": "Roma"}
{"city": "Milano", "postal_code": "20123"}
{"street_type": "Largo", "street_name": "degli abeti", "city": "Catania"}

Applicazioni

Chattare con un video

Usage: qv <YouTube URL> <Question> [-p language <language>] [-sub <filename>] [-t|--template <template>] [--text-only] [--debug]

Example:
  qv.sh 'https://www.youtube.com/watch?v=OM6XIICm_qo' 'What is this video about?'  # Ask a question about the video
  qv.sh 'https://www.youtube.com/watch?v=OM6XIICm_qo' 'What is this about?' -t andy  # Use a specific template
  qv.sh 'https://www.youtube.com/watch?v=OM6XIICm_qo' 'What is this video about?' -p language Italian  # Get the answer in Italian
  qv.sh 'https://www.youtube.com/watch?v=OM6XIICm_qo' --text-only  # Output subtitles to stdout
  qv.sh 'https://www.youtube.com/watch?v=OM6XIICm_qo' 'What is this video about?' -sub subtitles.txt  # Save subtitles to a file

Il codice

    # Build system prompt with improved formatting
    if [ "$debug" = true ]; then
      cat <<EOF > "$temp_file"
You are a helpful assistant that can answer questions about YouTube videos.
${language:+Reply to me in $language\n}
Video title: $title
Content:
${content}
EOF
    else
      cat <<EOF > "$temp_file"
You are a helpful assistant that can answer questions about YouTube videos.
${language:+Reply to me in $language\n}
${content}
EOF
    fi

    # Process the question with LLM using stdin
    echo "Processing your question..."

    if [ "$debug" = true ]; then
      echo -e "\nDEBUG: First 3 lines sent to LLM:"
      head -n 3 "$temp_file"
      echo -e "\n"
    fi

    if [ -n "$template" ]; then
      cat "$temp_file" | llm prompt "$question" -t "$template"
    else
      cat "$temp_file" | llm prompt "$question"
    fi

Grazie 😉

andrea.borruso@ondata.it