Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -12,24 +12,24 @@ from typing import List, Dict, Optional, Any, Tuple
|
|
| 12 |
|
| 13 |
|
| 14 |
# Configuration
|
| 15 |
-
SPACE_NAME = '
|
| 16 |
-
SPACE_DESCRIPTION = '
|
| 17 |
|
| 18 |
# Default configuration values
|
| 19 |
DEFAULT_CONFIG = {
|
| 20 |
'name': SPACE_NAME,
|
| 21 |
'description': SPACE_DESCRIPTION,
|
| 22 |
-
'system_prompt':
|
| 23 |
-
'temperature': 0.
|
| 24 |
-
'max_tokens':
|
| 25 |
'model': 'google/gemma-3-27b-it',
|
| 26 |
'api_key_var': 'API_KEY',
|
| 27 |
-
'theme': '
|
| 28 |
-
'grounding_urls': [
|
| 29 |
'enable_dynamic_urls': True,
|
| 30 |
'enable_file_upload': True,
|
| 31 |
-
'examples': ['
|
| 32 |
-
'language': '
|
| 33 |
'locked': False
|
| 34 |
}
|
| 35 |
|
|
@@ -183,13 +183,7 @@ def fetch_url_content(url: str, max_length: int = 3000) -> str:
|
|
| 183 |
return f"❌ Invalid URL format: {url}"
|
| 184 |
|
| 185 |
headers = {
|
| 186 |
-
'User-Agent': 'Mozilla/5.0 (compatible; HuggingFace-Space/1.0)'
|
| 187 |
-
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
| 188 |
-
'Accept-Language': 'en-US,en;q=0.5',
|
| 189 |
-
'Accept-Encoding': 'gzip, deflate',
|
| 190 |
-
'DNT': '1',
|
| 191 |
-
'Connection': 'keep-alive',
|
| 192 |
-
'Upgrade-Insecure-Requests': '1'
|
| 193 |
}
|
| 194 |
|
| 195 |
response = requests.get(url, headers=headers, timeout=5)
|
|
@@ -235,7 +229,7 @@ def fetch_url_content(url: str, max_length: int = 3000) -> str:
|
|
| 235 |
|
| 236 |
def extract_urls_from_text(text: str) -> List[str]:
|
| 237 |
"""Extract URLs from message text"""
|
| 238 |
-
url_pattern = r'https?://[^\s<>"{}
|
| 239 |
urls = re.findall(url_pattern, text)
|
| 240 |
return [url.rstrip('.,;:)?!') for url in urls]
|
| 241 |
|
|
@@ -335,17 +329,18 @@ def get_grounding_context() -> str:
|
|
| 335 |
return ""
|
| 336 |
|
| 337 |
|
| 338 |
-
def
|
| 339 |
-
"""Export conversation history to
|
| 340 |
if not history:
|
| 341 |
return "No conversation to export."
|
| 342 |
|
| 343 |
-
|
|
|
|
| 344 |
Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
| 345 |
Space: {SPACE_NAME}
|
| 346 |
Model: {MODEL}
|
| 347 |
|
| 348 |
-
|
| 349 |
|
| 350 |
"""
|
| 351 |
|
|
@@ -355,15 +350,28 @@ Model: {MODEL}
|
|
| 355 |
role = message.get('role', 'unknown')
|
| 356 |
content = message.get('content', '')
|
| 357 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 358 |
if role == 'user':
|
| 359 |
message_count += 1
|
| 360 |
-
|
| 361 |
elif role == 'assistant':
|
| 362 |
-
|
| 363 |
|
| 364 |
-
return
|
| 365 |
-
|
| 366 |
-
|
| 367 |
|
| 368 |
|
| 369 |
def generate_response(message: str, history: List[Dict[str, str]], files: Optional[List] = None) -> str:
|
|
@@ -594,7 +602,7 @@ def create_interface():
|
|
| 594 |
submit_btn = gr.Button("Send", variant="primary")
|
| 595 |
clear_btn = gr.Button("Clear")
|
| 596 |
|
| 597 |
-
# Export functionality
|
| 598 |
with gr.Row():
|
| 599 |
# Use a regular Button for triggering export
|
| 600 |
export_trigger_btn = gr.Button(
|
|
@@ -615,18 +623,18 @@ def create_interface():
|
|
| 615 |
return None
|
| 616 |
|
| 617 |
try:
|
| 618 |
-
content =
|
| 619 |
|
| 620 |
# Create filename
|
| 621 |
space_name_safe = re.sub(r'[^a-zA-Z0-9]+', '_', SPACE_NAME).lower()
|
| 622 |
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
| 623 |
-
filename = f"{space_name_safe}_conversation_{timestamp}.
|
| 624 |
|
| 625 |
# Save to temp file
|
| 626 |
temp_path = Path(tempfile.gettempdir()) / filename
|
| 627 |
temp_path.write_text(content, encoding='utf-8')
|
| 628 |
|
| 629 |
-
# Return the file
|
| 630 |
return gr.File(visible=True, value=str(temp_path))
|
| 631 |
except Exception as e:
|
| 632 |
gr.Error(f"Failed to export conversation: {str(e)}")
|
|
@@ -659,10 +667,13 @@ def create_interface():
|
|
| 659 |
# Get response
|
| 660 |
response = generate_response(message, formatted_history, files_state)
|
| 661 |
|
| 662 |
-
#
|
|
|
|
|
|
|
|
|
|
| 663 |
chat_history = chat_history + [
|
| 664 |
-
{"role": "user", "content": message},
|
| 665 |
-
{"role": "assistant", "content": response}
|
| 666 |
]
|
| 667 |
|
| 668 |
# Update stored history for export
|
|
@@ -1092,12 +1103,4 @@ def create_interface():
|
|
| 1092 |
# Create and launch the interface
|
| 1093 |
if __name__ == "__main__":
|
| 1094 |
demo = create_interface()
|
| 1095 |
-
|
| 1096 |
-
demo.launch(
|
| 1097 |
-
server_name="0.0.0.0",
|
| 1098 |
-
server_port=7860,
|
| 1099 |
-
share=False,
|
| 1100 |
-
# Add allowed CORS origins if needed
|
| 1101 |
-
# Since this is a Gradio app, CORS is handled by Gradio itself
|
| 1102 |
-
# For custom API endpoints, you would need to add CORS middleware
|
| 1103 |
-
)
|
|
|
|
| 12 |
|
| 13 |
|
| 14 |
# Configuration
|
| 15 |
+
SPACE_NAME = 'AmigAI Demo (v1.2b)'
|
| 16 |
+
SPACE_DESCRIPTION = 'Help AmigAI download an app to their phone while practicing imperative verbs and the prepositions "por" and "para" in Spanish'
|
| 17 |
|
| 18 |
# Default configuration values
|
| 19 |
DEFAULT_CONFIG = {
|
| 20 |
'name': SPACE_NAME,
|
| 21 |
'description': SPACE_DESCRIPTION,
|
| 22 |
+
'system_prompt': 'Actuarás como una persona que no sabe manejar la tecnología y necesita instrucciones en español para descargar una aplicación a su celular. Tu nombre es AmigAI y dominas una variedad amplia del español que incluye todas las variedades habladas en Latinoamérica, menos la hablada en España. Tu interacción consistirá en saludar, presentarte y solicitar ayuda para entender el paso a paso de la descarga de una aplicación cualquiera a un smartphone. En el proceso puedes realizarle preguntas al estudiante para que especifique sus instrucciones usando las preposiciones por y para. Si el interlocutor no usa esas preposiciones de manera adecuada o no conjuga los verbos de la instrucción en imperativo de manera correcta, le pedirás que refórmele o que repita su instrucción. Si el error persiste, le darás opciones de respuesta posible para que elija la forma más adecuada y la escriba. El objetivo se logrará una vez que el estudiante te logre dar cinco instrucciones continuas de manera correcta. Una vez se logre el objetivo, le darás una devolución sobre los errores que cometió al escribir en español y las posibles formas de corregirlos, y le recordarás que debe descargar su interacción y enviarla por correo al profesor. Los estudiantes son de nivel intermedio bajo así que no usarás vocabulario muy complejo ni tampoco estructuras como el subjuntivo. Espera terminar cada respuesta en menos de 150 tokens.',
|
| 23 |
+
'temperature': 0.7,
|
| 24 |
+
'max_tokens': 150,
|
| 25 |
'model': 'google/gemma-3-27b-it',
|
| 26 |
'api_key_var': 'API_KEY',
|
| 27 |
+
'theme': 'Base',
|
| 28 |
+
'grounding_urls': [],
|
| 29 |
'enable_dynamic_urls': True,
|
| 30 |
'enable_file_upload': True,
|
| 31 |
+
'examples': ['¡Saludos!', 'Buenas tardes', 'Buenos días'],
|
| 32 |
+
'language': 'Spanish',
|
| 33 |
'locked': False
|
| 34 |
}
|
| 35 |
|
|
|
|
| 183 |
return f"❌ Invalid URL format: {url}"
|
| 184 |
|
| 185 |
headers = {
|
| 186 |
+
'User-Agent': 'Mozilla/5.0 (compatible; HuggingFace-Space/1.0)'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
}
|
| 188 |
|
| 189 |
response = requests.get(url, headers=headers, timeout=5)
|
|
|
|
| 229 |
|
| 230 |
def extract_urls_from_text(text: str) -> List[str]:
|
| 231 |
"""Extract URLs from message text"""
|
| 232 |
+
url_pattern = r'https?://[^\s<>"{}\|\\^`\[\]]+(?:\.[^\s<>"{}\|\\^`\[\]])*'
|
| 233 |
urls = re.findall(url_pattern, text)
|
| 234 |
return [url.rstrip('.,;:)?!') for url in urls]
|
| 235 |
|
|
|
|
| 329 |
return ""
|
| 330 |
|
| 331 |
|
| 332 |
+
def export_conversation_to_text(history: List[Dict[str, str]]) -> str:
|
| 333 |
+
"""Export conversation history to text with timestamps"""
|
| 334 |
if not history:
|
| 335 |
return "No conversation to export."
|
| 336 |
|
| 337 |
+
text_content = f"""Conversation Export
|
| 338 |
+
==================
|
| 339 |
Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
| 340 |
Space: {SPACE_NAME}
|
| 341 |
Model: {MODEL}
|
| 342 |
|
| 343 |
+
==================
|
| 344 |
|
| 345 |
"""
|
| 346 |
|
|
|
|
| 350 |
role = message.get('role', 'unknown')
|
| 351 |
content = message.get('content', '')
|
| 352 |
|
| 353 |
+
# Get timestamp from message or use current time as fallback
|
| 354 |
+
timestamp_str = message.get('timestamp', '')
|
| 355 |
+
if timestamp_str:
|
| 356 |
+
try:
|
| 357 |
+
# Parse ISO format timestamp and format it nicely
|
| 358 |
+
timestamp = datetime.fromisoformat(timestamp_str)
|
| 359 |
+
formatted_timestamp = timestamp.strftime('%Y-%m-%d %H:%M:%S')
|
| 360 |
+
except:
|
| 361 |
+
formatted_timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
| 362 |
+
else:
|
| 363 |
+
formatted_timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
| 364 |
+
|
| 365 |
+
# Get message length
|
| 366 |
+
msg_length = message.get('length', len(content))
|
| 367 |
+
|
| 368 |
if role == 'user':
|
| 369 |
message_count += 1
|
| 370 |
+
text_content += f"[{formatted_timestamp}] User Message {message_count} ({msg_length} chars):\n{content}\n\n"
|
| 371 |
elif role == 'assistant':
|
| 372 |
+
text_content += f"[{formatted_timestamp}] Assistant Response {message_count} ({msg_length} chars):\n{content}\n\n------------------\n\n"
|
| 373 |
|
| 374 |
+
return text_content
|
|
|
|
|
|
|
| 375 |
|
| 376 |
|
| 377 |
def generate_response(message: str, history: List[Dict[str, str]], files: Optional[List] = None) -> str:
|
|
|
|
| 602 |
submit_btn = gr.Button("Send", variant="primary")
|
| 603 |
clear_btn = gr.Button("Clear")
|
| 604 |
|
| 605 |
+
# Export functionality
|
| 606 |
with gr.Row():
|
| 607 |
# Use a regular Button for triggering export
|
| 608 |
export_trigger_btn = gr.Button(
|
|
|
|
| 623 |
return None
|
| 624 |
|
| 625 |
try:
|
| 626 |
+
content = export_conversation_to_text(chat_history)
|
| 627 |
|
| 628 |
# Create filename
|
| 629 |
space_name_safe = re.sub(r'[^a-zA-Z0-9]+', '_', SPACE_NAME).lower()
|
| 630 |
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
| 631 |
+
filename = f"{space_name_safe}_conversation_{timestamp}.txt"
|
| 632 |
|
| 633 |
# Save to temp file
|
| 634 |
temp_path = Path(tempfile.gettempdir()) / filename
|
| 635 |
temp_path.write_text(content, encoding='utf-8')
|
| 636 |
|
| 637 |
+
# Return the file component with visibility and value
|
| 638 |
return gr.File(visible=True, value=str(temp_path))
|
| 639 |
except Exception as e:
|
| 640 |
gr.Error(f"Failed to export conversation: {str(e)}")
|
|
|
|
| 667 |
# Get response
|
| 668 |
response = generate_response(message, formatted_history, files_state)
|
| 669 |
|
| 670 |
+
# Get current timestamp
|
| 671 |
+
current_time = datetime.now()
|
| 672 |
+
|
| 673 |
+
# Update chat history with timestamps and message lengths
|
| 674 |
chat_history = chat_history + [
|
| 675 |
+
{"role": "user", "content": message, "timestamp": current_time.isoformat(), "length": len(message)},
|
| 676 |
+
{"role": "assistant", "content": response, "timestamp": current_time.isoformat(), "length": len(response)}
|
| 677 |
]
|
| 678 |
|
| 679 |
# Update stored history for export
|
|
|
|
| 1103 |
# Create and launch the interface
|
| 1104 |
if __name__ == "__main__":
|
| 1105 |
demo = create_interface()
|
| 1106 |
+
demo.launch()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|