All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fi.evolver.ai.spring.provider.openai.OpenAiAssistant Maven / Gradle / Ivy

package fi.evolver.ai.spring.provider.openai;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

import fi.evolver.ai.spring.AssistantContentSubscriber;
import fi.evolver.ai.spring.assistant.Assistant;
import fi.evolver.ai.spring.assistant.AssistantPrompt;
import fi.evolver.ai.spring.assistant.AssistantResponse;
import fi.evolver.ai.spring.chat.prompt.Message;
import fi.evolver.ai.spring.file.AiFile;
import fi.evolver.ai.spring.provider.openai.OpenAiAssistantResponse.AssistantContent;
import fi.evolver.ai.spring.provider.openai.response.assistants.OTool;
import fi.evolver.ai.spring.provider.openai.response.files.OFile;


public class OpenAiAssistant implements Assistant {
	private final OpenAiService openAiService;
	private final String provider;
	private final AssistantPrompt prompt;
	private final Duration timeout;
	private final String id;

	private String beforeId;
	private String threadId;
	private String vectorStoreId;
	private final List fileIds = new ArrayList<>();
	private final boolean hasFileSearchTool;

	OpenAiAssistant(
			OpenAiService openAiService,
			String provider,
			AssistantPrompt prompt,
			String assistantId,
			Duration timeout) {

		this.openAiService = openAiService;
		this.provider = provider;
		this.prompt = prompt;
		this.id = assistantId;
		this.timeout = timeout;
		this.hasFileSearchTool = prompt.tools().stream()
				.map(OTool::type)
				.anyMatch("file_search"::equals);
	}

	@Override
	public AssistantResponse ask(Message message) {
		if (threadId == null)
			threadId = openAiService.createThread(provider).id();

		openAiService.createMessage(provider, threadId, message, timeout);

		NextMessagesPrompt nextMessagesPrompt = NextMessagesPrompt.builder(threadId, id)
				.setProvider(provider)
				.setBeforeId(beforeId)
				.setParameter(OpenAiRequestParameters.STREAM, prompt.getBooleanProperty(OpenAiRequestParameters.STREAM).orElse(false))
				.build();

		AssistantResponse response = openAiService.getNextThreadMessages(nextMessagesPrompt, timeout);

		if (response instanceof OpenAiAssistantResponse)
			response.addSubscriber(new AssistantResponseConsumer(((OpenAiAssistantResponse)response), this));

		return response;
	}

	@Override
	public String addFile(AiFile file) {
		OFile uploadFileResponse = openAiService.uploadFile(provider, file);
		fileIds.add(uploadFileResponse.id());
		addVectorStoreFile(uploadFileResponse.id());
		openAiService.modifyAssistant(prompt.withFilesAndStores(fileIds, vectorStoreId != null ? List.of(vectorStoreId) : List.of()), id);
		return uploadFileResponse.id();
	}

	private void addVectorStoreFile(String fileId) {
		if (!hasFileSearchTool)
			return;

		if (vectorStoreId == null)
			vectorStoreId = openAiService.createVectorStore(provider, fileIds).id();
		else
			openAiService.createVectorStoreFile(provider, vectorStoreId, fileId);
	}

	@Override
	public void deleteFile(String fileId) {
		if (fileIds.remove(fileId)) {
			openAiService.deleteFile(provider, fileId);
			if (vectorStoreId != null)
				openAiService.deleteVectorStoreFile(provider, vectorStoreId, fileId);

			AssistantPrompt updatedPrompt = prompt.withFilesAndStores(fileIds, vectorStoreId != null ? List.of(vectorStoreId) : List.of());
			openAiService.modifyAssistant(updatedPrompt, id);
		}
	}

	@Override
	public void close() {
		if (threadId != null)
			openAiService.deleteThread(provider, threadId);
		openAiService.deleteAssistant(provider, prompt.model(), id);
		for (String fileId: fileIds)
			openAiService.deleteFile(provider, fileId);
		if (vectorStoreId != null)
			openAiService.deleteVectorStore(provider, vectorStoreId);
	}

	@Override
	public String getProvider() {
		return provider;
	}

	private static class AssistantResponseConsumer implements AssistantContentSubscriber {
		private final OpenAiAssistantResponse response;
		private final OpenAiAssistant assistant;

		public AssistantResponseConsumer(OpenAiAssistantResponse response, OpenAiAssistant assistant) {
			this.response = response;
			this.assistant = assistant;
		}

		@Override
		public void onComplete(String status) {
			assistant.beforeId = response.getMessageId();
		}

		@Override
		public void onContent(AssistantContent content) { /* NOOP */ }

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy