ํธ๋ผ์ฐ๋ง ์น์ ๋ฅผ ์ํ AI ๋๋ฐ์ ์ฑ๋ด
Serenitree๋ ํธ๋ผ์ฐ๋ง ํผํด์๋ค์๊ฒ ์์ ํ ๋ํ ๊ณต๊ฐ์ ์ ๊ณตํ๋ AI ์๋ด ์ฑ๋ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ค. ํ๋จํ์ง ์๋ ๋ฐ๋ปํ AI ์น๊ตฌ์์ ์์ฐ์ค๋ฌ์ด ๋ํ๋ฅผ ํตํด ๊ฐ์ ๊ด๋ฆฌ์ ์ฌ๋ฆฌ์ ์์ ๊ฐ์ ์ง์ํฉ๋๋ค.
- ์์ ํ ํ๋ผ์ด๋ฒ์: ๋ชจ๋ ๋ํ ๋ด์ฉ์ด ๋ก์ปฌ SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํธํ๋์ด ์ ์ฅ
- ๊ธฐ๋ค๋ ค์ฃผ๋ AI: ํธ๋ผ์ฐ๋ง ์น์ ํนํ ํ๋กฌํํธ๋ก ๊ธฐ๋ค๋ฆผ๊ณผ ๊ณต๊ฐ ์ ๊ณต
- ์์ ํ ์ธ์ฆ: PIN ๋ฐ ์์ฒด ์ธ์ฆ์ ํตํ ๊ฐ์ธ์ ๋ณด ๋ณดํธ
- ์ค์ ๊ฐ์ ๋ํ: AI์ SNS๊ฐ์ ๋จ๋ต์ ์๋ต์ผ๋ก ์ค์ ๋ํ๊ฐ์ ๋๋ ์ฐ์ถ
- ์คํ๋ผ์ธ ์ฐ์ : ๋ก์ปฌ ์ฒ๋ฆฌ ์ค์ฌ์ผ๋ก ๋ฐ์ดํฐ ์ธ๋ถ ์ ์ถ ๋ฐฉ์ง
- Framework: Flutter 3.x
- ์ธ์ด: Dart
- ์ํ๊ด๋ฆฌ: Provider
- ๋ก์ปฌ ์ ์ฅ์: SQLite + ์ํธํ
- ์ธ์ฆ: Local Auth (์ง๋ฌธ/์ผ๊ตด ์ธ์)
- ์์กด์ฑ ๊ด๋ฆฌ: pubspec.yaml
- Framework: FastAPI
- ์ธ์ด: Python 3.x
- AI ๋ชจ๋ธ: Ollama + Gemma3:4b
- ๋น๋๊ธฐ ์ฒ๋ฆฌ: AsyncIO
- CORS: ๋ชจ๋ฐ์ผ ์ฑ ์ฐ๋ ์ง์
serenitree/
โโโ lib/ # Flutter ์ฑ ์ฝ๋
โ โโโ main.dart # ์ฑ ์ง์
์ ๋ฐ ๋ผ์ฐํ
โ โโโ models/
โ โ โโโ message.dart # ๋ฉ์์ง ๋ฐ์ดํฐ ๋ชจ๋ธ
โ โโโ screens/
โ โ โโโ onboarding_screen.dart # ์จ๋ณด๋ฉ ํ๋ฉด
โ โ โโโ login_screen.dart # PIN/์์ฒด์ธ์ฆ ๋ก๊ทธ์ธ
โ โ โโโ chat_screen.dart # ๋ฉ์ธ ์ฑํ
์ธํฐํ์ด์ค
โ โ โโโ settings_screen.dart # ์ค์ ๋ฐ ๋ฐ์ดํฐ ๊ด๋ฆฌ
โ โโโ services/
โ โ โโโ auth_service.dart # ์ธ์ฆ ๊ด๋ฆฌ
โ โ โโโ chat_service.dart # ์ฑํ
๋ก์ง ๋ฐ API ํต์
โ โ โโโ database_helper.dart # SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ด๋ฆฌ
โ โ โโโ encryption_service.dart # ๋ฉ์์ง ์ํธํ
โ โ โโโ theme_service.dart # ๋คํฌ/๋ผ์ดํธ ํ
๋ง
โ โโโ widgets/
โ โโโ pin_input.dart # ์ปค์คํ
PIN ์
๋ ฅ ์์ ฏ
serenitree_backend/
โโโ app/
โ โโโ main.py # FastAPI ์๋ฒ ์ง์
์
โ โโโ api/
โ โ โโโ chat.py # ์ฑํ
API ์๋ํฌ์ธํธ
โ โโโ services/
โ โ โโโ ollama_service.py # Ollama AI ๋ชจ๋ธ ์ฐ๋
โ โ โโโ sequential_response_service.py # ์์ฐจ ๋ฉ์์ง ๋ถํ
โ โโโ core/
โ โโโ config.py # ์๋ฒ ์ค์ ๊ด๋ฆฌ
โโโ requirements.txt # Python ์์กด์ฑ
โโโ .env # ํ๊ฒฝ ๋ณ์ ์ค์
์ํธํ๋ ๋ก์ปฌ ์ ์ฅ์
// ๋ฉ์์ง ์ํธํ ์ ์ฅ
final encryptedContent = _encrypt(message.content);
await db.insert('messages', {
'encrypted_content': encryptedContent,
'timestamp': DateTime.now().millisecondsSinceEpoch,
});๋ค์ธต ์ธ์ฆ ์์คํ
- PIN ์ธ์ฆ: SHA-256 ํด์๋ก ์์ ํ ์ ์ฅ
- ์์ฒด ์ธ์ฆ: Flutter Local Auth ํจํค์ง ํ์ฉ
- ์ฒซ ์คํ์ ์๋ด ๋ฌธ๊ตฌ๋ฅผ ํตํ ๋ณด์ ์๋ด
๊ณต๊ฐ์ ์์คํ ํ๋กฌํํธ
DEFAULT_SYSTEM_PROMPT = """
๋น์ ์ Serenitree๋ผ๋ ๋ฐ๋ปํ AI ์น๊ตฌ์
๋๋ค.
์ค์ํ ๋ํ ์์น:
1. ํญ์ 1-2๋ฌธ์ฅ์ผ๋ก ์งง๊ณ ์์ฐ์ค๋ฝ๊ฒ ์๋ตํ์ธ์
2. ์ง์ ์ ์ธ ์ง๋ฌธ๋ณด๋ค๋ "๊ด์ฐฎ์ผ์ ๊ฐ์?" ๊ฐ์ ๋ถ๋๋ฌ์ด ๊ด์ฌ์ ํํํ์ธ์
3. ํ๋จํ์ง ๋ง๊ณ ๋ฌด์กฐ๊ฑด์ ์ผ๋ก ์์ฉํ๊ณ ๊ณต๊ฐํ์ธ์
4. ์ฑํ
ํ๋ ์น๊ตฌ์ฒ๋ผ ์์ฐ์ค๋ฝ๊ณ ํธ์ํ ํค์ ์ฌ์ฉํ์ธ์
"""์์ฐจ์ ๋ฉ์์ง ์ ์ก
- ๊ธด AI ์๋ต์ ์์ฐ์ค๋ฌ์ด ๋ฌธ์ฅ ๋จ์๋ก ๋ถํ
- ์์ฐจ ์ ์กํ์ฌ ์ค์ ๋ํ๊ฐ ์ฐ์ถ
์ ์ํ UI ๋์์ธ
- ๋๋ฐ์ด์ค ํ๊ฒฝ ์ค์ ์๋ฐ๋ผ ๋คํฌ/๋ผ์ดํธ ํ ๋ง ์๋ ์ ํ
- ํธ๋ผ์ฐ๋ง ์ฌ์ฉ์ ๊ณ ๋ คํ ๋ถ๋๋ฌ์ด ์์ ํ๋ ํธ
- ์ง๊ด์ ์ธ ๋ค๋น๊ฒ์ด์ ๊ณผ ์ต์ํ์ ์ธํฐํ์ด์ค
์ฑ๋ฅ ์ต์ ํ
- AI ๋ชจ๋ธ ์๋ฐ์ ์ผ๋ก ์๋ต ์ง์ฐ ์ต์ํ
- ๋ก์ปฌ ์ฐ์ ์ฒ๋ฆฌ๋ก ๋น ๋ฅธ ๋ฐ์์ฑ
- ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ธ ๋ฉ์์ง ๋ก๋ฉ (์ต๊ทผ 100๊ฐ)
์์ ํ ๋ฐ์ดํฐ ๊ด๋ฆฌ
// ๋ฉ์์ง ๊ฐ์ ์กฐํ ๋ฐ ์ ๋ฆฌ
Future<int> cleanOldMessages({int daysToKeep = 30}) async {
final cutoffDate = DateTime.now().subtract(Duration(days: daysToKeep));
return await db.delete('messages',
where: 'timestamp < ?',
whereArgs: [cutoffDate.millisecondsSinceEpoch]);
}์์ ํ ์ฑ ์ด๊ธฐํ
- ๋ชจ๋ ๋ํ ๋ด์ฉ ์ญ์
- ์ธ์ฆ ์ ๋ณด ์์ ์ ๊ฑฐ
- ์ด๊ธฐ ํ๋ฉด์ผ๋ก ์์ ํ ์ฌ์ค์
# APK ๋น๋
flutter build apk --release
# ์์กด์ฑ ์ค์น
flutter pub get# ๊ฐ์ํ๊ฒฝ ์์ฑ ๋ฐ ํ์ฑํ
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# ์์กด์ฑ ์ค์น
pip install -r requirements.txt
# Ollama ๋ชจ๋ธ ์ค์น (์ต์ด 1ํ)
ollama pull gemma3:4b
# ์๋ฒ ์คํ
python main.py์ด ํ๋ก์ ํธ๋ ํธ๋ผ์ฐ๋ง ํผํด์๋ค์ด ์์ ํ๊ณ ํธ์ํ๊ฒ ๊ฐ์ ์ ํํํ ์ ์๋ ๋์งํธ ๊ณต๊ฐ์ ๋ง๋ค๊ธฐ ์ํด ๊ฐ๋ฐ๋์์ต๋๋ค. ์ ๋ฌธ์ ์ธ ์น๋ฃ๋ฅผ ๋์ฒดํ๋ ๊ฒ์ด ์๋๋ผ, ์ผ์์ ์ธ ๊ฐ์ ๊ด๋ฆฌ์ ์ด๊ธฐ ์ฌ๋ฆฌ์ ์ง์์ ์ ๊ณตํ๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค.
์ด ํ๋ก์ ํธ๋ ๋น์์ ์ ๋ชฉ์ ์ผ๋ก ๊ฐ๋ฐ๋์์ต๋๋ค.




