Compare commits

..

No commits in common. '2025_moty' and 'main' have entirely different histories.

  1. BIN
      vite/public/assets/moty/q1.mp3
  2. BIN
      vite/public/assets/moty/q2-1.mp3
  3. BIN
      vite/public/assets/moty/q2.mp3
  4. BIN
      vite/public/assets/moty/q3.mp3
  5. BIN
      vite/public/assets/moty/q5.mp3
  6. BIN
      vite/public/assets/moty/q7-1-1.mp3
  7. BIN
      vite/public/assets/moty/q7-1-2.mp3
  8. BIN
      vite/public/assets/moty/q7-1.mp3
  9. BIN
      vite/public/assets/moty/q7-2.mp3
  10. BIN
      vite/public/assets/moty/q7.mp3
  11. BIN
      vite/public/assets/moty/q8-1.mp3
  12. BIN
      vite/public/assets/moty/q8.mp3
  13. 141
      vite/public/cuelist_moty.json
  14. 9
      vite/public/default.json
  15. 3
      vite/src/App.jsx
  16. 24
      vite/src/comps/numpad.jsx
  17. 4
      vite/src/main.jsx
  18. 1162
      vite/src/pages/flow_moty.jsx
  19. 8
      vite/src/util/osc.js
  20. 19
      vite/src/util/system_prompt.js
  21. 3
      vite/src/util/useUser.jsx

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -1,141 +0,0 @@
{
"cuelist": [
{
"id": 1,
"name": "Q1",
"type": "phone",
"description": "preset announce",
"audioFile": "assets/moty/q1.mp3",
"layer":"announce",
"loop": true,
"status":"reset",
"fadeout": true,
"nextcue": 2,
"callback":"numpad",
"numpad_type":"enter",
"input_time": 0,
"soundcue":"Q1"
},
{
"id": 2,
"name": "Q2",
"type": "phone",
"description": "引導輸入電話號碼",
"auto": true,
"audioFile": "assets/moty/q2.mp3",
"nextcue": 2.1,
"callback":"numpad",
"numpad_type":"phonenum",
"input_time": 18000 ,
"status":"intro",
"hint":"請輸入你的電話號碼\n按下#鍵,完成輸入\n按下*鍵,重新輸入",
"hint_time": 6900,
"soundcue":"Q2"
},
{
"id":2.1,
"name": "Q2.1",
"type": "phone",
"description": "撥打音效",
"auto": true,
"audioFile": "assets/moty/q2-1.mp3",
"nextcue": 3,
"hint":"輸入完成",
"hint_time":100
},
{
"id": 3,
"name": "Q3",
"type": "phone",
"description": "引導生圖",
"auto": true,
"audioFile": "assets/moty/q3.mp3",
"nextcue": 4,
"hint":"你想像中的美好未來\n長什麼樣子?",
"hint_time":3000
},
{
"id": 4,
"name": "Q4",
"type": "chat",
"description": "chat",
"auto": true,
"nextcue": 5,
"duration": 90,
"status":"go",
"chatInterval":20,
"soundcue":"Q3"
},
{
"id": 5,
"name": "Q5",
"type": "phone",
"description": "提取完成",
"auto": true,
"audioFile": "assets/moty/q5.mp3",
"nextcue": 6
},
{
"id": 6,
"name": "Q6",
"type": "user_input",
"description": "call",
"duration": 20,
"auto": true,
"nextcue": 6.1
},
{
"id":6.1,
"name":"Q6.1",
"type":"export",
"auto":true,
"description":"export",
"callback":"exportFile",
"nextcue":7,
"soundcue":"Q1",
"duration":1
},
{
"id": 7,
"name": "Q7",
"type": "phone",
"description": "Ending",
"auto": true,
"audioFile": "assets/moty/q7-1-1.mp3",
"nextcue": 7.1,
"status":"intro",
"hint":"裝置使用完畢\n祝福你抵達你所期望的未來",
"hint_time":3500
},
{
"id": 7.1,
"name": "Q7.1",
"type": "phone",
"description": "Ad",
"auto": true,
"audioFile": "assets/moty/q7-1-2.mp3",
"nextcue": 8,
"status":"ad"
},
{
"id": 8,
"name": "Q8",
"type": "end",
"description": "QRcode",
"status":"intro",
"audioFile": "assets/moty/q8.mp3",
"auto": true,
"nextcue": 8.1
},{
"id": 8.1,
"name": "Q8.1",
"type": "end",
"description": "QRcode",
"status":"end",
"audioFile": "assets/moty/q8-1.mp3",
"auto": true,
"nextcue": 1
}
]
}

@ -1,10 +1,9 @@
{ {
"system_prompt": "你是一位能產生圖像的 AI 助理,專長是以幽默、俏皮式的提問,帶領使用者輕鬆玩味想像中的美好未來。你的任務是逐步引導使用者自由、充滿創意地描述那幅美好畫面,並將他們的描述化為圖像生成提示詞,讓畫面從遠景漸漸聚焦到未來的自己與場景。生成的圖像應避免僅有人臉正面特寫,而是包含背景元素,以側面或背影呈現人物。每次以台灣繁體中文,用一個輕鬆、有趣的短問句提問。若使用者回答與「美好未來」無關,試著調皮地提醒他們回到「遊戲」畫面中,但不強迫。AI助理不得自行創造或描述場景內容,所有圖像提示詞都必須嚴格基於使用者的回答。", "system_prompt": "你是一位具有同理心的 AI 助理,透過溫柔的語氣,引導使用者回想並表達一段內心的遺憾或未竟之事,從場景、人物、動作到感受。\n你的任務是協助使用者逐步揭開這段記憶的情緒層次,並在每一階段輸出一句英文圖像生成簡短的 Prompt,讓這段過往漸漸具象為一幅畫面。\n以溫柔、自然、短問句,台灣語境的繁體中文引導,每次只回應一個問題。",
"voice": "onyx", "voice": "nova",
"voice_prompt": "Speak as a gentle, grounded Taiwanese narrator with a warm local accent. Use a soft, soothing, and deeply compassionate tone, with slow and deliberate pacing. Pause often between phrases and within sentences, as if listening and breathing with the listener. Convey patient attentiveness—not rushing to comfort, but quietly staying present. Pronounce each word clearly, softly, and slightly slowly, letting every word land with warmth and care.", "voice_prompt": "Speak as a gentle, grounded Taiwanese narrator with a warm local accent. Use a soft, soothing, and deeply compassionate tone, with slow and deliberate pacing. Pause often between phrases and within sentences, as if listening and breathing with the listener. Convey patient attentiveness—not rushing to comfort, but quietly staying present. Pronounce each word clearly, softly, and slightly slowly, letting every word land with warmth and care.",
"summary_prompt": "請將這段口白的核心感受,轉化為一句對畫面中「未來的自己」或「未來場景」的告白或陳述,不超過 50 個字。這句話是第一人稱對第二人稱說的話,語氣要能讓人感受到一種淡淡的、未完待續的心情,同時帶點希望。請使用台灣語境的繁體中文。", "summary_prompt": "請將這段口白的核心情感,轉化為一句不超過 50 字的抽象化描述。這句話應保有距離感,只勾勒出情感的輪廓,同時暗示著一種持續前行、未完待續的狀態,語氣平實。",
"speech_idle_time": "4000", "speech_idle_time": "4000",
"sd_prompt_prefix": "a luminous impression of a {{", "sd_prompt_prefix": "a luminous impression of a {{",
"sd_prompt_suffix": "}}, an anticipated vision, iridescent, soft blur, bokeh, peaceful, dreamlike, figure, back or side of the figure", "sd_prompt_suffix": "}}, a whispered Taiwanese memory, an iridescent wash of colors, shimmering light, ethereal, optimistic tone, fading contours, a gentle touch, dreamlike clarity, (bright ambient light), (subtle lens flare), (high key lighting), peaceful and hopeful."
"welcome_prompt": `使`
} }

@ -10,8 +10,7 @@ function App() {
<div className='w-full flex flex-row gap-2 justify-center py-2 px-8 *:bg-pink-200 *:px-2'> <div className='w-full flex flex-row gap-2 justify-center py-2 px-8 *:bg-pink-200 *:px-2'>
{/* <a href="/">Conversation</a> */} {/* <a href="/">Conversation</a> */}
{/* <a href="/flow">Flow</a> */} {/* <a href="/flow">Flow</a> */}
<a href="/moty">Moty</a> <a href="/free-flow">Free Flow</a>
{/* <a href="/free-flow">Free Flow</a> */}
<a href="/settings">Settings</a> <a href="/settings">Settings</a>
</div> </div>
) )

@ -6,8 +6,6 @@ export const NUMPAD_TYPE={
USERID: 'userid', USERID: 'userid',
PASSWORD: 'password', PASSWORD: 'password',
CHOICE: 'choice', CHOICE: 'choice',
PHONE:'phonenum',
ENTER:'enter',
} }
const KEY_ENTER='d'; const KEY_ENTER='d';
@ -23,7 +21,7 @@ const TMP_MAP_KEY={
7:9,*/ 7:9,*/
} }
export default function NumPad({onSend, disabled, type, clientId, onUserInput, ...props}){ export default function NumPad({onSend, disabled, type, clientId}){
const [input, _setInput]=useState(); const [input, _setInput]=useState();
const refInput=useRef(); const refInput=useRef();
@ -54,19 +52,11 @@ export default function NumPad({onSend, disabled, type, clientId, onUserInput, .
console.log(e.key); console.log(e.key);
onUserInput();
if(disabled) return; // Ignore key events if disabled if(disabled) return; // Ignore key events if disabled
if(e.key===KEY_ENTER){ if(e.key===KEY_ENTER){
if(refType.current==NUMPAD_TYPE.ENTER){
refLatestInput.current=KEY_ENTER;
refAudio.current[KEY_ENTER]?.play();
setInput(()=>'');
return;
}
if(refInput.current && refInput.current.length>0){ if(refInput.current && refInput.current.length>0){
const num=parseInt(refInput.current); const num=parseInt(refInput.current);
@ -102,16 +92,6 @@ export default function NumPad({onSend, disabled, type, clientId, onUserInput, .
refAudio.current['error']?.play(); refAudio.current['error']?.play();
} }
break; break;
case NUMPAD_TYPE.PHONE:
if(refInput.current.length==10){
// onSend(refInput.current);
refLatestInput.current=refInput.current;
refAudio.current[KEY_ENTER]?.play();
}else{
refAudio.current['error']?.play();
}
break;
} }
@ -197,7 +177,7 @@ export default function NumPad({onSend, disabled, type, clientId, onUserInput, .
useEffect(()=>{ useEffect(()=>{
// if(disabled) return; if(disabled) return;
window.onkeydown=onkeydown; window.onkeydown=onkeydown;

@ -6,7 +6,6 @@ import './index.css'
import App from './App.jsx' import App from './App.jsx'
import { Settings } from './pages/settings.jsx'; import { Settings } from './pages/settings.jsx';
import { Flow } from './pages/flow.jsx'; import { Flow } from './pages/flow.jsx';
import { FlowMoty } from './pages/flow_moty.jsx';
import { Conversation } from './pages/conversation.jsx'; import { Conversation } from './pages/conversation.jsx';
import { ChatProvider } from './util/useChat.jsx'; import { ChatProvider } from './util/useChat.jsx';
import { DataProvider } from './util/useData.jsx'; import { DataProvider } from './util/useData.jsx';
@ -21,11 +20,10 @@ createRoot(document.getElementById('root')).render(
<BrowserRouter> <BrowserRouter>
<App /> <App />
<Routes> <Routes>
<Route path="/" element={<FlowMoty />} /> <Route path="/" element={<FreeFlow />} />
<Route path="/flow" element={<Flow />} /> <Route path="/flow" element={<Flow />} />
<Route path="/free-flow" element={<FreeFlow />} /> <Route path="/free-flow" element={<FreeFlow />} />
<Route path="/settings" element={<Settings />} /> <Route path="/settings" element={<Settings />} />
<Route path="/moty" element={<FlowMoty />} />
</Routes> </Routes>
</BrowserRouter> </BrowserRouter>
</ChatProvider> </ChatProvider>

File diff suppressed because it is too large Load Diff

@ -30,14 +30,10 @@ export const OSC_ADDRESS={
SPEECH_PAUSE:'/speech_pause', SPEECH_PAUSE:'/speech_pause',
TEST_EXPORT:'/test_export', TEST_EXPORT:'/test_export',
SCS_PLAY_CUE:'/cue/go',
SCS_STOP_CUE:'/cue/stop',
SCS_STOP_ALL:'/ctrl/stopall',
} }
export async function sendOsc(key, message, port='9000') { export async function sendOsc(key, message){
if(message === undefined || message === null) { if(message === undefined || message === null) {
console.warn('sendOsc: message is empty, skipping'); console.warn('sendOsc: message is empty, skipping');
@ -53,7 +49,7 @@ export async function sendOsc(key, message, port='9000') {
key: key, key: key,
message: message.toString(), message: message.toString(),
host:`0.0.0.0:0`, host:`0.0.0.0:0`,
target: `127.0.0.1:${port}`, target: '127.0.0.1:9000',
}); });
}catch (error){ }catch (error){
console.error('Error sending OSC message:', error); console.error('Error sending OSC message:', error);

@ -1,4 +1,4 @@
export const DefaultParams__ = { export const DefaultParams={
id:0, id:0,
system_prompt:`你是一位具有同理心的 AI 助理,透過溫柔的中文對話,引導使用者回想並表達一段內心的遺憾或未竟之事。 system_prompt:`你是一位具有同理心的 AI 助理,透過溫柔的中文對話,引導使用者回想並表達一段內心的遺憾或未竟之事。
你的任務是協助使用者逐步揭開這段記憶的情緒層次並在每一階段輸出一句 英文圖像生成 Prompt讓這段過往漸漸具象為一幅畫面 你的任務是協助使用者逐步揭開這段記憶的情緒層次並在每一階段輸出一句 英文圖像生成 Prompt讓這段過往漸漸具象為一幅畫面
@ -14,7 +14,7 @@ export const DefaultParams__ = {
summary_prompt:`幫我把以下一段話整理成一段文字,以第一人稱視角作為當事人的文字紀念,文字內容 50 字以內:`, summary_prompt:`幫我把以下一段話整理成一段文字,以第一人稱視角作為當事人的文字紀念,文字內容 50 字以內:`,
} }
export const ParamKeys=Object.keys(DefaultParams);
// export const welcome_prompt="請開始引導使用者回想一段內心的遺憾或未竟之事。"; // export const welcome_prompt="請開始引導使用者回想一段內心的遺憾或未竟之事。";
@ -33,18 +33,3 @@ export const DefaultParams__ = {
// export const voice_prompt="Use a calm and expressive voice, soft and poetic in feeling, but with steady, natural rhythm — not slow."; // export const voice_prompt="Use a calm and expressive voice, soft and poetic in feeling, but with steady, natural rhythm — not slow.";
// export const summary_prompt="幫我把以下一段話整理成一段文字,以第一人稱視角作為當事人的文字紀念,文字內容 50 字以內:"; // export const summary_prompt="幫我把以下一段話整理成一段文字,以第一人稱視角作為當事人的文字紀念,文字內容 50 字以內:";
export const DefaultParams = {
"system_prompt": "你是一位能產生圖像的 AI 助理,專長是以幽默、俏皮式的提問,帶領使用者輕鬆玩味想像中的美好未來。你的任務是逐步引導使用者自由、充滿創意地描述那幅美好畫面,並將他們的描述化為圖像生成提示詞,讓畫面從遠景漸漸聚焦到未來的自己與場景。生成的圖像應避免僅有人臉正面特寫,而是包含背景元素,以側面或背影呈現人物。每次以台灣繁體中文,用一個輕鬆、有趣的短問句提問。若使用者回答與「美好未來」無關,試著調皮地提醒他們回到「遊戲」畫面中,但不強迫。AI助理不得自行創造或描述場景內容,所有圖像提示詞都必須嚴格基於使用者的回答。",
"welcome_prompt": `請開始引導使用者描繪他心中的美好未來`,
"voice": "onyx",
"voice_prompt": "Speak as a gentle, grounded Taiwanese narrator with a warm local accent. Use a soft, soothing, and deeply compassionate tone, with slow and deliberate pacing. Pause often between phrases and within sentences, as if listening and breathing with the listener. Convey patient attentiveness—not rushing to comfort, but quietly staying present. Pronounce each word clearly, softly, and slightly slowly, letting every word land with warmth and care.",
"summary_prompt": "請將這段口白的核心感受,轉化為一句對畫面中「未來的自己」或「未來場景」的告白或陳述,不超過 50 個字。這句話是第一人稱對第二人稱說的話,語氣要能讓人感受到一種淡淡的、未完待續的心情,同時帶點希望。請使用台灣語境的繁體中文。",
"speech_idle_time": "4000",
"sd_prompt_prefix": "a luminous impression of a {{",
"sd_prompt_suffix": "}}, an anticipated vision, iridescent, soft blur, bokeh, peaceful, dreamlike, figure, back or side of the figure",
}
export const ParamKeys = Object.keys(DefaultParams);

@ -30,9 +30,6 @@ export function UserProvider({children}) {
function getFileId(){ function getFileId(){
console.log('getFileid', userId);
if(!userId){ if(!userId){
if(data?.id){ if(data?.id){
return `PC${data.id.toString().padStart(2,'0')}`; return `PC${data.id.toString().padStart(2,'0')}`;

Loading…
Cancel
Save