KDT-villainlp / villainlp

노블라블라(novelah blah)은 사용자와 AI가 함께 창의적인 이야기를 만들어 나가는 협업 소설 쓰기 경험을 제공하는 앱입니다
0 stars 1 forks source link

Fix: 사용자가 입력한 title이 같아도 채팅방을 구분하게 하기 #46

Closed vmkmym closed 8 months ago

vmkmym commented 8 months ago

db 규칙 변경

{
  "rules": {
    ".read": "now < 1893456000000",  // 2025-1-1
    ".write": "now < 1893456000000",  // 2025-1-1
    "gpt35": { // open ai 모델 규칙
      ".indexOn": "threadId" 
    },
    "final": { // gemini 모델 규칙
        ".indexOn": "uuid"
    }
  }
}
vmkmym commented 8 months ago

오늘 작업했는데 구분은 잘되는 상태, 근데 로드를 못해옴 (저장은 잘됨) 이것만 고치면 될 듯

vmkmym commented 8 months ago
class GeminiChatModel {
    fun saveChatMessage(geminiChatMessage: GeminiChatMessage, title: String, uuid: String) {
        val database = Firebase.database
        val chatRef = database.getReference("final/$title")
        val newMessageRef = chatRef.push()
        newMessageRef.setValue(geminiChatMessage)

        newMessageRef.child("uuid").setValue(uuid)
    }

    fun saveChatbotMessage(geminiChatbotMessage: GeminiChatMessage, title: String, uuid: String) {
        val database = Firebase.database
        val chatRef = database.getReference("final/$title")
        val newMessageRef = chatRef.push()
        newMessageRef.setValue(geminiChatbotMessage)

        newMessageRef.child("uuid").setValue(uuid)
    }

    fun loadChatMessages(listener: (List<GeminiChatMessage>) -> Unit, title: String, uuid: String) {
        val database = Firebase.database
        val chatRef = database.getReference("final/$title")

        val query = chatRef.orderByChild("uuid").equalTo(uuid)

        query.addValueEventListener(object : ValueEventListener {
            override fun onDataChange(snapshot: DataSnapshot) {
                val messages = mutableListOf<GeminiChatMessage>()
                for (childSnapshot in snapshot.children) {
                    val chatMessage = childSnapshot.getValue(GeminiChatMessage::class.java)
                    chatMessage?.let {
                        messages.add(it)
                    }
                }
                listener(messages)
            }

            override fun onCancelled(error: DatabaseError) {
                // Failed to read value
                Log.w("GeminiChatModel, loadChatMessages", "fail load message", error.toException())
            }
        })
    }

    fun loadChatbotMessages(listener: (List<GeminiChatMessage>) -> Unit, title: String, uuid: String) {
        val database = Firebase.database
        val chatRef = database.getReference("final/$title")

        val query = chatRef.orderByChild("uuid").equalTo(uuid)

        query.addValueEventListener(object : ValueEventListener {
            override fun onDataChange(snapshot: DataSnapshot) {
                val messages = mutableListOf<GeminiChatMessage>()
                for (childSnapshot in snapshot.children) {
                    val chatMessage = childSnapshot.getValue(GeminiChatMessage::class.java)
                    chatMessage?.let {
                        messages.add(it)
                    }
                }
                listener(messages)
            }

            override fun onCancelled(error: DatabaseError) {
                Log.w("GeminiChatModel, loadChatBotMessages", "fail load message", error.toException())
            }
        })
    }
}
hongmyeoun commented 8 months ago

무엇이 어떻게 안되는 건지는 모르겠지만, uuid값을 추적해봤습니다. 커밋은 안했어요.

수정 전

Firebase DB

image

Realtime DB

image image

발견한 문제

uuid 값이 다름 , 채팅을 보낼 때도 문장마다 다름

================================================================================

수정 과정

uuid 값이 다름 , 채팅을 보낼 때도 문장마다 다름 -> 왜 다른지 확인 -> Realtime DB에 보낼때? == uuid값을 매개변수로 받아옴(어디서?) -> ChatListScreen에서 받아옴 -> $novelInfo.uuid로 받아옴(novelInfo에 uuid를 어디서 만들지?) -> val uuid: String = UUID.randomUUID().toString() 기본값으로 생성해줌(값을 지정 안해주면 랜덤 생성이 됨) -> 값이 지정 안됐을 것 같음(어디서?) -> 불러올 때 어떻게 불러오는지 확인 -> documentId값을 넣어주려고 novelInfo값을 전부 대입시켰음(지금 보면 db에 올릴때 documentID값을 만들어줘서 필요없는 로직) -> 이때 uuid값을 대입 시켜주지 않음(uuid가 랜덤으로 생성됨) -> 로직 변경(user_id만 같다면 data를 그냥 불러옴) -> uuid값을 db에 올린 값을 계속 사용

변경전 코드(Firebase Tool 위치)
        suspend fun fetchNovelInfoDataFromFirestore(userId: String): List<NovelInfo> =
        suspendCoroutine { continuation ->
            val db = FirebaseFirestore.getInstance()
            val result = mutableListOf<NovelInfo>()

            db.collection("NovelInfo")
                .orderBy("createdDate", Query.Direction.DESCENDING)
                .get().addOnSuccessListener { querySnapshot ->
                    for (document in querySnapshot) {
                        val novelInfoId = document.id
                        val novelInfo = document.toObject(NovelInfo::class.java)
                        if (novelInfo.userID == userId) {
                            val bookWithId = NovelInfo(
                                novelInfo.title,
                                novelInfo.assistId,
                                novelInfo.threadId,
                                novelInfo.userID,
                                novelInfo.createdDate,
                                novelInfoId
                            )
                            result.add(bookWithId)
                        }
                    }
                    continuation.resume(result)
                }.addOnFailureListener { exception ->
                    println("Error getting documents: $exception")
                    continuation.resumeWithException(exception)
                }
        }

변경 후 코드
    suspend fun fetchNovelInfoDataFromFirestore(userId: String): List<NovelInfo> = coroutineScope {
        val db = FirebaseFirestore.getInstance()

        try {
            db.collection("NovelInfo")
                .orderBy("createdDate", Query.Direction.DESCENDING)
                .get().await().documents.mapNotNull { document ->
                    val novelInfo = document.toObject(NovelInfo::class.java)
                    if (novelInfo?.userID == userId) {
                        novelInfo
                    } else {
                        null
                    }
                }
        } catch (e: Exception) {
            println("Error getting documents: $e")
            emptyList()
        }
    }

================================================================================

수정 후

Firebase DB

image

Realtime DB

image image

uuid 값이 같아짐

vmkmym commented 8 months ago
data class NovelInfo(
    val title: String = "",
    val assistId: String = "",
    val threadId: String = "",
    val userID: String = "",
    val createdDate: String = "",
    val documentID: String? = null,
    val uuid: String = ""
)

데이터 클래스를 호출할 때 랜덤값 생성이 아니라 assistId, threadId, createdDate처럼 값이 생성되어야 할 때 만들어주고 할당된 값을 재사용하는 방식으로 로직을 짜보려고 함

vmkmym commented 8 months ago

해결과정

  1. data class NovelInfouuid 필드를 String으로 선언해준다.
  2. Create Ground.kt에서 showGeminiDialog일 때 confirmButton을 누를 때 val currentUUID = UUID.randomUUID().toString()를 선언해줘서 채팅방을 만들 때 고유값을 랜덤 생성해준다. 그 값을 NovelInfo 객체에 uuid = currentUUID로 할당해준다.
  3. saveNovelInfoNovelInfo.uuid를 추가해준다.
  4. GeminiChatScreen.kt, ChatListScreen.kt, GeminiChatModel.kt, GeminiChatViewModel.kt에서 uuid매개변수를 추가해준다.
  5. test를 해보면 uuid값이 채팅방마다 고유값으로 설정되기 때문에 동일한 title이어도 채팅방을 구분할 수 있다.