ContiAI-v4 / core /content_services.py
ziadsameh32's picture
Initial FastAPI CrewAI setup
3e14896
# app/core/content_service.py
from concurrent.futures import ThreadPoolExecutor
from crewai import Crew, Process
from .content_crew_config import safe_run_cached
from agents.content_phase import (
course_writer_agent,
course_writer_task,
) # ุงู†ุช ุนู†ุฏูƒ ุฏูˆู„ ุฌุงู‡ุฒูŠู†
MAX_UNIT_WORKERS = 3
def process_unit(unit: dict, course_title: str) -> dict:
output_unit = {
"unit_name": unit["unit_name"],
"unit_outcome": unit["outcome"],
"topics": [],
}
# ====== CACHED CREW (ูŠูุณุชุฎุฏู… ููŠ ุฃูŠ ู…ูƒุงู†) ======
agent = course_writer_agent()
task = course_writer_task(agent)
cached_crew = Crew(
agents=[agent],
tasks=[task],
process=Process.sequential,
memory=False,
verbose=False,
)
for topic in unit["topics"]:
topic_entry = {"topic_title": topic["title"], "subtopics": []}
# sequential subtopics for highest quality
for sub in topic["subtopics"]:
combined_scraped = "\n\n".join(
r.get("scraped_content", "")[:1500]
for r in sub.get("results", [])
if "scraped_content" in r
)
inputs = {
"course_title": course_title,
"unit_title": unit["unit_name"],
"topic_title": topic["title"],
"subtopic_title": sub["title"],
"subtopic_description": sub["description"],
"combined_scraped_texts": combined_scraped,
}
print(f"๐ŸŸข Writing: {sub['title']}")
generated, used_sources = safe_run_cached(inputs, cached_crew=cached_crew)
topic_entry["subtopics"].append(
{
"title": sub["title"],
"description": sub["description"],
"generated_content": generated,
"sources": used_sources,
}
)
output_unit["topics"].append(topic_entry)
return output_unit
def generate_course_content(course_data: dict) -> dict:
"""
ุฏูŠ ุงู„ู„ูŠ ู‡ุชู†ุงุฏูŠู‡ุง ู…ู† ุงู„ู€ FastAPI
course_data ุดูƒู„ู‡ุง ุฒูŠ ุงู„ู„ูŠ ูƒุงู† ููŠ ุงู„ูุงูŠู„:
{
"course_name": ...,
"course_audience": ...,
"units": [...]
}
"""
units = course_data["units"]
final_results_ordered = [None] * len(units)
futures = []
with ThreadPoolExecutor(max_workers=MAX_UNIT_WORKERS) as executor:
for idx, unit in enumerate(units):
future = executor.submit(process_unit, unit, course_data["course_name"])
futures.append((idx, future))
for idx, future in futures:
final_results_ordered[idx] = future.result()
output = {
"course_name": course_data["course_name"],
"course_audience": course_data["course_audience"],
"results": final_results_ordered,
}
return output