Fix merge conflicts and resolve circular import issues

- Resolve conflict markers in logging_config.py, main.py, app.py
- Fix circular imports in story_writer services (image/audio/video generation)
  by using lazy imports for get_story_media_write_dir
- Restore clean versions of:
  - sif_agents.py
  - tenant_provider_config.py
  - personalization_service.py
  - huggingface_provider.py
  - main_text_generation.py
  - logger_utils.py
- Use setup_clean_logging() consistently across app.py and main.py
- Restore verbose_mode handling in start_alwrity_backend.py
This commit is contained in:
ajaysi
2026-03-22 10:45:05 +05:30
parent d412275748
commit d557bd4918
13 changed files with 232 additions and 1179 deletions

View File

@@ -15,7 +15,6 @@ from loguru import logger
from .txtai_service import TxtaiIntelligenceService, TXTAI_AVAILABLE
from services.intelligence.agents.core_agent_framework import BaseALwrityAgent
from services.llm_providers.main_text_generation import llm_text_gen
from services.intelligence.agent_flat_context import AgentFlatContextStore
# Optional txtai imports (align with core agent framework)
try:
@@ -35,16 +34,7 @@ class SharedLLMWrapper:
try:
# We ignore kwargs like 'max_tokens' as llm_text_gen handles defaults,
# but we could map them if needed.
return llm_text_gen(
prompt,
user_id=self.user_id,
<<<<<<< HEAD
preferred_hf_models=LOW_COST_SHARED_REMOTE_MODELS,
flow_type="sif_agent",
=======
preferred_hf_models=REMOTE_LOW_COST_HF_MODELS,
>>>>>>> pr-418
)
return llm_text_gen(prompt, user_id=self.user_id)
except Exception as e:
logger.error(f"SharedLLMWrapper failed to generate text: {e}")
return f"[ERROR: Shared LLM generation failed for user {self.user_id}]"
@@ -54,17 +44,6 @@ class SharedLLMWrapper:
_local_llm_cache = {}
<<<<<<< HEAD
LOW_COST_SHARED_REMOTE_MODELS = [
=======
REMOTE_LOW_COST_HF_MODELS = [
>>>>>>> pr-418
"Qwen/Qwen2.5-1.5B-Instruct",
"Qwen/Qwen2.5-0.5B-Instruct",
"TinyLlama/TinyLlama-1.1B-Chat-v1.0",
]
LOCAL_LLM_FALLBACKS = [
"Qwen/Qwen2.5-1.5B-Instruct",
"Qwen/Qwen2.5-0.5B-Instruct",
@@ -191,8 +170,8 @@ class SIFBaseAgent(BaseALwrityAgent):
def _create_txtai_agent(self):
"""
Expose a txtai Agent interface with flat-file context tools.
Tools are scoped to the current user workspace via AgentFlatContextStore.
SIF agents primarily use the intelligence service directly, but we can expose
capabilities via a standard agent interface if available.
"""
if not TXTAI_AVAILABLE or Agent is None:
raise RuntimeError(f"[{self.__class__.__name__}] txtai Agent not available")
@@ -201,103 +180,11 @@ class SIFBaseAgent(BaseALwrityAgent):
_llm_for_agent = self.llm
for _ in range(3):
_llm_for_agent = getattr(_llm_for_agent, "llm", _llm_for_agent)
return Agent(
llm=_llm_for_agent,
tools=[
{
"name": "flat_context_manifest",
"description": "Returns manifest of available onboarding flat-context documents for this user",
"target": self._tool_flat_context_manifest,
},
{
"name": "flat_context_read",
"description": "Read a flat-context document by logical name: step2|step3|step4|step5|manifest",
"target": self._tool_flat_context_read,
},
{
"name": "flat_context_write_note",
"description": "Write lightweight agent notes/updates to a specific flat-context document",
"target": self._tool_flat_context_write_note,
},
],
)
return Agent(llm=_llm_for_agent, tools=[])
except Exception as e:
logger.error(f"[{self.__class__.__name__}] Failed to create txtai Agent: {e}")
raise
def _tool_flat_context_manifest(self, context: Dict[str, Any]) -> Dict[str, Any]:
"""Tool: list available flat-context docs and links."""
try:
store = AgentFlatContextStore(self.user_id)
manifest = store.load_context_manifest() or {"documents": []}
return {"ok": True, "manifest": manifest}
except Exception as e:
return {"ok": False, "error": str(e)}
def _tool_flat_context_read(self, context: Dict[str, Any]) -> Dict[str, Any]:
"""Tool: read one user-scoped context doc."""
try:
key = str((context or {}).get("document") or "").strip().lower()
store = AgentFlatContextStore(self.user_id)
mapping = {
"step2": store.load_step2_context_document,
"step3": store.load_step3_context_document,
"step4": store.load_step4_context_document,
"step5": store.load_step5_context_document,
"manifest": store.load_context_manifest,
}
if key not in mapping:
return {"ok": False, "error": "Invalid document. Use step2|step3|step4|step5|manifest"}
data = mapping[key]()
return {"ok": True, "document": key, "data": data or {}}
except Exception as e:
return {"ok": False, "error": str(e)}
def _tool_flat_context_write_note(self, context: Dict[str, Any]) -> Dict[str, Any]:
"""Tool: append agent note/update to step context by re-saving payload."""
try:
key = str((context or {}).get("document") or "").strip().lower()
note = str((context or {}).get("note") or "").strip()
if not note:
return {"ok": False, "error": "note is required"}
store = AgentFlatContextStore(self.user_id)
if key == "step2":
doc = store.load_step2_context_document() or {}
payload = doc.get("data") if isinstance(doc.get("data"), dict) else {}
notes = payload.get("agent_notes") if isinstance(payload.get("agent_notes"), list) else []
notes.append({"note": note, "agent": self.agent_type, "ts": datetime.utcnow().isoformat()})
payload["agent_notes"] = notes[-50:]
ok = store.save_step2_website_analysis(payload, source="agent_note")
elif key == "step3":
doc = store.load_step3_context_document() or {}
payload = doc.get("data") if isinstance(doc.get("data"), dict) else {}
notes = payload.get("agent_notes") if isinstance(payload.get("agent_notes"), list) else []
notes.append({"note": note, "agent": self.agent_type, "ts": datetime.utcnow().isoformat()})
payload["agent_notes"] = notes[-50:]
ok = store.save_step3_research_preferences(payload, source="agent_note")
elif key == "step4":
doc = store.load_step4_context_document() or {}
payload = doc.get("data") if isinstance(doc.get("data"), dict) else {}
notes = payload.get("agent_notes") if isinstance(payload.get("agent_notes"), list) else []
notes.append({"note": note, "agent": self.agent_type, "ts": datetime.utcnow().isoformat()})
payload["agent_notes"] = notes[-50:]
ok = store.save_step4_persona_data(payload, source="agent_note")
elif key == "step5":
doc = store.load_step5_context_document() or {}
payload = doc.get("data") if isinstance(doc.get("data"), dict) else {}
notes = payload.get("agent_notes") if isinstance(payload.get("agent_notes"), list) else []
notes.append({"note": note, "agent": self.agent_type, "ts": datetime.utcnow().isoformat()})
payload["agent_notes"] = notes[-50:]
ok = store.save_step5_integrations(payload, source="agent_note")
else:
return {"ok": False, "error": "Invalid document. Use step2|step3|step4|step5"}
return {"ok": bool(ok), "document": key}
except Exception as e:
return {"ok": False, "error": str(e)}
class StrategyArchitectAgent(SIFBaseAgent):
"""Agent for discovering content pillars and identifying strategic gaps."""
@@ -799,25 +686,7 @@ class ContentGuardianAgent(SIFBaseAgent):
if not text:
return {"compliance_score": 0.0, "issues": ["No text provided"]}
guidelines_source = "provided" if style_guidelines else "none"
# 1. Fetch Style Guidelines from flat-file context first, then SIF fallback
if not style_guidelines:
try:
flat_doc = AgentFlatContextStore(self.user_id).load_step2_context_document()
flat_data = (flat_doc or {}).get("data") if isinstance(flat_doc, dict) else None
if isinstance(flat_data, dict):
style_guidelines = {
"tone": (flat_data.get("brand_analysis") or {}).get("brand_voice", "neutral"),
"style_patterns": flat_data.get("style_patterns", {}),
"writing_style": flat_data.get("writing_style", {}),
"style_guidelines": flat_data.get("style_guidelines", {}),
}
guidelines_source = "flat_file"
logger.info(f"[{self.__class__.__name__}] Retrieved style guidelines from flat context")
except Exception as e:
logger.warning(f"[{self.__class__.__name__}] Failed to retrieve style guidelines from flat context: {e}")
# 1. Fetch Style Guidelines from SIF if not provided
if not style_guidelines and self.sif_service:
try:
# Search for website analysis to get brand voice/style
@@ -828,7 +697,7 @@ class ContentGuardianAgent(SIFBaseAgent):
res = results[0]
metadata_str = res.get('object')
metadata = json.loads(metadata_str) if isinstance(metadata_str, str) else (metadata_str or res)
if metadata.get('type') == 'website_analysis':
report = metadata.get('full_report', {})
style_guidelines = {
@@ -836,7 +705,6 @@ class ContentGuardianAgent(SIFBaseAgent):
"style_patterns": report.get('style_patterns', {}),
"writing_style": report.get('writing_style', {})
}
guidelines_source = "sif_index"
logger.info(f"[{self.__class__.__name__}] Retrieved style guidelines from SIF: {style_guidelines.get('tone')}")
except Exception as e:
logger.warning(f"[{self.__class__.__name__}] Failed to retrieve style guidelines from SIF: {e}")
@@ -867,7 +735,7 @@ class ContentGuardianAgent(SIFBaseAgent):
"compliance_score": max(0.0, score),
"issues": issues,
"is_compliant": score > 0.8,
"guidelines_source": guidelines_source
"guidelines_source": "sif_index" if not style_guidelines and self.sif_service else "provided"
}
except Exception as e: