diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/auth/SessionManager.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/auth/SessionManager.java index a0e3403..6557d8a 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/auth/SessionManager.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/auth/SessionManager.java @@ -20,10 +20,20 @@ public abstract class SessionManager { + /** + * Checks if the user is logged in by verifying both SAP and Ollama sessions. + * + * @return {@code true} if the user is logged into either SAP or Ollama, {@code false} otherwise. + */ public static boolean isUserLoggedIn() { return (isSapSession() || isOllamaSession()) ? true : false; } + /** + * Checks if an SAP session is active by verifying required memory components. + * + * @return {@code true} if all required SAP session components are present, {@code false} otherwise. + */ public static boolean isSapSession() { MemoryAccessToken memoryAccessToken = MemoryAccessToken.getInstance(); MemoryServiceKey memoryServiceKey = MemoryServiceKey.getInstance(); @@ -34,6 +44,11 @@ public static boolean isSapSession() { || memoryDeployment.isEmpty()) ? false : true; } + /** + * Checks if an Ollama session is active by verifying required memory components. + * + * @return {@code true} if all required Ollama session components are present, {@code false} otherwise. + */ public static boolean isOllamaSession() { MemoryOllamaEndpoint memoryOllamaEndpoint = MemoryOllamaEndpoint.getInstance(); MemoryOllamaModel memoryOllamaModel = MemoryOllamaModel.getInstance(); @@ -69,11 +84,21 @@ public static void logout(final Browser browser, final EclipseMemory eclipseMemo } } + /** + * Clears all active sessions, including both SAP and Ollama sessions. + */ public static void clearAllSessions() { clearSapSession(); clearOllamaSession(); } + /** + * Clears all SAP session-related memory components. + *
+ * This method resets stored access tokens, service keys, resource groups, + * and deployment information associated with the SAP session. + *
+ */ private static void clearSapSession() { MemoryAccessToken.getInstance().clear(); MemoryServiceKey.getInstance().clear(); @@ -81,6 +106,12 @@ private static void clearSapSession() { MemoryDeployment.getInstance().clear(); } + /** + * Clears all Ollama session-related memory components. + *+ * This method resets stored Ollama endpoint and model information. + *
+ */ private static void clearOllamaSession() { MemoryOllamaEndpoint.getInstance().clear(); MemoryOllamaModel.getInstance().clear(); diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/chat/AIClientFactory.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/chat/AIClientFactory.java index 12d8002..b5fd672 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/chat/AIClientFactory.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/chat/AIClientFactory.java @@ -47,6 +47,16 @@ public static IAIClient getClient() { } } + /** + * Creates and returns an {@link IAIClient} for SAP AI Core. + *+ * This method initializes the required memory components, authentication client, + * and deployment details. If the deployment's model name matches an OpenAI model, + * an {@link OpenAIClient} is returned. Otherwise, it returns {@code null}. + *
+ * + * @return an instance of {@link IAIClient} for SAP AI Core, or {@code null} if unsupported. + */ private static IAIClient getClientForSapAiCore() { // Load memory components for access token, service key, resource group, deployment, and message history. MemoryMessageHistory memoryMessageHistory = MemoryMessageHistory.getInstance(); @@ -71,6 +81,16 @@ private static IAIClient getClientForSapAiCore() { } } + /** + * Creates and returns an {@link IAIClient} for Ollama. + *+ * This method initializes the required memory components and + * returns an {@link OllamaClient} instance configured with + * an {@link OllamaClientHelper}. + *
+ * + * @return an instance of {@link OllamaClient}. + */ private static IAIClient getClientForOllama() { MemoryMessageHistory memoryMessageHistory = MemoryMessageHistory.getInstance(); IMemoryObject+ * The {@code OllamaClient} facilitates chat interactions by sending requests + * to an Ollama chat API endpoint and processing responses. It also manages + * message history using an in-memory storage system. + *
+ */ public class OllamaClient implements IAIClient { - - private HttpClient httpClient; - - private IMemoryMessageHistory memoryMessageHistory; - - private IMemoryObject+ * This method constructs a request using the provided chat messages and sends + * it to the configured API endpoint. It then processes the response and returns + * the generated AI message. + *
+ * + * @param messages the list of chat messages forming the conversation history. + * @return the AI-generated response as an {@link IChatMessage}. + * @throws IOException if an I/O error occurs when sending the request. + * @throws InterruptedException if the request is interrupted while waiting for a response. + */ + @Override + public IChatMessage chatCompletion(final List+ * The {@code OllamaClientHelper} is responsible for serializing chat request bodies, + * deserializing chat responses, and retrieving the currently selected Ollama model. + *
+ */ public class OllamaClientHelper implements IOllamaClientHelper { - - private IMemoryObject+ * This class contains the model name, streaming flag, and a list of chat messages. + * It also provides serialization to JSON using the {@link Gson} library. + *
+ */ public class OllamaRequestBody { + /** The name of the AI model to use for chat completion. */ private String model; + /** Indicates whether the chat response should be streamed. */ private boolean stream; + /** The list of chat messages forming the conversation history. */ private List* The {@link Role.RoleSerializer} is registered to handle role serialization. + *
* * @return the JSON representation of this request body as a {@link String}. */ @@ -54,5 +96,4 @@ public String toString() { // @formatter:on return gson.toJson(this); } - -} +} \ No newline at end of file diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/chat/ollama/OllamaRequestResponse.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/chat/ollama/OllamaRequestResponse.java index a476d85..cb76598 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/chat/ollama/OllamaRequestResponse.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/chat/ollama/OllamaRequestResponse.java @@ -2,123 +2,252 @@ import com.google.gson.annotations.SerializedName; +/** + * Represents the response received from the Ollama API after a chat request. + *+ * This class contains details about the generated chat response, including the + * model used, message content, completion status, evaluation metrics, and timing details. + * It is designed for serialization and deserialization using the {@link com.google.gson.Gson} library. + *
+ */ public class OllamaRequestResponse { + /** The name of the AI model used for generating the response. */ private String model; + /** The timestamp when the response was created. */ @SerializedName("created_at") private String createdAt; + /** The chat message generated by the AI model. */ private OllamaChatMessage message; + /** The reason the chat request was completed (e.g., "stop", "length", etc.). */ @SerializedName("done_reason") private String doneReason; + /** Indicates whether the response generation is complete. */ private boolean done; + /** The total duration (in milliseconds) taken to generate the response. */ @SerializedName("total_duration") private long totalDuration; + /** The duration (in milliseconds) taken to load the model before response generation. */ @SerializedName("load_duration") private long loadDuration; + /** The number of tokens processed in the prompt evaluation phase. */ @SerializedName("prompt_eval_count") private int promptEvalCount; + /** The duration (in milliseconds) taken to evaluate the prompt. */ @SerializedName("prompt_eval_duration") private long promptEvalDuration; + /** The number of tokens processed in the main evaluation phase. */ @SerializedName("eval_count") private int evalCount; + /** The duration (in milliseconds) taken for the main evaluation phase. */ @SerializedName("eval_duration") private long evalDuration; + /** + * Retrieves the name of the AI model used. + * + * @return the model name as a {@link String}. + */ public String getModel() { return model; } + /** + * Sets the name of the AI model used. + * + * @param model the model name to set. + */ public void setModel(final String model) { this.model = model; } + /** + * Retrieves the timestamp when the response was created. + * + * @return the creation timestamp as a {@link String}. + */ public String getCreatedAt() { return createdAt; } + /** + * Sets the timestamp when the response was created. + * + * @param createdAt the creation timestamp to set. + */ public void setCreatedAt(final String createdAt) { this.createdAt = createdAt; } + /** + * Retrieves the generated chat message. + * + * @return the chat message as an {@link OllamaChatMessage}. + */ public OllamaChatMessage getMessage() { return message; } + /** + * Sets the generated chat message. + * + * @param message the chat message to set. + */ public void setMessage(final OllamaChatMessage message) { this.message = message; } + /** + * Retrieves the reason why the response generation was completed. + * + * @return the completion reason as a {@link String}. + */ public String getDoneReason() { return doneReason; } + /** + * Sets the reason why the response generation was completed. + * + * @param doneReason the completion reason to set. + */ public void setDoneReason(final String doneReason) { this.doneReason = doneReason; } + /** + * Checks if the response generation is complete. + * + * @return {@code true} if the response is fully generated, {@code false} otherwise. + */ public boolean isDone() { return done; } + /** + * Sets whether the response generation is complete. + * + * @param done {@code true} if the response is fully generated, {@code false} otherwise. + */ public void setDone(final boolean done) { this.done = done; } + /** + * Retrieves the total duration taken to generate the response. + * + * @return the total duration in milliseconds. + */ public long getTotalDuration() { return totalDuration; } + /** + * Sets the total duration taken to generate the response. + * + * @param totalDuration the total duration in milliseconds. + */ public void setTotalDuration(final long totalDuration) { this.totalDuration = totalDuration; } + /** + * Retrieves the duration taken to load the model before response generation. + * + * @return the load duration in milliseconds. + */ public long getLoadDuration() { return loadDuration; } + /** + * Sets the duration taken to load the model before response generation. + * + * @param loadDuration the load duration in milliseconds. + */ public void setLoadDuration(final long loadDuration) { this.loadDuration = loadDuration; } + /** + * Retrieves the number of tokens evaluated in the prompt phase. + * + * @return the prompt evaluation token count. + */ public int getPromptEvalCount() { return promptEvalCount; } + /** + * Sets the number of tokens evaluated in the prompt phase. + * + * @param promptEvalCount the prompt evaluation token count to set. + */ public void setPromptEvalCount(final int promptEvalCount) { this.promptEvalCount = promptEvalCount; } + /** + * Retrieves the duration taken to evaluate the prompt. + * + * @return the prompt evaluation duration in milliseconds. + */ public long getPromptEvalDuration() { return promptEvalDuration; } + /** + * Sets the duration taken to evaluate the prompt. + * + * @param promptEvalDuration the prompt evaluation duration in milliseconds. + */ public void setPromptEvalDuration(final long promptEvalDuration) { this.promptEvalDuration = promptEvalDuration; } + /** + * Retrieves the number of tokens evaluated in the main evaluation phase. + * + * @return the evaluation token count. + */ public int getEvalCount() { return evalCount; } + /** + * Sets the number of tokens evaluated in the main evaluation phase. + * + * @param evalCount the evaluation token count to set. + */ public void setEvalCount(final int evalCount) { this.evalCount = evalCount; } + /** + * Retrieves the duration taken for the main evaluation phase. + * + * @return the evaluation duration in milliseconds. + */ public long getEvalDuration() { return evalDuration; } + /** + * Sets the duration taken for the main evaluation phase. + * + * @param evalDuration the evaluation duration in milliseconds. + */ public void setEvalDuration(final long evalDuration) { this.evalDuration = evalDuration; } -} +} \ No newline at end of file diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/functions/PreferencesHandler.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/functions/PreferencesHandler.java index 1963939..7d45e12 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/functions/PreferencesHandler.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/functions/PreferencesHandler.java @@ -12,22 +12,50 @@ import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.PreferencesUtil; +/** + * Handles opening the preferences dialog in the Eclipse plugin. + *+ * The {@code PreferencesHandler} extends {@link Action} to provide a UI action + * that allows users to access the plugin's settings via the Eclipse preferences page. + * It sets an icon for the action and executes the preferences dialog when triggered. + *
+ */ public class PreferencesHandler extends Action { - - private static final String ICON = "platform:/plugin/org.eclipse.egit.ui/icons/obj16/settings.png"; - - private static final String PREFERENCES_PAGE_ID = "com.developer.nefarious.zjoule.plugin.core.preferences.PluginPreferencesPage"; - + + /** The icon path for the preferences action. */ + private static final String ICON = "platform:/plugin/org.eclipse.egit.ui/icons/obj16/settings.png"; + + /** The preference page ID for the plugin's settings. */ + private static final String PREFERENCES_PAGE_ID = "com.developer.nefarious.zjoule.plugin.core.preferences.PluginPreferencesPage"; + + /** + * Creates and returns an instance of {@code PreferencesHandler}. + * + * @return a new instance of {@code PreferencesHandler}. + */ public static PreferencesHandler create() { return new PreferencesHandler(); } - + + /** + * Private constructor to prevent direct instantiation. + *+ * This constructor initializes the action's text, tooltip, and icon. + *
+ */ private PreferencesHandler() { setText("Preferences"); setToolTipText("User settings."); setIcon(); } - + + /** + * Opens the preferences dialog for the plugin when the action is triggered. + *+ * This method invokes the Eclipse Preferences API to display the preference + * dialog corresponding to {@link #PREFERENCES_PAGE_ID}. + *
+ */ @Override public void run() { PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(null, PREFERENCES_PAGE_ID, null, null); @@ -35,7 +63,14 @@ public void run() { dialog.open(); } } - + + /** + * Sets the icon for the preferences action. + *+ * The method attempts to load the icon from the specified URL. If the URL + * is invalid or cannot be loaded, it falls back to a default Eclipse info icon. + *
+ */ private void setIcon() { try { URI iconURI = new URI(ICON); @@ -46,5 +81,4 @@ private void setIcon() { setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK)); } } - -} +} \ No newline at end of file diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/preferences/InputField.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/preferences/InputField.java index 15ecba3..dc97c94 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/preferences/InputField.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/preferences/InputField.java @@ -5,21 +5,53 @@ import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; +/** + * Represents a customizable input field for user preferences. + *+ * The {@code InputField} extends {@link StringFieldEditor} and provides an + * input text field with a fixed width and height. It is designed for use in + * Eclipse preference pages to capture user input with validation on focus loss. + *
+ */ public class InputField extends StringFieldEditor { - - private static final int WIDTH_IN_CHARS = 10; - - private static final int HEIGTH_IN_CHARS = 2; - - private static final int MINIMUM_WIDTH = 300; - - private static final int MINIMUM_HEIGHT = 50; - - public InputField(final String key, final String labelText, final Composite parent) { - super(key, labelText, WIDTH_IN_CHARS, HEIGTH_IN_CHARS, VALIDATE_ON_FOCUS_LOST, parent); - setFixedWidth(parent); - } + /** Default width of the input field in characters. */ + private static final int WIDTH_IN_CHARS = 10; + + /** Default height of the input field in characters. */ + private static final int HEIGTH_IN_CHARS = 2; + + /** Minimum width of the input field in pixels. */ + private static final int MINIMUM_WIDTH = 300; + + /** Minimum height of the input field in pixels. */ + private static final int MINIMUM_HEIGHT = 50; + + /** + * Constructs an {@code InputField} with the specified key, label, and parent composite. + *+ * This constructor initializes the text field with predefined dimensions and attaches + * it to the specified parent composite. + *
+ * + * @param key the preference key associated with this input field. + * @param labelText the label text displayed next to the input field. + * @param parent the parent {@link Composite} in which this field is created. + */ + public InputField(final String key, final String labelText, final Composite parent) { + super(key, labelText, WIDTH_IN_CHARS, HEIGTH_IN_CHARS, VALIDATE_ON_FOCUS_LOST, parent); + setFixedWidth(parent); + } + + /** + * Sets a fixed width and height for the input field. + *+ * This method ensures the input field has a minimum width and height + * by applying a {@link GridData} layout to its text control. + *
+ * + * @param parent the parent {@link Composite} containing the input field. + */ private void setFixedWidth(final Composite parent) { if (getTextControl(parent) != null) { GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); @@ -28,5 +60,4 @@ private void setFixedWidth(final Composite parent) { getTextControl(parent).setLayoutData(gridData); } } - -} +} \ No newline at end of file diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/preferences/OutputField.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/preferences/OutputField.java index 134ffc2..3556d7e 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/preferences/OutputField.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/preferences/OutputField.java @@ -6,23 +6,58 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Text; +/** + * Represents a read-only output field for displaying values in an Eclipse preference page. + *+ * The {@code OutputField} extends {@link StringFieldEditor} but overrides its behavior + * to prevent storing, loading, or modifying values through the preference store. The field + * is displayed as a read-only text field with a fixed width. + *
+ */ public class OutputField extends StringFieldEditor { - - private String currentValue = ""; // To hold the temporary value - - private static final int MINIMUM_WIDTH = 300; - - public OutputField(final String labelText, final String value, final Composite parent) { + + /** Holds the temporary value for the field since it is not stored in preferences. */ + private String currentValue = ""; + + /** Minimum width of the output field in pixels. */ + private static final int MINIMUM_WIDTH = 300; + + /** + * Constructs an {@code OutputField} with the specified label and initial value. + *+ * The field is initialized with the given value and displayed in the specified parent composite. + *
+ * + * @param labelText the label text displayed next to the field. + * @param value the initial value to display in the field. + * @param parent the parent {@link Composite} in which this field is created. + */ + public OutputField(final String labelText, final String value, final Composite parent) { super("local", labelText, parent); setStringValue(value); setFixedWidth(parent); } + /** + * Overrides the default load behavior to prevent resetting the value. + *+ * This method is intentionally left empty to ensure that the field + * does not load any default values from the preference store. + *
+ */ @Override protected void doLoadDefault() { // Do nothing to prevent the value from being reset } - + + /** + * Creates the UI control for the output field and sets it to read-only. + *+ * This method ensures that the text field cannot be edited by the user. + *
+ * + * @param parent the parent {@link Composite} in which this field is created. + */ @Override protected void createControl(final Composite parent) { super.createControl(parent); @@ -33,28 +68,66 @@ protected void createControl(final Composite parent) { textField.setEditable(false); } } - + + /** + * Overrides the store behavior to prevent saving the value. + *+ * This method is intentionally left empty to ensure that the field + * does not store any values in the preference store. + *
+ */ @Override protected void doStore() { // Do nothing, as we don't want to store the value } + /** + * Overrides the load behavior to prevent loading a value from preferences. + *+ * This method is intentionally left empty to ensure that the field + * does not retrieve any stored values from the preference store. + *
+ */ @Override protected void doLoad() { // Do nothing, as we don't want to load from the preference store } + /** + * Sets the displayed value of the output field. + *+ * This value is stored locally and not persisted to the preference store. + *
+ * + * @param value the new value to display in the field. + */ @Override public void setStringValue(final String value) { super.setStringValue(value); this.currentValue = value; // Keep the value locally } + /** + * Retrieves the current value displayed in the output field. + *+ * This method returns the locally stored value instead of fetching from preferences. + *
+ * + * @return the current value of the field as a {@link String}. + */ @Override public String getStringValue() { return this.currentValue; // Return the locally stored value } - + + /** + * Sets a fixed width for the output field. + *+ * This method ensures the field has a minimum width by applying a {@link GridData} layout. + *
+ * + * @param parent the parent {@link Composite} containing the output field. + */ private void setFixedWidth(final Composite parent) { // Retrieve the text control from the StringFieldEditor if (getTextControl(parent) != null) { @@ -63,5 +136,4 @@ private void setFixedWidth(final Composite parent) { getTextControl(parent).setLayoutData(gridData); } } - -} +} \ No newline at end of file diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/preferences/PluginPreferencesPage.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/preferences/PluginPreferencesPage.java index 15d9da3..0996afd 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/preferences/PluginPreferencesPage.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/core/preferences/PluginPreferencesPage.java @@ -19,132 +19,183 @@ import com.developer.nefarious.zjoule.plugin.models.Deployment; import com.developer.nefarious.zjoule.plugin.models.OllamaModel; +/** + * Represents the preference page for configuring plugin settings. + *+ * The {@code PluginPreferencesPage} allows users to configure settings + * related to SAP AI Core and Ollama AI models. It dynamically determines + * which settings to display based on the active session type. + *
+ */ public class PluginPreferencesPage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { - - private static final int SPACER_SIZE = 10; - - private static final int SPACER_WIDTH = 10; - - private static final int SPACER_HEIGHT = 10; - - public PluginPreferencesPage() { - super(GRID); - } - - @Override - public void init(final IWorkbench workbench) { - setPreferenceStore(Activator.getDefault().getPreferenceStore()); - } - - @Override - protected void createFieldEditors() { - - displayInstructionsInput(); - - createSpacer(); - - if (SessionManager.isSapSession()) { - displaySapSettings(); - } else if (SessionManager.isOllamaSession()) { - displayOllamaSettings(); - } - - } - - private void displayInstructionsInput() { - Group group = new Group(getFieldEditorParent(), SWT.NONE); - group.setText("Chat Settings"); - group.setLayout(new GridLayout(1, false)); - group.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); - - Composite groupContent = new Composite(group, SWT.NONE); - groupContent.setLayout(new GridLayout(1, false)); - groupContent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - - addField(new InputField(Instruction.KEY, "Instructions:", groupContent)); - } - - private void createSpacer() { - Composite spacer = new Composite(getFieldEditorParent(), SWT.NONE); - GridData gridData = new GridData(SPACER_WIDTH,SPACER_HEIGHT); - gridData.heightHint = SPACER_SIZE; - spacer.setLayoutData(gridData); - } - - private Composite createContentContainer(final String title) { - Group group = new Group(getFieldEditorParent(), SWT.NONE); - group.setText(title); - group.setLayout(new GridLayout(1, false)); - group.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); - - Composite groupContent = new Composite(group, SWT.NONE); - groupContent.setLayout(new GridLayout(1, false)); - groupContent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - return groupContent; - } - - private void displaySapSettings() { - Composite contentContainer = createContentContainer("SAP AI Core Configuration Parameters"); - - class OutputFieldFactory { - StringFieldEditor create(final String key, final String value) { - return new OutputField(key, value, contentContainer); - } - } - - OutputFieldFactory outputFieldFactory = new OutputFieldFactory(); - - String resourceGroup = MemoryResourceGroup.getInstance().load(); - addField(outputFieldFactory.create("Resource Group:", resourceGroup)); - - Deployment deployment = MemoryDeployment.getInstance().load(); - - String configurationName = deployment.getConfigurationName(); - addField(outputFieldFactory.create("Configuration Name:", configurationName)); - - String model = deployment.getModelName(); - addField(outputFieldFactory.create("Model:", model)); - - String version = deployment.getModelVersion(); - addField(outputFieldFactory.create("Version:", version)); - - String deploymentUrl = deployment.getDeploymentUrl(); - addField(outputFieldFactory.create("Deployment Url:", deploymentUrl)); - } - - private void displayOllamaSettings() { - Composite contentContainer = createContentContainer("Ollama Configuration Parameters"); - - class OutputFieldFactory { - StringFieldEditor create(final String key, final String value) { - return new OutputField(key, value, contentContainer); - } - } - - OutputFieldFactory outputFieldFactory = new OutputFieldFactory(); - - String endpoint = MemoryOllamaEndpoint.getInstance().load(); - addField(outputFieldFactory.create("Endpoint:", endpoint)); - - OllamaModel ollamaModel = MemoryOllamaModel.getInstance().load(); - - String name = ollamaModel.getName(); - addField(outputFieldFactory.create("Name:", name)); - - String model = ollamaModel.getModel(); - addField(outputFieldFactory.create("Model:", model)); - - String format = ollamaModel.getFormat(); - addField(outputFieldFactory.create("Format:", format)); - - String family = ollamaModel.getFamily(); - addField(outputFieldFactory.create("Family:", family)); - - String parameterSize = ollamaModel.getParameterSize(); - addField(outputFieldFactory.create("Parameter Size:", parameterSize)); - - String quantizationLevel = ollamaModel.getQuantizationLevel(); - addField(outputFieldFactory.create("Quantization Level:", quantizationLevel)); - } - -} + + /** Default spacer size in pixels. */ + private static final int SPACER_SIZE = 10; + + /** Default spacer width in pixels. */ + private static final int SPACER_WIDTH = 10; + + /** Default spacer height in pixels. */ + private static final int SPACER_HEIGHT = 10; + + /** + * Constructs a {@code PluginPreferencesPage} instance. + *+ * This sets up the preference page layout using the Eclipse preference store. + *
+ */ + public PluginPreferencesPage() { + super(GRID); + } + + /** + * Initializes the preference page with the Eclipse workbench. + * + * @param workbench the {@link IWorkbench} instance associated with the preference page. + */ + @Override + public void init(final IWorkbench workbench) { + setPreferenceStore(Activator.getDefault().getPreferenceStore()); + } + + /** + * Creates the field editors for the preference page. + *+ * This method dynamically adds configuration settings based on the session type. + * It displays chat instructions and either SAP AI Core or Ollama configuration settings. + *
+ */ + @Override + protected void createFieldEditors() { + displayInstructionsInput(); + createSpacer(); + + if (SessionManager.isSapSession()) { + displaySapSettings(); + } else if (SessionManager.isOllamaSession()) { + displayOllamaSettings(); + } + } + + /** + * Displays the input field for chat instructions. + */ + private void displayInstructionsInput() { + Group group = new Group(getFieldEditorParent(), SWT.NONE); + group.setText("Chat Settings"); + group.setLayout(new GridLayout(1, false)); + group.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + Composite groupContent = new Composite(group, SWT.NONE); + groupContent.setLayout(new GridLayout(1, false)); + groupContent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + addField(new InputField(Instruction.KEY, "Instructions:", groupContent)); + } + + /** + * Creates a spacer to add vertical spacing in the layout. + */ + private void createSpacer() { + Composite spacer = new Composite(getFieldEditorParent(), SWT.NONE); + GridData gridData = new GridData(SPACER_WIDTH, SPACER_HEIGHT); + gridData.heightHint = SPACER_SIZE; + spacer.setLayoutData(gridData); + } + + /** + * Creates a container group with a given title for organizing settings. + * + * @param title the title of the container group. + * @return a {@link Composite} container for adding UI components. + */ + private Composite createContentContainer(final String title) { + Group group = new Group(getFieldEditorParent(), SWT.NONE); + group.setText(title); + group.setLayout(new GridLayout(1, false)); + group.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + Composite groupContent = new Composite(group, SWT.NONE); + groupContent.setLayout(new GridLayout(1, false)); + groupContent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + return groupContent; + } + + /** + * Displays SAP AI Core configuration settings. + *+ * This method retrieves SAP AI Core parameters from memory and presents + * them as read-only fields. + *
+ */ + private void displaySapSettings() { + Composite contentContainer = createContentContainer("SAP AI Core Configuration Parameters"); + + class OutputFieldFactory { + StringFieldEditor create(final String key, final String value) { + return new OutputField(key, value, contentContainer); + } + } + + OutputFieldFactory outputFieldFactory = new OutputFieldFactory(); + + String resourceGroup = MemoryResourceGroup.getInstance().load(); + addField(outputFieldFactory.create("Resource Group:", resourceGroup)); + + Deployment deployment = MemoryDeployment.getInstance().load(); + + String configurationName = deployment.getConfigurationName(); + addField(outputFieldFactory.create("Configuration Name:", configurationName)); + + String model = deployment.getModelName(); + addField(outputFieldFactory.create("Model:", model)); + + String version = deployment.getModelVersion(); + addField(outputFieldFactory.create("Version:", version)); + + String deploymentUrl = deployment.getDeploymentUrl(); + addField(outputFieldFactory.create("Deployment Url:", deploymentUrl)); + } + + /** + * Displays Ollama AI model configuration settings. + *+ * This method retrieves Ollama parameters from memory and presents + * them as read-only fields. + *
+ */ + private void displayOllamaSettings() { + Composite contentContainer = createContentContainer("Ollama Configuration Parameters"); + + class OutputFieldFactory { + StringFieldEditor create(final String key, final String value) { + return new OutputField(key, value, contentContainer); + } + } + + OutputFieldFactory outputFieldFactory = new OutputFieldFactory(); + + String endpoint = MemoryOllamaEndpoint.getInstance().load(); + addField(outputFieldFactory.create("Endpoint:", endpoint)); + + OllamaModel ollamaModel = MemoryOllamaModel.getInstance().load(); + + String name = ollamaModel.getName(); + addField(outputFieldFactory.create("Name:", name)); + + String model = ollamaModel.getModel(); + addField(outputFieldFactory.create("Model:", model)); + + String format = ollamaModel.getFormat(); + addField(outputFieldFactory.create("Format:", format)); + + String family = ollamaModel.getFamily(); + addField(outputFieldFactory.create("Family:", family)); + + String parameterSize = ollamaModel.getParameterSize(); + addField(outputFieldFactory.create("Parameter Size:", parameterSize)); + + String quantizationLevel = ollamaModel.getQuantizationLevel(); + addField(outputFieldFactory.create("Quantization Level:", quantizationLevel)); + } +} \ No newline at end of file diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/LoginOptionsWizardDialog.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/LoginOptionsWizardDialog.java index c73574f..c215e64 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/LoginOptionsWizardDialog.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/LoginOptionsWizardDialog.java @@ -4,15 +4,36 @@ import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.widgets.Shell; +/** + * A custom wizard dialog for handling login options. + *+ * The {@code LoginOptionsWizardDialog} extends {@link WizardDialog} to present + * a wizard-based interface for user login options. It customizes the finish + * button text to display "Select" instead of the default label. + *
+ */ public class LoginOptionsWizardDialog extends WizardDialog { - - public LoginOptionsWizardDialog(final Shell parentShell, final LoginWizard wizard) { + + /** + * Constructs a {@code LoginOptionsWizardDialog} with the specified parent shell and wizard. + * + * @param parentShell the parent {@link Shell} for the wizard dialog. + * @param wizard the {@link LoginWizard} instance associated with this dialog. + */ + public LoginOptionsWizardDialog(final Shell parentShell, final LoginWizard wizard) { super(parentShell, wizard); } + /** + * Updates the dialog buttons, modifying the finish button text to "Select". + *+ * This override ensures that the finish button is labeled appropriately + * for selecting login options instead of completing a traditional wizard flow. + *
+ */ @Override - public void updateButtons() { + public void updateButtons() { super.updateButtons(); getButton(IDialogConstants.FINISH_ID).setText("Select"); } -} +} \ No newline at end of file diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/LoginWizard.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/LoginWizard.java index a05e6d6..09322ca 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/LoginWizard.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/LoginWizard.java @@ -7,51 +7,97 @@ import com.developer.nefarious.zjoule.plugin.login.pages.LoginOptionsPage; +/** + * A wizard for selecting and initiating the login process for an AI provider. + *+ * The {@code LoginWizard} presents a user interface for choosing between + * different AI provider login options, such as SAP AI Core and Ollama. + * It delegates the login process to the corresponding wizard based on the user's selection. + *
+ */ public class LoginWizard extends Wizard { - - private Shell shell; - + + /** The parent shell for displaying the wizard dialog. */ + private Shell shell; + + /** The browser instance used for authentication during the login process. */ private Browser browser; - + + /** + * Constructs a {@code LoginWizard} with the specified shell and browser. + *+ * This wizard sets up the login selection process and configures the UI title. + *
+ * + * @param shell the parent {@link Shell} for displaying the wizard dialog. + * @param browser the {@link Browser} instance used for login authentication. + */ public LoginWizard(final Shell shell, final Browser browser) { - this.shell = shell; + this.shell = shell; this.browser = browser; setWindowTitle("Setup AI Provider"); } - + + /** + * Adds the login options page to the wizard. + *+ * This page presents the available AI provider login choices to the user. + *
+ */ @Override public void addPages() { addPage(new LoginOptionsPage()); } - @Override - public boolean performFinish() { - LoginOptionsPage loginOptionsPage = (LoginOptionsPage) getPage(LoginOptionsPage.PAGE_ID); - - if (loginOptionsPage.isOption1Selected()) { - startSapAiCoreLogin(); - return true; - } - - if (loginOptionsPage.isOption2Selected()) { - startOllamaLogin(); - return true; - } - - return false; - } - - private void startSapAiCoreLogin() { - SapLoginWizard wizard = new SapLoginWizard(browser); + /** + * Completes the wizard by initiating the login process based on user selection. + *+ * If the user selects SAP AI Core, the {@code startSapAiCoreLogin()} method is triggered. + * If the user selects Ollama, the {@code startOllamaLogin()} method is triggered. + * The wizard completes successfully if a valid selection is made. + *
+ * + * @return {@code true} if the login process starts successfully, {@code false} otherwise. + */ + @Override + public boolean performFinish() { + LoginOptionsPage loginOptionsPage = (LoginOptionsPage) getPage(LoginOptionsPage.PAGE_ID); + + if (loginOptionsPage.isOption1Selected()) { + startSapAiCoreLogin(); + return true; + } + + if (loginOptionsPage.isOption2Selected()) { + startOllamaLogin(); + return true; + } + + return false; + } + + /** + * Initiates the login process for SAP AI Core. + *+ * This method launches a new {@link SapLoginWizard} within a {@link WizardDialog}. + *
+ */ + private void startSapAiCoreLogin() { + SapLoginWizard wizard = new SapLoginWizard(browser); WizardDialog dialog = new WizardDialog(shell, wizard); dialog.open(); - } - - private void startOllamaLogin() { - OllamaLoginWizard wizard = new OllamaLoginWizard(browser); + } + + /** + * Initiates the login process for Ollama. + *+ * This method launches a new {@link OllamaLoginWizard} within a {@link WizardDialog}. + *
+ */ + private void startOllamaLogin() { + OllamaLoginWizard wizard = new OllamaLoginWizard(browser); WizardDialog dialog = new WizardDialog(shell, wizard); dialog.open(); - } - -} + } +} \ No newline at end of file diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/OllamaLoginWizard.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/OllamaLoginWizard.java index 173500a..b76d1fa 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/OllamaLoginWizard.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/OllamaLoginWizard.java @@ -12,34 +12,75 @@ import com.developer.nefarious.zjoule.plugin.login.pages.FirstOllamaLoginWizardPage; import com.developer.nefarious.zjoule.plugin.login.pages.SecondOllamaLoginWizardPage; +/** + * A wizard for handling the Ollama login process. + *+ * The {@code OllamaLoginWizard} guides the user through multiple steps + * to authenticate with Ollama and configure its endpoint and model settings. + * The wizard clears existing sessions before finalizing the login process. + *
+ */ public class OllamaLoginWizard extends Wizard { - - private Browser browser; - - private IOllamaLoginClient ollamaLoginClient; - - public OllamaLoginWizard(final Browser browser) { + + /** The browser instance used for authentication during the login process. */ + private Browser browser; + + /** The client responsible for managing the Ollama login process. */ + private IOllamaLoginClient ollamaLoginClient; + + /** + * Constructs an {@code OllamaLoginWizard} with the specified browser. + *+ * Initializes the wizard with a title and configures an instance of + * {@link OllamaLoginClient} for handling API interactions. + *
+ * + * @param browser the {@link Browser} instance used for authentication. + */ + public OllamaLoginWizard(final Browser browser) { this.browser = browser; setWindowTitle("Login to Ollama"); ollamaLoginClient = new OllamaLoginClient(new OllamaLoginClientHelper()); } - - @Override + + /** + * Adds the necessary pages to the wizard for configuring the Ollama login. + *+ * The wizard includes: + *
+ * This method: + *
+ * This class is used to store and retrieve a list of {@link OllamaModel} + * objects, typically received from an API call. + *
+ */ public class GetOllamaModelsResponse { - + + /** The list of available Ollama models. */ private List+ * The {@code OllamaLoginClient} communicates with the Ollama API to retrieve + * available models. It uses an {@link HttpClient} for HTTP requests and + * an {@link IOllamaLoginClientHelper} for handling request construction and response parsing. + *
+ */ public interface IOllamaLoginClient { + /** + * Retrieves the available Ollama models from the specified endpoint. + *+ * This method sends a GET request to the Ollama API's `/api/tags` endpoint + * and parses the response into a {@link GetOllamaModelsResponse} object. + *
+ * + * @param endpoint the base URL of the Ollama API. + * @return a {@link GetOllamaModelsResponse} containing the list of available models. + * @throws IOException if an I/O error occurs while sending the request. + * @throws InterruptedException if the request is interrupted while waiting for a response. + */ GetOllamaModelsResponse getModels(final String endpoint) throws IOException, InterruptedException; } diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/api/IOllamaLoginClientHelper.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/api/IOllamaLoginClientHelper.java index 2a9ac1c..4666066 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/api/IOllamaLoginClientHelper.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/api/IOllamaLoginClientHelper.java @@ -2,10 +2,29 @@ import java.net.URI; +/** + * A helper interface for handling API requests and responses related to Ollama login. + *+ * The {@code OllamaLoginClientHelper} provides utility methods for creating URIs + * and parsing JSON responses from the Ollama API. + *
+ */ public interface IOllamaLoginClientHelper { + /** + * Creates a {@link URI} from the given endpoint string. + * + * @param endpoint the API endpoint as a {@link String}. + * @return the corresponding {@link URI}. + */ URI createUri(final String endpoint); + /** + * Parses the JSON response body into a {@link GetOllamaModelsResponse} object. + * + * @param responseBody the JSON response from the API. + * @return a {@link GetOllamaModelsResponse} containing the list of available Ollama models. + */ GetOllamaModelsResponse parseOllamaModelsResponseToObject(final String responseBody); } diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/api/OllamaLoginClient.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/api/OllamaLoginClient.java index 757ab93..87b9017 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/api/OllamaLoginClient.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/api/OllamaLoginClient.java @@ -6,21 +6,43 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; +/** + * A client for handling Ollama login-related API interactions. + *+ * The {@code OllamaLoginClient} communicates with the Ollama API to retrieve + * available models. It uses an {@link HttpClient} for HTTP requests and + * an {@link IOllamaLoginClientHelper} for handling request construction and response parsing. + *
+ */ public class OllamaLoginClient implements IOllamaLoginClient { - - private HttpClient httpClient; - - private IOllamaLoginClientHelper ollamaLoginClientHelper; - - public OllamaLoginClient(final IOllamaLoginClientHelper ollamaLoginClientHelper) { - httpClient = HttpClient.newHttpClient(); - this.ollamaLoginClientHelper = ollamaLoginClientHelper; - } - - @Override - public GetOllamaModelsResponse getModels(final String endpoint) - throws IOException, InterruptedException { - URI endpointUri = ollamaLoginClientHelper.createUri(endpoint + "/api/tags"); + + /** The HTTP client used to send API requests. */ + private HttpClient httpClient; + + /** The helper class responsible for constructing requests and parsing responses. */ + private IOllamaLoginClientHelper ollamaLoginClientHelper; + + /** + * Constructs an {@code OllamaLoginClient} with the specified helper. + *+ * Initializes an {@link HttpClient} instance for sending HTTP requests. + *
+ * + * @param ollamaLoginClientHelper an instance of {@link IOllamaLoginClientHelper} + * for request and response handling. + */ + public OllamaLoginClient(final IOllamaLoginClientHelper ollamaLoginClientHelper) { + httpClient = HttpClient.newHttpClient(); + this.ollamaLoginClientHelper = ollamaLoginClientHelper; + } + + /** + * {@inheritDoc} + */ + @Override + public GetOllamaModelsResponse getModels(final String endpoint) + throws IOException, InterruptedException { + URI endpointUri = ollamaLoginClientHelper.createUri(endpoint + "/api/tags"); HttpRequest request = HttpRequest.newBuilder() .uri(endpointUri) @@ -30,6 +52,5 @@ public GetOllamaModelsResponse getModels(final String endpoint) HttpResponse+ * The {@code OllamaLoginClientHelper} provides utility methods for creating URIs + * and parsing JSON responses from the Ollama API. + *
+ */ public class OllamaLoginClientHelper implements IOllamaLoginClientHelper { - - private Gson gson; - - public OllamaLoginClientHelper() { - gson = new Gson(); - } - @Override - public URI createUri(final String endpoint) { - return URI.create(endpoint); - } + /** Gson instance for JSON serialization and deserialization. */ + private Gson gson; - @Override - public GetOllamaModelsResponse parseOllamaModelsResponseToObject(final String responseBody) { - return gson.fromJson(responseBody, GetOllamaModelsResponse.class); - } + /** + * Constructs an {@code OllamaLoginClientHelper} and initializes a {@link Gson} instance. + */ + public OllamaLoginClientHelper() { + gson = new Gson(); + } -} + /** + * {@inheritDoc} + */ + @Override + public URI createUri(final String endpoint) { + return URI.create(endpoint); + } + + /** + * {@inheritDoc} + */ + @Override + public GetOllamaModelsResponse parseOllamaModelsResponseToObject(final String responseBody) { + return gson.fromJson(responseBody, GetOllamaModelsResponse.class); + } +} \ No newline at end of file diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/events/OllamaModelSelectionAdapter.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/events/OllamaModelSelectionAdapter.java index 057a604..dba69fe 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/events/OllamaModelSelectionAdapter.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/events/OllamaModelSelectionAdapter.java @@ -9,39 +9,69 @@ import com.developer.nefarious.zjoule.plugin.memory.IMemoryObject; import com.developer.nefarious.zjoule.plugin.models.OllamaModel; +/** + * A selection adapter for handling Ollama model selection events. + *+ * The {@code OllamaModelSelectionAdapter} listens for selection events on + * the Ollama model dropdown in the {@link SecondOllamaLoginWizardPage}. It retrieves + * the selected model and stores it in memory, while also updating the wizard page's + * completion state. + *
+ */ public class OllamaModelSelectionAdapter extends SelectionAdapter { - - private SecondOllamaLoginWizardPage secondOllamaLoginWizardPage; - - private IMemoryObject+ * If a model is selected, it is stored in memory, and the wizard page + * is marked as complete. If no model is selected, the wizard page remains incomplete. + *
+ * + * @param e the {@link SelectionEvent} triggered by user selection. + */ + @Override public void widgetSelected(final SelectionEvent e) { - String selectedOllamaModelName = secondOllamaLoginWizardPage.getOllamaModelDropdown().getText(); + String selectedOllamaModelName = secondOllamaLoginWizardPage.getOllamaModelDropdown().getText(); if (selectedOllamaModelName.isEmpty()) { - secondOllamaLoginWizardPage.setPageComplete(false); + secondOllamaLoginWizardPage.setPageComplete(false); } else { OllamaModel selectedOllamaModelObject = getSelectedOllamaModelObject(selectedOllamaModelName); memoryOllamaModel.save(selectedOllamaModelObject); secondOllamaLoginWizardPage.setPageComplete(true); } - } -} + } +} \ No newline at end of file diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/memory/TemporaryMemoryOllamaEndpoint.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/memory/TemporaryMemoryOllamaEndpoint.java index ff704a8..b3faf1c 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/memory/TemporaryMemoryOllamaEndpoint.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/memory/TemporaryMemoryOllamaEndpoint.java @@ -4,14 +4,31 @@ import com.developer.nefarious.zjoule.plugin.memory.IMemoryObject; import com.developer.nefarious.zjoule.plugin.memory.MemoryOllamaEndpoint; +/** + * A temporary memory storage for the Ollama endpoint used during the login process. + *+ * The {@code TemporaryMemoryOllamaEndpoint} stores the Ollama endpoint in Eclipse preferences + * temporarily before persisting it permanently. It provides methods to load, save, clear, + * and persist data. This class follows a singleton pattern and requires explicit initialization. + *
+ */ public class TemporaryMemoryOllamaEndpoint implements IMemoryObject+ * This method must be called before accessing {@link #getInstance()}. + *
+ * + * @param eclipseMemory the {@link IEclipseMemory} instance to be used for preference storage. + */ public static void initialize(final IEclipseMemory eclipseMemory) { if (instance == null) { instance = new TemporaryMemoryOllamaEndpoint(eclipseMemory); } } + /** + * Resets the singleton instance. + *+ * This method clears the instance reference, allowing re-initialization. + *
+ */ public static void resetInstance() { instance = null; } + /** + * Private constructor to enforce the singleton pattern. + * + * @param eclipseMemory the {@link IEclipseMemory} instance used for storing preferences. + */ private TemporaryMemoryOllamaEndpoint(final IEclipseMemory eclipseMemory) { this.eclipseMemory = eclipseMemory; } + /** + * {@inheritDoc} + */ @Override public Boolean isEmpty() { String ollamaEndpoint = load(); @@ -42,22 +81,34 @@ public Boolean isEmpty() { return false; } + /** + * {@inheritDoc} + */ @Override public String load() { return eclipseMemory.loadFromEclipsePreferences(KEY); } + /** + * {@inheritDoc} + */ @Override public void persist() { String ollamaEndpoint = eclipseMemory.loadFromEclipsePreferences(KEY); eclipseMemory.saveOnEclipsePreferences(MemoryOllamaEndpoint.KEY, ollamaEndpoint); } + /** + * {@inheritDoc} + */ @Override public void save(final String ollamaEndpoint) { eclipseMemory.saveOnEclipsePreferences(KEY, ollamaEndpoint); } + /** + * {@inheritDoc} + */ @Override public void clear() { eclipseMemory.deleteFromEclipsePreferences(KEY); diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/pages/FirstOllamaLoginWizardPage.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/pages/FirstOllamaLoginWizardPage.java index df58527..97b4301 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/pages/FirstOllamaLoginWizardPage.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/pages/FirstOllamaLoginWizardPage.java @@ -15,87 +15,141 @@ import com.developer.nefarious.zjoule.plugin.login.api.IOllamaLoginClient; import com.developer.nefarious.zjoule.plugin.memory.IMemoryObject; +/** + * The first wizard page for setting up an Ollama instance. + *+ * The {@code FirstOllamaLoginWizardPage} allows the user to enter the local Ollama endpoint + * and validates its existence by retrieving the available models. If the endpoint is invalid, + * an error message is displayed. + *
+ */ public class FirstOllamaLoginWizardPage extends WizardPage { - public static final String PAGE_ID = "Ollama Login First Page"; - - private IOllamaLoginClient ollamaLoginClient; - - private IMemoryObject+ * If the endpoint is empty or invalid, an error message is displayed and navigation + * to the next page is blocked. + *
+ * + * @return the next {@link IWizardPage}, or {@code null} if validation fails. + */ + @Override + public IWizardPage getNextPage() { + + String ollamaEndpoint = endpointText.getText(); + + if (ollamaEndpoint == null || ollamaEndpoint.isEmpty() || ollamaEndpoint.isBlank()) { + displayErrorMessage("Please, enter a local Ollama endpoint to proceed."); + return null; + } + + try { + setAvailableModelsFor(ollamaEndpoint); + } catch (IllegalArgumentException | IOException | InterruptedException e) { + displayErrorMessage("Local instance of Ollama invalid or doesn't exist at the provided address."); + return null; + } + + errorText.setVisible(false); + memoryOllamaEndpoint.save(ollamaEndpoint); + return super.getNextPage(); // Proceed to the next wizard page + } + + /** + * Queries the Ollama API for available models at the specified endpoint. + *+ * This method retrieves available models and updates the second wizard page + * with the options. + *
+ * + * @param ollamaEndpoint the URL of the Ollama instance. + * @throws IOException if an I/O error occurs while querying the API. + * @throws InterruptedException if the request is interrupted. + */ + private void setAvailableModelsFor(final String ollamaEndpoint) throws IOException, InterruptedException { + GetOllamaModelsResponse getOllamaModelsResponse = ollamaLoginClient.getModels(ollamaEndpoint); + SecondOllamaLoginWizardPage secondPage = + (SecondOllamaLoginWizardPage) getWizard().getPage(SecondOllamaLoginWizardPage.PAGE_ID); + secondPage.setOllamaModelsForSelection(getOllamaModelsResponse); + } + + /** + * Displays an error message in the error text field. + * + * @param message the error message to display. + */ + private void displayErrorMessage(final String message) { + errorText.setText(message); + errorText.setVisible(true); + } +} \ No newline at end of file diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/pages/LoginOptionsPage.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/pages/LoginOptionsPage.java index 4a09734..4b00830 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/pages/LoginOptionsPage.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/pages/LoginOptionsPage.java @@ -7,47 +7,82 @@ import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; +/** + * A wizard page for selecting an AI provider during the login process. + *+ * The {@code LoginOptionsPage} presents the user with two options: + *
+ * This method sets up two radio buttons for selecting the AI provider + * and ensures that selecting an option marks the page as complete. + *
+ * + * @param parent the parent composite in which UI components are created. + */ + @Override + public void createControl(final Composite parent) { + Composite container = new Composite(parent, SWT.NONE); + container.setLayout(new GridLayout(1, false)); + + option1 = new Button(container, SWT.RADIO); + option1.setText("SAP AI Core"); + option1.setToolTipText("Select model from the SAP AI Core Generative AI Hub."); + option1.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + option1.addListener(SWT.Selection, event -> setPageComplete(true)); + + option2 = new Button(container, SWT.RADIO); + option2.setText("Ollama (Local)"); + option2.setToolTipText("Select a local Ollama model."); + option2.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + option2.addListener(SWT.Selection, event -> setPageComplete(true)); + + setControl(container); + } +} \ No newline at end of file diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/pages/SecondOllamaLoginWizardPage.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/pages/SecondOllamaLoginWizardPage.java index 09a573e..c97d218 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/pages/SecondOllamaLoginWizardPage.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/pages/SecondOllamaLoginWizardPage.java @@ -17,61 +17,113 @@ import com.developer.nefarious.zjoule.plugin.memory.IMemoryObject; import com.developer.nefarious.zjoule.plugin.models.OllamaModel; +/** + * The second wizard page for selecting an Ollama model. + *+ * The {@code SecondOllamaLoginWizardPage} allows users to select a model from + * a dropdown list populated with available Ollama models retrieved from the API. + * The selection is stored in memory and used during the login process. + *
+ */ public class SecondOllamaLoginWizardPage extends WizardPage { - public static final String PAGE_ID = "Ollama Login Second Page"; - - private Combo ollamaModelDropdown; - - private List+ * This method sets up a dropdown menu for selecting an Ollama model + * and attaches an event listener to handle model selection. + *
+ * + * @param parent the parent composite in which UI components are created. + */ + @Override + public void createControl(final Composite parent) { + Composite container = new Composite(parent, SWT.NONE); + container.setLayout(new GridLayout(2, false)); + + Label modelLabel = new Label(container, SWT.NONE); + modelLabel.setText("Select the Model:"); + + ollamaModelDropdown = new Combo(container, SWT.DROP_DOWN | SWT.READ_ONLY); + ollamaModelDropdown.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + + ollamaModelDropdown.addSelectionListener(new OllamaModelSelectionAdapter(this, memoryOllamaModel)); + + setControl(container); + } + + /** + * Retrieves the list of Ollama models available for selection. + * + * @return a list of {@link OllamaModel} objects. + */ + public List+ * This method extracts model names from the API response and updates + * the selection list. + *
+ * + * @param getOllamaModelsResponse the API response containing the available models. + */ + public void setOllamaModelsForSelection(final GetOllamaModelsResponse getOllamaModelsResponse) { + this.ollamaModelsForSelection = getOllamaModelsResponse.getModels(); + List+ * When the page is hidden, it deselects all options and marks the page as incomplete. + *
+ * + * @param visible {@code true} if the page is being shown, {@code false} otherwise. + */ + @Override + public void setVisible(final boolean visible) { + super.setVisible(visible); + if (!visible) { + ollamaModelDropdown.deselectAll(); + setPageComplete(false); + } + } +} \ No newline at end of file diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/utils/OllamaModelNamesExtractor.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/utils/OllamaModelNamesExtractor.java index fe2d090..f0bdd89 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/utils/OllamaModelNamesExtractor.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/login/utils/OllamaModelNamesExtractor.java @@ -6,9 +6,27 @@ import com.developer.nefarious.zjoule.plugin.login.api.GetOllamaModelsResponse; import com.developer.nefarious.zjoule.plugin.models.OllamaModel; +/** + * A utility class for extracting Ollama model names from API responses. + *+ * The {@code OllamaModelNamesExtractor} provides a static method to convert a + * {@link GetOllamaModelsResponse} into a list of model names. This helps in + * populating dropdown menus or other UI components with available models. + *
+ */ public abstract class OllamaModelNamesExtractor { - - public static List+ * This method retrieves the list of {@link OllamaModel} objects from the response + * and extracts their names into a list of strings. + *
+ * + * @param response the API response containing Ollama models. + * @return a list of model names, or {@code null} if the response is {@code null}. + */ + public static List+ * The {@code MemoryOllamaEndpoint} class stores, retrieves, and clears the Ollama endpoint + * using the Eclipse preferences system. It follows a singleton pattern and must be initialized + * before use. + *
+ */ public class MemoryOllamaEndpoint implements IMemoryObject+ * This method must be called before accessing {@link #getInstance()}. + *
+ * + * @param eclipseMemory the {@link IEclipseMemory} instance to be used for preference storage. + */ public static void initialize(final IEclipseMemory eclipseMemory) { if (instance == null) { instance = new MemoryOllamaEndpoint(eclipseMemory); } } + /** + * Resets the singleton instance. + *+ * This method clears the instance reference, allowing re-initialization. + *
+ */ public static void resetInstance() { instance = null; } + /** + * Private constructor to enforce the singleton pattern. + * + * @param eclipseMemory the {@link IEclipseMemory} instance used for storing preferences. + */ private MemoryOllamaEndpoint(final IEclipseMemory eclipseMemory) { this.eclipseMemory = eclipseMemory; } + /** + * {@inheritDoc} + */ @Override public Boolean isEmpty() { String ollamaEndpoint = load(); @@ -38,16 +77,25 @@ public Boolean isEmpty() { return false; } + /** + * {@inheritDoc} + */ @Override public String load() { return eclipseMemory.loadFromEclipsePreferences(KEY); } + /** + * {@inheritDoc} + */ @Override public void save(final String ollamaEndpoint) { eclipseMemory.saveOnEclipsePreferences(KEY, ollamaEndpoint); } + /** + * {@inheritDoc} + */ @Override public void clear() { eclipseMemory.deleteFromEclipsePreferences(KEY); diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/memory/MemoryResourceGroup.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/memory/MemoryResourceGroup.java index 5b83c46..3a5d5a5 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/memory/MemoryResourceGroup.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/memory/MemoryResourceGroup.java @@ -85,6 +85,9 @@ public void save(final String resourceGroup) { eclipseMemory.saveOnEclipsePreferences(KEY, resourceGroup); } + /** + * {@inheritDoc} + */ @Override public void clear() { eclipseMemory.deleteFromEclipsePreferences(KEY); diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/memory/MemoryServiceKey.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/memory/MemoryServiceKey.java index 1bd46f8..967f2a8 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/memory/MemoryServiceKey.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/memory/MemoryServiceKey.java @@ -101,6 +101,9 @@ public void save(final ServiceKey serviceKey) { eclipseMemory.saveOnEclipsePreferences(KEY, serializedObject); } + /** + * {@inheritDoc} + */ @Override public void clear() { eclipseMemory.deleteFromEclipsePreferences(KEY); diff --git a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/models/OllamaModel.java b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/models/OllamaModel.java index 734a0fe..96ec55f 100644 --- a/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/models/OllamaModel.java +++ b/com.developer.nefarious.zjoule.plugin/src/com/developer/nefarious/zjoule/plugin/models/OllamaModel.java @@ -4,151 +4,316 @@ import com.google.gson.annotations.SerializedName; +/** + * Represents a machine learning model in the Ollama system. + *+ * This class provides metadata about the model, such as its name, size, digest, + * modification date, and additional details contained within {@link OllamaModelDetails}. + * It is designed for serialization and deserialization using the Google Gson library. + *
+ */ public class OllamaModel { - + + /** The name of the model. */ private String name; + /** The model identifier. */ private String model; + /** The timestamp indicating when the model was last modified. */ @SerializedName("modified_at") private String modifiedAt; + /** The size of the model in bytes. */ private long size; + /** The digest hash representing the model's unique fingerprint. */ private String digest; + /** Additional details about the model, including its format, family, and parameters. */ private OllamaModelDetails details; - // Getters and Setters + /** + * Retrieves the name of the model. + * + * @return the model name as a {@link String}. + */ public String getName() { return name; } + /** + * Sets the name of the model. + * + * @param name the model name to set. + */ public void setName(final String name) { this.name = name; } + /** + * Retrieves the model identifier. + * + * @return the model identifier as a {@link String}. + */ public String getModel() { return model; } + /** + * Sets the model identifier. + * + * @param model the model identifier to set. + */ public void setModel(final String model) { this.model = model; } + /** + * Retrieves the last modification timestamp of the model. + * + * @return the modification timestamp as a {@link String}. + */ public String getModifiedAt() { return modifiedAt; } + /** + * Sets the last modification timestamp of the model. + * + * @param modifiedAt the modification timestamp to set. + */ public void setModifiedAt(final String modifiedAt) { this.modifiedAt = modifiedAt; } + /** + * Retrieves the size of the model in bytes. + * + * @return the model size as a {@code long}. + */ public long getSize() { return size; } + /** + * Sets the size of the model in bytes. + * + * @param size the model size to set. + */ public void setSize(final long size) { this.size = size; } + /** + * Retrieves the digest hash of the model. + * + * @return the digest hash as a {@link String}. + */ public String getDigest() { return digest; } + /** + * Sets the digest hash of the model. + * + * @param digest the digest hash to set. + */ public void setDigest(final String digest) { this.digest = digest; } + /** + * Retrieves additional details about the model. + * + * @return the {@link OllamaModelDetails} object containing additional model metadata. + */ public OllamaModelDetails getDetails() { return details; } + /** + * Sets additional details about the model. + * + * @param details the {@link OllamaModelDetails} object to set. + */ public void setDetails(final OllamaModelDetails details) { this.details = details; } - + + /** + * Retrieves the model's format from its details. + * + * @return the model format as a {@link String}. + */ public String getFormat() { return details.getFormat(); } - + + /** + * Retrieves the model's family from its details. + * + * @return the model family as a {@link String}. + */ public String getFamily() { return details.getFamily(); } - + + /** + * Retrieves the model's parameter size from its details. + * + * @return the parameter size as a {@link String}. + */ public String getParameterSize() { return details.getParameterSize(); } - + + /** + * Retrieves the model's quantization level from its details. + * + * @return the quantization level as a {@link String}. + */ public String getQuantizationLevel() { return details.getQuantizationLevel(); } - } +/** + * Represents detailed metadata about an {@link OllamaModel}. + *+ * This class contains attributes such as the parent model, format, family, + * and additional technical details like parameter size and quantization level. + * It is designed for serialization and deserialization using the Google Gson library. + *
+ */ class OllamaModelDetails { - + + /** The parent model from which this model was derived, if applicable. */ @SerializedName("parent_model") private String parentModel; + /** The format of the model, indicating the model type. */ private String format; + /** The family of the model, grouping it within a larger category. */ private String family; + /** A list of families the model belongs to. */ private List