diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7181031..da40796 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,10 +19,13 @@ activityCompose = "1.8.2" composeBom = "2024.03.00" appcompat = "1.6.1" material = "1.11.0" +materialIconsCoreAndroid = "1.6.5" media3Exoplayer = "1.3.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +androidx-material-icons-core-android = { module = "androidx.compose.material:material-icons-core-android", version.ref = "materialIconsCoreAndroid" } +androidx-material-icons-extended-android = { module = "androidx.compose.material:material-icons-extended-android", version.ref = "materialIconsCoreAndroid" } androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3Exoplayer" } androidx-media3-ui = { module = "androidx.media3:media3-ui", version.ref = "media3Exoplayer" } junit = { group = "junit", name = "junit", version.ref = "junit" } diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/OpenAI.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/OpenAI.kt index 208a5ad..65982c1 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/OpenAI.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/OpenAI.kt @@ -6,9 +6,11 @@ package dev.sunnat629.ai_client -import dev.sunnat629.ai_client.KoinModules.openAiAndroidLibModuleKoin +import dev.sunnat629.ai_client.di.KoinModules.openAiAndroidLibModuleKoin import dev.sunnat629.ai_client.clients.Audio import dev.sunnat629.ai_client.clients.Chat +import dev.sunnat629.ai_client.clients.Embeddings +import dev.sunnat629.ai_client.clients.File import dev.sunnat629.ai_client.clients.Models import dev.sunnat629.ai_client.clients.Moderations import dev.sunnat629.ai_client.models.openaAI.OpenAIBuilderConfig @@ -21,6 +23,8 @@ interface OpenAI { val models: Models val moderations: Moderations val audio: Audio + val embeddings: Embeddings + val file: File } internal class OpenAIImpl(configModel: OpenAIBuilderConfig) : OpenAI, KoinComponent { @@ -37,6 +41,12 @@ internal class OpenAIImpl(configModel: OpenAIBuilderConfig) : OpenAI, KoinCompon private val _audio: Audio by inject() override val audio: Audio get() = _audio + private val _embeddings: Embeddings by inject() + override val embeddings: Embeddings get() = _embeddings + + private val _file: File by inject() + override val file: File get() = _file + init { openAiAndroidLibModuleKoin(configModel) } diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/assistants/AssistantRepositoryImpl.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/assistants/AssistantRepositoryImpl.kt index 3ac10ab..4b2e064 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/assistants/AssistantRepositoryImpl.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/assistants/AssistantRepositoryImpl.kt @@ -8,7 +8,6 @@ package dev.sunnat629.ai_client.apis.assistants import dev.sunnat629.ai_client.models.assistants.AssistantResponse import dev.sunnat629.ai_client.models.assistants.CreateAssistantRequest -import dev.sunnat629.ai_client.networks.ApiResult import dev.sunnat629.ai_client.networks.deleteRequest import dev.sunnat629.ai_client.networks.getRequest import dev.sunnat629.ai_client.networks.patchRequest @@ -20,20 +19,20 @@ class AssistantRepositoryImpl(private val httpClient: HttpClient) : AssistantRep private val baseUrl = "https://api.openai.com/v1/assistants" - override suspend fun createAssistant(request: CreateAssistantRequest): ApiResult { + override suspend fun createAssistant(request: CreateAssistantRequest): AssistantResponse { return httpClient.postRequest( url = baseUrl, request = request ) } - override suspend fun listAssistants(): ApiResult> { + override suspend fun listAssistants(): List { return httpClient.getRequest( url = baseUrl ) } - override suspend fun retrieveAssistant(assistantId: String): ApiResult { + override suspend fun retrieveAssistant(assistantId: String): AssistantResponse { return httpClient.getRequest( url = "$baseUrl/$assistantId" ) @@ -42,14 +41,14 @@ class AssistantRepositoryImpl(private val httpClient: HttpClient) : AssistantRep override suspend fun updateAssistant( assistantId: String, request: CreateAssistantRequest - ): ApiResult { + ): AssistantResponse { return httpClient.patchRequest( url = "$baseUrl/$assistantId", request = request ) } - override suspend fun deleteAssistant(assistantId: String): ApiResult { + override suspend fun deleteAssistant(assistantId: String): Unit { return httpClient.deleteRequest( url = "$baseUrl/$assistantId" ) diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/assistants/AssistantsRepository.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/assistants/AssistantsRepository.kt index a38c705..ec087cb 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/assistants/AssistantsRepository.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/assistants/AssistantsRepository.kt @@ -8,25 +8,24 @@ package dev.sunnat629.ai_client.apis.assistants import dev.sunnat629.ai_client.models.assistants.AssistantResponse import dev.sunnat629.ai_client.models.assistants.CreateAssistantRequest -import dev.sunnat629.ai_client.networks.ApiResult // AssistantRepository.kt interface AssistantRepository { /** Creates a new assistant */ - suspend fun createAssistant(request: CreateAssistantRequest): ApiResult + suspend fun createAssistant(request: CreateAssistantRequest): AssistantResponse /** Lists all assistants */ - suspend fun listAssistants(): ApiResult> + suspend fun listAssistants(): List /** Retrieves an assistant by ID */ - suspend fun retrieveAssistant(assistantId: String): ApiResult + suspend fun retrieveAssistant(assistantId: String): AssistantResponse /** Updates an assistant */ suspend fun updateAssistant( assistantId: String, request: CreateAssistantRequest - ): ApiResult + ): AssistantResponse /** Deletes an assistant */ - suspend fun deleteAssistant(assistantId: String): ApiResult + suspend fun deleteAssistant(assistantId: String): Unit } \ No newline at end of file diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/embeddings/EmbeddingsRepository.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/embeddings/EmbeddingsRepository.kt index 56b52f3..d8519ca 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/embeddings/EmbeddingsRepository.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/embeddings/EmbeddingsRepository.kt @@ -6,12 +6,10 @@ package dev.sunnat629.ai_client.apis.embeddings -import dev.sunnat629.ai_client.models.embeddings.CreateEmbeddingsRequest -import dev.sunnat629.ai_client.models.embeddings.CreateEmbeddingsResponse -import dev.sunnat629.ai_client.networks.ApiResult +import dev.sunnat629.ai_client.models.embeddings.EmbeddingsRequest +import dev.sunnat629.ai_client.models.embeddings.EmbeddingsResponse interface EmbeddingsRepository { - // Embeddings Operations - suspend fun createEmbedding(request: CreateEmbeddingsRequest): ApiResult + suspend fun createEmbedding(request: EmbeddingsRequest): EmbeddingsResponse } \ No newline at end of file diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/embeddings/EmbeddingsRepositoryImpl.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/embeddings/EmbeddingsRepositoryImpl.kt index b08773d..798c63e 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/embeddings/EmbeddingsRepositoryImpl.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/embeddings/EmbeddingsRepositoryImpl.kt @@ -6,16 +6,15 @@ package dev.sunnat629.ai_client.apis.embeddings -import dev.sunnat629.ai_client.models.embeddings.CreateEmbeddingsRequest -import dev.sunnat629.ai_client.models.embeddings.CreateEmbeddingsResponse -import dev.sunnat629.ai_client.networks.ApiResult +import dev.sunnat629.ai_client.models.embeddings.EmbeddingsRequest +import dev.sunnat629.ai_client.models.embeddings.EmbeddingsResponse +import dev.sunnat629.ai_client.networks.URLs.EMBEDDINGS import dev.sunnat629.ai_client.networks.postRequest import io.ktor.client.HttpClient class EmbeddingsRepositoryImpl(private val client: HttpClient) : EmbeddingsRepository { - private val baseUrl = "https://api.openai.com/v1/embeddings" - override suspend fun createEmbedding(request: CreateEmbeddingsRequest): ApiResult { - return client.postRequest(baseUrl, request) + override suspend fun createEmbedding(request: EmbeddingsRequest): EmbeddingsResponse { + return client.postRequest(EMBEDDINGS, request) } } \ No newline at end of file diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/files/FilesRepository.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/files/FilesRepository.kt index 63bb19c..502fe90 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/files/FilesRepository.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/files/FilesRepository.kt @@ -9,7 +9,6 @@ package dev.sunnat629.ai_client.apis.files import dev.sunnat629.ai_client.models.files.FileResponse import dev.sunnat629.ai_client.models.files.ListFilesResponse import dev.sunnat629.ai_client.models.files.UploadFileRequest -import dev.sunnat629.ai_client.networks.ApiResult /** * Interface defining operations for managing files with the OpenAI API. @@ -19,31 +18,31 @@ interface FilesRepository { /** * Uploads a file to the OpenAI API for use with various services like fine-tuning. * - * @param file The file to be uploaded. - * @return ApiResult Result of the file upload operation. + * @param request The require contents for the API + * @return FileResponse Result of the file upload operation. */ - suspend fun uploadFile(file: FileResponse): ApiResult + suspend fun uploadFile(request: UploadFileRequest, byteArray: ByteArray?): FileResponse /** * Retrieves a list of files previously uploaded to the OpenAI API. * - * @return ApiResult A list of files. + * @return ListFilesResponse A list of files. */ - suspend fun listFiles(): ApiResult + suspend fun listFiles(): ListFilesResponse /** * Retrieves a specific file by its unique identifier. * * @param fileId The unique identifier of the file to retrieve. - * @return ApiResult The requested file. + * @return FileResponse The requested file. */ - suspend fun retrieveFile(fileId: String): ApiResult + suspend fun retrieveFile(fileId: String): FileResponse /** * Deletes a specific file by its unique identifier. * * @param fileId The unique identifier of the file to delete. - * @return ApiResult The result of the deletion operation. + * @return FileResponse The result of the deletion operation. */ - suspend fun deleteFile(fileId: String): ApiResult + suspend fun deleteFile(fileId: String): FileResponse } \ No newline at end of file diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/files/FilesRepositoryImpl.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/files/FilesRepositoryImpl.kt index dc49c31..2d96e63 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/files/FilesRepositoryImpl.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/files/FilesRepositoryImpl.kt @@ -6,35 +6,65 @@ package dev.sunnat629.ai_client.apis.files +import android.util.Log import dev.sunnat629.ai_client.models.files.FileResponse import dev.sunnat629.ai_client.models.files.ListFilesResponse +import dev.sunnat629.ai_client.models.files.Purpose import dev.sunnat629.ai_client.models.files.UploadFileRequest -import dev.sunnat629.ai_client.networks.ApiResult import dev.sunnat629.ai_client.networks.deleteRequest import dev.sunnat629.ai_client.networks.getRequest import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.request.forms.formData +import io.ktor.client.request.forms.submitFormWithBinaryData +import io.ktor.http.Headers +import io.ktor.http.HttpHeaders +import io.ktor.util.InternalAPI -class FilesRepositoryImpl(private val httpClient: HttpClient) : FilesRepository { - override suspend fun uploadFile(file: FileResponse): ApiResult { - // Implement the upload logic, potentially handling multipart/form-data for file upload - return ApiResult.Failure(NotImplementedError()) +class FilesRepositoryImpl(private val client: HttpClient) : FilesRepository { + + @OptIn(InternalAPI::class) + override suspend fun uploadFile(request: UploadFileRequest, byteArray: ByteArray?): FileResponse { + + val content: Any = when (request.purpose) { + Purpose.FINE_TUNE -> request.fileJsonl + Purpose.ASSISTANTS -> byteArray + } + + val response = client.submitFormWithBinaryData( + url = "files", + formData = formData { + append("purpose", request.purpose.value) + append( + key = "file", + value = content, + headers = Headers.build { + append(HttpHeaders.ContentDisposition, "filename=file.jsonl") + } + ) + } + ) + + Log.e("ASDF", response.body().toString()) + + return response.body() } - override suspend fun listFiles(): ApiResult { - return httpClient.getRequest( - url = "https://api.openai.com/v1/files" + override suspend fun listFiles(): ListFilesResponse { + return client.getRequest( + url = "files" ) } - override suspend fun retrieveFile(fileId: String): ApiResult { - return httpClient.getRequest( - url = "https://api.openai.com/v1/files/$fileId" + override suspend fun retrieveFile(fileId: String): FileResponse { + return client.getRequest( + url = "files/$fileId" ) } - override suspend fun deleteFile(fileId: String): ApiResult { - return httpClient.deleteRequest( - url = "https://api.openai.com/v1/files/$fileId" + override suspend fun deleteFile(fileId: String): FileResponse { + return client.deleteRequest( + url = "/files/$fileId" ) } } \ No newline at end of file diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/fineTuning/FineTuningRepository.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/fineTuning/FineTuningRepository.kt index ef877a7..e9c245c 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/fineTuning/FineTuningRepository.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/fineTuning/FineTuningRepository.kt @@ -8,19 +8,18 @@ package dev.sunnat629.ai_client.apis.fineTuning import dev.sunnat629.ai_client.models.fineTuning.CreateFineTuningRequest import dev.sunnat629.ai_client.models.fineTuning.FineTuningResponse -import dev.sunnat629.ai_client.networks.ApiResult // FineTuningRepository.kt interface FineTuningRepository { /** Creates a fine-tuning job */ - suspend fun createFineTuningJob(request: CreateFineTuningRequest): ApiResult + suspend fun createFineTuningJob(request: CreateFineTuningRequest): FineTuningResponse /** Lists all fine-tuning jobs */ - suspend fun listFineTuningJobs(): ApiResult> + suspend fun listFineTuningJobs(): List /** Retrieves a fine-tuning job by ID */ - suspend fun retrieveFineTuningJob(fineTuneId: String): ApiResult + suspend fun retrieveFineTuningJob(fineTuneId: String): FineTuningResponse /** Cancels a fine-tuning job */ - suspend fun cancelFineTuningJob(fineTuneId: String): ApiResult + suspend fun cancelFineTuningJob(fineTuneId: String): Unit } \ No newline at end of file diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/fineTuning/FineTuningRepositoryImpl.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/fineTuning/FineTuningRepositoryImpl.kt index bd434b5..f39bf50 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/fineTuning/FineTuningRepositoryImpl.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/fineTuning/FineTuningRepositoryImpl.kt @@ -8,7 +8,6 @@ package dev.sunnat629.ai_client.apis.fineTuning import dev.sunnat629.ai_client.models.fineTuning.CreateFineTuningRequest import dev.sunnat629.ai_client.models.fineTuning.FineTuningResponse -import dev.sunnat629.ai_client.networks.ApiResult import dev.sunnat629.ai_client.networks.getRequest import dev.sunnat629.ai_client.networks.postRequest import io.ktor.client.HttpClient @@ -17,26 +16,26 @@ class FineTuningRepositoryImpl(private val httpClient: HttpClient) : FineTuningR private val baseUrl = "https://api.openai.com/v1/fine-tunes" - override suspend fun createFineTuningJob(request: CreateFineTuningRequest): ApiResult { + override suspend fun createFineTuningJob(request: CreateFineTuningRequest): FineTuningResponse { return httpClient.postRequest( url = baseUrl, request = request ) } - override suspend fun listFineTuningJobs(): ApiResult> { + override suspend fun listFineTuningJobs(): List { return httpClient.getRequest( url = baseUrl ) } - override suspend fun retrieveFineTuningJob(fineTuneId: String): ApiResult { + override suspend fun retrieveFineTuningJob(fineTuneId: String): FineTuningResponse { return httpClient.getRequest( url = "$baseUrl/$fineTuneId" ) } - override suspend fun cancelFineTuningJob(fineTuneId: String): ApiResult { + override suspend fun cancelFineTuningJob(fineTuneId: String): Unit { return httpClient.postRequest( url = "$baseUrl/$fineTuneId/cancel", request = "" diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/images/ImageRepository.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/images/ImageRepository.kt index 205297f..720be12 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/images/ImageRepository.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/images/ImageRepository.kt @@ -11,7 +11,6 @@ import dev.sunnat629.ai_client.models.images.CreateImageRequest import dev.sunnat629.ai_client.models.images.CreateImageResponse import dev.sunnat629.ai_client.models.images.CreateImageVariationsRequest import dev.sunnat629.ai_client.models.images.CreateImageVariationsResponse -import dev.sunnat629.ai_client.networks.ApiResult /** * Interface defining operations for creating and managing images with the OpenAI API. @@ -24,7 +23,7 @@ interface ImageRepository { * @param request The request parameters for image creation. * @return ApiResult The created image or images. */ - suspend fun createImage(request: CreateImageRequest): ApiResult + suspend fun createImage(request: CreateImageRequest): CreateImageResponse /** * Edits an existing image according to the specified modifications. @@ -32,7 +31,7 @@ interface ImageRepository { * @param request The request parameters for image editing. * @return ApiResult The edited image. */ - suspend fun editImage(request: CreateImageEditRequest): ApiResult + suspend fun editImage(request: CreateImageEditRequest): CreateImageResponse /** * Creates variations of a given image based on specified parameters. @@ -40,5 +39,5 @@ interface ImageRepository { * @param request The request parameters for creating image variations. * @return ApiResult The created image variations. */ - suspend fun createImageVariations(request: CreateImageVariationsRequest): ApiResult + suspend fun createImageVariations(request: CreateImageVariationsRequest): CreateImageVariationsResponse } \ No newline at end of file diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/images/ImageRepositoryImpl.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/images/ImageRepositoryImpl.kt index dd158c0..f3a28cd 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/images/ImageRepositoryImpl.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/images/ImageRepositoryImpl.kt @@ -11,7 +11,6 @@ import dev.sunnat629.ai_client.models.images.CreateImageRequest import dev.sunnat629.ai_client.models.images.CreateImageResponse import dev.sunnat629.ai_client.models.images.CreateImageVariationsRequest import dev.sunnat629.ai_client.models.images.CreateImageVariationsResponse -import dev.sunnat629.ai_client.networks.ApiResult import dev.sunnat629.ai_client.networks.postRequest import io.ktor.client.HttpClient @@ -19,21 +18,21 @@ class ImageRepositoryImpl(private val client: HttpClient) : ImageRepository { private val baseUrl = "https://api.openai.com/v1/images" - override suspend fun createImage(request: CreateImageRequest): ApiResult { + override suspend fun createImage(request: CreateImageRequest): CreateImageResponse { return client.postRequest( url = "$baseUrl/generations", request = request ) } - override suspend fun editImage(request: CreateImageEditRequest): ApiResult { + override suspend fun editImage(request: CreateImageEditRequest): CreateImageResponse { return client.postRequest( url = "$baseUrl/edits", request = request ) } - override suspend fun createImageVariations(request: CreateImageVariationsRequest): ApiResult { + override suspend fun createImageVariations(request: CreateImageVariationsRequest): CreateImageVariationsResponse { return client.postRequest( url = "$baseUrl/variations", request = request diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/messages/MessagesRepository.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/messages/MessagesRepository.kt index c6e2117..4107ff6 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/messages/MessagesRepository.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/messages/MessagesRepository.kt @@ -10,7 +10,6 @@ import dev.sunnat629.ai_client.models.messages.CreateMessageRequest import dev.sunnat629.ai_client.models.messages.ListMessageFilesResponse import dev.sunnat629.ai_client.models.messages.MessageFileDetails import dev.sunnat629.ai_client.models.messages.MessageResponse -import dev.sunnat629.ai_client.networks.ApiResult // MessageRepository.kt @@ -19,13 +18,13 @@ interface MessageRepository { suspend fun createMessage( threadId: String, request: CreateMessageRequest - ): ApiResult + ): MessageResponse /** Lists all messages in a thread */ - suspend fun listMessages(threadId: String): ApiResult> + suspend fun listMessages(threadId: String): List /** Retrieves a message by ID */ - suspend fun retrieveMessage(threadId: String, messageId: String): ApiResult + suspend fun retrieveMessage(threadId: String, messageId: String): MessageResponse /** * Lists all files associated with a specific message in a thread. @@ -37,7 +36,7 @@ interface MessageRepository { suspend fun listMessageFiles( threadId: String, messageId: String - ): ApiResult + ): ListMessageFilesResponse /** * Retrieves details for a specific file associated with a message in a thread. @@ -54,6 +53,6 @@ interface MessageRepository { threadId: String, messageId: String, fileId: String - ): ApiResult + ): MessageFileDetails } \ No newline at end of file diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/messages/MessagesRepositoryImpl.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/messages/MessagesRepositoryImpl.kt index b35b93a..f68ff30 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/messages/MessagesRepositoryImpl.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/messages/MessagesRepositoryImpl.kt @@ -10,7 +10,6 @@ import dev.sunnat629.ai_client.models.messages.CreateMessageRequest import dev.sunnat629.ai_client.models.messages.ListMessageFilesResponse import dev.sunnat629.ai_client.models.messages.MessageFileDetails import dev.sunnat629.ai_client.models.messages.MessageResponse -import dev.sunnat629.ai_client.networks.ApiResult import dev.sunnat629.ai_client.networks.getRequest import dev.sunnat629.ai_client.networks.postRequest import io.ktor.client.HttpClient @@ -22,14 +21,14 @@ class MessageRepositoryImpl(private val httpClient: HttpClient) : MessageReposit override suspend fun createMessage( threadId: String, request: CreateMessageRequest - ): ApiResult { + ): MessageResponse { return httpClient.postRequest( url = "$baseUrl/$threadId/messages", request = request ) } - override suspend fun listMessages(threadId: String): ApiResult> { + override suspend fun listMessages(threadId: String): List { return httpClient.getRequest( url = "$baseUrl/$threadId/messages" ) @@ -38,7 +37,7 @@ class MessageRepositoryImpl(private val httpClient: HttpClient) : MessageReposit override suspend fun retrieveMessage( threadId: String, messageId: String - ): ApiResult { + ): MessageResponse { return httpClient.getRequest( url = "$baseUrl/$threadId/messages/$messageId" ) @@ -47,7 +46,7 @@ class MessageRepositoryImpl(private val httpClient: HttpClient) : MessageReposit override suspend fun listMessageFiles( threadId: String, messageId: String - ): ApiResult { + ): ListMessageFilesResponse { TODO("Not yet implemented") } @@ -55,7 +54,7 @@ class MessageRepositoryImpl(private val httpClient: HttpClient) : MessageReposit threadId: String, messageId: String, fileId: String - ): ApiResult { + ): MessageFileDetails { TODO("Not yet implemented") } } \ No newline at end of file diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/threads/ThreadsRepository.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/threads/ThreadsRepository.kt index f70bd3e..ae40204 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/threads/ThreadsRepository.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/threads/ThreadsRepository.kt @@ -8,16 +8,15 @@ package dev.sunnat629.ai_client.apis.threads import dev.sunnat629.ai_client.models.threads.CreateThreadRequest import dev.sunnat629.ai_client.models.threads.ThreadResponse -import dev.sunnat629.ai_client.networks.ApiResult // ThreadRepository.kt interface ThreadRepository { /** Creates a new thread */ - suspend fun createThread(request: CreateThreadRequest): ApiResult + suspend fun createThread(request: CreateThreadRequest): ThreadResponse /** Lists all threads */ - suspend fun listThreads(): ApiResult> + suspend fun listThreads(): List /** Retrieves a thread by ID */ - suspend fun retrieveThread(threadId: String): ApiResult + suspend fun retrieveThread(threadId: String): ThreadResponse } \ No newline at end of file diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/threads/ThreadsRepositoryImpl.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/threads/ThreadsRepositoryImpl.kt index 87e0945..c42bee4 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/apis/threads/ThreadsRepositoryImpl.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/apis/threads/ThreadsRepositoryImpl.kt @@ -8,7 +8,6 @@ package dev.sunnat629.ai_client.apis.threads import dev.sunnat629.ai_client.models.threads.CreateThreadRequest import dev.sunnat629.ai_client.models.threads.ThreadResponse -import dev.sunnat629.ai_client.networks.ApiResult import dev.sunnat629.ai_client.networks.getRequest import dev.sunnat629.ai_client.networks.postRequest import io.ktor.client.HttpClient @@ -17,20 +16,20 @@ class ThreadRepositoryImpl(private val httpClient: HttpClient) : ThreadRepositor private val baseUrl = "https://api.openai.com/v1/threads" - override suspend fun createThread(request: CreateThreadRequest): ApiResult { + override suspend fun createThread(request: CreateThreadRequest): ThreadResponse { return httpClient.postRequest( url = baseUrl, request = request ) } - override suspend fun listThreads(): ApiResult> { + override suspend fun listThreads(): List { return httpClient.getRequest( url = baseUrl ) } - override suspend fun retrieveThread(threadId: String): ApiResult { + override suspend fun retrieveThread(threadId: String): ThreadResponse { return httpClient.getRequest( url = "$baseUrl/$threadId" ) diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/clients/Chat.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/clients/Chat.kt index 9592178..ed44ec1 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/clients/Chat.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/clients/Chat.kt @@ -108,7 +108,6 @@ interface Chat { internal class ChatImpl(private val repository: ChatRepository) : Chat { - private var _model: String? = null private var _role: String? = null private var _text: String? = null private var _imageUrl: String? = null @@ -120,6 +119,7 @@ internal class ChatImpl(private val repository: ChatRepository) : Chat { private var _toolChoice: String? = null private var _tools: List? = null + private var _model: String? = null override fun model(model: String): Chat { this._model = model return this diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/clients/Embeddings.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/clients/Embeddings.kt new file mode 100644 index 0000000..1f00c26 --- /dev/null +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/clients/Embeddings.kt @@ -0,0 +1,120 @@ +/** + * @author Mohi Us Sunnat + * @date 07.04.24 + * Copyright ©2024 Sunnat629.dev. All rights reserved. + */ + +package dev.sunnat629.ai_client.clients + +import dev.sunnat629.ai_client.apis.embeddings.EmbeddingsRepository +import dev.sunnat629.ai_client.models.embeddings.EmbeddingsRequest +import dev.sunnat629.ai_client.models.embeddings.EmbeddingsResponse +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow + +interface Embeddings { + + /** + * Sets a single input string for creating embeddings. + * + * @param input The input text to embed. + * @return [Embeddings] instance for chaining. + */ + fun input(input: String): Embeddings + + /** + * Sets a list of input strings for creating embeddings. + * + * @param input The list of input texts to embed. + * @return [Embeddings] instance for chaining. + */ + fun input(input: List): Embeddings + + /** + * Sets the model identifier to use for generating embeddings. + * + * @param model The model identifier. + * @return [Embeddings] instance for chaining. + */ + fun model(model: String): Embeddings + + /** + * Optionally specifies the format for the embeddings. + * + * @param encodingFormat The encoding format, e.g., "float" or "base64". + * @return [Embeddings] instance for chaining. + */ + fun encodingFormat(encodingFormat: String): Embeddings + + /** + * Optionally specifies the number of dimensions for the output embeddings. + * + * @param dimensions The number of dimensions. + * @return [Embeddings] instance for chaining. + */ + fun dimensions(dimensions: Int): Embeddings + + /** + * Optionally specifies a unique identifier for the end-user. + * + * @param user The user identifier. + * @return [Embeddings] instance for chaining. + */ + fun user(user: String): Embeddings + + /** + * Creates the embeddings based on the provided [EmbeddingsRequest]. + * + * @return [Flow]<[EmbeddingsResponse]> that emits the result of the embeddings creation. + */ + fun create(): Flow +} + +class EmbeddingsImpl(private val repository: EmbeddingsRepository): Embeddings { + private var _input: List? = null + private var _model: String? = null + private var _encodingFormat: String? = null + private var _dimensions: Int? = null + private var _user: String? = null + + override fun input(input: String): Embeddings { + this._input = listOf(input) + return this + } + + override fun input(input: List): Embeddings { + this._input = input + return this + } + + override fun model(model: String): Embeddings { + this._model = model + return this + } + + override fun encodingFormat(encodingFormat: String): Embeddings { + this._encodingFormat = encodingFormat + return this + } + + override fun dimensions(dimensions: Int): Embeddings { + this._dimensions = dimensions + return this + } + + override fun user(user: String): Embeddings { + this._user = user + return this + } + + override fun create(): Flow = flow { + val request = EmbeddingsRequest( + model = _model?: throw IllegalArgumentException("Model is required"), + input = _input?: throw IllegalArgumentException("Input is required"), + encodingFormat = _encodingFormat, + dimensions = _dimensions, + user = _user + ) + emit(repository.createEmbedding(request)) + } +} \ No newline at end of file diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/clients/File.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/clients/File.kt new file mode 100644 index 0000000..244cb2a --- /dev/null +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/clients/File.kt @@ -0,0 +1,80 @@ +/** + * @author Mohi Us Sunnat + * @date 07.04.24 + * Copyright ©2024 Sunnat629.dev. All rights reserved. + */ + +package dev.sunnat629.ai_client.clients + +import android.content.Context +import android.net.Uri +import dev.sunnat629.ai_client.apis.files.FilesRepository +import dev.sunnat629.ai_client.di.JsonUtils +import dev.sunnat629.ai_client.models.files.FileResponse +import dev.sunnat629.ai_client.models.files.ListFilesResponse +import dev.sunnat629.ai_client.models.files.Purpose +import dev.sunnat629.ai_client.models.files.UploadFileRequest +import dev.sunnat629.ai_client.utils.uriToByteArray +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow + +interface File { + + fun file(context: Context, file: Uri): File + fun file(context: Context, jsonlFile: String): File + fun purpose(purpose: Purpose): File + suspend fun uploadFile(): Flow + suspend fun listFiles(): Flow + suspend fun retrieveFile(fileId: String): Flow + suspend fun deleteFile(fileId: String): Flow +} + +class FileImpl(private val repository: FilesRepository): File { + + private var _context: Context? = null + private var _file: Uri? = null + private var _jsonlFile: String? = null + private var _purpose: Purpose? = null + + override fun file(context: Context, file: Uri): File { + this._context = context + this._file = file + return this + } + + override fun file(context: Context, jsonlFile: String): File { + this._context = context + this._jsonlFile = jsonlFile + return this + } + + override fun purpose(purpose: Purpose): File { + this._purpose = purpose + return this + } + + override suspend fun uploadFile(): Flow { + return flow { + if ((_file == null ||_jsonlFile == null) && _purpose == null) throw NullPointerException("Content is null") + val fileJsonl = JsonUtils.convertTxtToJsonl(_context, _file!!) ?: throw IllegalArgumentException("Content is null") + val byteArray = uriToByteArray(_context, _file!!) + + + val request = UploadFileRequest(purpose = _purpose!!, fileJsonl = fileJsonl) + emit(repository.uploadFile(request, byteArray)) + } + } + + override suspend fun listFiles(): Flow { + return flow { emit(repository.listFiles()) } + } + + override suspend fun retrieveFile(fileId: String): Flow { + TODO("Not yet implemented") + } + + override suspend fun deleteFile(fileId: String): Flow { + TODO("Not yet implemented") + } + +} \ No newline at end of file diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/di/JsonUtils.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/di/JsonUtils.kt index 45b2d0c..cc99846 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/di/JsonUtils.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/di/JsonUtils.kt @@ -1,6 +1,7 @@ package dev.sunnat629.ai_client.di import android.content.Context +import android.net.Uri import androidx.annotation.RawRes import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -8,6 +9,7 @@ import kotlinx.serialization.json.JsonObject import org.json.JSONException import org.koin.core.component.KoinComponent import org.koin.core.component.inject +import java.io.BufferedReader object JsonUtils : KoinComponent { val json: Json by inject() @@ -35,4 +37,14 @@ object JsonUtils : KoinComponent { fun convertStringFromRaw(context: Context, @RawRes rawFile: Int): String { return context.resources.openRawResource(rawFile).bufferedReader().use { it.readText() } } + + @JvmStatic + fun convertTxtToJsonl(context: Context?, uri: Uri): String? { + val inputStream = context?.contentResolver?.openInputStream(uri) ?: return null + val txtContent = inputStream.bufferedReader().use(BufferedReader::readText) + + return txtContent.lineSequence() + .filter { it.isNotBlank() } + .joinToString("\n") { """{"data": "$it"}""" } + } } \ No newline at end of file diff --git a/openai-android/src/main/java/dev/sunnat629/ai_client/KoinModules.kt b/openai-android/src/main/java/dev/sunnat629/ai_client/di/KoinModules.kt similarity index 91% rename from openai-android/src/main/java/dev/sunnat629/ai_client/KoinModules.kt rename to openai-android/src/main/java/dev/sunnat629/ai_client/di/KoinModules.kt index 4beaef7..cf660ed 100644 --- a/openai-android/src/main/java/dev/sunnat629/ai_client/KoinModules.kt +++ b/openai-android/src/main/java/dev/sunnat629/ai_client/di/KoinModules.kt @@ -4,8 +4,10 @@ * Copyright ©2024 Sunnat629.dev. All rights reserved. */ -package dev.sunnat629.ai_client +package dev.sunnat629.ai_client.di +import dev.sunnat629.ai_client.OpenAI +import dev.sunnat629.ai_client.OpenAIImpl import dev.sunnat629.ai_client.apis.assistants.AssistantRepository import dev.sunnat629.ai_client.apis.assistants.AssistantRepositoryImpl import dev.sunnat629.ai_client.apis.audio.AudioRepository @@ -32,6 +34,10 @@ import dev.sunnat629.ai_client.clients.Audio import dev.sunnat629.ai_client.clients.AudioImpl import dev.sunnat629.ai_client.clients.Chat import dev.sunnat629.ai_client.clients.ChatImpl +import dev.sunnat629.ai_client.clients.Embeddings +import dev.sunnat629.ai_client.clients.EmbeddingsImpl +import dev.sunnat629.ai_client.clients.File +import dev.sunnat629.ai_client.clients.FileImpl import dev.sunnat629.ai_client.clients.Models import dev.sunnat629.ai_client.clients.ModelsImpl import dev.sunnat629.ai_client.clients.Moderations @@ -86,6 +92,8 @@ object KoinModules { private val useCaseModule = module { factory