0% found this document useful (0 votes)
11 views4 pages

Chat AI

Uploaded by

Riki Allshop
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views4 pages

Chat AI

Uploaded by

Riki Allshop
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

package com.riki.

repairpiano

import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.riki.repairpiano.model.*
import kotlinx.coroutines.*
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.HttpException
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.Body
import retrofit2.http.POST

// -------------------- DATA CLASS (UI) --------------------


data class ChatMessage(val text: String, val isUser: Boolean, val showNegotiation:
Boolean = false)

// -------------------- API SERVICE --------------------


interface OpenAiApi {
@POST("v1/chat/completions")
suspend fun createChatCompletion(@Body request: ChatRequest): ChatResponse
}

// -------------------- CLIENT --------------------


object OpenAiClient {
private const val BASE_URL = "https://api.openai.com/"
private const val API_KEY =
"Bearer sk-proj-
3cTZv0yyiKOBGuu9oQyZavb8dXm4e2kENqaQJhZ3v87DvlwaU6yoSk8Ka88GL1_irRR5p0XTY1T3BlbkFJ2
JwFDzaN9Cf_fZxfsY0k5FRuC_IvgbQBs4jf-zIKxCRGP1zu13kJncysqSrx28PS_K7pWVnAkA"

private val client = OkHttpClient.Builder()


.addInterceptor { chain: Interceptor.Chain ->
val request = chain.request().newBuilder()
.addHeader("Authorization", API_KEY)
.addHeader("Content-Type", "application/json")
.build()
chain.proceed(request)
}
.build()

private val retrofit = Retrofit.Builder()


.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()

val api: OpenAiApi = retrofit.create(OpenAiApi::class.java)


}

// -------------------- ACTIVITY --------------------


class ChatActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ChatScreen()
}
}
}

// -------------------- COMPOSABLE --------------------


@Composable
fun ChatScreen() {
var messages by remember { mutableStateOf(listOf<ChatMessage>()) }
var input by remember { mutableStateOf("") }
var isLoading by remember { mutableStateOf(false) }

val scope = rememberCoroutineScope()

fun sendMessage(userMessage: String) {


// Auto-reply check dulu sebelum ke AI
val lowerMsg = userMessage.lowercase()
when {
listOf("nomor", "telepon", "kontak", "hp", "konsultasi").any
{ lowerMsg.contains(it) } -> {
messages = messages + ChatMessage("📞 Hubungi saya di: 0811-25-
6661", false)
return
}

listOf("alamat", "lokasi", "tempat").any { lowerMsg.contains(it) } -> {


messages = messages + ChatMessage("📍 Workshop: Se-Indonesia
Berpusat Jakarta", false)
return
}

listOf("harga", "biaya", "service", "ongkos", "reparasi",


"perbaikan").any { lowerMsg.contains(it) } -> {
messages = messages + ChatMessage(
"💰 Estimasi biaya reparasi mulai dari Rp345.000 – Rp6.789.000
(tergantung level kerusakan dan sparepart yang digunakan).",
false,
showNegotiation = true
)
return
}
}

// Tambahkan pesan user


messages = messages + ChatMessage(userMessage, true)

// Tambahkan indikator loading


isLoading = true
messages = messages + ChatMessage("⏳ AI sedang mengetik...", false)

val oldMessages = messages


scope.launch(Dispatchers.IO) {
try {
val response = OpenAiClient.api.createChatCompletion(
ChatRequest(messages = listOf(ChatMessageReq("user",
userMessage)))
)
val reply = response.choices.firstOrNull()?.message?.content ?: "❌
Kosong"

withContext(Dispatchers.Main) {
isLoading = false
messages = oldMessages.dropLast(1) + ChatMessage(reply, false)
}
} catch (e: HttpException) {
val errorBody = e.response()?.errorBody()?.string()
Log.e("ChatActivity", "HTTP ${e.code()} - $errorBody")
withContext(Dispatchers.Main) {
isLoading = false
messages = messages.dropLast(1) + ChatMessage("⚠️ Error $
{e.code()}", false)
}
} catch (e: Exception) {
Log.e("ChatActivity", "Exception", e)
withContext(Dispatchers.Main) {
isLoading = false
messages = messages.dropLast(1) + ChatMessage("⚠️ $
{e.message}", false)
}
}
}
}

// -------------------- UI --------------------
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
LazyColumn(
modifier = Modifier.weight(1f),
reverseLayout = true
) {
items(messages.reversed()) { msg ->
Column(modifier = Modifier.padding(4.dp)) {
Text(
text = if (msg.isUser) "🧑: ${msg.text}" else "🤖: $
{msg.text}",
style = MaterialTheme.typography.bodyLarge,
)
if (msg.showNegotiation) {
Button(
onClick = {
// 👉 nanti bisa diarahkan ke layar negoisasi
},
modifier = Modifier.padding(top = 4.dp)
) {
Text("Lanjut Nego")
}
}
}
}
}

Row(modifier = Modifier.fillMaxWidth()) {
TextField(
value = input,
onValueChange = { input = it },
modifier = Modifier.weight(1f),
placeholder = { Text("Ketik pesan...") }
)
Button(
onClick = {
if (input.isNotBlank() && !isLoading) {
sendMessage(input)
input = ""
}
},
modifier = Modifier.padding(start = 8.dp)
) {
Text("Kirim")
}
}
}
}

You might also like