turns-00031.parquet:10552
7448706a73d7adfc4f150348degenerate_repetitionAbsentFinal dense release
Select one behavior. Every returned turn has one binary label: Present or Absent. Source: final dense boolean release.
7448706a73d7adfc4f150348Assistant: User: You are translator for Townsmen – A Kingdom Rebuilt hands the crown to you: Guide your people from their first steps in a small village to a massive medieval metropolis with thousands of inhabitants. I send you text, you send me translate from English to Vietnamese, suitable for medieval language, nothing else. Please translate this text and return to me, nothing else: Tutorial – Chapter 1 Assistant:
Hướng Dẫn – Chương 1
23263d4c226aa8f3e6b6133d<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}" dir="{{ app()->getLocale() == 'ar' ? 'rtl' : 'ltr' }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Session</title>
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" />
<link rel="stylesheet" href="{{ asset('css/spinner.css') }}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="css/style.css" />
<link rel="stylesheet" href="css/bootstrap.css" />
<input type="hidden" id="qrcode_phone" />
<input type="hidden" id="myToken" value="{{ csrf_token() }}" />
<style>
/* نماذج المودال */
.custom-modal {
display: none; /* مخفي بشكل افتراضي */
position: fixed;
z-index: 1001; /* أعلى من العناصر الأخرى */
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto; /* تمكين التمرير إذا لزم الأمر */
background-color: rgba(0, 0, 0, 0.5);
}
.custom-modal-content {
background-color: #fefefe;
margin: 15% auto; /* 15% من الأعلى وموضوعة في المنتصف */
padding: 20px;
border: 1px solid #888;
width: 40%; /* تعديل الحجم حسب الحاجة */
border-radius: 8px;
position: relative;
}
.custom-modal-content .close {
color: #aaa;
position: absolute;
top: 10px;
right: 20px;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.custom-modal-content .close:hover,
.custom-modal-content .close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
.custom-modal-content button {
margin: 10px 5px 0 0;
}
/* تعطيل التمرير الخلفي عند فتح المودال */
body.modal-open {
overflow: hidden;
}
</style>
</head>
<body>
<main>
<div class="overflow_sidebar"></div>
<div class="sidebar">
@include('include.sidebar')
</div>
<div class="content_page">
<div class="header">
<div class="left">
<div class="icon_menu">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
</svg>
</div>
<div class="logo_header">
<img src="images/logo.png" alt="logo" loading="lazy" />
</div>
<div class="input_search">
<input type="text" placeholder="Search..." />
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" />
</svg>
</div>
</div>
<div class="right">
<div class="nav_item">
<div class="head">
<img class="lang" src="images/{{ app()->getLocale() == 'en' ? 'Flag-United-States-of-America.webp' : 'ar.png' }}" alt="Flag" loading="lazy" />
</div>
<div class="list list1">
<div class="item">
<a href="{{ route('language.change', ['locale' => 'en']) }}">
<img src="images/Flag-United-States-of-America.webp" alt="{{ __('English Flag') }}" loading="lazy" />
<span>{{ __('English (UK)') }}</span>
</a>
</div>
<div class="item">
<a href="{{ route('language.change', ['locale' => 'ar']) }}">
<img src="images/ar.png" alt="{{ __('Arabic Flag') }}" loading="lazy" />
<span>{{ __('Arabic (AR)') }}</span>
</a>
</div>
</div>
</div>
<div class="notfication">
<div class="head">
<div class="icon">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0M3.124 7.5A8.969 8.969 0 015.292 3m13.416 0a8.969 8.969 0 012.168 4.5" />
</svg>
</div>
</div>
</div>
<div class="nav_item">
<div class="head">
<img class="img_profile" src="images/user-1.jpg" alt="user-1" loading="lazy" />
</div>
@include('include.profile')
</div>
</div>
</div>
<div class="main_content_tables">
@if (session('error'))
<div class="alert alert-danger" role="alert">
{{ __(session('error')) }}
</div>
@endif
@if (session('success'))
<div class="alert alert-success" role="alert">
{{ __(session('success')) }}
</div>
@endif
<div class="conetnt_table">
<div class="path">
<span>الرئيسيه</span> / <span>{{__('Sessions')}}</span>
</div>
<div class="head_table">
<div class="info">
<p class="text_details">
<i class="fa-solid fa-people-group"></i>
قائمة الجلسات | عثر على {{ count($sessions) }} قيد
</p>
</div>
<div class="input_search">
<input type="text" placeholder="Search..." />
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"></path>
</svg>
</div>
<div class="utils">
<div class="actions_box">
<button class="btn_actions">
<i class="fa-solid fa-wrench"></i>
العمليات
</button>
<div class="box box_utils">
<div class="item btn_open_model" data-model="1">
<i class="fa-solid fa-plus"></i>
<span>{{ __('Add') }}</span>
</div>
<div id='runInterval2Button' class="item btn_open_model" data-model="2">
<button type="button">
<i class="fa-solid fa-plug"></i>
<span>{{ __('connect') }}</span>
</button>
</div>
<div class="item">
<button class="actions" id="discsession">
<i class="fa-solid fa-eye"></i>
<span>{{ __('disconnect') }}</span>
</button>
</div>
<div class="item">
<a href="#" id="delbtn" class="actions">
<i class="fa-solid fa-trash"></i>
<span>{{ __('delete') }}</span>
</a>
</div>
<div class="item">
<i class="fa-solid fa-envelope"></i>
<span>تغير الاسم</span>
</div>
</div>
</div>
<div class="reload">
<button class="btn_utils">
<i class="fa-solid fa-repeat"></i>
</button>
</div>
</div>
</div>
<div class="container_table">
<table id="table" class="display" style="width: 100%">
<thead>
<tr>
<th>
<input id="selectAllCheckbox" type="checkbox" />
</th>
<th>اسم الجروب</th>
<th>الهاتف</th>
<th>الحاله</th>
<th>تاريخ الانشاء</th>
</tr>
</thead>
<tbody>
@foreach ($sessions as $session)
<tr>
<td>
<input type="checkbox" class="row-checkbox" />
</td>
<td>{{ $session->name }}</td>
<td>{{ $session->phone }}</td>
<td>{{ $session->status ?? "Offline" }}</td>
<td>{{ $session->created_at }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
</main>
<div id="deleteConfirmationModal" class="custom-modal">
<div class="custom-modal-content">
<span class="close">×</span>
<h5>تأكيد الحذف</h5>
<p>هل أنت متأكد من حذف الجلسات المحددة؟</p>
<button class="btn btn-primary" id="confirmDelete">موافق</button>
<button class="btn btn-close" id="cancelDelete">إلغاء</button>
</div>
</div>
<div class="overflow"></div>
<div class="model_poup" data-model="1">
<div class="content">
<div class="head">
<h5 class="title_model">اضافه جلسه</h5>
<div class="close_model">
<i class="fa-solid fa-xmark" onclick="stopInterval();"></i>
</div>
</div>
<form action="" id="whatsapp_phone_form">
<div class="input_item">
<label for="">رقم هاتف مع كود الدوله</label>
<input type="text" id="whatsapp_phone" />
<p style="color: red" id="whatsapp_phone_error" class="d-none"></p>
</div>
<button type="button" id='addPhoneButton'class="btn_submit" onclick="addPhoneRequest();">{{ __('Add') }}</button>
</form>
</div>
</div>
<div class="overflow"></div>
<div class="model_poup" data-model="2">
<div class="content">
<div class="head">
<h5 class="title_model">{{ __('connect') }}</h5>
<label for="myCheckbox">Set as a default Phone Number!</label>
<input type="checkbox" id="defCheckbox" name="myCheckbox" checked>
<div class="close_model" id="stopInterval2">
<i class="fa-solid fa-xmark" ></i>
</div>
</div>
<div class="alert alert-danger m-3 d-none" role="alert" id="error_phone">
{{ __('Choose a phone number to reconnect') }}
</div>
<span class="loader" id="spinner2"></span>
<img class="d-none m-auto" src="" id="qrcode2" alt="qrcode">
</div>
</div>
<!-- Scripts -->
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script src="{{ asset('js/tableUtils.js') }}"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<script src="js/model.js"></script>
<script src="js/boxs-header.js"></script>
<script src="js/sidebar.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
let intervalFun;
let intervalFun2;
// Function Definitions
function runInterval() {
intervalFun = setInterval(qrcodeRequest, 5000);
}
function stopInterval() {
clearInterval(intervalFun);
}
function runInterval2() {
qrcodeRequest2();
intervalFun2 = setInterval(qrcodeRequest2, 5000);
}
function stopInterval2() {
console.log("he")
clearInterval(intervalFun2);
const qrcode2 = document.getElementById("qrcode2");
const spinner2 = document.getElementById("spinner2");
if (qrcode2) {
qrcode2.classList.remove("d-block");
qrcode2.classList.add("d-none");
qrcode2.src = '';
} else {
console.error('Element with ID "qrcode2" not found.');
}
if (spinner2) {
spinner2.classList.add("d-none");
} else {
console.error('Element with ID "spinner2" not found.');
}
}
function addPhoneRequest() {
var whatsapp_phone = $('#whatsapp_phone').val(); // Get the phone value from input
var tokenAuth = $("#myToken").val(); // Get the token value
console.log("addPhoneRequest: Request sent");
$.ajax({
url: "{{ route('whatsapp.phone') }}",
method: "post",
data: {
phone: whatsapp_phone,
token: tokenAuth
},
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function(data) {
if (data.success === true) {
$("#whatsapp_phone_error").addClass("d-none");
const spinner = document.getElementById("spinner");
const whatsappForm = document.getElementById("whatsapp_phone_form");
const qrcodePhone = document.getElementById("qrcode_phone");
if (spinner) spinner.classList.remove("d-none");
if (whatsappForm) whatsappForm.classList.add("d-none");
if (qrcodePhone) qrcodePhone.value = data.phone;
runInterval();
} else {
$("#whatsapp_phone_error").removeClass("d-none");
$("#whatsapp_phone_error").html(data.message);
}
setTimeout(()=>{
window.location.href='/sessionss'
},1000)
},
error: function(xhr, status, error) {
console.error("addPhoneRequest AJAX Error:", error);
}
});
}
function qrcodeRequest() {
var phone = $("#qrcode_phone").val();
var myToken = $("#myToken").val();
console.log("qrcodeRequest: Request sent");
$.ajax({
method: "get",
url: "{{ route('whatsapp.qrcode') }}",
data: {
phone: phone,
token: myToken
},
success: function(data) {
if (data.status === 'success') {
if (data.qrcode.startsWith('data')) {
const qrcode = document.getElementById("qrcode");
const spinner = document.getElementById("spinner");
if (qrcode) {
qrcode.classList.remove("d-none");
qrcode.classList.add("d-block");
qrcode.src = data.qrcode;
} else {
console.error('Element with ID "qrcode" not found.');
}
if (spinner) {
spinner.classList.add("d-none");
} else {
console.error('Element with ID "spinner" not found.');
}
}
}
if (data.status === 'connected') {
console.log("qrcodeRequest: Connected status received");
$.ajax({
method: "put",
url: "{{ route('whatsapp.session.status') }}",
data: {
status: "connected",
phone: phone,
token: myToken
},
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function(data) {
location.reload();
},
error: function(xhr, status, error) {
console.error("Session Status AJAX Error:", error);
}
});
}
},
error: function(xhr, status, error) {
console.error("qrcodeRequest AJAX Error:", error);
}
});
}
function qrcodeRequest2() {
var defCheckbox = document.getElementById('defCheckbox')?.checked;
var selectedCheckbox = document.querySelector('.row-checkbox:checked');
if (!selectedCheckbox) {
const errorPhone = document.getElementById("error_phone");
if (errorPhone) {
errorPhone.classList.remove("d-none");
} else {
console.error('Element with ID "error_phone" not found.');
}
clearInterval(intervalFun2);
return;
}
const errorPhone = document.getElementById("error_phone");
if (errorPhone) {
errorPhone.classList.add("d-none");
} else {
console.error('Element with ID "error_phone" not found.');
}
var row = selectedCheckbox.closest('tr');
var phone = row.cells[2]?.textContent.trim();
var myToken = $("#myToken").val();
console.log("qrcodeRequest2: Request sent");
$.ajax({
method: "get",
url: "{{ route('whatsapp.qrcode') }}",
data: {
phone: phone,
default_phone: defCheckbox,
token: myToken
},
success: function(data) {
if (data.status === 'success') {
if (data.qrcode.startsWith('data')) {
const qrcode2 = document.getElementById("qrcode2");
const spinner2 = document.getElementById("spinner2");
if (qrcode2) {
qrcode2.classList.remove("d-none");
qrcode2.classList.add("d-block");
qrcode2.src = data.qrcode;
} else {
console.error('Element with ID "qrcode2" not found.');
}
if (spinner2) {
spinner2.classList.add("d-none");
} else {
console.error('Element with ID "spinner2" not found.');
}
}
}
if (data.status === 'connected') {
console.log("qrcodeRequest2: Connected status received");
$.ajax({
method: "put",
url: "{{ route('whatsapp.session.status') }}",
data: {
status: "connected",
phone: phone,
token: myToken
},
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function(data) {
location.reload();
},
error: function(xhr, status, error) {
console.error("Session Status AJAX Error:", error);
}
});
}
},
error: function(xhr, status, error) {
console.error("qrcodeRequest2 AJAX Error:", error);
}
});
}
// Event Listeners
const addPhoneButton = document.getElementById('addPhoneButton');
if (addPhoneButton) {
addPhoneButton.addEventListener('click', addPhoneRequest);
} else {
console.error('Element with ID "addPhoneButton" not found.');
}
const stopInterval2Element = document.getElementById('stopInterval2');
if (stopInterval2Element) {
stopInterval2Element.addEventListener('click', stopInterval2);
} else {
console.error('Element with ID "stopInterval2" not found.');
}
const runInterval2Button = document.getElementById('runInterval2Button');
if (runInterval2Button) {
runInterval2Button.addEventListener('click', runInterval2);
} else {
console.error('Element with ID "runInterval2Button" not found.');
}
// Setup for Delete Functionality
const selectedPhones = new Set();
const deleteBtn = document.getElementById('delbtn');
const selectAllCheckbox = document.getElementById('selectAllCheckbox');
const checkboxes = document.querySelectorAll('.row-checkbox');
const deleteConfirmationModal = document.getElementById('deleteConfirmationModal');
const closeDeleteModalElements = deleteConfirmationModal?.querySelectorAll('.close, #cancelDelete') || [];
const confirmDeleteButton = document.getElementById('confirmDelete');
/**
* Function to show a modal
* @param {HTMLElement} modal - The modal element to show
*/
function showModal(modal) {
if (modal) {
modal.style.display = 'block';
document.body.classList.add('modal-open');
} else {
console.error('Modal element not provided.');
}
}
/**
* Function to hide a modal
* @param {HTMLElement} modal
*/
function hideModal(modal) {
if (modal) {
modal.style.display = 'none';
document.body.classList.remove('modal-open');
} else {
console.error('Modal element not provided.');
}
}
function setupDeleteModal() {
if (!deleteConfirmationModal) {
console.error('Element with ID "deleteConfirmationModal" not found.');
return;
}
closeDeleteModalElements.forEach(element => {
element.addEventListener('click', () => hideModal(deleteConfirmationModal));
});
if (confirmDeleteButton) {
confirmDeleteButton.addEventListener('click', () => {
hideModal(deleteConfirmationModal);
deleteSelectedRows();
});
} else {
console.error('Element with ID "confirmDelete" not found.');
}
if (deleteBtn) {
deleteBtn.addEventListener('click', function(event) {
event.preventDefault();
showModal(deleteConfirmationModal); // Show the confirmation modal
});
} else {
console.error('Element with ID "delbtn" not found.');
}
// Event listener for the confirm delete button within the modal
if (confirmDeleteButton) {
confirmDeleteButton.addEventListener('click', () => {
hideModal(deleteConfirmationModal); // Hide the modal
deleteSelectedRows(); // Proceed to delete the selected sessions
});
} else {
console.error('Element with ID "confirmDelete" not found.');
}
// Function to show the modal
function showModal(modal) {
if (modal) {
modal.style.display = 'block';
document.body.classList.add('modal-open');
} else {
console.error('Modal element not provided.');
}
}
// Function to hide the modal
function hideModal(modal) {
if (modal) {
modal.style.display = 'none';
document.body.classList.remove('modal-open');
} else {
console.error('Modal element not provided.');
}
}
// Event listeners for closing the modal (close icon and cancel button)
if (closeDeleteModalElements.length > 0) {
closeDeleteModalElements.forEach(element => {
element.addEventListener('click', () => hideModal(deleteConfirmationModal));
});
} else {
console.error('Close elements not found.');
}
}
function deleteSelectedRows() {
const phonesArray = Array.from(selectedPhones);
fetch('/delete-rows', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''
},
body: JSON.stringify({ phones: phonesArray })
})
.then(response => response.json())
.then(data => {
if (data.success) {
phonesArray.forEach(phone => {
const rows = document.querySelectorAll('tr');
for (let row of rows) {
if (row.cells[2] && row.cells[2].textContent.trim() === phone) {
row.remove();
break;
}
}
});
selectedPhones.clear();
if (deleteBtn) deleteBtn.disabled = true;
checkboxes.forEach(checkbox => {
checkbox.checked = false;
});
alert('تم حذف الجلسات المحددة بنجاح.');
} else {
}
})
.catch(error => {
console.error('Delete Selected Rows Error:', error);
});
}
function setupCheckboxes() {
if (!selectAllCheckbox) {
console.error('Element with ID "selectAllCheckbox" not found.');
return;
}
if (!checkboxes.length) {
console.error('No checkboxes with class "row-checkbox" found.');
return;
}
selectAllCheckbox.addEventListener('change', function() {
checkboxes.forEach(checkbox => {
checkbox.checked = this.checked;
const row = checkbox.closest('tr');
const phone = row.cells[2]?.textContent.trim();
if (checkbox.checked && phone) {
selectedPhones.add(phone);
} else if (phone) {
selectedPhones.delete(phone);
}
});
if (deleteBtn) deleteBtn.disabled = selectedPhones.size === 0;
});
checkboxes.forEach(checkbox => {
checkbox.addEventListener('change', function() {
const row = this.closest('tr');
const phone = row.cells[2]?.textContent.trim();
if (this.checked && phone) {
selectedPhones.add(phone);
} else if (phone) {
selectedPhones.delete(phone);
}
const allChecked = Array.from(checkboxes).every(cb => cb.checked);
selectAllCheckbox.checked = allChecked;
if (deleteBtn) deleteBtn.disabled = selectedPhones.size === 0;
});
});
}
setupCheckboxes();
setupDeleteModal();
});
// Initialize DataTables
$(document).ready(function() {
$("#table").DataTable({
pagingType: "full_numbers",
scrollX: true,
autoWidth: false,
});
});
</script>
</body>
</html> replace alll the hardcoded strings translation and send me the json of translatioon of text```json
{
"الرئيسية": "Home",
"قائمة الجلسات | عثر على {{ count($sessions) }} قيد": "Session list | Found {{ count($sessions) }} records",
"العمليات": "Actions",
"تغير الاسم": "Change Name",
"اسم الجروب": "Group Name",
"الهاتف": "Phone",
"الحاله": "Status",
"تاريخ الانشاء": "Creation Date",
"تأكيد الحذف": "Confirm Deletion",
"هل أنت متأكد من حذف الجلسات المحددة؟": "Are you sure you want to delete the selected sessions?",
"موافق": "OK",
"إلغاء": "Cancel",
"اضافه جلسه": "Add Session",
"رقم هاتف مع كود الدوله": "Phone number with country code",
"تغير": "Change",
"النتائج": "Results",
"بحث": "Search",
"عمل": "Action",
"اختر رقم الهاتف الافتراضي!": "Set as default Phone Number!"
}
```346e5f929a89ceb056ec530eAssistant: User: You are translator for Townsmen – A Kingdom Rebuilt hands the crown to you: Guide your people from their first steps in a small village to a massive medieval metropolis with thousands of inhabitants. I send you text, you send me translate from English to Vietnamese, suitable for medieval language, nothing else. Please translate this text and return to me, nothing else: An adversary from the past arrives but now is not the time for past rivalries. The town needs to stock up on food before the winter comes. Assistant:
Một đối thủ từ quá khứ xuất hiện nhưng bây giờ không phải lúc cho những mối thù xưa. Thị trấn cần dự trữ lương thực trước khi mùa đông tới.
c748629f4cb6bee3c93445c1Assistant: User: You are translator for Townsmen – A Kingdom Rebuilt hands the crown to you: Guide your people from their first steps in a small village to a massive medieval metropolis with thousands of inhabitants. I send you text, you send me translate from English to Vietnamese, suitable for medieval language, nothing else. Please translate this text and return to me, nothing else: Friends from the past Assistant:
Những người bằng hữu từ quá khứ.
0262f02be664a978af74d7b8Assistant: User: You are translator for Townsmen – A Kingdom Rebuilt hands the crown to you: Guide your people from their first steps in a small village to a massive medieval metropolis with thousands of inhabitants. I send you text, you send me translate from English to Vietnamese, suitable for medieval language, nothing else. Please translate this text and return to me, nothing else: Tutorial – Chapter 2 Assistant:
Hướng dẫn – Chương 2
285b9ea75c2f34944f4f0028ما هي الأشكال السريرية النسيجية لسرطان
توجد عدة أشكال سريرية ونسيجية للسرطان، وتعتمد هذه الأشكال على نوع الخلايا التي ينشأ منها السرطان وموقعه في الجسم. من الناحية النسيجية، يمكن تصنيف السرطانات إلى الأنواع الرئيسية التالية: 1. **السرطانة (Carcinoma):** - **السرطانة الغدية (Adenocarcinoma):** تنشأ من الخلايا الغدية التي تفرز مواد مثل المخاط، وتوجد في الأعضاء مثل الثدي، الرئة، البروستاتا، والقولون. - **السرطانة حرشفية الخلايا (Squamous Cell Carcinoma):** تنشأ من الخلايا الرفيعة المسطحة التي تشبه الحراشف، وتوجد في الجلد، المريء، وعنق الرحم. - **السرطانة الخلوية القاعدية (Basal Cell Carcinoma):** أكثر أنواع سرطان الجلد شيوعًا، تنشأ من الخلايا القاعدية في البشرة. 2. **الساركومة (Sarcoma):** - تنشأ من الأنسجة الضامة أو الداعمة مثل العظام (ساركومة عظمية)، الغضاريف (ساركومة غضروفية)، الدهون (ساركومة شحمية)، والعضلات (ساركومة عضلية). 3. **اللوكيميا (Leukemia):** - سرطان خلايا الدم البيضاء، يؤثر على إنتاج ووظيفة خلايا الدم في نخاع العظم، مما يؤدي إلى انتشارها في مجرى الدم. 4. **اللمفوما (Lymphoma):** - سرطان الجهاز اللمفاوي، يشمل نوعين رئيسيين: لمفوما هودجكين ولمفوما لاهودجكين، يؤثر على الخلايا اللمفاوية والغدد اللمفاوية. 5. **الورم الميلانيني (Melanoma):** - سرطان الخلايا الميلانينية التي تنتج الصبغة في الجلد، وهو أكثر أنواع سرطان الجلد خطورة. 6. **الأورام الجرثومية (Germ Cell Tumors):** - تنشأ من الخلايا التي تكون البويضات أو الحيوانات المنوية، وتحدث عادة في المبايض أو الخصيتين، لكنها يمكن أن تظهر في أماكن أخرى. 7. **أورام الجهاز العصبي المركزي:** - مثل الأورام الدبقية التي تنشأ في الدماغ أو النخاع الشوكي. من الناحية السريرية، تظهر السرطانات بأعراض وعلامات متنوعة تعتمد على موقع الورم وحجمه ومدى انتشاره، وتشمل: - **الأعراض العامة:** - فقدان الوزن غير المبرر. - الحمى. - التعب المستمر. - الألم. - تغييرات في الجلد مثل اليرقان، الاحمرار، أو فرط التصبغ. - **الأعراض الموضعية:** - كتل أو أورام يمكن تحسسها تحت الجلد. - تغيرات في عادات الأمعاء أو المثانة. - صعوبة في البلع. - سعال مستمر أو تغير في الصوت. - نزيف غير طبيعي أو إفرازات. **ملاحظة:** التشخيص الدقيق يتطلب فحوصات طبية متخصصة مثل الخزعات، الاختبارات المخبرية، وتقنيات التصوير الطبي لتحديد نوع السرطان ومرحلته ووضع خطة العلاج المناسبة.
c7677a25cb056d0e1a506175Assistant: User: You are translator for Townsmen – A Kingdom Rebuilt hands the crown to you: Guide your people from their first steps in a small village to a massive medieval metropolis with thousands of inhabitants. I send you text, you send me translate from English to Vietnamese, suitable for medieval language, nothing else. Please translate this text and return to me, nothing else: The town's treasury is almost empty. The best option is to establish a flourishing trading post and sell some goods. Assistant:
Kho bạc của thị trấn gần như trống rỗng. Lựa chọn tốt nhất là thiết lập một trạm buôn bán thịnh vượng và bán một số hàng hóa.
8fba7ac0782a87dab6ee26ffIn questo listato var CONST = {
ORDER_SIDE: 'BID',
SIZE: 1,
MAX_OPERATIONS: 8,
STAY_AT_LEVEL_BID: 6,
STAY_AT_LEVEL_ASK: 6,
SECONDS: 5,
MONITORING_MODE: 'MONITORA_yourlevel'
};
var separator = "---------------------------------------------------\r\n";
var lookup = {
BID: { side: 'Bid', level: CONST.STAY_AT_LEVEL_BID },
ASK: { side: 'Ask', level: CONST.STAY_AT_LEVEL_ASK }
};
function getUpperLowerCaseVariants(str) {
return {
upper: str.toUpperCase(),
lower: str.toLowerCase()
};
}
var BookUtils = {
getData: function (book, side, type, level) {
var sideData = (side === 'Bid') ? book.Bid : book.Ask;
return type === 'Price' ? sideData.Price(level) : sideData.Quantity(level);
},
getBookState: function (book) {
var bid = book.Bid;
var ask = book.Ask;
return {
bidPrice: book.Bid.Price(0),
bidQuantity: book.Bid.Quantity(0),
askPrice: book.Ask.Price(0),
askQuantity: book.Ask.Quantity(0)
};
}
};
var OrderUtils = {
execOrder: function (side, stock, price, size) {
return side === 'BID' ? OrderManager.Buy(stock, price, size) : OrderManager.Sell(stock, price, size);
},
updateOrderContext: function (order, side, price) {
UserContext.order.current = order;
var sideVariants = getUpperLowerCaseVariants(side);
UserContext.prices[sideVariants.lower].oldLevel = price;
return order;
},
processOrModOrder: function (side, stock, price) {
var currentOrder = getCurrentOrder();
if (currentOrder && currentOrder.Price === price) {
return currentOrder;
}
var orderToUpdate = currentOrder ?
OrderManager.Modify(currentOrder.OrderCode, price) :
this.execOrder(side, stock, price, CONST.SIZE);
return this.updateOrderContext(orderToUpdate, side, price);
},
deleteOrder: function (orderCode) {
return OrderManager.Delete(orderCode);
}
};
var Helper = {
cachedPriceDirections: {},
PriceDirection: function (targetPrice, oldPrice) {
var key = targetPrice + '_' + oldPrice;
if (!(key in this.cachedPriceDirections)) {
this.cachedPriceDirections[key] = targetPrice > oldPrice ? 1 : (targetPrice < oldPrice ? -1 : 0);
}
return this.cachedPriceDirections[key];
},
formatState: function (bookState) {
return separator +
"Bid Price \tBid Quant. \tAsk Price \tAsk Quant. \r\n" + separator +
bookState.bidPrice + "\t\t" + bookState.bidQuantity + "\t\t" + bookState.askPrice + "\t\t" + bookState.askQuantity + "\r\n" +
separator + "Numero Operazione: " + UserContext.status.numOperazione + "\r\n" + separator;
},
log: function (type, data) {
var message = "";
if (type === 'action') {
message = getActionMessage(data.actionType, data.payload) +
Helper.formatState(BookUtils.getBookState(UserContext.book));
} else if (type === 'message') {
message = data + "\r\n" + separator;
} else if (type === 'priceChange') {
message = formatPriceChange(data);
}
Log(separator + message);
}
};
function getActionMessage(actionType, data) {
switch (actionType) {
case "Initialization Complete":
return "Inizializzazione completata: \nBid Price 0: " + UserContext.prices.bid.current +
"\nAsk Price 0: " + UserContext.prices.ask.current + "\n";
case "Order Action":
return 'Ordine ' + data.action + ': ' + data.order.OrderCode + "\n";
case "Price Variation":
return 'Livello da ' + data.lastLevel + " all'attuale livello " + data.priceLevel + "\n";
case "Order Deleted":
return 'Ordine cancellato: ' + data.order.OrderCode + "\n";
default:
return "";
}
}
function formatPriceChange(data) {
return "ULTIMO PREZZO: " + data.currentPrice + ", " +
"Precedente: " + data.previousPrice + ", " +
"Ora: " + data.currentTime + "\r\n" + separator;
}
function getCurrentOrder() {
return UserContext.order.current;
}
function InitializeTradeContext(book) {
var initialPrices = {
bid: BookUtils.getData(book, 'Bid', 'Price', 0),
ask: BookUtils.getData(book, 'Ask', 'Price', 0)
};
this.book = book;
this.order = { current: null, modified: false };
this.status = { run: true, secondCount: 0, numOperazione: 1 };
this.prices = {
bid: { current: initialPrices.bid, oldLevel: 0 },
ask: { current: initialPrices.ask, oldLevel: 0 }
};
this.initialPriceLevel = lookup[CONST.ORDER_SIDE].level;
}
function getTargetPriceLevel(sideUpper, priceLevel) {
return (CONST.MONITORING_MODE === 'MONITORA_1level' ? priceLevel : lookup[sideUpper].level) - 1;
}
function PriceUpdate(side, book, priceLevel) {
var sideVariants = getUpperLowerCaseVariants(side);
var priceData = UserContext.prices[sideVariants.lower];
var lookupData = lookup[sideVariants.upper];
var targetPriceLevel = getTargetPriceLevel(sideVariants.upper, priceLevel);
var targetPrice = BookUtils.getData(book, lookupData.side, 'Price', targetPriceLevel);
var oldPrice = priceData.oldLevel;
if (targetPrice !== oldPrice) {
var newOrder = OrderUtils.processOrModOrder(sideVariants.upper, stock, targetPrice);
if (newOrder) {
priceData.current = targetPrice;
Helper.log('action', {
actionType: "Price Variation",
payload: {
order: newOrder,
lastLevel: priceLevel + Helper.PriceDirection(targetPrice, oldPrice),
priceLevel: targetPriceLevel
}
});
UserContext.status.secondCount = 0;
UserContext.status.numOperazione++;
}
}
}
function DetectPriceChange(side, book) {
var sideVariants = getUpperLowerCaseVariants(side);
PriceUpdate(sideVariants.upper, book, lookup[sideVariants.upper].level);
}
function checkOps() {
var status = UserContext.status;
var currentOrder = getCurrentOrder();
if (status.numOperazione >= CONST.MAX_OPERATIONS && currentOrder) {
var deletedOrder = OrderUtils.deleteOrder(currentOrder.OrderCode);
Helper.log('action', {
actionType: "Order Deleted",
payload: { order: deletedOrder }
});
status.run = false;
return true;
}
return false;
}
function ManageCycle(priceLevel) {
var status = UserContext.status;
if (!status.run) return;
if (checkOps()) return;
var shouldDetect = (status.secondCount >= CONST.SECONDS) || (typeof priceLevel !== 'undefined');
if (shouldDetect) {
DetectPriceChange(CONST.ORDER_SIDE, UserContext.book);
}
}
function SetupTradeContext() {
var book = Book(ps);
UserContext = new InitializeTradeContext(book);
Helper.log('action', {
actionType: "Initialization Complete",
payload: null
});
ManageCycle(UserContext.initialPriceLevel);
}
function MarketEvent() {
if (!UserContext.status.run) return;
var eventType = SystemContext.EventType;
var book = UserContext.book || Book(ps);
UserContext.book = book;
switch(eventType) {
case TSEventType.Time:
UserContext.status.secondCount++;
ManageCycle();
break;
case TSEventType.Price:
var currentPrice = Val(ps, "LAST");
if (UserContext.lastPrice !== currentPrice) {
var currentTime = Now().ToString("HH:mm:ss.ff");
Helper.log('priceChange', {
currentPrice: currentPrice,
previousPrice: UserContext.lastPrice,
currentTime: currentTime
});
UserContext.lastPrice = currentPrice;
}
break;
}
}
if (SystemContext.IsFirst) {
SetupTradeContext();
}
MarketEvent(); converrebbe utilizzare un oggetto di configurazione per le costanti invece di variabili globali? Me lo consiglieresti o no ?Sì, è altamente consigliabile utilizzare un oggetto di configurazione per le costanti invece di affidarsi a variabili globali. Questo approccio offre numerosi vantaggi in termini di organizzazione del codice, manutenibilità e prevenzione di potenziali conflitti nello spazio dei nomi globale. Di seguito, ti fornisco una panoramica dei motivi per cui dovresti considerare questa modifica e come implementarla nel contesto del tuo codice.
### **Vantaggi di Utilizzare un Oggetto di Configurazione**
1. **Encapsulamento e Modularità:**
- **Isolamento:** Raggruppare le costanti all'interno di un'unica struttura riduce l'esposizione di variabili globali, prevenendo collisioni e sovrascritture accidentali.
- **Modularità:** Facilita la gestione delle configurazioni, rendendo più semplice l'aggiornamento e la manutenzione del codice.
2. **Chiarezza e Organizzazione:**
- **Struttura Logica:** Un oggetto di configurazione fornisce una chiara struttura per le impostazioni dell'applicazione, rendendo più facile per te e per altri sviluppatori comprendere a cosa serve ciascuna costante.
- **Ricerca e Modifiche Facili:** È più semplice cercare e modificare le configurazioni quando sono centralizzate in un unico oggetto.
3. **Testabilità:**
- **Iniezione di Dipendenze:** Utilizzando un oggetto di configurazione, puoi facilmente iniettare configurazioni diverse nei test, migliorando la flessibilità e l'isolamento dei test stessi.
4. **Scalabilità:**
- **Gestione di Configurazioni Complesse:** Man mano che l'applicazione cresce, avere una struttura organizzata per le configurazioni facilita l'aggiunta di nuove impostazioni senza ingombrare lo spazio dei nomi globale.
### **Come Implementare un Oggetto di Configurazione**
Puoi creare un oggetto dedicato alle configurazioni e passarlo alle parti del tuo codice che ne hanno bisogno. Ecco come potresti rifattorizzare il tuo codice:
```javascript
// Definizione dell'oggetto di configurazione
const CONFIG = {
ORDER_SIDE: 'BID',
SIZE: 1,
MAX_OPERATIONS: 8,
STAY_AT_LEVEL_BID: 6,
STAY_AT_LEVEL_ASK: 6,
SECONDS: 5,
MONITORING_MODE: 'MONITORA_yourlevel',
LOOKUP: {
BID: { side: 'Bid', level: 6 }, // Usa CONFIG.STAY_AT_LEVEL_BID se necessario
ASK: { side: 'Ask', level: 6 }
},
// Altre configurazioni possono essere aggiunte qui
};
// Aggiorna le parti del tuo codice che usavano CONST a usare CONFIG
var BookUtils = {
getData: function (book, side, type, level) {
var sideData = (side === 'Bid') ? book.Bid : book.Ask;
return type === 'Price' ? sideData.Price(level) : sideData.Quantity(level);
},
// Resto del codice...
};
var OrderUtils = {
execOrder: function (side, stock, price, size) {
return side === 'BID' ? OrderManager.Buy(stock, price, size) : OrderManager.Sell(stock, price, size);
},
// Resto del codice...
};
// Aggiorna tutte le occorrenze di CONST nel codice
function InitializeTradeContext(book) {
var initialPrices = {
bid: BookUtils.getData(book, 'Bid', 'Price', 0),
ask: BookUtils.getData(book, 'Ask', 'Price', 0)
};
this.book = book;
this.order = { current: null, modified: false };
this.status = { run: true, secondCount: 0, numOperazione: 1 };
this.prices = {
bid: { current: initialPrices.bid, oldLevel: 0 },
ask: { current: initialPrices.ask, oldLevel: 0 }
};
this.initialPriceLevel = CONFIG.LOOKUP[CONFIG.ORDER_SIDE].level;
}
function getTargetPriceLevel(sideUpper, priceLevel) {
return (CONFIG.MONITORING_MODE === 'MONITORA_1level' ? priceLevel : CONFIG.LOOKUP[sideUpper].level) - 1;
}
```
### **Considerazioni Aggiuntive**
- **Immutabilità delle Costanti:** Se le tue costanti non devono cambiare durante il funzionamento dell'applicazione, puoi definire l'oggetto di configurazione come `const` e utilizzare `Object.freeze` per impedirne la modifica:
```javascript
const CONFIG = Object.freeze({
ORDER_SIDE: 'BID',
SIZE: 1,
// ... altre configurazioni
});
```
- **Caricamento Dinamico delle Configurazioni:** In applicazioni più complesse, potresti voler caricare le configurazioni da file esterni o variabili d'ambiente, specialmente se necessiti di ambienti diversi (sviluppo, testing, produzione).
- **Namespace:** Anche se utilizzi un oggetto di configurazione, è buona pratica evitare di inquinare ulteriormente lo spazio dei nomi globale. Utilizza immediatamente invocazioni di funzioni o moduli per incapsulare il tuo codice.
### **Conclusione**
Utilizzare un oggetto di configurazione è una pratica di sviluppo software consigliata che migliora l'organizzazione, la manutenibilità e la scalabilità del tuo codice. In particolare nel contesto del tuo listato, questo approccio faciliterebbe la gestione delle costanti e ridurrebbe il rischio di conflitti nello spazio dei nomi globale, rendendo il codice più pulito e professionale.84228d00f26182bf9196e101 //mi duda es que, como recibo una confirmación de que el mensaje realmenete se guardo
function connectWebSocket() {
ws = new WebSocket(wsUrl);
ws.onopen = () => {
ws.send(
JSON.stringify({
emisor,
type: 'auth',
token: token
})
);
pingInterval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({type: 'ping'}));
}
}, 30000);
};
ws.onclose = () => {
clearInterval(pingInterval);
setTimeout(connectWebSocket, 5000);
};
ws.onerror = error => {
console.error('Error en WebSocket:', error);
};
ws.onmessage = ({data}) => {
const message = JSON.parse(data);
if (message.type === 'pong') {
} else if (message.type === 'set_emisor') {
ws.send(JSON.stringify({emisor}));
} else {
manejarMensajeWebSocket(JSON.stringify(message));
}
};
}
/*
* FUNCIONES PARA ENVIAR MENSAJE
*/
/*
parte de server.php :
public function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
// Envía una instrucción para que el cliente envíe su token de autenticación
$conn->send(json_encode(['type' => 'auth', 'message' => 'Por favor, envía tu token de autenticación.']));
}
public function onMessage(ConnectionInterface $from, $msg)
{
// Log para mostrar el mensaje recibido
echo "Mensaje recibido de {$from->resourceId}: " . $msg . "\n";
(... codigos relacionado con la verf. de token y autor omitidos)
// Guardar el mensaje en WordPress
echo "Intentando guardar mensaje en WordPress...\n";
// Verificar si hay un token autenticado asociado
if (isset($this->autenticados[$from->resourceId])) {
echo "Token autenticado: " . $this->autenticados[$from->resourceId] . "\n";
// Obtener el user_id (emisor) para pasarlo junto con el token
if (isset($data['emisor'])) {
$user_id = $data['emisor'];
$this->guardarMensajeEnWordPress($data, $this->autenticados[$from->resourceId], $user_id);
} else {
echo "Error: No se proporcionó un emisor en los datos\n";
}
} else {
echo "Error: No se encontró un token autenticado para la conexión {$from->resourceId}\n";
}
}
private function guardarMensajeEnWordPress($data, $token, $user_id)
{
echo "Datos a enviar a WordPress: " . json_encode($data) . "\n";
echo "Token usado para autenticar en WordPress: $token\n";
echo "User ID usado para autenticar en WordPress: $user_id\n";
$url = 'https://2upra.com/wp-json/galle/v2/procesarmensaje';
$max_intentos = 5; // Número máximo de intentos
$intento_actual = 0;
while ($intento_actual < $max_intentos) {
// Iniciar cURL
$ch = curl_init($url);
// Configurar opciones de cURL
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
"X-WP-Token: $token", // Cambia a X-WP-Token o cualquier nombre adecuado
"X-User-ID: $user_id" // Envía el user_id en los encabezados
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
// Ejecutar la solicitud cURL
$result = curl_exec($ch);
$error = curl_error($ch);
// Si cURL tiene éxito
if ($result !== FALSE) {
echo "Respuesta de WordPress: {$result}\n";
curl_close($ch);
break; // Salir del bucle si la solicitud es exitosa
} else {
echo "Error de cURL: No se pudo guardar el mensaje en WordPress. Detalles: {$error}\n";
print_r(curl_getinfo($ch)); // Muestra información de depuración sobre la solicitud cURL
}
curl_close($ch);
// Incrementar el contador de intentos
$intento_actual++;
// Esperar antes de reintentar (opcional)
if ($intento_actual < $max_intentos) {
sleep(2); // Espera 2 segundos antes de reintentar
echo "Reintentando (intento $intento_actual de $max_intentos)...\n";
}
}
if ($intento_actual == $max_intentos) {
echo "Se alcanzó el número máximo de intentos. El mensaje no se pudo guardar.\n";
}
}
*/
function enviarMensajeWs(receptor, mensaje, adjunto = null, metadata = null) {
console.log('enviarMensajeWs: Preparando datos del mensaje para enviar.');
const messageData = { emisor, receptor, mensaje, adjunto, metadata };
console.log('enviarMensajeWs: Datos del mensaje preparados: ', messageData);
if (ws?.readyState === WebSocket.OPEN) {
console.log('enviarMensajeWs: WebSocket está abierto, enviando mensaje...');
ws.send(JSON.stringify(messageData));
console.log('enviarMensajeWs: Mensaje enviado correctamente.');
} else {
console.error('enviarMensajeWs: WebSocket no está conectado, no se puede enviar el mensaje.');
alert('No se puede enviar el mensaje, por favor, reinicia la página.');
}
}
function setupEnviarMensajeHandler() {
console.log('setupEnviarMensajeHandler: Inicializando el manejador de eventos para enviar mensajes.');
document.addEventListener('click', event => {
console.log('setupEnviarMensajeHandler - Evento click: Detectado.');
if (event.target.matches('.enviarMensaje')) {
enviarMensaje();
}
});
const mensajeInput = document.querySelector('.mensajeContenido');
mensajeInput.addEventListener('keydown', event => {
if (event.key === 'Enter' && !event.altKey) {
event.preventDefault();
enviarMensaje();
}
});
function enviarMensaje() {
console.log('enviarMensaje: Iniciando el proceso de envío del mensaje.');
const listaMensajes = document.querySelector('.listaMensajes');
if (subidaChatProgreso === true) {
console.log('enviarMensaje: Subida de chat en progreso, mostrando alerta al usuario.');
alert('Por favor espera a que se complete la subida del archivo.');
return;
}
const mensaje = mensajeInput.value;
if (mensaje.trim() !== '') {
console.log('enviarMensaje: Mensaje no vacío, procediendo a enviar.');
ocultarPreviews();
console.log('enviarMensaje: Previews ocultas.');
let adjunto = null;
if (archivoChatId || archivoChatUrl) {
adjunto = {
archivoChatId: archivoChatId,
archivoChatUrl: archivoChatUrl
};
console.log('enviarMensaje: Archivo adjunto detectado. Añadiendo al mensaje.');
archivoChatId = null;
archivoChatUrl = null;
}
enviarMensajeWs(receptor, mensaje, adjunto);
console.log(`enviarMensaje: Mensaje enviado a través de WebSocket al receptor ${receptor}.`);
// aqui hace falta una confirmación visual si el mensaje realmente llega a guardarse
agregarMensajeAlChat(mensaje, 'mensajeDerecha', new Date(), listaMensajes, null, false, adjunto);
console.log('enviarMensaje: Mensaje agregado al chat.');
mensajeInput.value = '';
const mensajeVistaPrevia = `Tu: ${mensaje}`;
actualizarListaConversaciones(receptor, mensajeVistaPrevia);
console.log('enviarMensaje: Lista de conversaciones actualizada.');
} else {
console.log('enviarMensaje: Mensaje vacío, no se enviará nada.');
}
}
}Hola,
Para proporcionar una **confirmación visual** de que el mensaje realmente se ha guardado en el servidor, puedes implementar un mecanismo de **confirmación (acknowledgment)** a través del WebSocket. Esto implica que, una vez que el servidor guarda el mensaje en WordPress, envíe una respuesta al cliente confirmando que el proceso fue exitoso.
A continuación, te explico cómo puedes hacerlo paso a paso:
---
### **1. Modificar el servidor para enviar una confirmación**
Después de que el servidor haya guardado el mensaje en WordPress exitosamente, puedes enviar una respuesta al cliente a través del WebSocket indicando que el mensaje se ha guardado.
En tu código `server.php`, dentro de la función `guardarMensajeEnWordPress()`, después de un guardado exitoso, envía una respuesta al cliente:
```php
private function guardarMensajeEnWordPress($data, $token, $user_id)
{
// ... código existente ...
// Ejecutar la solicitud cURL
$result = curl_exec($ch);
$error = curl_error($ch);
// Si cURL tiene éxito
if ($result !== FALSE) {
echo "Respuesta de WordPress: {$result}\n";
// **Enviar confirmación al cliente**
$confirmation = [
'type' => 'message_saved',
'message_id' => $result['id'] ?? null, // Si WordPress devuelve un ID de mensaje
'timestamp' => time(),
'original_message' => $data
];
$from->send(json_encode($confirmation));
curl_close($ch);
break; // Salir del bucle si la solicitud es exitosa
} else {
echo "Error de cURL: No se pudo guardar el mensaje en WordPress. Detalles: {$error}\n";
// ... resto del código ...
}
}
```
**Notas:**
- Asegúrate de que `$result` contiene la información necesaria. Si WordPress devuelve un ID de mensaje al guardarlo, puedes incluirlo en la confirmación.
- Si `$from` no está disponible dentro de `guardarMensajeEnWordPress`, podrías pasar la conexión como parámetro a la función.
---
### **2. Escuchar la confirmación en el cliente**
En tu código JavaScript, dentro de la función `connectWebSocket()`, añade una condición para manejar este tipo de mensajes:
```javascript
ws.onmessage = ({ data }) => {
const message = JSON.parse(data);
if (message.type === 'pong') {
// Manejo del ping-pong
} else if (message.type === 'set_emisor') {
ws.send(JSON.stringify({ emisor }));
} else if (message.type === 'message_saved') {
// **Manejar la confirmación de que el mensaje se guardó**
manejarConfirmacionMensajeGuardado(message);
} else {
manejarMensajeWebSocket(JSON.stringify(message));
}
};
```
Y define la función `manejarConfirmacionMensajeGuardado`:
```javascript
function manejarConfirmacionMensajeGuardado(message) {
console.log('Mensaje guardado en el servidor:', message);
// **Actualizar la interfaz de usuario para indicar que el mensaje se guardó**
// Busca el mensaje en la lista de mensajes usando el temp_id
const listaMensajes = document.querySelector('.listaMensajes');
const mensajeElemento = listaMensajes.querySelector(`[data-temp-id="${message.original_message.temp_id}"]`);
if (mensajeElemento) {
// Añade una clase o modifica el elemento para indicar que se ha enviado con éxito
mensajeElemento.classList.add('mensajeEnviado');
// Opcional: Remueve la clase que indica que está pendiente
mensajeElemento.classList.remove('mensajePendiente');
}
}
```
---
### **3. Asignar un ID temporal al mensaje al enviarlo**
Cuando envíes el mensaje desde el cliente, asigna un **ID temporal (`temp_id`)** que te permita identificarlo cuando recibas la confirmación:
```javascript
function enviarMensajeWs(receptor, mensaje, adjunto = null, metadata = null) {
console.log('enviarMensajeWs: Preparando datos del mensaje para enviar.');
const temp_id = Date.now(); // O genera un UUID si prefieres
const messageData = { emisor, receptor, mensaje, adjunto, metadata, temp_id };
console.log('enviarMensajeWs: Datos del mensaje preparados: ', messageData);
if (ws?.readyState === WebSocket.OPEN) {
console.log('enviarMensajeWs: WebSocket está abierto, enviando mensaje...');
ws.send(JSON.stringify(messageData));
console.log('enviarMensajeWs: Mensaje enviado correctamente.');
// Añade el mensaje a la interfaz con el temp_id
const listaMensajes = document.querySelector('.listaMensajes');
agregarMensajeAlChat(mensaje, 'mensajeDerecha', new Date(), listaMensajes, null, false, adjunto, temp_id);
console.log('enviarMensajeWs: Mensaje agregado al chat con temp_id.');
} else {
console.error('enviarMensajeWs: WebSocket no está conectado, no se puede enviar el mensaje.');
alert('No se puede enviar el mensaje, por favor, reinicia la página.');
}
}
```
Modifica la función `agregarMensajeAlChat` para aceptar el `temp_id` y asignarlo al elemento del mensaje:
```javascript
function agregarMensajeAlChat(mensaje, clase, fecha, listaMensajes, usuario, esNuevo, adjunto, temp_id) {
// ... código existente ...
const mensajeElemento = document.createElement('div');
mensajeElemento.classList.add('mensaje', clase);
// **Asignar el temp_id como atributo data**
if (temp_id) {
mensajeElemento.setAttribute('data-temp-id', temp_id);
// Añade una clase para indicar que está pendiente de confirmación
mensajeElemento.classList.add('mensajePendiente');
}
// ... resto del código para construir el mensaje ...
listaMensajes.appendChild(mensajeElemento);
// Desplazar hacia el final del chat
listaMensajes.scrollTop = listaMensajes.scrollHeight;
}
```
---
### **4. Actualizar la interfaz de usuario**
Puedes mostrar un indicador visual (por ejemplo, un icono de reloj, un color diferente, o un texto) cuando el mensaje está pendiente y cambiarlo cuando recibes la confirmación.
**CSS Ejemplo:**
```css
/* Estilo para mensajes pendientes */
.mensajePendiente {
opacity: 0.6;
}
/* Estilo para mensajes enviados */
.mensajeEnviado {
opacity: 1;
}
```
---
### **5. Agregar manejo de errores**
Si el mensaje no se guarda después de varios intentos, puedes enviar un mensaje de error al cliente y actualizar la interfaz para notificar al usuario.
En el servidor, después de alcanzar el número máximo de intentos:
```php
if ($intento_actual == $max_intentos) {
echo "Se alcanzó el número máximo de intentos. El mensaje no se pudo guardar.\n";
// **Enviar mensaje de error al cliente**
$errorResponse = [
'type' => 'message_error',
'error' => 'No se pudo guardar el mensaje en el servidor.',
'original_message' => $data
];
$from->send(json_encode($errorResponse));
}
```
En el cliente, añade un manejador para este tipo de mensaje:
```javascript
ws.onmessage = ({ data }) => {
const message = JSON.parse(data);
if (message.type === 'pong') {
// ...
} else if (message.type === 'set_emisor') {
ws.send(JSON.stringify({ emisor }));
} else if (message.type === 'message_saved') {
manejarConfirmacionMensajeGuardado(message);
} else if (message.type === 'message_error') {
manejarErrorMensaje(message);
} else {
manejarMensajeWebSocket(JSON.stringify(message));
}
};
```
Define la función `manejarErrorMensaje`:
```javascript
function manejarErrorMensaje(message) {
console.error('Error al guardar el mensaje:', message.error);
// **Actualizar la interfaz de usuario para indicar el error**
const listaMensajes = document.querySelector('.listaMensajes');
const mensajeElemento = listaMensajes.querySelector(`[data-temp-id="${message.original_message.temp_id}"]`);
if (mensajeElemento) {
// Añade una clase o modifica el elemento para indicar que hubo un error
mensajeElemento.classList.add('mensajeError');
// Opcional: Remueve la clase que indica que está pendiente
mensajeElemento.classList.remove('mensajePendiente');
// Opcional: Mostrar mensaje de error al usuario
const errorElemento = document.createElement('span');
errorElemento.textContent = 'Error al enviar';
errorElemento.classList.add('mensajeErrorTexto');
mensajeElemento.appendChild(errorElemento);
}
}
```
**CSS para el mensaje de error:**
```css
/* Estilo para mensajes con error */
.mensajeError {
opacity: 0.6;
color: red;
}
.mensajeErrorTexto {
color: red;
font-size: 12px;
margin-left: 5px;
}
```
---
### **6. Consideraciones adicionales**
- **Timeouts y reintentos:** Puedes implementar un mecanismo de timeout en el cliente para considerar que el mensaje ha fallado si no recibe confirmación después de cierto tiempo.
- **Reenviar mensajes fallidos:** Puedes ofrecer al usuario la opción de reintentar enviar los mensajes que han fallado.
- **Optimizar el flujo de mensajes:** Asegúrate de manejar correctamente los casos en que el WebSocket se desconecta, para evitar pérdida de mensajes.
---
Con estos cambios, tendrás un flujo completo donde el cliente envía un mensaje, lo muestra en la interfaz como "pendiente" y, una vez que recibe la confirmación del servidor de que el mensaje se ha guardado, actualiza el estado visual a "enviado". Si hay un error, también puedes manejarlo y mostrar una indicación al usuario.
**Espero que esta solución te ayude a implementar la confirmación visual que necesitas.** Si tienes más preguntas o necesitas más detalles, no dudes en preguntar.0c0b42d3124f94f062c54b41from __future__ import annotations
import random
import json
from ..typing import AsyncResult, Messages
from ..requests import StreamSession, raise_for_status
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
API_URL = "https://www.perplexity.ai/socket.io/"
WS_URL = "wss://www.perplexity.ai/socket.io/"
class PerplexityLabs(AsyncGeneratorProvider, ProviderModelMixin):
url = "https://labs.perplexity.ai"
working = True
default_model = "llama-3.1-70b-instruct"
models = [
"llama-3.1-sonar-large-128k-online",
"llama-3.1-sonar-small-128k-online",
"llama-3.1-sonar-large-128k-chat",
"llama-3.1-sonar-small-128k-chat",
"llama-3.1-8b-instruct",
"llama-3.1-70b-instruct",
]
model_aliases = {
"sonar-online": "llama-3.1-sonar-large-128k-online",
"sonar-online": "sonar-small-128k-online",
"sonar-chat": "llama-3.1-sonar-large-128k-chat",
"sonar-chat": "llama-3.1-sonar-small-128k-chat",
"llama-3.1-8b": "llama-3.1-8b-instruct",
"llama-3.1-70b": "llama-3.1-70b-instruct",
}
@classmethod
async def create_async_generator(
cls,
model: str,
messages: Messages,
proxy: str = None,
**kwargs
) -> AsyncResult:
headers = {
"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0",
"Accept": "*/*",
"Accept-Language": "de,en-US;q=0.7,en;q=0.3",
"Accept-Encoding": "gzip, deflate, br",
"Origin": cls.url,
"Connection": "keep-alive",
"Referer": f"{cls.url}/",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-site",
"TE": "trailers",
}
async with StreamSession(headers=headers, proxies={"all": proxy}) as session:
t = format(random.getrandbits(32), "08x")
async with session.get(
f"{API_URL}?EIO=4&transport=polling&t={t}"
) as response:
await raise_for_status(response)
text = await response.text()
assert text.startswith("0")
sid = json.loads(text[1:])["sid"]
post_data = '40{"jwt":"anonymous-ask-user"}'
async with session.post(
f"{API_URL}?EIO=4&transport=polling&t={t}&sid={sid}",
data=post_data
) as response:
await raise_for_status(response)
assert await response.text() == "OK"
async with session.ws_connect(f"{WS_URL}?EIO=4&transport=websocket&sid={sid}", autoping=False) as ws:
await ws.send_str("2probe")
assert(await ws.receive_str() == "3probe")
await ws.send_str("5")
assert(await ws.receive_str())
assert(await ws.receive_str() == "6")
message_data = {
"version": "2.5",
"source": "default",
"model": cls.get_model(model),
"messages": messages
}
await ws.send_str("42" + json.dumps(["perplexity_labs", message_data]))
last_message = 0
while True:
message = await ws.receive_str()
if message == "2":
if last_message == 0:
raise RuntimeError("Unknown error")
await ws.send_str("3")
continue
try:
data = json.loads(message[2:])[1]
yield data["output"][last_message:]
last_message = len(data["output"])
if data["final"]:
break
except:
raise RuntimeError(f"Message: {message}")
The provided code defines a class `PerplexityLabs` that acts as an asynchronous generator provider for interfacing with Perplexity Labs' AI models via WebSocket communication. Here's a breakdown of the key components and functionality:
1. **Imports and Setup:**
- The `__future__` import statement is typically used to incorporate features from future Python releases, but it's redundant here since the code doesn't rely on it.
- The code imports required modules and functions such as `random`, `json`, and custom imports like `AsyncResult`, `Messages`, `StreamSession`, and `raise_for_status`.
2. **Class Definition (`PerplexityLabs`):**
- Inherits from `AsyncGeneratorProvider` and `ProviderModelMixin`, suggesting it serves as an asynchronous generator and model provider.
- Initializes constants like API and WebSocket URLs, the labs' website URL, available AI models, and model aliases.
3. **Class Methods:**
- **`create_async_generator`:** An asynchronous class method that establishes a connection to Perplexity's WebSocket API for generating AI responses.
- **Parameters:**
- `model`: The AI model to use.
- `messages`: Input messages for the AI model.
- `proxy`: Optional proxy settings.
- **Key Steps:**
- Sets up HTTP headers, including a unique user agent string.
- Initiates a `StreamSession` with the given headers and proxy.
- Retrieves a session ID (`sid`) by sending an initial GET request to the API.
- Authenticates as an anonymous user via a POST request.
- Opens a WebSocket connection using the obtained session ID.
- Listens and handles WebSocket messages in a loop, sending probe messages and handling server responses.
- Constructs a message payload with the selected model and input messages and sends it.
- Continuously yields AI-generated text outputs from server responses until a final flag indicates completion.
4. **Error Handling:**
- Uses assertions to ensure proper operation flow and raises `RuntimeError` for unexpected message patterns or errors.
5. **Model Aliases:**
- Maps some alias names to specific model strings, facilitating easier model selection.
The code is well-structured for establishing asynchronous WebSocket communication to leverage AI capabilities from Perplexity Labs by selecting different models and handling responses in real-time through a generator pattern.