fix: server recommendation issues and __DIRECT__ tag visibility

- Fix USD price display: all prices now show in KRW (₩)
- Add Korea region auto-detection: extracts region preference from user messages
- Fix low-spec recommendation for high-performance requirements:
  - Add extractTechStack() to detect PostgreSQL, Redis, MongoDB keywords
  - Enhance inferExpectedUsers() to consider tech stack complexity
  - SaaS/B2B services now recommend 4GB+ RAM servers
- Fix __DIRECT__ tag appearing in output:
  - Reorder message concatenation in server-agent.ts
  - Add stripping logic in conversation-service.ts and api.ts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-01-28 20:24:54 +09:00
parent 53547f097e
commit d3b743c3c1
5 changed files with 1363 additions and 229 deletions

View File

@@ -5,6 +5,9 @@ import {
generateAIResponse,
} from '../summary-service';
import { sendChatAction } from '../telegram';
import { createLogger } from '../utils/logger';
const logger = createLogger('conversation');
export interface ConversationResult {
responseText: string;
@@ -26,7 +29,9 @@ export class ConversationService {
telegramUserId: string
): Promise<ConversationResult> {
// 1. 타이핑 액션 전송 (비동기로 실행, 기다리지 않음)
sendChatAction(this.env.BOT_TOKEN, Number(chatId), 'typing').catch(console.error);
sendChatAction(this.env.BOT_TOKEN, Number(chatId), 'typing').catch(err =>
logger.error('타이핑 액션 전송 실패', err as Error)
);
// 2. 사용자 메시지 버퍼에 추가
await addToBuffer(this.env.DB, userId, chatId, 'user', text);
@@ -40,6 +45,12 @@ export class ConversationService {
telegramUserId
);
// __DIRECT__ 마커 제거 (AI가 그대로 전달한 경우 대비)
if (responseText.includes('__DIRECT__')) {
const directIndex = responseText.indexOf('__DIRECT__');
responseText = responseText.slice(directIndex + '__DIRECT__'.length).trim();
}
// 4. 봇 응답 버퍼에 추가 (키보드 데이터 마커 등은 그대로 저장)
// 실제 사용자에게 보여질 텍스트만 저장하는 것이 좋으나,
// 현재 구조상 전체를 저장하고 나중에 컨텍스트로 활용 시 정제될 수 있음
@@ -58,18 +69,18 @@ export class ConversationService {
const keyboardMatch = responseText.match(/__KEYBOARD__(.+?)__END__\n?/s);
if (keyboardMatch) {
console.log('[ConversationService] Keyboard marker detected:', keyboardMatch[1].substring(0, 100));
logger.debug('키보드 마커 감지', { preview: keyboardMatch[1].substring(0, 100) });
responseText = responseText.replace(/__KEYBOARD__.+?__END__\n?/s, '');
try {
keyboardData = JSON.parse(keyboardMatch[1]) as KeyboardData;
console.log('[ConversationService] Keyboard parsed successfully:', keyboardData.type);
logger.debug('키보드 파싱 성공', { type: keyboardData.type });
} catch (e) {
console.error('[ConversationService] Keyboard parsing error:', e);
console.error('[ConversationService] Failed to parse:', keyboardMatch[1]);
logger.error('키보드 파싱 오류', e as Error, { rawData: keyboardMatch[1] });
}
} else if (responseText.includes('__KEYBOARD__')) {
console.warn('[ConversationService] Keyboard marker found but regex did not match');
console.warn('[ConversationService] Response preview:', responseText.substring(0, 200));
logger.warn('키보드 마커 발견했으나 정규식 매칭 실패', {
preview: responseText.substring(0, 200)
});
}
return {