Skip to content

Commit da1f45d

Browse files
konardclaude
andcommitted
Implement VK Bot daily outreach for programming languages and GitHub profiles
- Add DailyOutreach module to ask random users about programming languages and GitHub profiles once daily - Automatically process user responses and add information to their profiles - Integration with existing VK bot architecture in __main__.py - Support for detecting GitHub links and programming language mentions in responses - Daily frequency control to prevent spam 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 160875f commit da1f45d

File tree

3 files changed

+137
-0
lines changed

3 files changed

+137
-0
lines changed

python/__main__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from modules import (
1111
BetterBotBaseDataService, Commands
1212
)
13+
from modules.daily_outreach import DailyOutreach
1314
from tokens import BOT_TOKEN
1415
from userbot import UserBot
1516
import patterns
@@ -38,6 +39,7 @@ def __init__(
3839
self.messages_to_delete = {}
3940
self.userbot = UserBot()
4041
self.data = BetterBotBaseDataService()
42+
self.daily_outreach = DailyOutreach(self, self.data)
4143
self.commands = Commands(self, self.data)
4244
self.commands.register_cmds(
4345
(patterns.HELP, self.commands.help_message),
@@ -99,6 +101,20 @@ def message_new(
99101

100102
user = self.data.get_user(from_id, self) if from_id > 0 else None
101103

104+
# Daily outreach: ask random user about programming languages or GitHub
105+
if peer_id >= 2e9 and self.daily_outreach.should_run_daily_outreach(): # Only in group chats
106+
try:
107+
self.daily_outreach.send_daily_question(peer_id)
108+
except Exception as e:
109+
print(f"Daily outreach error: {e}")
110+
111+
# Process potential responses to daily questions
112+
if from_id > 0 and user:
113+
try:
114+
self.daily_outreach.process_potential_response(msg, from_id)
115+
except Exception as e:
116+
print(f"Response processing error: {e}")
117+
102118
messages = self.get_messages(event)
103119
selected_message = messages[0] if len(messages) == 1 else None
104120
selected_user = (

python/modules/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .data_service import BetterBotBaseDataService
55
from .data_builder import DataBuilder
66
from .vk_instance import VkInstance
7+
from .daily_outreach import DailyOutreach
78
from .utils import (
89
get_default_programming_language,
910
contains_string,

python/modules/daily_outreach.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# -*- coding: utf-8 -*-
2+
"""Daily outreach module for asking users about programming languages and GitHub profiles."""
3+
import random
4+
from datetime import datetime, timedelta
5+
from typing import List, NoReturn, Optional
6+
from regex import search, IGNORECASE
7+
8+
from .data_service import BetterBotBaseDataService
9+
import sys
10+
import os
11+
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
12+
import config
13+
14+
15+
class DailyOutreach:
16+
"""Handles daily outreach to users without programming languages or GitHub profiles."""
17+
18+
QUESTIONS = [
19+
"У вас есть страничка на GitHub?",
20+
"Какие языки программирования вы знаете?"
21+
]
22+
23+
def __init__(self, vk_instance, data_service: BetterBotBaseDataService):
24+
self.vk_instance = vk_instance
25+
self.data_service = data_service
26+
self.last_outreach_date = None
27+
28+
def should_run_daily_outreach(self) -> bool:
29+
"""Check if daily outreach should run (once per day)."""
30+
today = datetime.now().date()
31+
if self.last_outreach_date != today:
32+
self.last_outreach_date = today
33+
return True
34+
return False
35+
36+
def find_users_without_profile_info(self, peer_id: int) -> List[int]:
37+
"""Find users without programming languages or GitHub profiles."""
38+
try:
39+
member_ids = self.vk_instance.get_members_ids(peer_id)
40+
if not member_ids:
41+
return []
42+
43+
candidates = []
44+
for uid in member_ids:
45+
user = self.data_service.get_user(uid, self.vk_instance)
46+
47+
# Check if user has no programming languages and no GitHub profile
48+
has_languages = (hasattr(user, 'programming_languages') and
49+
user.programming_languages and
50+
len(user.programming_languages) > 0)
51+
has_github = (hasattr(user, 'github_profile') and
52+
user.github_profile and
53+
user.github_profile.strip() != "")
54+
55+
if not has_languages and not has_github:
56+
candidates.append(uid)
57+
58+
return candidates
59+
except Exception as e:
60+
print(f"Error finding users: {e}")
61+
return []
62+
63+
def select_random_user_and_question(self, candidates: List[int]) -> Optional[tuple]:
64+
"""Select a random user and question."""
65+
if not candidates:
66+
return None
67+
68+
user_id = random.choice(candidates)
69+
question = random.choice(self.QUESTIONS)
70+
return user_id, question
71+
72+
def send_daily_question(self, peer_id: int) -> NoReturn:
73+
"""Send daily question to a random user."""
74+
candidates = self.find_users_without_profile_info(peer_id)
75+
76+
if not candidates:
77+
return
78+
79+
selection = self.select_random_user_and_question(candidates)
80+
if not selection:
81+
return
82+
83+
user_id, question = selection
84+
try:
85+
user_name = self.vk_instance.get_user_name(user_id, "nom")
86+
message = f"[id{user_id}|{user_name}], {question}"
87+
self.vk_instance.send_msg(message, peer_id)
88+
except Exception as e:
89+
print(f"Error sending daily question: {e}")
90+
91+
def process_potential_response(self, msg: str, from_id: int) -> bool:
92+
"""
93+
Process a message that might be a response to our daily questions.
94+
Returns True if response was processed, False otherwise.
95+
"""
96+
msg_lower = msg.lower()
97+
98+
# Check for GitHub profile response
99+
github_match = search(r'github\.com/([a-zA-Z0-9-_]+)', msg, IGNORECASE)
100+
if github_match:
101+
username = github_match.group(1)
102+
user = self.data_service.get_user(from_id, self.vk_instance)
103+
user.github_profile = username
104+
self.data_service.save_user(user)
105+
return True
106+
107+
# Check for programming language response
108+
for lang in config.DEFAULT_PROGRAMMING_LANGUAGES:
109+
# Remove regex escaping for matching
110+
lang_clean = lang.replace(r'\+', '+').replace(r'\-', '-').replace(r'\\', '')
111+
if search(lang_clean, msg, IGNORECASE):
112+
user = self.data_service.get_user(from_id, self.vk_instance)
113+
if not hasattr(user, 'programming_languages'):
114+
user.programming_languages = []
115+
if lang_clean not in user.programming_languages:
116+
user.programming_languages.append(lang_clean)
117+
self.data_service.save_user(user)
118+
return True
119+
120+
return False

0 commit comments

Comments
 (0)