Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,311 +1,198 @@
|
|
1 |
import gradio as gr
|
2 |
-
import
|
3 |
-
import requests
|
4 |
-
import io
|
5 |
-
from PIL import Image
|
6 |
-
from huggingface_hub import InferenceClient, HfApi
|
7 |
from deep_translator import GoogleTranslator
|
8 |
from indic_transliteration import sanscript
|
9 |
from indic_transliteration.detect import detect as detect_script
|
10 |
from indic_transliteration.sanscript import transliterate
|
11 |
import langdetect
|
12 |
import re
|
13 |
-
import os
|
14 |
-
|
15 |
-
# Get secrets from Hugging Face Space
|
16 |
-
HF_TOKEN = os.environ.get('HF_TOKEN')
|
17 |
-
if not HF_TOKEN:
|
18 |
-
raise ValueError("Please set the HF_TOKEN secret in your HuggingFace Space")
|
19 |
|
20 |
# Initialize clients
|
21 |
-
text_client = InferenceClient(
|
22 |
-
|
23 |
-
token=HF_TOKEN
|
24 |
-
)
|
25 |
-
|
26 |
-
# Image generation setup
|
27 |
-
API_URL = "https://api-inference.huggingface.co/models/SG161222/RealVisXL_V4.0"
|
28 |
-
headers = {"Authorization": f"Bearer {HF_TOKEN}"}
|
29 |
-
|
30 |
-
def detect_language(text):
|
31 |
-
"""Detect the language of input text"""
|
32 |
-
try:
|
33 |
-
return langdetect.detect(text)
|
34 |
-
except:
|
35 |
-
return 'en'
|
36 |
-
|
37 |
-
def detect_and_transliterate(text):
|
38 |
-
"""Detect script and transliterate if needed"""
|
39 |
-
try:
|
40 |
-
script = detect_script(text)
|
41 |
-
if script:
|
42 |
-
# Transliterate to Latin script if the text is in another script
|
43 |
-
return transliterate(text, script, sanscript.IAST)
|
44 |
-
except:
|
45 |
-
pass
|
46 |
-
return text
|
47 |
|
48 |
-
def
|
49 |
-
"""
|
|
|
50 |
try:
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
except:
|
56 |
-
|
57 |
-
return text
|
58 |
|
59 |
-
def
|
60 |
-
"""Check if
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
r
|
65 |
-
r
|
66 |
-
r
|
67 |
-
r
|
68 |
]
|
69 |
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
return
|
74 |
|
75 |
-
def
|
76 |
-
"""
|
77 |
-
|
78 |
-
|
|
|
79 |
|
80 |
-
|
81 |
-
|
82 |
|
83 |
-
#
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
|
|
|
|
|
|
|
|
88 |
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
if not history:
|
94 |
-
return history, None
|
95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
try:
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
# Check for image generation request
|
105 |
-
if check_for_image_generation(translated_message):
|
106 |
-
# Generate image based on the message
|
107 |
-
image = generate_image(translated_message)
|
108 |
-
# Add bot response with proper format
|
109 |
-
history.append({
|
110 |
-
"role": "assistant",
|
111 |
-
"content": "I've generated an image based on your request."
|
112 |
-
})
|
113 |
-
return history, image
|
114 |
-
|
115 |
-
# Prepare chat messages for the model
|
116 |
-
messages = [
|
117 |
-
{"role": "system", "content": system_msg},
|
118 |
-
]
|
119 |
-
|
120 |
-
# Add conversation history
|
121 |
-
for msg in history:
|
122 |
-
messages.append(msg)
|
123 |
-
|
124 |
-
# Get model response
|
125 |
-
response = text_client.text_generation(
|
126 |
-
prompt=str(messages),
|
127 |
-
max_new_tokens=max_tokens,
|
128 |
-
temperature=temperature,
|
129 |
-
top_p=top_p,
|
130 |
-
repetition_penalty=1.1,
|
131 |
)
|
132 |
-
|
133 |
-
#
|
134 |
-
|
135 |
-
"role": "assistant",
|
136 |
-
"content": response
|
137 |
-
})
|
138 |
-
|
139 |
except Exception as e:
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
|
147 |
-
|
|
|
|
|
148 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
def create_chat_interface():
|
150 |
-
# Custom CSS for better styling
|
151 |
custom_css = """
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
}
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
opacity: 0;
|
187 |
-
transform: translateY(10px);
|
188 |
-
}
|
189 |
-
to {
|
190 |
-
opacity: 1;
|
191 |
-
transform: translateY(0);
|
192 |
-
}
|
193 |
-
}
|
194 |
-
|
195 |
-
.user-message {
|
196 |
-
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%) !important;
|
197 |
-
color: white !important;
|
198 |
-
margin-left: 2rem !important;
|
199 |
-
}
|
200 |
-
|
201 |
-
.bot-message {
|
202 |
-
background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%) !important;
|
203 |
-
margin-right: 2rem !important;
|
204 |
-
}
|
205 |
-
|
206 |
-
/* Button Styles */
|
207 |
-
button.primary {
|
208 |
-
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%) !important;
|
209 |
-
border: none !important;
|
210 |
-
color: white !important;
|
211 |
-
padding: 0.75rem 1.5rem !important;
|
212 |
-
border-radius: 12px !important;
|
213 |
-
font-weight: 600 !important;
|
214 |
-
transition: all 0.3s ease !important;
|
215 |
-
transform: translateY(0);
|
216 |
-
box-shadow: 0 4px 6px rgba(99, 102, 241, 0.2) !important;
|
217 |
-
}
|
218 |
-
|
219 |
-
button.primary:hover {
|
220 |
-
transform: translateY(-2px);
|
221 |
-
box-shadow: 0 8px 12px rgba(99, 102, 241, 0.3) !important;
|
222 |
-
}
|
223 |
-
|
224 |
-
button.primary:active {
|
225 |
-
transform: translateY(0);
|
226 |
-
}
|
227 |
-
|
228 |
-
button.secondary {
|
229 |
-
background: #f3f4f6 !important;
|
230 |
-
border: 2px solid #e5e7eb !important;
|
231 |
-
color: #4b5563 !important;
|
232 |
-
padding: 0.75rem 1.5rem !important;
|
233 |
-
border-radius: 12px !important;
|
234 |
-
font-weight: 600 !important;
|
235 |
-
transition: all 0.3s ease !important;
|
236 |
-
}
|
237 |
-
|
238 |
-
button.secondary:hover {
|
239 |
-
background: #e5e7eb !important;
|
240 |
-
border-color: #d1d5db !important;
|
241 |
-
}
|
242 |
-
|
243 |
-
/* Input Styles */
|
244 |
-
.input-container {
|
245 |
-
position: relative;
|
246 |
-
margin-bottom: 1rem;
|
247 |
-
}
|
248 |
-
|
249 |
-
textarea {
|
250 |
-
border: 2px solid #e5e7eb !important;
|
251 |
-
border-radius: 12px !important;
|
252 |
-
padding: 1rem !important;
|
253 |
-
transition: all 0.3s ease !important;
|
254 |
-
font-size: 1rem !important;
|
255 |
-
line-height: 1.5 !important;
|
256 |
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05) !important;
|
257 |
-
}
|
258 |
-
|
259 |
-
textarea:focus {
|
260 |
-
border-color: #6366f1 !important;
|
261 |
-
box-shadow: 0 4px 6px rgba(99, 102, 241, 0.1) !important;
|
262 |
-
}
|
263 |
-
|
264 |
-
/* Settings Panel */
|
265 |
-
.settings-block {
|
266 |
-
background: white !important;
|
267 |
-
border-radius: 15px !important;
|
268 |
-
padding: 1.5rem !important;
|
269 |
-
margin-top: 1rem !important;
|
270 |
-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05) !important;
|
271 |
-
transition: all 0.3s ease !important;
|
272 |
-
}
|
273 |
-
|
274 |
-
.settings-block:hover {
|
275 |
-
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.08) !important;
|
276 |
-
}
|
277 |
-
|
278 |
-
/* Slider Styles */
|
279 |
-
.gr-slider {
|
280 |
-
height: 4px !important;
|
281 |
-
background: #e5e7eb !important;
|
282 |
-
border-radius: 2px !important;
|
283 |
-
}
|
284 |
-
|
285 |
-
.gr-slider .handle {
|
286 |
-
width: 16px !important;
|
287 |
-
height: 16px !important;
|
288 |
-
border: 2px solid #6366f1 !important;
|
289 |
-
background: white !important;
|
290 |
-
border-radius: 50% !important;
|
291 |
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
|
292 |
-
transition: all 0.2s ease !important;
|
293 |
-
}
|
294 |
-
|
295 |
-
.gr-slider .handle:hover {
|
296 |
-
transform: scale(1.1);
|
297 |
-
}
|
298 |
-
|
299 |
-
/* Loading Animation */
|
300 |
-
@keyframes pulse {
|
301 |
-
0% { opacity: 1; }
|
302 |
-
50% { opacity: 0.5; }
|
303 |
-
100% { opacity: 1; }
|
304 |
-
}
|
305 |
-
|
306 |
-
.loading {
|
307 |
-
animation: pulse 1.5s ease-in-out infinite;
|
308 |
-
}
|
309 |
"""
|
310 |
|
311 |
# Create the interface with custom theme
|
@@ -313,14 +200,37 @@ def create_chat_interface():
|
|
313 |
# Header
|
314 |
with gr.Row():
|
315 |
gr.HTML("""
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
323 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
324 |
""")
|
325 |
|
326 |
# Main chat interface
|
@@ -330,44 +240,26 @@ def create_chat_interface():
|
|
330 |
height=500,
|
331 |
show_label=False,
|
332 |
container=True,
|
333 |
-
elem_classes=["chat-window"]
|
334 |
-
type='messages'
|
335 |
-
)
|
336 |
-
|
337 |
-
image_output = gr.Image(
|
338 |
-
type="pil",
|
339 |
-
label="Generated Image",
|
340 |
-
visible=False,
|
341 |
-
elem_classes=["generated-image"]
|
342 |
)
|
343 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
344 |
with gr.Row():
|
345 |
-
|
346 |
-
|
347 |
-
show_label=False,
|
348 |
-
placeholder="Type your message here...",
|
349 |
-
container=False,
|
350 |
-
elem_classes=["input-textbox"]
|
351 |
-
)
|
352 |
-
with gr.Column(scale=1):
|
353 |
-
send_btn = gr.Button(
|
354 |
-
"Send",
|
355 |
-
variant="primary",
|
356 |
-
elem_classes=["primary"]
|
357 |
-
)
|
358 |
-
with gr.Column(scale=1):
|
359 |
-
clear_btn = gr.Button(
|
360 |
-
"Clear",
|
361 |
-
variant="secondary",
|
362 |
-
elem_classes=["secondary"]
|
363 |
-
)
|
364 |
|
365 |
-
# Settings panel
|
366 |
-
with gr.Accordion(
|
367 |
-
"⚙️ Advanced Settings",
|
368 |
-
open=False,
|
369 |
-
elem_classes=["settings-accordion"]
|
370 |
-
):
|
371 |
with gr.Row():
|
372 |
with gr.Column():
|
373 |
system_msg = gr.Textbox(
|
@@ -398,11 +290,63 @@ def create_chat_interface():
|
|
398 |
label="Top-p (nucleus sampling)"
|
399 |
)
|
400 |
|
401 |
-
#
|
402 |
-
|
|
|
|
|
|
|
403 |
|
404 |
-
|
405 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
406 |
user_message,
|
407 |
[txt, chatbot],
|
408 |
[txt, chatbot],
|
@@ -410,7 +354,7 @@ def create_chat_interface():
|
|
410 |
).then(
|
411 |
bot_response,
|
412 |
[chatbot, system_msg, max_tokens, temperature, top_p],
|
413 |
-
|
414 |
)
|
415 |
|
416 |
send_btn.click(
|
@@ -421,21 +365,20 @@ def create_chat_interface():
|
|
421 |
).then(
|
422 |
bot_response,
|
423 |
[chatbot, system_msg, max_tokens, temperature, top_p],
|
424 |
-
|
425 |
)
|
426 |
|
427 |
-
clear_btn.click(
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
image_output
|
439 |
)
|
440 |
|
441 |
return demo
|
|
|
1 |
import gradio as gr
|
2 |
+
from huggingface_hub import InferenceClient
|
|
|
|
|
|
|
|
|
3 |
from deep_translator import GoogleTranslator
|
4 |
from indic_transliteration import sanscript
|
5 |
from indic_transliteration.detect import detect as detect_script
|
6 |
from indic_transliteration.sanscript import transliterate
|
7 |
import langdetect
|
8 |
import re
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
# Initialize clients
|
11 |
+
text_client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
|
12 |
+
image_client = InferenceClient("SG161222/RealVisXL_V3.0")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
+
def detect_language_script(text: str) -> tuple[str, str]:
|
15 |
+
"""Detect language and script of the input text.
|
16 |
+
Returns (language_code, script_type)"""
|
17 |
try:
|
18 |
+
# Use confidence threshold to avoid false detections
|
19 |
+
lang_detect = langdetect.detect_langs(text)
|
20 |
+
if lang_detect[0].prob > 0.8:
|
21 |
+
# Only accept high confidence detections
|
22 |
+
lang = lang_detect[0].lang
|
23 |
+
else:
|
24 |
+
lang = 'en' # Default to English if unsure
|
25 |
+
|
26 |
+
script = None
|
27 |
+
try:
|
28 |
+
script = detect_script(text)
|
29 |
+
except:
|
30 |
+
pass
|
31 |
+
return lang, script
|
32 |
except:
|
33 |
+
return 'en', None
|
|
|
34 |
|
35 |
+
def is_romanized_indic(text: str) -> bool:
|
36 |
+
"""Check if text appears to be romanized Indic language.
|
37 |
+
More strict pattern matching."""
|
38 |
+
# Common Bengali romanized patterns with word boundaries
|
39 |
+
bengali_patterns = [
|
40 |
+
r'\b(ami|tumi|apni)\b', # Common pronouns
|
41 |
+
r'\b(ache|achen|thako|thaken)\b', # Common verbs
|
42 |
+
r'\b(kemon|bhalo|kharap)\b', # Common adjectives
|
43 |
+
r'\b(ki|kothay|keno)\b' # Common question words
|
44 |
]
|
45 |
|
46 |
+
# Require multiple matches to confirm it's actually Bengali
|
47 |
+
text_lower = text.lower()
|
48 |
+
matches = sum(1 for pattern in bengali_patterns if re.search(pattern, text_lower))
|
49 |
+
return matches >= 2 # Require at least 2 matches to consider it Bengali
|
50 |
|
51 |
+
def translate_text(text: str, target_lang='en') -> tuple[str, str, bool]:
|
52 |
+
"""Translate text to target language, with more conservative translation logic."""
|
53 |
+
# Skip translation for very short inputs or basic greetings
|
54 |
+
if len(text.split()) <= 2 or text.lower() in ['hello', 'hi', 'hey']:
|
55 |
+
return text, 'en', False
|
56 |
|
57 |
+
original_lang, script = detect_language_script(text)
|
58 |
+
is_transliterated = False
|
59 |
|
60 |
+
# Only process if confident it's non-English
|
61 |
+
if original_lang != 'en' and len(text.split()) > 2:
|
62 |
+
try:
|
63 |
+
translator = GoogleTranslator(source='auto', target=target_lang)
|
64 |
+
translated = translator.translate(text)
|
65 |
+
return translated, original_lang, is_transliterated
|
66 |
+
except Exception as e:
|
67 |
+
print(f"Translation error: {e}")
|
68 |
+
return text, 'en', False
|
69 |
|
70 |
+
# Check for romanized Indic text only if it's a longer input
|
71 |
+
if original_lang == 'en' and len(text.split()) > 2 and is_romanized_indic(text):
|
72 |
+
text = romanized_to_bengali(text)
|
73 |
+
return translate_text(text, target_lang) # Recursive call with Bengali script
|
|
|
|
|
74 |
|
75 |
+
return text, 'en', False
|
76 |
+
|
77 |
+
def check_custom_responses(message: str) -> str:
|
78 |
+
"""Check for specific patterns and return custom responses."""
|
79 |
+
message_lower = message.lower()
|
80 |
+
custom_responses = {
|
81 |
+
"what is ur name?": "xylaria",
|
82 |
+
"what is your name?": "xylaria",
|
83 |
+
"what's your name?": "xylaria",
|
84 |
+
"whats your name": "xylaria",
|
85 |
+
"how many 'r' is in strawberry?": "3",
|
86 |
+
"who is your developer?": "sk md saad amin",
|
87 |
+
"how many r is in strawberry": "3",
|
88 |
+
"who is ur dev": "sk md saad amin",
|
89 |
+
"who is ur developer": "sk md saad amin",
|
90 |
+
}
|
91 |
+
for pattern, response in custom_responses.items():
|
92 |
+
if pattern in message_lower:
|
93 |
+
return response
|
94 |
+
return None
|
95 |
+
|
96 |
+
def is_image_request(message: str) -> bool:
|
97 |
+
"""Detect if the message is requesting image generation."""
|
98 |
+
image_triggers = [
|
99 |
+
"generate an image",
|
100 |
+
"create an image",
|
101 |
+
"draw",
|
102 |
+
"make a picture",
|
103 |
+
"generate a picture",
|
104 |
+
"create a picture",
|
105 |
+
"generate art",
|
106 |
+
"create art",
|
107 |
+
"make art",
|
108 |
+
"visualize",
|
109 |
+
"show me",
|
110 |
+
]
|
111 |
+
message_lower = message.lower()
|
112 |
+
return any(trigger in message_lower for trigger in image_triggers)
|
113 |
+
|
114 |
+
def generate_image(prompt: str) -> str:
|
115 |
+
"""Generate an image using DALLE-4K model."""
|
116 |
try:
|
117 |
+
response = image_client.text_to_image(
|
118 |
+
prompt,
|
119 |
+
parameters={
|
120 |
+
"negative_prompt": "blurry, bad quality, nsfw",
|
121 |
+
"num_inference_steps": 30,
|
122 |
+
"guidance_scale": 7.5
|
123 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
)
|
125 |
+
# Save the image and return the path or base64 string
|
126 |
+
# Note: Implementation depends on how you want to handle the image output
|
127 |
+
return response
|
|
|
|
|
|
|
|
|
128 |
except Exception as e:
|
129 |
+
print(f"Image generation error: {e}")
|
130 |
+
return None
|
131 |
+
def romanized_to_bengali(text: str) -> str:
|
132 |
+
"""Convert romanized Bengali text to Bengali script."""
|
133 |
+
bengali_mappings = {
|
134 |
+
'ami': 'আমি',
|
135 |
+
'tumi': 'তুমি',
|
136 |
+
'apni': 'আপনি',
|
137 |
+
'kemon': 'কেমন',
|
138 |
+
'achen': 'আছেন',
|
139 |
+
'acchen': 'আছেন',
|
140 |
+
'bhalo': 'ভালো',
|
141 |
+
'achi': 'আছি',
|
142 |
+
'ki': 'কি',
|
143 |
+
'kothay': 'কোথায়',
|
144 |
+
'keno': 'কেন',
|
145 |
+
}
|
146 |
|
147 |
+
text_lower = text.lower()
|
148 |
+
for roman, bengali in bengali_mappings.items():
|
149 |
+
text_lower = re.sub(r'\b' + roman + r'\b', bengali, text_lower)
|
150 |
|
151 |
+
if text_lower == text.lower():
|
152 |
+
try:
|
153 |
+
return transliterate(text, sanscript.ITRANS, sanscript.BENGALI)
|
154 |
+
except:
|
155 |
+
return text
|
156 |
+
|
157 |
+
return text_lower
|
158 |
+
|
159 |
def create_chat_interface():
|
160 |
+
# Custom CSS for better styling
|
161 |
custom_css = """
|
162 |
+
body {
|
163 |
+
font-family: 'Inter', sans-serif;
|
164 |
+
}
|
165 |
+
|
166 |
+
.chat-container {
|
167 |
+
padding-top: 0;
|
168 |
+
padding-bottom: 0;
|
169 |
+
}
|
170 |
+
|
171 |
+
.chat-messages {
|
172 |
+
scroll-behavior: smooth;
|
173 |
+
}
|
174 |
+
|
175 |
+
.input-container {
|
176 |
+
border-top: 1px solid #ccc;
|
177 |
+
}
|
178 |
+
|
179 |
+
.input-container textarea {
|
180 |
+
border-radius: 12px 0 0 12px;
|
181 |
+
}
|
182 |
+
|
183 |
+
.input-container button {
|
184 |
+
border-radius: 0 12px 12px 0;
|
185 |
+
}
|
186 |
+
|
187 |
+
.loading {
|
188 |
+
animation: pulse 1.5s ease-in-out infinite;
|
189 |
+
}
|
190 |
+
|
191 |
+
@keyframes pulse {
|
192 |
+
0% { opacity: 1; }
|
193 |
+
50% { opacity: 0.5; }
|
194 |
+
100% { opacity: 1; }
|
195 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
196 |
"""
|
197 |
|
198 |
# Create the interface with custom theme
|
|
|
200 |
# Header
|
201 |
with gr.Row():
|
202 |
gr.HTML("""
|
203 |
+
<!DOCTYPE html>
|
204 |
+
<html lang="en">
|
205 |
+
<head>
|
206 |
+
<meta charset="UTF-8">
|
207 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
208 |
+
<title>Xylaria Chat</title>
|
209 |
+
<link rel="stylesheet" href="styles.css">
|
210 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/full.css">
|
211 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
|
212 |
+
</head>
|
213 |
+
<body>
|
214 |
+
<div id="app" class="mx-auto max-w-5xl">
|
215 |
+
<header class="bg-white rounded shadow-lg p-10 text-center mb-10">
|
216 |
+
<h1 class="text-6xl font-bold text-violet-600 mb-5">✨ Xylaria Chat</h1>
|
217 |
+
<p class="text-lg font-medium text-gray-600">Your Intelligent Multilingual Assistant</p>
|
218 |
+
</header>
|
219 |
+
<section class="bg-white rounded shadow-lg p-10 chat-container">
|
220 |
+
<div class="chat-messages overflow-y-auto max-h-screen">
|
221 |
+
<div v-for="(message, index) in messages" :key="index" class="my-4" :class="{ 'flex justify-end': message.type === 'user' }">
|
222 |
+
<div class="rounded-lg py-4 px-6" :class="{ 'bg-violet-500 text-white': message.type === 'user', 'bg-gray-200': message.type === 'bot' }">{{ message.text }}</div>
|
223 |
</div>
|
224 |
+
</div>
|
225 |
+
<div class="input-container flex mt-6">
|
226 |
+
<textarea v-model="inputText" class="w-full p-4 rounded-lg border-2 border-gray-400 resize-y" rows="3" placeholder="Type a message..."></textarea>
|
227 |
+
<button @click="sendMessage" class="bg-violet-500 text-white p-3 rounded-lg ml-4 hover:bg-violet-600 transition duration-300">Send</button>
|
228 |
+
</div>
|
229 |
+
</section>
|
230 |
+
</div>
|
231 |
+
<script src="script.js"></script>
|
232 |
+
</body>
|
233 |
+
</html>
|
234 |
""")
|
235 |
|
236 |
# Main chat interface
|
|
|
240 |
height=500,
|
241 |
show_label=False,
|
242 |
container=True,
|
243 |
+
elem_classes=["chat-window"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
244 |
)
|
245 |
|
246 |
+
# Input area with buttons
|
247 |
+
with gr.Row():
|
248 |
+
txt = gr.Textbox(
|
249 |
+
show_label=False,
|
250 |
+
placeholder="Type your message here...",
|
251 |
+
container=False
|
252 |
+
)
|
253 |
+
send_btn = gr.Button("Send", variant="primary")
|
254 |
+
clear_btn = gr.Button("Clear")
|
255 |
+
|
256 |
+
# Additional features bar
|
257 |
with gr.Row():
|
258 |
+
audio_input = gr.Audio(source="microphone", type="filepath", label="Voice Input")
|
259 |
+
image_output = gr.Image(label="Generated Image", visible=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
260 |
|
261 |
+
# Settings panel (collapsible)
|
262 |
+
with gr.Accordion("Advanced Settings", open=False):
|
|
|
|
|
|
|
|
|
263 |
with gr.Row():
|
264 |
with gr.Column():
|
265 |
system_msg = gr.Textbox(
|
|
|
290 |
label="Top-p (nucleus sampling)"
|
291 |
)
|
292 |
|
293 |
+
# Function to handle sending messages
|
294 |
+
def user_message(message, history):
|
295 |
+
if message:
|
296 |
+
return "", history + [[message, None]]
|
297 |
+
return "", history
|
298 |
|
299 |
+
def bot_response(history, system_msg, max_tokens, temperature, top_p):
|
300 |
+
if len(history) == 0:
|
301 |
+
return history
|
302 |
+
|
303 |
+
# Get the last user message
|
304 |
+
message = history[-1][0]
|
305 |
+
|
306 |
+
# Check for custom responses first
|
307 |
+
custom_response = check_custom_responses(message)
|
308 |
+
if custom_response:
|
309 |
+
history[-1][1] = custom_response
|
310 |
+
return history
|
311 |
+
|
312 |
+
# Check for image generation request
|
313 |
+
if is_image_request(message):
|
314 |
+
try:
|
315 |
+
image = generate_image(message)
|
316 |
+
if image:
|
317 |
+
history[-1][1] = "Here's your generated image!"
|
318 |
+
# Handle image display logic
|
319 |
+
return history
|
320 |
+
except Exception as e:
|
321 |
+
history[-1][1] = f"Sorry, I couldn't generate the image: {str(e)}"
|
322 |
+
return history
|
323 |
+
|
324 |
+
# Handle regular text responses
|
325 |
+
try:
|
326 |
+
translated_msg, original_lang, was_transliterated = translate_text(message)
|
327 |
+
response = respond(
|
328 |
+
translated_msg,
|
329 |
+
history[:-1],
|
330 |
+
system_msg,
|
331 |
+
max_tokens,
|
332 |
+
temperature,
|
333 |
+
top_p
|
334 |
+
)
|
335 |
+
|
336 |
+
# Stream the response
|
337 |
+
partial_response = ""
|
338 |
+
for chunk in response:
|
339 |
+
partial_response += chunk
|
340 |
+
history[-1][1] = partial_response
|
341 |
+
yield history
|
342 |
+
time.sleep(0.02) # Add slight delay for smooth streaming
|
343 |
+
|
344 |
+
except Exception as e:
|
345 |
+
history[-1][1] = f"An error occurred: {str(e)}"
|
346 |
+
yield history
|
347 |
+
|
348 |
+
# Event handlers
|
349 |
+
txt_msg = txt.submit(
|
350 |
user_message,
|
351 |
[txt, chatbot],
|
352 |
[txt, chatbot],
|
|
|
354 |
).then(
|
355 |
bot_response,
|
356 |
[chatbot, system_msg, max_tokens, temperature, top_p],
|
357 |
+
chatbot
|
358 |
)
|
359 |
|
360 |
send_btn.click(
|
|
|
365 |
).then(
|
366 |
bot_response,
|
367 |
[chatbot, system_msg, max_tokens, temperature, top_p],
|
368 |
+
chatbot
|
369 |
)
|
370 |
|
371 |
+
clear_btn.click(lambda: None, None, chatbot, queue=False)
|
372 |
+
|
373 |
+
# Handle voice input
|
374 |
+
def process_audio(audio_file):
|
375 |
+
# Add your audio transcription logic here
|
376 |
+
return "Audio input received! (Add your transcription logic)"
|
377 |
|
378 |
+
audio_input.change(
|
379 |
+
process_audio,
|
380 |
+
inputs=[audio_input],
|
381 |
+
outputs=[txt]
|
|
|
382 |
)
|
383 |
|
384 |
return demo
|