Public Source Viewer

비나래아카이브 개발자 포털

실제 서비스 구조를 살펴볼 수 있는 공개용 코드 뷰어입니다. 인증, 세션, 외부 연동, 토큰, 관리자 식별 등 보안상 민감한 구현은 파일 단위 또는 줄 단위로 검열됩니다.

Redacted View
src/services/binarae-signal.service.ts
공개 가능
1 import fs from 'fs';
2 import path from 'path';
3 import { openai } from '../config/ai.config';
4 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
5
6 export type BinaraeSignal = {
7 sourceText: string;
8 statusText: string;
9 terminalCommand: string;
10 terminalText: string;
11 keywords: string[];
12 updatedAt: string;
13 analyzedBy: 'openai' | 'local';
14 };
15
16 type SignalPick = Pick<BinaraeSignal, 'statusText' | 'terminalCommand' | 'terminalText' | 'keywords'>;
17
18 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
19
20 const defaultSignal: BinaraeSignal = {
21 sourceText: '',
22 statusText: '파릇하게 기록 중',
23 terminalCommand: 'mood --fresh',
24 terminalText: 'green signal, memory online',
25 keywords: ['fresh', 'archive', 'memory'],
26 updatedAt: new Date(0).toISOString(),
27 analyzedBy: 'local'
28 };
29
30 function ensureDataDir(): void {
31 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
32 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
33 }
34 }
35
36 function normalizeKeyword(value: unknown): string {
37 return String(value || '')
38 .replace(/[^0-9a-zA-Z가-힣-]/g, '')
39 .trim()
40 .slice(0, 18);
41 }
42
43 function normalizeSignal(raw: Partial<BinaraeSignal>): BinaraeSignal {
44 return {
45 sourceText: String(raw.sourceText || '').slice(0, 240),
46 statusText: String(raw.statusText || defaultSignal.statusText).slice(0, 28),
47 terminalCommand: String(raw.terminalCommand || defaultSignal.terminalCommand).slice(0, 32),
48 terminalText: String(raw.terminalText || defaultSignal.terminalText).slice(0, 64),
49 keywords: Array.isArray(raw.keywords)
50 ? raw.keywords.map(normalizeKeyword).filter(Boolean).slice(0, 6)
51 : defaultSignal.keywords,
52 updatedAt: raw.updatedAt || new Date().toISOString(),
53 analyzedBy: raw.analyzedBy === 'openai' ? 'openai' : 'local'
54 };
55 }
56
57 function pickLocalSignal(sourceText: string): SignalPick {
58 const text = sourceText.toLowerCase();
59
60 if (/두려|무서|공포|불안|불안정|초조|걱정|겁나|좋지 않은 생각|나쁜 생각|위험한 생각|죽고|죽음|자해|사라지고|끝내고|fear|afraid|anxiety|panic|bad thought|self-harm|suicid/.test(text)) {
61 return {
62 statusText: '조심히 정리 중',
63 terminalCommand: 'mood --care',
64 terminalText: 'care signal, holding steady',
65 keywords: ['care', 'anxiety', 'steady', '기록']
66 };
67 }
68
69 if (/외롭|허전|우울|슬프|가라앉|눈물|힘들|sad|blue|lonely|down/.test(text)) {
70 return {
71 statusText: '차분히 정리 중',
72 terminalCommand: 'mood --calm',
73 terminalText: 'blue note, gentle archive',
74 keywords: ['calm', 'blue', 'note']
75 };
76 }
77
78 if (/피곤|졸리|쉬고|지침|지쳤|수면|sleep|tired|rest/.test(text)) {
79 return {
80 statusText: '조용히 충전 중',
81 terminalCommand: 'mood --rest',
82 terminalText: 'quiet battery, soft reboot',
83 keywords: ['rest', 'quiet', 'reboot']
84 };
85 }
86
87 if (/바쁘|작업|마감|정리|분주|busy|work|task/.test(text)) {
88 return {
89 statusText: '분주하게 동기화 중',
90 terminalCommand: 'mood --sync',
91 terminalText: 'tasks queued, archive syncing',
92 keywords: ['busy', 'sync', 'task']
93 };
94 }
95
96 if (/기쁘|좋아|신남|행복|반짝|최고|happy|spark/.test(text)) {
97 return {
98 statusText: '반짝이며 저장 중',
99 terminalCommand: 'mood --spark',
100 terminalText: 'spark signal, happy cache',
101 keywords: ['spark', 'happy', 'cache']
102 };
103 }
104
105 return {
106 statusText: defaultSignal.statusText,
107 terminalCommand: defaultSignal.terminalCommand,
108 terminalText: defaultSignal.terminalText,
109 keywords: defaultSignal.keywords
110 };
111 }
112
113 function needsCareOverride(sourceText: string): boolean {
114 return /두려|무서|공포|불안|초조|걱정|좋지 않은 생각|나쁜 생각|위험한 생각|죽고|죽음|자해|사라지고|끝내고|fear|afraid|anxiety|panic|bad thought|self-harm|suicid/i.test(sourceText);
115 }
116
117 function localAnalyzeSignal(sourceText: string): BinaraeSignal {
118 return normalizeSignal({
119 ...pickLocalSignal(sourceText),
120 sourceText,
121 updatedAt: new Date().toISOString(),
122 analyzedBy: 'local'
123 });
124 }
125
126 export function getBinaraeSignal(): BinaraeSignal {
127 try {
128 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
129 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
130 } catch {
131 return defaultSignal;
132 }
133 }
134
135 export async function analyzeAndSaveBinaraeSignal(sourceText: string): Promise<BinaraeSignal> {
136 const trimmed = sourceText.replace(/\s+/g, ' ').trim().slice(0, 240);
137 if (!trimmed) {
138 const signal = normalizeSignal({ ...defaultSignal, updatedAt: new Date().toISOString() });
139 saveBinaraeSignal(signal);
140 return signal;
141 }
142
143 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
144 try {
145 const response: any = await openai.responses.create({
146 model: 'gpt-5.5',
147 input: [
148 {
149 role: 'system',
150 content: [
151 'You convert a Korean mood sentence into compact status UI copy.',
152 'Return strict JSON only.',
153 'Fields: statusText Korean <= 14 chars, terminalCommand ascii starts with "mood --", terminalText ascii <= 48 chars, keywords array 3-6 ascii/korean short words.',
154 'If the sentence contains fear, anxiety, bad thoughts, self-harm, or danger signals, do not use fresh/green/positive wording. Use careful, calm, steady wording.',
155 'Keep it poetic but not dramatic. No private inference beyond the sentence.'
156 ].join(' ')
157 },
158 { role: 'user', content: trimmed }
159 ],
160 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
161 } as any);
162
163 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
164 const careOverride = needsCareOverride(trimmed) ? pickLocalSignal(trimmed) : null;
165 const signal = normalizeSignal({
166 sourceText: trimmed,
167 statusText: careOverride?.statusText || parsed.statusText,
168 terminalCommand: careOverride?.terminalCommand || parsed.terminalCommand,
169 terminalText: careOverride?.terminalText || parsed.terminalText,
170 keywords: careOverride?.keywords || parsed.keywords,
171 updatedAt: new Date().toISOString(),
172 analyzedBy: 'openai'
173 });
174 saveBinaraeSignal(signal);
175 return signal;
176 } catch (error) {
177 console.error('Binarae signal AI analysis failed:', error);
178 }
179 }
180
181 const fallback = localAnalyzeSignal(trimmed);
182 saveBinaraeSignal(fallback);
183 return fallback;
184 }
185
186 function saveBinaraeSignal(signal: BinaraeSignal): void {
187 ensureDataDir();
188 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
189 }
190