Files
conjurer/conjurer_librarian/conjurer_librarian.py
T
gitea 3f68c6aaed Test
aaa

aa

Bugfixing et masse

bbb

asas

aas

asas

aa

as

qq

as

as

as

as

as

aaa

asa

nn

aa

sda

88

asa

sasa

adsa

a

as

asdas

Final version before tests

Fix1

aa

aa

fx

dx

:)

aa

Hopefully last fix

aaa

aaa

bbb

bb

dd

aa

sdae

aa

bb

aa

kk

a

Fix

fx

aa

deploy

fx

asas

bb

as

fx

fx

aa

aa

mess

kk

A

fix

aa

aa

Viwe fix

a

test

a

aa

FX
2024-04-10 15:26:18 +02:00

188 lines
7.0 KiB
Python

import re
import logging
import threading
import time
from flask import Flask, jsonify, request
import netrc
import json
from json.decoder import JSONDecodeError
from platform import uname
from sys import platform
from urllib.request import urlopen
from habanero import Crossref
from waitress import serve
if platform in ("linux", "linux2"):
SEPARATOR_FILE_PATH = "/"
if "microsoft-standard" in uname().release:
NETRC_FILE = "/home/mtuszowski/.netrc"
else:
NETRC_FILE = "/home/pi/.netrc"
elif platform == "win32":
NETRC_FILE = "C:\\Users\\mtusz\\.netrc"
#HOST_ADDRESS = "192.168.1.191"
HOST_ADDRESS = "0.0.0.0"
PORT_ADDRESS = 5001
class Librarian(object):
def __init__(self) -> None:
netrc_mod = netrc.netrc(NETRC_FILE)
authTokens = netrc_mod.authenticators("crossref")
self.cr = Crossref(mailto=authTokens[0])
self.limit = 1000
self.fetched = 0
self.hit = 0
self.total = 0
def search_crossref(self, query, uuid):
search_result_from_cr = self.cr.works(query = query, limit = self.limit)
self.total = search_result_from_cr['message']['total-results']
self.fetched = len(search_result_from_cr['message']['items'])
#add to sql with UUID
#sql row - title, doi, author, uuid, last retrieved, is_available
with open("results.json", "r+", encoding="UTF-8") as data_file:
# First we load existing data into a dict.
try:
file_data = json.load(data_file)
except JSONDecodeError:
file_data = []
# Join new_data with file_data inside emp_details
summarized_results = []
for item in search_result_from_cr['message']['items']:
container = "NO"
if "container-title" in item:
container = "YES"
summarized_results.append({"DOI" : item['DOI'], "title": item['title'] if 'title' in item else None,"type": item['type'] if 'type' in item else None, "container": container})
result = {"UUID": uuid, "total_results": search_result_from_cr['message']['total-results'], "on_page" : 1, "summary":summarized_results, "results":search_result_from_cr['message']['items'], }
file_data.append(result)
print("Saving")
data_file.seek(0)
# convert back to json.
json.dump(file_data, data_file, indent=4)
return result
def check_if_exists(self,page_url):
in_scihub_db = True
if not page_url.startswith(("http:", "https:")):
raise ValueError("URL must start with 'http:' or 'https:'")
# trunk-ignore(bandit/B310)
with urlopen(page_url) as response:
data = response.read()
text = data.decode("utf-8")
for line in text.splitlines():
if re.match(r".*Unfortunately, Sci-Hub doesn't have the requested document.*", line):
return None
if in_scihub_db:
return text
return None
def download(self, page_url):
if response := self.check_if_exists(page_url):
for line in response.splitlines():
if m := re.match(r".*<embed type=\"application.pdf\"\s*src=\"(.*\.pdf)",line):
return "https:" + str(m.group(1))
return None
def provide_sci_hub_link(self, page_url):
if self.check_if_exists(page_url):
return page_url
return None
def refine_query(self, unrefined_reqult):
print("Refine result")
refined_result = []
for item in unrefined_reqult["summary"]:
if item["container"] == "NO" and item["title"]:
item_link = "https://sci-hub.se/" + str(item['DOI'])
if self.check_if_exists(item_link):
refined_result.append(item)
print ("HIT")
print(item["title"])
time.sleep(0.01)
print("Existing hits")
self.hit = len(refined_result)
return refined_result
def answer_query(self, query, uuid):
#Search sql for UUID
#SQL SELECT * FROM RESULTS WHERE UUID = uuid
print("Answer result")
uuid_found = False
database = None
with open("results.json", "r", encoding="UTF-8") as new_file:
#tu logika komunikacji z SQL i cała logika związana z wyszukaniem
#ale tymczasowo plik
try:
database = json.load(new_file)
except JSONDecodeError:
pass
if database:
for item in database:
if item["UUID"] == uuid:
print (item["UUID"])
uuid_found = True
return self.refine_query(item)
if not uuid_found:
answer = self.search_crossref(query=query, uuid=uuid)
return self.refine_query(answer)
#example not exists
#sample_non_existing_page_url = "https://sci-hub.se/10.4324/9781003006237"
#sample usage to download
#sample_existing_page_url = "https://sci-hub.se/10.1057/9781137435026"
#print(cl.download(sample_existing_page_url))
#cl.search_crossref("BDSM")
app = Flask(__name__)
def flask_debug():
"""
The `flask_debug` function starts a Flask application in debug mode without using the reloader.
Do not use for production for fucks sake.
"""
# trunk-ignore(bandit/B201)
app.run(debug=True, use_reloader=False, host=HOST_ADDRESS, port=PORT_ADDRESS)
def waitress_run():
"""
The `waitress_run` function serves the `app` on host "0.0.0.0"
and port 5000 using the Waitress WSGI server.
"""
serve(app, host=HOST_ADDRESS, port=PORT_ADDRESS)
@app.route("/query", methods=["POST"])
def query_database():
record = json.loads(request.data)
app.logger.info(record)
app.logger.info(record["query"])
app.logger.info(record["UUID"])
cl = Librarian()
answer_data = cl.answer_query(record["query"], record["UUID"])
app.logger.info(answer_data)
summary = (cl.hit,cl.fetched, cl.total, record["UUID"])
answer_data = (summary,answer_data)
return_data = (
jsonify(isError=False, message="Success", statusCode=200, data=answer_data),
200,
)
return return_data
if __name__ == "__main__":
logger = logging.getLogger('conjurer_musician')
logger.setLevel(logging.DEBUG)
threads = []
#threads.append(threading.Thread(target=waitress_run))
threads.append(threading.Thread(target=flask_debug))
for worker in threads:
worker.start()
for worker in threads:
worker.join()
#1. robi liste wyników i ją wyświetla - ale tylko tytuły niezależnych dzieł - jeśli jest coś w containerze to trza pogrupować
#2. Tworzy przyciski pozwalające sprawdzić czy jest dostępne - i jeśli jest zwraca link
#3. Jest też przycisk "more" - wyszukujemy po 100, wyświetlamy po 20. Po 100 jak jeszcze to dopiero odpytujemy crossref przyciski strzałek przesuwają po obecnej porcji danych