Public Source Viewer
비나래아카이브 개발자 포털
실제 서비스 구조를 살펴볼 수 있는 공개용 코드 뷰어입니다. 인증, 세션, 외부 연동, 토큰, 관리자 식별 등 보안상 민감한 구현은 파일 단위 또는 줄 단위로 검열됩니다.
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