client.mojo (4066B)
1 from std.collections import Optional 2 from std.time import perf_counter_ns 3 4 from json import Value 5 from flare.http import HttpClient 6 7 from hyf_provider.config import MaxLocalProviderConfig 8 9 10 @fieldwise_init 11 struct MaxLocalTransportResponse(Copyable, Movable): 12 var status: Int 13 var body_text: String 14 var latency_ms: Int 15 16 17 @fieldwise_init 18 struct MaxLocalTransportFailure(Copyable, Movable): 19 var kind: String 20 var reason: String 21 22 23 @fieldwise_init 24 struct MaxLocalTransportOutcome(Copyable, Movable): 25 var response: Optional[MaxLocalTransportResponse] 26 var failure: Optional[MaxLocalTransportFailure] 27 28 29 def _trim_trailing_slash(url: String) -> String: 30 if url.endswith("/") and url.byte_length() > 1: 31 return String(url[byte = 0 : url.byte_length() - 1]) 32 return String(url) 33 34 35 def _http_url(url: String) -> Bool: 36 return url.startswith("http://") or url.startswith("https://") 37 38 39 def _elapsed_ms_since(start_ns: UInt) -> Int: 40 return Int((perf_counter_ns() - start_ns) // 1_000_000) 41 42 43 def _transport_response_outcome( 44 status: Int, body_text: String, latency_ms: Int 45 ) -> MaxLocalTransportOutcome: 46 return MaxLocalTransportOutcome( 47 response=Optional[MaxLocalTransportResponse]( 48 MaxLocalTransportResponse( 49 status=status, 50 body_text=String(body_text), 51 latency_ms=latency_ms, 52 ) 53 ), 54 failure=Optional[MaxLocalTransportFailure](None), 55 ) 56 57 58 def _transport_failure_outcome( 59 kind: String, reason: String 60 ) -> MaxLocalTransportOutcome: 61 return MaxLocalTransportOutcome( 62 response=Optional[MaxLocalTransportResponse](None), 63 failure=Optional[MaxLocalTransportFailure]( 64 MaxLocalTransportFailure(kind=String(kind), reason=String(reason)) 65 ), 66 ) 67 68 69 def _transport_exception_reason( 70 start_ns: UInt, request_timeout_ms: Int 71 ) -> String: 72 if _elapsed_ms_since(start_ns) >= request_timeout_ms: 73 return "timeout" 74 return "unknown_transport" 75 76 77 def make_max_local_http_client(config: MaxLocalProviderConfig) -> HttpClient: 78 return HttpClient(timeout_ms=config.request_timeout_ms) 79 80 81 def max_local_chat_completions_url(config: MaxLocalProviderConfig) -> String: 82 return _trim_trailing_slash(config.base_url) + "/chat/completions" 83 84 85 def get_max_local_health( 86 config: MaxLocalProviderConfig, 87 ) -> MaxLocalTransportOutcome: 88 if not _http_url(config.health_url): 89 return _transport_failure_outcome("transport", "invalid_url") 90 91 var start_ns = perf_counter_ns() 92 try: 93 with make_max_local_http_client(config) as client: 94 var response = client.get(config.health_url) 95 var latency_ms = _elapsed_ms_since(start_ns) 96 if not response.ok(): 97 return _transport_failure_outcome("http_status", "non_2xx") 98 return _transport_response_outcome( 99 response.status, response.text(), latency_ms 100 ) 101 except: 102 return _transport_failure_outcome( 103 "transport", 104 _transport_exception_reason(start_ns, config.request_timeout_ms), 105 ) 106 107 108 def post_max_local_chat_completion( 109 config: MaxLocalProviderConfig, body: Value 110 ) -> MaxLocalTransportOutcome: 111 var url = max_local_chat_completions_url(config) 112 if not _http_url(url): 113 return _transport_failure_outcome("transport", "invalid_url") 114 115 var start_ns = perf_counter_ns() 116 try: 117 with make_max_local_http_client(config) as client: 118 var response = client.post(url, body) 119 var latency_ms = _elapsed_ms_since(start_ns) 120 if not response.ok(): 121 return _transport_failure_outcome( 122 "http_status", "provider_non_2xx" 123 ) 124 return _transport_response_outcome( 125 response.status, response.text(), latency_ms 126 ) 127 except: 128 return _transport_failure_outcome( 129 "transport", 130 _transport_exception_reason(start_ns, config.request_timeout_ms), 131 )