Diffbot'u ilk kez 2021'de Adobe Developer blogu için API'lerinin bir demosunu oluşturduğumda keşfettim ( "Doğal Dil İşleme, Adobe PDF Özü ve Derin PDF Zekası" ).
O zamanlar Diffbot'un API'sinin ne kadar kolay olduğundan ve ne kadar hızlı yanıt verdiğinden etkilenmiştim. Bir süredir API'lerine bakmamıştım ama birkaç gün önce metin özetlemeye yönelik yeni desteklerini duyurdular. Bunun Adobe PDF Extract API ile birleştirmenin harika bir şey olacağını düşündüm. İşte bulduğum şey.
Öncelikle, bunu kendiniz denemek istiyorsanız şunlara ihtiyacınız olacak:
Peki, özet akışının nasıl çalışabileceğine bakalım.
Extract API (kusura bakmayın, "Adobe PDF Extract API", bekleyin, bu benim blogum, bazı şeyleri kısaltabilirim!) oldukça güçlüdür. Belgedeki her öğe ayrıntısını doğru şekilde bulmak amacıyla PDF'yi akıllıca ayrıştırmak için yapay zekayı kullanır.
Yani metin, yazı tipleri, renkler, konum vb. Ayrıca görselleri ve tablo halindeki verileri de bulabilir ve bu da bazı oldukça güçlü kullanım durumlarına yol açar. (Bunun güzel bir örneği için, astronomik verileri toplayıp bir araya getirmek ve raporlar oluşturmak için birden fazla bilimsel dergiyi taradığım blog gönderime bakın.)
Bu demo için kelimenin tam anlamıyla sadece metne ihtiyacımız var. Bunun için REST API'lerinden yararlanacağım. Mevcut PDF hizmetlerinin neredeyse tüm yönlerine ilişkin "akış" şunlardır:
Kullanabileceğiniz SDK'ların da olduğunu unutmayın, ancak REST API'lerimizi o kadar basit buldum ki doğrudan uç noktalara ulaştım. İşte Extract işlemini yapmak için yazdığım script. Temel olarak yukarıda söylediğim her şey ve yerel dosya sistemimdeki kaynak PDF'ye işaret ediyor.
/* This demo is a two step process. This file, step one, handles extracting and storing the JSON from a PDF. */ import 'dotenv/config'; import fs from 'fs'; import { Readable } from 'stream'; import { finished } from 'stream/promises'; const SOURCE_PDF = '../../source_pdfs/boring_adobe_security_doc.pdf'; const REST_API = "https://pdf-services.adobe.io/"; const CLIENT_ID = process.env.CLIENT_ID; const CLIENT_SECRET = process.env.CLIENT_SECRET; async function delay(x) { return new Promise(resolve => { setTimeout(() => resolve(), x); }); } async function getAccessToken(id, secret) { const params = new URLSearchParams(); params.append('client_id', id); params.append('client_secret', secret); let resp = await fetch('https://pdf-services-ue1.adobe.io/token', { method: 'POST', headers: { 'Content-Type':'application/x-www-form-urlencoded' }, body:params }); let data = await resp.json(); return data.access_token; } async function getUploadData(mediaType, token, clientId) { let body = { 'mediaType': mediaType }; body = JSON.stringify(body); let req = await fetch(REST_API+'assets', { method:'post', headers: { 'X-API-Key':clientId, 'Authorization':`Bearer ${token}`, 'Content-Type':'application/json' }, body: body }); let data = await req.json(); return data; } async function uploadFile(url, filePath, mediaType) { let stream = fs.createReadStream(filePath); let stats = fs.statSync(filePath); let fileSizeInBytes = stats.size; let upload = await fetch(url, { method:'PUT', redirect:'follow', headers: { 'Content-Type':mediaType, 'Content-Length':fileSizeInBytes }, duplex:'half', body:stream }); if(upload.status === 200) return; else { throw('Bad result, handle later.'); } } async function pollJob(url, token, clientId) { let status = null; let asset; while(status !== 'done') { let req = await fetch(url, { method:'GET', headers: { 'X-API-Key':clientId, 'Authorization':`Bearer ${token}`, } }); let res = await req.json(); status = res.status; if(status === 'done') { asset = res; } else { await delay(2000); } } return asset; } async function downloadFile(url, filePath) { let res = await fetch(url); const body = Readable.fromWeb(res.body); const download_write_stream = fs.createWriteStream(filePath); return await finished(body.pipe(download_write_stream)); } async function extractJob(asset, token, clientId) { let body = { 'assetID': asset.assetID } let resp = await fetch(REST_API + 'operation/extractpdf', { method: 'POST', headers: { 'Authorization':`Bearer ${token}`, 'X-API-KEY':clientId, 'Content-Type':'application/json' }, body:JSON.stringify(body) }); return resp.headers.get('location'); } let accessToken = await getAccessToken(CLIENT_ID, CLIENT_SECRET); console.log('Got our access token.'); let uploadedAsset = await getUploadData('application/pdf', accessToken, CLIENT_ID); await uploadFile(uploadedAsset.uploadUri, SOURCE_PDF, 'application/pdf'); console.log('Source PDF Uploaded.'); let job = await extractJob(uploadedAsset, accessToken, CLIENT_ID); console.log('Job created. Now to poll it.'); let result = await pollJob(job, accessToken, CLIENT_ID); console.log('Job is done.'); await downloadFile(result.content.downloadUri, 'extract.json'); console.log('All done.');
Tamam, umarım hâlâ okuyorsundur. Genel olarak, bu şekilde devasa kod blokları yayınlamaktan kaçınmaya çalışıyorum, ancak sondaki satırlara odaklanırsanız, yalnızca yukarıdaki akışta tanımladığım şeyi yapan yardımcı işlevlere bastığımı göreceksiniz. Kimlik doğrulaması yapın, bir PDF yüklemeyi isteyin, bir işi başlatın, kontrol edin ve sonucu indirin.
Bir not ekleyeceğim. Extract, JSON sonuç kümesini ve isteğe bağlı olarak tabloları ve görüntüleri içeren bir zip dosyası döndürür. REST API'nin güzel yanı, doğrudan JSON'a ulaşıp onu saklayabilmemdir.
JSON sonucu oldukça büyük olabilir. Üç sayfalık kaynak PDF'im (inanılmaz derecede sıkıcı bir Adobe güvenlik belgesi) için ortaya çıkan JSON 4560 satır uzunluğundadır. Kaynak PDF'mi burada ve Extract'ın ham çıktısını burada bulabilirsiniz.
4,5k satırın tamamını buraya koymak yerine, API tarafından bulunan iki benzersiz öğe olan bir pasajı göstereyim:
{ "Bounds": [ 44.62139892578125, 756.9429931640625, 245.0037841796875, 766.3184967041016 ], "Font": { "alt_family_name": "* Arial", "embedded": true, "encoding": "Identity-H", "family_name": "* Arial", "font_type": "CIDFontType0", "italic": false, "monospaced": false, "name": "*Arial-6539", "subset": false, "weight": 400 }, "HasClip": false, "Lang": "en", "Page": 0, "Path": "//Document/Sect/P", "Text": "Adobe Vendor Security Review Program White Paper ", "TextSize": 8.5, "attributes": { "SpaceAfter": 18 } }, { "Bounds": [ 0.0, 0.0, 630.0, 820.7799987792969 ], "ClipBounds": [ 548.72802734375, 739.1929931640625, 602.5444488525391, 820.7799987792969 ], "Page": 0, "Path": "//Document/Sect/Figure", "attributes": { "BBox": [ 548.9779999999737, 739.4429999999993, 587.61599999998, 790.920999999973 ], "Placement": "Block" } },
Yukarıdaki örnekte, ilk öğenin metinsel olduğunu ve Text
özelliği içerdiğini, ikincisinin ise şekil olduğunu görebilirsiniz. Demom için, mevcut olduğunda Text
özelliğini kullanmam gerekiyor. Bunu uygulamalı olarak görelim.
Daha önce Diffbot API'nin kullanımının oldukça basit olduğundan bahsetmiştim. Bunu göstereyim.
Öncelikle bazı değişkenleri ayarlayıp ilk adımdan aldığım JSON'da okuyacağım. Açık olmak gerekirse, her şeyi tek bir süreçte yapabilirim, ancak Extract'ı birden fazla çalıştırmanın aslında hiçbir anlamı yok. Harika olan şu ki, sonuçta birden fazla arama yapabilirim.
Örnek olarak, Diffbot'un bir diğer harika özelliği de metinden varlıklar, yani bir belgenin ne hakkında konuştuğunu (kişiler, yerler, vb.) elde etmektir. Her neyse, işte başlangıç:
/* In this file, we take the result from our Extract operation and pass it to Diffbot */ import 'dotenv/config'; import fs from 'fs'; const DIFFBOT_KEY = process.env.DIFFBOT_KEY; const SOURCE_JSON = './extract.json'; const data = JSON.parse(fs.readFileSync(SOURCE_JSON, 'utf8')); console.log(`Read in source data from ${SOURCE_JSON}.`);
Daha sonra, Extract sonucundaki metni ayrıştırmam gerekiyor:
let text = data.elements.reduce((text, el) => { if(el.Text) text += el.Text + '\n'; return text; },'');
Daha sonra Diffbot'a bir HTTP isteği hazırlıyorum. Daha fazla bilgi için belgelerine bakın.
let fields = 'summary'; let url = `https://nl.diffbot.com/v1/?fields=${fields}&token=${DIFFBOT_KEY}`; let body = [{ content:text, lang:'en', format:'plain text' }]; console.log('Passing text to Diffbot.'); let req = await fetch(url, { method:'POST', body:JSON.stringify(body), headers: { 'Content-Type':'application/json' } }); let result = await req.json();
Ve bu kadar. Son adım olarak basitçe çıktısını alıyorum:
console.log(`Summary of PDF:\n${result[0].summary}`);
Kaynak PDF göz önüne alındığında, nihai sonuç şöyledir:
Adobe has a vendor security review program that evaluates vendors that collect, store, process, transmit, or dispose of Adobe data outside of Adobe-controlled physical offices or data center locations. The VSR program includes requirements for vendors to follow when handling sensitive data and assigns a risk level score to vendors based on their compliance with Adobe standards. If a vendor fails the VSR program, Adobe holds discussions with the business owner to understand the details of the vendor's security practices and determine whether or not to continue working with them.
Üç sayfalık PDF'im artık basit bir paragraftan ibaret. Milyonlarca belgeye sahip kuruluşlar için bunun ne kadar faydalı olacağını tahmin edebilirsiniz. Bunu diğer hizmetlerle birleştirirseniz (daha önce bahsettiğim varlıklar özelliği gibi) büyük kütüphanelerle çalışmayı çok daha kolay hale getirir.
Bunu kendiniz kontrol etmek istiyorsanız tüm kodu buradan alabilirsiniz: https://github.com/cfjedimaster/document-services-demos/tree/main/random_demos/extract_diffbot_summary . Dediğim gibi, buradaki her şey ücretsiz olarak test edilebilir, bu yüzden bir deneyin ve aşağıdaki yorumda ne düşündüğünüzü bana bildirin.