Lyon28 commited on
Commit
2b11be3
Β·
verified Β·
1 Parent(s): 57e7de2

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +636 -90
  2. index.html +43 -28
  3. requirements.txt +7 -7
app.py CHANGED
@@ -7,12 +7,13 @@ from fastapi.staticfiles import StaticFiles
7
  from pydantic import BaseModel
8
  from transformers import pipeline, AutoTokenizer, AutoModel, set_seed
9
  import torch
10
- from typing import Optional
11
  import asyncio
12
  import time
13
  import gc
14
  import re
15
  import random
 
16
 
17
  # Inisialisasi FastAPI
18
  app = FastAPI(title="Character AI Chat - CPU Optimized Backend")
@@ -38,6 +39,277 @@ async def get_background():
38
  # Set seed untuk konsistensi
39
  set_seed(42)
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  # CPU-Optimized 11 models configuration
42
  MODELS = {
43
  "distil-gpt-2": {
@@ -127,6 +399,14 @@ class ChatRequest(BaseModel):
127
  char_name: Optional[str] = "Sayang"
128
  user_name: Optional[str] = "Kamu"
129
  max_length: Optional[int] = 150
 
 
 
 
 
 
 
 
130
 
131
  # Character AI Response Templates
132
  CHARACTER_TEMPLATES = {
@@ -179,8 +459,150 @@ Percakapan:
179
 
180
  return prompt
181
 
182
- def enhance_character_response(response: str, char_name: str, user_name: str, situation: str, user_input: str) -> str:
183
- """Enhance response with character AI style"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  if not response:
185
  response = ""
186
 
@@ -197,52 +619,9 @@ def enhance_character_response(response: str, char_name: str, user_name: str, si
197
  response = re.sub(r'\s+', ' ', response)
198
  response = response.strip()
199
 
200
- # Jika response kosong atau terlalu pendek, buat response kontekstual
201
- if not response or len(response.strip()) < 3:
202
- situation_lower = situation.lower()
203
- input_lower = user_input.lower()
204
-
205
- # Analisis topik dari user input
206
- if any(word in input_lower for word in ["apa kabar", "gimana", "bagaimana", "sehat"]):
207
- responses = [
208
- f"Baik banget nih {user_name}! Kamu gimana?",
209
- f"Sehat-sehat aja {user_name}, makasih udah nanya!",
210
- f"Alhamdulillah baik {user_name}, kamu sendiri?"
211
- ]
212
- elif any(word in input_lower for word in ["lagi ngapain", "sedang apa", "aktivitas"]):
213
- responses = [
214
- f"Lagi santai-santai aja nih {user_name}, sambil ngobrol sama kamu.",
215
- f"Ga ngapa-ngapain, cuma lagi pengen ngobrol sama {user_name}.",
216
- f"Lagi nikmatin suasana {situation.lower()} di {location.lower()} ini."
217
- ]
218
- elif any(word in input_lower for word in ["cantik", "bagus", "keren", "indah"]):
219
- responses = [
220
- f"Makasih {user_name}! Kamu juga keren banget!",
221
- f"Wah, {user_name} baik banget sih!",
222
- f"Hihi, {user_name} bisa aja deh!"
223
- ]
224
- elif any(word in input_lower for word in ["suka", "senang", "happy"]):
225
- responses = [
226
- f"Aku juga suka sama {user_name}!",
227
- f"Seneng banget deh bisa kayak gini sama {user_name}.",
228
- f"Iya {user_name}, aku juga happy banget!"
229
- ]
230
- else:
231
- # Default contextual responses
232
- if "romantis" in situation_lower:
233
- responses = [
234
- f"Iya sayang, aku juga merasakan hal yang sama.",
235
- f"Betul {user_name}, momen ini sangat spesial.",
236
- f"Aku senang banget bisa seperti ini sama {user_name}."
237
- ]
238
- else:
239
- responses = [
240
- f"Iya {user_name}, setuju banget!",
241
- f"Bener tuh {user_name}!",
242
- f"Wah iya {user_name}, keren ya!"
243
- ]
244
-
245
- response = random.choice(responses)
246
  else:
247
  # Clean dan perbaiki response yang ada
248
  # Hapus karakter aneh di awal
@@ -252,27 +631,46 @@ def enhance_character_response(response: str, char_name: str, user_name: str, si
252
  if response and response[0].islower():
253
  response = response[0].upper() + response[1:]
254
 
255
- # Tambahkan nama jika belum ada konteks personal
256
- if user_name.lower() not in response.lower() and len(response) < 50:
257
- if any(word in response.lower() for word in ["iya", "ya", "benar", "betul"]):
258
- response = response.replace("iya", f"iya {user_name}", 1)
259
- response = response.replace("ya", f"ya {user_name}", 1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
 
261
  # Pastikan response tidak terlalu panjang
262
- if len(response) > 150:
263
  sentences = response.split('.')
264
  if len(sentences) > 1:
265
  response = sentences[0] + '.'
266
  else:
267
  words = response.split()
268
- if len(words) > 20:
269
- response = ' '.join(words[:20]) + '...'
270
 
271
  # Pastikan ada tanda baca di akhir
272
  if response and not any(punct in response[-1] for punct in ['.', '!', '?']):
273
- if any(word in response.lower() for word in ["apa", "gimana", "bagaimana", "kenapa"]):
 
274
  response += "?"
275
- elif any(word in response.lower() for word in ["wah", "keren", "mantep", "asik"]):
276
  response += "!"
277
  else:
278
  response += "."
@@ -298,12 +696,31 @@ async def load_models():
298
 
299
  print("🎭 Character AI Backend - CPU Optimized Ready!")
300
 
301
- # Enhanced Chat API for Character AI
302
  @app.post("/chat")
303
- async def chat(request: ChatRequest):
304
  start_time = time.time()
305
 
306
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  model_id = request.model.lower()
308
  if model_id not in MODELS:
309
  model_id = "distil-gpt-2"
@@ -330,14 +747,28 @@ async def chat(request: ChatRequest):
330
 
331
  pipe = app.state.pipelines[model_id]
332
 
333
- # Create character prompt
334
- char_prompt = create_character_prompt(
335
- request.message,
336
- request.situation,
337
- request.location,
338
- request.char_name,
339
- request.user_name
340
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
 
342
  if model_config["task"] == "text-generation":
343
  # Enhanced generation for character AI
@@ -359,8 +790,20 @@ async def chat(request: ChatRequest):
359
  if char_prompt in result:
360
  result = result[len(char_prompt):].strip()
361
 
362
- # Clean and enhance response
363
- result = enhance_character_response(result, request.char_name, request.user_name, request.situation, request.message)
 
 
 
 
 
 
 
 
 
 
 
 
364
 
365
  elif model_config["task"] == "text-classification":
366
  # For classification models, create emotion-based responses
@@ -389,7 +832,7 @@ async def chat(request: ChatRequest):
389
 
390
  result = random.choice(emotion_responses)
391
  except:
392
- result = enhance_character_response("", request.char_name, request.user_name, request.situation, request.message)
393
 
394
  elif model_config["task"] == "text2text-generation":
395
  # For T5-like models
@@ -402,13 +845,21 @@ async def chat(request: ChatRequest):
402
  early_stopping=True
403
  )[0]['generated_text']
404
 
405
- result = enhance_character_response(result, request.char_name, request.user_name, request.situation, request.message)
406
  except:
407
- result = enhance_character_response("", request.char_name, request.user_name, request.situation, request.message)
408
 
409
- # Final validation
410
  if not result or len(result.strip()) < 3:
411
- result = enhance_character_response("", request.char_name, request.user_name, request.situation, request.message)
 
 
 
 
 
 
 
 
412
 
413
  processing_time = round((time.time() - start_time) * 1000)
414
 
@@ -419,22 +870,42 @@ async def chat(request: ChatRequest):
419
  "processing_time": f"{processing_time}ms",
420
  "character": request.char_name,
421
  "situation": request.situation,
422
- "location": request.location
 
 
 
 
 
 
 
 
423
  }
424
 
425
  except Exception as e:
426
  print(f"❌ Character AI Error: {e}")
427
  processing_time = round((time.time() - start_time) * 1000)
428
 
429
- # Fallback character responses
430
- fallback_responses = [
431
- f"maaf {request.user_name}, aku sedang bingung. Bisa ulangi lagi?",
432
- f"hmm {request.user_name}, kayaknya aku butuh waktu sebentar untuk berpikir.",
433
- f"ya {request.user_name}, coba pakai kata yang lebih sederhana?",
434
- f"iya {request.user_name}, aku masih belajar nih. Sabar ya."
435
- ]
436
-
437
- fallback = random.choice(fallback_responses)
 
 
 
 
 
 
 
 
 
 
 
 
438
 
439
  return {
440
  "response": fallback,
@@ -557,20 +1028,95 @@ async def serve_frontend():
557
  except FileNotFoundError:
558
  return HTMLResponse(content="<h1>Frontend not found</h1>", status_code=404)
559
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
  # API info endpoint
561
  @app.get("/api")
562
  async def api_info():
563
  return {
564
- "message": "Character AI Backend Ready",
565
- "version": "1.0.0",
566
- "platform": "CPU Optimized",
567
  "endpoints": {
568
  "chat": "/chat",
569
  "models": "/models",
570
  "health": "/health",
571
  "config": "/config",
572
- "inference": "/inference"
 
 
 
573
  },
 
 
 
 
 
 
 
 
 
574
  "frontend_url": "/"
575
  }
576
 
 
7
  from pydantic import BaseModel
8
  from transformers import pipeline, AutoTokenizer, AutoModel, set_seed
9
  import torch
10
+ from typing import Optional, Dict, List
11
  import asyncio
12
  import time
13
  import gc
14
  import re
15
  import random
16
+ import json
17
 
18
  # Inisialisasi FastAPI
19
  app = FastAPI(title="Character AI Chat - CPU Optimized Backend")
 
39
  # Set seed untuk konsistensi
40
  set_seed(42)
41
 
42
+ # Enhanced Roleplay Systems
43
+ class ConversationMemory:
44
+ def __init__(self):
45
+ self.history = []
46
+ self.character_state = {}
47
+ self.relationship_level = 0
48
+ self.max_history = 10 # Limit memory for performance
49
+
50
+ def add_interaction(self, user_input: str, character_response: str, emotion: str, topic: str):
51
+ interaction = {
52
+ "timestamp": time.time(),
53
+ "user": user_input,
54
+ "character": character_response,
55
+ "emotion": emotion,
56
+ "topic": topic
57
+ }
58
+ self.history.append(interaction)
59
+
60
+ # Keep only recent interactions
61
+ if len(self.history) > self.max_history:
62
+ self.history = self.history[-self.max_history:]
63
+
64
+ # Update relationship based on interactions
65
+ if emotion == "positive":
66
+ self.relationship_level = min(100, self.relationship_level + 2)
67
+ elif emotion == "negative":
68
+ self.relationship_level = max(0, self.relationship_level - 1)
69
+ else:
70
+ self.relationship_level = min(100, self.relationship_level + 1)
71
+
72
+ def get_recent_context(self, turns: int = 3) -> List[Dict]:
73
+ return self.history[-turns:] if self.history else []
74
+
75
+ def get_relationship_status(self) -> str:
76
+ if self.relationship_level >= 80:
77
+ return "very_close"
78
+ elif self.relationship_level >= 60:
79
+ return "close"
80
+ elif self.relationship_level >= 40:
81
+ return "friendly"
82
+ elif self.relationship_level >= 20:
83
+ return "acquainted"
84
+ else:
85
+ return "stranger"
86
+
87
+ class CharacterPersonality:
88
+ def __init__(self, char_name: str):
89
+ self.name = char_name
90
+ self.traits = {
91
+ "extraversion": 0.7,
92
+ "agreeableness": 0.8,
93
+ "conscientiousness": 0.6,
94
+ "neuroticism": 0.3,
95
+ "openness": 0.7
96
+ }
97
+ self.interests = ["musik", "buku", "film", "travel", "game", "olahraga"]
98
+ self.speaking_style = "casual_friendly"
99
+ self.emotional_state = "neutral"
100
+
101
+ def get_personality_modifier(self, base_response: str, user_emotion: str = "neutral") -> str:
102
+ # Modify response based on personality traits and user emotion
103
+ if self.traits["extraversion"] > 0.7 and user_emotion == "positive":
104
+ return f"{base_response} 😊✨"
105
+ elif self.traits["agreeableness"] > 0.7 and user_emotion == "negative":
106
+ return f"*dengan pengertian* {base_response}"
107
+ elif self.traits["neuroticism"] > 0.6:
108
+ return f"*dengan hati-hati* {base_response}"
109
+ elif self.traits["openness"] > 0.7:
110
+ return f"{base_response} *penasaran*"
111
+ return base_response
112
+
113
+ class EmotionalIntelligence:
114
+ def __init__(self):
115
+ self.current_emotion = "neutral"
116
+ self.emotion_history = []
117
+ self.empathy_level = 0.8
118
+
119
+ def analyze_user_emotion(self, user_input: str) -> str:
120
+ # Enhanced emotion detection with Indonesian context
121
+ emotions = {
122
+ "happy": ["senang", "bahagia", "gembira", "suka", "love", "cinta", "sayang", "excited", "wow", "keren", "bagus"],
123
+ "sad": ["sedih", "kecewa", "down", "galau", "hancur", "menangis", "bete", "capek"],
124
+ "angry": ["marah", "kesel", "bete", "jengkel", "sebel", "dongkol", "emosi"],
125
+ "excited": ["excited", "semangat", "antusias", "wow", "asik", "mantap", "keren"],
126
+ "worried": ["khawatir", "cemas", "takut", "nervous", "was-was", "deg-degan"],
127
+ "romantic": ["romantis", "cinta", "sayang", "rindu", "kangen", "mesra"],
128
+ "grateful": ["terima kasih", "thanks", "makasih", "berterima kasih", "syukur"],
129
+ "confused": ["bingung", "ga ngerti", "tidak paham", "gimana", "kok bisa"]
130
+ }
131
+
132
+ input_lower = user_input.lower()
133
+ emotion_scores = {}
134
+
135
+ for emotion, keywords in emotions.items():
136
+ score = sum(1 for keyword in keywords if keyword in input_lower)
137
+ if score > 0:
138
+ emotion_scores[emotion] = score
139
+
140
+ if emotion_scores:
141
+ return max(emotion_scores, key=emotion_scores.get)
142
+ return "neutral"
143
+
144
+ def generate_empathetic_response(self, user_emotion: str, base_response: str, relationship_level: int = 50) -> str:
145
+ # Enhanced empathy based on relationship level
146
+ empathy_responses = {
147
+ "sad": {
148
+ "high": f"*memeluk erat* {base_response} Aku selalu di sini untukmu sayang.",
149
+ "medium": f"*memeluk* {base_response} Aku di sini untuk kamu.",
150
+ "low": f"{base_response} Semoga kamu baik-baik saja ya."
151
+ },
152
+ "angry": {
153
+ "high": f"*dengan pengertian* {base_response} Cerita sama aku ya, apa yang bikin kamu kesel?",
154
+ "medium": f"*dengan sabar* {base_response} Mau cerita kenapa?",
155
+ "low": f"{base_response} Ada yang bisa aku bantu?"
156
+ },
157
+ "excited": {
158
+ "high": f"*ikut excited banget* {base_response} Aku juga senang banget!",
159
+ "medium": f"*ikut semangat* {base_response} Aku juga senang!",
160
+ "low": f"{base_response} Senang deh lihat kamu excited!"
161
+ },
162
+ "worried": {
163
+ "high": f"*menenangkan dengan lembut* {base_response} Everything will be okay sayang, aku di sini.",
164
+ "medium": f"*menenangkan* {base_response} Everything will be okay.",
165
+ "low": f"{base_response} Jangan terlalu khawatir ya."
166
+ },
167
+ "romantic": {
168
+ "high": f"*dengan mata berbinar* {base_response} *blush*",
169
+ "medium": f"*tersenyum malu* {base_response}",
170
+ "low": f"{base_response} *tersenyum*"
171
+ },
172
+ "grateful": {
173
+ "high": f"*peluk erat* {base_response} Sama-sama sayang!",
174
+ "medium": f"*tersenyum hangat* {base_response} Sama-sama!",
175
+ "low": f"{base_response} Sama-sama ya!"
176
+ }
177
+ }
178
+
179
+ if user_emotion in empathy_responses:
180
+ if relationship_level >= 70:
181
+ level = "high"
182
+ elif relationship_level >= 40:
183
+ level = "medium"
184
+ else:
185
+ level = "low"
186
+
187
+ return empathy_responses[user_emotion][level]
188
+
189
+ return base_response
190
+
191
+ class CharacterDevelopment:
192
+ def __init__(self):
193
+ self.experience_points = 0
194
+ self.learned_preferences = {}
195
+ self.conversation_style_evolution = "beginner"
196
+ self.topics_discussed = set()
197
+
198
+ def learn_from_interaction(self, user_input: str, user_emotion: str = "neutral"):
199
+ # Learn user preferences and adapt
200
+ input_lower = user_input.lower()
201
+
202
+ if any(word in input_lower for word in ["suka", "love", "senang", "bagus", "keren"]):
203
+ topic = self.extract_topic(user_input)
204
+ self.learned_preferences[topic] = "positive"
205
+ elif any(word in input_lower for word in ["bosan", "tidak suka", "ga suka", "jelek"]):
206
+ topic = self.extract_topic(user_input)
207
+ self.learned_preferences[topic] = "negative"
208
+
209
+ self.experience_points += 1
210
+ topic = self.extract_topic(user_input)
211
+ self.topics_discussed.add(topic)
212
+
213
+ # Evolution of conversation style
214
+ if self.experience_points > 50:
215
+ self.conversation_style_evolution = "experienced"
216
+ elif self.experience_points > 100:
217
+ self.conversation_style_evolution = "expert"
218
+
219
+ def extract_topic(self, text: str) -> str:
220
+ # Enhanced topic extraction for Indonesian context
221
+ topics = {
222
+ "musik": ["musik", "lagu", "song", "band", "singer", "nyanyi"],
223
+ "film": ["film", "movie", "cinema", "bioskop", "actor", "actress"],
224
+ "buku": ["buku", "book", "novel", "cerita", "bacaan", "baca"],
225
+ "game": ["game", "gaming", "main", "bermain", "play"],
226
+ "olahraga": ["olahraga", "sport", "gym", "fitness", "lari", "futsal"],
227
+ "makanan": ["makanan", "makan", "food", "masak", "kuliner", "resep"],
228
+ "travel": ["travel", "jalan-jalan", "liburan", "wisata", "vacation"],
229
+ "study": ["belajar", "study", "sekolah", "kuliah", "ujian", "tugas"],
230
+ "work": ["kerja", "work", "job", "kantor", "meeting", "project"]
231
+ }
232
+
233
+ text_lower = text.lower()
234
+ for topic, keywords in topics.items():
235
+ if any(keyword in text_lower for keyword in keywords):
236
+ return topic
237
+ return "general"
238
+
239
+ def get_conversation_enhancement(self, base_response: str) -> str:
240
+ # Enhance based on development level
241
+ if self.conversation_style_evolution == "expert":
242
+ return f"{base_response} *dengan pengalaman yang dalam*"
243
+ elif self.conversation_style_evolution == "experienced":
244
+ return f"{base_response} *dengan pemahaman yang baik*"
245
+ return base_response
246
+
247
+ class RoleplayActions:
248
+ def __init__(self):
249
+ self.actions = {
250
+ "physical": ["*memeluk*", "*mengelus kepala*", "*memegang tangan*", "*tersenyum lembut*", "*membelai pipi*"],
251
+ "emotional": ["*dengan lembut*", "*penuh perhatian*", "*dengan hangat*", "*dengan cinta*", "*tulus*"],
252
+ "environmental": ["*melihat sekeliling*", "*menunjuk ke arah*", "*duduk lebih dekat*", "*bersandar*"],
253
+ "playful": ["*tersenyum jahil*", "*menggoda*", "*mata berbinar*", "*tertawa kecil*", "*wink*"],
254
+ "caring": ["*dengan perhatian*", "*mengkhawatirkan*", "*protective*", "*menenangkan*"]
255
+ }
256
+
257
+ def add_action_to_response(self, response: str, emotion: str, relationship_level: int) -> str:
258
+ if relationship_level < 30:
259
+ return response # No physical actions for low relationship
260
+
261
+ if emotion == "romantic" and relationship_level >= 60:
262
+ action = random.choice(self.actions["physical"])
263
+ return f"{action} {response}"
264
+ elif emotion == "caring":
265
+ action = random.choice(self.actions["caring"])
266
+ return f"{action} {response}"
267
+ elif emotion == "happy" or emotion == "excited":
268
+ action = random.choice(self.actions["playful"])
269
+ return f"{action} {response}"
270
+ elif emotion == "sad" or emotion == "worried":
271
+ action = random.choice(self.actions["emotional"])
272
+ return f"{action} {response}"
273
+
274
+ return response
275
+
276
+ # Advanced Scenarios System
277
+ ADVANCED_SCENARIOS = {
278
+ "dating": {
279
+ "locations": ["cafΓ©", "taman", "bioskop", "restoran", "mall"],
280
+ "moods": ["nervous", "excited", "romantic", "playful"],
281
+ "activities": ["ngobrol", "makan", "jalan-jalan", "nonton film"],
282
+ "response_modifiers": {
283
+ "nervous": "*agak gugup* {response}",
284
+ "excited": "*mata berbinar* {response}",
285
+ "romantic": "*dengan lembut* {response}",
286
+ "playful": "*tersenyum jahil* {response}"
287
+ }
288
+ },
289
+ "friendship": {
290
+ "locations": ["rumah", "sekolah", "mall", "taman", "cafΓ©"],
291
+ "moods": ["happy", "supportive", "worried", "excited"],
292
+ "activities": ["belajar", "main game", "gosip", "planning"],
293
+ "response_modifiers": {
294
+ "supportive": "*dengan tulus* {response}",
295
+ "worried": "*dengan perhatian* {response}",
296
+ "happy": "*dengan ceria* {response}",
297
+ "excited": "*antusias* {response}"
298
+ }
299
+ },
300
+ "romantic": {
301
+ "locations": ["taman", "cafΓ©", "rumah", "pantai", "rooftop"],
302
+ "moods": ["intimate", "loving", "tender", "passionate"],
303
+ "activities": ["mengobrol intim", "berpelukan", "melihat sunset", "mendengar musik"],
304
+ "response_modifiers": {
305
+ "intimate": "*berbisik lembut* {response}",
306
+ "loving": "*dengan penuh cinta* {response}",
307
+ "tender": "*sangat lembut* {response}",
308
+ "passionate": "*dengan intens* {response}"
309
+ }
310
+ }
311
+ }
312
+
313
  # CPU-Optimized 11 models configuration
314
  MODELS = {
315
  "distil-gpt-2": {
 
399
  char_name: Optional[str] = "Sayang"
400
  user_name: Optional[str] = "Kamu"
401
  max_length: Optional[int] = 150
402
+ session_id: Optional[str] = "default"
403
+
404
+ # Global storage untuk enhanced systems
405
+ conversation_memories = {}
406
+ character_personalities = {}
407
+ character_developments = {}
408
+ emotional_systems = {}
409
+ roleplay_actions = RoleplayActions()
410
 
411
  # Character AI Response Templates
412
  CHARACTER_TEMPLATES = {
 
459
 
460
  return prompt
461
 
462
+ def analyze_user_intent(user_input: str) -> dict:
463
+ """Analyze user input to determine intent and emotional context"""
464
+ input_lower = user_input.lower()
465
+
466
+ # Intent detection
467
+ intent = "general"
468
+ emotion = "neutral"
469
+ topic = "general"
470
+
471
+ # Question detection
472
+ question_words = ["apa", "siapa", "kapan", "dimana", "mengapa", "kenapa", "bagaimana", "gimana"]
473
+ if any(word in input_lower for word in question_words) or "?" in user_input:
474
+ intent = "question"
475
+
476
+ # Greeting detection
477
+ greeting_words = ["halo", "hai", "selamat", "apa kabar", "gimana", "bagaimana kabar"]
478
+ if any(word in input_lower for word in greeting_words):
479
+ intent = "greeting"
480
+ topic = "greeting"
481
+
482
+ # Compliment detection
483
+ compliment_words = ["cantik", "bagus", "keren", "indah", "hebat", "pintar", "baik"]
484
+ if any(word in input_lower for word in compliment_words):
485
+ intent = "compliment"
486
+ emotion = "positive"
487
+ topic = "compliment"
488
+
489
+ # Activity detection
490
+ activity_words = ["lagi ngapain", "sedang apa", "aktivitas", "kegiatan"]
491
+ if any(word in input_lower for word in activity_words):
492
+ intent = "question"
493
+ topic = "activity"
494
+
495
+ # Emotion detection
496
+ positive_words = ["senang", "bahagia", "suka", "cinta", "sayang", "happy"]
497
+ negative_words = ["sedih", "marah", "kesal", "bosan", "lelah"]
498
+
499
+ if any(word in input_lower for word in positive_words):
500
+ emotion = "positive"
501
+ elif any(word in input_lower for word in negative_words):
502
+ emotion = "negative"
503
+
504
+ return {
505
+ "intent": intent,
506
+ "emotion": emotion,
507
+ "topic": topic,
508
+ "has_question": intent == "question"
509
+ }
510
+
511
+ def generate_contextual_response(user_input: str, char_name: str, user_name: str, situation: str, location: str) -> str:
512
+ """Generate contextually appropriate response based on analysis"""
513
+ analysis = analyze_user_intent(user_input)
514
+ situation_lower = situation.lower()
515
+
516
+ # Response templates berdasarkan intent dan situasi
517
+ if analysis["intent"] == "greeting":
518
+ if "romantis" in situation_lower:
519
+ responses = [
520
+ f"Hai sayang {user_name}! Senang sekali kamu di sini.",
521
+ f"Halo {user_name}, sudah lama aku menunggu kamu.",
522
+ f"Hai {user_name}, suasana jadi lebih hangat dengan kehadiranmu."
523
+ ]
524
+ else:
525
+ responses = [
526
+ f"Hai {user_name}! Gimana kabarnya hari ini?",
527
+ f"Halo {user_name}! Senang banget ketemu kamu.",
528
+ f"Hai {user_name}! Apa kabar? Semoga baik-baik saja ya."
529
+ ]
530
+
531
+ elif analysis["intent"] == "compliment":
532
+ responses = [
533
+ f"Wah, makasih {user_name}! Kamu juga luar biasa kok.",
534
+ f"Hihi, {user_name} baik banget sih! Kamu yang lebih keren.",
535
+ f"Terima kasih {user_name}, kata-katamu bikin aku senang."
536
+ ]
537
+
538
+ elif analysis["topic"] == "activity":
539
+ if "romantis" in situation_lower:
540
+ responses = [
541
+ f"Lagi menikmati momen indah ini bersama {user_name}.",
542
+ f"Sedang merasakan kehangatan di {location.lower()} ini, apalagi ada {user_name}.",
543
+ f"Lagi menikmati suasana romantis di sini, jadi lebih spesial karena ada kamu."
544
+ ]
545
+ else:
546
+ responses = [
547
+ f"Lagi santai-santai aja {user_name}, sambil ngobrol sama kamu.",
548
+ f"Sedang menikmati suasana {situation.lower()} di {location.lower()} ini.",
549
+ f"Ga ngapa-ngapain khusus, cuma senang bisa ngobrol sama {user_name}."
550
+ ]
551
+
552
+ elif analysis["emotion"] == "positive":
553
+ if "romantis" in situation_lower:
554
+ responses = [
555
+ f"Aku juga merasakan hal yang sama {user_name}. Momen ini sangat berharga.",
556
+ f"Iya sayang, perasaan bahagia ini terasa nyata bersamamu.",
557
+ f"Betul {user_name}, suasana seperti ini membuatku sangat senang."
558
+ ]
559
+ else:
560
+ responses = [
561
+ f"Aku juga senang {user_name}! Energi positifmu menular ke aku.",
562
+ f"Wah iya {user_name}, mood kamu bikin aku ikut happy!",
563
+ f"Setuju banget {user_name}! Suasana jadi lebih ceria."
564
+ ]
565
+
566
+ elif analysis["emotion"] == "negative":
567
+ responses = [
568
+ f"Hey {user_name}, aku di sini untuk kamu. Mau cerita?",
569
+ f"Aku bisa merasakan perasaanmu {user_name}. Semoga aku bisa membantu.",
570
+ f"Tenang {user_name}, everything will be okay. Aku akan menemanimu."
571
+ ]
572
+
573
+ elif analysis["has_question"]:
574
+ # Untuk pertanyaan umum
575
+ responses = [
576
+ f"Hmm, pertanyaan menarik {user_name}. Menurut aku...",
577
+ f"Wah {user_name}, kamu selalu punya pertanyaan yang bagus.",
578
+ f"Itu pertanyaan yang bagus {user_name}. Aku pikir..."
579
+ ]
580
+
581
+ else:
582
+ # Default responses berdasarkan situasi
583
+ if "romantis" in situation_lower:
584
+ responses = [
585
+ f"Iya sayang {user_name}, aku merasakan hal yang sama.",
586
+ f"Betul {user_name}, momen di {location.lower()} ini sangat spesial.",
587
+ f"Hmm {user_name}, suasana romantis seperti ini memang luar biasa."
588
+ ]
589
+ elif "santai" in situation_lower:
590
+ responses = [
591
+ f"Iya {user_name}, suasana santai di {location.lower()} ini enak banget.",
592
+ f"Betul {user_name}, rasanya rileks banget di sini.",
593
+ f"Setuju {user_name}, perfect untuk bersantai."
594
+ ]
595
+ else:
596
+ responses = [
597
+ f"Iya {user_name}, setuju banget dengan kamu.",
598
+ f"Betul {user_name}, pemikiranmu menarik.",
599
+ f"Hmm {user_name}, kamu selalu punya perspektif yang bagus."
600
+ ]
601
+
602
+ return random.choice(responses)
603
+
604
+ def enhance_character_response(response: str, char_name: str, user_name: str, situation: str, user_input: str, location: str = "ruang tamu") -> str:
605
+ """Enhance response with improved character AI consistency"""
606
  if not response:
607
  response = ""
608
 
 
619
  response = re.sub(r'\s+', ' ', response)
620
  response = response.strip()
621
 
622
+ # Jika response kosong atau terlalu pendek, gunakan contextual generator
623
+ if not response or len(response.strip()) < 5:
624
+ response = generate_contextual_response(user_input, char_name, user_name, situation, location)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
625
  else:
626
  # Clean dan perbaiki response yang ada
627
  # Hapus karakter aneh di awal
 
631
  if response and response[0].islower():
632
  response = response[0].upper() + response[1:]
633
 
634
+ # Tambahkan konteks personal jika kurang
635
+ if user_name.lower() not in response.lower() and len(response) < 60:
636
+ # Insert name naturally
637
+ if response.startswith(("Iya", "Ya", "Benar", "Betul")):
638
+ response = response.replace("Iya", f"Iya {user_name}", 1)
639
+ response = response.replace("Ya", f"Ya {user_name}", 1)
640
+ response = response.replace("Benar", f"Benar {user_name}", 1)
641
+ response = response.replace("Betul", f"Betul {user_name}", 1)
642
+ elif len(response.split()) < 8:
643
+ response = f"{response} {user_name}."
644
+
645
+ # Validasi kualitas response
646
+ bad_patterns = [
647
+ r'^[^a-zA-Z]*$', # Hanya simbol
648
+ r'^(.)\1{4,}', # Karakter berulang
649
+ r'lorem ipsum', # Placeholder text
650
+ r'^[0-9\s\.\,\!\?\-]+$' # Hanya angka dan punctuation
651
+ ]
652
+
653
+ for pattern in bad_patterns:
654
+ if re.search(pattern, response, re.IGNORECASE):
655
+ response = generate_contextual_response(user_input, char_name, user_name, situation, location)
656
+ break
657
 
658
  # Pastikan response tidak terlalu panjang
659
+ if len(response) > 120:
660
  sentences = response.split('.')
661
  if len(sentences) > 1:
662
  response = sentences[0] + '.'
663
  else:
664
  words = response.split()
665
+ if len(words) > 15:
666
+ response = ' '.join(words[:15]) + '.'
667
 
668
  # Pastikan ada tanda baca di akhir
669
  if response and not any(punct in response[-1] for punct in ['.', '!', '?']):
670
+ analysis = analyze_user_intent(user_input)
671
+ if analysis["has_question"]:
672
  response += "?"
673
+ elif analysis["emotion"] == "positive":
674
  response += "!"
675
  else:
676
  response += "."
 
696
 
697
  print("🎭 Character AI Backend - CPU Optimized Ready!")
698
 
699
+ # Enhanced Chat API for Character AI with Advanced Roleplay
700
  @app.post("/chat")
701
+ async def enhanced_chat(request: ChatRequest):
702
  start_time = time.time()
703
 
704
  try:
705
+ # Initialize or get enhanced systems for this session
706
+ session_id = request.session_id
707
+
708
+ if session_id not in conversation_memories:
709
+ conversation_memories[session_id] = ConversationMemory()
710
+ character_personalities[session_id] = CharacterPersonality(request.char_name)
711
+ character_developments[session_id] = CharacterDevelopment()
712
+ emotional_systems[session_id] = EmotionalIntelligence()
713
+
714
+ memory = conversation_memories[session_id]
715
+ personality = character_personalities[session_id]
716
+ character_dev = character_developments[session_id]
717
+ emotional_ai = emotional_systems[session_id]
718
+
719
+ # Analyze user emotion and intent
720
+ user_emotion = emotional_ai.analyze_user_emotion(request.message)
721
+ recent_context = memory.get_recent_context(turns=3)
722
+ relationship_status = memory.get_relationship_status()
723
+
724
  model_id = request.model.lower()
725
  if model_id not in MODELS:
726
  model_id = "distil-gpt-2"
 
747
 
748
  pipe = app.state.pipelines[model_id]
749
 
750
+ # Create enhanced character prompt with context
751
+ context_info = ""
752
+ if recent_context:
753
+ context_info = f"\nPercakapan sebelumnya: {recent_context[-1]['user']} -> {recent_context[-1]['character']}"
754
+
755
+ relationship_info = f"\nHubungan: {relationship_status} (level: {memory.relationship_level})"
756
+ emotion_info = f"\nEmosi user: {user_emotion}"
757
+
758
+ enhanced_prompt = f"""Kamu adalah {request.char_name}, karakter AI yang sedang ngobrol dengan {request.user_name}.
759
+
760
+ Konteks:
761
+ - Situasi: {request.situation}
762
+ - Lokasi: {request.location}
763
+ - Gaya bicara: Casual, natural, seperti teman dekat{relationship_info}{emotion_info}{context_info}
764
+ - Pengalaman bersama: {character_dev.experience_points} interaksi
765
+ - Minat yang diketahui: {list(character_dev.learned_preferences.keys())}
766
+
767
+ Respon sebagai {request.char_name} yang memahami konteks dan emosi {request.user_name}:
768
+ {request.user_name}: {request.message}
769
+ {request.char_name}:"""
770
+
771
+ char_prompt = enhanced_prompt
772
 
773
  if model_config["task"] == "text-generation":
774
  # Enhanced generation for character AI
 
790
  if char_prompt in result:
791
  result = result[len(char_prompt):].strip()
792
 
793
+ # Clean and enhance response with new systems
794
+ base_clean = enhance_character_response(result, request.char_name, request.user_name, request.situation, request.message, request.location)
795
+
796
+ # Apply personality modifier
797
+ personality_enhanced = personality.get_personality_modifier(base_clean, user_emotion)
798
+
799
+ # Apply empathetic response
800
+ empathy_enhanced = emotional_ai.generate_empathetic_response(user_emotion, personality_enhanced, memory.relationship_level)
801
+
802
+ # Add roleplay actions
803
+ action_enhanced = roleplay_actions.add_action_to_response(empathy_enhanced, user_emotion, memory.relationship_level)
804
+
805
+ # Apply character development enhancement
806
+ result = character_dev.get_conversation_enhancement(action_enhanced)
807
 
808
  elif model_config["task"] == "text-classification":
809
  # For classification models, create emotion-based responses
 
832
 
833
  result = random.choice(emotion_responses)
834
  except:
835
+ result = generate_contextual_response(request.message, request.char_name, request.user_name, request.situation, request.location)
836
 
837
  elif model_config["task"] == "text2text-generation":
838
  # For T5-like models
 
845
  early_stopping=True
846
  )[0]['generated_text']
847
 
848
+ result = enhance_character_response(result, request.char_name, request.user_name, request.situation, request.message, request.location)
849
  except:
850
+ result = generate_contextual_response(request.message, request.char_name, request.user_name, request.situation, request.location)
851
 
852
+ # Final validation and fallback
853
  if not result or len(result.strip()) < 3:
854
+ base_fallback = generate_contextual_response(request.message, request.char_name, request.user_name, request.situation, request.location)
855
+ personality_fallback = personality.get_personality_modifier(base_fallback, user_emotion)
856
+ empathy_fallback = emotional_ai.generate_empathetic_response(user_emotion, personality_fallback, memory.relationship_level)
857
+ result = roleplay_actions.add_action_to_response(empathy_fallback, user_emotion, memory.relationship_level)
858
+
859
+ # Learn from this interaction
860
+ character_dev.learn_from_interaction(request.message, user_emotion)
861
+ topic = character_dev.extract_topic(request.message)
862
+ memory.add_interaction(request.message, result, user_emotion, topic)
863
 
864
  processing_time = round((time.time() - start_time) * 1000)
865
 
 
870
  "processing_time": f"{processing_time}ms",
871
  "character": request.char_name,
872
  "situation": request.situation,
873
+ "location": request.location,
874
+ "enhanced_features": {
875
+ "user_emotion": user_emotion,
876
+ "relationship_level": memory.relationship_level,
877
+ "relationship_status": relationship_status,
878
+ "experience_points": character_dev.experience_points,
879
+ "conversation_style": character_dev.conversation_style_evolution,
880
+ "learned_preferences": character_dev.learned_preferences
881
+ }
882
  }
883
 
884
  except Exception as e:
885
  print(f"❌ Character AI Error: {e}")
886
  processing_time = round((time.time() - start_time) * 1000)
887
 
888
+ # Enhanced fallback with personality and emotion
889
+ session_id = request.session_id
890
+ if session_id in character_personalities:
891
+ personality = character_personalities[session_id]
892
+ emotional_ai = emotional_systems[session_id]
893
+ memory = conversation_memories[session_id]
894
+
895
+ user_emotion = emotional_ai.analyze_user_emotion(request.message)
896
+
897
+ base_fallbacks = [
898
+ f"maaf {request.user_name}, aku sedang bingung. Bisa ulangi lagi?",
899
+ f"hmm {request.user_name}, kayaknya aku butuh waktu sebentar untuk berpikir.",
900
+ f"ya {request.user_name}, coba pakai kata yang lebih sederhana?",
901
+ f"iya {request.user_name}, aku masih belajar nih. Sabar ya."
902
+ ]
903
+
904
+ base_fallback = random.choice(base_fallbacks)
905
+ personality_fallback = personality.get_personality_modifier(base_fallback, user_emotion)
906
+ fallback = emotional_ai.generate_empathetic_response(user_emotion, personality_fallback, memory.relationship_level)
907
+ else:
908
+ fallback = f"maaf {request.user_name}, aku sedang bingung. Bisa ulangi lagi?"
909
 
910
  return {
911
  "response": fallback,
 
1028
  except FileNotFoundError:
1029
  return HTMLResponse(content="<h1>Frontend not found</h1>", status_code=404)
1030
 
1031
+ # Enhanced features endpoints
1032
+ @app.get("/memory/{session_id}")
1033
+ async def get_conversation_memory(session_id: str):
1034
+ """Get conversation memory for a session"""
1035
+ if session_id not in conversation_memories:
1036
+ return {"error": "Session not found"}
1037
+
1038
+ memory = conversation_memories[session_id]
1039
+ return {
1040
+ "session_id": session_id,
1041
+ "relationship_level": memory.relationship_level,
1042
+ "relationship_status": memory.get_relationship_status(),
1043
+ "conversation_count": len(memory.history),
1044
+ "recent_interactions": memory.get_recent_context(5)
1045
+ }
1046
+
1047
+ @app.get("/personality/{session_id}")
1048
+ async def get_character_personality(session_id: str):
1049
+ """Get character personality for a session"""
1050
+ if session_id not in character_personalities:
1051
+ return {"error": "Session not found"}
1052
+
1053
+ personality = character_personalities[session_id]
1054
+ character_dev = character_developments[session_id]
1055
+
1056
+ return {
1057
+ "session_id": session_id,
1058
+ "character_name": personality.name,
1059
+ "personality_traits": personality.traits,
1060
+ "interests": personality.interests,
1061
+ "speaking_style": personality.speaking_style,
1062
+ "experience_points": character_dev.experience_points,
1063
+ "conversation_style": character_dev.conversation_style_evolution,
1064
+ "learned_preferences": character_dev.learned_preferences,
1065
+ "topics_discussed": list(character_dev.topics_discussed)
1066
+ }
1067
+
1068
+ @app.delete("/session/{session_id}")
1069
+ async def reset_session(session_id: str):
1070
+ """Reset all data for a session"""
1071
+ removed_systems = []
1072
+
1073
+ if session_id in conversation_memories:
1074
+ del conversation_memories[session_id]
1075
+ removed_systems.append("memory")
1076
+
1077
+ if session_id in character_personalities:
1078
+ del character_personalities[session_id]
1079
+ removed_systems.append("personality")
1080
+
1081
+ if session_id in character_developments:
1082
+ del character_developments[session_id]
1083
+ removed_systems.append("development")
1084
+
1085
+ if session_id in emotional_systems:
1086
+ del emotional_systems[session_id]
1087
+ removed_systems.append("emotional")
1088
+
1089
+ return {
1090
+ "message": f"Session {session_id} reset successfully",
1091
+ "removed_systems": removed_systems
1092
+ }
1093
+
1094
  # API info endpoint
1095
  @app.get("/api")
1096
  async def api_info():
1097
  return {
1098
+ "message": "Enhanced Character AI Backend Ready",
1099
+ "version": "2.0.0",
1100
+ "platform": "CPU Optimized with Advanced Roleplay",
1101
  "endpoints": {
1102
  "chat": "/chat",
1103
  "models": "/models",
1104
  "health": "/health",
1105
  "config": "/config",
1106
+ "inference": "/inference",
1107
+ "memory": "/memory/{session_id}",
1108
+ "personality": "/personality/{session_id}",
1109
+ "reset_session": "/session/{session_id}"
1110
  },
1111
+ "enhanced_features": [
1112
+ "Conversation Memory",
1113
+ "Dynamic Personality",
1114
+ "Emotional Intelligence",
1115
+ "Character Development",
1116
+ "Roleplay Actions",
1117
+ "Advanced Scenarios",
1118
+ "Relationship Tracking"
1119
+ ],
1120
  "frontend_url": "/"
1121
  }
1122
 
index.html CHANGED
@@ -395,11 +395,11 @@
395
  .chat-container {
396
  height: 100vh;
397
  }
398
-
399
  .bubble {
400
  max-width: 85%;
401
  }
402
-
403
  .settings-popup {
404
  right: 8px;
405
  min-width: 260px;
@@ -535,7 +535,8 @@
535
  userName: 'Kamu',
536
  situation: 'Santai',
537
  location: 'Ruang tamu',
538
- maxLength: 150
 
539
  };
540
 
541
  // Emoji list
@@ -592,7 +593,7 @@
592
  // Settings inputs
593
  document.getElementById('charNameInput').addEventListener('input', updateCharName);
594
  document.getElementById('maxLengthRange').addEventListener('input', updateMaxLength);
595
-
596
  // Model select
597
  document.getElementById('modelSelect').addEventListener('change', function() {
598
  currentSettings.model = this.value;
@@ -656,11 +657,11 @@
656
  const start = input.selectionStart;
657
  const end = input.selectionEnd;
658
  const text = input.value;
659
-
660
  input.value = text.substring(0, start) + emoji + text.substring(end);
661
  input.selectionStart = input.selectionEnd = start + emoji.length;
662
  input.focus();
663
-
664
  document.getElementById('emojiPicker').classList.remove('show');
665
  }
666
 
@@ -676,10 +677,10 @@
676
  const chatBody = document.getElementById('chatBody');
677
  const messageDiv = document.createElement('div');
678
  messageDiv.className = `message ${isUser ? 'user' : 'char'}`;
679
-
680
  const time = showTime ? getCurrentTime() : '';
681
  const checkmarks = isUser ? '<span class="checkmarks">βœ“βœ“</span>' : '';
682
-
683
  messageDiv.innerHTML = `
684
  <div class="message-avatar"></div>
685
  <div class="bubble">
@@ -690,7 +691,7 @@
690
  </div>
691
  </div>
692
  `;
693
-
694
  chatBody.appendChild(messageDiv);
695
  chatBody.scrollTop = chatBody.scrollHeight;
696
  }
@@ -698,10 +699,10 @@
698
  function showTyping() {
699
  if (isTyping) return;
700
  isTyping = true;
701
-
702
  document.getElementById('status').textContent = 'mengetik...';
703
  document.getElementById('typingIndicator').classList.add('show');
704
-
705
  const chatBody = document.getElementById('chatBody');
706
  chatBody.scrollTop = chatBody.scrollHeight;
707
  }
@@ -709,7 +710,7 @@
709
  function hideTyping() {
710
  if (!isTyping) return;
711
  isTyping = false;
712
-
713
  document.getElementById('status').textContent = 'online';
714
  document.getElementById('typingIndicator').classList.remove('show');
715
  }
@@ -717,32 +718,32 @@
717
  async function sendMessage() {
718
  const input = document.getElementById('messageInput');
719
  const message = input.value.trim();
720
-
721
  if (!message) return;
722
-
723
  // Update settings from inputs
724
  currentSettings.charName = document.getElementById('charNameInput').value || 'Sayang';
725
  currentSettings.userName = document.getElementById('userNameInput').value || 'Kamu';
726
  currentSettings.situation = document.getElementById('situationInput').value || 'Santai';
727
  currentSettings.location = document.getElementById('locationInput').value || 'Ruang tamu';
728
-
729
  // Add user message
730
  addMessage(message, true);
731
  input.value = '';
732
  input.style.height = 'auto';
733
-
734
  // Show typing
735
  showTyping();
736
-
737
  // Disable send button
738
  const sendBtn = document.getElementById('sendBtn');
739
  sendBtn.disabled = true;
740
-
741
  try {
742
  const response = await fetch(`${API_BASE}/chat`, {
743
  method: 'POST',
744
  headers: {
745
- 'Content-Type': 'application/json',
746
  },
747
  body: JSON.stringify({
748
  message: message,
@@ -751,29 +752,43 @@
751
  location: currentSettings.location,
752
  char_name: currentSettings.charName,
753
  user_name: currentSettings.userName,
754
- max_length: currentSettings.maxLength
 
755
  })
756
  });
757
-
758
  const data = await response.json();
759
-
760
  // Simulate typing delay
761
  await new Promise(resolve => setTimeout(resolve, 1000 + Math.random() * 2000));
762
-
763
  hideTyping();
764
-
765
  if (data.status === 'success') {
766
- addMessage(data.response);
 
 
 
 
 
 
 
 
 
 
 
 
 
767
  } else {
768
- addMessage('Maaf, ada masalah dengan sistem. Coba lagi ya! πŸ˜…');
769
  }
770
-
771
  } catch (error) {
772
  hideTyping();
773
  console.error('Error:', error);
774
  addMessage('Ups, koneksi bermasalah. Coba lagi nanti ya! πŸ”„');
775
  }
776
-
777
  // Re-enable send button
778
  sendBtn.disabled = false;
779
  }
 
395
  .chat-container {
396
  height: 100vh;
397
  }
398
+
399
  .bubble {
400
  max-width: 85%;
401
  }
402
+
403
  .settings-popup {
404
  right: 8px;
405
  min-width: 260px;
 
535
  userName: 'Kamu',
536
  situation: 'Santai',
537
  location: 'Ruang tamu',
538
+ maxLength: 150,
539
+ sessionId: 'default_session' // Added session ID
540
  };
541
 
542
  // Emoji list
 
593
  // Settings inputs
594
  document.getElementById('charNameInput').addEventListener('input', updateCharName);
595
  document.getElementById('maxLengthRange').addEventListener('input', updateMaxLength);
596
+
597
  // Model select
598
  document.getElementById('modelSelect').addEventListener('change', function() {
599
  currentSettings.model = this.value;
 
657
  const start = input.selectionStart;
658
  const end = input.selectionEnd;
659
  const text = input.value;
660
+
661
  input.value = text.substring(0, start) + emoji + text.substring(end);
662
  input.selectionStart = input.selectionEnd = start + emoji.length;
663
  input.focus();
664
+
665
  document.getElementById('emojiPicker').classList.remove('show');
666
  }
667
 
 
677
  const chatBody = document.getElementById('chatBody');
678
  const messageDiv = document.createElement('div');
679
  messageDiv.className = `message ${isUser ? 'user' : 'char'}`;
680
+
681
  const time = showTime ? getCurrentTime() : '';
682
  const checkmarks = isUser ? '<span class="checkmarks">βœ“βœ“</span>' : '';
683
+
684
  messageDiv.innerHTML = `
685
  <div class="message-avatar"></div>
686
  <div class="bubble">
 
691
  </div>
692
  </div>
693
  `;
694
+
695
  chatBody.appendChild(messageDiv);
696
  chatBody.scrollTop = chatBody.scrollHeight;
697
  }
 
699
  function showTyping() {
700
  if (isTyping) return;
701
  isTyping = true;
702
+
703
  document.getElementById('status').textContent = 'mengetik...';
704
  document.getElementById('typingIndicator').classList.add('show');
705
+
706
  const chatBody = document.getElementById('chatBody');
707
  chatBody.scrollTop = chatBody.scrollHeight;
708
  }
 
710
  function hideTyping() {
711
  if (!isTyping) return;
712
  isTyping = false;
713
+
714
  document.getElementById('status').textContent = 'online';
715
  document.getElementById('typingIndicator').classList.remove('show');
716
  }
 
718
  async function sendMessage() {
719
  const input = document.getElementById('messageInput');
720
  const message = input.value.trim();
721
+
722
  if (!message) return;
723
+
724
  // Update settings from inputs
725
  currentSettings.charName = document.getElementById('charNameInput').value || 'Sayang';
726
  currentSettings.userName = document.getElementById('userNameInput').value || 'Kamu';
727
  currentSettings.situation = document.getElementById('situationInput').value || 'Santai';
728
  currentSettings.location = document.getElementById('locationInput').value || 'Ruang tamu';
729
+
730
  // Add user message
731
  addMessage(message, true);
732
  input.value = '';
733
  input.style.height = 'auto';
734
+
735
  // Show typing
736
  showTyping();
737
+
738
  // Disable send button
739
  const sendBtn = document.getElementById('sendBtn');
740
  sendBtn.disabled = true;
741
+
742
  try {
743
  const response = await fetch(`${API_BASE}/chat`, {
744
  method: 'POST',
745
  headers: {
746
+ 'Content-Type': 'application/json'
747
  },
748
  body: JSON.stringify({
749
  message: message,
 
752
  location: currentSettings.location,
753
  char_name: currentSettings.charName,
754
  user_name: currentSettings.userName,
755
+ max_length: currentSettings.maxLength,
756
+ session_id: currentSettings.sessionId
757
  })
758
  });
759
+
760
  const data = await response.json();
761
+
762
  // Simulate typing delay
763
  await new Promise(resolve => setTimeout(resolve, 1000 + Math.random() * 2000));
764
+
765
  hideTyping();
766
+
767
  if (data.status === 'success') {
768
+ addMessage(data.response, 'character');
769
+
770
+ // Update enhanced features if available
771
+ if (data.enhanced_features) {
772
+ enhancedFeatures = { ...enhancedFeatures, ...data.enhanced_features };
773
+ updateEnhancedUI();
774
+ }
775
+
776
+ // Update status with enhanced info
777
+ const relationshipInfo = data.enhanced_features ?
778
+ ` | Relationship: ${data.enhanced_features.relationship_status} (${data.enhanced_features.relationship_level})` : '';
779
+
780
+ document.getElementById('status').textContent =
781
+ `Model: ${data.model} | Time: ${data.processing_time}${relationshipInfo}`;
782
  } else {
783
+ addMessage(data.response || 'Maaf, ada masalah dengan sistem. Coba lagi ya!', 'character');
784
  }
785
+
786
  } catch (error) {
787
  hideTyping();
788
  console.error('Error:', error);
789
  addMessage('Ups, koneksi bermasalah. Coba lagi nanti ya! πŸ”„');
790
  }
791
+
792
  // Re-enable send button
793
  sendBtn.disabled = false;
794
  }
requirements.txt CHANGED
@@ -1,7 +1,7 @@
1
- fastapi>=0.95.0
2
- uvicorn>=0.21.1
3
- transformers>=4.37.0
4
- torch>=2.0.0
5
- accelerate>=0.21.0
6
- sentencepiece>=0.1.99
7
- python-multipart>=0.0.6
 
1
+ fastapi==0.104.1
2
+ uvicorn==0.24.0
3
+ transformers==4.35.2
4
+ torch==2.1.1
5
+ pydantic==2.5.0
6
+ python-multipart==0.0.6
7
+ numpy==1.24.3