Legislația este codul sursă al societății noastre, dar este adesea scrisă într-un mod care este inaccesibil chiar oamenilor pe care îi guvernează. Bills pot fi zeci de pagini lungi, umplute cu legale dense și referințe încrucișate care le fac aproape imposibil de citit la întâmplare. Ce-ar fi dacă aș putea folosi datele pentru a instrui un AI să citească orice factură și să-și scrie propriul rezumat?Aceasta este povestea modului în care am construit un conductor de la capăt la capăt pentru a face exact asta: de la ștergerea datelor, la curățarea dezordinii, la finisarea unui model de limbă puternic. Primul pas a fost de a obține URL-urile pentru fiecare factură care a trecut, împreună cu textul complet și rezumatul oficial. The Basic Toolkit: BeautifulSoup Pentru pagini HTML simple și urllib de Python sunt instrumentele perfecte. Am început prin scrierea unui script (all_house_texas.py) pentru a naviga pe paginile facturilor, pentru a găsi toate legăturile la istoricul facturilor individuale și pentru a extrage informații de bază, cum ar fi autorul și subtitrarea. Partea 1: Scraping un site guvernamental al secolului 20 # From: leg_module_test.py # A simple function to turn a URL into a BeautifulSoup object import urllib.request from bs4 import BeautifulSoup def make_soup(url): thepage = urllib.request.urlopen(url) soupdata = BeautifulSoup(thepage, "lxml") return soupdata website ='https://capitol.texas.gov/BillLookup/History.aspx?LegSess=89R&Bill=SB1' soup = make_soup(website) # Find the author's name by its specific HTML ID for data in soup.findAll('td', id = 'cellAuthors'): print(data.text) Acest lucru a funcționat bine pentru datele inițiale, dar am lovit rapid un perete. Cum să utilizați Selenium pentru JavaScript Cea mai valoroasă bucată de date nu a fost un link standard. a fost ascunsă în spatele unui eveniment de clic pe JavaScript care a deschis o nouă fereastră pop-up. Aceasta este o provocare comună în scraping-ul web modern. Folosind Selenium, script-ul meu ar putea încărca pagina, aștepta ca JavaScript-ul să rendereze și apoi să interacționeze cu butonul la fel ca un om. Selenium Script-ul meu texas_leg_txt_from_list.py a folosit această abordare pentru a obține în cele din urmă URL-ul de rezumat. # From: texas_leg_txt_from_list.py # Using Selenium to find an element and extract its JavaScript-based URL from selenium import webdriver from selenium.webdriver.common.by import By import time # ... (driver setup code) ... driver.get('https://capitol.texas.gov/BillLookup/Text.aspx?LegSess=75R&Bill=HB1') time.sleep(1.5) # Wait for the page to load # Find the summary link by its ID bill_summary_link = driver.find_element(By.ID, 'lnkBillSumm') # Get the 'onclick' attribute, which contains the JavaScript function call onclick_attribute = bill_summary_link.get_attribute('onclick') # A bit of string manipulation to extract the URL from the JavaScript start_index = onclick_attribute.find("('") + 2 end_index = onclick_attribute.find("'", start_index) bill_summary_url = 'https://capitol.texas.gov/BillLookup/' + onclick_attribute[start_index:end_index] print(f"Successfully extracted summary URL: {bill_summary_url}") driver.quit() Cu aceasta, mi-am putut colecta în mod fiabil cele trei bucăți cheie de date pentru mii de facturi: adresa URL a paginii principale, textul complet înscris și textul oficial de rezumat. Partea 2: Echipa de curățare - transformarea haosului HTML în date curate Datele web sunt tulburi. textul răsturnat a fost umplut cu spațiu alb suplimentar, caractere spațiale non-breaking (\xa0), și alte artefacte HTML. Înainte de a putea alimenta acest lucru la un model, a fost nevoie de o curățare serioasă. Scriptul meu start_analysis_0.py a fost dedicat acestui pas crucial. În primul rând, am scris o funcție simplă de curățare folosind regex pentru a standardiza spațiul alb și a elimina caracterele junk. # From: start_analysis_0.py # A function to clean raw text scraped from the web import re def clean_text(text): if not isinstance(text, str): return "" # Handle cases where data might not be a string text = re.sub(r'\s+', ' ', text) # Collapse all whitespace into single spaces text = text.replace('\xa0', ' ') # Remove non-breaking spaces text = text.replace('__','') # ... other replacements ... return text.strip() Apoi, am implementat un control critic al calității. Un rezumat bun ar trebui să fie semnificativ mai scurt decât textul original, dar nu atât de scurt încât să fie inutil. Am decis să păstrez doar perechi în care lungimea rezumatului era între 10% și 100% din lungimea întregii facturi. Această vizualizare a confirmat faptul că majoritatea datelor mele au căzut într-o distribuție sănătoasă, validând logica mea de filtrare. Partea 3: Fine-Tuning un model T5 Acum, pentru partea distractivă. am ales să folosesc un transformator puternic și versatil de transfer text-to-text. T5 este excelent pentru instruirea următoarelor sarcini. Prin prependarea textului cu rezumat, am putut Pipe-ul meu de instruire a fost construit în start_analysis_1.py și start_analysis_2.py folosind transformatoarele Hugging Face și bibliotecile TensorFlow. Modelul T5 mic Învață modelul Procesul de bază arată astfel: Tokenizarea: Acest pas convertește textul în ID-uri numerice pe care modelul le poate înțelege. am creat o funcție de pre-procesare pentru a gestiona acest lucru atât pentru textul facturii (intrarea) cât și pentru rezumat (eticheta țintă). # From: start_analysis_1.py # This function tokenizes the text and prepares it for the model from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained('t5-small') prefix = "summarize: " def preprocess_function(examples): # Prepare the input text with the "summarize: " prefix inputs = [prefix + doc for doc in examples["source_text"]] model_inputs = tokenizer(inputs, max_length=512, truncation=True) # Tokenize the target summaries with tokenizer.as_target_tokenizer(): labels = tokenizer(examples["target_text"], max_length=128, truncation=True) model_inputs["labels"] = labels["input_ids"] return model_inputs Încărcarea datelor: Am încărcat JSON curățat într-un obiect Hugging Face Dataset și am aplicat tokenizarea. Formare: În cele din urmă, am configurat modelul, am setat un optimizator și am pornit procesul de formare cu model.fit(). Aici se întâmplă magia. Modelul iterează prin date, face predicții, le compară cu rezumatele oficiale și își ajustează ponderile interne pentru a deveni mai bine și mai bine. # From: start_analysis_1.py # The final training call in TensorFlow import tensorflow as tf from transformers import TFAutoModelForSeq2SeqLM, AdamWeightDecay # ... (dataset and data_collator setup) ... optimizer = AdamWeightDecay(learning_rate=2e-5, weight_decay_rate=0.01) model = TFAutoModelForSeq2SeqLM.from_pretrained("t5-small") model.compile(optimizer=optimizer) # Let's train! model.fit( x=tf_train_set, validation_data=tf_test_set, epochs=3 ) # Save the fine-tuned model for later use model.save_pretrained("./t5_small_texas_bills") Partea 4: Verdictul - A funcționat? După ore de antrenament, a venit momentul adevărului. am hrănit modelul cu o factură pe care nu o văzuse niciodată înainte pentru a vedea ce va produce. Iată un exemplu: ** Textul original al proiectului de lege (Snippet): "...UN ACT referitor la prevenirea unei reduceri a limitării cuantumului total al impozitelor ad valorem care pot fi impuse de un district școlar asupra locuințelor de reședință ale persoanelor în vârstă sau ale persoanelor cu handicap pentru a reflecta orice reducere a ratei impozitului districtului școlar și pentru a proteja un district școlar împotriva oricărei pierderi a veniturilor locale care rezultă..." ** Textul original al proiectului de lege (Snippet): "...UN ACT referitor la prevenirea unei reduceri a limitării cuantumului total al impozitelor ad valorem care pot fi impuse de un district școlar asupra locuințelor de reședință ale persoanelor în vârstă sau ale persoanelor cu handicap pentru a reflecta orice reducere a ratei impozitului districtului școlar și pentru a proteja un district școlar împotriva oricărei pierderi a veniturilor locale care rezultă..." **Rezumat oficial (Adevărul de teren): \ "Această lege reduce limitarea impozitelor ad valorem pe districtul școlar pentru proprietarii de case în vârstă sau cu handicap pentru a reflecta reducerile ratelor de impozitare. se asigură că districtele școlare sunt compensate pentru orice pierdere de venit rezultată. **Rezumat oficial (Adevărul de teren): \ "Această lege reduce limitarea impozitelor ad valorem pe districtul școlar pentru proprietarii de case în vârstă sau cu handicap pentru a reflecta reducerile ratelor de impozitare. se asigură că districtele școlare sunt compensate pentru orice pierdere de venit rezultată. **I-Generated Summary: "Legea se referă la o reducere a limitării cuantumului total al impozitelor ad valorem care pot fi impuse de un district școlar pe casele de reședință ale persoanelor în vârstă sau cu handicap. **I-Generated Summary: "Legea se referă la o reducere a limitării cuantumului total al impozitelor ad valorem care pot fi impuse de un district școlar pe casele de reședință ale persoanelor în vârstă sau cu handicap. Analiza: Modelul a identificat corect subiectele principale (impozite ad valorem, districte școlare, adăposturi pentru vârstnici / persoane cu handicap) și acțiunea de bază (reducerea limitelor fiscale). Deși nu este la fel de elocvent ca rezumatul uman, este precis și captează esența contului perfect. Modelul a identificat corect subiectele principale (taxe ad valorem, districte școlare, adăposturi pentru vârstnici / persoane cu handicap) și acțiunea de bază (reducerea limitelor fiscale). Deși nu este la fel de elocventă ca rezumatul uman, este exactă și captează esența contului perfect. Analysis: Concluzie Acest proiect a fost o reamintire puternică că cele mai influente aplicații AI se bazează adesea pe o fundație de inginerie a datelor. construirea modelului a fost ultimul 20% din muncă; primul 80% a fost procesul dureros de achiziționare și curățare a datelor. Modelul final nu este perfect, dar este o dovadă puternică a conceptului. demonstrează că putem folosi inteligența artificială modernă pentru a face informațiile cetățenești complexe mai accesibile pentru toată lumea. What's next? Implementarea ca API: transformați acest lucru într-un serviciu public unde oricine poate trimite textul unei facturi și poate obține un rezumat. Crearea unui bot: Pentru a posta rezumate ale facturilor depuse recent. Extinderea în alte state: Fiecare legislatură are aceeași problemă. Dacă sunteți un dezvoltator, vă încurajez să vă uitați la propriile date ale guvernului local.Ați putea găsi o oportunitate similară de a construi ceva care nu numai că vă îmbunătățește abilitățile, ci și vă servește comunității.