99import org .springframework .stereotype .Service ;
1010
1111import javax .annotation .Nullable ;
12- import java .io .*;
12+ import java .io .BufferedReader ;
13+ import java .io .FileNotFoundException ;
14+ import java .io .IOException ;
15+ import java .io .InputStream ;
16+ import java .io .InputStreamReader ;
1317import java .net .URI ;
1418import java .net .http .HttpClient ;
1519import java .net .http .HttpRequest ;
1620import java .net .http .HttpResponse ;
1721import java .nio .charset .StandardCharsets ;
22+ import java .time .Duration ;
1823import java .util .HashMap ;
1924import java .util .Map ;
2025import java .util .Optional ;
@@ -98,7 +103,7 @@ public String fillTemplate(final String promptTemplate, final Map<String, String
98103 while (matcher .find ()) {
99104 final String fullPlaceholder = matcher .group ();
100105
101- final String key = fullPlaceholder .substring (2 , fullPlaceholder .length () - 2 );
106+ final String key = fullPlaceholder .substring (2 , fullPlaceholder .length () - 2 ). trim () ;
102107 final String value = args .get (key );
103108
104109 if (value != null ) {
@@ -131,13 +136,16 @@ public <ResponseType> ResponseType startQuery(
131136 @ Nullable final String modelOverride ) {
132137 try {
133138 final String promptTemplate = getTemplate (templateFileName );
134-
135139 final String filledPrompt = fillTemplate (promptTemplate , argMap );
136140
137141 final TypeReference <HashMap <String , Object >> typeRef = new TypeReference <>() {};
138142 final String jsonSchema = jsonSchemaService .getJsonSchema (responseType );
139143 final Map <String , Object > schemaObject = jsonMapper .readValue (jsonSchema , typeRef );
140144
145+ if (schemaObject .get ("properties" ) instanceof Map <?, ?> properties ) {
146+ schemaObject .put ("required" , properties .keySet ());
147+ }
148+
141149 // Determine which model to use: override or default config
142150 final String modelToUse = (modelOverride != null && !modelOverride .isBlank ())
143151 ? modelOverride
@@ -192,18 +200,24 @@ public <ResponseType> ResponseType startQuery(
192200 * @throws IOException if the request or response handling fails
193201 * @throws InterruptedException if the HTTP call is interrupted
194202 */
195- private OllamaResponse queryLLM (OllamaRequest request ) throws IOException , InterruptedException {
203+ private OllamaResponse queryLLM (final OllamaRequest request ) throws IOException , InterruptedException {
196204 final String json = jsonMapper .writeValueAsString (request );
197205
198- HttpRequest req = HttpRequest .newBuilder ()
206+ final HttpRequest . Builder reqBuilder = HttpRequest .newBuilder ()
199207 .uri (URI .create (this .config .getUrl () + "/" + this .config .getEndpoint ()))
200208 .header ("Content-Type" , "application/json" )
201- .POST (HttpRequest .BodyPublishers .ofString (json ))
202- .build ();
209+ .timeout (Duration .ofMinutes (10 ))
210+ .POST (HttpRequest .BodyPublishers .ofString (json ));
211+
212+ if (this .config .getApiKey () != null && !this .config .getApiKey ().isBlank ()) {
213+ reqBuilder .header ("Authorization" , "Bearer " + this .config .getApiKey ());
214+ }
215+
216+ final HttpResponse <String > response = client .send (reqBuilder .build (), HttpResponse .BodyHandlers .ofString ());
203217
204- HttpResponse < String > response = client . send ( req , HttpResponse . BodyHandlers . ofString ());
218+ log . info ( "RAW OLLAMA HTTP RESPONSE BODY: {}" , response . body ());
205219
206- OllamaResponse result = jsonMapper .readValue (response .body (), OllamaResponse .class );
220+ final OllamaResponse result = jsonMapper .readValue (response .body (), OllamaResponse .class );
207221
208222 if (result .getError () != null ) {
209223 throw new RuntimeException ("Ollama returned error: " + result .getError ());
@@ -221,9 +235,11 @@ private OllamaResponse queryLLM(OllamaRequest request) throws IOException, Inter
221235 * @return an optional of the parsed response
222236 * @param <ResponseType> the type to cast to
223237 */
224- public <ResponseType > Optional <ResponseType > parseResponse (OllamaResponse ollamaResponse , Class <ResponseType > responseType ) {
238+ public <ResponseType > Optional <ResponseType > parseResponse (
239+ final OllamaResponse ollamaResponse ,
240+ final Class <ResponseType > responseType ) {
225241 final String response = ollamaResponse .getResponse ();
226- if (responseType == null || response == null ) {
242+ if (responseType == null || response == null ) {
227243 log .info ("Response is null or empty: {}" , response );
228244 return Optional .empty ();
229245 }
0 commit comments