/** * ${jpp:disclaimer} * * ${jpp:copyright} **/ package com.inet.cowork.gptbot; import com.inet.config.Configuration; import com.inet.config.ConfigurationManager; import com.inet.cowork.api.CoWorkManager; import com.inet.cowork.api.commands.CoWorkCommandHandler; import com.inet.cowork.api.commands.CoWorkCommandProvider; import com.inet.cowork.api.commands.CommandDescription; import com.inet.cowork.api.model.CoWorkMessage; import com.inet.cowork.gptbot.structure.*; import com.inet.id.GUID; import com.inet.lib.json.Json; import javax.annotation.Nullable; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Scanner; import java.util.concurrent.ForkJoinPool; import static com.inet.cowork.gptbot.CoWorkGPTBotServerPlugin.MSG; /** * The actual bot command instance which implements both the Command Provider * for displaying its command in CoWork when typing / but also the handler of the * Command which will call the ChatGPT 3.5 Turbo API. */ public class CoWorkGPTBotCommand implements CoWorkCommandProvider, CoWorkCommandHandler { /** {@inheritDoc} */ @Override public boolean handleCommandMessage( GUID channelId, GUID messageId, GUID userId, String text ) { Configuration configuration = ConfigurationManager.getInstance().getCurrent(); String apikey = configuration.get( CoWorkGPTBotStructureProvider.OPENAI_KEY ); if (apikey == null) { // As of 23.4, this is still internal API but this is how you add a new message to a given channel CoWorkManager.getInstance().addMessage( null, channelId, null, messageId, MSG.getMsg( "apikeymissing" ), null ); return true; } // As of 23.4, this is still internal API but this is how you add a new message to a given channel final CoWorkMessage newMessage = CoWorkManager.getInstance().addMessage( null, channelId, null, messageId, MSG.getMsg( "thinking"), null ); ForkJoinPool.commonPool().execute( () -> { try { URL url = new URL( "https://api.openai.com/v1/chat/completions" ); HttpURLConnection con = (HttpURLConnection)url.openConnection(); con.setRequestMethod( "POST" ); con.setRequestProperty( "Content-Type", "application/json; utf-8" ); con.setRequestProperty( "Authorization", "Bearer "+apikey ); con.setDoOutput( true ); /* example JSON request: { "messages": [ { "role": "system", "content": "You are a helpful assistant that will do its best to fulfill the user request." }, { "role": "user", "content": "this is my request." } ], "model": "gpt-3.5-turbo" } */ HashMap requestMap = new HashMap<>(); requestMap.put( "model", "gpt-3.5-turbo" ); List> messages = new ArrayList<>(); HashMap systemMsg = new HashMap<>(); systemMsg.put( "role", "system" ); systemMsg.put( "content", configuration.get( CoWorkGPTBotStructureProvider.OPENAI_SYSTEM_PROMPT ) ); messages.add( systemMsg ); HashMap userMsg = new HashMap<>(); userMsg.put( "role", "user" ); userMsg.put( "content", text.substring( "gpt".length() ) ); // the command is prefixed messages.add( userMsg ); requestMap.put( "messages", messages ); String jsonInputString = new Json().toJson( requestMap ); try (java.io.OutputStream os = con.getOutputStream()) { byte[] input = jsonInputString.getBytes( StandardCharsets.UTF_8 ); os.write( input, 0, input.length ); } /* Example JSON response: { "id": "chatcmpl-6uIZPP8pDKlICUIapAIY9dPuxDZRf", "object": "chat.completion", "created": 1678875771, "model": "gpt-3.5-turbo-0301", "usage": { "prompt_tokens": 33, "completion_tokens": 33, "total_tokens": 66 }, "choices": [ { "message": { "role": "assistant", "content": "Hello!" }, "finish_reason": "stop", "index": 0 } ] } */ try (Scanner scanner = new Scanner( con.getInputStream(), StandardCharsets.UTF_8.name() )) { String next = scanner.useDelimiter( "\\A" ).next(); HashMap response = new Json().fromJson( next, HashMap.class ); List choices = (List)response.get( "choices" ); HashMap c1 = (HashMap)choices.get( 0 ); HashMap m = (HashMap)c1.get( "message" ); String content = (String)m.get( "content" ); // As of 23.4, this is still internal API but this is how you edit an existing message CoWorkManager.getInstance().updateMessage( channelId, newMessage.getId(), content ); } } catch( Exception e ) { // As of 23.4, this is still internal API but this is how you edit an existing message CoWorkManager.getInstance().updateMessage( channelId, newMessage.getId(), MSG.getMsg( "error" ) ); } }); return true; } /** {@inheritDoc} */ @Nullable @Override public List getCommands( GUID guid ) { List commands = new ArrayList<>(); commands.add( new CommandDescription( "gpt ", MSG.getMsg( "gptcommanddescription" ) ) ); return commands; } }