Belekezdtem a régóta halogatott projectembe - a Cursor AI Code Editor segítségével

Gondolom sokan tudjátok, hogy szeretek a szavak etimológiájával foglalkozni. Ez egy (számomra) érdekes elfoglaltság, és remélem, hogy talán egy picit sikerül előremozdítanom ezt a területet. Eddig a szavak eredetét a wiktionary.org-on kutattam, és elég jól használható, de egy valami nagyon hiányzik.

A vizualizáció.

A szavak eredete tökéletes, ha az ember gráfokkal akar foglalkozni.

És én szeretem nem csak a szavak eredetét, hanem a gráfokat is.

De ebben a postban nem erről, hanem az AI-segített programozásról szeretnék inkább írni.

Kb. egy hete elkezdtem használgatni a Cursor-t, ami egy VSCode alapú, integrált AI-jal rendelkező IDE. Claude 3.5 Sonnet-et használok, az X felhasználók elsöprő többsége szerint jelenleg a legjobb LLM programozáshoz.

Ahhoz, hogy elkezdhessem végre a projectet, az első feladatok, amiket meg kellett oldani:

  • az adat beszerzése
  • értelmezése
  • SQLite adatbázis schema létrehozása
  • script írása az adatbázis feltöltésére
  • build script létrehozása ezek kezelésére

Az adatot a wikimediáról linkelt kaikki.org-ról szereztem be (raw Wiktextract data (JSONL, one object per line)).

Ugyan, ez egy hatalmas file, de mivel egy JSON object - egy sor, így talán tesztelésre jobb, illetve egyszerűbb az AI számára is megérteni a struktúráját egy kis objectnek, mint a hatalmas egésznek.

Le kell szögeznem, hogy az eddig elvégzett munka során egy sor programkódot nem írtam. De még az elején vagyunk, szóval biztos lesz, ahol kézzel bele kell nyúlnom.

Szóval megkértem Claude-ot, hogy írjon egy script-et, ami a JSONL file tetszőleges sorát kiírja.

import json
import sys

def extract_line(file_path, line_number):
    try:
        with open(file_path, 'r') as file:
            # Skip to the desired line
            for _ in range(line_number - 1):
                file.readline()
            # Read the desired line
            line = file.readline().strip()
            
        # Parse the JSON line
        json_object = json.loads(line)
        
        # Print the parsed JSON object
        print(json.dumps(json_object, indent=2))
    except FileNotFoundError:
        print(f"Error: The file '{file_path}' was not found.")
    except json.JSONDecodeError:
        print(f"Error: The line {line_number} is not valid JSON.")
    except Exception as e:
        print(f"An error occurred: {str(e)}")

# Check if correct number of arguments are provided
if len(sys.argv) != 3:
    print("Usage: python script.py <file_path> <line_number>")
    sys.exit(1)

# Get file path and line number from command line arguments
file_path = sys.argv[1]
line_number = int(sys.argv[2])

extract_line(file_path, line_number)

Ezzel felvértezve, kiírattam pár sort a nagy JSONL file-ból, ezeket elmentettem.

~/wikidata on  main! ⌚ 15:07:29
$ python3 extract-jsonl.py raw-wiktextract-data.jsonl 100 >> 100.json

Manuálisan lekérdeztem 6 különböző sort, és ezeket a JSON file-okat feltöltöttem Claude-nak, mondván, hogy találja meg a kötelező és az opcionális mezőket.

> These files are from the same dataset. Identify the mandatory and optional fields

Analysis of JSON Fields in Dataset

Mandatory Fields

These fields appear in all provided JSON files:

  1. senses: An array containing detailed information about word meanings
  2. pos: Part of speech
  3. head_templates: Contains information about the word's grammatical form
  4. categories: List of categories the word belongs to
  5. etymology_text: Text describing the word's etymology

    ...

 

Ezt a választ elmentettem a Claude Project Knowledge-be és megkértem Claude-ot, hogy ezt használva készítsen egy SQLite schemát.

> Based on the "Analysis of JSON Fields", create a SQLite schema to store the data found in the JSON file in the database

-- Main table for words
CREATE TABLE words (
    id INTEGER PRIMARY KEY,
    word TEXT NOT NULL,
    lang TEXT NOT NULL,
    lang_code TEXT NOT NULL,
    pos TEXT,
    etymology_text TEXT
);

-- Table for word forms
CREATE TABLE forms (
    id INTEGER PRIMARY KEY,
    word_id INTEGER,
    form TEXT NOT NULL,
    FOREIGN KEY (word_id) REFERENCES words (id)
);

-- Table for sounds (pronunciations)
CREATE TABLE sounds (
    id INTEGER PRIMARY KEY,
    word_id INTEGER,
    ipa TEXT,
    audio_file TEXT,
    FOREIGN KEY (word_id) REFERENCES words (id)
);

...

Ezek után megkértem, hogy készítsen egy Python scriptet, ami:

Based on the SQLite schema you've created, create a Python script that creates a SQLite database based on the schema. The schema is stored in another file, defined in the source code. The Python script then reads a JSONL file (where one line is one JSON object), and dumps the data into the database. Make the start and end line number indicator configurable

import json
import sqlite3
import argparse
from pathlib import Path

def create_database(db_path, schema_path):
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()

    with open(schema_path, 'r') as schema_file:
        schema_script = schema_file.read()
        cursor.executescript(schema_script)

    conn.commit()
    return conn, cursor

def insert_word(cursor, word_data):
    cursor.execute('''
        INSERT INTO words (word, lang, lang_code, pos, etymology_text)
        VALUES (?, ?, ?, ?, ?)
    ''', (
        word_data['word'],
        word_data['lang'],
        word_data['lang_code'],
        word_data.get('pos'),
        word_data.get('etymology_text')
    ))
    return cursor.lastrowid


...

---------------

Már csak a build script generálása van hátra, de azt kifejtem egy másik postban/kommentben.

Jelenleg, amikor fel akarom tölteni az adatbázist a build script segítségével (az működik rendesen), akkor ilyen error-t kapok:

Unexpected error on line 2: Error binding parameter 1 - probably unsupported type.
Unexpected error on line 3: 'list' object has no attribute 'get'
Unexpected error on line 4: 'list' object has no attribute 'get'
Unexpected error on line 5: Error binding parameter 1 - probably unsupported type.
Unexpected error on line 6: 'list' object has no attribute 'get'

Szóval nem tökéletes a megoldás. De jelenleg itt tartok, szóval megyek is megkérni Claude-ot, hogy debugolja már meg a kódot, amit generált :)

Hozzászólások

Egy dolog eléggé zavaró mondjuk.

Ha Claude-dal dolgozok, akkor a web-es felületen lehetőség van Projecteket létrehozni, hogy a chat-ek együtt legyenek a kontextus miatt (embernek és AI-nak is), fel lehet tölteni dokumentumokat, stb.

Viszont Cursor-ral használva a Claude API sajnos nem tud ezekről, szóval egyelőre manuálisan szinkronban kell majd valahogy tartani őket.

Update: úgy látszik, hogy a bug megoldásra került:

I get errors which say:

Unexpected error on line 2: Error binding parameter 1 - probably unsupported type. Unexpected error on line 3: 'list' object has no attribute 'get' Unexpected error on line 4: 'list' object has no attribute 'get' Unexpected error on line 5: Error binding parameter 1 - probably unsupported type. Unexpected error on line 6: 'list' object has no attribute 'get'

-----

is it because of some bug in the code, or do we need to analyse the JSON structure a bit more?

>>>>>>

I apologize for the oversight. These errors suggest that the JSON structure in your file is different from what we initially assumed. It appears that some lines contain lists instead of dictionaries, which is causing the errors. Let's analyze the JSON structure more closely and update our code accordingly.

First, let's modify our script to print out the problematic JSON lines so we can see what we're dealing with. Here's an updated version of the process_jsonl function:

...

Mivel ehhez a kérdéshez a Claude webUI-t használtam, ezért be kellett másolnom az updatelt process_jsonl függvényt. Ez Cursor-ral használva nem szükséges, helyben módosítja a kódot.

Ha már etimológia, nekem most esett le, amikor előkerült a "Numa-numa jéj" retro zene, hogy a román "hajduk", mint törvényen kívüli/utonálló jöhetett a magyar hajdú elnevezés.

Saying a programming language is good because it works on all platforms is like saying anal sex is good because it works on all genders....

en magyarul a Hajdút max. bojlerral asszocialtam, ertsd nem gondoltam mögé jelentést.

Egy gyors interju a kornyezetemben, és mas se tudta a jelentését .

Saying a programming language is good because it works on all platforms is like saying anal sex is good because it works on all genders....

TL;DR marhákat tereltek ezek a derék emberek, vagyis hajtók voltak eredetileg.

[Már ne sima pásztorokra gondoljunk, hanem olyanokra, akik többszáz kilométeren át terelték a gulyákat hogy jó áron adhassák el a jószágot, közben esetleg rablókkal is találkozhattak, szóval lehetett harci szakértelmük is.]

Szerkesztve: 2024. 08. 25., v – 10:47

A Czuczor-Fogarasi szótár szóbokrokat lát a magyar nyelvben. Azaz a szavaknak van egy szinte egy szótagos töve, amiből jelentéshalmazok származnak.
Persze bezavar egy csomó az elmúlt néhány száz évben jött / nyelvújításkor keletkezett szó. Bár pl. a vonat is beleillik ebbe a képbe, hiába később keletkezett: von szótő, vonó, vontat, vontatott, vonakodás, vonaglás, vonalzó, vonás, vonszol, vonz, vonzó ...

Nem tudom mennyire igaz, vagy csak véletlen egybeesések, de érdemes lehet ebbe az irányba is vizsgálódni.

CzF-et is érdemes lenne feldolgozni, és talán már a szerzői jog is lejárt rajta, szóval jogilag nem lenne probléma vele, de sajnos ahhoz nincs olyan dataset, mint ami a wiktionary-hoz elérhető. Így meg baromi sok idő lenne parse-olni a dokumentumot, aztán osztályozni az adatokat, minőségellenőrzés stb.

Egyszer, ha lesz rá időm, akkor valószínüleg megcsinálom majd, de egyelőre legyen egy működő megoldás, extra adatokat ráérünk később is hozzáadni :)

Amúgy az elmúlt 2 és fél napban (a kezdetektől, csak egy 11Gb-os JSONL file-ból kiindulva) eljutottam odáig, hogy az adatok SQLite adatbázisba vannak töltve, és tudok szavakra keresni, a query meg visszaadja az etimológiáját. Egyelőre egy Python scriptet használok erre, az appot még nem kezdtem el. Generáltattam az AI-val adatbázis diagramot, README-t, ilyen-olyan scripteket.

Brutál, hogy mennyire meggyorsítja az LLM a fejlesztést.

És nem is feltétlenül a kódgenerálás gyorsasága a fontos, hanem az, hogy mentálisan nem terhelődök le az "ezt kéne csinálni, valami nem jó, debugoljunk, na mostmár jó, hol is tartottam??" folyamat által. Sokkal egyszerűbb diff-eket értelmezni, mint állandóan context-switch-csel, random programnyelveken íródott kódbázisokban bug-ot vadászni. 

Ez a probléma a Czuczorral:

(...)

Minthogy a szék szó önhangzója hosszú, bizonyossággal állíthatjuk, hogy az két önhangzóból húzatott egybe sze-ek vagy sza-ek, és így a gyök sze vagy sza azonos azon sza gyökkel, mely száll szónak is elemét alkotja. Innen székeredeti értelme szállás, megszállás, a hol megszállunk, megülepedünk, megtelepedünk. De ugyancsak eredeti értelménél fogva jelent emelkedést (felszállást), emelkedett helyet is. Idegen nyelvekben egyezik vele közelebbről a török szeki (lieu un peu élevé pour s’ asseoir; banc, estrade), persa szaku v. szóku (sedile seu scumnum), mongol szago-khu (s’ asseoir, demeurer), honnan: szaghodal v. szagholta v. szaghori (siège, demeure, domicile), továbbá szintén a mongol szeöke (chaise à porteurs, Sänfte), arab szeken (szék, székhely, domicil, habitation); távolabbról a latin: sca-mnum és török iszkemle törzse. Különösen a latin scamnum-ot a nyelvészek scando (= hágok, fel- vagy leszállok) igéből származtatják. De egyezik vele gyökben a latin sedes, sedeo, sella, solium, német sitzen, Sessel, szláv szedim, szedlo, szelo, franczia seoir, asseoir, siége stb. is.

link

Ezt kéne valahogy értelmesen parse-olni.

Ezzel szemben a wiktionary JSONL ilyen JSON objectekkel rendelkezik (AI-jal generálva):

https://imgur.com/a/4dH7Yfa

A mandatory-common-optional osztályozást is egy LLM végezte, miután adtam neki vagy 10 JSON objectet teszt példaként.