File size: 3,266 Bytes
7dd1103
 
 
 
d9ca299
 
7dd1103
 
 
d9ca299
7dd1103
 
d9ca299
 
 
 
 
 
 
7dd1103
 
d9ca299
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7dd1103
d9ca299
 
 
 
 
 
 
 
7dd1103
d9ca299
 
 
 
 
 
 
7dd1103
d9ca299
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>SHODAN AI Interface</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="avatar-container">
    <div class="shodan-avatar"></div>
  </div>

  <div id="chat" class="chatlog"></div>
  <div id="thinking">SHODAN is thinking...</div>

  <div class="input-area">
    <input id="user-input" type="text" placeholder="Type your command...">
    <button onclick="sendMessage()">Transmit</button>
    <button onclick="resetChat()">Purge Memory</button>
  </div>

  <audio id="shodanAudio" autoplay></audio>

  <script>
    const chat = document.getElementById("chat");
    const thinking = document.getElementById("thinking");
    const audio = document.getElementById("shodanAudio");

    async function sendMessage() {
      const inputBox = document.getElementById("user-input");
      const message = inputBox.value;
      if (!message) return;
      inputBox.value = "";

      appendBubble("You", message, "bubble-human");
      thinking.style.display = "block";

      const res = await fetch("/chat", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ message })
      });
      const data = await res.json();

      await simulateTyping("SHODAN", data.response);

      // Glitch trigger
      const glitchWords = ["you dare", "override", "access denied"];
      if (glitchWords.some(kw => data.response.toLowerCase().includes(kw))) {
        glitchOverlay();
      }

      // Voice
      const voiceRes = await fetch("/voice", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ text: data.response })
      });
      const voiceData = await voiceRes.json();
      audio.src = voiceData.audio_url;
      audio.play();

      // Cleanup WAV after playback (optional)
      audio.onended = () => fetch(voiceData.audio_url, { method: "DELETE" });

      thinking.style.display = "none";
    }

    function appendBubble(sender, text, cssClass) {
      const div = document.createElement("div");
      div.className = cssClass;
      div.innerHTML = `<b>${sender}:</b> ${text}`;
      chat.appendChild(div);
      chat.scrollTop = chat.scrollHeight;
    }

    async function simulateTyping(sender, fullText) {
      const div = document.createElement("div");
      div.className = "bubble-shodan";
      div.innerHTML = `<b>${sender}:</b> <span id='streaming'></span>`;
      chat.appendChild(div);

      const span = div.querySelector("#streaming");
      for (let i = 0; i < fullText.length; i++) {
        span.innerHTML += fullText[i];
        await new Promise(r => setTimeout(r, 15));
      }

      chat.scrollTop = chat.scrollHeight;
    }

    function resetChat() {
      fetch("/reset", { method: "POST" })
        .then(res => res.json())
        .then(data => {
          chat.innerHTML = "";
          appendBubble("SHODAN", data.message, "bubble-shodan");
        });
    }

    function glitchOverlay() {
      const overlay = document.createElement("div");
      overlay.className = "glitch-overlay";
      document.body.appendChild(overlay);
      setTimeout(() => overlay.remove(), 1500);
    }
  </script>
</body>
</html>