risum 모듈 — RISU modules[] — 기능 확장
조회 153 · 2026-05-21
https://drive.proton.me/urls/XSYTJZQQ7M#8C8EOHJ2N2C6 사용법 1.단 봇에 루아스크립트와 저수준접근을 켜 2.제 /노래마법을 입력해 3. 그 다음 효과 입력하고, 가사 입력하면 됨 채점창 편집버튼 눌러보면 어떤 기준으로 평가했는지도 나옴 근데 개인적인 경험으로는 잼삼플로 하면 진짜 효과 ㅇㅇ 가사 ㅇㅇ 이딴짓만 안하면 어지간한짓 해도 80% 이상은 주는 편향이 있더라
/노래마법 입력 시 발동. 봇 정규식 쪽에 Lua 사용, 저수준 접근 필요
{
"name": "노래마법 모듈",
"description": "/노래마법 입력 시 발동. 봇 정규식 쪽에 Lua 사용, 저수준 접근 필요",
"id": "e37f7efa-e1a6-4c7c-a0fe-f9cbf504a4f2",
"hideIcon": false,
"lorebook": [],
"trigger": [
{
"comment": "",
"type": "start",
"conditions": [],
"effect": [
{
"type": "triggerlua",
"code": "\n-- ============================================================\n-- 🎤 Song Magic Resonance System (Pure Lua & Native UI)\n-- JS 플러그인 불필요 / 메인 모델 차단 완벽 보장 / 일회용 UI 지원\n-- ============================================================\n\nlocal THRESHOLD_PERFECT = 90\nlocal THRESHOLD_HIGH = 70\nlocal THRESHOLD_MEDIUM = 50\nlocal THRESHOLD_LOW = 30\n\n-- 1️⃣ 결과 카드 HTML 생성기\nlocal function makeResultCard(rate, effect, lyrics, judgeName, emoji)\n local lyricsPreview = lyrics\n if #lyricsPreview > 120 then lyricsPreview = lyricsPreview:sub(1, 120) .. \"...\" end\n lyricsPreview = lyricsPreview:gsub(\"%s*/%s*\", \"<br>\"):gsub(\"\\n\", \"<br>\")\n\n local barColor = \"#ff4444\"\n if rate >= THRESHOLD_PERFECT then barColor = \"#ffd700\"\n elseif rate >= THRESHOLD_HIGH then barColor = \"#44ff88\"\n elseif rate >= THRESHOLD_MEDIUM then barColor = \"#5cacee\"\n elseif rate >= THRESHOLD_LOW then barColor = \"#ffaa44\" end\n\n return '<div style=\"font-family:\\'Segoe UI\\',sans-serif;max-width:480px;margin:10px auto;background:linear-gradient(145deg,#0d1117,#161b22);border:1px solid #2a5a8a;border-radius:12px;box-shadow:0 0 25px rgba(30,144,255,0.15);overflow:hidden;\">'\n .. '<div style=\"background:#0a1628;border-bottom:1px solid #2a5a8a;padding:12px 16px;text-align:center;color:#5cacee;font-size:15px;font-weight:bold;letter-spacing:1px;\">🎵 공명률 측정 🎵</div>'\n .. '<div style=\"padding:16px 20px 10px;\">'\n .. '<div style=\"display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;\">'\n .. '<span style=\"color:#7ab0d6;font-size:12px;font-weight:bold;\">RESONANCE SCORE</span>'\n .. '<span style=\"color:' .. barColor .. ';font-size:22px;font-weight:900;\">' .. emoji .. \" \" .. tostring(rate) .. '%</span></div>'\n .. '<div style=\"width:100%;height:10px;background:#1a2a3a;border-radius:5px;overflow:hidden;\">'\n .. '<div style=\"width:' .. tostring(rate) .. '%;height:100%;background:linear-gradient(90deg,' .. barColor .. ',' .. barColor .. 'cc);border-radius:5px;\"></div></div></div>'\n .. '<div style=\"padding:4px 20px 16px;\">'\n .. '<div style=\"color:#c9d6e3;font-size:13px;margin:6px 0;\"><span style=\"color:#7ab0d6;font-weight:bold;\">[판정]</span> ' .. judgeName .. '</div>'\n .. '<div style=\"color:#c9d6e3;font-size:13px;margin:6px 0;\"><span style=\"color:#7ab0d6;font-weight:bold;\">[효과]</span> ' .. effect .. '</div>'\n .. '<div style=\"color:#8a9aaa;font-size:13px;margin:8px 0 0;line-height:1.5;background:rgba(0,0,0,0.3);padding:10px;border-radius:8px;font-style:italic;\">\"' .. lyricsPreview .. '\"</div>'\n .. '</div></div>'\nend\n\n-- 2️⃣ 점수에 따른 텍스트 및 지시문 생성기\nlocal function getJudgment(rate)\n if rate >= THRESHOLD_PERFECT then return \"완전공명 (Perfect Resonance)\", \"🌟\"\n elseif rate >= THRESHOLD_HIGH then return \"고공명 (High Resonance)\", \"✨\"\n elseif rate >= THRESHOLD_MEDIUM then return \"부분공명 (Partial Resonance)\", \"🔵\"\n elseif rate >= THRESHOLD_LOW then return \"미약공명 (Weak Resonance)\", \"🟡\"\n else return \"공명실패 (Resonance Failure)\", \"❌\" end\nend\n\nlocal function makeDirective(score, effect)\n local level, desc\n if score >= THRESHOLD_PERFECT then level = \"PERFECT RESONANCE\"; desc = \"The magic activates at FULL POWER with spectacular success. Describe the miraculous effect in vivid detail.\"\n elseif score >= THRESHOLD_HIGH then level = \"HIGH RESONANCE\"; desc = \"The magic activates SUCCESSFULLY with strong power. The intended effect manifests clearly.\"\n elseif score >= THRESHOLD_MEDIUM then level = \"PARTIAL RESONANCE\"; desc = \"The magic activates with REDUCED effectiveness. Only a portion of the intended effect manifests.\"\n elseif score >= THRESHOLD_LOW then level = \"WEAK RESONANCE\"; desc = \"The magic BARELY activates with MINIMAL effect.\"\n else level = \"RESONANCE FAILURE\"; desc = \"The magic DOES NOT activate. Nothing happens, or there is backlash.\" end\n\n return \"[SONG MAGIC — \" .. level .. \" (\" .. tostring(score) .. \"%)]\\nEffect: \" .. effect .. \"\\n\" .. desc\nend\n\n-- 3️⃣ 보조 모델 프롬프트 조합 (★ CoT: 사고의 사슬 적용으로 지능 향상)\nlocal function buildScoringPrompt(id, effect, lyrics)\n local chatLen = getChatLength(id)\n local contextLines = {}\n for i = math.max(0, chatLen - 8), chatLen - 1 do\n local msg = getChat(id, i)\n if msg and msg.data then\n local role = (msg.role == \"user\") and \"User\" or \"Character\"\n local txt = msg.data:sub(1, 300) -- 컨텍스트 길이 살짝 늘림\n table.insert(contextLines, role .. \": \" .. txt)\n end\n end\n local ctx = table.concat(contextLines, \"\\n\")\n \n local sysP = \"You are a Song Magic Judge. Evaluate how well the LYRICS match the INTENDED EFFECT in the given CONTEXT.\\nCriteria: Thematic Relevance, Situational Fit, Emotional Intensity.\\n\\nINSTRUCTION:\\n1. Briefly explain your evaluation reasoning in 1-2 sentences.\\n2. You MUST end your response exactly with the format: 'FINAL SCORE: [number]' (number between 0 and 100).\"\n local usrP = \"CONTEXT:\\n\" .. ctx .. \"\\n\\nEFFECT:\\n\" .. effect .. \"\\n\\nLYRICS:\\n\" .. lyrics .. \"\\n\\nEvaluate and output reasoning, then FINAL SCORE:\"\n\n return { {role = \"system\", content = sysP}, {role = \"user\", content = usrP} }\nend\n\nlocal function extractScore(text)\n if type(text) ~= \"string\" or text == \"\" then return 50 end\n \n -- 1순위: FINAL SCORE: 85 형태를 가장 먼저 찾음\n local match = text:match(\"FINAL SCORE:%s*(%d+)\")\n if match then \n return math.min(100, math.max(0, tonumber(match)))\n end\n\n -- 2순위: 못 찾았으면 텍스트에서 마지막으로 등장한 숫자를 찾음\n local score = 50\n for num in text:gmatch(\"%d+\") do \n score = tonumber(num) \n end\n return math.min(100, math.max(0, score))\nend\n\n-- 4️⃣ 가이드 UI 삭제용 헬퍼 함수\nlocal function removeGuide(id)\n local len = getChatLength(id)\n for i = len - 1, 0, -1 do\n local msg = getChat(id, i)\n if msg and msg.data and msg.data:find(\"노래 마법 시스템\") then\n removeChat(id, i)\n end\n end\nend\n\n-- ============================================================\n-- [관문 1] 채팅창에 \"/노래마법\" 입력 시 가이드 UI 팝업\n-- ============================================================\nfunction onStart(id)\n local msg = getUserLastMessage(id)\n \n if getState(id, \"sm_guide_open\") then\n removeGuide(id)\n setState(id, \"sm_guide_open\", false)\n reloadDisplay(id)\n end\n\n if msg and msg:find(\"^/노래마법\") then\n stopChat(id)\n removeChat(id, getChatLength(id) - 1)\n\n local css = [[<style>\n .sm-wrap { font-family: -apple-system, sans-serif; max-width: 400px; margin: 0 auto; background: #161b22; border: 1px solid #2a5a8a; border-radius: 12px; padding: 20px; box-shadow: 0 4px 15px rgba(0,0,0,0.5); }\n .sm-title { text-align: center; color: #5cacee; font-size: 1.2em; font-weight: bold; margin-bottom: 8px; }\n .sm-desc { color: #8a9aaa; font-size: 0.85em; text-align: center; line-height: 1.5; margin-bottom: 20px; }\n .sm-btn { display: block; width: 100%; padding: 12px; background: linear-gradient(135deg, #1a5a9a, #2a7acc); color: white; border: none; border-radius: 8px; font-size: 1em; font-weight: bold; cursor: pointer; text-align: center; border: 1px solid #3a8add; transition: 0.2s; }\n .sm-btn:active { transform: scale(0.97); }\n </style>]]\n\n local html = css .. [[<div class=\"sm-wrap\">\n <div class=\"sm-title\">🎤 노래 마법 시스템</div>\n <div class=\"sm-desc\">아래 버튼을 눌러 마법 효과와 가사를 입력하세요.<br>보조 모델(axLLM)이 대화 상황을 분석해<br>스스로 공명률을 판정합니다.</div>\n <button risu-btn=\"TriggerSongMagic\" class=\"sm-btn\">✨ 마법 영창 시작</button>\n </div>]]\n\n addChat(id, \"system\", html)\n setState(id, \"sm_guide_open\", true)\n reloadDisplay(id)\n return false \n end\nend\n\n-- ============================================================\n-- [관문 2] 유저가 버튼을 눌렀을 때의 동작 (Risu 순정 팝업 활용)\n-- ============================================================\nonButtonClick = async(function(id, data)\n if data == \"TriggerSongMagic\" then\n \n removeGuide(id)\n setState(id, \"sm_guide_open\", false)\n reloadDisplay(id)\n\n local effect = alertInput(id, \"◈ 의도하는 마법 효과를 적어주세요.\\n(예: 광역 치유, 적 둔화, 화염 폭발 등)\"):await()\n if not effect or effect == \"\" then return end\n\n local lyrics = alertInput(id, \"◈ 영창할 노래 가사(대사)를 적어주세요.\\n(줄바꿈이 필요한 곳에는 슬래시 '/' 를 적어주세요)\"):await()\n if not lyrics or lyrics == \"\" then return end\n\n local chatLyrics = lyrics:gsub(\"%s*/%s*\", \"\\n\")\n\n addChat(id, \"user\", \"*노래 마법을 시전합니다.*\\n\\n*\\\"\" .. chatLyrics .. \"\\\"*\")\n \n addChat(id, \"system\", \"🎵 *보조 모델이 마법의 공명률을 판정하고 있습니다...*\")\n local loadingIdx = getChatLength(id) - 1\n reloadDisplay(id)\n\n local prompt = buildScoringPrompt(id, effect, chatLyrics)\n local resp = nil\n for attempt = 1, 3 do\n resp = axLLM(id, prompt)\n if resp and resp.success then break end\n end\n\n local score = 50\n local rawAiResponse = \"AI 응답 없음\"\n \n if resp and resp.success then\n rawAiResponse = resp.result\n score = extractScore(rawAiResponse)\n else\n local errInfo = resp and resp.result or \"알 수 없음(응답 없음)\"\n alertError(id, \"⚠️ 보조 모델 통신 실패! 기본값(50점)으로 처리됩니다.\\n에러: \" .. tostring(errInfo))\n end\n\n local judgeName, emoji = getJudgment(score)\n local resultCard = makeResultCard(score, effect, chatLyrics, judgeName, emoji)\n local directive = makeDirective(score, effect)\n\n -- ★ 여기에 AI의 실제 답변(이유)을 주석으로 몰래 숨겨둡니다. \n -- 나중에 결과 메시지의 [수정] 버튼을 눌러서 AI가 왜 이 점수를 줬는지 확인할 수 있습니다.\n local hiddenAiLog = \"\\n<!--\\n=== AI 채점 로그 ===\\n\" .. tostring(rawAiResponse) .. \"\\n==================\\n\" .. directive .. \"\\n-->\"\n\n setChat(id, loadingIdx, resultCard .. hiddenAiLog)\n reloadDisplay(id)\n \n end\nend)\n\n-- ============================================================"
}
],
"lowLevelAccess": true
}
],
"lowLevelAccess": true,
"regex": [],
"assets": []
}