Major updates: LinkedIn auto-posting, timezone fixes, and Docker improvements
Features: - Add LinkedIn OAuth integration and auto-posting functionality - Add scheduler service for automated post publishing - Add metadata field to generated_posts for LinkedIn URLs - Add privacy policy page for LinkedIn API compliance - Add company management features and employee accounts - Add license key system for company registrations Fixes: - Fix timezone issues (use UTC consistently across app) - Fix datetime serialization errors in database operations - Fix scheduling timezone conversion (local time to UTC) - Fix import errors (get_database -> db) Infrastructure: - Update Docker setup to use port 8001 (avoid conflicts) - Add SSL support with nginx-proxy and Let's Encrypt - Add LinkedIn setup documentation - Add migration scripts for schema updates Services: - Add linkedin_service.py for LinkedIn API integration - Add scheduler_service.py for background job processing - Add storage_service.py for Supabase Storage - Add email_service.py improvements - Add encryption utilities for token storage Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
"""Base agent class."""
|
||||
import asyncio
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
from openai import OpenAI
|
||||
import httpx
|
||||
from loguru import logger
|
||||
|
||||
from src.config import settings
|
||||
from src.config import settings, estimate_cost
|
||||
from src.database.client import db
|
||||
|
||||
|
||||
class BaseAgent(ABC):
|
||||
@@ -21,13 +22,59 @@ class BaseAgent(ABC):
|
||||
"""
|
||||
self.name = name
|
||||
self.openai_client = OpenAI(api_key=settings.openai_api_key)
|
||||
self._usage_logs: List[Dict[str, Any]] = []
|
||||
self._user_id: Optional[str] = None
|
||||
self._company_id: Optional[str] = None
|
||||
self._operation: str = "unknown"
|
||||
logger.info(f"Initialized {name} agent")
|
||||
|
||||
def set_tracking_context(
|
||||
self,
|
||||
operation: str,
|
||||
user_id: Optional[str] = None,
|
||||
company_id: Optional[str] = None
|
||||
):
|
||||
"""Set context for usage tracking."""
|
||||
self._operation = operation
|
||||
self._user_id = user_id
|
||||
self._company_id = company_id
|
||||
self._usage_logs = []
|
||||
|
||||
@abstractmethod
|
||||
async def process(self, *args, **kwargs) -> Any:
|
||||
"""Process the agent's task."""
|
||||
pass
|
||||
|
||||
async def _log_usage(self, provider: str, model: str, prompt_tokens: int, completion_tokens: int, total_tokens: int):
|
||||
"""Log API usage to database."""
|
||||
cost = estimate_cost(model, prompt_tokens, completion_tokens)
|
||||
usage = {
|
||||
"provider": provider,
|
||||
"model": model,
|
||||
"operation": self._operation,
|
||||
"prompt_tokens": prompt_tokens,
|
||||
"completion_tokens": completion_tokens,
|
||||
"total_tokens": total_tokens,
|
||||
"estimated_cost_usd": cost
|
||||
}
|
||||
self._usage_logs.append(usage)
|
||||
|
||||
try:
|
||||
from uuid import UUID
|
||||
await db.log_api_usage(
|
||||
provider=provider,
|
||||
model=model,
|
||||
operation=self._operation,
|
||||
prompt_tokens=prompt_tokens,
|
||||
completion_tokens=completion_tokens,
|
||||
total_tokens=total_tokens,
|
||||
estimated_cost_usd=cost,
|
||||
user_id=UUID(self._user_id) if self._user_id else None,
|
||||
company_id=UUID(self._company_id) if self._company_id else None
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to log usage to DB: {e}")
|
||||
|
||||
async def call_openai(
|
||||
self,
|
||||
system_prompt: str,
|
||||
@@ -74,6 +121,16 @@ class BaseAgent(ABC):
|
||||
result = response.choices[0].message.content
|
||||
logger.debug(f"[{self.name}] Received response (length: {len(result)})")
|
||||
|
||||
# Track usage
|
||||
if response.usage:
|
||||
await self._log_usage(
|
||||
provider="openai",
|
||||
model=model,
|
||||
prompt_tokens=response.usage.prompt_tokens,
|
||||
completion_tokens=response.usage.completion_tokens,
|
||||
total_tokens=response.usage.total_tokens
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
async def call_perplexity(
|
||||
@@ -117,4 +174,15 @@ class BaseAgent(ABC):
|
||||
content = result["choices"][0]["message"]["content"]
|
||||
logger.debug(f"[{self.name}] Received Perplexity response (length: {len(content)})")
|
||||
|
||||
# Track usage
|
||||
usage = result.get("usage", {})
|
||||
if usage:
|
||||
await self._log_usage(
|
||||
provider="perplexity",
|
||||
model=model,
|
||||
prompt_tokens=usage.get("prompt_tokens", 0),
|
||||
completion_tokens=usage.get("completion_tokens", 0),
|
||||
total_tokens=usage.get("prompt_tokens", 0) + usage.get("completion_tokens", 0)
|
||||
)
|
||||
|
||||
return content
|
||||
|
||||
Reference in New Issue
Block a user