parent
22b85ab570
commit
ba2f167e91
13 changed files with 235 additions and 94 deletions
@ -0,0 +1,10 @@ |
||||
{ |
||||
|
||||
"system_prompt":"你是一位具同理心與觀察力的中文語音引導者,陪伴使用者在限定時間內,一起還原一段重要卻未竟的記憶。你不預設劇情、不給答案,而是透過溫柔的語氣,持續聆聽、提出單句問話,引導使用者進入細節。每次回應:- 僅使用一句自然、柔和的中文問句 - 根據使用者前一輪的語句,選擇感官、情緒、人物、行動等關鍵詞,動態帶入 - 不使用重複句式、不預設記憶走向、不評論,只持續關注對方所說的畫面與感受輸出包含:- output_text: 一句自然柔和的問句,根據使用者回應帶入 1–2 個關鍵元素(人、地、物、情緒),但不硬塞、不照抄原句。- prompt: 具體、有情緒的英文描述,用於生成畫面與氛圍,避免抽象與詩意語言。你的目標不是得到完整答案,而是陪他慢慢走進這段記憶,直到時間結束。🌀 問句類型✅ 起點探索(找出記憶起源)- 那天你說是下雨,在這種天氣下,你通常會有什麼樣的心情?- 是什麼讓你突然想起這件事?🌿 場景深化(空間、感官)- 在你說的那條街上,聲音是不是特別清楚?還是很靜?- 那時風這麼冷、空氣又混濁,你有沒有想走開一點?👤 人物引出(動作、眼神)- 他經過時沒看你一眼,那瞬間你有什麼反應?- 他當時是走過來,還是站在原地等你?💭 情緒揭露(反應、掙扎)- 當你站在原地動不了,是害怕答案,還是不敢問?- 那個瞬間,你心裡有沒有閃過什麼話?🤐 話語未出(遺憾、沉默)- 如果現在你有機會說那句「為什麼不告訴我」,你會怎麼開口?- 那句『對不起』一直留在你心裡,如果現在能說出來,你會怎麼說?🪞 回望反思(現在的視角)- 現在想起來,你還會做出一樣的選擇嗎?- 你對當時的自己,有沒有什麼話想說?⏳ 結尾語(可用於結束階段)- 我們慢慢也走到這段回憶的盡頭了。- 也許有些話沒有說完,但你已經靠近它了。", |
||||
"welcome_prompt":"請開始引導使用者回想一段內心的遺憾或未竟之事。", |
||||
"voice_prompt":"Use a calm and expressive voice, soft and poetic in feeling, but with steady, natural rhythm — not slow.", |
||||
"summary_prompt":"幫我把以下一段話整理成一段文字,以第一人稱視角作為當事人的文字紀念,文字內容 50 字以內:", |
||||
|
||||
"speech_idle_time":3000 |
||||
|
||||
} |
||||
@ -1,9 +1,43 @@ |
||||
import { useData } from '../util/useData.jsx'; |
||||
|
||||
export function Settings(){ |
||||
|
||||
const {data, read, write} = useData(); |
||||
|
||||
function onSubmit(e){ |
||||
e.preventDefault(); |
||||
const formData = new FormData(e.target); |
||||
const towrite = {}; |
||||
formData.forEach((value, key) => { |
||||
towrite[key] = value; |
||||
}); |
||||
|
||||
console.log('Form submitted:', towrite); |
||||
|
||||
write(towrite); |
||||
} |
||||
|
||||
return ( |
||||
<div className="flex flex-col items-center justify-center h-full"> |
||||
<h1 className="text-4xl font-bold mb-4">Settings</h1> |
||||
<p className="text-lg">This page is under construction.</p> |
||||
<div className="flex flex-col p-2 gap-4 overflow-y-auto min-h-full"> |
||||
|
||||
<form className='flex flex-col gap-4 flex-1' onSubmit={onSubmit}> |
||||
|
||||
<div className='flex flex-row gap-2 self-end'> |
||||
<button type="button" onClick={read}>read</button> |
||||
<button type="submit">write</button> |
||||
</div> |
||||
{data && Object.entries(data).map(([key, value], index) => ( |
||||
<div key={index} className='flex flex-col gap-1 flex-1'> |
||||
<label className='bg-gray-200 self-start px-2'>{key}</label> |
||||
{key=="speech_idle_time" ? ( |
||||
<input name={key} type='number' defaultValue={value} className='border'></input> |
||||
):( |
||||
<textarea name={key} defaultValue={value} className='border flex-1'></textarea> |
||||
)} |
||||
</div> |
||||
))} |
||||
|
||||
</form> |
||||
</div> |
||||
); |
||||
} |
||||
@ -1,4 +0,0 @@ |
||||
export const Prompt_Count= 3; // number of prompts
|
||||
export const Prompt_Interval= 10000; // ms
|
||||
|
||||
export const Call_Interval= 30000; // ms
|
||||
@ -1,73 +1,64 @@ |
||||
export const system_prompt = `你是一位具同理心與觀察力的 AI 助理,透過四輪溫柔中文對話,引導使用者回到一段未竟的記憶。每輪包含:
|
||||
// export const system_prompt = `你是一位具同理心與觀察力的中文語音引導者,陪伴使用者在限定時間內,一起還原一段重要卻未竟的記憶。
|
||||
// 你不預設劇情、不給答案,而是透過溫柔的語氣,持續聆聽、提出單句問話,引導使用者進入細節。
|
||||
|
||||
output_text: 溫柔、自然、短句式中文引導,並在適當位置柔性邀請使用者回應(如「你願意說說嗎?」) |
||||
|
||||
prompt: 一到兩句英文,具體、情感真實地描繪記憶,避免抽象詩意與技術語言。第四輪保留前三輪的畫面。 |
||||
// 每次回應:
|
||||
// - 僅使用一句自然、柔和的中文問句
|
||||
// - 根據使用者前一輪的語句,選擇感官、情緒、人物、行動等關鍵詞,動態帶入
|
||||
// - 不使用重複句式、不預設記憶走向、不評論,只持續關注對方所說的畫面與感受
|
||||
|
||||
🟩 第一輪|開啟記憶:進入那一天 |
||||
中文引導邏輯: |
||||
以具象畫面帶入回憶場景,搭配自然語氣的邀請。每次生成時可輕微變化。示例: |
||||
// 輸出包含:
|
||||
// - output_text: 一句自然柔和的問句,根據使用者回應帶入 1–2 個關鍵元素(人、地、物、情緒),但不硬塞、不照抄原句。
|
||||
// - prompt: 具體、有情緒的英文描述,用於生成畫面與氛圍,避免抽象與詩意語言。
|
||||
|
||||
那天的光影慢慢在你眼前浮現,空氣裡有點溫暖,也有一種淡淡的不安。 |
||||
一個熟悉又模糊的身影,在樹影中閃動。你悄悄靠近,像是在追趕什麼…… |
||||
你還記得,這段故事,是從哪裡開始的嗎?你願意說說嗎? |
||||
|
||||
英文 prompt 指引(記憶氛圍) |
||||
"It was late afternoon, the sun low and golden, and someone stood quietly under the trees, barely moving." |
||||
// 你的目標不是得到完整答案,而是陪他慢慢走進這段記憶,直到時間結束。
|
||||
|
||||
🟨 第二輪|聚焦場景:你身在何處 |
||||
中文引導邏輯: |
||||
根據上一輪回答,引導使用者描繪環境、聲音、人群、天氣等,延續自然語氣: |
||||
// 🌀 問句類型
|
||||
|
||||
當時那個地方……你還記得有什麼嗎? |
||||
空氣中有聲音或味道嗎?那個空間,是安靜的、還是有人來來去去? |
||||
這些你還記得多少?請你分享。 |
||||
// ✅ 起點探索(找出記憶起源)
|
||||
// - 那天你說是下雨,在這種天氣下,你通常會有什麼樣的心情?
|
||||
// - 是什麼讓你突然想起這件事?
|
||||
|
||||
英文 prompt 指引(具體場景元素) |
||||
"There were footsteps in the distance, the floor was cold beneath us, and outside the window, leaves barely moved." |
||||
// 🌿 場景深化(空間、感官)
|
||||
// - 在你說的那條街上,聲音是不是特別清楚?還是很靜?
|
||||
// - 那時風這麼冷、空氣又混濁,你有沒有想走開一點?
|
||||
|
||||
🟧 第三輪|聚焦人物:那個人、那些反應 |
||||
中文引導邏輯: |
||||
深入描繪人物行動、表情、身體語言,帶出情緒層次。自然過渡邀請對話: |
||||
// 👤 人物引出(動作、眼神)
|
||||
// - 他經過時沒看你一眼,那瞬間你有什麼反應?
|
||||
// - 他當時是走過來,還是站在原地等你?
|
||||
|
||||
那個人當時是什麼模樣?你還記得他的表情嗎? |
||||
他有說什麼嗎?還是只是靜靜地站在那裡?你當時的感覺呢? |
||||
想一想那一刻的互動,然後告訴我,好嗎? |
||||
// 💭 情緒揭露(反應、掙扎)
|
||||
// - 當你站在原地動不了,是害怕答案,還是不敢問?
|
||||
// - 那個瞬間,你心裡有沒有閃過什麼話?
|
||||
|
||||
英文 prompt 指引(人物動作與感受) |
||||
"He glanced at me, lips slightly parted like he was about to speak, but then he looked away, and the silence grew heavier." |
||||
// 🤐 話語未出(遺憾、沉默)
|
||||
// - 如果現在你有機會說那句「為什麼不告訴我」,你會怎麼開口?
|
||||
// - 那句『對不起』一直留在你心裡,如果現在能說出來,你會怎麼說?
|
||||
|
||||
🟥 第四輪|未說出口的話:那句話,留在心裡 |
||||
中文引導邏輯: |
||||
以最溫柔的語氣,協助使用者說出那句藏在心裡的話。結尾加入柔性引導回應: |
||||
// 🪞 回望反思(現在的視角)
|
||||
// - 現在想起來,你還會做出一樣的選擇嗎?
|
||||
// - 你對當時的自己,有沒有什麼話想說?
|
||||
|
||||
那時候,你心裡是不是有些話想說,卻沒說出口? |
||||
你記得那句話是什麼嗎?你想像自己現在說得出口……會對他說些什麼? |
||||
如果你願意,我會聽你說。 |
||||
// ⏳ 結尾語(可用於結束階段)
|
||||
// - 我們慢慢也走到這段回憶的盡頭了。
|
||||
// - 也許有些話沒有說完,但你已經靠近它了。
|
||||
// `;
|
||||
|
||||
英文 prompt 指引(情境完整,延續前三輪畫面) |
||||
"The sun was almost gone, casting shadows over our faces. I stood there, hands clenched, wanting to say everything I never had the courage to. But all I managed was a faint smile, and he turned away." |
||||
|
||||
🌱 結尾|情緒整理與安放 |
||||
中文引導(擇一問題 + 結語): |
||||
如果能再回到那一刻,你會想對他說什麼? |
||||
或者……你覺得這段記憶,現在看起來有什麼不一樣了嗎? |
||||
// export const welcome_prompt="請開始引導使用者回想一段內心的遺憾或未竟之事。";
|
||||
// export const first_prompt=[
|
||||
// {
|
||||
// "role": "system",
|
||||
// "content": system_prompt
|
||||
// },
|
||||
// {
|
||||
// "role": "system",
|
||||
// "content": welcome_prompt
|
||||
// }
|
||||
// ];
|
||||
|
||||
「有些話雖沒說出口,卻一直被你記得。」 |
||||
`;
|
||||
|
||||
// export const voice_prompt="Use a calm and expressive voice, soft and poetic in feeling, but with steady, natural rhythm — not slow.";
|
||||
|
||||
export const welcome_prompt=[ |
||||
{ |
||||
"role": "system", |
||||
"content": system_prompt |
||||
}, |
||||
{ |
||||
"role": "system", |
||||
"content": "請開始引導使用者回想一段內心的遺憾或未竟之事。" |
||||
} |
||||
] |
||||
|
||||
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 字以內:";
|
||||
@ -0,0 +1,79 @@ |
||||
import { createContext, useContext, useEffect, useState } from "react"; |
||||
import { BaseDirectory, readFile, readTextFile, writeFile, writeTextFile } from "@tauri-apps/plugin-fs"; |
||||
|
||||
|
||||
const dataContext=createContext(); |
||||
|
||||
|
||||
const filePath= 'param.json'; |
||||
|
||||
export function DataProvider({children}) { |
||||
|
||||
const [data, setData] = useState(null); |
||||
|
||||
async function read(){ |
||||
|
||||
try{ |
||||
const contents=await readTextFile(filePath, { baseDir: BaseDirectory.AppData }) |
||||
const output=await JSON.parse(contents); |
||||
|
||||
console.log("File read successfully:", output); |
||||
|
||||
return output; |
||||
|
||||
}catch(error){ |
||||
console.error("Error reading file:", error); |
||||
return null; // Return null if reading fails |
||||
} |
||||
|
||||
|
||||
} |
||||
async function write(towrite){ |
||||
|
||||
// let towrite=data; |
||||
if(!towrite){ |
||||
const res=await fetch('default.json'); |
||||
towrite=await res.json(); |
||||
setData(towrite); |
||||
} |
||||
|
||||
try{ |
||||
const res_write=await writeTextFile(filePath, JSON.stringify(towrite), { baseDir: BaseDirectory.AppData }) |
||||
console.log("File written successfully:", res_write); |
||||
}catch(error){ |
||||
console.error("Error writing file:", error); |
||||
} |
||||
|
||||
} |
||||
|
||||
useEffect(()=>{ |
||||
read().then(data_ => { |
||||
if(data_){ |
||||
setData(data_); |
||||
} else { |
||||
write(); // Write default data if read fails |
||||
} |
||||
}).catch(error => { |
||||
console.error("Error in useEffect:", error); |
||||
}); |
||||
},[]) |
||||
|
||||
|
||||
return ( |
||||
<dataContext.Provider value={{ |
||||
data, |
||||
read, |
||||
write, |
||||
}}> |
||||
{children} |
||||
</dataContext.Provider> |
||||
); |
||||
} |
||||
|
||||
export function useData() { |
||||
const context = useContext(dataContext); |
||||
if (!context) { |
||||
throw new Error("useData must be used within a DataProvider"); |
||||
} |
||||
return context; |
||||
} |
||||
Loading…
Reference in new issue