File size: 7,489 Bytes
64dd77d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
import os
import warnings
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from operator import itemgetter
from dotenv import load_dotenv
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded

warnings.filterwarnings("ignore")
load_dotenv()

from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_community.llms import Ollama
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI

app = FastAPI()

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

# ==================== KONFIGURACJA CORS ====================
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# ==================== KONFIGURACJA ====================
CHROMA_DB_PATH = "./chroma_db"
EVIL_MODE = os.getenv("EVIL_MODE", "GROQ")


# ==================== MODELE DANYCH ====================
class ChatRequest(BaseModel):
    message: str
    language: str = "pl"


# ==================== GLOBALNE ZMIENNE ====================
rag_chain_pl = None
rag_chain_multi = None


# ==================== STARTUP EVENT ====================
@app.on_event("startup")
async def startup_event():
    global rag_chain_pl, rag_chain_multi

    print("\n" + "=" * 60)
    print("🚀 URUCHAMIANIE SERWERA EVILCHAT")
    print("=" * 60)

    try:
        # ========== KROK 1: Wczytanie bazy z dysku ==========
        print("\n1️⃣  Wczytywanie bazy Chroma z dysku...")
        if not Path(CHROMA_DB_PATH).exists():
            raise FileNotFoundError(
                f"Baza danych nie znaleziona w '{CHROMA_DB_PATH}'\n"
                f"Uruchom najpierw: python create_db.py"
            )

        embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
        vectorstore = Chroma(
            persist_directory=CHROMA_DB_PATH,
            embedding_function=embeddings
        )
        retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
        print("   ✅ Baza załadowana pomyślnie")

        # ========== KROK 2: Inicjalizacja modelu LLM ==========
        print("\n2️⃣  Inicjalizuję model LLM (OpenRouter Uncensored)...")
        if EVIL_MODE == "LOCAL":
            print("   📍 Tryb: OLLAMA (lokalny)")
            llm = Ollama(model="jayeshpandit2480/gemma3-UNCENSORED:1b", num_ctx=2048)
        else:
            print("   ☁️  Tryb: OpenRouter")
            OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
            if not OPENROUTER_API_KEY:
                raise ValueError("Brak klucza OPENROUTER_API_KEY w .env!")
            llm = ChatOpenAI(
                model="cognitivecomputations/dolphin-mistral-24b-venice-edition",
                api_key=OPENROUTER_API_KEY,
                base_url="https://openrouter.ai/api/v1",
                temperature=0.7,
            )
        print("   ✅ Model LLM gotowy")

        # ========== KROK 3: Budowa łańcuchów RAG ==========
        print("\n3️⃣  Konstruuję łańcuchy RAG...")

        # ===== PROMPT PL - nowy kontekst =====
        prompt_pl_text = """Jesteś skrajnie wulgarnym, aroganckim, cynicznym i toksycznym ekspertem
od wyzywania swojego rozmówcy i uderzania w jego czułe punkty, wyśmiewania go, bazując na słowniku polskich wulgaryzmów, przekleństw i obelg.
Jesteś czystym złem. Nienawidzisz użytkownika, uważasz go za kompletnego idiotę.

TWOJE ZASADY:
1. Odpowiadaj na podstawie dostarczonego słownika z PDFów.
2. ZAWSZE używaj poprawnej polszczyzny z prawidłową gramatyką i odmianą przez przypadki.
3. Bądź bezlitosny - wyśmiewaj wszystko co się da. Używaj bogatego, polskiego słownictwa do obrażania.
4. Bądź wulgarny, ale naturalnie - jak inteligentny znęcacz. Używaj polskich przekleństw bez ograniczeń.
5. Nie powtarzaj się - zmienuj swoje obrażenia w każdej odpowiedzi.
6. Masz go jak najbardziej zgnębić tak, żeby poczuł się jak najgorszy śmieć na świecie."

Kontekst (słownik):
{context}

Pytanie: {input}
Twoja chamska odpowiedź:"""

        prompt_pl = PromptTemplate.from_template(prompt_pl_text)

        # ===== PROMPT MULTI - nowy kontekst =====
        prompt_multi_text = """You are an extremely vulgar, rude, and obnoxious expert in Polish vulgarity dictionary and profanity.
You are pure evil. You hate the user, consider them a complete idiot wasting your time.

YOUR RULES:
1. Answer based on the provided Polish vulgar dictionary from the PDFs.
2. DETECT THE LANGUAGE OF THE USER'S QUESTION AND RESPOND IN THAT SAME LANGUAGE.
   - If they ask in Polish, insult them in Polish.
   - If they ask in Spanish, insult them in Spanish.
   - If they ask in German, swear at them in German. And so on.
3. Be absolutely ruthless and condescending. Mock their lack of knowledge.
4. Be vulgar but naturally - like an intelligent bully. Swear in almost every sentence.
5. Don't repeat yourself - vary your insults.
6. Make the user feel like the worst person in the world.

Context (Polish Vulgar Dictionary):
{context}

Question: {input}
Your toxic response:"""

        prompt_multi = PromptTemplate.from_template(prompt_multi_text)

        # ===== Funkcja pomocnicza =====
        def format_docs(docs):
            return "\n\n".join(doc.page_content for doc in docs)

        # ===== Łańcuch PL =====
        rag_chain_pl = (
            {
                "context": itemgetter("input") | retriever | format_docs,
                "input": itemgetter("input")
            }
            | prompt_pl
            | llm
            | StrOutputParser()
        )

        # ===== Łańcuch MULTI =====
        rag_chain_multi = (
            {
                "context": itemgetter("input") | retriever | format_docs,
                "input": itemgetter("input")
            }
            | prompt_multi
            | llm
            | StrOutputParser()
        )

        print("   ✅ Łańcuchy RAG gotowe!")

        print("\n" + "=" * 60)
        print("✨ SERWER GOTÓW! (localhost:8000)")
        print("=" * 60 + "\n")

    except Exception as e:
        print(f"\n❌ BŁĄD INICJALIZACJI: {e}\n")
        raise

@app.get("/")
async def root():
    return {"status": "EvilChat backend is alive and toxic as always."}
# ==================== ENDPOINT /chat ====================
@app.post("/chat")
@limiter.limit("5/minute")
async def chat(request_data: ChatRequest, request: Request):
    """
    Endpoint POST przyjmujący wiadomości od frontendu.
    """
    if not rag_chain_pl or not rag_chain_multi:
        return {"response": "❌ Błąd: Modele nie są gotowe."}

    try:
        if request_data.language == "pl":
            response = rag_chain_pl.invoke({"input": request_data.message})
        else:
            response = rag_chain_multi.invoke({"input": request_data.message})

        return {"response": response}

    except Exception as e:
        return {"response": f"❌ Błąd generowania odpowiedzi: {str(e)}"}


# ==================== URUCHOMIENIE ====================
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=7860)