저번 AI_TOP_100 1차에서 예선 탈락한 이후, 다음 대회가 열린다면 열심히 준비하겠다고 다짐하고 있었다. 그리고 마침, 6개월도 안지나서 AI_TOP_100(Campus)대회가 열린 것이다! 본선만 가도 TOP 100명에 든 것이니, 본선만 가자는 마인드로 준비했다. 예선 준비지난번에 탈락했을 때 고전했던 부분이 OCR에 대한 부분이였다. 아예 준비를 안하다보니, AI에 흐릿한 사진 파일들을 주고 진행했고 문제가 잘 풀리지 않았다. 하지만 예선이니만큼, 어마어마한 준비를 하지는 않고 CLOVA OCR를 신청해두는 정도로 준비했다.바로 예선에서 OCR을 활용하는 문제가 출제되었고(이제보니 단골같다. AI를 별 생각 없이 쓰는 사람을 구별해낼 수 있는 좋은 방법이라고 생각하는 것 같고, 실제로 그러한..
전체 글
전공 이외의 것들은 여기 작성하고 있습니다→https://blog.naver.com/7chabin외부 API를 프록시하는 서버에서 동시 요청이 몰릴 때 429를 근본적으로 차단하는 방법을 정리한다.배경: 모의투자 앱의 캔들 차트모의투자 서비스에서 종목 상세 화면의 캔들 차트는 과거 봉 데이터가 필요하다. 유저가 차트를 왼쪽으로 스크롤(페이지네이션)하면 서버가 Upbit REST API에서 과거 캔들을 가져와 DB에 저장한 뒤 응답한다.클라이언트 → 우리 서버 → Upbit API (캔들 조회) ↓ DB 저장 (캐시) ↓ 클라이언트에 응답한 번 DB에 저장된 구간은 이후 요청에서 Upbit를 거치지 않고 바로 응답한다. 문제는 아직 적재되지 않은 구간을 여러 유저가 동시에 요청할 때다.클라이언트에서 직..
https://www.acmicpc.net/problem/1759 문제분석단 한번에 풀어서 너무 감동적인, 뜻깊은 문제다.사실 단 한번에 풀린만큼, 그렇게 어려운 내용은 아니다. L만큼의 암호 길이를 만들어야 하고, C만큼 제공된 문자 종류를 활용해야 한다. 조건은 모음이 1개 이상, 자음이 2개 이상이다.이 조건을 다 따져가면서 문자를 넣는 것이 아니다. DFS로 모든 경우를 탐색(브루트포스)하면서, 암호가 L길이가 됐을 때 -> 조건 충족한다면 출력 후보에 추가, 충족 안할경우 버림. 이 로직이 끝이다. 추가적으로 탐색을 막기 위해, 남은 문자로 L개 문자 못만드는 경우를 return해줬다. 코드import java.util.*;import java.io.*;public class Main { ..
모의코인 서버를 개발하면서 캔들 backfill 로직에 조용한 성능 문제가 있다는 걸 뒤늦게 발견했다.이 글은 그 문제를 발견하고 고친 과정을 실제 벤치마크 수치와 함께 정리한 기록이다.배경: 캔들 backfill이란모의코인 서버는 Upbit 거래소 API로 시세 데이터를 수집하고, 클라이언트가 차트를 요청하면 DB에서 캔들을 조회해 내려준다.클라이언트가 GET /api/v1/markets/KRW-BTC/candles?interval=1h&count=200 같은 요청을 보냈을 때,해당 시간대 데이터가 DB에 없으면 Upbit API를 호출해 채우는 과정이 backfill이다.문제는 이 backfill을 어떤 방식으로 구현하느냐였다.변경 전: 1분봉이 진리다초기 구현의 철학은 단순했다."1분봉이 원천 데이..
ChatGPT, Claude 같은 LLM 서비스는 토큰을 하나씩 스트리밍으로 내려준다.이때 서버-클라이언트 사이의 프로토콜로 WebSocket과 SSE 중 뭘 써야 할까?왜 이 실험을 했나AI 응답을 실시간으로 전달하는 방법은 크게 두 가지다.SSE (Server-Sent Events): 단순 HTTP GET 위에 text/event-stream으로 서버→클라이언트 단방향 푸시WebSocket: HTTP Upgrade(101)를 거친 뒤 양방향 전이중 통신둘 다 "토큰을 한 글자씩 내려보내는" 용도로는 충분히 동작한다. 하지만 프로토콜 자체의 핸드셰이크 비용, 고부하 안정성, 네트워크 효율은 꽤 다를 수 있다. 실제 AI 호출 없이 프로토콜 순수 비용만 격리해서 측정해봤다.실험 설계서버항목스펙프레임워크S..
https://github.com/chabinhwang/toss-mcp GitHub - chabinhwang/toss-mcp: 토스 개발자 문서(앱인토스, TDS React Native, TDS Mobile) 및 TDS기반 토스 아이토스 개발자 문서(앱인토스, TDS React Native, TDS Mobile) 및 TDS기반 토스 아이콘 정보를 AI에게 제공하는 MCP 서버 - chabinhwang/toss-mcpgithub.com https://github.com/chabinhwang/upbit-mcp GitHub - chabinhwang/upbit-mcp: 업비트 API 문서를 AI에게 제공하는 MCP 서버업비트 API 문서를 AI에게 제공하는 MCP 서버. Contribute to chabinhw..
https://www.acmicpc.net/problem/1937문제분석판다가 갈 수 있는 '가장 긴 거리' 를 알아내는 문제이다. 핵심은 dp를 "얼마나 더 갈 수 있는지 저장" 하는 것이다. 문제를 보면 알겠지만, 모든 칸에서 DFS를 돌아야 한다. 따라서, 가지치기를 통해 DFS횟수를 최소화 하는 것이 가장 중요하다.처음에는 깊이(depth)를 파악하려고 했다. 하지만 이렇게 된다면 DFS를 최소화하지 못하고, 시간초과로 틀리게 된다.따라서, DFS를 할 때 dp에 값이 없으면, 모든 방향 DFS를 돌고 그중 최고값을 저장하게 끔 해야한다.쉽게말해, "애매하게 여러 번 보다, 확실하게 한번" 계산하자는 게 이 문제의 목적이다. 코드import java.util.*;import java.io.*;pu..
https://www.acmicpc.net/problem/1520 문제분석dp[i][j]를, '(i,j)에서 목적지까지 가는 방법의 합' 으로 저장하면서 사용하는 방식이다. 쌩 DFS로만 구현하면 안되고, dfs를 하면서 한번 방문한 노드는 한번만 계산하고, 추후에 또 계산하면 안되는 조건을 지켜야 시간초과가 나지 않는다. 예를들어A->B->CA->D->B->C가 있으면B를 2번 계산하는 게 아니라, 첫번째 B 방문에서 계산을 마쳐야 한다. 코드import java.io.*;import java.util.*;public class Main { static int[][] dp; // [r][c] : 해당 row/col에서 목적지까지 가는 경우의 수 static int[][] map; // 지도..