Skip to content

Commit 42a9e3b

Browse files
committed
Release v1.7.0: Ricerca AI con Exa - Performance e Semplicità
- Sostituzione Gemini CLI con Exa AI API per ricerca documenti legali - Configurazione semplificata con variabile d'ambiente EXA_API_KEY - Performance significativamente migliorate - Test completi e documentazione aggiornata
1 parent f987e0f commit 42a9e3b

11 files changed

Lines changed: 243 additions & 90 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,5 @@ legge_*.md
3535
# Build artifacts
3636
akoma2md.egg-info/
3737
build/
38-
dist/
38+
dist/
39+
.env

LOG.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,68 @@
22

33
Questo file documenta gli avanzamenti significativi e le decisioni chiave del progetto `normattiva_2_md`.
44

5+
## 2025-11-03
6+
7+
### 🚀 Release v1.7.0: Ricerca AI con Exa - Performance e Semplicità
8+
9+
**Maggiore velocità e semplicità:** Sostituzione infrastruttura ricerca da Gemini CLI a Exa AI API con prestazioni significativamente migliorate
10+
11+
#### ✨ Nuove Funzionalità Principali
12+
- **Exa AI Integration**: Passaggio da Gemini CLI a Exa AI API per ricerca intelligente documenti legali
13+
- **Configurazione Semplificata**: Solo variabile d'ambiente `EXA_API_KEY` invece di installazione CLI esterna
14+
- **Ricerca Ottimizzata**: Utilizzo `includeDomains: ["normattiva.it"]` per ricerche mirate e precise
15+
- **Performance Migliorata**: Risposte più veloci grazie alla specializzazione di Exa per web search
16+
17+
#### 🔧 Miglioramenti Tecnici
18+
- **API Moderna**: Integrazione diretta con Exa AI API invece di subprocess CLI
19+
- **Gestione Errori**: Timeout 30s, validazione HTTP status, parsing JSON robusto
20+
- **Sicurezza**: API key protetta in file `.env` (già nel `.gitignore`)
21+
- **Codice Pulito**: Refactoring completo di `lookup_normattiva_url()` senza dipendenze esterne
22+
23+
#### 🧪 Testing e Qualità
24+
- **Test End-to-End**: Validazione con ricerche reali ("legge stanca", "decreto dignità", "costituzione italiana")
25+
- **Suite Completa**: Tutti test unitari aggiornati per mockare Exa API
26+
- **Conversione Verificata**: XML→Markdown con front matter e struttura gerarchica corretta
27+
- **Retrocompatibilità**: Mantenuta interfaccia CLI esistente (`--search/-s`)
28+
29+
#### 📦 Distribuzione
30+
- **Versione**: 1.7.0 con changelog completo
31+
- **PyPI**: Pubblicazione automatica su Python Package Index
32+
- **GitHub Releases**: Binari standalone per Linux e Windows
33+
- **Documentazione**: README aggiornato con istruzioni Exa AI
34+
35+
## 2025-11-03
36+
37+
### 🔄 Sostituzione Gemini con Exa per Ricerca AI
38+
39+
**Cambio infrastruttura ricerca:** Passaggio da Gemini CLI a Exa AI API per funzionalità di ricerca naturale documenti legali
40+
41+
#### ✅ Modifiche Implementate
42+
- **Sostituzione API**: Rimpiazzato Gemini CLI con Exa AI API per ricerca intelligente
43+
- **Configurazione semplificata**: Passaggio da installazione CLI esterna a variabile d'ambiente EXA_API_KEY
44+
- **Ricerca ottimizzata**: Utilizzo `includeDomains` per limitare ricerca esclusivamente a normattiva.it
45+
- **Codice aggiornato**: Refactoring completo funzione `lookup_normattiva_url()` con gestione errori migliorata
46+
- **Test aggiornati**: Tutti test di regressione modificati per mockare Exa API invece di Gemini CLI
47+
48+
#### 🔧 Dettagli Tecnici
49+
- **Endpoint API**: `https://api.exa.ai/search` con parametri ottimizzati per ricerca legale
50+
- **Query format**: `{search_query} site:normattiva.it` per precisione risultati
51+
- **Gestione errori**: Timeout 30s, validazione HTTP status, parsing JSON robusto
52+
- **Compatibilità**: Mantenuta interfaccia CLI esistente (`--search/-s`)
53+
54+
#### 🧪 Testing e Validazione
55+
- **Test end-to-end**: Ricerca "legge stanca" → Decreto Legislativo 4/2004 ✅
56+
- **Test multipli**: Ricerca "decreto dignità" → Decreto-legge 87/2018 ✅
57+
- **Test costituzione**: Ricerca "costituzione italiana" → Costituzione 1947 ✅
58+
- **Conversione completa**: XML→Markdown con front matter e struttura gerarchica corretta
59+
- **Suite test**: Tutti test unitari passano senza regressioni
60+
61+
#### 📦 Impatto
62+
- **Dipendenze**: Rimossa necessità installazione Gemini CLI, aggiunta configurazione API key
63+
- **Performance**: Risposta più veloce con ricerca domain-specific
64+
- **Manutenibilità**: Codice più semplice senza gestione subprocess esterni
65+
- **Sicurezza**: API key protetta in file .env (già nel .gitignore)
66+
567
## 2025-11-05
668

769
### 🚀 Rilascio Versione 1.6.1

README.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Convertire le norme legali da XML Akoma Ntoso a Markdown offre vantaggi signific
2828
-**CLI flessibile** con argomenti posizionali e nominati
2929
-**Gestione errori robusta** con messaggi informativi
3030
-**Nessuna dipendenza esterna** per conversione XML→Markdown (solo librerie standard Python)
31-
-**Ricerca per nome naturale** richiede [Gemini CLI](https://github.com/google-gemini/gemini-cli) per l'integrazione AI
31+
-**Ricerca per nome naturale** richiede [Exa AI API](https://exa.ai) per l'integrazione AI
3232

3333
## 📦 Installazione
3434

@@ -47,16 +47,16 @@ pip install akoma2md
4747
akoma2md input.xml output.md
4848
```
4949

50-
### Installazione Gemini CLI (Opzionale - per ricerca per nome)
50+
### Configurazione Exa AI API (Opzionale - per ricerca per nome)
5151

52-
Per utilizzare la funzionalità di ricerca per nome naturale (`--search`), è necessario installare [Gemini CLI](https://github.com/google-gemini/gemini-cli):
52+
Per utilizzare la funzionalità di ricerca per nome naturale (`--search`), è necessario configurare una [API key di Exa AI](https://exa.ai):
5353

5454
```bash
55-
# Installazione globale
56-
npm install -g @google/gemini-cli
55+
# Configura la variabile d'ambiente con la tua API key
56+
export EXA_API_KEY='your-exa-api-key-here'
5757

58-
# Verifica installazione
59-
gemini --help
58+
# Verifica che sia configurata
59+
echo $EXA_API_KEY
6060
```
6161

6262
### Installazione da sorgenti
@@ -114,11 +114,11 @@ akoma2md -i input.xml -o output.md
114114
akoma2md --input input.xml --output output.md
115115
```
116116

117-
### Metodo 3: Ricerca per nome naturale (con Gemini CLI)
117+
### Metodo 3: Ricerca per nome naturale (con Exa AI)
118118

119-
**⚠️ Richiede Gemini CLI installato e configurato**
119+
**⚠️ Richiede API key Exa AI configurata**
120120

121-
Prima di utilizzare questa funzionalità, assicurati di aver installato e configurato [Gemini CLI](#installazione-gemini-cli-opzionale---per-ricerca-per-nome).
121+
Prima di utilizzare questa funzionalità, assicurati di aver configurato l'[API key di Exa AI](#configurazione-exa-ai-api-opzionale---per-ricerca-per-nome).
122122

123123
**Importante**: Per la ricerca in linguaggio naturale devi **sempre usare il flag `-s` o `--search`**:
124124

@@ -141,7 +141,7 @@ akoma2md decreto_82_2005.xml codice_amministrazione_digitale.md
141141
# Con percorsi assoluti
142142
akoma2md /percorso/documento.xml /percorso/output.md
143143

144-
# Ricerca per nome naturale (richiede Gemini CLI - usa SEMPRE -s)
144+
# Ricerca per nome naturale (richiede Exa AI API - usa SEMPRE -s)
145145
akoma2md -s "legge stanca" legge_stanca.md
146146
akoma2md -s "decreto dignità" > decreto.md
147147

@@ -167,7 +167,7 @@ opzioni:
167167
-o OUTPUT, --output OUTPUT
168168
File Markdown di output
169169
-s SEARCH, --search SEARCH
170-
Cerca documento per nome naturale (richiede Gemini CLI)
170+
Cerca documento per nome naturale (richiede Exa AI API)
171171
172172
argomenti posizionali:
173173
input File XML locale o URL normattiva.it
@@ -255,7 +255,7 @@ dataVigenza: 20251101
255255

256256
- Python 3.7+
257257
- Nessuna dipendenza esterna per conversione XML→Markdown (solo librerie standard Python)
258-
- [Gemini CLI](https://github.com/google-gemini/gemini-cli) per funzionalità ricerca per nome naturale
258+
- [Exa AI API](https://exa.ai) per funzionalità ricerca per nome naturale
259259

260260
### Configurazione dell'ambiente di sviluppo
261261

convert_akomantoso.py

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -977,69 +977,76 @@ def process_article(article_element, markdown_content_list, ns, level=2):
977977

978978
def lookup_normattiva_url(search_query):
979979
"""
980-
Usa Gemini CLI per cercare l'URL normattiva.it corrispondente alla query di ricerca.
980+
Usa Exa AI API per cercare l'URL normattiva.it corrispondente alla query di ricerca.
981981
982982
Args:
983983
search_query (str): La stringa di ricerca naturale (es. "legge stanca")
984984
985985
Returns:
986986
str or None: L'URL trovato, oppure None se non trovato o errore
987987
"""
988-
import subprocess
989-
import re
988+
import os
990989
import json
991990

992-
# Prompt semplificato per Gemini CLI
993-
prompt = f"""Cerca su normattiva.it l'URL della "{search_query}" e restituisci solo l'URL completo che inizia con https://www.normattiva.it/"""
994-
995991
try:
996-
# Verifica che gemini sia disponibile
997-
import shutil
998-
gemini_path = shutil.which('gemini')
999-
if not gemini_path:
1000-
print("❌ Gemini CLI non trovato nel PATH. Installalo con: npm install -g @google/gemini-cli", file=sys.stderr)
1001-
print(" Per istruzioni: https://github.com/google/gemini-cli", file=sys.stderr)
992+
# Verifica che l'API key di Exa sia configurata
993+
exa_api_key = os.getenv('EXA_API_KEY')
994+
if not exa_api_key:
995+
print("❌ EXA_API_KEY non trovata nelle variabili d'ambiente", file=sys.stderr)
996+
print(" Configura la variabile: export EXA_API_KEY='your-api-key'", file=sys.stderr)
997+
print(" Registrati su: https://exa.ai", file=sys.stderr)
1002998
return None
1003999

1004-
# Chiama Gemini CLI con il prompt via stdin e output JSON
1005-
result = subprocess.run(
1006-
[gemini_path, '--output-format', 'json'],
1007-
input=prompt,
1008-
capture_output=True,
1009-
text=True,
1010-
timeout=60 # Aumentato il timeout per ricerche più complesse
1011-
)
1000+
# Prepara la richiesta per Exa API
1001+
url = "https://api.exa.ai/search"
1002+
headers = {
1003+
"x-api-key": exa_api_key,
1004+
"Content-Type": "application/json"
1005+
}
1006+
1007+
# Query ottimizzata per cercare su normattiva.it
1008+
payload = {
1009+
"query": f"{search_query} site:normattiva.it",
1010+
"includeDomains": ["normattiva.it"],
1011+
"numResults": 5,
1012+
"type": "auto"
1013+
}
1014+
1015+
# Effettua la chiamata API
1016+
response = requests.post(url, headers=headers, json=payload, timeout=30)
10121017

1013-
if result.returncode != 0:
1014-
print(f"❌ Errore Gemini CLI: {result.stderr}", file=sys.stderr)
1018+
if response.status_code != 200:
1019+
print(f"❌ Errore Exa API (HTTP {response.status_code}): {response.text}", file=sys.stderr)
10151020
return None
10161021

10171022
# Parse JSON response
10181023
try:
1019-
json_response = json.loads(result.stdout.strip())
1020-
response_text = json_response.get('response', '').strip()
1024+
data = response.json()
10211025
except json.JSONDecodeError as e:
1022-
print(f"❌ Errore nel parsing JSON da Gemini CLI: {e}", file=sys.stderr)
1026+
print(f"❌ Errore nel parsing JSON da Exa API: {e}", file=sys.stderr)
10231027
return None
10241028

1025-
# Cerca URL normattiva.it nella risposta
1026-
url_pattern = r'https://www\.normattiva\.it/[^\s]+'
1027-
match = re.search(url_pattern, response_text)
1029+
# Estrai risultati
1030+
results = data.get('results', [])
1031+
if not results:
1032+
print(f"❌ Nessun risultato trovato per: {search_query}", file=sys.stderr)
1033+
return None
10281034

1029-
if match:
1030-
url = match.group(0)
1031-
# Valida che sia un URL normattiva valido
1032-
if is_normattiva_url(url):
1035+
# Prendi il primo risultato valido
1036+
for result in results:
1037+
url = result.get('url')
1038+
if url and is_normattiva_url(url):
1039+
print(f"✅ URL trovato: {url}", file=sys.stderr)
10331040
return url
1034-
else:
1035-
print(f"❌ URL trovato non è valido per normattiva.it: {url}", file=sys.stderr)
1036-
return None
1037-
else:
1038-
print(f"❌ Nessun URL normattiva.it trovato nella risposta di Gemini", file=sys.stderr)
1039-
return None
10401041

1041-
except subprocess.TimeoutExpired:
1042-
print("❌ Timeout nella chiamata a Gemini CLI", file=sys.stderr)
1042+
print(f"❌ Nessun URL normattiva.it valido trovato nei risultati", file=sys.stderr)
1043+
return None
1044+
1045+
except requests.exceptions.Timeout:
1046+
print("❌ Timeout nella chiamata a Exa API", file=sys.stderr)
1047+
return None
1048+
except requests.exceptions.RequestException as e:
1049+
print(f"❌ Errore di connessione a Exa API: {e}", file=sys.stderr)
10431050
return None
10441051
except Exception as e:
10451052
print(f"❌ Errore nella ricerca URL: {e}", file=sys.stderr)
@@ -1079,7 +1086,7 @@ def main():
10791086
python convert_akomantoso.py "https://www.normattiva.it/uri-res/N2Ls?urn:nir:stato:decreto-legge:2018-07-12;87~art3" --completo output.md
10801087
python convert_akomantoso.py -c "https://www.normattiva.it/uri-res/N2Ls?urn:nir:stato:legge:2022;53~art16bis" output.md
10811088
1082-
# Ricerca per nome naturale (richiede Gemini CLI)
1089+
# Ricerca per nome naturale (richiede Exa API key)
10831090
python convert_akomantoso.py -s "legge stanca" output.md
10841091
python convert_akomantoso.py --search "decreto dignità" > output.md
10851092
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
## Why
2+
The current implementation uses Gemini CLI for natural language search of legal documents. While functional, switching to Exa AI would provide better search capabilities specifically designed for web search and research tasks. Exa offers more comprehensive and accurate results for finding legal documents on normattiva.it.
3+
4+
## What Changes
5+
- Replace Gemini CLI integration with Exa AI API
6+
- Update the natural language search functionality to use Exa's search capabilities
7+
- Maintain the same CLI interface and user experience
8+
- **BREAKING**: Changes dependency from Gemini CLI to Exa API
9+
10+
## Impact
11+
- Affected specs: url-lookup capability (modify existing implementation)
12+
- Affected code: lookup_normattiva_url() function and related search logic
13+
- New dependency: Exa API instead of Gemini CLI
14+
- User experience: Same interface, potentially improved search accuracy
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
## MODIFIED Requirements
2+
### Requirement: Natural Language URL Lookup
3+
The system SHALL accept natural language strings describing legal documents and use Exa AI API to find corresponding normattiva.it URLs for conversion.
4+
5+
#### Scenario: Successful URL Resolution
6+
- **WHEN** user provides a natural language string like "legge stanca"
7+
- **THEN** the system SHALL call Exa AI API with appropriate search query
8+
- **AND** extract the found normattiva.it URL
9+
- **AND** proceed with conversion using the resolved URL
10+
11+
#### Scenario: No URL Found
12+
- **WHEN** Exa AI API cannot find a matching URL
13+
- **THEN** the system SHALL display an informative error message
14+
- **AND** exit without attempting conversion
15+
16+
#### Scenario: Exa API Unavailable
17+
- **WHEN** Exa API is not accessible or authentication fails
18+
- **THEN** the system SHALL display configuration guidance
19+
- **AND** exit with appropriate error code
20+
21+
#### Scenario: Multiple URL Matches
22+
- **WHEN** Exa returns multiple potential URLs
23+
- **THEN** the system SHALL use the most relevant match
24+
- **OR** prompt user to choose if interactive mode is available
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## 1. Research and Planning
2+
- [ ] Research Exa AI API documentation and authentication requirements
3+
- [ ] Analyze current Gemini integration in convert_akomantoso.py
4+
- [ ] Determine Exa API integration approach (direct API calls vs CLI)
5+
6+
## 2. Implementation
7+
- [ ] Add Exa API dependency to setup.py/pyproject.toml
8+
- [ ] Create Exa API client module
9+
- [ ] Replace Gemini CLI calls with Exa API calls in lookup_normattiva_url()
10+
- [ ] Update error handling for Exa API responses
11+
- [ ] Test Exa search functionality with sample queries
12+
13+
## 3. Testing and Validation
14+
- [ ] Update unit tests to mock Exa API instead of Gemini CLI
15+
- [ ] Test end-to-end functionality with real Exa API calls
16+
- [ ] Verify search accuracy and URL extraction
17+
- [ ] Ensure backward compatibility with existing CLI interface
18+
19+
## 4. Documentation and Cleanup
20+
- [ ] Update README.md to reflect Exa dependency instead of Gemini
21+
- [ ] Update installation instructions
22+
- [ ] Remove Gemini-specific documentation
23+
- [ ] Update help text and error messages

openspec/specs/url-lookup/spec.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,26 @@
44
TBD - created by archiving change add-natural-language-url-lookup. Update Purpose after archive.
55
## Requirements
66
### Requirement: Natural Language URL Lookup
7-
The system SHALL accept natural language strings describing legal documents and use Gemini CLI to find corresponding normattiva.it URLs for conversion.
7+
The system SHALL accept natural language strings describing legal documents and use Exa AI API to find corresponding normattiva.it URLs for conversion.
88

99
#### Scenario: Successful URL Resolution
1010
- **WHEN** user provides a natural language string like "legge stanca"
11-
- **THEN** the system SHALL call Gemini CLI with appropriate prompt
11+
- **THEN** the system SHALL call Exa AI API with appropriate search query
1212
- **AND** extract the found normattiva.it URL
1313
- **AND** proceed with conversion using the resolved URL
1414

1515
#### Scenario: No URL Found
16-
- **WHEN** Gemini CLI cannot find a matching URL
16+
- **WHEN** Exa AI API cannot find a matching URL
1717
- **THEN** the system SHALL display an informative error message
1818
- **AND** exit without attempting conversion
1919

20-
#### Scenario: Gemini CLI Unavailable
21-
- **WHEN** Gemini CLI is not installed or accessible
22-
- **THEN** the system SHALL display installation guidance
20+
#### Scenario: Exa API Unavailable
21+
- **WHEN** Exa API is not accessible or authentication fails
22+
- **THEN** the system SHALL display configuration guidance
2323
- **AND** exit with appropriate error code
2424

2525
#### Scenario: Multiple URL Matches
26-
- **WHEN** Gemini returns multiple potential URLs
26+
- **WHEN** Exa returns multiple potential URLs
2727
- **THEN** the system SHALL use the most relevant match
2828
- **OR** prompt user to choose if interactive mode is available
2929

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "akoma2md"
7-
version = "1.6.1"
7+
version = "1.7.0"
88
description = "Convertitore da XML Akoma Ntoso a formato Markdown con supporto URL articolo-specifici e ricerca AI"
99
readme = "README.md"
1010
requires-python = ">=3.7"

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def read_readme():
1616

1717
setup(
1818
name="akoma2md",
19-
version="1.5.0",
19+
version="1.7.0",
2020
description="Convertitore da XML Akoma Ntoso a formato Markdown con supporto URL normattiva.it",
2121
long_description=read_readme(),
2222
long_description_content_type="text/markdown",

0 commit comments

Comments
 (0)