Skip to content

Repository files navigation

Life Plan Scheduler AI (Azure 전용)


프로그램명: Life Plan Scheduler AI
한 줄 소개: 설정 패널 없이 바로 쓰는 Azure OpenAI 기반 일정/메모/조사 AI 웹앱


1) 구조

  • 메인 엔트리: index.html
  • 스타일: main.css
  • 프런트 로직: main.js
  • 백엔드 프록시: llm-proxy-server.js
  • 사용자별 데이터/설정 저장소: db.js (SQLite, 파일: data.sqlite3)
  • 스모크 테스트: scripts/smoke-test.mjs
  • 환경 변수 템플릿: .env.example

참고:

  • app.js, style.css, simple.html, simple-enhanced.html은 과거 실험 파일이며 현재 실행 경로에서 사용하지 않습니다.
  • 현재 기본 실행 경로는 index.html + main.js + llm-proxy-server.js입니다.
  • data.sqlite3.gitignore에 포함되어 커밋되지 않습니다.

2) 설계 원칙

  • Azure OpenAI 단일 경로만 사용, 설정 패널 없이 바로 사용
  • 답변 형식(설명/계획/비교/요약)은 AI가 질문 의도를 보고 스스로 판단해서 결정 (하드코딩된 분기 없음)
  • 인터넷 조사 결과는 참고 컨텍스트로만 제공하고, 최종 문장 생성은 항상 AI가 담당
  • 새로고침 후에도 대화/추출 항목 유지 (localStorage + 서버 SQLite 동기화)
  • 사용자 이름으로 데이터 분리, 사용자별 모델/temperature/max_tokens 설정 가능
  • rate limit(429) 등 장애 상황에서도 화면이 멈추지 않고 명확한 안내 제공

3) 실행 방법

3-1. 환경 변수 준비

.env.example.env로 복사 후 값 입력:

  • AZURE_OPENAI_ENDPOINT
  • AZURE_OPENAI_KEY
  • (선택) AZURE_OPENAI_DEPLOYMENT (기본: gpt-4o-mini)
  • (선택) AZURE_OPENAI_API_VERSION (기본: 2024-02-15-preview)
  • (선택) PROXY_MAX_RETRIES (기본: 2, 5xx 네트워크 오류에만 적용)
  • (선택) ALLOWED_ORIGIN (기본: http://localhost:8000, CORS 허용 출처)
  • PORT (기본 8787)

3-2. 프록시 실행

npm run start:proxy

3-3. 웹 서버 실행

npm run start:web

3-4. 접속

  • http://localhost:8000/index.html

3-5. 스모크 테스트

npm run test:smoke
  • 프록시(8787)가 떠 있어야 합니다.
  • 확인 항목: health, 날씨 조사 라우팅, 장소 조사 라우팅, 일반 조사, (Azure 설정 시) 챗 엔드포인트

4) 동작 흐름

  1. 사용자가 입력 후 전송
  2. main.js가 프록시(8787)의 /api/research로 인터넷 조사 자료를 먼저 수집 (날씨/장소/일반 검색 자동 분기)
  3. 조사 자료를 컨텍스트로 붙여 Azure OpenAI에 채팅 요청
  4. AI가 질문 의도에 맞는 형식(설명/계획/비교/요약)을 스스로 선택해 Markdown으로 응답
  5. 응답을 채팅에 렌더링 (표/목록/강조 등 Markdown 서식 지원)
  6. 일정/메모 키워드나 날짜·시간 표현이 있으면 최근 항목으로 자동 추출 (최대 8개, 예상 일정 메타 표시)

오류 시:

  • Azure 미설정이면 폴백 안내 표시, 화면은 계속 사용 가능
  • 전체 응답 대기시간에 상한(워치독)이 있어 무한정 "생각 중..."에 머무르지 않음

Rate limit(429) 대응:

  • 프록시는 429를 즉시 반환합니다 (내부 블로킹 재시도 없음, 5xx만 짧게 재시도)
  • 프런트는 서버가 알려준 실제 대기시간(retryAfterMs)만큼 1회만 기다렸다가 재시도합니다
  • 계속 반복되면 Azure 배포 쿼터(TPM/RPM) 상향이 필요하다는 안내를 표시합니다

5) 검증 체크리스트

  • /health에서 providers.azure.configuredtrue
  • 전송 버튼 클릭 시 로딩 메시지(생각 중...) 표시
  • 응답 수신 후 로딩 메시지가 실제 답변으로 교체
  • 새로고침 후 대화 기록과 최근 추출 항목 유지
  • 최근 추출 항목 최대 8개 유지, 수정/삭제 동작 확인
  • 초기화 클릭 시 대화만 초기화되고 메모(최근 추출 항목)는 유지
  • npm run test:smoke 전체 통과

6) 스크립트

  • npm run llm-proxy / npm run start:proxy: 프록시 서버 실행
  • npm run start:web: 정적 웹 서버 실행 (포트 8000)
  • npm run test:smoke: 조사 라우팅(날씨/장소/일반)과 챗 엔드포인트 자동 점검

7) 문제 해결 (Rate Limit / 429)

증상: 응답이 계속 지연되거나 "Azure 요청 한도(rate limit) 초과" 메시지가 반복됨

원인 확인:

az cognitiveservices account deployment list --name <resource-name> --resource-group <rg-name> -o json
  • rateLimitsrequest/token 값이 낮으면 배포 용량(TPM)이 부족한 상태입니다.

해결(용량 상향 예시, 여유 쿼터가 있을 때):

az cognitiveservices account deployment create \
  --name <resource-name> \
  --resource-group <rg-name> \
  --deployment-name <deployment-name> \
  --model-name gpt-4.1-mini \
  --model-version "2025-04-14" \
  --model-format OpenAI \
  --sku-name GlobalStandard \
  --sku-capacity 10
  • 리전별 여유 쿼터는 az cognitiveservices usage list --location <region>으로 확인합니다.

8) 변경 이력 (요약)

  • Azure OpenAI 단일 경로 구조로 정리, 설정 패널 제거
  • 최근 추출 항목: 수정/삭제, 날짜·시간 파싱(오늘/내일/모레 + 오전/오후 N시, HH:MM), 초기화 시 메모 유지
  • 대화/항목 JSON 내보내기(내보내기 JSON 버튼)
  • 인터넷 조사 자동 라우팅 추가 (/api/research): 날씨(Open-Meteo), 장소(OpenStreetMap), 일반 검색(Wikipedia/DuckDuckGo/HackerNews)
  • AI 응답을 하드코딩된 템플릿 분기 대신 모델이 직접 판단해 생성하도록 변경, Markdown 렌더링 적용
  • Rate limit(429) 처리 개선: 프록시 즉시 반환 + 프런트 1회 실대기 재시도로 응답 지연 대폭 단축
  • Azure 배포 용량 상향(요청 1/분 → 10/분, 토큰 1,000/분 → 10,000/분)
  • scripts/smoke-test.mjs 추가로 핵심 경로 자동 검증
  • SQLite 기반 사용자별 데이터/설정 저장 추가 (db.js, /api/users, /api/state, /api/settings)

9) 사용자 / 설정 (DB 연동)

  • 상단 사용자 이름 입력 + 전환 버튼: 이름으로 사용자를 구분하며, 전환 시 서버(SQLite)에 저장된 대화/항목을 불러옵니다.
  • 로그인/비밀번호는 없습니다. 같은 이름을 입력하면 같은 데이터를 이어서 사용합니다.
  • 설정 버튼: 사용자별 model, temperature, max_tokens를 편집하고 저장합니다. 저장된 값은 다음 요청부터 바로 적용됩니다.
  • 대화/항목은 localStorage에 즉시 저장되고, 1.2초 디바운스 후 서버(SQLite)에도 동기화됩니다. 상단 DB 동기화 상태 표시로 확인 가능합니다.
  • 관련 API:
    • GET /api/users, POST /api/users (사용자 생성/조회)
    • GET /api/state?user=NAME, POST /api/state (대화/항목/사용량 저장·조회)
    • GET /api/settings?user=NAME, POST /api/settings (모델/온도/토큰 설정 저장·조회)

10) 다크모드 / 화이트모드

  • 상단 🌙 다크모드 / ☀️ 화이트모드 버튼으로 즉시 전환됩니다.
  • 브라우저에 저장(localStorage: lps-theme)되어 새로고침·재방문 시에도 유지됩니다.
  • 저장된 값이 없으면 OS의 다크모드 설정(prefers-color-scheme)을 따릅니다.
  • 서버 동기화 대상이 아닌 브라우저 로컬 개인 설정입니다(사용자별 DB 설정과는 별개).

11) 개인 설정 확장

  • 글자 크기(작게/보통/크게), 채팅 밀도(여유롭게/촘촘하게): 설정 패널에서 변경, localStorage에 저장되어 즉시 적용됩니다.
  • 사용자별 모델/temperature/max_tokens: 기존과 동일하게 서버(SQLite)에 저장됩니다.

12) 보안

  • 로그인 / 회원가입 (권장): 상단 아이디/비밀번호 입력 후 회원가입 또는 로그인 버튼으로 정식 계정을 사용할 수 있습니다.
    • 비밀번호는 scrypt + salt로 해시 저장됩니다(평문 저장 없음).
    • 로그인 성공 시 서버가 세션 토큰을 발급하며, 브라우저에는 sessionStorage에만 저장됩니다(탭 닫으면 만료, 서버 기준 7일 유효).
    • 이후 해당 계정 이름으로 /api/state, /api/settings 접근 시 Authorization: Bearer <token> 세션이 필요하며, 다른 사람의 유효한 세션 토큰으로도 남의 데이터에는 접근할 수 없습니다 (토큰의 소유자와 요청 대상 사용자가 반드시 일치해야 함).
    • 로그아웃 시 서버에서 세션 토큰을 즉시 폐기합니다.
    • 관련 API: POST /api/auth/register, POST /api/auth/login, POST /api/auth/logout
  • PIN 기반 데이터 보호(구버전 호환): 비밀번호 계정을 만들지 않은 사용자 이름은 기존처럼 설정 패널의 PIN으로 보호할 수 있습니다.
    • PIN도 scrypt로 해시 저장되며, 브라우저에는 sessionStorage에만 보관됩니다.
    • PIN도 비밀번호도 설정하지 않은 이름은 기존처럼 개방형(닉네임 게시판 방식)으로 동작합니다.
  • XSS 방어: AI 응답(Markdown, 인터넷 조사 결과 포함)은 DOMPurify로 살균 후 렌더링하며, http/https/mailto 외 링크 스킴(javascript: 등)은 제거됩니다.
  • 요청 제한(Rate Limit): /api/llm/chat(20회/분), /api/research(30회/분), /api/state·/api/settings(60회/분), /api/auth/*(10회/분, 무차별 대입 방지)로 IP당 요청 수를 제한합니다.
  • CORS 제한: 기본적으로 http://localhost:8000 출처만 허용합니다. 다른 호스트에서 서비스할 경우 ALLOWED_ORIGIN 환경 변수로 변경하세요.
  • 입력 크기 제한: 조사 질의는 300자, 채팅 메시지 배열은 최근 40개로 제한합니다.
  • 참고: 로컬 개발 환경 기준이며, 실제 배포 시에는 반드시 HTTPS를 적용하세요(세션 토큰과 비밀번호가 평문 HTTP로 전송되지 않도록).

About

test message

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages