forked from webyrd/mediKanren
-
Notifications
You must be signed in to change notification settings - Fork 0
/
trapi-cli.rkt
151 lines (133 loc) · 4.7 KB
/
trapi-cli.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#lang racket
#|
Reads TRAPI filenames from stdin and runs them. Example (run all Dec 2021 queries):
git clone https://github.com/NCATSTranslator/minihackathons
find minihackathons -maxdepth 3 -type f -path \*2021-12_demo\* -name \*.json \
| racket -l errortrace -u medikanren2/trapi-cli.rkt
|#
(require
"common.rkt"
"trapi.rkt"
"logging.rkt"
racket/file racket/function racket/list racket/hash
(except-in racket/match ==)
racket/pretty
racket/runtime-path
racket/dict
racket/async-channel
http/request
json
)
(define seconds-per-query (make-parameter 60))
(define seconds-idle-between-queries (make-parameter 15))
(define uri-trapi (make-parameter #f))
(define (with-timeout seconds thunk)
(define ach (make-async-channel))
(define t (thread
(lambda ()
(async-channel-put
ach
(list (thunk)))))) ; nonempty list indicates success
; Watcher thread:
(thread (lambda ()
(sleep seconds)
(kill-thread t)
(async-channel-put ach '()))) ; empty list indicates timeout
(sync ach))
(define (run-query-without-network-impl fn msg)
(flush-output (current-output-port))
(define maybe-out (with-timeout (seconds-per-query) (lambda () (trapi-response msg))))
(flush-output (current-output-port))
(if (null? maybe-out)
(hasheq 'results '())
(let* ((out (car maybe-out))
(r (dict-ref out 'results)))
(dict-set out 'results r))))
(define (run-query-without-network fn json1)
(define jsexpr (string->jsexpr json1))
(define trapimsg (hash-ref jsexpr 'message))
(define out (run-query-without-network-impl fn trapimsg))
(hasheq 'message out))
(define http-version "1.1")
(define (run-query-with-network fn json1)
(define uri (format "~a~a" (uri-trapi) "/query"))
(define headers '((#"Content-Type" . "application/json")))
(define bytes-out (call/output-request http-version
"POST"
uri
(string->bytes/utf-8 json1)
#f
headers
read-entity/bytes
#:redirects 0))
(define tmp (bytes->jsexpr bytes-out))
(sleep (seconds-idle-between-queries))
tmp)
(define (run-query fn json1)
(displayln (jsexpr->string (hasheq
'event "request"
'fn fn)))
(define out
(if (uri-trapi)
(run-query-with-network fn json1)
(run-query-without-network fn json1)))
(displayln (jsexpr->string (hasheq
'event "response"
'fn fn
'out out
)))
out)
(define (read-and-run-by-filename fd)
(define (iter inouts)
(define l (read-line fd 'any))
(if (eof-object? l)
inouts
(let ((fn (string-trim l)))
(if (or (<= (string-length fn) 1) (not (file-exists? fn)))
'()
(let* (
(t0 (current-milliseconds))
(json1 (file->string fn))
(out (run-query fn json1))
(dt (exact->inexact (/ (- (current-milliseconds) t0) 1000)))
(inout `((fn . ,fn) (dt . ,dt) (json . ,json1) (out . ,out))))
(iter (cons inout inouts)))))))
(iter '()))
(define (num-results-from-out a1)
; (printf "a1=\n")
; (pretty-write a1)
(if (null? a1)
-1 ; -1 indicates timeout
(length (dict-ref (dict-ref a1 'message) 'results))))
(define (run-main)
(let ((inouts (read-and-run-by-filename (current-input-port))))
(for ((inout inouts))
(let* (
(n (num-results-from-out (dict-ref inout 'out))))
(displayln
(jsexpr->string
(hasheq
'event "summary"
'num-answers n
'dt (dict-ref inout 'dt)
'fn (dict-ref inout 'fn)))))))
)
(define (parse-configuration)
(command-line
#:program "trapi-cli.rkt"
#:usage-help "trapi-cli.rkt <options>"
#:once-each
[("--seconds-per-query") sec
"Number of seconds to allow for each query"
(seconds-per-query (string->number (string-trim #:left? #f sec)))]
[("--uri-trapi") adir
"A URI to a TRAPI service"
(uri-trapi (string-trim #:left? #f adir))]
#:args ()
'())
;"" ; We don't care about the return value because configuration lives in mutatable racket parameters
)
(module+ main
(parse-configuration)
(run-main)
)