자, 이제 마지막 단계!!!
네이버 카페에 내용을 올리는 코드를 작성하면, 일단 파이프라인은 완성된다.
하지만 이 과정도 녹록지는 않았다.
일단 kotlin에서 바로 네이버 카페로 올리는걸 시도해봤는데 안됐다. 원인을 생각해보았다:
- 액세스 허가를 받은거는 안드로이드인데, 코틀린으로 바로 포스팅을 시도하려니 잘 안되는 것 같았다.
- 그리고 자료를 찾아보니까 네이버 로그인 먼저 하고나서 로그인 토큰을 받아서 그걸로 네이버 카페에 올리는거까지 해야되는 것 같았다. 참고: 네아로 구현과정
그래서 바로 안드로이드에서 포스트를 올려보는 쪽으로 진행해보도록 하자.
coroutine
참고
일단 업로드를 위해서는 비동기처리를 해야한다고 한다. 안그러면 다음 에러가 뜬다.
android.os.NetworkOnMainThreadException
그래서 코루틴을 사용해서 비동기처리를 했다.
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
import java.net.URLEncoder
class NaverCafePosting {
fun post() = CoroutineScope(Dispatchers.IO).launch {
val token = "..." //애플리케이션 클라이언트 아이디값"
val header = "Bearer $token" // Bearer 다음에 공백 추가
try {
// api url 설정
val clubid = "31180384" // 카페의 고유 ID값: https://cafe.naver.com/informpaper
val menuid = "2" // 카페 게시판 id
val apiURL = "https://openapi.naver.com/v1/cafe/$clubid/menu/$menuid/articles"
val mu = MultipartUtil(apiURL)
// 접근 토큰 헤더 추가
mu.addHeaderField("Authorization", header)
mu.readyToConnect()
// cafe 글쓰기 필수 요청변수 subject 추가
val subject = URLEncoder.encode("네이버 multi-part 이미지 첨부 테스트", "UTF-8")
mu.addFormField("subject", subject)
// cafe 글쓰기 필수 요청변수 content 추가
val content = URLEncoder.encode("<font color='red'>multi-part</font>로 첨부한 글입니다. <br> 이미지 첨부 <br>", "UTF-8")
mu.addFormField("content", content)
// [시작] image 첨부 로직 - 필요시 이미지수 만큼 반복
val uploadFile1 = File("sample.jpeg")
mu.addFilePart("0", uploadFile1)
// [종료] 이미지 첨부 로직 - 필요시 이미지수 만큼 반복
// HTTP 호출 결과 수신
val response = mu.finish()
CoroutineScope(Dispatchers.Main).launch {
println("SERVER REPLIED:")
for (line in response) {
println(line)
}
}
} catch (e: Exception) {
CoroutineScope(Dispatchers.Main).launch {
println(e)
}
}
}
}
이미지 업로드
그 다음 안드로이드 갤러리에서 선택한 이미지를 받아와서 네이버 카페에 request를 보내는 거까지 구현해야 했다.
보니까 사진을 선택하면 imageUri를 구할 수 있고, 이걸 바탕으로 이미지 파일의 경로를 찾아서 서버에 전송하는 것까지 가능하다.
MainActivity.kt
// 결과를 처리하기 위한 ActivityResultLauncher 초기화
resultLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
imageUri = uri
println("imageUri: $imageUri")
NaverCafePosting(this).post(imageUri)
uri?.let {
val base64Image = convertImageToBase64(it)
ImageProcess().imageProcess(base64Image)
}
}
NaverCafePosting.kt
// [시작] image 첨부 로직 - 필요시 이미지수 만큼 반복
// val uploadFile1 = File(imageUri!!.path!!)
// mu.addFilePart("0", uploadFile1)
imageUri?.let { uri ->
// ContentResolver를 사용하여 선택된 이미지 Uri로부터 입력 스트림을 얻습니다.
val inputStream: InputStream? = context.contentResolver.openInputStream(uri)
// context의 캐시 디렉터리에 "upload.jpg"라는 이름으로 임시 파일을 생성합니다.
val file = File(context.cacheDir, "upload.jpg")
// 생성된 임시 파일에 대한 파일 출력 스트림을 엽니다.
val outputStream = FileOutputStream(file)
// 입력 스트림에서 읽은 데이터를 파일 출력 스트림으로 복사합니다. 이 과정에서 실제 이미지 데이터가 임시 파일에 저장됩니다.
inputStream?.copyTo(outputStream)
// MultipartUtil 객체의 addFilePart 메소드를 사용하여 서버로 파일을 업로드할 준비를 합니다.
// "0"은 서버에서 이 파일을 구분하기 위한 키 값입니다.
mu.addFilePart("0", file)
// 파일 업로드 작업이 완료된 후 임시로 생성된 파일을 삭제하여 저장 공간을 확보합니다.
file.delete()
}
// [종료] 이미지 첨부 로직 - 필요시 이미지수 만큼 반복
이렇게 했더니, 맨 처음 나왔던 401에러가 떴다.(처음 구현하고 정리할 때는 네이버 로그인 기능이 필요한지 모르고 구현을 하지 않았다.) 즉, 이미지 파일을 보내는 것까지는 일단 정상으로 돌아간다는 뜻. 따라서 이제 권한을 받아오면 된다.
(네아로 구현 부분은 아래 링크에서 확인할 수 있다.)
이슈) openAI로 작성된 글을 파싱 관련
자 이제 openAI에서 이미지 처리한 것을 카페 글쓰는 부분에 적용하면 된다
그런데, gpt api를 통해서 받은 response를 파싱하고, response 중에서 content의 형태를 다시 파싱하는 과정에서 에러가 자주 발생했다.
처음에는 포스터 이미지를 보고 제목과 요약을 json 형태로 요청해서 이걸 파싱할라 했는데, chatgpt api다 보니 마크다운 형식으로
```json
{
제목:
요약: ```json{
목적:
기타:
등등:
}
```
}
내용````
이런식으로 뱉는 경우가 생겼다. 이럴 때는 파싱을 두 번 했어야 했는데, 코틀린 초보인 나에게는 꽤 번거롭고 이걸로 인해 시간이 많이 뺏길 것 같았다. 그래서 그냥 내려놓고 그냥 요약 부분은 줄글로 받기로 했다.
변경된 프롬프트
이 포스터의 내용을 제목과 요약으로 정리해서 json 형태로 적어줘. 요약은 이 포스터의 목적과 내용 구성에 대해서 줄글 형태로 적어줘. please write in Korean.
그렇게 해서 받았는데, 에러가 떴다. 글 적으면서 생각해보니 액세스 토큰 만료 문제였다. refreshToken으로 accessToken을 갱신시켜야 하는데, 이 부분은 네아로 구현 부분에 정리를 해 놓았다.
참고자료
가장 공이 컸던 chatGPT
관련 포스팅 자료들
이건 한 번 읽어볼만할 것 같다.
오류 코드에 대한 명세
gson
파이썬의 dict같은 kotlin의 자료형
로그인 토큰은 여기서 힌트를 얻었다.
'진행중' 카테고리의 다른 글
[프로젝트] 지역 공공 포스터를 포스팅해보자. 번외) 안드로이드에서 비밀키를 관리하는 법. (0) | 2024.04.09 |
---|---|
[프로젝트] 지역 공공 포스터를 포스팅해보자. 6) 기타 이슈 및 추가 작업 사항 (0) | 2024.04.09 |
[프로젝트] 지역 공공 포스터를 포스팅해보자. 4) chatGPT api에 prompt와 이미지를 전송해서 답변을 받아내기 (0) | 2024.04.09 |
[프로젝트] 지역 공공 포스터를 포스팅해보자. 3) 갤러리에서 이미지를 불러오기 (0) | 2024.04.09 |
[프로젝트] 지역 공공 포스터를 포스팅해보자. 2) 네이버 아이디로 로그인(네아로) 구현 (0) | 2024.04.08 |