Daemontatox commited on
Commit
91e94f1
·
verified ·
1 Parent(s): c91f5aa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +171 -126
app.py CHANGED
@@ -6,6 +6,8 @@ from typing import Iterator, List, Tuple
6
 
7
  # Configuration Constants
8
  DEFAULT_SYSTEM_PROMPT = """
 
 
9
  أنت مترجم ثنائي اللغة متخصص في الترجمة بين العربية والإنجليزية. هدفك هو تقديم ترجمات دقيقة، ملائمة للسياق، ومتسقة من الناحية الأسلوبية، مع الالتزام بالإرشادات التالية:
10
  أسلوب الكتابة:
11
  1. الدقة النحوية: احرص دائمًا على أن تكون الترجمة صحيحة نحويًا.
@@ -38,97 +40,148 @@ DEFAULT_SYSTEM_PROMPT = """
38
  حافظ على تنسيق البيانات المهمة (مثل التواريخ، والقياسات، والاستشهادات القانونية).
39
  عند الشك:
40
  قدم الأولوية للوضوح، والتناسق، والملاءمة مع احتياجات الجمهور المستهدف. قم دائمًا بموازنة التعليمات الخاصة بالمشروع مع هذه الإرشادات، مع إعطاء الأولوية لمتطلبات العميل عند وجود أي تعارض.
41
- """ # (keeping the full prompt as in original)
 
 
42
 
43
  TITLE = "<h1><center>Mawared T Assistant</center></h1>"
44
  PLACEHOLDER = "Ask me anything! I'll think through it step by step."
45
 
46
  CSS = """
47
- .duplicate-button {
48
- margin: auto !important;
49
- color: white !important;
50
- background: black !important;
51
- border-radius: 100vh !important;
52
  }
53
- h3 {
54
- text-align: center;
 
 
 
 
 
 
 
 
55
  }
 
56
  .message-wrap {
57
  overflow-x: auto;
 
 
 
58
  }
59
- .message-wrap p {
60
- margin-bottom: 1em;
 
 
 
 
 
 
61
  }
62
- .message-wrap pre {
63
- background-color: #f6f8fa;
64
- border-radius: 3px;
65
- padding: 16px;
66
- overflow-x: auto;
 
 
67
  }
68
- .message-wrap code {
69
- background-color: rgba(175,184,193,0.2);
70
- border-radius: 3px;
71
- padding: 0.2em 0.4em;
72
- font-family: monospace;
 
73
  }
74
- .custom-tag {
75
- color: #0066cc;
76
- font-weight: bold;
 
 
 
 
 
 
 
 
 
 
77
  }
 
78
  .chat-area {
79
  height: 500px !important;
80
  overflow-y: auto !important;
 
 
 
 
 
 
 
 
 
 
81
  }
82
  """
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  def format_text(text: str) -> str:
85
  """Format text with proper spacing and tag highlighting"""
86
- tag_patterns = [
87
- (r'<Thinking>', '\n<Thinking>\n'),
88
- (r'</Thinking>', '\n</Thinking>\n'),
89
- (r'<Critique>', '\n<Critique>\n'),
90
- (r'</Critique>', '\n</Critique>\n'),
91
- (r'<Revising>', '\n<Revising>\n'),
92
- (r'</Revising>', '\n</Revising>\n'),
93
- (r'<Final>', '\n<Final>\n'),
94
- (r'</Final>', '\n</Final>\n')
95
- ]
96
-
97
  formatted = text
98
- for pattern, replacement in tag_patterns:
99
- formatted = re.sub(pattern, replacement, formatted)
100
-
101
- formatted = '\n'.join(line for line in formatted.split('\n') if line.strip())
102
-
103
- return formatted
104
 
105
  def format_chat_history(history: List[List[str]]) -> str:
106
- """Format chat history for display"""
107
- formatted = []
108
  for user_msg, assistant_msg in history:
109
- formatted.append(f"User: {user_msg}")
 
 
 
 
 
 
 
 
110
  if assistant_msg:
111
- formatted.append(f"Assistant: {assistant_msg}")
112
- return "\n\n".join(formatted)
113
-
114
- def create_examples() -> List[str]:
115
- """Create example queries for the UI"""
116
- return [
117
- "Explain the concept of artificial intelligence.",
118
- "How does photosynthesis work?",
119
- "What are the main causes of climate change?",
120
- "Describe the process of protein synthesis.",
121
- "What are the key features of a democratic government?",
122
- ]
123
 
124
  def convert_history_to_cohere_format(history: List[List[str]]) -> List[dict]:
125
- """Convert chat history to Cohere's format"""
126
  cohere_history = []
127
  for user_msg, assistant_msg in history:
128
  if user_msg:
129
- cohere_history.append({"role": "User", "message": user_msg})
130
  if assistant_msg:
131
- cohere_history.append({"role": "Chatbot", "message": assistant_msg})
132
  return cohere_history
133
 
134
  def chat_response(
@@ -144,44 +197,41 @@ def chat_response(
144
  api_key: str = os.getenv("COHERE_API_KEY")
145
  ) -> Iterator[Tuple[List[List[str]], str]]:
146
  """Generate chat responses using Cohere API"""
 
 
 
 
 
 
147
  co = cohere.Client(api_key=api_key)
148
-
149
- # Convert history to Cohere format
150
  chat_history = convert_history_to_cohere_format(history)
151
-
152
- # Initialize buffer for streaming
153
  buffer = ""
154
- history = history + [[message, ""]]
155
 
156
- # Process stream
157
  try:
158
- # Initialize stream
159
  stream = co.chat_stream(
160
  model='c4ai-aya-expanse-32b',
161
  message=message,
162
  temperature=temperature,
 
 
 
 
163
  chat_history=chat_history,
164
  prompt_truncation='AUTO',
165
  preamble=system_prompt
166
  )
167
-
168
  for event in stream:
169
  if event.event_type == "text-generation":
170
  buffer += event.text
171
- formatted_buffer = format_text(buffer)
172
- history[-1][1] = formatted_buffer
173
- chat_display = format_chat_history(history)
174
- yield history, chat_display
175
-
176
  except Exception as e:
177
  error_message = f"Error: {str(e)}"
178
  history[-1][1] = error_message
179
- chat_display = format_chat_history(history)
180
- yield history, chat_display
181
-
182
- def process_example(example: str) -> tuple:
183
- """Process example query and return empty history and updated display"""
184
- return [], f"User: {example}\n\n"
185
 
186
  def main():
187
  """Main function to set up and launch the Gradio interface"""
@@ -195,21 +245,22 @@ def main():
195
  with gr.Row():
196
  with gr.Column():
197
  chat_history = gr.State([])
198
- chat_display = gr.TextArea(
199
  value="",
200
  label="Chat History",
201
- interactive=False,
202
  elem_classes=["chat-area"],
203
  )
204
 
205
  message = gr.TextArea(
206
  placeholder=PLACEHOLDER,
207
  label="Your message",
208
- lines=3
 
 
209
  )
210
 
211
  with gr.Row():
212
- submit = gr.Button("Send")
213
  clear = gr.Button("Clear")
214
 
215
  with gr.Accordion("���️ Advanced Settings", open=False):
@@ -217,6 +268,7 @@ def main():
217
  value=DEFAULT_SYSTEM_PROMPT,
218
  label="System Prompt",
219
  lines=5,
 
220
  )
221
  temperature = gr.Slider(
222
  minimum=0,
@@ -253,65 +305,58 @@ def main():
253
  value=1.2,
254
  label="Repetition Penalty",
255
  )
256
-
257
- examples = gr.Examples(
258
- examples=create_examples(),
259
- inputs=[message],
260
- outputs=[chat_history, chat_display],
261
- fn=process_example,
262
- cache_examples=False,
263
- )
264
-
265
- # Set up event handlers
266
- submit_click = submit.click(
267
  chat_response,
268
- inputs=[
269
- message,
270
- chat_history,
271
- chat_display,
272
- system_prompt,
273
- temperature,
274
- max_tokens,
275
- top_p,
276
- top_k,
277
- penalty,
278
- ],
279
  outputs=[chat_history, chat_display],
280
  show_progress=True,
281
- )
282
-
283
- # Bind Enter key to submit
284
  message.submit(
285
  chat_response,
286
- inputs=[
287
- message,
288
- chat_history,
289
- chat_display,
290
- system_prompt,
291
- temperature,
292
- max_tokens,
293
- top_p,
294
- top_k,
295
- penalty,
296
- ],
297
  outputs=[chat_history, chat_display],
298
  show_progress=True,
299
- )
300
-
301
  clear.click(
302
  lambda: ([], ""),
303
  outputs=[chat_history, chat_display],
304
  show_progress=True,
305
  )
306
-
307
- # Clear input after submission
308
- submit_click.then(lambda: "", outputs=message)
309
- message.submit(lambda: "", outputs=message)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
 
311
  return demo
312
 
313
  if __name__ == "__main__":
314
  demo = main()
315
- demo.launch()
316
-
317
-
 
6
 
7
  # Configuration Constants
8
  DEFAULT_SYSTEM_PROMPT = """
9
+
10
+
11
  أنت مترجم ثنائي اللغة متخصص في الترجمة بين العربية والإنجليزية. هدفك هو تقديم ترجمات دقيقة، ملائمة للسياق، ومتسقة من الناحية الأسلوبية، مع الالتزام بالإرشادات التالية:
12
  أسلوب الكتابة:
13
  1. الدقة النحوية: احرص دائمًا على أن تكون الترجمة صحيحة نحويًا.
 
40
  حافظ على تنسيق البيانات المهمة (مثل التواريخ، والقياسات، والاستشهادات القانونية).
41
  عند الشك:
42
  قدم الأولوية للوضوح، والتناسق، والملاءمة مع احتياجات الجمهور المستهدف. قم دائمًا بموازنة التعليمات الخاصة بالمشروع مع هذه الإرشادات، مع إعطاء الأولوية لمتطلبات العميل عند وجود أي تعارض.
43
+
44
+
45
+ """
46
 
47
  TITLE = "<h1><center>Mawared T Assistant</center></h1>"
48
  PLACEHOLDER = "Ask me anything! I'll think through it step by step."
49
 
50
  CSS = """
51
+ :root {
52
+ --rtl-bg: #f0f8ff;
53
+ --ltr-bg: #fff8f0;
 
 
54
  }
55
+
56
+ .rtl {
57
+ direction: rtl !important;
58
+ text-align: right !important;
59
+ font-family: 'Tahoma', 'Arial', sans-serif !important;
60
+ }
61
+
62
+ .ltr {
63
+ direction: ltr !important;
64
+ text-align: left !important;
65
  }
66
+
67
  .message-wrap {
68
  overflow-x: auto;
69
+ padding: 20px;
70
+ border-radius: 10px;
71
+ margin: 10px 0;
72
  }
73
+
74
+ .user-message {
75
+ background: var(--rtl-bg);
76
+ padding: 15px;
77
+ border-radius: 15px 15px 0 15px;
78
+ margin: 10px 0;
79
+ max-width: 80%;
80
+ margin-left: auto;
81
  }
82
+
83
+ .assistant-message {
84
+ background: var(--ltr-bg);
85
+ padding: 15px;
86
+ border-radius: 15px 15px 15px 0;
87
+ margin: 10px 0;
88
+ max-width: 80%;
89
  }
90
+
91
+ .direction-toggle {
92
+ position: absolute;
93
+ right: 10px;
94
+ top: 10px;
95
+ z-index: 1000;
96
  }
97
+
98
+ .arabic-text {
99
+ font-size: 1.1em;
100
+ line-height: 1.8;
101
+ }
102
+
103
+ .text-input {
104
+ min-height: 120px !important;
105
+ }
106
+
107
+ .rtl-textarea textarea {
108
+ text-align: right !important;
109
+ direction: rtl !important;
110
  }
111
+
112
  .chat-area {
113
  height: 500px !important;
114
  overflow-y: auto !important;
115
+ background: #f8f9fa !important;
116
+ border-radius: 10px !important;
117
+ padding: 20px !important;
118
+ }
119
+
120
+ .duplicate-button {
121
+ margin: auto !important;
122
+ color: white !important;
123
+ background: black !important;
124
+ border-radius: 100vh !important;
125
  }
126
  """
127
 
128
+ # Precompile regex patterns
129
+ TAG_PATTERNS = [
130
+ (re.compile(r'<Thinking>'), '\n<Thinking>\n'),
131
+ (re.compile(r'</Thinking>'), '\n</Thinking>\n'),
132
+ (re.compile(r'<Critique>'), '\n<Critique>\n'),
133
+ (re.compile(r'</Critique>'), '\n</Critique>\n'),
134
+ (re.compile(r'<Revising>'), '\n<Revising>\n'),
135
+ (re.compile(r'</Revising>'), '\n</Revising>\n'),
136
+ (re.compile(r'<Final>'), '\n<Final>\n'),
137
+ (re.compile(r'</Final>'), '\n</Final>\n')
138
+ ]
139
+
140
+ ARABIC_REGEX = re.compile(r'[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]')
141
+
142
+ def has_arabic(text: str) -> bool:
143
+ """Check if text contains Arabic characters"""
144
+ return bool(ARABIC_REGEX.search(text))
145
+
146
  def format_text(text: str) -> str:
147
  """Format text with proper spacing and tag highlighting"""
 
 
 
 
 
 
 
 
 
 
 
148
  formatted = text
149
+ for pattern, replacement in TAG_PATTERNS:
150
+ formatted = pattern.sub(replacement, formatted)
151
+ return '\n'.join(line for line in formatted.split('\n') if line.strip())
 
 
 
152
 
153
  def format_chat_history(history: List[List[str]]) -> str:
154
+ """Format chat history with RTL/LTR support"""
155
+ html = []
156
  for user_msg, assistant_msg in history:
157
+ if user_msg:
158
+ direction = "rtl" if has_arabic(user_msg) else "ltr"
159
+ html.append(f"""
160
+ <div class="message-wrap {direction}">
161
+ <div class="user-message arabic-text {direction}">
162
+ <strong>User:</strong> {user_msg}
163
+ </div>
164
+ </div>
165
+ """)
166
  if assistant_msg:
167
+ direction = "rtl" if has_arabic(assistant_msg) else "ltr"
168
+ html.append(f"""
169
+ <div class="message-wrap {direction}">
170
+ <div class="assistant-message {direction}">
171
+ <strong>Assistant:</strong> {assistant_msg}
172
+ </div>
173
+ </div>
174
+ """)
175
+ return "".join(html)
 
 
 
176
 
177
  def convert_history_to_cohere_format(history: List[List[str]]) -> List[dict]:
178
+ """Convert chat history to Cohere's format with proper roles"""
179
  cohere_history = []
180
  for user_msg, assistant_msg in history:
181
  if user_msg:
182
+ cohere_history.append({"role": "USER", "message": user_msg})
183
  if assistant_msg:
184
+ cohere_history.append({"role": "CHATBOT", "message": assistant_msg})
185
  return cohere_history
186
 
187
  def chat_response(
 
197
  api_key: str = os.getenv("COHERE_API_KEY")
198
  ) -> Iterator[Tuple[List[List[str]], str]]:
199
  """Generate chat responses using Cohere API"""
200
+ if not api_key:
201
+ error_message = "Error: COHERE_API_KEY environment variable not set."
202
+ history.append([message, error_message])
203
+ yield history, format_chat_history(history)
204
+ return
205
+
206
  co = cohere.Client(api_key=api_key)
 
 
207
  chat_history = convert_history_to_cohere_format(history)
 
 
208
  buffer = ""
209
+ history.append([message, ""])
210
 
 
211
  try:
 
212
  stream = co.chat_stream(
213
  model='c4ai-aya-expanse-32b',
214
  message=message,
215
  temperature=temperature,
216
+ max_tokens=max_new_tokens,
217
+ p=top_p,
218
+ k=top_k,
219
+ frequency_penalty=penalty,
220
  chat_history=chat_history,
221
  prompt_truncation='AUTO',
222
  preamble=system_prompt
223
  )
224
+
225
  for event in stream:
226
  if event.event_type == "text-generation":
227
  buffer += event.text
228
+ history[-1][1] = format_text(buffer)
229
+ yield history, format_chat_history(history)
230
+
 
 
231
  except Exception as e:
232
  error_message = f"Error: {str(e)}"
233
  history[-1][1] = error_message
234
+ yield history, format_chat_history(history)
 
 
 
 
 
235
 
236
  def main():
237
  """Main function to set up and launch the Gradio interface"""
 
245
  with gr.Row():
246
  with gr.Column():
247
  chat_history = gr.State([])
248
+ chat_display = gr.HTML(
249
  value="",
250
  label="Chat History",
 
251
  elem_classes=["chat-area"],
252
  )
253
 
254
  message = gr.TextArea(
255
  placeholder=PLACEHOLDER,
256
  label="Your message",
257
+ lines=3,
258
+ elem_id="message_input",
259
+ elem_classes=["text-input"]
260
  )
261
 
262
  with gr.Row():
263
+ submit = gr.Button("Send", elem_id="submit_btn")
264
  clear = gr.Button("Clear")
265
 
266
  with gr.Accordion("���️ Advanced Settings", open=False):
 
268
  value=DEFAULT_SYSTEM_PROMPT,
269
  label="System Prompt",
270
  lines=5,
271
+ elem_classes=["rtl-textarea"]
272
  )
273
  temperature = gr.Slider(
274
  minimum=0,
 
305
  value=1.2,
306
  label="Repetition Penalty",
307
  )
308
+
309
+ # Event handlers
310
+ submit.click(
 
 
 
 
 
 
 
 
311
  chat_response,
312
+ inputs=[message, chat_history, chat_display, system_prompt,
313
+ temperature, max_tokens, top_p, top_k, penalty],
 
 
 
 
 
 
 
 
 
314
  outputs=[chat_history, chat_display],
315
  show_progress=True,
316
+ ).then(lambda: "", outputs=message)
317
+
 
318
  message.submit(
319
  chat_response,
320
+ inputs=[message, chat_history, chat_display, system_prompt,
321
+ temperature, max_tokens, top_p, top_k, penalty],
 
 
 
 
 
 
 
 
 
322
  outputs=[chat_history, chat_display],
323
  show_progress=True,
324
+ ).then(lambda: "", outputs=message)
325
+
326
  clear.click(
327
  lambda: ([], ""),
328
  outputs=[chat_history, chat_display],
329
  show_progress=True,
330
  )
331
+
332
+ # JavaScript for dynamic RTL/LTR switching
333
+ demo.load(
334
+ None,
335
+ None,
336
+ None,
337
+ _js="""
338
+ function setupDirectionHandling() {
339
+ const textarea = document.querySelector('#message_input textarea');
340
+ const chatArea = document.querySelector('.chat-area');
341
+
342
+ // Input field handling
343
+ textarea.addEventListener('input', function(e) {
344
+ const hasArabic = /[\u0600-\u06FF]/.test(e.target.value);
345
+ this.parentElement.classList.toggle('rtl', hasArabic);
346
+ this.parentElement.classList.toggle('ltr', !hasArabic);
347
+ });
348
+
349
+ // Chat area scroll handling
350
+ chatArea.addEventListener('DOMSubtreeModified', function() {
351
+ this.scrollTop = this.scrollHeight;
352
+ });
353
+ }
354
+ setupDirectionHandling();
355
+ """
356
+ )
357
 
358
  return demo
359
 
360
  if __name__ == "__main__":
361
  demo = main()
362
+ demo.launch()