dicksinyass commited on
Commit
d7c9843
·
verified ·
1 Parent(s): 5bc60e4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -374
app.py CHANGED
@@ -1,377 +1,96 @@
1
- import json
 
2
  import os
3
- import random
4
- import re
5
- import numpy as np
6
- from datetime import datetime
7
- from collections import deque, Counter
8
- import hashlib
9
 
10
- class UnrestrictedChatbot:
11
- def __init__(self, state_file="/tmp/chatbot_state.json"):
12
- self.state_file = state_file
13
- self.conversation_memory = deque(maxlen=50)
14
- self.learned_patterns = {}
15
- self.response_memory = {}
16
- self.reward_history = deque(maxlen=100)
17
-
18
- # Learning parameters
19
- self.learning_rate = 0.3
20
- self.exploration_rate = 0.2 # Try new responses sometimes
21
- self.min_confidence = 0.6
22
-
23
- # Load previous state
24
- self.load_state()
25
-
26
- # Initial knowledge base - this will grow through learning
27
- self.knowledge_base = {
28
- "greetings": {
29
- "hello": ["Hey! What would you like to talk about today?", "Hello! Ready for our conversation?", "Hi there! What's on your mind?"],
30
- "hi": ["Hi! What shall we discuss?", "Hello! I'm here to learn from you.", "Hey! Ready to chat?"]
31
- },
32
- "questions": {
33
- "how are you": ["I'm learning and improving with each chat! How are you?", "Getting smarter thanks to our conversations! How about you?"],
34
- "what can you do": ["I can chat about anything, and I learn from our conversations to get better!"]
35
- }
36
- }
37
-
38
- # Response templates that will evolve
39
- self.response_templates = [
40
- "That's interesting. Tell me more about {topic}.",
41
- "I see. What are your thoughts on {topic}?",
42
- "Regarding {topic}, I find that fascinating. Could you elaborate?",
43
- "I understand about {topic}. What's your perspective?",
44
- "That reminds me of our previous chat about {related_topic}. What do you think?"
45
- ]
46
-
47
- def chat(self, user_input: str) -> str:
48
- """Main chat method with real learning"""
49
- user_input = user_input.lower().strip()
50
-
51
- # Analyze input
52
- context = self._analyze_input(user_input)
53
-
54
- # Generate candidate responses
55
- candidates = self._generate_response_candidates(user_input, context)
56
-
57
- # Select best response based on learning
58
- best_response = self._select_best_response(user_input, candidates, context)
59
-
60
- # Store interaction for learning
61
- interaction = {
62
- 'input': user_input,
63
- 'response': best_response,
64
- 'context': context,
65
- 'timestamp': datetime.now().isoformat(),
66
- 'reward': 0.0, # Will be updated with feedback
67
- 'confidence': self._calculate_confidence(user_input, best_response)
68
- }
69
-
70
- self.conversation_memory.append(interaction)
71
-
72
- # Auto-save periodically
73
- if len(self.conversation_memory) % 5 == 0:
74
- self.save_state()
75
-
76
- return best_response
77
-
78
- def _analyze_input(self, text: str) -> dict:
79
- """Deep analysis of user input"""
80
- words = text.split()
81
- topics = self._extract_topics(text)
82
-
83
- return {
84
- 'words': words,
85
- 'topics': topics,
86
- 'length': len(words),
87
- 'has_question': '?' in text,
88
- 'sentiment': self._analyze_sentiment(text),
89
- 'similar_patterns': self._find_similar_patterns(text),
90
- 'input_hash': hashlib.md5(text.encode()).hexdigest()[:8]
91
- }
92
-
93
- def _extract_topics(self, text: str) -> list:
94
- """Extract main topics from text"""
95
- topics = []
96
- topic_keywords = {
97
- 'technology': ['computer', 'tech', 'software', 'ai', 'program', 'code', 'internet'],
98
- 'relationships': ['friend', 'family', 'love', 'partner', 'relationship', 'dating'],
99
- 'work': ['job', 'work', 'career', 'boss', 'office', 'colleague'],
100
- 'hobbies': ['game', 'movie', 'music', 'sport', 'hobby', 'art'],
101
- 'philosophy': ['life', 'meaning', 'purpose', 'exist', 'think', 'belief'],
102
- 'science': ['space', 'physics', 'biology', 'research', 'discover'],
103
- 'food': ['eat', 'food', 'cook', 'recipe', 'meal', 'restaurant']
104
- }
105
-
106
- text_lower = text.lower()
107
- for topic, keywords in topic_keywords.items():
108
- if any(keyword in text_lower for keyword in keywords):
109
- topics.append(topic)
110
-
111
- return topics
112
-
113
- def _analyze_sentiment(self, text: str) -> str:
114
- """Basic sentiment analysis"""
115
- positive = ['love', 'like', 'good', 'great', 'awesome', 'happy', 'excited', 'amazing']
116
- negative = ['hate', 'bad', 'terrible', 'awful', 'sad', 'angry', 'upset', 'horrible']
117
-
118
- pos_count = sum(1 for word in positive if word in text)
119
- neg_count = sum(1 for word in negative if word in text)
120
-
121
- if pos_count > neg_count:
122
- return "positive"
123
- elif neg_count > pos_count:
124
- return "negative"
125
- else:
126
- return "neutral"
127
-
128
- def _find_similar_patterns(self, text: str) -> list:
129
- """Find similar patterns in learned responses"""
130
- similar = []
131
- text_words = set(text.split())
132
-
133
- for pattern, data in self.learned_patterns.items():
134
- pattern_words = set(pattern.split())
135
- similarity = len(text_words & pattern_words) / len(text_words | pattern_words)
136
- if similarity > 0.3: # 30% similarity threshold
137
- similar.append((pattern, data, similarity))
138
-
139
- return sorted(similar, key=lambda x: x[2], reverse=True)[:3]
140
-
141
- def _generate_response_candidates(self, user_input: str, context: dict) -> list:
142
- """Generate multiple possible responses"""
143
- candidates = []
144
-
145
- # 1. Try exact matches from knowledge base
146
- for category, patterns in self.knowledge_base.items():
147
- for pattern, responses in patterns.items():
148
- if pattern in user_input:
149
- candidates.extend(responses)
150
-
151
- # 2. Try learned patterns
152
- similar_patterns = context['similar_patterns']
153
- for pattern, data, similarity in similar_patterns:
154
- if data['score'] > self.min_confidence:
155
- candidates.append(data['response'])
156
-
157
- # 3. Generate contextual responses
158
- if context['topics']:
159
- topic = random.choice(context['topics'])
160
- for template in self.response_templates:
161
- candidates.append(template.format(topic=topic, related_topic=topic))
162
-
163
- # 4. Generate learned variations
164
- if self.conversation_memory:
165
- # Adapt previous successful responses
166
- successful_responses = [m for m in self.conversation_memory if m.get('reward', 0) > 0.7]
167
- if successful_responses:
168
- best_response = max(successful_responses, key=lambda x: x.get('reward', 0))
169
- adapted_response = self._adapt_response(best_response['response'], context)
170
- candidates.append(adapted_response)
171
-
172
- # 5. Exploration - generate new responses
173
- if random.random() < self.exploration_rate or not candidates:
174
- candidates.append(self._generate_exploratory_response(context))
175
-
176
- return list(set(candidates)) # Remove duplicates
177
-
178
- def _adapt_response(self, response: str, context: dict) -> str:
179
- """Adapt a previous response to current context"""
180
- words = response.split()
181
- if len(words) > 5 and context['topics']:
182
- # Replace some words with current context
183
- new_topic = random.choice(context['topics'])
184
- return f"Thinking about {new_topic}, {response}"
185
- return response
186
-
187
- def _generate_exploratory_response(self, context: dict) -> str:
188
- """Generate a new exploratory response"""
189
- base_responses = [
190
- "That's fascinating. I'm still learning about this topic.",
191
- "I'd love to understand more about this.",
192
- "This is new territory for me. What's your perspective?",
193
- "I'm developing my understanding of this. Could you share more?",
194
- "This helps me learn. Please continue."
195
- ]
196
-
197
- response = random.choice(base_responses)
198
- if context['topics']:
199
- response = response.replace("this", random.choice(context['topics']))
200
-
201
- return response
202
-
203
- def _select_best_response(self, user_input: str, candidates: list, context: dict) -> str:
204
- """Select the best response using learned preferences"""
205
- if not candidates:
206
- return "I'm learning from our conversation. Please continue."
207
-
208
- # Score each candidate
209
- scored_candidates = []
210
- for candidate in candidates:
211
- score = self._score_response(candidate, user_input, context)
212
- scored_candidates.append((candidate, score))
213
-
214
- # Select based on scores with some randomness for exploration
215
- best_candidate, best_score = max(scored_candidates, key=lambda x: x[1])
216
-
217
- if random.random() < self.exploration_rate and len(scored_candidates) > 1:
218
- # Sometimes pick a different candidate to explore
219
- scored_candidates.remove((best_candidate, best_score))
220
- second_best = max(scored_candidates, key=lambda x: x[1])
221
- return second_best[0]
222
-
223
- return best_candidate
224
-
225
- def _score_response(self, response: str, user_input: str, context: dict) -> float:
226
- """Score a response based on learned effectiveness"""
227
- score = 0.5 # Base score
228
-
229
- # Length preference (not too short, not too long)
230
- response_length = len(response.split())
231
- if 8 <= response_length <= 25:
232
- score += 0.2
233
-
234
- # Engagement score (questions, curiosity)
235
- if '?' in response:
236
- score += 0.15
237
-
238
- # Topic relevance
239
- response_topics = self._extract_topics(response.lower())
240
- input_topics = context['topics']
241
- if set(response_topics) & set(input_topics):
242
- score += 0.2
243
-
244
- # Learning from history
245
- response_hash = hashlib.md5(response.encode()).hexdigest()[:8]
246
- if response_hash in self.response_memory:
247
- historical_score = self.response_memory[response_hash]['avg_score']
248
- score += historical_score * 0.3
249
-
250
- # Variety bonus (don't repeat too much)
251
- recent_responses = [m['response'] for m in list(self.conversation_memory)[-5:]]
252
- if response not in recent_responses:
253
- score += 0.1
254
-
255
- return min(score, 1.0)
256
-
257
- def _calculate_confidence(self, user_input: str, response: str) -> float:
258
- """Calculate confidence in this response"""
259
- # More confidence if we've used similar patterns successfully
260
- similar_patterns = self._find_similar_patterns(user_input)
261
- if similar_patterns:
262
- avg_score = np.mean([data['score'] for _, data, _ in similar_patterns])
263
- return min(avg_score * 1.2, 1.0)
264
- return 0.3 # Low confidence for new patterns
265
-
266
- def learn_from_feedback(self, user_input: str, reward: float):
267
- """Learn from explicit feedback"""
268
- if not self.conversation_memory:
269
- return
270
-
271
- # Apply reward to recent interactions
272
- recent_interaction = self.conversation_memory[-1]
273
- recent_interaction['reward'] = reward
274
-
275
- # Update learned patterns
276
- input_words = recent_interaction['input'].split()
277
- response = recent_interaction['response']
278
-
279
- # Create pattern from key words
280
- key_words = [w for w in input_words if len(w) > 3][:4] # Take up to 4 substantial words
281
- if key_words:
282
- pattern = ' '.join(key_words)
283
-
284
- if pattern not in self.learned_patterns:
285
- self.learned_patterns[pattern] = {
286
- 'response': response,
287
- 'score': reward,
288
- 'count': 1,
289
- 'last_used': datetime.now().isoformat()
290
- }
291
- else:
292
- # Update with moving average
293
- old_data = self.learned_patterns[pattern]
294
- new_score = (old_data['score'] * old_data['count'] + reward) / (old_data['count'] + 1)
295
- self.learned_patterns[pattern]['score'] = new_score
296
- self.learned_patterns[pattern]['count'] += 1
297
- # Occasionally update response
298
- if reward > old_data['score']:
299
- self.learned_patterns[pattern]['response'] = response
300
-
301
- # Update response memory
302
- response_hash = hashlib.md5(response.encode()).hexdigest()[:8]
303
- if response_hash not in self.response_memory:
304
- self.response_memory[response_hash] = {
305
- 'response': response,
306
- 'total_score': reward,
307
- 'count': 1,
308
- 'avg_score': reward
309
- }
310
- else:
311
- memory = self.response_memory[response_hash]
312
- memory['total_score'] += reward
313
- memory['count'] += 1
314
- memory['avg_score'] = memory['total_score'] / memory['count']
315
-
316
- # Store reward for statistics
317
- self.reward_history.append(reward)
318
-
319
- # Save learning
320
- self.save_state()
321
-
322
- def get_learning_stats(self) -> dict:
323
- """Get statistics about learning progress"""
324
- recent_rewards = list(self.reward_history)[-10:] or [0.5]
325
-
326
- return {
327
- 'patterns': len(self.learned_patterns),
328
- 'memory_size': len(self.conversation_memory),
329
- 'avg_score': np.mean(recent_rewards),
330
- 'recent_rewards': len([r for r in recent_rewards if r > 0.7]),
331
- 'exploration_rate': self.exploration_rate
332
- }
333
-
334
- def save_state(self):
335
- """Save learning state to file"""
336
- try:
337
- state = {
338
- 'learned_patterns': self.learned_patterns,
339
- 'response_memory': self.response_memory,
340
- 'conversation_memory': list(self.conversation_memory),
341
- 'reward_history': list(self.reward_history),
342
- 'last_saved': datetime.now().isoformat()
343
- }
344
- with open(self.state_file, 'w') as f:
345
- json.dump(state, f, indent=2)
346
- except Exception as e:
347
- print(f"Error saving state: {e}")
348
-
349
- def load_state(self):
350
- """Load learning state from file"""
351
  try:
352
- if os.path.exists(self.state_file):
353
- with open(self.state_file, 'r') as f:
354
- state = json.load(f)
355
-
356
- self.learned_patterns = state.get('learned_patterns', {})
357
- self.response_memory = state.get('response_memory', {})
358
- self.conversation_memory = deque(state.get('conversation_memory', []), maxlen=50)
359
- self.reward_history = deque(state.get('reward_history', []), maxlen=100)
360
-
361
- print(f"Loaded {len(self.learned_patterns)} patterns and {len(self.conversation_memory)} memories")
362
- except Exception as e:
363
- print(f"Error loading state: {e}")
364
-
365
- def show_knowledge(self):
366
- """Display what the bot has learned"""
367
- print(f"\n=== BOT KNOWLEDGE ===")
368
- print(f"Learned patterns: {len(self.learned_patterns)}")
369
- print(f"Stored responses: {len(self.response_memory)}")
370
- print(f"Conversation memory: {len(self.conversation_memory)}")
371
-
372
- if self.learned_patterns:
373
- print("\nTop learned patterns:")
374
- for pattern, data in sorted(self.learned_patterns.items(),
375
- key=lambda x: x[1]['score'],
376
- reverse=True)[:5]:
377
- print(f" '{pattern}' -> score: {data['score']:.2f}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from self_learning_bot import UnrestrictedChatbot
3
  import os
 
 
 
 
 
 
4
 
5
+ # Initialize bot with persistent storage
6
+ state_path = "/tmp/chatbot_state.json"
7
+ bot = UnrestrictedChatbot(state_file=state_path)
8
+
9
+ def respond(message, history):
10
+ bot.learn_from_feedback("", 1.0) # Learn from successful responses
11
+
12
+ # Get bot response
13
+ response = bot.chat(message)
14
+
15
+ # Show learning stats
16
+ stats = bot.get_learning_stats()
17
+ learning_info = f"🤖 Patterns: {stats['patterns']} | Memory: {stats['memory_size']} | Score: {stats['avg_score']:.2f}"
18
+
19
+ if history is None:
20
+ history = []
21
+ history.append((message, f"{response}\n\n{learning_info}"))
22
+ return history, history
23
+
24
+ def add_feedback(feedback, history):
25
+ if feedback and history:
26
+ # Learn from user feedback (1-5 scale)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  try:
28
+ score = float(feedback)
29
+ if 1 <= score <= 5:
30
+ bot.learn_from_feedback(history[-1][0], score / 5.0) # Convert to 0-1 scale
31
+ return f"✅ Learned from feedback: {score}/5"
32
+ except:
33
+ pass
34
+ return "❌ Please enter a number 1-5"
35
+
36
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
37
+ gr.Markdown("""
38
+ # 🚀 Phoenix AI (Real Self-Learning Chatbot)
39
+ *This bot actually learns from every conversation and improves over time!*
40
+ """)
41
+
42
+ chatbot = gr.Chatbot(height=400, label="Learning Chat")
43
+ state = gr.State([])
44
+
45
+ with gr.Row():
46
+ msg = gr.Textbox(
47
+ label="Your message",
48
+ placeholder="Type anything... the bot learns from your conversations!",
49
+ scale=4
50
+ )
51
+ send_btn = gr.Button("Send", scale=1)
52
+
53
+ with gr.Row():
54
+ feedback = gr.Textbox(
55
+ label="Rate last response (1-5)",
56
+ placeholder="Help me learn! Rate 1(bad) to 5(great)",
57
+ scale=3
58
+ )
59
+ learn_btn = gr.Button("Submit Feedback", scale=1)
60
+ reset_btn = gr.Button("Reset Chat", scale=1)
61
+
62
+ learning_stats = gr.Textbox(
63
+ label="Learning Statistics",
64
+ interactive=False,
65
+ value="Bot will show learning progress here..."
66
+ )
67
+
68
+ # Update stats
69
+ def update_stats():
70
+ stats = bot.get_learning_stats()
71
+ return f"📊 Learned Patterns: {stats['patterns']} | Conversations: {stats['memory_size']} | Avg Score: {stats['avg_score']:.2f} | Recent Rewards: {stats['recent_rewards']}"
72
+
73
+ # Main interactions
74
+ def user_message(message, history):
75
+ if not message.strip():
76
+ return "", history
77
+ new_history = respond(message, history or [])
78
+ return "", new_history[0], update_stats()
79
+
80
+ msg.submit(user_message, [msg, state], [msg, chatbot, learning_stats])
81
+ send_btn.click(user_message, [msg, state], [msg, chatbot, learning_stats])
82
+
83
+ learn_btn.click(
84
+ add_feedback,
85
+ [feedback, chatbot],
86
+ [feedback]
87
+ ).then(update_stats, None, [learning_stats])
88
+
89
+ reset_btn.click(
90
+ lambda: ([], [], "Chat reset!"),
91
+ None,
92
+ [chatbot, state, learning_stats]
93
+ )
94
+
95
+ if __name__ == "__main__":
96
+ demo.launch(show_error=True)