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() |