subi333's picture
Initial commit for AI coding assistant
e8a6607
Raw
History Blame Contribute Delete
4.14 kB
import asyncio
import re
import json
from typing import Any
import logging
from bullmq import Worker, Job
import redis
# from socketio_emitter import Emitter
from .gpt_chat import gpt_chat_process
# from TextGeneration.generate_ai_desc_producer import send_ai_gen_desc_message
logger = logging.getLogger(__name__)
class WorkerManager:
def __init__(self, queue_name: str, redis_url: str = "redis://127.0.0.1:6379"):
self.queue_name = queue_name
# 2. Defensive handling in case someone explicitly passes None as redis_url
if redis_url is None:
redis_url = "redis://127.0.0.1:6379"
self.redis_url = redis_url
self.worker = None
self.redis_client = redis.Redis.from_url(redis_url)
# self.io_emitter = Emitter(client=self.redis_client, namespace="/")
async def job_processor(self, job: Job, token: str) -> Any:
"""The core business logic that runs when a job is picked up."""
logger.debug(f"βš™οΈ Processing Job {job.id} [{job.name}]...")
try:
# Simulate background task workload (e.g., calling an LLM or database script)
# await asyncio.sleep(2)
if job.name == 'gpt-chat-process':
prompt = job.data.get('prompt')
msg_session = job.data.get('msgSession')
user_id = job.data.get('userId')
result = await asyncio.to_thread(gpt_chat_process, prompt, msg_session, user_id)
logger.debug(result)
text_content = result.get('result')
msg_session = result.get('msg_session')
user_id = result.get('user_id')
# Regex tracking to grab exactly what sits inside the markdown ticks
code_match = re.search(r'```(?:python)?\n(.*?)```', text_content, re.DOTALL)
clean_code = code_match.group(1).strip() if code_match else text_content.strip()
self.redis_client.publish(
"ai_response",
json.dumps({
"event": "gptChatRes",
"userId": user_id,
"msg_session": msg_session,
"payload": {
"result": clean_code
}
})
)
except Exception:
logger.exception("Message send failed")
# This return value will be stored in Redis as the job result
return {"status": "success", "processed_data": job.data}
def setup_event_listeners(self) -> None:
"""Hooks into specific job lifecycles using event callbacks."""
if not self.worker:
return
# @self.worker.on("completed")
def on_completed(job: Job, result: Any, token: str):
logger.debug(f"βœ… Event: Job {job.id} completed! Result: {result}")
self.worker.on("completed", on_completed)
# @self.worker.on("failed")
def on_failed(job: Job, error: Exception, token: str):
logger.debug(f"❌ Event: Job {job.id} failed! Reason: {error}")
self.worker.on("failed", on_failed)
# @self.worker.on("active")
def on_active(job: Job, token: str):
logger.debug(f"πŸƒ Event: Job {job.id} is now active.")
self.worker.on("active", on_active)
async def start(self) -> None:
"""Starts the background worker instance."""
if not self.worker:
self.worker = Worker(
self.queue_name,
self.job_processor,
opts={"connection": self.redis_url}
)
self.setup_event_listeners()
logger.info(f"πŸš€ Worker is running and listening to queue: {self.queue_name}")
async def stop(self) -> None:
"""Gracefully closes the worker loop."""
if self.worker:
await self.worker.close()
self.worker = None
logger.info(f"πŸ›‘ Worker stopped safely.")