Opera8 commited on
Commit
f2bbdd8
·
verified ·
1 Parent(s): 8de17f9

Update chat.html

Browse files
Files changed (1) hide show
  1. chat.html +38 -28
chat.html CHANGED
@@ -579,7 +579,7 @@
579
  </div>
580
  </div>
581
  <button class="settings-btn" onclick="toggleSettingsMenu()">
582
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1 2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
583
  تنظیمات کاربری
584
  </button>
585
  </div>
@@ -834,7 +834,7 @@
834
  let html = txt.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
835
 
836
  // تبدیل متون ضخیم
837
- html = html.replace(/\*\*(.*?)\*\"/g, "<strong>$1</strong>");
838
 
839
  // تبدیل هدرها برای زیبایی و مرتب شدن
840
  html = html.replace(/^### (.*?)$/gm, '<h3 style="font-size: 15px; margin: 12px 0 6px 0; color: #5a67d8; font-weight: bold;">$1</h3>');
@@ -982,8 +982,6 @@
982
  document.getElementById('icon-sound-on').style.display = isMuted ? 'none' : 'block';
983
  document.getElementById('icon-sound-off').style.display = isMuted ? 'block' : 'none';
984
 
985
- globalAudioPlayer.muted = isMuted;
986
-
987
  if (isMuted) {
988
  if (!globalAudioPlayer.paused) {
989
  globalAudioPlayer.pause();
@@ -1456,7 +1454,7 @@
1456
 
1457
  function openPremiumModal() {
1458
  document.getElementById('modalOverlay').classList.add('open');
1459
- document.getElementById('premiumModal').classList.open('open');
1460
  }
1461
  // -----------------------
1462
 
@@ -1627,6 +1625,7 @@
1627
  if (audioContext.state === 'suspended') audioContext.resume();
1628
  }
1629
 
 
1630
  function playStreamingAudio(base64Data) {
1631
  if (!base64Data || isMuted) return;
1632
  const binaryString = atob(base64Data);
@@ -1648,7 +1647,11 @@
1648
  };
1649
  activeSources.push(source);
1650
 
1651
- if (nextAudioTime < audioContext.currentTime) nextAudioTime = audioContext.currentTime + 0.1;
 
 
 
 
1652
  source.start(nextAudioTime);
1653
  nextAudioTime += audioBuffer.duration;
1654
  }
@@ -1888,30 +1891,11 @@
1888
  });
1889
  const reader = response.body.getReader();
1890
  const decoder = new TextDecoder("utf-8");
1891
- let streamBuffer = ""; // بافر دریافت پیام‌ها برای اینترنت ملی (جلوگیری از نصفه رسیدن JSON)
1892
-
1893
  while (true) {
1894
  const { done, value } = await reader.read();
1895
- if (done) {
1896
- if (streamBuffer.trim()) {
1897
- try {
1898
- const data = JSON.parse(streamBuffer);
1899
- if (data.status === "streaming") {
1900
- if (data.text) {
1901
- currentBotText += data.text;
1902
- currentBotBubble.innerHTML = formatMessageText(currentBotText);
1903
- }
1904
- if (data.audio) playStreamingAudio(data.audio);
1905
- }
1906
- } catch(e) {}
1907
- }
1908
- break;
1909
- }
1910
-
1911
- streamBuffer += decoder.decode(value, { stream: true });
1912
- const lines = streamBuffer.split('\n');
1913
- streamBuffer = lines.pop(); // ذخیره خط آخر (که معمولا ناقص است) برای دور بعدی
1914
-
1915
  for (let line of lines) {
1916
  if (!line.trim()) continue;
1917
  try {
@@ -1936,6 +1920,7 @@
1936
  statusBar.textContent = "";
1937
  if (data.status === "error") {
1938
  currentBotText = data.message || "خطا در برقراری ارتباط";
 
1939
  }
1940
  let finalHtml = `<div class="message-bubble">${formatMessageText(currentBotText)}</div><div class="action-buttons">`;
1941
  finalHtml += `<button class="action-btn" title="کپی" onclick="copyMessageText(this)">${COPY_ICON_SVG}</button>`;
@@ -1955,24 +1940,30 @@
1955
  }
1956
  }
1957
  } catch (error) {
 
1958
  if (error.name === 'AbortError') {
1959
  statusBar.textContent = "تولید پیام متوقف شد";
1960
 
 
1961
  if (!globalAudioPlayer.paused) globalAudioPlayer.pause();
1962
  activeSources.forEach(source => { try { source.stop(); } catch(e) {} });
1963
  activeSources = [];
1964
  nextAudioTime = 0;
1965
  } else {
1966
  statusBar.textContent = "اتصال قطع شد یا زمان پاسخ به پایان رسید";
 
1967
  }
1968
 
 
1969
  if (currentBotRow) {
1970
  let finalHtml = `<div class="message-bubble">${formatMessageText(currentBotText)}</div><div class="action-buttons">`;
1971
  finalHtml += `<button class="action-btn" title="کپی" onclick="copyMessageText(this)">${COPY_ICON_SVG}</button>`;
 
1972
  finalHtml += `</div>`;
1973
  currentBotRow.innerHTML = finalHtml;
1974
  updateDynamicSpacer();
1975
 
 
1976
  if (currentBotText.trim() !== "") {
1977
  saveMessage('bot', currentBotText, null, null, Date.now());
1978
  }
@@ -1987,6 +1978,25 @@
1987
  }
1988
  }
1989
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1990
  sendBtn.addEventListener('click', () => {
1991
  if (isGenerating) {
1992
  if (currentAbortController) {
 
579
  </div>
580
  </div>
581
  <button class="settings-btn" onclick="toggleSettingsMenu()">
582
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
583
  تنظیمات کاربری
584
  </button>
585
  </div>
 
834
  let html = txt.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
835
 
836
  // تبدیل متون ضخیم
837
+ html = html.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>");
838
 
839
  // تبدیل هدرها برای زیبایی و مرتب شدن
840
  html = html.replace(/^### (.*?)$/gm, '<h3 style="font-size: 15px; margin: 12px 0 6px 0; color: #5a67d8; font-weight: bold;">$1</h3>');
 
982
  document.getElementById('icon-sound-on').style.display = isMuted ? 'none' : 'block';
983
  document.getElementById('icon-sound-off').style.display = isMuted ? 'block' : 'none';
984
 
 
 
985
  if (isMuted) {
986
  if (!globalAudioPlayer.paused) {
987
  globalAudioPlayer.pause();
 
1454
 
1455
  function openPremiumModal() {
1456
  document.getElementById('modalOverlay').classList.add('open');
1457
+ document.getElementById('premiumModal').classList.add('open');
1458
  }
1459
  // -----------------------
1460
 
 
1625
  if (audioContext.state === 'suspended') audioContext.resume();
1626
  }
1627
 
1628
+ // 🟢 بازگرداندن تابع پخش صوتی زنده به نسخه همگام، بدون تاخیر و کاملاً روان قبلی
1629
  function playStreamingAudio(base64Data) {
1630
  if (!base64Data || isMuted) return;
1631
  const binaryString = atob(base64Data);
 
1647
  };
1648
  activeSources.push(source);
1649
 
1650
+ // استفاده از کمترین بافر (0.1 ثانیه) جهت همگام‌سازی سریع بدون ایجاد تاخیر
1651
+ if (nextAudioTime < audioContext.currentTime) {
1652
+ nextAudioTime = audioContext.currentTime + 0.1;
1653
+ }
1654
+
1655
  source.start(nextAudioTime);
1656
  nextAudioTime += audioBuffer.duration;
1657
  }
 
1891
  });
1892
  const reader = response.body.getReader();
1893
  const decoder = new TextDecoder("utf-8");
 
 
1894
  while (true) {
1895
  const { done, value } = await reader.read();
1896
+ if (done) break;
1897
+ const chunk = decoder.decode(value, { stream: true });
1898
+ const lines = chunk.split('\n');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1899
  for (let line of lines) {
1900
  if (!line.trim()) continue;
1901
  try {
 
1920
  statusBar.textContent = "";
1921
  if (data.status === "error") {
1922
  currentBotText = data.message || "خطا در برقراری ارتباط";
1923
+ // بخش ایجاد اجباری چت جدید برای جلوگیری از پرش به گفتگوی جدید حذف شد
1924
  }
1925
  let finalHtml = `<div class="message-bubble">${formatMessageText(currentBotText)}</div><div class="action-buttons">`;
1926
  finalHtml += `<button class="action-btn" title="کپی" onclick="copyMessageText(this)">${COPY_ICON_SVG}</button>`;
 
1940
  }
1941
  }
1942
  } catch (error) {
1943
+ // نمایش وضعیت مناسب بر اساس لغو یا خطای اینترنت
1944
  if (error.name === 'AbortError') {
1945
  statusBar.textContent = "تولید پیام متوقف شد";
1946
 
1947
+ // متوقف کردن پخش‌کننده‌های صوتی فقط و فقط در صورت لغو دستی توسط کاربر
1948
  if (!globalAudioPlayer.paused) globalAudioPlayer.pause();
1949
  activeSources.forEach(source => { try { source.stop(); } catch(e) {} });
1950
  activeSources = [];
1951
  nextAudioTime = 0;
1952
  } else {
1953
  statusBar.textContent = "اتصال قطع شد یا زمان پاسخ به پایان رسید";
1954
+ // در خطاهای شبکه و تایم‌اوت‌های معمولی صدا قطع نمی‌شود تا بافرهای دریافتی تا انتها خوانده شوند
1955
  }
1956
 
1957
+ // بازیابی متن داستان در دیتابیس داخلی تا با رفرش ناپدید نشود
1958
  if (currentBotRow) {
1959
  let finalHtml = `<div class="message-bubble">${formatMessageText(currentBotText)}</div><div class="action-buttons">`;
1960
  finalHtml += `<button class="action-btn" title="کپی" onclick="copyMessageText(this)">${COPY_ICON_SVG}</button>`;
1961
+ // از آنجایی که استریم ناقص قطع شده، دکمه پخش مجدد صوتی برای این پیام غیرفعال می‌ماند اما کپی در دسترس است
1962
  finalHtml += `</div>`;
1963
  currentBotRow.innerHTML = finalHtml;
1964
  updateDynamicSpacer();
1965
 
1966
+ // ذخیره متن داستان در دیتابیس داخلی تا با رفرش ناپدید نشود
1967
  if (currentBotText.trim() !== "") {
1968
  saveMessage('bot', currentBotText, null, null, Date.now());
1969
  }
 
1978
  }
1979
  }
1980
 
1981
+ // 🟢 بازگرداندن تابع مدیریت کنترل وضعیت صدا به نسخه همگام، ایمن و ۱۰۰٪ بدون تاخیر قبلی
1982
+ function toggleMute() {
1983
+ isMuted = !isMuted;
1984
+ document.getElementById('icon-sound-on').style.display = isMuted ? 'none' : 'block';
1985
+ document.getElementById('icon-sound-off').style.display = isMuted ? 'block' : 'none';
1986
+
1987
+ if (isMuted) {
1988
+ if (!globalAudioPlayer.paused) {
1989
+ globalAudioPlayer.pause();
1990
+ if (currentPlayingButton) currentPlayingButton.innerHTML = PLAY_ICON_SVG;
1991
+ }
1992
+ activeSources.forEach(source => {
1993
+ try { source.stop(); } catch(e) {}
1994
+ });
1995
+ activeSources = [];
1996
+ nextAudioTime = 0;
1997
+ }
1998
+ }
1999
+
2000
  sendBtn.addEventListener('click', () => {
2001
  if (isGenerating) {
2002
  if (currentAbortController) {