22
33import com .openai .client .OpenAIClient ;
44import com .openai .client .okhttp .OpenAIOkHttpClient ;
5+ import com .openai .models .files .FileCreateParams ;
6+ import com .openai .models .files .FileObject ;
7+ import com .openai .models .files .FilePurpose ;
58import com .openai .models .responses .Response ;
69import com .openai .models .responses .ResponseCreateParams ;
710import com .openai .models .responses .ResponseOutputText ;
11+ import com .openai .models .responses .Tool ;
12+ import com .openai .models .responses .WebSearchTool ;
13+ import com .openai .models .vectorstores .VectorStore ;
14+ import com .openai .models .vectorstores .VectorStoreCreateParams ;
815import org .slf4j .Logger ;
916import org .slf4j .LoggerFactory ;
1017
1118import org .togetherjava .tjbot .config .Config ;
1219
1320import javax .annotation .Nullable ;
1421
22+ import java .io .File ;
23+ import java .nio .file .Path ;
1524import java .time .Duration ;
25+ import java .util .List ;
1626import java .util .Optional ;
1727import java .util .stream .Collectors ;
1828
@@ -23,6 +33,8 @@ public class ChatGptService {
2333 private static final Logger logger = LoggerFactory .getLogger (ChatGptService .class );
2434 private static final Duration TIMEOUT = Duration .ofSeconds (90 );
2535
36+ private static final String VECTOR_STORE_XKCD = "xkcd-comics" ;
37+
2638 /** The maximum number of tokens allowed for the generated answer. */
2739 private static final int MAX_TOKENS = 1000 ;
2840
@@ -88,14 +100,103 @@ public Optional<String> askRaw(String inputPrompt, ChatGptModel chatModel) {
88100 return sendPrompt (inputPrompt , chatModel );
89101 }
90102
103+ /**
104+ * Sends a prompt to the ChatGPT API with web capabilities and returns the response.
105+ *
106+ * @param prompt The prompt to send to ChatGPT.
107+ * @param chatModel The AI model to use for this request.
108+ * @return response from ChatGPT as a String.
109+ */
110+ public Optional <String > sendWebPrompt (String prompt , ChatGptModel chatModel ) {
111+ Tool webSearchTool = Tool
112+ .ofWebSearch (WebSearchTool .builder ().type (WebSearchTool .Type .WEB_SEARCH ).build ());
113+
114+ return sendPrompt (prompt , chatModel , List .of (webSearchTool ));
115+ }
116+
117+ /**
118+ * Sends a prompt to the ChatGPT API and returns the response.
119+ *
120+ * @param prompt The prompt to send to ChatGPT.
121+ * @param chatModel The AI model to use for this request.
122+ * @return response from ChatGPT as a String.
123+ */
124+ public Optional <String > sendPrompt (String prompt , ChatGptModel chatModel ) {
125+ return sendPrompt (prompt , chatModel , List .of ());
126+ }
127+
128+ public Optional <String > getUploadedFileId (String filePath ) {
129+ return openAIClient .files ()
130+ .list ()
131+ .items ()
132+ .stream ()
133+ .filter (fileObj -> fileObj .filename ().equalsIgnoreCase (filePath ))
134+ .map (FileObject ::id )
135+ .findFirst ();
136+ }
137+
138+ public Optional <String > uploadFileIfNotExists (Path filePath , FilePurpose purpose ) {
139+ if (isDisabled ) {
140+ logger .warn ("ChatGPT file upload attempted but service is disabled" );
141+ return Optional .empty ();
142+ }
143+
144+ File file = filePath .toFile ();
145+ if (!file .exists ()) {
146+ logger .warn ("Could not find file '{}' to upload to ChatGPT" , filePath );
147+ return Optional .empty ();
148+ }
149+
150+ if (getUploadedFileId (filePath .toString ()).isPresent ()) {
151+ logger .warn ("File '{}' already exists." , filePath );
152+ return Optional .empty ();
153+ }
154+
155+ FileCreateParams fileCreateParams =
156+ FileCreateParams .builder ().file (filePath ).purpose (purpose ).build ();
157+
158+ FileObject fileObj = openAIClient .files ().create (fileCreateParams );
159+ String id = fileObj .id ();
160+
161+ logger .info ("Uploaded file to ChatGPT with ID {}" , id );
162+ return Optional .of (id );
163+ }
164+
165+ public String createOrGetXkcdVectorStore (String fileId ) {
166+ List <VectorStore > vectorStores = openAIClient .vectorStores ()
167+ .list ()
168+ .items ()
169+ .stream ()
170+ .filter (vectorStore -> vectorStore .name ().equalsIgnoreCase (VECTOR_STORE_XKCD ))
171+ .toList ();
172+ Optional <VectorStore > vectorStore = vectorStores .stream ().findFirst ();
173+
174+ if (vectorStore .isPresent ()) {
175+ return vectorStore .get ().id ();
176+ }
177+
178+ VectorStoreCreateParams params = VectorStoreCreateParams .builder ()
179+ .name (VECTOR_STORE_XKCD )
180+ .fileIds (List .of (fileId ))
181+ .build ();
182+
183+ VectorStore newVectorStore = openAIClient .vectorStores ().create (params );
184+ String vectorStoreId = newVectorStore .id ();
185+
186+ logger .info ("Created vector store {} with XKCD data" , vectorStoreId );
187+
188+ return vectorStoreId ;
189+ }
190+
91191 /**
92192 * Sends a prompt to the ChatGPT API and returns the response.
93193 *
94194 * @param prompt The prompt to send to ChatGPT.
95195 * @param chatModel The AI model to use for this request.
196+ * @param tools The list of OpenAPI tools to enhance the prompt's answers.
96197 * @return response from ChatGPT as a String.
97198 */
98- private Optional <String > sendPrompt (String prompt , ChatGptModel chatModel ) {
199+ public Optional <String > sendPrompt (String prompt , ChatGptModel chatModel , List < Tool > tools ) {
99200 if (isDisabled ) {
100201 logger .warn ("ChatGPT request attempted but service is disabled" );
101202 return Optional .empty ();
@@ -107,6 +208,7 @@ private Optional<String> sendPrompt(String prompt, ChatGptModel chatModel) {
107208 ResponseCreateParams params = ResponseCreateParams .builder ()
108209 .model (chatModel .toChatModel ())
109210 .input (prompt )
211+ .tools (tools )
110212 .maxOutputTokens (MAX_TOKENS )
111213 .build ();
112214
0 commit comments