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")
}
}
}
}