Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
88 changes: 88 additions & 0 deletions backend/app/services/agents/team_doc_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,100 @@
import json
from typing import List, Dict, Any
from backend.app.core.logger import orchestrator_logger
from backend.app.services.nlg.llm_client import LLMClient
from backend.app.services.nlg.prompt_templates import get_template, fill_template

class TeamDocAgent:
"""
Agent for scraping team information, project documentation, and whitepaper details.
"""

async def generate_team_doc_text(self, team_data: List[Dict[str, Any]], doc_data: Dict[str, Any]) -> str:
"""
Summarizes team roles, experience, credibility, and documentation strength
using LLM prompts to turn scraped text into a readable analysis.

Args:
team_data: A list of dictionaries, each representing a team member's profile.
doc_data: A dictionary containing extracted whitepaper/documentation details.

Returns:
A structured string containing the summarized analysis.
"""
orchestrator_logger.info("Generating team and documentation analysis using LLM.")
summary_parts = []

async with LLMClient() as client:
# Summarize Team Roles
team_roles_prompt = fill_template(
get_template("team_roles_summary"),
team_data=json.dumps(team_data, indent=2)
)
try:
team_roles_response = await client.generate_text(team_roles_prompt)
choices = team_roles_response.get("choices") or []
content = choices[0].get("message", {}).get("content", "N/A") if choices else "N/A"
summary_parts.append("### Team Roles and Responsibilities\n")
summary_parts.append(content)
except Exception as e:
orchestrator_logger.error(f"Error generating team roles summary: {e}")
summary_parts.append("### Team Roles and Responsibilities\n")
summary_parts.append("N/A (Failed to generate team roles summary)")
summary_parts.append("\n\n")

# Summarize Team Experience
team_experience_prompt = fill_template(
get_template("team_experience_summary"),
team_data=json.dumps(team_data, indent=2)
)
try:
team_experience_response = await client.generate_text(team_experience_prompt)
choices = team_experience_response.get("choices") or []
content = choices[0].get("message", {}).get("content", "N/A") if choices else "N/A"
summary_parts.append("### Team Experience and Expertise\n")
summary_parts.append(content)
except Exception as e:
orchestrator_logger.error(f"Error generating team experience summary: {e}")
summary_parts.append("### Team Experience and Expertise\n")
summary_parts.append("N/A (Failed to generate team experience summary)")
summary_parts.append("\n\n")

# Summarize Team Credibility
team_credibility_prompt = fill_template(
get_template("team_credibility_summary"),
team_data=json.dumps(team_data, indent=2)
)
try:
team_credibility_response = await client.generate_text(team_credibility_prompt)
choices = team_credibility_response.get("choices") or []
content = choices[0].get("message", {}).get("content", "N/A") if choices else "N/A"
summary_parts.append("### Team Credibility\n")
summary_parts.append(content)
except Exception as e:
orchestrator_logger.error(f"Error generating team credibility summary: {e}")
summary_parts.append("### Team Credibility\n")
summary_parts.append("N/A (Failed to generate team credibility summary)")
summary_parts.append("\n\n")

# Summarize Documentation Strength
doc_strength_prompt = fill_template(
get_template("documentation_strength_summary"),
doc_data=json.dumps(doc_data, indent=2)
)
try:
doc_strength_response = await client.generate_text(doc_strength_prompt)
choices = doc_strength_response.get("choices") or []
content = choices[0].get("message", {}).get("content", "N/A") if choices else "N/A"
summary_parts.append("### Documentation Strength\n")
summary_parts.append(content)
except Exception as e:
orchestrator_logger.error(f"Error generating documentation strength summary: {e}")
summary_parts.append("### Documentation Strength\n")
summary_parts.append("N/A (Failed to generate documentation strength summary)")
summary_parts.append("\n\n")

return "".join(summary_parts)

def scrape_team_profiles(self, urls: List[str]) -> List[Dict[str, Any]]:
"""
Scrapes team profiles from provided URLs (e.g., LinkedIn, company bio pages).
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import pytest
from unittest.mock import AsyncMock


@pytest.mark.asyncio
async def test_generate_team_doc_text(mocker):
# Mock LLMClient class and its instance
mock_llm_client_class = mocker.patch('backend.app.services.agents.team_doc_agent.LLMClient')
mock_llm_client_instance = AsyncMock()
mock_llm_client_class.return_value.__aenter__.return_value = mock_llm_client_instance

# Import TeamDocAgent after patching LLMClient
from backend.app.services.agents.team_doc_agent import TeamDocAgent
agent = TeamDocAgent()

# Sample data
team_data = [
{"name": "John Doe", "title": "CEO", "biography": "Experienced leader in blockchain.", "credentials_verified": True},
{"name": "Jane Smith", "title": "CTO", "biography": "Expert in smart contract development.", "credentials_verified": True}
]
doc_data = {
"project_timelines": [{"event": "Phase 1 Completion", "date": "Q1 2026"}],
"roadmap_items": ["Mainnet Launch"],
"analysis_summary": "Comprehensive documentation available."
}

# Mock LLM responses
mock_llm_client_instance.generate_text.side_effect = [
{"choices": [{"message": {"content": "Summary of team roles."}}]}, # Corrected
{"choices": [{"message": {"content": "Summary of team experience."}}]}, # Corrected
{"choices": [{"message": {"content": "Summary of team credibility."}}]}, # Corrected
{"choices": [{"message": {"content": "Summary of documentation strength."}}]}, # Corrected
]

expected_output_parts = [
"### Team Roles and Responsibilities\nSummary of team roles.\n\n",
"### Team Experience and Expertise\nSummary of team experience.\n\n",
"### Team Credibility\nSummary of team credibility.\n\n",
"### Documentation Strength\nSummary of documentation strength.\n\n"
]
expected_output = "".join(expected_output_parts)

result = await agent.generate_team_doc_text(team_data, doc_data)

assert result == expected_output
assert mock_llm_client_instance.generate_text.call_count == 4

# Verify prompts were called (basic check)
calls = mock_llm_client_instance.generate_text.call_args_list
assert len(calls) == 4
# Further assertions could check the content of the prompts if needed, but for now, just checking call count is sufficient.
Binary file not shown.
33 changes: 33 additions & 0 deletions backend/app/services/nlg/prompt_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,39 @@ def get_template(section_id: str) -> str:

Risk Factors Data:
{data}
""",
"team_roles_summary": """
Based on the following team member data, summarize the key roles and responsibilities
identified within the team. Highlight the diversity of roles and how they contribute
to the project's overall structure and execution.

Team Member Data:
{team_data}
""",
"team_experience_summary": """
Analyze the provided team member data to summarize the collective experience and expertise
within the team. Focus on relevant industry experience, technical skills, and past project
successes. Discuss how this experience strengthens the team's ability to deliver.

Team Member Data:
{team_data}
""",
"team_credibility_summary": """
From the given team member data, assess and summarize the team's credibility.
Consider factors like verified credentials, significant past achievements,
and public recognition. Explain why the team is credible and trustworthy.

Team Member Data:
{team_data}
""",
"documentation_strength_summary": """
Evaluate the strength and comprehensiveness of the project documentation
based on the provided documentation data. Highlight well-documented areas,
clarity, and accessibility. Discuss how strong documentation supports
user adoption and developer engagement.

Documentation Data:
{doc_data}
"""
}
return templates.get(section_id, "No template found for this section ID.")
Expand Down
10 changes: 10 additions & 0 deletions backend/logs/app.log
Original file line number Diff line number Diff line change
Expand Up @@ -6807,3 +6807,13 @@ Exception: Agent failed
2025-11-20 14:38:15,751 - services - WARNING - Report with id non_existent_report not found when attempting to retrieve data.
2025-11-20 14:38:15,751 - api - ERROR - Report with id non_existent_report not found or not completed for data request.
2025-11-20 14:38:15,751 - api - ERROR - ReportNotFoundException: Report not found or not completed
2025-11-20 16:50:01,613 - orchestrator - INFO - Generating team and documentation analysis using LLM.
2025-11-20 16:51:14,852 - orchestrator - INFO - Generating team and documentation analysis using LLM.
2025-11-20 16:51:32,188 - orchestrator - INFO - Generating team and documentation analysis using LLM.
2025-11-20 16:52:01,427 - orchestrator - INFO - Generating team and documentation analysis using LLM.
2025-11-20 16:52:21,913 - orchestrator - INFO - Generating team and documentation analysis using LLM.
2025-11-20 17:07:34,213 - orchestrator - ERROR - Error scraping http://example.com/team/404: HTTP Error: 404
2025-11-20 17:07:34,215 - orchestrator - ERROR - Error scraping http://example.com/team/network-error: Network is unreachable
2025-11-20 17:07:34,216 - orchestrator - ERROR - Error scraping http://example.com/team/404: HTTP Error: 404
2025-11-20 17:07:34,216 - orchestrator - ERROR - Error scraping http://example.com/team/connection-refused: Connection refused
2025-11-20 17:07:34,219 - orchestrator - INFO - Generating team and documentation analysis using LLM.