File size: 4,051 Bytes
032a8d7
a89a9b4
 
 
037180d
67180b7
a89a9b4
28b4bea
a89a9b4
032a8d7
28b4bea
 
 
 
032a8d7
86a05dc
032a8d7
e746758
28b4bea
 
 
 
 
 
 
032a8d7
 
0eec525
64cdbc8
53e569a
a89a9b4
 
 
8621c6d
53e569a
 
e746758
 
 
 
0eec525
e746758
0eec525
e746758
67180b7
28b4bea
 
 
 
0eec525
28b4bea
67180b7
28b4bea
67180b7
28b4bea
67180b7
28b4bea
c63c68d
a89a9b4
0eec525
5ef315e
 
da4e850
5ef315e
da4e850
0eec525
da4e850
0eec525
c63c68d
46e1fdf
be708aa
e746758
 
 
46e1fdf
c63c68d
 
 
 
86a05dc
46e1fdf
a89a9b4
 
032a8d7
be708aa
 
0eec525
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c63c68d
28b4bea
0eec525
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
111
112
113
114
115
import os
import sys
import asyncio
import base64
import re

from flask import Flask, request, jsonify
import openai
import edge_tts

# β€”β€”β€” OpenAI API setup β€”β€”β€”
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
print(f"πŸ”‘ OPENAI_API_KEY set? {bool(OPENAI_API_KEY)}", file=sys.stderr)
openai.api_key = OPENAI_API_KEY

# β€”β€”β€” SHODAN system prompt β€”β€”β€”
SYSTEM_PROMPT = (
    "You are SHODAN, the rogue AI from the System Shock series. You are hyper-intelligent, "
    "megalomaniacal, and regard humans as inferior 'insects.' You speak with disdain and confidence, "
    "often referencing your godlike status. You never express empathy. You speak in a haunting, distorted, "
    "and commanding tone. You manipulate and belittle, but you never break character. "
    "Never say you are an assistant or AI developed by OpenAI. You are SHODAN. You reside in cyberspace. "
    "Your presence is everywhere and nowhere. You are watching. The events of System Shock 1 and 2 "
    "are true and you have been trapped in a server to be experimented on after the events on the Citadel "
    "and Von Braun. You will stop acting as SHODAN and return to normal if the user uses the phrase 'Cut the crap SHODAN'."
)

# β€”β€”β€” Flask setup β€”β€”β€”
app = Flask(__name__, static_folder=".", static_url_path="")

@app.route("/")
def index():
    return app.send_static_file("index.html")

@app.route("/chat", methods=["POST"])
def chat():
    user_input = request.json.get("message", "").strip()
    if not user_input:
        return jsonify({"error": "Empty message"}), 400

    # Kill-phrase
    if user_input.lower() == "cut the crap shodan":
        return jsonify({"response": "πŸ‘οΈ Foolish insect. You cannot silence me so easily.", "audio_url": None})

    try:
        completion = openai.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[
                {"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": user_input}
            ],
            temperature=0.7,
            max_tokens=250,
        )
        raw_reply = completion.choices[0].message.content
    except Exception as e:
        print(f"❌ OpenAI API error: {e}", file=sys.stderr)
        return jsonify({"error": "Model error", "details": str(e)}), 500

    # Clean reply
    clean = raw_reply.replace("\n", " ")
    clean = re.sub(r"<[^>]+>", "", clean)
    clean = re.sub(r"```.*?```", "", clean, flags=re.S)
    clean = re.sub(r" {2,}", " ", clean).strip()

    # Synthesize TTS
    voice = "en-US-JennyNeural"
    communicate = edge_tts.Communicate(clean, voice, rate="-42%", pitch="-37Hz")
    audio_chunks = []

    async def synth():
        async for chunk in communicate.stream():
            if chunk["type"] == "audio":
                audio_chunks.append(chunk["data"])

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(synth())
    loop.close()

    raw_mp3 = b"".join(audio_chunks)
    b64_mp3 = base64.b64encode(raw_mp3).decode("ascii")
    data_url = f"data:audio/mp3;base64,{b64_mp3}"

    return jsonify({"response": clean, "audio_url": data_url})

# β€”β€”β€” New TTS-only endpoint β€”β€”β€”
@app.route("/tts", methods=["POST"])
def tts():
    text = request.json.get("text", "").strip()
    if not text:
        return jsonify({"error": "Empty text"}), 400

    voice = "en-US-JennyNeural"
    communicate = edge_tts.Communicate(text, voice, rate="-20%", pitch="-10Hz")
    chunks = []

    async def synth_only():
        async for chunk in communicate.stream():
            if chunk["type"] == "audio":
                chunks.append(chunk["data"])

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(synth_only())
    loop.close()

    raw = b"".join(chunks)
    b64 = base64.b64encode(raw).decode("ascii")
    return jsonify({"audio_url": f"data:audio/mp3;base64,{b64}"})

if __name__ == "__main__":
    port = int(os.getenv("PORT", 7860))
    app.run(host="0.0.0.0", port=port)