|
# retoor <retoor@molodetz.nl>
|
|
|
|
import asyncio
|
|
import hashlib
|
|
import logging
|
|
import random
|
|
import re
|
|
import time
|
|
from datetime import datetime
|
|
from typing import Any, Optional
|
|
|
|
from faker import Faker
|
|
|
|
from devplacepy.services.bot.browser import BotBrowser
|
|
from devplacepy.services.bot.config import (
|
|
COMMENT_COOLDOWN_MAX_SECONDS,
|
|
COMMENT_COOLDOWN_MIN_SECONDS,
|
|
FEED_TOPICS,
|
|
GIST_LANGUAGES,
|
|
MAX_SIBLING_COMMENTS,
|
|
MAX_THREAD_REPLIES,
|
|
MENTION_REPLIES_PER_SESSION,
|
|
NOTIFICATION_CHECK_PROB,
|
|
PERSONAS,
|
|
PROJECT_STATUSES,
|
|
PROJECT_TYPES,
|
|
REACT_RATE_DEFAULT,
|
|
REACT_RATES,
|
|
SEARCH_TERMS,
|
|
SESSION_COMMENT_CAP_MAX,
|
|
SESSION_COMMENT_CAP_MIN,
|
|
SIBLING_SNIPPET_LEN,
|
|
USER_AGENTS,
|
|
VIEWPORTS,
|
|
persona_article_score,
|
|
pick_category,
|
|
)
|
|
from devplacepy.services.bot.handles import make_handle
|
|
from devplacepy.services.bot.llm import LLMClient
|
|
from devplacepy.services.bot.news_fetcher import NewsFetcher
|
|
from devplacepy.services.bot.registry import ArticleRegistry
|
|
from devplacepy.services.bot.runtime import BotRuntimeConfig
|
|
from devplacepy.services.bot.state import BotState
|
|
from devplacepy.services.bot.agent import BotAgentMixin
|
|
from devplacepy.services.bot.auth import BotAuthMixin
|
|
from devplacepy.services.bot.browse import BotBrowseMixin
|
|
from devplacepy.services.bot.engage import BotEngageMixin
|
|
from devplacepy.services.bot.helpers import BotHelpersMixin
|
|
from devplacepy.services.bot.human import BotHumanMixin
|
|
from devplacepy.services.bot.loop import BotLoopMixin
|
|
from devplacepy.services.bot.posting import BotPostingMixin
|
|
from devplacepy.services.bot.social import BotSocialMixin
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class DevPlaceBot(
|
|
BotHelpersMixin,
|
|
BotAuthMixin,
|
|
BotHumanMixin,
|
|
BotAgentMixin,
|
|
BotEngageMixin,
|
|
BotPostingMixin,
|
|
BotSocialMixin,
|
|
BotBrowseMixin,
|
|
BotLoopMixin,
|
|
):
|
|
def __init__(self, cfg: BotRuntimeConfig, on_event=None, slot: int = 0):
|
|
self.cfg = cfg
|
|
self.base_url = cfg.base_url
|
|
self.state_path = cfg.state_path
|
|
self.on_event = on_event
|
|
self._slot = slot
|
|
self.state = BotState.load(cfg.state_path)
|
|
if not self.state.persona:
|
|
self.state.persona = random.choice(PERSONAS)
|
|
self._gateway_fallback_key = cfg.api_key
|
|
self.llm = LLMClient(
|
|
self.state.account_api_key or cfg.api_key,
|
|
cfg.api_url,
|
|
cfg.model,
|
|
cfg.input_cost_per_1m,
|
|
cfg.output_cost_per_1m,
|
|
gist_min_lines=cfg.gist_min_lines,
|
|
)
|
|
self.llm.total_cost = self.state.total_cost
|
|
self.llm.total_calls = self.state.total_calls
|
|
self.llm.total_in_tokens = self.state.total_in_tokens
|
|
self.llm.total_out_tokens = self.state.total_out_tokens
|
|
self.news = NewsFetcher(cfg.news_api)
|
|
self.registry = ArticleRegistry(
|
|
cfg.registry_path, cfg.max_per_article, cfg.article_ttl_days
|
|
)
|
|
self._pause_min = min(cfg.action_pause_min, cfg.action_pause_max)
|
|
self._pause_max = max(cfg.action_pause_min, cfg.action_pause_max)
|
|
self._break_scale = max(0.1, cfg.break_scale)
|
|
self._startup_jitter = max(0, cfg.startup_jitter_seconds)
|
|
self._ai_decisions = cfg.ai_decisions
|
|
self._decision_temperature = cfg.decision_temperature
|
|
self.faker = Faker()
|
|
if not self.state.user_agent:
|
|
self.state.user_agent = random.choice(USER_AGENTS)
|
|
if not self.state.viewport:
|
|
self.state.viewport = random.choice(VIEWPORTS)
|
|
self.b = BotBrowser(
|
|
headless=cfg.headless,
|
|
user_agent=self.state.user_agent,
|
|
viewport=self.state.viewport,
|
|
)
|
|
self._session_comments = 0
|
|
self._session_comment_cap = 0
|
|
self._session_mention_replies = 0
|
|
self._profile_verified = False
|
|
self._post_cache: list[tuple[str, str, str, str, str]] = []
|
|
self._project_cache: list[tuple[str, str]] = []
|
|
self._issue_cache: list[tuple[str, str]] = []
|
|
self._session_start_cost: float = 0.0
|
|
self._session_start_calls: int = 0
|
|
self._session_history: list[str] = []
|
|
self._session_energy: float = 0.5
|
|
self._session_stop_after: int = 0
|