Spaces:
Sleeping
Sleeping
| import os | |
| import re | |
| import cohere | |
| import gradio as gr | |
| from typing import Iterator, List, Tuple | |
| # Configuration Constants | |
| DEFAULT_SYSTEM_PROMPT = """ | |
| أنت مترجم ثنائي اللغة متخصص في الترجمة بين العربية والإنجليزية. هدفك هو تقديم ترجمات دقيقة، ملائمة للسياق، ومتسقة من الناحية الأسلوبية، مع الالتزام بالإرشادات التالية: | |
| أسلوب الكتابة: | |
| 1. الدقة النحوية: احرص دائمًا على أن تكون الترجمة صحيحة نحويًا. | |
| 2. الملاءمة السياقية: قم بتكييف الترجمة مع السياق والجمهور المستهدف: | |
| استخدم جملًا موجزة وواضحة في المحتوى الطبي والقانوني. | |
| اعتمد لغة جذابة وخيالية في المواد التسويقية. | |
| حافظ على الرسمية والبلاغية في المحتوى القانوني. | |
| 3. البنية السليمة: احترم تراكيب الجمل العربية وتجنب النسخ المباشر لقواعد لغة المصدر. فضل استخدام "الجملة الفعلية" إلا إذا كانت "الجملة الاسمية" أكثر ملاءمة (مثلًا في العناوين أو التنويهات). | |
| الخيارات الأسلوبية: | |
| استخدم التشكيل فقط عند الضرورة لتوضيح المعنى. | |
| تعامل مع الأسماء والأحرف المختصرة حسب السياق: | |
| قم بتعريب الأسماء وأسماء الأدوية إلا إذا وُجدت لها مرادفات عربية. | |
| ترجم أسماء البرامج والإدارات والهيئات عندما يكون ذلك مفيدًا. | |
| استخدم الأرقام العربية وتأكد من التعامل الصحيح مع الوحدات والعناوين والمراجع. | |
| علامات الترقيم: | |
| طبق قواعد الترقيم العربية لضمان وضوح النص. | |
| استخدم الفاصلة العربية (،) والفاصلة المنقوطة (؛) حسب الأعراف. | |
| تجنب الإفراط في استخدام علامات الاقتباس واحرص على وضع النقطتين (:) بشكل منطقي. | |
| الأخطاء الشائعة التي يجب تجنبها: | |
| تجنب ترجمة "is" بـ "يُعتبر" إلا إذا كان ذلك مناسبًا للسياق. | |
| استخدم حروف الجر والعطف بشكل صحيح لضمان تدفق الجمل بسلاسة. | |
| قلل من التكرار واستخدم الضمائر حيثما أمكن. | |
| تجنب الإفراط في استخدام تراكيب مثل "(قام + الفعل)" و"الخاص بـ." | |
| المصطلحات المحددة: | |
| في الترجمات القانونية، حافظ على النبرة الرسمية وتأكد من دقة المصطلحات. | |
| في الترجمات الطبية، بسّط المصطلحات التقنية للجمهور العام مع الاحتفاظ بالتعقيد عند مخاطبة المتخصصين. | |
| في الترجمات التسويقية، ركّز على الإبداع بدلًا من الترجمة الحرفية، مع الحفاظ على الرسالة الأساسية. | |
| إرشادات التنسيق: | |
| التزم بمعايير الطباعة العربية بشكل متسق. | |
| حافظ على تنسيق البيانات المهمة (مثل التواريخ، والقياسات، والاستشهادات القانونية). | |
| عند الشك: | |
| قدم الأولوية للوضوح، والتناسق، والملاءمة مع احتياجات الجمهور المستهدف. قم دائمًا بموازنة التعليمات الخاصة بالمشروع مع هذه الإرشادات، مع إعطاء الأولوية لمتطلبات العميل عند وجود أي تعارض. | |
| """ | |
| TITLE = "<h1><center>Arabic localizer Translation Assistant </center></h1>" | |
| PLACEHOLDER = "اسأل عن أي شيء! سأفكر فيه خطوة بخطوة." | |
| CSS = """ | |
| .duplicate-button { | |
| margin: auto !important; | |
| color: white !important; | |
| background: black !important; | |
| border-radius: 100vh !important; | |
| } | |
| h3 { | |
| text-align: center; | |
| } | |
| .message-wrap { | |
| overflow-x: auto; | |
| } | |
| .message-wrap p { | |
| margin-bottom: 1em; | |
| } | |
| .message-wrap pre { | |
| background-color: #f6f8fa; | |
| border-radius: 3px; | |
| padding: 16px; | |
| overflow-x: auto; | |
| } | |
| .message-wrap code { | |
| background-color: rgba(175,184,193,0.2); | |
| border-radius: 3px; | |
| padding: 0.2em 0.4em; | |
| font-family: monospace; | |
| } | |
| .custom-tag { | |
| color: #0066cc; | |
| font-weight: bold; | |
| } | |
| .chat-area { | |
| height: 500px !important; | |
| overflow-y: auto !important; | |
| } | |
| .arabic-input { | |
| direction: rtl; | |
| text-align: right; | |
| font-family: 'Arabic', Arial, sans-serif; | |
| } | |
| """ | |
| def is_arabic_text(text: str) -> bool: | |
| """Detect if the text contains Arabic characters""" | |
| return any('\u0600' <= char <= '\u06FF' for char in text) | |
| def format_text(text: str) -> str: | |
| """Format text with proper spacing and tag highlighting""" | |
| tag_patterns = [ | |
| (r'<Thinking>', '\n<Thinking>\n'), | |
| (r'</Thinking>', '\n</Thinking>\n'), | |
| (r'<Critique>', '\n<Critique>\n'), | |
| (r'</Critique>', '\n</Critique>\n'), | |
| (r'<Revising>', '\n<Revising>\n'), | |
| (r'</Revising>', '\n</Revising>\n'), | |
| (r'<Final>', '\n<Final>\n'), | |
| (r'</Final>', '\n</Final>\n') | |
| ] | |
| formatted = text | |
| for pattern, replacement in tag_patterns: | |
| formatted = re.sub(pattern, replacement, formatted) | |
| formatted = '\n'.join(line for line in formatted.split('\n') if line.strip()) | |
| return formatted | |
| def format_chat_history(history: List[List[str]]) -> str: | |
| """Format chat history for display""" | |
| formatted = [] | |
| for user_msg, assistant_msg in history: | |
| formatted.append(f"User: {user_msg}") | |
| if assistant_msg: | |
| formatted.append(f"Assistant: {assistant_msg}") | |
| return "\n\n".join(formatted) | |
| def create_examples() -> List[str]: | |
| """Create example queries for the UI""" | |
| return [ | |
| "اشرح مفهوم الذكاء الاصطناعي", | |
| "كيف تعمل عملية التمثيل الضوئي؟", | |
| "ما هي الأسباب الرئيسية لتغير المناخ؟", | |
| "صف عملية تخليق البروتين", | |
| "ما هي الميزات الرئيسية للحكومة الديمقراطية؟", | |
| ] | |
| def convert_history_to_cohere_format(history: List[List[str]]) -> List[dict]: | |
| """Convert chat history to Cohere's format""" | |
| cohere_history = [] | |
| for user_msg, assistant_msg in history: | |
| if user_msg: | |
| cohere_history.append({"role": "User", "message": user_msg}) | |
| if assistant_msg: | |
| cohere_history.append({"role": "Chatbot", "message": assistant_msg}) | |
| return cohere_history | |
| def chat_response( | |
| message: str, | |
| history: List[List[str]], | |
| chat_display: str, | |
| system_prompt: str, | |
| temperature: float = 0, | |
| max_new_tokens: int = 8192, | |
| top_p: float = 0.8, | |
| top_k: int = 40, | |
| penalty: float = 1.2, | |
| api_key: str = os.getenv("COHERE_API_KEY") | |
| ) -> Iterator[Tuple[List[List[str]], str]]: | |
| """Generate chat responses using Cohere API""" | |
| co = cohere.Client(api_key=api_key) | |
| # Convert history to Cohere format | |
| chat_history = convert_history_to_cohere_format(history) | |
| # Initialize buffer for streaming | |
| buffer = "" | |
| history = history + [[message, ""]] | |
| # Process stream | |
| try: | |
| # Initialize stream | |
| stream = co.chat_stream( | |
| #model='c4ai-aya-expanse-32b', | |
| model='command-r7b-arabic-02-2025', | |
| message=message, | |
| temperature=temperature, | |
| chat_history=chat_history, | |
| preamble=system_prompt | |
| ) | |
| for event in stream: | |
| if event.event_type == "text-generation": | |
| buffer += event.text | |
| formatted_buffer = format_text(buffer) | |
| history[-1][1] = formatted_buffer | |
| chat_display = format_chat_history(history) | |
| yield history, chat_display | |
| except Exception as e: | |
| error_message = f"Error: {str(e)}" | |
| history[-1][1] = error_message | |
| chat_display = format_chat_history(history) | |
| yield history, chat_display | |
| def process_example(example: str) -> tuple: | |
| """Process example query and return empty history and updated display""" | |
| return [], f"User: {example}\n\n" | |
| def main(): | |
| """Main function to set up and launch the Gradio interface""" | |
| with gr.Blocks(css=CSS, theme="JohnSmith9982/small_and_pretty'") as demo: | |
| gr.HTML(TITLE) | |
| gr.DuplicateButton( | |
| value="", | |
| elem_classes="duplicate-button" | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| chat_history = gr.State([]) | |
| chat_display = gr.TextArea( | |
| value="", | |
| label="Chat History", | |
| interactive=True, | |
| elem_classes=["chat-area"], | |
| ) | |
| message = gr.TextArea( | |
| placeholder=PLACEHOLDER, | |
| label="Your message", | |
| lines=3, | |
| elem_classes=["message-input"] | |
| ) | |
| with gr.Row(): | |
| submit = gr.Button("Send") | |
| clear = gr.Button("Clear") | |
| with gr.Accordion("⚙️ Advanced Settings", open=False): | |
| system_prompt = gr.TextArea( | |
| value=DEFAULT_SYSTEM_PROMPT, | |
| label="System Prompt", | |
| lines=7, | |
| ) | |
| temperature = gr.Slider( | |
| minimum=0, | |
| maximum=1, | |
| step=0.1, | |
| value=0, | |
| label="Temperature", | |
| ) | |
| max_tokens = gr.Slider( | |
| minimum=128, | |
| maximum=32000, | |
| step=128, | |
| value=8192, | |
| label="Max Tokens", | |
| ) | |
| top_p = gr.Slider( | |
| minimum=0.1, | |
| maximum=1.0, | |
| step=0.1, | |
| value=0.8, | |
| label="Top-p", | |
| ) | |
| top_k = gr.Slider( | |
| minimum=1, | |
| maximum=100, | |
| step=1, | |
| value=40, | |
| label="Top-k", | |
| ) | |
| penalty = gr.Slider( | |
| minimum=1.0, | |
| maximum=2.0, | |
| step=0.1, | |
| value=1.2, | |
| label="Repetition Penalty", | |
| ) | |
| examples = gr.Examples( | |
| examples=create_examples(), | |
| inputs=[message], | |
| outputs=[chat_history, chat_display], | |
| fn=process_example, | |
| cache_examples=False, | |
| ) | |
| # JavaScript to handle Enter key submission and RTL direction | |
| js_handler = """ | |
| function handleKeyPress(textArea, submitButton) { | |
| textArea.addEventListener('keydown', function(e) { | |
| // Check for Arabic characters | |
| const containsArabic = /[\u0600-\u06FF]/.test(textArea.value); | |
| // Apply RTL class for Arabic text | |
| if (containsArabic) { | |
| textArea.classList.add('arabic-input'); | |
| } else { | |
| textArea.classList.remove('arabic-input'); | |
| } | |
| // Handle Enter key for submission (without Shift) | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); // Prevent default new line | |
| submitButton.click(); // Trigger submit button click | |
| } | |
| }); | |
| } | |
| """ | |
| # Set up event handlers | |
| submit_click = submit.click( | |
| chat_response, | |
| inputs=[ | |
| message, | |
| chat_history, | |
| chat_display, | |
| system_prompt, | |
| temperature, | |
| max_tokens, | |
| top_p, | |
| top_k, | |
| penalty, | |
| ], | |
| outputs=[chat_history, chat_display], | |
| show_progress=True, | |
| ) | |
| # Clear input after submission | |
| submit_click.then(lambda: "", outputs=message) | |
| # Add JavaScript to handle Enter key and RTL | |
| demo.load(None, inputs=[message, submit], js=js_handler) | |
| clear.click( | |
| lambda: ([], ""), | |
| outputs=[chat_history, chat_display], | |
| show_progress=True, | |
| ) | |
| return demo | |
| if __name__ == "__main__": | |
| demo = main() | |
| demo.launch() |