Files changed (1) hide show
  1. app.py +97 -79
app.py CHANGED
@@ -1,39 +1,94 @@
1
  import gradio as gr
2
  import os
3
  import uuid
 
4
 
5
  from ultralytics import YOLO
6
  from openai import OpenAI
7
- from gtts import gTTS
8
- from PIL import Image
9
-
10
  from gradio_client import Client, handle_file
 
 
11
 
12
  # =========================
13
- # YOLO
14
  # =========================
15
-
16
  model = YOLO("best_egypt.pt")
17
 
 
18
  # =========================
19
- # OpenRouter
20
  # =========================
21
-
22
  client = OpenAI(
23
  base_url="https://openrouter.ai/api/v1",
24
  api_key=os.environ["OPENROUTER_API_KEY"]
25
  )
26
 
 
27
  # =========================
28
- # Wav2Lip API
29
  # =========================
30
-
31
  wav2lip_client = Client("fatma812/Wav2lip-ZeroGPU2")
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  # =========================
34
- # Generate Story + Voice
35
  # =========================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
 
 
 
 
 
 
 
37
  def generate(image_path, language):
38
 
39
  results = model(image_path)
@@ -42,52 +97,44 @@ def generate(image_path, language):
42
  raise gr.Error("No artifact detected")
43
 
44
  label_id = int(results[0].boxes.cls[0])
45
-
46
  artifact = results[0].names[label_id]
47
 
48
- if language == "Arabic":
49
 
 
50
  prompt = f"""
51
- أنت {artifact} أثر مصري قديم.
52
- تحدث بصيغة المتكلم في 2-3 جمل قصيرة تعرف بنفسك وتحكي حقيقة تاريخية واحدة.
 
53
  """
54
-
55
- tts_lang = "ar"
56
-
57
  else:
58
-
59
  prompt = f"""
60
  You are {artifact}, an ancient Egyptian artifact.
61
- Speak in first person in 2-3 short sentences introducing yourself and sharing one historical fact.
 
62
  """
63
-
64
- tts_lang = "en"
65
 
66
  response = client.chat.completions.create(
67
  model="openai/gpt-4o-mini",
68
- messages=[
69
- {
70
- "role": "user",
71
- "content": prompt
72
- }
73
- ]
74
  )
75
 
76
  story = response.choices[0].message.content
77
 
78
- audio_path = f"audio_{uuid.uuid4().hex}.mp3"
 
79
 
80
- gTTS(
81
- text=story,
82
- lang=tts_lang
83
- ).save(audio_path)
84
 
85
  return artifact, story, audio_path
86
 
 
87
  # =========================
88
- # Generate Talking Video
89
  # =========================
90
-
91
  def make_video(image, audio):
92
 
93
  result = wav2lip_client.predict(
@@ -101,70 +148,41 @@ def make_video(image, audio):
101
 
102
  return result
103
 
 
104
  # =========================
105
  # UI
106
  # =========================
107
-
108
  with gr.Blocks() as demo:
109
 
110
- gr.Markdown("# 🏛 Talking Egyptian Artifact AI")
111
 
112
- image = gr.Image(
113
- type="filepath",
114
- label="Artifact Image"
115
- )
116
 
117
  language = gr.Radio(
118
  ["Arabic", "English"],
119
- value="Arabic",
120
- label="Language"
121
  )
122
 
123
- generate_btn = gr.Button(
124
- "Generate Story + Voice"
125
- )
126
 
127
- artifact_box = gr.Textbox(
128
- label="Artifact"
129
- )
130
 
131
- story_box = gr.Textbox(
132
- label="Generated Story"
133
- )
134
-
135
- audio_box = gr.Audio(
136
- type="filepath",
137
- label="Generated Voice"
138
- )
139
 
140
- video_btn = gr.Button(
141
- "Generate Talking Video"
142
- )
143
-
144
- video_box = gr.Video(
145
- label="Talking Artifact"
146
- )
147
 
148
- generate_btn.click(
149
  generate,
150
- inputs=[
151
- image,
152
- language
153
- ],
154
- outputs=[
155
- artifact_box,
156
- story_box,
157
- audio_box
158
- ]
159
  )
160
 
161
- video_btn.click(
162
  make_video,
163
- inputs=[
164
- image,
165
- audio_box
166
- ],
167
- outputs=video_box
168
  )
169
 
170
  demo.queue()
 
1
  import gradio as gr
2
  import os
3
  import uuid
4
+ import asyncio
5
 
6
  from ultralytics import YOLO
7
  from openai import OpenAI
 
 
 
8
  from gradio_client import Client, handle_file
9
+ import edge_tts
10
+
11
 
12
  # =========================
13
+ # YOLO MODEL
14
  # =========================
 
15
  model = YOLO("best_egypt.pt")
16
 
17
+
18
  # =========================
19
+ # OPENROUTER
20
  # =========================
 
21
  client = OpenAI(
22
  base_url="https://openrouter.ai/api/v1",
23
  api_key=os.environ["OPENROUTER_API_KEY"]
24
  )
25
 
26
+
27
  # =========================
28
+ # WAV2LIP API
29
  # =========================
 
30
  wav2lip_client = Client("fatma812/Wav2lip-ZeroGPU2")
31
 
32
+
33
+ # =========================
34
+ # PERSONA STYLE (ROYAL VOICES)
35
+ # =========================
36
+ PERSONA_PREFIX = {
37
+ "bust-of-ramesses-ii": "I speak with royal authority and unmatched power.",
38
+ "Ramses-II-Red-Granite-Statue": "I am the great king of strength and war.",
39
+ "Colossal-Statue-of-Ramesses-II": "I am eternal, carved in stone and glory.",
40
+
41
+ "Mask-of-Tutankhamun": "I am young, mysterious, and full of hidden legacy.",
42
+ "Tutankhamun": "I am the boy king of Egypt.",
43
+
44
+ "Nefertiti": "I speak with elegance, beauty, and royal grace.",
45
+ "Hatshepsut": "I rule with wisdom, divine authority, and strength."
46
+ }
47
+
48
+
49
  # =========================
50
+ # VOICE MAP (EDGE TTS)
51
  # =========================
52
+ VOICE_MAP = {
53
+ # Ramses II (strong male Arabic)
54
+ "bust-of-ramesses-ii": "ar-DZ-IsmaelNeural",
55
+
56
+ # Tutankhamun (young male Arabic)
57
+ "Mask-of-Tutankhamun": "ar-EG-ShakirNeural",
58
+ "Tutankhamun": "ar-EG-ShakirNeural",
59
+
60
+ # Queens (elegant English voices)
61
+ "Nefertiti": "en-GB-SoniaNeural",
62
+ "Hatshepsut": "en-US-AriaNeural",
63
+ }
64
+
65
+
66
+ def get_voice(name):
67
+ return VOICE_MAP.get(name, "en-US-GuyNeural")
68
+
69
+
70
+ def get_persona(name):
71
+ return PERSONA_PREFIX.get(
72
+ name,
73
+ "I am an ancient Egyptian artifact speaking from history."
74
+ )
75
+
76
+
77
+ # =========================
78
+ # EDGE TTS
79
+ # =========================
80
+ async def _speak(text, voice, path):
81
+ communicate = edge_tts.Communicate(text=text, voice=voice)
82
+ await communicate.save(path)
83
+
84
 
85
+ def generate_audio(text, voice, path):
86
+ asyncio.run(_speak(text, voice, path))
87
+
88
+
89
+ # =========================
90
+ # GENERATE STORY + VOICE
91
+ # =========================
92
  def generate(image_path, language):
93
 
94
  results = model(image_path)
 
97
  raise gr.Error("No artifact detected")
98
 
99
  label_id = int(results[0].boxes.cls[0])
 
100
  artifact = results[0].names[label_id]
101
 
102
+ persona = get_persona(artifact)
103
 
104
+ if language == "Arabic":
105
  prompt = f"""
106
+ أنت {artifact} من آثار مصر القديمة.
107
+ {persona}
108
+ تحدث بصوت ملكي قوي في 2-3 جمل قصيرة.
109
  """
110
+ voice = get_voice(artifact)
 
 
111
  else:
 
112
  prompt = f"""
113
  You are {artifact}, an ancient Egyptian artifact.
114
+ {persona}
115
+ Speak in a powerful royal tone in 2-3 short sentences.
116
  """
117
+ voice = get_voice(artifact)
 
118
 
119
  response = client.chat.completions.create(
120
  model="openai/gpt-4o-mini",
121
+ messages=[{"role": "user", "content": prompt}]
 
 
 
 
 
122
  )
123
 
124
  story = response.choices[0].message.content
125
 
126
+ # add royal boost
127
+ story = persona + " " + story
128
 
129
+ audio_path = f"audio_{uuid.uuid4().hex}.mp3"
130
+ generate_audio(story, voice, audio_path)
 
 
131
 
132
  return artifact, story, audio_path
133
 
134
+
135
  # =========================
136
+ # MAKE VIDEO (WAV2LIP API)
137
  # =========================
 
138
  def make_video(image, audio):
139
 
140
  result = wav2lip_client.predict(
 
148
 
149
  return result
150
 
151
+
152
  # =========================
153
  # UI
154
  # =========================
 
155
  with gr.Blocks() as demo:
156
 
157
+ gr.Markdown("# 🏛 Egyptian Talking AI (Final Version)")
158
 
159
+ image = gr.Image(type="filepath")
 
 
 
160
 
161
  language = gr.Radio(
162
  ["Arabic", "English"],
163
+ value="Arabic"
 
164
  )
165
 
166
+ btn1 = gr.Button("Generate Story + Voice")
 
 
167
 
168
+ artifact = gr.Textbox(label="Artifact")
169
+ story = gr.Textbox(label="Story")
170
+ audio = gr.Audio(type="filepath")
171
 
172
+ btn2 = gr.Button("Generate Video")
 
 
 
 
 
 
 
173
 
174
+ video = gr.Video()
 
 
 
 
 
 
175
 
176
+ btn1.click(
177
  generate,
178
+ inputs=[image, language],
179
+ outputs=[artifact, story, audio]
 
 
 
 
 
 
 
180
  )
181
 
182
+ btn2.click(
183
  make_video,
184
+ inputs=[image, audio],
185
+ outputs=video
 
 
 
186
  )
187
 
188
  demo.queue()