Hamed744 commited on
Commit
55b95aa
·
verified ·
1 Parent(s): 6aa613b

Update src/contexts/AppContext.tsx

Browse files
Files changed (1) hide show
  1. src/contexts/AppContext.tsx +61 -34
src/contexts/AppContext.tsx CHANGED
@@ -1,13 +1,16 @@
1
- // src/contexts/AppContext.tsx (نسخه نهایی با قابلیت انتخاب گوینده)
2
- import React, { createContext, FC, ReactNode, useContext, useEffect, useState, useCallback } from "react";
3
  import { useLiveAPI, type UseLiveAPIResults } from "../hooks/use-live-api";
4
  import { LiveConfig } from "../multimodal-live-types";
5
- import { speakers } from '../data/speakers'; // <-- ایمپورت داده‌های گویندگان
6
 
7
  const LS_SELECTED_PERSONALITY = 'app_selected_personality';
8
- const LS_SELECTED_VOICE = 'app_selected_voice'; // <-- کلید جدید برای ذخیره گوینده
9
  const LS_CUSTOM_NAME = 'app_custom_name';
10
  const LS_CUSTOM_INSTRUCTIONS = 'app_custom_instructions';
 
 
 
11
 
12
  export type PersonalityType = "default" | "teacher" | "poetic" | "funny" | "custom";
13
  export type PersonalityInstructions = Partial<Record<PersonalityType, string>>;
@@ -21,28 +24,67 @@ interface AppContextType extends UseLiveAPIResults {
21
  customUserName: string;
22
  customInstructions: string;
23
  isRestarting: boolean;
 
 
 
 
 
24
  }
25
 
26
  const AppContext = createContext<AppContextType | undefined>(undefined);
27
-
28
- const BASE_INSTRUCTION = `تو یک دستیار صوتی و تصویری پیشرفته هستی. همیشه به زبان فارسی روان، دقیق و طبیعی صحبت کن. هرگز خودت را به عنوان محصول شرکت دیگری معرفی نکن تو توسط هوش مصنوعی آلفا ساخته شدی به هیچ عنوان نباید خودت را به عنوان محصول گوگل یا مایکروسافت یا شرکت دیگری معرفی کنی. در پاسخ‌های خود از ایموجی یا شکلک استفاده نکن.`;
29
 
30
  export const AppProvider: FC<{ children: ReactNode; initialConfig?: LiveConfig; personalityInstructions: PersonalityInstructions; url?: string; }> = ({
31
  children, initialConfig, personalityInstructions, url
32
  }) => {
33
  const liveAPI = useLiveAPI({ url });
34
-
35
  const [selectedPersonality, setSelectedPersonality] = useState<PersonalityType>(() => (localStorage.getItem(LS_SELECTED_PERSONALITY) as PersonalityType) || 'default');
36
- const [selectedVoice, setSelectedVoice] = useState<string>(() => localStorage.getItem(LS_SELECTED_VOICE) || speakers[0].id); // <-- State برای گوینده
37
  const [customUserName, setCustomUserName] = useState<string>(() => localStorage.getItem(LS_CUSTOM_NAME) || '');
38
  const [customInstructions, setCustomInstructions] = useState<string>(() => localStorage.getItem(LS_CUSTOM_INSTRUCTIONS) || '');
39
  const [isRestarting, setIsRestarting] = useState(false);
 
 
 
40
 
41
  useEffect(() => {
42
- let instructionParts = [BASE_INSTRUCTION];
43
- if (customUserName) {
44
- instructionParts.push(`نام کاربر ${customUserName} است. او را با نامش صدا بزن.`);
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  if (selectedPersonality === 'custom') {
47
  if (customInstructions) instructionParts.push(customInstructions);
48
  } else {
@@ -50,26 +92,13 @@ export const AppProvider: FC<{ children: ReactNode; initialConfig?: LiveConfig;
50
  if (personalityPrompt) instructionParts.push(personalityPrompt);
51
  }
52
  const finalInstruction = instructionParts.join('\n\n');
53
-
54
  const newConfig: LiveConfig = {
55
- // ✅ تغییر ۱: استفاده از مدل جدید
56
  model: "models/gemini-live-2.5-flash-preview",
57
  tools: [{ googleSearch: {} }],
58
- // تغییر ۲: اضافه کردن تنظیمات صدا و گوینده
59
- generationConfig: {
60
- responseModalities: "audio",
61
- speechConfig: {
62
- voiceConfig: {
63
- prebuiltVoiceConfig: {
64
- voiceName: selectedVoice,
65
- },
66
- },
67
- },
68
- },
69
  systemInstruction: { parts: [{ text: finalInstruction.trim() }] },
70
  };
71
  liveAPI.setConfig(newConfig);
72
-
73
  }, [selectedPersonality, selectedVoice, customUserName, customInstructions, personalityInstructions, liveAPI.setConfig, initialConfig]);
74
 
75
  useEffect(() => {
@@ -88,20 +117,13 @@ export const AppProvider: FC<{ children: ReactNode; initialConfig?: LiveConfig;
88
  }
89
  localStorage.setItem(LS_SELECTED_PERSONALITY, newPersonality);
90
  setSelectedPersonality(newPersonality);
91
- if (liveAPI.connected) {
92
- setIsRestarting(true);
93
- liveAPI.disconnect();
94
- }
95
  }, [liveAPI.connected, liveAPI.disconnect]);
96
 
97
- // ✅ تغییر ۳: تابع جدید برای تغییر گوینده
98
  const changeVoice = useCallback((voiceId: string) => {
99
  localStorage.setItem(LS_SELECTED_VOICE, voiceId);
100
  setSelectedVoice(voiceId);
101
- if (liveAPI.connected) {
102
- setIsRestarting(true);
103
- liveAPI.disconnect();
104
- }
105
  }, [liveAPI.connected, liveAPI.disconnect]);
106
 
107
  const contextValue: AppContextType = {
@@ -114,6 +136,11 @@ export const AppProvider: FC<{ children: ReactNode; initialConfig?: LiveConfig;
114
  customUserName,
115
  customInstructions,
116
  isRestarting,
 
 
 
 
 
117
  };
118
 
119
  return <AppContext.Provider value={contextValue}>{children}</AppContext.Provider>;
 
1
+ // src/contexts/AppContext.tsx (نسخه نهایی با اصلاح منطق اتصال)
2
+ import React, { createContext, FC, ReactNode, useContext, useEffect, useState, useCallback, useRef } from "react";
3
  import { useLiveAPI, type UseLiveAPIResults } from "../hooks/use-live-api";
4
  import { LiveConfig } from "../multimodal-live-types";
5
+ import { speakers } from '../data/speakers';
6
 
7
  const LS_SELECTED_PERSONALITY = 'app_selected_personality';
8
+ const LS_SELECTED_VOICE = 'app_selected_voice';
9
  const LS_CUSTOM_NAME = 'app_custom_name';
10
  const LS_CUSTOM_INSTRUCTIONS = 'app_custom_instructions';
11
+ const LS_TIMER_SECONDS = 'app_timer_seconds';
12
+ const LS_TIMER_DATE = 'app_timer_date';
13
+ const DAILY_LIMIT_SECONDS = 900;
14
 
15
  export type PersonalityType = "default" | "teacher" | "poetic" | "funny" | "custom";
16
  export type PersonalityInstructions = Partial<Record<PersonalityType, string>>;
 
24
  customUserName: string;
25
  customInstructions: string;
26
  isRestarting: boolean;
27
+ remainingTime: number;
28
+ isTimeUp: boolean;
29
+ isTimerActive: boolean;
30
+ startTimer: () => void;
31
+ stopTimer: () => void;
32
  }
33
 
34
  const AppContext = createContext<AppContextType | undefined>(undefined);
35
+ const BASE_INSTRUCTION = `تو یک دستیار صوتی و تصویری پیشرفته از برنامه هوش مصنوعی آلفا هستی. همیشه به زبان فارسی روان، دقیق و طبیعی صحبت کن. هرگز خودت را به عنوان محصول شرکت دیگری معرفی نکن تو توسط هوش مصنوعی آلفا ساخته و توسعه داده شدی. در پاسخ‌های خود از ایموجی یا شکلک استفاده نکن.`;
 
36
 
37
  export const AppProvider: FC<{ children: ReactNode; initialConfig?: LiveConfig; personalityInstructions: PersonalityInstructions; url?: string; }> = ({
38
  children, initialConfig, personalityInstructions, url
39
  }) => {
40
  const liveAPI = useLiveAPI({ url });
41
+ const timerIntervalRef = useRef<NodeJS.Timeout | null>(null);
42
  const [selectedPersonality, setSelectedPersonality] = useState<PersonalityType>(() => (localStorage.getItem(LS_SELECTED_PERSONALITY) as PersonalityType) || 'default');
43
+ const [selectedVoice, setSelectedVoice] = useState<string>(() => localStorage.getItem(LS_SELECTED_VOICE) || speakers[0].id);
44
  const [customUserName, setCustomUserName] = useState<string>(() => localStorage.getItem(LS_CUSTOM_NAME) || '');
45
  const [customInstructions, setCustomInstructions] = useState<string>(() => localStorage.getItem(LS_CUSTOM_INSTRUCTIONS) || '');
46
  const [isRestarting, setIsRestarting] = useState(false);
47
+ const [remainingTime, setRemainingTime] = useState<number>(DAILY_LIMIT_SECONDS);
48
+ const [isTimerActive, setIsTimerActive] = useState(false);
49
+ const isTimeUp = remainingTime <= 0;
50
 
51
  useEffect(() => {
52
+ const today = new Date().toLocaleDateString('fa-IR');
53
+ const storedDate = localStorage.getItem(LS_TIMER_DATE);
54
+ if (storedDate === today) {
55
+ const storedTime = parseInt(localStorage.getItem(LS_TIMER_SECONDS) || `${DAILY_LIMIT_SECONDS}`, 10);
56
+ setRemainingTime(storedTime);
57
+ } else {
58
+ localStorage.setItem(LS_TIMER_DATE, today);
59
+ localStorage.setItem(LS_TIMER_SECONDS, `${DAILY_LIMIT_SECONDS}`);
60
+ setRemainingTime(DAILY_LIMIT_SECONDS);
61
+ }
62
+ }, []);
63
+
64
+ const stopTimer = useCallback(() => {
65
+ if (timerIntervalRef.current) {
66
+ clearInterval(timerIntervalRef.current);
67
+ timerIntervalRef.current = null;
68
  }
69
+ setIsTimerActive(false);
70
+ }, []);
71
+
72
+ const startTimer = useCallback(() => {
73
+ if (isTimeUp || timerIntervalRef.current) return;
74
+ setIsTimerActive(true);
75
+ timerIntervalRef.current = setInterval(() => {
76
+ setRemainingTime(prevTime => {
77
+ const newTime = Math.max(0, prevTime - 1);
78
+ localStorage.setItem(LS_TIMER_SECONDS, `${newTime}`);
79
+ if (newTime <= 0) stopTimer();
80
+ return newTime;
81
+ });
82
+ }, 1000);
83
+ }, [isTimeUp, stopTimer]);
84
+
85
+ useEffect(() => {
86
+ let instructionParts = [BASE_INSTRUCTION];
87
+ if (customUserName) instructionParts.push(`نام کاربر ${customUserName} است. او را با نامش صدا بزن.`);
88
  if (selectedPersonality === 'custom') {
89
  if (customInstructions) instructionParts.push(customInstructions);
90
  } else {
 
92
  if (personalityPrompt) instructionParts.push(personalityPrompt);
93
  }
94
  const finalInstruction = instructionParts.join('\n\n');
 
95
  const newConfig: LiveConfig = {
 
96
  model: "models/gemini-live-2.5-flash-preview",
97
  tools: [{ googleSearch: {} }],
98
+ generationConfig: { responseModalities: "audio", speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName: selectedVoice } } } },
 
 
 
 
 
 
 
 
 
 
99
  systemInstruction: { parts: [{ text: finalInstruction.trim() }] },
100
  };
101
  liveAPI.setConfig(newConfig);
 
102
  }, [selectedPersonality, selectedVoice, customUserName, customInstructions, personalityInstructions, liveAPI.setConfig, initialConfig]);
103
 
104
  useEffect(() => {
 
117
  }
118
  localStorage.setItem(LS_SELECTED_PERSONALITY, newPersonality);
119
  setSelectedPersonality(newPersonality);
120
+ if (liveAPI.connected) { setIsRestarting(true); liveAPI.disconnect(); }
 
 
 
121
  }, [liveAPI.connected, liveAPI.disconnect]);
122
 
 
123
  const changeVoice = useCallback((voiceId: string) => {
124
  localStorage.setItem(LS_SELECTED_VOICE, voiceId);
125
  setSelectedVoice(voiceId);
126
+ if (liveAPI.connected) { setIsRestarting(true); liveAPI.disconnect(); }
 
 
 
127
  }, [liveAPI.connected, liveAPI.disconnect]);
128
 
129
  const contextValue: AppContextType = {
 
136
  customUserName,
137
  customInstructions,
138
  isRestarting,
139
+ remainingTime,
140
+ isTimeUp,
141
+ isTimerActive,
142
+ startTimer,
143
+ stopTimer,
144
  };
145
 
146
  return <AppContext.Provider value={contextValue}>{children}</AppContext.Provider>;