main
reng 4 months ago
parent 0dba15b34e
commit e627a7e5d8
  1. 1740
      vite/package-lock.json
  2. 1
      vite/package.json
  3. 21
      vite/public/cuelist_demo2.json
  4. 43
      vite/src/comps/numpad.jsx
  5. 22
      vite/src/pages/flow_free.jsx
  6. 35
      vite/src/util/backend.js
  7. 3
      vite/src/util/osc.js
  8. 43
      vite/src/util/useUser.jsx

1740
vite/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -14,6 +14,7 @@
"@tauri-apps/plugin-fs": "^2.3.0",
"@tauri-apps/plugin-http": "^2.4.4",
"@tauri-apps/plugin-opener": "^2.4.0",
"firebase": "^12.1.0",
"gsap": "^3.13.0",
"moment": "^2.30.1",
"react": "^19.1.0",

@ -36,7 +36,8 @@
"auto": false,
"audioFile": "assets/ai/ai-01.mp3",
"nextcue": 4.01,
"callback":"numpad"
"callback":"numpad",
"numpad_type":"userid"
},
{
"id": 4.01,
@ -129,8 +130,16 @@
"description": "call",
"duration": 30,
"auto": true,
"nextcue": 5.2,
"callback":"summary"
"nextcue": 5.11
},
{
"id": 5.11,
"name": "Q5.11",
"type": "summary",
"description": "結束逼",
"auto": true,
"audioFile": "assets/sfx/sfx-08.mp3",
"nextcue": 5.2
},
{
"id": 5.2,
@ -148,6 +157,7 @@
"description": "保留刪除操作說明",
"audioFile": "assets/ai/ai-06.mp3",
"callback":"numpad",
"numpad_type":"choice",
"auto": false,
"branch":{
"1": {
@ -172,14 +182,15 @@
"auto": false,
"nextcue": 6,
"audioFile": "assets/ai/ai-07.mp3",
"callback":"numpad"
"callback":"numpad",
"numpad_type":"password"
},
{
"id": 5.5,
"name": "Q5.5",
"type": "phone",
"description": "刪除",
"auto": false,
"auto": true,
"nextcue": 6,
"audioFile": "assets/ai/ai-08.mp3"
},

@ -1,4 +1,11 @@
import { use, useEffect, useRef, useState } from "react";
import { useEffect, useRef, useState } from "react";
export const NUMPAD_TYPE={
USERID: 'userid',
PASSWORD: 'password',
CHOICE: 'choice',
}
const KEY_ENTER='q';
const KEY_BACKSPACE='a';
@ -13,10 +20,13 @@ const TMP_MAP_KEY={
7:9,
}
export default function NumPad({onSend, disabled}){
export default function NumPad({onSend, disabled, type}){
const [input, _setInput]=useState();
const refInput=useRef();
const refType=useRef(type);
const setInput=(valueFunc)=>{
if(typeof valueFunc==='function'){
_setInput(valueFunc(refInput.current));
@ -40,12 +50,34 @@ export default function NumPad({onSend, disabled}){
if(refInput.current && refInput.current.length>0){
const num=parseInt(refInput.current);
switch(refType.current){
case NUMPAD_TYPE.USERID:
if(num>=1 && num<=24){
onSend(num);
refAudio.current[KEY_ENTER]?.play();
}else{
refAudio.current['error']?.play();
}
break;
case NUMPAD_TYPE.PASSWORD:
if(num>=0 && num<=999){
onSend(num.toString().padStart(3, '0'));
refAudio.current[KEY_ENTER]?.play();
}else{
refAudio.current['error']?.play();
}
break;
case NUMPAD_TYPE.CHOICE:
if(num==1 || num==9){
onSend(num);
refAudio.current[KEY_ENTER]?.play();
}else{
refAudio.current['error']?.play();
}
break;
}
}else{
@ -71,6 +103,11 @@ export default function NumPad({onSend, disabled}){
}
useEffect(() => {
refType.current = type; // Update the type reference
setInput(()=>''); // Reset input when type changes
}, [type]);
useEffect(() => {
@ -111,7 +148,7 @@ export default function NumPad({onSend, disabled}){
return (
<div className={`flex flex-col justify-center ${disabled?'bg-gray-400': 'bg-yellow-400'} text-4xl overflow-hidden relative`}>
<label className="absolute top-0 left-0"> Numpad</label>
<label className="absolute top-0 left-0"> Numpad {type}</label>
{input}
</div>
);

@ -6,7 +6,7 @@ import { Countdown } from "../comps/timer";
import { Status, useChat } from "../util/useChat";
import { getSummary } from "../util/chat";
import { saveHistory } from "../util/output";
import NumPad from "../comps/numpad";
import NumPad, { NUMPAD_TYPE } from "../comps/numpad";
import { Light } from "../comps/light";
import { useData } from "../util/useData";
import VoiceAnalysis from "../comps/voiceanalysis";
@ -55,7 +55,7 @@ export function FreeFlow(){
//const [speechPaused, setSpeechPaused]=useState(false);
const [chatStatus, setChatStatus] = useState(ChatStatus.System); // System, User, Processing
const { userId, setUserId, getFileId, setPassword, reset:resetUser } = useUser();
const { userId, setUserId, getFileId, setPassword, reset:resetUser, uploadHistory } = useUser();
const refTimer=useRef();
const refAudio=useRef();
@ -133,8 +133,9 @@ export function FreeFlow(){
audio.onended = () => {
if(refCurrentCue.current?.type!='chat'){
onCueEnd();
setChatStatus(ChatStatus.End);
onCueEnd();
console.log('Audio ended, ending current cue');
}else{
setChatStatus(ChatStatus.User); // Reset chat status to User after audio ends
@ -281,6 +282,8 @@ export function FreeFlow(){
refChatCueEnd.current=true;
return;
}
uploadHistory(history); // Save chat history when cue ends
}
@ -318,14 +321,14 @@ export function FreeFlow(){
let cue=refCurrentCue.current;
let next=cue.nextcue;
switch(cue.id){
case 4:
switch(cue.numpad_type){
case NUMPAD_TYPE.USERID:
setUserId(()=>mess);
break;
case 5.3:
case NUMPAD_TYPE.CHOICE:
next=cue.branch[mess.toString()].nextcue;
break;
case 5.4:
case NUMPAD_TYPE.PASSWORD:
setPassword(()=>mess);
break;
}
@ -507,7 +510,10 @@ export function FreeFlow(){
<button className="!bg-red-300" onClick={onStop}>Stop</button>
{/* <button onClick={saveImage}>Save image</button> */}
<NumPad onSend={onNumpad} disabled={currentCue?.callback !== 'numpad' || chatStatus!=ChatStatus.End} />
<NumPad onSend={onNumpad}
disabled={currentCue?.callback !== 'numpad'}
type={currentCue?.numpad_type}
/>
<Light ref={refLight} />
<VoiceAnalysis/>
{/* <div className="flex flex-col">

@ -0,0 +1,35 @@
import { initializeApp } from "firebase/app";
import { getFirestore, doc, setDoc } from "firebase/firestore";
const firebaseConfig = {
apiKey: "AIzaSyD1VzUKXt0JskwyfjfIAbdROzPNB3fTIw0",
authDomain: "uc-24070-thegreattipsy.firebaseapp.com",
projectId: "uc-24070-thegreattipsy",
storageBucket: "uc-24070-thegreattipsy.firebasestorage.app",
messagingSenderId: "772804793020",
appId: "1:772804793020:web:258003100900c20e0fb6b9",
measurementId: "G-1CRHMJY4L9"
};
const CollectionName="records";
// Initialize Firebase
const app = initializeApp(firebaseConfig);
export async function updateUser(id, data){
if(!id || !data) {
console.error("Invalid id or data for updateUser");
return;
}
try{
const db = getFirestore(app);
await setDoc(doc(db, CollectionName, id), data);
console.log("Document successfully written!");
}catch(error){
console.error("Error writing document: ", error);
};
}

@ -10,7 +10,10 @@ export const OSC_ADDRESS={
SCRIPT: '/script',
SUMMARY: '/summary',
PROMPT: '/prompt',
EXPORT: '/export',
SAVE: '/save',
DISCARD: '/discard',
PASSWORD: '/password',
}

@ -1,5 +1,6 @@
import { createContext, useState, useEffect, useContext } from "react";
import moment from "moment";
import { updateUser } from "./backend";
const userContext=createContext();
@ -30,6 +31,46 @@ export function UserProvider({children}) {
setPassword(null);
}
function saveHistory(history) {
console.log('Saving history:', history);
const data={
history,
}
updateUser(getFileId(), data)
.then(() => {
console.log("History saved successfully");
})
.catch((error) => {
console.error("Error saving history:", error);
});
}
useEffect(()=>{
console.log("User ID changed:", password, sessionId, userId);
if(!userId) return;
const data={
userId,
sessionId,
password,
date: moment().format("YYYY-MM-DD"),
fileId: getFileId(),
};
console.log("Updating user data:", data);
updateUser(getFileId(), data)
.then(() => {
console.log("User data updated successfully");
})
.catch((error) => {
console.error("Error updating user data:", error);
});
},[password, sessionId]);
useEffect(() => {
let symbol='';
@ -49,7 +90,7 @@ export function UserProvider({children}) {
}, [userId]);
return (
<userContext.Provider value={{ userId, setUserId, getFileId, setPassword, reset }}>
<userContext.Provider value={{ userId, setUserId, getFileId, setPassword, reset, uploadHistory: saveHistory }}>
{children}
</userContext.Provider>
);

Loading…
Cancel
Save