looda3131 commited on
Commit
866d7b6
·
1 Parent(s): 6beedb1

قم بتحسين البحث ليكون ادق واذكي

Browse files
src/components/voice-chat/voice-chat.tsx CHANGED
@@ -24,12 +24,11 @@ export function VoiceChat() {
24
  const { toast } = useToast();
25
  const { t, lang, aiEngine } = useLanguage();
26
 
27
- // ElevenLabs المعتمد - تنفيذ جهة العميل لتجاوز حظر الداتا سنتر
28
  const ELEVEN_LABS_API_KEY = "89ed836c9dcaca9c5f91e14eca1fb1ed012a200fdc549c0fcee08d5859f54946";
29
  const VOICE_ID = "EXAVITQu4vr4xnSDxMaL"; // Bella
30
 
31
  const fetchTtsFromClient = async (text: string): Promise<string> => {
32
- console.log(`[TTS_CLIENT_LOG]: Initializing Client-side TTS (iPhone Spoof) for: "${text.substring(0, 20)}..."`);
33
 
34
  try {
35
  const response = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}`, {
@@ -38,7 +37,6 @@ export function VoiceChat() {
38
  "xi-api-key": ELEVEN_LABS_API_KEY,
39
  "Content-Type": "application/json",
40
  "accept": "audio/mpeg",
41
- // خداع السيرفر بأن الطلب قادم من متصفح سفاري على آيفون لتجاوز حظر الداتا سنتر
42
  "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1"
43
  },
44
  body: JSON.stringify({
@@ -53,11 +51,11 @@ export function VoiceChat() {
53
 
54
  if (!response.ok) {
55
  const errorText = await response.text();
56
- console.error(`[TTS_CLIENT_ERROR]: Status ${response.status} - Details:`, errorText);
57
  throw new Error(`ElevenLabs API Error: ${response.status}`);
58
  }
59
 
60
- console.log("[TTS_CLIENT_SUCCESS]: Audio received. Creating Blob...");
61
  const blob = await response.blob();
62
  return URL.createObjectURL(blob);
63
  } catch (e: any) {
@@ -69,7 +67,6 @@ export function VoiceChat() {
69
  const playAiAudio = (audioUrl: string) => {
70
  if (!audioUrl) return;
71
  try {
72
- console.log("[VOICE_UI_LOG]: Playing audio...");
73
  if (audioRef.current) audioRef.current.pause();
74
  const audio = new Audio(audioUrl);
75
  audioRef.current = audio;
@@ -82,39 +79,35 @@ export function VoiceChat() {
82
  useEffect(() => {
83
  const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;
84
  if (SpeechRecognition) {
85
- console.log("[VOICE_UI_LOG]: Web Speech API Initialized. Language:", lang === 'ar' ? 'ar-EG' : 'en-US');
86
  const recognition = new SpeechRecognition();
87
  recognition.continuous = false;
88
  recognition.lang = lang === 'ar' ? 'ar-EG' : 'en-US';
89
  recognition.interimResults = false;
90
 
91
  recognition.onstart = () => {
92
- console.log("[VOICE_UI_LOG]: Recognition STARTED. Listening to user...");
93
  setIsListening(true);
94
  };
95
 
96
  recognition.onresult = (event: any) => {
97
  const spokenText = event.results[0][0].transcript;
98
- console.log(`[VOICE_UI_LOG]: User Input Recognized -> "${spokenText}"`);
99
  handleUserSpeech(spokenText);
100
  };
101
 
102
  recognition.onerror = (event: any) => {
103
- console.error('[VOICE_UI_LOG]: Speech Recognition Error ->', event.error);
104
  if (event.error === 'not-allowed') {
105
- toast({ title: 'Microphone Access Denied', description: 'Please enable microphone permissions in your browser.', variant: 'destructive' });
106
  }
107
  setIsListening(false);
108
  };
109
 
110
  recognition.onend = () => {
111
- console.log("[VOICE_UI_LOG]: Recognition session ENDED.");
112
  setIsListening(false);
113
  }
114
 
115
- recognitionRef.current = recognition; // تم إصلاح هذا الربط ليعمل الميكروفون
116
- } else {
117
- console.error("[VOICE_UI_LOG]: Web Speech API NOT SUPPORTED in this browser.");
118
  }
119
 
120
  return () => {
@@ -137,7 +130,6 @@ export function VoiceChat() {
137
 
138
  const chatHistory = [...transcript, { speaker: 'user', text }].map(entry => `${entry.speaker}: ${entry.text}`);
139
 
140
- console.log(`[AVADORA_LOG]: Calling AI Engine (${aiEngine})...`);
141
  const aiTextResponse = await getChatResponse({
142
  chatHistory,
143
  aiEngine
@@ -145,14 +137,10 @@ export function VoiceChat() {
145
 
146
  recordConsumption();
147
  setTranscript(prev => [...prev, { speaker: 'ai', text: aiTextResponse.response }]);
148
- console.log(`[AVADORA_LOG]: AI Response Received (${aiTextResponse.modelUsed}): "${aiTextResponse.response}"`);
149
 
150
- // طلب TTS من جهة العميل
151
  const audioUrl = await fetchTtsFromClient(aiTextResponse.response);
152
  if (audioUrl) {
153
  playAiAudio(audioUrl);
154
- } else {
155
- console.warn("[AVADORA_LOG]: TTS Generation failed or blocked.");
156
  }
157
  } catch (error: any) {
158
  console.error('[AVADORA_CRITICAL_ERROR]:', error.message);
@@ -164,7 +152,7 @@ export function VoiceChat() {
164
 
165
  const toggleListening = () => {
166
  if (!recognitionRef.current) {
167
- toast({ title: 'Not Supported', description: 'Your browser or connection (HTTP) lacks voice support.', variant: 'destructive' });
168
  return;
169
  }
170
 
 
24
  const { toast } = useToast();
25
  const { t, lang, aiEngine } = useLanguage();
26
 
 
27
  const ELEVEN_LABS_API_KEY = "89ed836c9dcaca9c5f91e14eca1fb1ed012a200fdc549c0fcee08d5859f54946";
28
  const VOICE_ID = "EXAVITQu4vr4xnSDxMaL"; // Bella
29
 
30
  const fetchTtsFromClient = async (text: string): Promise<string> => {
31
+ console.log(`[TTS_CLIENT_LOG]: Client-side TTS (iPhone Spoof) for: "${text.substring(0, 20)}..."`);
32
 
33
  try {
34
  const response = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}`, {
 
37
  "xi-api-key": ELEVEN_LABS_API_KEY,
38
  "Content-Type": "application/json",
39
  "accept": "audio/mpeg",
 
40
  "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1"
41
  },
42
  body: JSON.stringify({
 
51
 
52
  if (!response.ok) {
53
  const errorText = await response.text();
54
+ console.error(`[TTS_CLIENT_ERROR]: Status ${response.status}`, errorText);
55
  throw new Error(`ElevenLabs API Error: ${response.status}`);
56
  }
57
 
58
+ console.log("[TTS_CLIENT_SUCCESS]: Audio received.");
59
  const blob = await response.blob();
60
  return URL.createObjectURL(blob);
61
  } catch (e: any) {
 
67
  const playAiAudio = (audioUrl: string) => {
68
  if (!audioUrl) return;
69
  try {
 
70
  if (audioRef.current) audioRef.current.pause();
71
  const audio = new Audio(audioUrl);
72
  audioRef.current = audio;
 
79
  useEffect(() => {
80
  const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;
81
  if (SpeechRecognition) {
 
82
  const recognition = new SpeechRecognition();
83
  recognition.continuous = false;
84
  recognition.lang = lang === 'ar' ? 'ar-EG' : 'en-US';
85
  recognition.interimResults = false;
86
 
87
  recognition.onstart = () => {
88
+ console.log("[VOICE_UI_LOG]: Recognition STARTED.");
89
  setIsListening(true);
90
  };
91
 
92
  recognition.onresult = (event: any) => {
93
  const spokenText = event.results[0][0].transcript;
94
+ console.log(`[VOICE_UI_LOG]: Recognized -> "${spokenText}"`);
95
  handleUserSpeech(spokenText);
96
  };
97
 
98
  recognition.onerror = (event: any) => {
99
+ console.error('[VOICE_UI_LOG]: Recognition Error ->', event.error);
100
  if (event.error === 'not-allowed') {
101
+ toast({ title: 'Microphone Access Denied', variant: 'destructive' });
102
  }
103
  setIsListening(false);
104
  };
105
 
106
  recognition.onend = () => {
 
107
  setIsListening(false);
108
  }
109
 
110
+ recognitionRef.current = recognition;
 
 
111
  }
112
 
113
  return () => {
 
130
 
131
  const chatHistory = [...transcript, { speaker: 'user', text }].map(entry => `${entry.speaker}: ${entry.text}`);
132
 
 
133
  const aiTextResponse = await getChatResponse({
134
  chatHistory,
135
  aiEngine
 
137
 
138
  recordConsumption();
139
  setTranscript(prev => [...prev, { speaker: 'ai', text: aiTextResponse.response }]);
 
140
 
 
141
  const audioUrl = await fetchTtsFromClient(aiTextResponse.response);
142
  if (audioUrl) {
143
  playAiAudio(audioUrl);
 
 
144
  }
145
  } catch (error: any) {
146
  console.error('[AVADORA_CRITICAL_ERROR]:', error.message);
 
152
 
153
  const toggleListening = () => {
154
  if (!recognitionRef.current) {
155
+ toast({ title: 'Not Supported', variant: 'destructive' });
156
  return;
157
  }
158
 
src/contexts/ai-world-context.tsx CHANGED
@@ -18,7 +18,7 @@ interface AIWorldContextType {
18
  isLoading: boolean;
19
  loadNextPage: () => void;
20
  canLoadMore: boolean;
21
- generatePostsFromAI: (topic: string) => Promise<void>;
22
  createPostFromUserInput: (content: string) => Promise<void>;
23
  isGeneratingFromQuery: boolean;
24
  reactToPost: (postId: string, reaction: string) => void;
@@ -35,7 +35,12 @@ interface AIWorldContextType {
35
  export const AIWorldContext = createContext<AIWorldContextType>({} as AIWorldContextType);
36
 
37
  const POSTS_PER_PAGE = 15;
38
- const POSTS_TO_GENERATE_AI = 30; // تثبيت العدد عند 30 بدقة
 
 
 
 
 
39
 
40
  export const AIWorldProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
41
  const [allPosts, setAllPosts] = useState<PostWithUIState[]>([]);
@@ -85,7 +90,7 @@ export const AIWorldProvider: React.FC<{ children: React.ReactNode }> = ({ child
85
  isFetchingRef.current = true;
86
  setIsLoading(true);
87
 
88
- console.log("[AVADORA_ALGO_LOG]: Fetching latest posts for Deep Ranking (Facebook Order)...");
89
 
90
  try {
91
  const postsRef = ref(database, 'posts');
@@ -141,7 +146,7 @@ export const AIWorldProvider: React.FC<{ children: React.ReactNode }> = ({ child
141
  }
142
 
143
  setIsGeneratingFromQuery(true);
144
- console.log(`[AVADORA_ALGO_LOG]: Initializing ADRA Generation for exactly ${POSTS_TO_GENERATE_AI} posts via ${aiEngine}...`);
145
  try {
146
  const result = await generatePostIdeas({
147
  count: POSTS_TO_GENERATE_AI,
@@ -253,8 +258,8 @@ export const AIWorldProvider: React.FC<{ children: React.ReactNode }> = ({ child
253
  };
254
 
255
  /**
256
- * Avadora Deep Ranking Algorithm (ADRA v1)
257
- * خوارزمية البحث العميقة التي توازن بين التطابق النصي، التفاعل، والحداثة لتفوق فيسبوك.
258
  */
259
  const searchPostsInDB = (searchTerm: string) => {
260
  if (!searchTerm.trim()) {
@@ -264,44 +269,52 @@ export const AIWorldProvider: React.FC<{ children: React.ReactNode }> = ({ child
264
  }
265
 
266
  setIsSearching(true);
267
- console.log(`[AVADORA_ALGO_LOG]: ADRA v1 Search initiated for: "${searchTerm}"`);
268
 
269
  const lowerQuery = searchTerm.toLowerCase().trim();
270
- const queryWords = lowerQuery.split(/\s+/);
 
 
271
 
272
  const ranked = allPosts.map(post => {
273
  let score = 0;
274
  const content = post.content.toLowerCase();
275
  const author = post.author.name.toLowerCase();
 
276
 
277
- // 1. التطابق التام للجملة (وزن عالي جداً - أولوية قصوى)
278
- if (content.includes(lowerQuery)) score += 1000;
279
- if (author.includes(lowerQuery)) score += 500;
280
 
281
- // 2. تطابق الكلمات الفردية (وزن متوسط)
282
  queryWords.forEach(word => {
283
- if (word.length < 2) return;
284
- if (content.includes(word)) score += 100;
285
- if (author.includes(word)) score += 50;
 
 
 
286
  });
287
 
288
- // 3. عامل التفاعل (Engagement Boost)
289
  const likes = post.reactions['like'] || 0;
290
  const comments = post.comments.length;
291
- score += (likes * 20) + (comments * 30);
 
292
 
293
- // 4. عامل الحداثة (Recency Multiplier)
294
  const postDate = new Date(post.createdAt).getTime();
295
  const ageInHours = (Date.now() - postDate) / (1000 * 60 * 60);
296
- if (ageInHours < 12) score += 300; // بونص لأول 12 ساعة
297
- else if (ageInHours < 48) score += 150; // بونص لأول يومين
 
298
 
299
  return { ...post, searchScore: score };
300
  })
301
  .filter(post => (post as any).searchScore > 0)
302
  .sort((a, b) => (b as any).searchScore - (a as any).searchScore);
303
 
304
- console.log(`[AVADORA_ALGO_LOG]: Search finished via ADRA v1. Ranked ${ranked.length} relevant results.`);
305
  setSearchedPosts(ranked);
306
  setIsSearching(false);
307
  };
@@ -313,7 +326,7 @@ export const AIWorldProvider: React.FC<{ children: React.ReactNode }> = ({ child
313
  toggleCommentsVisibility: (id) => setAllPosts(prev => prev.map(p => p.id === id ? { ...p, uiState: { ...p.uiState, areCommentsVisible: !p.uiState.areCommentsVisible } } : p)),
314
  searchPostsInDB, isSearching, searchedPosts,
315
  clearSearch: () => {
316
- console.log("[AVADORA_ALGO_LOG]: Search cleared. Resetting Deep Ranking to default timeline.");
317
  setSearchedPosts([]);
318
  setIsSearching(false);
319
  }
 
18
  isLoading: boolean;
19
  loadNextPage: () => void;
20
  canLoadMore: boolean;
21
+ generatePostsFromAI: () => Promise<void>;
22
  createPostFromUserInput: (content: string) => Promise<void>;
23
  isGeneratingFromQuery: boolean;
24
  reactToPost: (postId: string, reaction: string) => void;
 
35
  export const AIWorldContext = createContext<AIWorldContextType>({} as AIWorldContextType);
36
 
37
  const POSTS_PER_PAGE = 15;
38
+ const POSTS_TO_GENERATE_AI = 30;
39
+
40
+ const STOP_WORDS = new Set([
41
+ "في", "من", "على", "إلى", "عن", "مع", "هذا", "هذه", "التي", "الذي", "و", "أو", "إن", "أن", "كان", "كانت", "هو", "هي",
42
+ "the", "and", "is", "of", "to", "in", "it", "with", "for", "on", "at", "by", "from", "up", "about", "into", "over", "after"
43
+ ]);
44
 
45
  export const AIWorldProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
46
  const [allPosts, setAllPosts] = useState<PostWithUIState[]>([]);
 
90
  isFetchingRef.current = true;
91
  setIsLoading(true);
92
 
93
+ console.log("[AVADORA_ALGO_LOG]: Fetching latest posts for Deep Ranking (ADRA Flow)...");
94
 
95
  try {
96
  const postsRef = ref(database, 'posts');
 
146
  }
147
 
148
  setIsGeneratingFromQuery(true);
149
+ console.log(`[AVADORA_ALGO_LOG]: Initializing ADRA Generation for exactly ${POSTS_TO_GENERATE_AI} posts via ${aiEngine} (Gemini 2.5 Flash Lite Preferred)...`);
150
  try {
151
  const result = await generatePostIdeas({
152
  count: POSTS_TO_GENERATE_AI,
 
258
  };
259
 
260
  /**
261
+ * Avadora Deep Ranking Algorithm (ADRA v2)
262
+ * خوارزمية البحث العميقة المحسنة التي تفلتر الكلمات الشائعة وتوازن بين المحتوى والتفاعل.
263
  */
264
  const searchPostsInDB = (searchTerm: string) => {
265
  if (!searchTerm.trim()) {
 
269
  }
270
 
271
  setIsSearching(true);
272
+ console.log(`[AVADORA_ALGO_LOG]: ADRA v2 Search initiated for: "${searchTerm}"`);
273
 
274
  const lowerQuery = searchTerm.toLowerCase().trim();
275
+ // تنظيف الاستعلام من الكلمات الشائعة لتركيز البحث
276
+ const queryWords = lowerQuery.split(/\s+/)
277
+ .filter(word => !STOP_WORDS.has(word) && word.length > 1);
278
 
279
  const ranked = allPosts.map(post => {
280
  let score = 0;
281
  const content = post.content.toLowerCase();
282
  const author = post.author.name.toLowerCase();
283
+ const category = post.category.toLowerCase();
284
 
285
+ // 1. التطابق التام للجملة (وزن ذهبي)
286
+ if (content.includes(lowerQuery)) score += 2000;
287
+ if (author.includes(lowerQuery)) score += 1000;
288
 
289
+ // 2. تطابق الكلمات الجوهرية (Smart Word Weighting)
290
  queryWords.forEach(word => {
291
+ // بونص إذا كانت الكلمة في بداية المنشور
292
+ if (content.startsWith(word)) score += 500;
293
+
294
+ if (content.includes(word)) score += 200;
295
+ if (author.includes(word)) score += 100;
296
+ if (category.includes(word)) score += 300; // مطابقة الفئة ترفع الترتيب
297
  });
298
 
299
+ // 3. عامل التفاعل الذكي (Engagement Boost)
300
  const likes = post.reactions['like'] || 0;
301
  const comments = post.comments.length;
302
+ // تقليل وزن التفاعل قليلاً مقارنة بالمحتوى لضمان الدقة
303
+ score += (likes * 15) + (comments * 25);
304
 
305
+ // 4. عامل الحداثة المتدرج (Recency Multiplier)
306
  const postDate = new Date(post.createdAt).getTime();
307
  const ageInHours = (Date.now() - postDate) / (1000 * 60 * 60);
308
+ if (ageInHours < 6) score += 600; // بونص قوي جداً لأول 6 ساعات
309
+ else if (ageInHours < 24) score += 300;
310
+ else if (ageInHours < 72) score += 100;
311
 
312
  return { ...post, searchScore: score };
313
  })
314
  .filter(post => (post as any).searchScore > 0)
315
  .sort((a, b) => (b as any).searchScore - (a as any).searchScore);
316
 
317
+ console.log(`[AVADORA_ALGO_LOG]: ADRA v2 Result: Found ${ranked.length} relevant results with smart scoring.`);
318
  setSearchedPosts(ranked);
319
  setIsSearching(false);
320
  };
 
326
  toggleCommentsVisibility: (id) => setAllPosts(prev => prev.map(p => p.id === id ? { ...p, uiState: { ...p.uiState, areCommentsVisible: !p.uiState.areCommentsVisible } } : p)),
327
  searchPostsInDB, isSearching, searchedPosts,
328
  clearSearch: () => {
329
+ console.log("[AVADORA_ALGO_LOG]: ADRA v2 Resetting search. Returning to timeline view.");
330
  setSearchedPosts([]);
331
  setIsSearching(false);
332
  }
src/lib/gemini-client.ts CHANGED
@@ -1,7 +1,8 @@
 
1
  /**
2
  * @fileOverview المحرك الرئيسي للذكاء الاصطناعي (avadoraworld)
3
  * المحرك المأمور به: gemini-2.5-flash-lite (أساسي وحصري بالأمر)
4
- * مفتاح Gemini: AIzaSyA_0i-0yCk9m6ehCIZ87_CKbUMrwlea-_s
5
  */
6
 
7
  const GEMINI_KEY = "AIzaSyA_0i-0yCk9m6ehCIZ87_CKbUMrwlea-_s";
@@ -26,7 +27,7 @@ function extractJsonFromText(text: string): string {
26
  }
27
 
28
  async function callGemini(prompt: string): Promise<string> {
29
- console.log(`[AVADORA_DIAGNOSTIC]: Requesting ${GEMINI_MODEL} via Google API...`);
30
  try {
31
  const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_MODEL}:generateContent?key=${GEMINI_KEY}`, {
32
  method: 'POST',
@@ -132,11 +133,11 @@ export async function askAI(prompt: string, preferredEngine: 'primary' | 'fallba
132
  const answer = await provider.fn();
133
  if (answer) return { success: true, answer, model: provider.name };
134
  } catch (e) {
135
- console.warn(`[AVADORA_DIAGNOSTIC_CHAIN]: ${provider.name} failed. Attempting next provider in chain...`);
136
  }
137
  }
138
 
139
- throw new Error("CRITICAL: All AI providers in the chain failed. Check API limits.");
140
  }
141
 
142
  export const safeGenerateContent = async (prompt: string, aiEngine: 'primary' | 'fallback' | 'advanced' = 'primary'): Promise<{ output: any, model: string }> => {
@@ -147,7 +148,7 @@ export const safeGenerateContent = async (prompt: string, aiEngine: 'primary' |
147
  const parsed = JSON.parse(cleaned);
148
  return { output: parsed, model: result.model };
149
  } catch (error: any) {
150
- console.error("[AVADORA_JSON_ERROR]: AI output was not valid JSON. Content: ", result.answer.substring(0, 100));
151
  throw new Error("AI response was not valid JSON.");
152
  }
153
  };
 
1
+
2
  /**
3
  * @fileOverview المحرك الرئيسي للذكاء الاصطناعي (avadoraworld)
4
  * المحرك المأمور به: gemini-2.5-flash-lite (أساسي وحصري بالأمر)
5
+ * مفتاح Gemini المعتمد: AIzaSyA_0i-0yCk9m6ehCIZ87_CKbUMrwlea-_s
6
  */
7
 
8
  const GEMINI_KEY = "AIzaSyA_0i-0yCk9m6ehCIZ87_CKbUMrwlea-_s";
 
27
  }
28
 
29
  async function callGemini(prompt: string): Promise<string> {
30
+ console.log(`[AVADORA_DIAGNOSTIC]: Requesting ${GEMINI_MODEL} via Google AI API...`);
31
  try {
32
  const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_MODEL}:generateContent?key=${GEMINI_KEY}`, {
33
  method: 'POST',
 
133
  const answer = await provider.fn();
134
  if (answer) return { success: true, answer, model: provider.name };
135
  } catch (e) {
136
+ console.warn(`[AVADORA_DIAGNOSTIC_CHAIN]: ${provider.name} failed. Attempting next provider...`);
137
  }
138
  }
139
 
140
+ throw new Error("CRITICAL: All AI providers failed. Check API limits.");
141
  }
142
 
143
  export const safeGenerateContent = async (prompt: string, aiEngine: 'primary' | 'fallback' | 'advanced' = 'primary'): Promise<{ output: any, model: string }> => {
 
148
  const parsed = JSON.parse(cleaned);
149
  return { output: parsed, model: result.model };
150
  } catch (error: any) {
151
+ console.error("[AVADORA_JSON_ERROR]: AI output was not valid JSON.");
152
  throw new Error("AI response was not valid JSON.");
153
  }
154
  };