- scripts/pkm_utils.py: 공통 유틸 (로거, dotenv, osascript 래퍼) - scripts/prompts/classify_document.txt: Ollama 분류 프롬프트 - applescript/auto_classify.scpt: Inbox → AI 분류 → DB 이동 - applescript/omnifocus_sync.scpt: Projects → OmniFocus 작업 생성 - scripts/law_monitor.py: 법령 변경 모니터링 + DEVONthink 임포트 - scripts/mailplus_archive.py: MailPlus IMAP → Archive DB - scripts/pkm_daily_digest.py: 일일 다이제스트 + OmniFocus 액션 - scripts/embed_to_chroma.py: GPU 서버 벡터 임베딩 → ChromaDB - launchd/*.plist: 3개 스케줄 (07:00, 07:00+18:00, 20:00) - docs/deploy.md: Mac mini 배포 가이드 - docs/devonagent-setup.md: 검색 세트 9종 설정 가이드 - tests/test_classify.py: 5종 문서 분류 테스트 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
102 lines
4.1 KiB
AppleScript
102 lines
4.1 KiB
AppleScript
-- DEVONthink 4 Smart Rule: AI 자동 분류
|
|
-- Inbox DB 새 문서 → Ollama 분류 → 태그 + 메타데이터 + 도메인 DB 이동
|
|
-- Smart Rule 설정: Event = On Import, 조건 = Tags is empty
|
|
|
|
on performSmartRule(theRecords)
|
|
tell application id "DNtp"
|
|
repeat with theRecord in theRecords
|
|
try
|
|
-- 1. 문서 텍스트 추출 (최대 4000자)
|
|
set docText to plain text of theRecord
|
|
set docUUID to uuid of theRecord
|
|
|
|
if length of docText > 4000 then
|
|
set docText to text 1 thru 4000 of docText
|
|
end if
|
|
|
|
if length of docText < 10 then
|
|
-- 텍스트가 너무 짧으면 건너뜀
|
|
set tags of theRecord to {"@상태/검토필요"}
|
|
continue repeat
|
|
end if
|
|
|
|
-- 2. 분류 프롬프트 로딩
|
|
set promptPath to (POSIX path of (path to home folder)) & "Documents/code/DEVONThink_my server/scripts/prompts/classify_document.txt"
|
|
set promptTemplate to do shell script "cat " & quoted form of promptPath
|
|
|
|
-- 문서 텍스트를 프롬프트에 삽입 (특수문자 이스케이프)
|
|
set escapedText to do shell script "echo " & quoted form of docText & " | sed 's/\\\\/\\\\\\\\/g; s/\"/\\\\\"/g; s/\\n/\\\\n/g' | head -c 4000"
|
|
|
|
-- 3. Ollama API 호출
|
|
set curlCmd to "curl -s --max-time 120 http://localhost:11434/api/generate -d '{\"model\": \"qwen3.5:35b-a3b-q4_K_M\", \"prompt\": " & quoted form of escapedText & ", \"stream\": false, \"format\": \"json\"}'"
|
|
set jsonResult to do shell script curlCmd
|
|
|
|
-- 4. JSON 파싱 (Python 사용)
|
|
set parseCmd to "echo " & quoted form of jsonResult & " | python3 -c \"
|
|
import sys, json
|
|
try:
|
|
r = json.loads(sys.stdin.read())
|
|
d = json.loads(r.get('response', '{}'))
|
|
tags = ','.join(d.get('tags', []))
|
|
db = d.get('domain_db', '00_Note_BOX')
|
|
grp = d.get('sub_group', '00_Inbox')
|
|
ch = d.get('sourceChannel', 'inbox_route')
|
|
origin = d.get('dataOrigin', 'external')
|
|
print(f'{db}|{grp}|{tags}|{ch}|{origin}')
|
|
except:
|
|
print('00_Note_BOX|00_Inbox||inbox_route|external')
|
|
\""
|
|
|
|
set classResult to do shell script parseCmd
|
|
set AppleScript's text item delimiters to "|"
|
|
set resultParts to text items of classResult
|
|
set targetDB to item 1 of resultParts
|
|
set targetGroup to item 2 of resultParts
|
|
set tagString to item 3 of resultParts
|
|
set sourceChannel to item 4 of resultParts
|
|
set dataOrigin to item 5 of resultParts
|
|
set AppleScript's text item delimiters to ""
|
|
|
|
-- 5. 태그 설정
|
|
if tagString is not "" then
|
|
set AppleScript's text item delimiters to ","
|
|
set tagList to text items of tagString
|
|
set AppleScript's text item delimiters to ""
|
|
set tags of theRecord to tagList
|
|
end if
|
|
|
|
-- 6. 커스텀 메타데이터 설정
|
|
add custom meta data sourceChannel for "sourceChannel" to theRecord
|
|
add custom meta data dataOrigin for "dataOrigin" to theRecord
|
|
add custom meta data (current date) for "lastAIProcess" to theRecord
|
|
add custom meta data "inbox_route" for "sourceChannel" to theRecord
|
|
|
|
-- 7. 대상 도메인 DB로 이동
|
|
set targetDatabase to missing value
|
|
repeat with db in databases
|
|
if name of db is targetDB then
|
|
set targetDatabase to db
|
|
exit repeat
|
|
end if
|
|
end repeat
|
|
|
|
if targetDatabase is not missing value then
|
|
set groupPath to "/" & targetGroup
|
|
set targetLocation to create location groupPath in targetDatabase
|
|
move record theRecord to targetLocation
|
|
end if
|
|
|
|
-- 8. GPU 서버 벡터 임베딩 비동기 전송
|
|
set embedScript to (POSIX path of (path to home folder)) & "Documents/code/DEVONThink_my server/venv/bin/python3"
|
|
set embedPy to (POSIX path of (path to home folder)) & "Documents/code/DEVONThink_my server/scripts/embed_to_chroma.py"
|
|
do shell script embedScript & " " & quoted form of embedPy & " " & quoted form of docUUID & " &> /dev/null &"
|
|
|
|
on error errMsg
|
|
-- 에러 시 로그 기록 + 검토필요 태그
|
|
set tags of theRecord to {"@상태/검토필요", "AI분류실패"}
|
|
do shell script "echo '[" & (current date) & "] [auto_classify] [ERROR] " & errMsg & "' >> ~/Documents/code/DEVONThink_my\\ server/logs/auto_classify.log"
|
|
end try
|
|
end repeat
|
|
end tell
|
|
end performSmartRule
|