Cum identificăm articolele relevante în domeniile noastre? Acest proiect folosește exemple de fluxuri de jurnal RSS cu rezumate, folosește LLMS pentru a extrage puncte de interes și împărtășește informații despre curiozitatea Bluesky – stimulând.
Motivații
Există nenumărate articole excelente publicate zilnic, dar cum identificăm care sunt relevante pentru domeniile noastre? Cum putem extrage esența unui articol – în mod specific, abstractul său? Să construim ceva care să folosească Bluesky ca forum pentru a stimula curiozitatea și învățarea.
Planul este de a folosi fluxurile RSS furnizate de jurnale (care sperăm să includă rezumate) și apoi să folosească aceste rezumate cu un LLM pentru a surprinde esența. Acest lucru ar putea declanșa curiozitatea în mai multe moduri: poate ceva pare neobișnuit sau intrigant, ceea ce ne determină să verificăm dacă LLM a interpretat -o corect. Poate că am citit deja rezumatul și articolul, dar LLM a identificat ceva ce ne -a lipsit.
În urma rezumatului generației sumare 🤣, cum putem folosi Bluesky ca platformă pentru a împărtăși aceste informații? Vom explora cum să implementăm toate aceste capacități în R.
Obiective:
Obțineți ID RSS Feed
library(tidyverse) library(tidyRSS) url <- "https://academic.oup.com/rss/site_5269/3135.xml" (df <- tidyfeed(url)) ## # A tibble: 46 × 13 ## feed_title feed_link feed_description feed_language feed_pub_date #### 1 Clinical Infect… http://a… "n " en-us 2025-02-24 00:00:00 ## 2 Clinical Infect… http://a… "n " en-us 2025-02-24 00:00:00 ## 3 Clinical Infect… http://a… "n " en-us 2025-02-24 00:00:00 ## 4 Clinical Infect… http://a… "n " en-us 2025-02-24 00:00:00 ## 5 Clinical Infect… http://a… "n " en-us 2025-02-24 00:00:00 ## 6 Clinical Infect… http://a… "n " en-us 2025-02-24 00:00:00 ## 7 Clinical Infect… http://a… "n " en-us 2025-02-24 00:00:00 ## 8 Clinical Infect… http://a… "n " en-us 2025-02-24 00:00:00 ## 9 Clinical Infect… http://a… "n " en-us 2025-02-24 00:00:00 ## 10 Clinical Infect… http://a… "n " en-us 2025-02-24 00:00:00 ## # ℹ 36 more rows ## # ℹ 8 more variables: feed_last_build_date , feed_generator , ## # item_title , item_link , item_description , ## # item_pub_date , item_guid , item_category
Este atât de simplu! Două linii de coduri. Apreciez foarte mult că Oxford Publisher adaugă rezumat la feed -ul lor RSS. Acest lucru este foarte util pentru a trimite la LLM pentru rezumare.
Pentru a o seta ca automatizare, ar trebui să tragem date vechi și să vedem dacă se potrivește cu date noi. Să presupunem că avem deja date vechi care au fost salvate rda
. Voi simula date vechi, dar eliminând 50% din întâmplare df
ca așa. Și creați o coloană sent
cu număr 1
modul meu de a afirma că acestea au fost postate pe Bluesky.
Obțineți date vechi
df_old <- df |> slice_sample(prop = 0.5) |> mutate(sent = 1)
Dar, în realitate, l -am încărca din fișierul de date ca așa.
(load("old_data.rda")) #assuming it's saved under df_old ## (1) "df_old"
Rețineți, de asemenea, că nu există niciun rezumat LLM în DF_OLD Mock.
Potriviți -vă cu date noi
Să presupunem asta df
noul flux RSS capturat este noile noastre date, pe care le vom dori anti_join
Cei vechi să -i returneze decât pe cele care în datele noastre vechi.
df_new <- df |> anti_join(df_old, by = "item_link") |> mutate(sent = 0) df_new(10,"item_description") |> pull() ## (1) "AbstractBackgroundBlastomycosis is an environmentally acquired fungal infection that can result in severe pulmonary illness and high hospitalization rates. In 2023, a blastomycosis outbreak was detected among workers at a paper mill in Delta County, Michigan.MethodsWe included patients with clinical and laboratory evidence of blastomycosis who had spent ≥40 hours in Delta County since 1 September 2022 and had illness onset 1 December 2022–1 July 2023. We assessed epidemiological and clinical features of patients and evaluated factors associated with hospitalization. We performed whole-genome sequencing to characterize genetic relatedness of clinical isolates from 8 patients.ResultsIn total, 131 patients were identified; all had worked at or visited the mill. Sixteen patients (12%) were hospitalized; 1 died. Compared with nonhospitalized patients, more hospitalized patients had diabetes (P = .03) and urine antigen titers above the lower limit of quantification (P < .001). Hospitalized patients were also more likely to have had ≥1 healthcare visits before receiving a blastomycosis diagnostic test (P = .02) and to have been treated with antibiotics prior to antifungal prescription (P = .001). All sequenced isolates were identified as Blastomyces gilchristii and clustered into a distinct outbreak cluster.ConclusionsThis was the largest documented blastomycosis outbreak in the United States. Epidemiologic evidence indicated exposures occurred at or near the mill, and genomic findings suggested a common exposure source. Patients with diabetes may have increased risk of hospitalization, and elevated urine antigen titers could indicate greater disease severity. Early suspicion of blastomycosis may prompt earlier diagnosis and treatment, potentially reducing unnecessary antibiotic prescriptions and improving patient outcomes."
După cum puteți vedea, analizând rândul 10 al datelor, CID RSS Feed include abstract! 🙌 Norocos pentru noi!
Rezumați prin LLM
## install openai virtualenv ## Run this if it's your first time by uncommenting it ## reticulate::virtualenv_install(envname = "openai", packages = c("openai","atproto")) reticulate::use_virtualenv("openai") library(reticulate) openai <- import("openai") OpenAI <- openai$OpenAI client = OpenAI(api_key = 'YOUR API KEY') ## change this to yours response <- client$chat$completions$create( model = "gpt-4o-mini", messages = list(dict( role = "system", content = "You are a summarizer. Please summarize the following abstract. Include statistics.Use emoji to shorten characters. The summary must not exceed 200 characters—if you reach 200 characters, stop immediately. Do not add any extra commentary or exceed the 200-character limit." ), dict( role = "user", content = df_new(10,"item_description") |> pull() ) ), temperature = 0 ) (summary <- response$choices((1))$message$content) ## (1) "26,233 adults studied (median age 71). 60.9% treated on day 0; n30-day mortality: 7.5% (day 0), 8.5% (day 1), 10.2% (days 2-5). Delay increases ndeath risk (OR 1.14 & 1.40). 🚨💊"
Aici puteți personaliza cu adevărat probabil. Ce este important pentru tine pe care ai vrea să -l vezi dintr -un rezumat, astfel încât să faci clic pe linkul jurnalului și să citești mai multe? Pentru mine, sunt statisticile. Prin urmare, am specificat asta în prompt. Deoarece Bluesky permite doar 300 de grafene (personaje vizibile), am experimentat cu 200.250.300 și am găsit 200 pare a fi cel mai sigur, astfel încât să nu trecem și să ajungem să dăm o eroare. Pentru îmbunătățiri viitoare, ar fi bine să creăm o funcție care să verifice acest lucru și să re-ruleze promptul cu reglare sau să-l fileze.
Postează pe Bluesky
Vă rugăm să rețineți că, acest lucru demonstrează doar postarea unui titlu specific df_new((10,))
. Putem modifica acest cod mai târziu, astfel încât să nu fie atât de rigid. Acest lucru este doar pentru a arăta cum să trimiteți postări albastre prin intermediul atproto
. Acesta este un pachet R numit bskyr
Pe care îl puteți folosi și pentru a trimite postări, deși nu sunt sigur dacă puteți încorpora extern.
atproto <- import("atproto") Client <- atproto$Client models <- atproto$models client_utils <- atproto$client_utils ## Login bsky <- Client() bsky$login("username", "password") #change to your username and app password ## Build Text text <- client_utils$TextBuilder() text$text(summary) ## Embed embed <- models$app$bsky$embed$external$Main( external = models$AppBskyEmbedExternal$External( uri=df_new((10, 'item_link')), # The main link title=df_new((10, 'item_title')), # Title of the preview description=df_new((10, 'item_description')), # # Description of the link )) bsky$send_post(text = text, embed = embed)
Salvați -l și postați mai târziu
Este posibil să fi observat că de fapt avem o coloană în df_old
chemat sent
. Aceasta este să activăm postarea de titluri pe care nu le -am postat. Practic, atribuim 1
ori de câte ori am trimis o postare și 0
Ori de câte ori există un nou titlu pe care nu l -am postat. În cele din urmă, va trebui să salvăm întregul DataFrame. Să punem tot codul la un loc doar pentru a avea sens. Vom presupune, de asemenea, că avem deja old_data.rda
și, de asemenea, avem deja env. openai
şi atproto
.
### 1. Get Feed library(tidyverse) library(tidyRSS) url <- "https://academic.oup.com/rss/site_5269/3135.xml" df <- tidyfeed(url) ### 2. Get Old Data load("old_data.rda") #df_old is our dataframe ### 3. Match feed and old data, to return only ones that are not in old data df_new <- df |> anti_join(df_old, by = "item_link") |> mutate(sent = 0) ### 4. Randomly pull a title that has not been sent previously topic_to_send <- df_new |> filter(sent == 0) |> slice_sample(n = 1) ### 5. OpenAI LLM summarization reticulate::use_virtualenv("openai") library(reticulate) openai <- import("openai") OpenAI <- openai$OpenAI client = OpenAI(api_key = 'YOUR API KEY') ## change this to yours response <- client$chat$completions$create( model = "gpt-4o-mini", messages = list(dict( role = "system", content = "You are a summarizer. Please summarize the following abstract. Include statistics.Use emoji to shorten characters. The summary must not exceed 200 characters—if you reach 200 characters, stop immediately. Do not add any extra commentary or exceed the 200-character limit." ), dict( role = "user", content = topic_to_send |> pull(item_description) ) ), temperature = 0 ) summary <- response$choices((1))$message$content ### 6. Post on Bluesky atproto <- import("atproto") Client <- atproto$Client models <- atproto$models client_utils <- atproto$client_utils ## Login bsky <- Client() bsky$login("username", "password") #change to your username and app password ## Build Text text <- client_utils$TextBuilder() text$text(summary) ## Embed embed <- models$app$bsky$embed$external$Main( external = models$AppBskyEmbedExternal$External( uri=topic_to_send((1, 'item_link')), # The main link title=topic_to_send((1, 'item_title')), # Title of the preview description=topic_to_send((1, 'item_description')), # # Description of the link )) ## Post bsky$send_post(text = text, embed = embed) ### 7. Combine old and new df_old <- rbind(df_old, df_new) |> mutate(sent = case_when( item_link == topic_to_send$item_link ~ 1, TRUE ~ sent )) save(df_old, file = "old_data.rda")
Nu cel mai elegant cod, dar obțineți conceptul și asta va face deocamdată 🤣. Puteți seta apoi Scheduler Task sau Crontab pentru a -l rula o dată pe săptămână, etc. Partea de postare poate fi probabil separată de întregul script, astfel încât noul dvs. ecran de flux și postare să fie separate. Voi lăsa asta la codificarea voastră creativă 🙌
Limitare/oportunități de îmbunătățire
- Modelul LLM nu este perfect. Este posibil să nu rezume întotdeauna corect. Mai ales cu anii, o modalitate prin care ne putem îmbunătăți, este să stabilim anul curent
- Mi -am dat seama că atunci când articolele nu afirmă în mod explicit anul curent, acesta va fi implicit până în 2023. 🤔
- Limitarea personajelor în interogarea LLM
- Nu este gratuit, dar GPT-4O-Mini este destul de accesibil. 50% reducere dacă se lovește
- Abrevierile sunt greu de înțeles uneori
- Proiectul viitor ar fi să adăugați legende de prescurtare pe un fir
- Uneori, dacă rezumatul conține mai mult de 300 de grafice (caractere cam), nu vom putea posta
- trebuie să creăm o funcție care verifică 300 grafen și apoi să facă ceva pentru a o modifica
- convertit
openai
şibluesky
să -și folosească API -ul HTTP, astfel încât să nu ne bazămreticulate
și modulele respectivehttr2
va fi un instrument excelent pentru acest lucru
Gânduri finale
- Acest lucru nu înlocuiește oamenii, ar fi minunat dacă oamenii pot rezuma pe toate, dar știm că acest lucru nu este posibil.
- Oferă un fragment, un instantaneu și, de asemenea, puteți personaliza promptul pentru ceea ce este important pentru dvs., aici vreau statistici în mod specific. Dar puteți schimba promptul după bunul plac, experimentați cu acesta!
- La prima citire sau privire, este posibil să nu vă atragă atenția, dar postările ulterioare ale altora ar putea declanșa o atenție suplimentară. Sau ceea ce mi -a atras atenția a fost dacă nu prea am înțeles prescurtările … doar din curiozitate m -a făcut să verific ce înseamnă acestea
Confirmare
Apreciez foarte mult feedback -ul lui Jonathan Ryder și Joseph Marcus cu privire la acest proiect! Au ajutat la verificarea încrucișată a ceea ce a fost important de rezumat, ce nu a fost. Ce rezumat a avut sens, ceea ce nu. De asemenea, a oferit legături bune pentru monitorizarea jurnalului de identitate. Chiar nu ar fi putut să o facă fără ideea și supravegherea lor. Dă -le o urmărire pe 🦋
Lecții învățate
- Oxford oferă un cadru bun de schemă de furaje, inclusiv abstract
- Ingineria promptă este importantă
- Învăţat
()
în R înseamnă a -l imprima - Deși nu face parte din cele de mai sus, dar am citit
httr2
pachet și cred că ar fi o modificare excelentă pentru codul de mai sus, astfel încât să nu depindem depython
module - A avea prieteni pentru a oferi feedback cu privire la proiect este important! Când scriem aceste cod, vom avea prejudecăți inerente că arată grozav 🤣. Dar a avea alții te va readuce pe pământ. Am învățat atât de multe de la Joseph și Jonathan. Vă mulțumim că ați făcut parte din asta!
Dacă vă place acest articol: