looda3131 commited on
Commit
fd6ceab
·
1 Parent(s): 4a80719

طيب رائع لاكن انظر نريد مثلا ان البلاد تتحدد من قائمه بلدان وليس المسخد

Browse files
src/ai/flows/ai-generate-image-query.ts CHANGED
@@ -1,22 +1,20 @@
 
1
  'use server';
2
  /**
3
  * @fileOverview An AI agent to generate an image search query from post content.
4
- *
5
- * - generateImageQuery - A function that creates an image query.
6
- * - GenerateImageQueryInput - The input type for the function.
7
- * - GenerateImageQueryOutput - The return type for the function.
8
  */
9
 
10
  import { safeGenerateChat } from '@/lib/gemini-client';
11
  import type { GenerateImageQueryInput, GenerateImageQueryOutput } from './types';
12
 
13
- const promptTemplate = (content: string) => `Based on the following social media post content, generate a very precise and descriptive English search query for an image that perfectly fits the post's main idea, mood, and concept. This should be a detailed description of a scene or an abstract concept.
14
 
15
- **STRICT RULES:**
16
- 1. If the post is purely textual, poetic, or philosophical and doesn't need a specific image, you MUST return the exact query "text on color".
17
- 2. The query must NOT contain any words related to humans, people, faces, or bodies (e.g., 'man', 'woman', 'person', 'face', 'boy', 'girl'). Focus strictly on landscapes, objects, abstract art, animals, or patterns. For example, instead of "a sad man looking at the rain", use "rainy window pane focus on droplets". Instead of "a happy person celebrating", use "abstract fireworks explosion of color".
18
- 3. The query should be creative and evocative.
19
- 4. Only return the search query text, with no additional explanation or context.
20
 
21
  **Post Content:**
22
  "${content}"
@@ -28,5 +26,10 @@ export async function generateImageQuery(
28
  ): Promise<GenerateImageQueryOutput> {
29
  const prompt = promptTemplate(input.content);
30
  const query = await safeGenerateChat(prompt);
31
- return { imageQuery: query.trim() };
 
 
 
 
 
32
  }
 
1
+
2
  'use server';
3
  /**
4
  * @fileOverview An AI agent to generate an image search query from post content.
5
+ * Strictly enforced "NO HUMAN" policy for imagery.
 
 
 
6
  */
7
 
8
  import { safeGenerateChat } from '@/lib/gemini-client';
9
  import type { GenerateImageQueryInput, GenerateImageQueryOutput } from './types';
10
 
11
+ const promptTemplate = (content: string) => `Based on the following social media post content, generate a very precise and descriptive English search query for an image that fits the post's mood.
12
 
13
+ **STRICT RULES - NO HUMANS:**
14
+ 1. The query MUST NOT contain any words related to humans, people, faces, eyes, hands, men, women, children, or any biological human parts.
15
+ 2. Focus strictly on: nature, landscapes, inanimate objects, architecture, abstract patterns, animals, or celestial bodies.
16
+ 3. If the post content is too abstract, return "abstract textures and colors (no people)".
17
+ 4. Only return the search query text, with no additional explanation.
18
 
19
  **Post Content:**
20
  "${content}"
 
26
  ): Promise<GenerateImageQueryOutput> {
27
  const prompt = promptTemplate(input.content);
28
  const query = await safeGenerateChat(prompt);
29
+
30
+ // Safety fallback: strip any human-related words just in case
31
+ const humanWords = /\b(man|woman|person|people|face|boy|girl|human|body|hands|eyes|child|kid)\b/gi;
32
+ const sanitizedQuery = query.replace(humanWords, 'object').trim();
33
+
34
+ return { imageQuery: sanitizedQuery };
35
  }
src/ai/flows/ai-generate-post-ideas.ts CHANGED
@@ -4,26 +4,32 @@
4
  /**
5
  * @fileOverview An AI agent to generate a bulk of social media post ideas.
6
  * Now takes user location and language into account for better localization.
 
7
  */
8
 
9
  import { safeGenerateContent } from '@/lib/gemini-client';
10
  import type { GeneratePostIdeasInput, GeneratePostIdeasOutput } from './types';
11
 
12
- const promptTemplate = (count: number, location: string, language: string) => `You are a highly creative and insightful social media content creator. Your goal is to generate posts that feel authentic, relatable, and emotionally engaging.
13
 
14
  **CONTEXT:**
15
  - User Location: ${location}
16
  - Output Language: ${language === 'en' ? 'English' : 'Colloquial Egyptian Arabic'}
17
 
18
- **CRITICAL RULES:**
19
- 1. **Safety & Responsibility:** If the topic is inappropriate, refuse.
20
- 2. **Localization:** All content MUST reflect the culture, slang, and common topics relevant to ${location}. If the language is Arabic, use authentic, raw colloquial Egyptian Arabic. If English, use natural social media English.
21
- 3. **No Non-Verbal Cues:** Only text and emojis.
 
 
 
 
 
22
 
23
  Generate ${count} distinct post packages. Each package must contain:
24
  1. **content:** The post text.
25
  2. **isMeme:** Boolean.
26
- 3. **imageQuery:** Precise English search query (NO humans).
27
  4. **category:** 'funny', 'sad', 'deep', 'angry', 'inspirational', 'general'.
28
  5. **initialComments:** 3-5 realistic comments in the target language.
29
 
@@ -35,7 +41,7 @@ Generate ${count} distinct post packages. Each package must contain:
35
  {
36
  "content": "Post text",
37
  "isMeme": true,
38
- "imageQuery": "Image search query",
39
  "category": "funny",
40
  "initialComments": ["Comment 1", "Comment 2"]
41
  }
@@ -50,7 +56,7 @@ export async function generatePostIdeas(
50
  const location = input.location || 'Egypt';
51
  const language = input.language || 'ar';
52
 
53
- console.log(`AI REQUEST: Generating ${input.count} posts for ${location} in ${language}...`);
54
  const prompt = promptTemplate(input.count, location, language);
55
  const output = await safeGenerateContent(prompt);
56
  return output as GeneratePostIdeasOutput;
 
4
  /**
5
  * @fileOverview An AI agent to generate a bulk of social media post ideas.
6
  * Now takes user location and language into account for better localization.
7
+ * Strict safety and non-human imagery rules applied.
8
  */
9
 
10
  import { safeGenerateContent } from '@/lib/gemini-client';
11
  import type { GeneratePostIdeasInput, GeneratePostIdeasOutput } from './types';
12
 
13
+ const promptTemplate = (count: number, location: string, language: string) => `You are a culturally sensitive social media content creator. Your goal is to generate posts that feel authentic, relatable, and emotionally engaging for people in ${location}.
14
 
15
  **CONTEXT:**
16
  - User Location: ${location}
17
  - Output Language: ${language === 'en' ? 'English' : 'Colloquial Egyptian Arabic'}
18
 
19
+ **STRICT CULTURAL SAFETY RULES:**
20
+ 1. **NO Sexual Content:** Strictly prohibit any sexual themes, innuendos, or references to sexual activity.
21
+ 2. **NO Alcohol/Drugs:** Do not mention or promote alcohol, narcotics, or any illegal substances.
22
+ 3. **NO Offense:** Strictly avoid sensitive religious topics, hate speech, or offensive political debates.
23
+ 4. **Local Context:** Adapt your humor and topics to be relevant to the culture of ${location}. If in an Arab country, ensure respect for local customs.
24
+
25
+ **STRICT IMAGERY RULES:**
26
+ 1. **NO HUMANS:** The "imageQuery" field MUST NOT contain any words related to humans, people, faces, men, women, children, or body parts.
27
+ 2. **Focus on:** Landscapes, objects, nature, architecture, abstract art, textures, or animals.
28
 
29
  Generate ${count} distinct post packages. Each package must contain:
30
  1. **content:** The post text.
31
  2. **isMeme:** Boolean.
32
+ 3. **imageQuery:** Precise English search query (NO HUMANS ALLOWED).
33
  4. **category:** 'funny', 'sad', 'deep', 'angry', 'inspirational', 'general'.
34
  5. **initialComments:** 3-5 realistic comments in the target language.
35
 
 
41
  {
42
  "content": "Post text",
43
  "isMeme": true,
44
+ "imageQuery": "Landscape showing high mountains at dawn (no humans)",
45
  "category": "funny",
46
  "initialComments": ["Comment 1", "Comment 2"]
47
  }
 
56
  const location = input.location || 'Egypt';
57
  const language = input.language || 'ar';
58
 
59
+ console.log(`AI REQUEST: Generating ${input.count} posts for ${location} in ${language} with strict safety rules...`);
60
  const prompt = promptTemplate(input.count, location, language);
61
  const output = await safeGenerateContent(prompt);
62
  return output as GeneratePostIdeasOutput;
src/app/login/page.tsx CHANGED
@@ -3,7 +3,7 @@
3
 
4
  import { Button } from "@/components/ui/button";
5
  import { Header } from "@/components/header";
6
- import { Loader2, LogIn, ShieldCheck, MessageSquare, User, Lock, Chrome, MapPin, Calendar } from "lucide-react";
7
  import { useAuth } from "@/contexts/auth-context";
8
  import { useEffect, useState } from "react";
9
  import { useRouter } from "next/navigation";
@@ -13,6 +13,8 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
13
  import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
14
  import { useToast } from "@/hooks/use-toast";
15
  import { useLanguage } from "@/contexts/language-context";
 
 
16
 
17
  export default function LoginPage() {
18
  const { user, userData, loading: authLoading, signInWithGoogle, signInWithUsername, completeProfile } = useAuth();
@@ -64,6 +66,10 @@ export default function LoginPage() {
64
  const handleCompleteProfile = async (e: React.FormEvent) => {
65
  e.preventDefault();
66
  if (!validateAge(age)) return;
 
 
 
 
67
  setIsSigningIn(true);
68
  await completeProfile(parseInt(age), location);
69
  setIsSigningIn(false);
@@ -86,7 +92,7 @@ export default function LoginPage() {
86
  <form onSubmit={handleCompleteProfile}>
87
  <CardHeader>
88
  <CardTitle>إكمال البيانات</CardTitle>
89
- <CardDescription>يرجى إدخال عمرك ومنطقتك للمتابعة</CardDescription>
90
  </CardHeader>
91
  <CardContent className="space-y-4">
92
  <div className="space-y-2">
@@ -95,7 +101,19 @@ export default function LoginPage() {
95
  </div>
96
  <div className="space-y-2">
97
  <Label>{t.location}</Label>
98
- <Input value={location} onChange={e => setLocation(e.target.value)} placeholder="مثال: القاهرة، مصر" required />
 
 
 
 
 
 
 
 
 
 
 
 
99
  </div>
100
  </CardContent>
101
  <CardFooter>
@@ -156,14 +174,26 @@ export default function LoginPage() {
156
  <Label>{t.password}</Label>
157
  <Input type="password" value={password} onChange={e => setPassword(e.target.value)} required />
158
  </div>
159
- <div className="grid grid-cols-2 gap-4">
160
  <div className="space-y-2">
161
  <Label>{t.age}</Label>
162
  <Input type="number" value={age} onChange={e => setAge(e.target.value)} required />
163
  </div>
164
  <div className="space-y-2">
165
  <Label>{t.location}</Label>
166
- <Input value={location} onChange={e => setLocation(e.target.value)} required />
 
 
 
 
 
 
 
 
 
 
 
 
167
  </div>
168
  </div>
169
  </CardContent>
 
3
 
4
  import { Button } from "@/components/ui/button";
5
  import { Header } from "@/components/header";
6
+ import { Loader2, LogIn, MessageSquare, Chrome } from "lucide-react";
7
  import { useAuth } from "@/contexts/auth-context";
8
  import { useEffect, useState } from "react";
9
  import { useRouter } from "next/navigation";
 
13
  import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
14
  import { useToast } from "@/hooks/use-toast";
15
  import { useLanguage } from "@/contexts/language-context";
16
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
17
+ import { countries } from "@/lib/countries";
18
 
19
  export default function LoginPage() {
20
  const { user, userData, loading: authLoading, signInWithGoogle, signInWithUsername, completeProfile } = useAuth();
 
66
  const handleCompleteProfile = async (e: React.FormEvent) => {
67
  e.preventDefault();
68
  if (!validateAge(age)) return;
69
+ if (!location) {
70
+ toast({ title: t.mandatoryFields, variant: "destructive" });
71
+ return;
72
+ }
73
  setIsSigningIn(true);
74
  await completeProfile(parseInt(age), location);
75
  setIsSigningIn(false);
 
92
  <form onSubmit={handleCompleteProfile}>
93
  <CardHeader>
94
  <CardTitle>إكمال البيانات</CardTitle>
95
+ <CardDescription>يرجى اختيار بلدك وعمرك للمتابعة</CardDescription>
96
  </CardHeader>
97
  <CardContent className="space-y-4">
98
  <div className="space-y-2">
 
101
  </div>
102
  <div className="space-y-2">
103
  <Label>{t.location}</Label>
104
+ <Select onValueChange={setLocation} value={location}>
105
+ <SelectTrigger className="w-full">
106
+ <SelectValue placeholder="اختر بلدك" />
107
+ </SelectTrigger>
108
+ <SelectContent>
109
+ {countries.map((c) => (
110
+ <SelectItem key={c.code} value={c.name}>
111
+ <span className="ml-2">{c.flag}</span>
112
+ {c.name}
113
+ </SelectItem>
114
+ ))}
115
+ </SelectContent>
116
+ </Select>
117
  </div>
118
  </CardContent>
119
  <CardFooter>
 
174
  <Label>{t.password}</Label>
175
  <Input type="password" value={password} onChange={e => setPassword(e.target.value)} required />
176
  </div>
177
+ <div className="grid grid-cols-1 gap-4">
178
  <div className="space-y-2">
179
  <Label>{t.age}</Label>
180
  <Input type="number" value={age} onChange={e => setAge(e.target.value)} required />
181
  </div>
182
  <div className="space-y-2">
183
  <Label>{t.location}</Label>
184
+ <Select onValueChange={setLocation} value={location}>
185
+ <SelectTrigger className="w-full">
186
+ <SelectValue placeholder="اختر بلدك" />
187
+ </SelectTrigger>
188
+ <SelectContent>
189
+ {countries.map((c) => (
190
+ <SelectItem key={c.code} value={c.name}>
191
+ <span className="ml-2">{c.flag}</span>
192
+ {c.name}
193
+ </SelectItem>
194
+ ))}
195
+ </SelectContent>
196
+ </Select>
197
  </div>
198
  </div>
199
  </CardContent>
src/lib/countries.ts ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ export interface Country {
3
+ name: string;
4
+ code: string;
5
+ flag: string;
6
+ }
7
+
8
+ export const countries: Country[] = [
9
+ { name: "مصر", code: "EG", flag: "🇪🇬" },
10
+ { name: "المملكة العربية السعودية", code: "SA", flag: "🇸🇦" },
11
+ { name: "الإمارات العربية المتحدة", code: "AE", flag: "🇦🇪" },
12
+ { name: "الكويت", code: "KW", flag: "🇰🇼" },
13
+ { name: "قطر", code: "QA", flag: "🇶🇦" },
14
+ { name: "البحرين", code: "BH", flag: "🇧🇭" },
15
+ { name: "عمان", code: "OM", flag: "🇴🇲" },
16
+ { name: "الأردن", code: "JO", flag: "🇯🇴" },
17
+ { name: "لبنان", code: "LB", flag: "🇱🇧" },
18
+ { name: "سوريا", code: "SY", flag: "🇸🇾" },
19
+ { name: "العراق", code: "IQ", flag: "🇮🇶" },
20
+ { name: "فلسطين", code: "PS", flag: "🇵🇸" },
21
+ { name: "المغرب", code: "MA", flag: "🇲🇦" },
22
+ { name: "تونس", code: "TN", flag: "🇹🇳" },
23
+ { name: "الجزائر", code: "DZ", flag: "🇩🇿" },
24
+ { name: "ليبيا", code: "LY", flag: "🇱🇾" },
25
+ { name: "السودان", code: "SD", flag: "🇸🇩" },
26
+ { name: "اليمن", code: "YE", flag: "🇾🇪" },
27
+ { name: "الولايات المتحدة", code: "US", flag: "🇺🇸" },
28
+ { name: "المملكة المتحدة", code: "GB", flag: "🇬🇧" },
29
+ { name: "فرنسا", code: "FR", flag: "🇫🇷" },
30
+ { name: "ألمانيا", code: "DE", flag: "🇩🇪" },
31
+ { name: "كندا", code: "CA", flag: "🇨🇦" },
32
+ { name: "تركيا", code: "TR", flag: "🇹🇷" }
33
+ ].sort((a, b) => a.name.localeCompare(b.name, 'ar'));