Initial commit
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
"""
|
||||
EdgarTools MCP Tool Handlers
|
||||
|
||||
This module contains workflow-oriented tool handlers for the MCP server.
|
||||
"""
|
||||
|
||||
from edgar.ai.mcp.tools.utils import (
|
||||
check_output_size,
|
||||
format_error_with_suggestions,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"check_output_size",
|
||||
"format_error_with_suggestions",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,192 @@
|
||||
"""
|
||||
Company Research Tool Handler
|
||||
|
||||
Provides comprehensive company intelligence including profile,
|
||||
financials, recent activity, and ownership information.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from mcp.types import TextContent
|
||||
|
||||
from edgar import Company
|
||||
from edgar.ai.mcp.tools.utils import (
|
||||
build_company_profile,
|
||||
check_output_size,
|
||||
format_error_with_suggestions,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def handle_company_research(args: dict[str, Any]) -> list[TextContent]:
|
||||
"""
|
||||
Handle company research tool requests.
|
||||
|
||||
Provides comprehensive company intelligence in one call, combining:
|
||||
- Company profile (name, CIK, ticker, industry)
|
||||
- Latest financial information (optional)
|
||||
- Recent filing activity (optional)
|
||||
- Ownership highlights (optional)
|
||||
|
||||
Args:
|
||||
args: Tool arguments containing:
|
||||
- identifier (required): Company ticker, CIK, or name
|
||||
- include_financials (default True): Include latest financials
|
||||
- include_filings (default True): Include recent filing summary
|
||||
- include_ownership (default False): Include ownership highlights
|
||||
- detail_level (default "standard"): minimal/standard/detailed
|
||||
|
||||
Returns:
|
||||
List containing TextContent with company research results
|
||||
"""
|
||||
identifier = args.get("identifier")
|
||||
detail_level = args.get("detail_level", "standard")
|
||||
include_financials = args.get("include_financials", True)
|
||||
include_filings = args.get("include_filings", True)
|
||||
include_ownership = args.get("include_ownership", False)
|
||||
|
||||
if not identifier:
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text="Error: identifier parameter is required"
|
||||
)]
|
||||
|
||||
try:
|
||||
# Get company
|
||||
company = Company(identifier)
|
||||
|
||||
# Build response parts
|
||||
response_parts = []
|
||||
|
||||
# 1. Company profile
|
||||
profile = build_company_profile(company, detail_level)
|
||||
response_parts.append(profile)
|
||||
|
||||
# 2. Latest financials (if requested)
|
||||
if include_financials:
|
||||
try:
|
||||
financials = extract_latest_financials(company, detail_level)
|
||||
if financials:
|
||||
response_parts.append("\n\nLatest Financials:")
|
||||
response_parts.append(financials)
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not retrieve financials: {e}")
|
||||
response_parts.append(f"\n\nFinancials: Not available ({str(e)})")
|
||||
|
||||
# 3. Recent filings (if requested)
|
||||
if include_filings:
|
||||
try:
|
||||
filings = recent_filing_summary(company, detail_level)
|
||||
if filings:
|
||||
response_parts.append("\n\nRecent Filings:")
|
||||
response_parts.append(filings)
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not retrieve filings: {e}")
|
||||
response_parts.append(f"\n\nRecent Filings: Not available ({str(e)})")
|
||||
|
||||
# 4. Ownership highlights (if requested)
|
||||
if include_ownership:
|
||||
try:
|
||||
ownership = ownership_highlights(company)
|
||||
if ownership:
|
||||
response_parts.append("\n\nOwnership Highlights:")
|
||||
response_parts.append(ownership)
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not retrieve ownership: {e}")
|
||||
response_parts.append(f"\n\nOwnership: Not available ({str(e)})")
|
||||
|
||||
# Combine response
|
||||
response_text = "\n".join(response_parts)
|
||||
|
||||
# Check output size and truncate if needed
|
||||
response_text = check_output_size(response_text)
|
||||
|
||||
return [TextContent(type="text", text=response_text)]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in company research: {e}", exc_info=True)
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text=format_error_with_suggestions(e)
|
||||
)]
|
||||
|
||||
|
||||
def extract_latest_financials(company: Any, detail_level: str = "standard") -> str:
|
||||
"""
|
||||
Extract latest financial information for a company.
|
||||
|
||||
Args:
|
||||
company: Company object
|
||||
detail_level: Level of detail to include
|
||||
|
||||
Returns:
|
||||
Formatted financial summary
|
||||
"""
|
||||
try:
|
||||
# Get income statement with 3 periods for trend analysis (annual) with concise format for LLM
|
||||
stmt = company.income_statement(periods=3, annual=True, concise_format=True)
|
||||
|
||||
if detail_level == "minimal":
|
||||
# Just key metrics
|
||||
parts = ["Latest Annual Period"]
|
||||
# TODO: Extract specific metrics once we understand the API better
|
||||
return stmt.to_llm_string()
|
||||
else:
|
||||
# Standard or detailed
|
||||
return stmt.to_llm_string()
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not extract financials: {e}")
|
||||
return ""
|
||||
|
||||
|
||||
def recent_filing_summary(company: Any, detail_level: str = "standard") -> str:
|
||||
"""
|
||||
Get summary of recent filing activity.
|
||||
|
||||
Args:
|
||||
company: Company object
|
||||
detail_level: Level of detail to include
|
||||
|
||||
Returns:
|
||||
Formatted filing summary
|
||||
"""
|
||||
try:
|
||||
# Get recent filings (last 5)
|
||||
filings = company.get_filings(limit=5)
|
||||
|
||||
if not filings:
|
||||
return "No recent filings found"
|
||||
|
||||
parts = []
|
||||
for filing in filings:
|
||||
if detail_level == "minimal":
|
||||
parts.append(f"- {filing.form} ({filing.filing_date})")
|
||||
else:
|
||||
parts.append(f"- {filing.form} - {filing.filing_date}")
|
||||
if hasattr(filing, 'description') and filing.description:
|
||||
parts.append(f" {filing.description}")
|
||||
|
||||
return "\n".join(parts)
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not retrieve filings: {e}")
|
||||
return ""
|
||||
|
||||
|
||||
def ownership_highlights(company: Any) -> str:
|
||||
"""
|
||||
Get ownership highlights (insider/institutional activity).
|
||||
|
||||
Args:
|
||||
company: Company object
|
||||
|
||||
Returns:
|
||||
Formatted ownership summary
|
||||
"""
|
||||
# TODO: Implement once we understand ownership data access
|
||||
# This might require analyzing Form 4 (insider) and 13F (institutional) filings
|
||||
logger.info("Ownership highlights not yet implemented")
|
||||
return "Ownership data: Feature not yet implemented"
|
||||
@@ -0,0 +1,106 @@
|
||||
"""
|
||||
Financial Analysis Tool Handler
|
||||
|
||||
Provides multi-period financial statement analysis.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from mcp.types import TextContent
|
||||
|
||||
from edgar import Company
|
||||
from edgar.ai.mcp.tools.utils import (
|
||||
check_output_size,
|
||||
format_error_with_suggestions,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def handle_analyze_financials(args: dict[str, Any]) -> list[TextContent]:
|
||||
"""
|
||||
Handle financial analysis tool requests.
|
||||
|
||||
Provides multi-period financial statement analysis using Company
|
||||
convenience methods (income_statement, balance_sheet, cash_flow).
|
||||
|
||||
Args:
|
||||
args: Tool arguments containing:
|
||||
- company (required): Company ticker, CIK, or name
|
||||
- periods (default 4): Number of periods to analyze
|
||||
- annual (default True): Annual (true) or quarterly (false)
|
||||
- statement_types (default ["income"]): Statements to include
|
||||
|
||||
Returns:
|
||||
List containing TextContent with financial analysis results
|
||||
"""
|
||||
company_id = args.get("company")
|
||||
periods = args.get("periods", 4)
|
||||
annual = args.get("annual", True)
|
||||
statement_types = args.get("statement_types", ["income"])
|
||||
|
||||
if not company_id:
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text="Error: company parameter is required"
|
||||
)]
|
||||
|
||||
try:
|
||||
# Get company
|
||||
company = Company(company_id)
|
||||
|
||||
# Extract requested statements
|
||||
response_parts = []
|
||||
response_parts.append(f"Financial Analysis: {company.name}")
|
||||
response_parts.append(f"Periods: {periods} {'Annual' if annual else 'Quarterly'}")
|
||||
response_parts.append("")
|
||||
|
||||
# Process each requested statement type
|
||||
if "income" in statement_types:
|
||||
try:
|
||||
stmt = company.income_statement(periods=periods, annual=annual, concise_format=True)
|
||||
response_parts.append("=== Income Statement ===")
|
||||
response_parts.append(stmt.to_llm_string())
|
||||
response_parts.append("")
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not retrieve income statement: {e}")
|
||||
response_parts.append(f"Income Statement: Not available ({str(e)})")
|
||||
response_parts.append("")
|
||||
|
||||
if "balance" in statement_types:
|
||||
try:
|
||||
stmt = company.balance_sheet(periods=periods, annual=annual, concise_format=True)
|
||||
response_parts.append("=== Balance Sheet ===")
|
||||
response_parts.append(stmt.to_llm_string())
|
||||
response_parts.append("")
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not retrieve balance sheet: {e}")
|
||||
response_parts.append(f"Balance Sheet: Not available ({str(e)})")
|
||||
response_parts.append("")
|
||||
|
||||
if "cash_flow" in statement_types:
|
||||
try:
|
||||
stmt = company.cash_flow(periods=periods, annual=annual, concise_format=True)
|
||||
response_parts.append("=== Cash Flow Statement ===")
|
||||
response_parts.append(stmt.to_llm_string())
|
||||
response_parts.append("")
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not retrieve cash flow: {e}")
|
||||
response_parts.append(f"Cash Flow: Not available ({str(e)})")
|
||||
response_parts.append("")
|
||||
|
||||
# Combine response
|
||||
response_text = "\n".join(response_parts)
|
||||
|
||||
# Check output size and truncate if needed
|
||||
response_text = check_output_size(response_text, max_tokens=3000) # Larger limit for financials
|
||||
|
||||
return [TextContent(type="text", text=response_text)]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in financial analysis: {e}", exc_info=True)
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text=format_error_with_suggestions(e)
|
||||
)]
|
||||
@@ -0,0 +1,238 @@
|
||||
"""
|
||||
Industry Analysis Tool Handlers
|
||||
|
||||
Provides industry sector analysis and competitive benchmarking capabilities.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from mcp.types import TextContent
|
||||
|
||||
from edgar import Company
|
||||
from edgar.ai.mcp.tools.utils import (
|
||||
check_output_size,
|
||||
format_error_with_suggestions,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Industry function mapping
|
||||
INDUSTRY_FUNCTIONS = {
|
||||
"pharmaceuticals": "get_pharmaceutical_companies",
|
||||
"biotechnology": "get_biotechnology_companies",
|
||||
"software": "get_software_companies",
|
||||
"semiconductors": "get_semiconductor_companies",
|
||||
"banking": "get_banking_companies",
|
||||
"investment": "get_investment_companies",
|
||||
"insurance": "get_insurance_companies",
|
||||
"real_estate": "get_real_estate_companies",
|
||||
"oil_gas": "get_oil_gas_companies",
|
||||
"retail": "get_retail_companies",
|
||||
}
|
||||
|
||||
|
||||
async def handle_industry_overview(args: dict[str, Any]) -> list[TextContent]:
|
||||
"""
|
||||
Handle industry overview tool requests.
|
||||
|
||||
Provides overview of an industry sector including:
|
||||
- Total company count
|
||||
- SIC code(s)
|
||||
- Major public companies
|
||||
- Industry description
|
||||
|
||||
Args:
|
||||
args: Tool arguments containing:
|
||||
- industry (required): Industry sector name
|
||||
- include_top_companies (default True): Include major companies
|
||||
- limit (default 10): Number of top companies to show
|
||||
|
||||
Returns:
|
||||
List containing TextContent with industry overview
|
||||
"""
|
||||
industry = args.get("industry")
|
||||
include_top = args.get("include_top_companies", True)
|
||||
limit = args.get("limit", 10)
|
||||
|
||||
if not industry:
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text="Error: industry parameter is required"
|
||||
)]
|
||||
|
||||
if industry not in INDUSTRY_FUNCTIONS:
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text=f"Error: Unknown industry '{industry}'. Must be one of: {', '.join(INDUSTRY_FUNCTIONS.keys())}"
|
||||
)]
|
||||
|
||||
try:
|
||||
# Import and call the appropriate industry function
|
||||
from edgar.ai import helpers
|
||||
function_name = INDUSTRY_FUNCTIONS[industry]
|
||||
get_companies = getattr(helpers, function_name)
|
||||
companies = get_companies()
|
||||
|
||||
# Build response
|
||||
response_parts = [
|
||||
f"# {industry.replace('_', ' ').title()} Industry Overview",
|
||||
"",
|
||||
f"**Total Companies**: {len(companies):,}",
|
||||
]
|
||||
|
||||
# Get unique SIC codes
|
||||
sic_codes = sorted(companies['sic'].unique().tolist())
|
||||
if len(sic_codes) == 1:
|
||||
response_parts.append(f"**SIC Code**: {sic_codes[0]}")
|
||||
else:
|
||||
response_parts.append(f"**SIC Codes**: {', '.join(map(str, sic_codes))}")
|
||||
|
||||
# Get primary description (from first company)
|
||||
if len(companies) > 0 and 'sic_description' in companies.columns:
|
||||
primary_desc = companies['sic_description'].iloc[0]
|
||||
response_parts.append(f"**Description**: {primary_desc}")
|
||||
|
||||
response_parts.append("")
|
||||
|
||||
# Add major companies if requested
|
||||
if include_top and len(companies) > 0:
|
||||
# Filter to companies with tickers (publicly traded)
|
||||
public = companies[companies['ticker'].notna()].copy()
|
||||
|
||||
if len(public) > 0:
|
||||
response_parts.append("## Major Public Companies")
|
||||
response_parts.append("")
|
||||
|
||||
# Show top N companies
|
||||
top_companies = public.head(limit)
|
||||
|
||||
for _, row in top_companies.iterrows():
|
||||
ticker = row['ticker'] if row['ticker'] else 'N/A'
|
||||
exchange = row['exchange'] if row['exchange'] else 'N/A'
|
||||
response_parts.append(
|
||||
f"- **{ticker}** - {row['name']} ({exchange})"
|
||||
)
|
||||
else:
|
||||
response_parts.append("*No public companies found in this sector*")
|
||||
|
||||
# Combine response
|
||||
response_text = "\n".join(response_parts)
|
||||
|
||||
# Check output size
|
||||
response_text = check_output_size(response_text)
|
||||
|
||||
return [TextContent(type="text", text=response_text)]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in industry overview: {e}", exc_info=True)
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text=format_error_with_suggestions(e)
|
||||
)]
|
||||
|
||||
|
||||
async def handle_compare_industry_companies(args: dict[str, Any]) -> list[TextContent]:
|
||||
"""
|
||||
Handle industry company comparison tool requests.
|
||||
|
||||
Compares financial performance of companies within an industry sector.
|
||||
|
||||
Args:
|
||||
args: Tool arguments containing:
|
||||
- industry (required): Industry sector name
|
||||
- companies (optional): Specific tickers to compare
|
||||
- limit (default 5): Number of companies if not specified
|
||||
- periods (default 3): Number of periods for comparison
|
||||
- annual (default True): Annual (true) or quarterly (false)
|
||||
|
||||
Returns:
|
||||
List containing TextContent with comparative analysis
|
||||
"""
|
||||
industry = args.get("industry")
|
||||
company_tickers = args.get("companies")
|
||||
limit = args.get("limit", 5)
|
||||
periods = args.get("periods", 3)
|
||||
annual = args.get("annual", True)
|
||||
|
||||
if not industry:
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text="Error: industry parameter is required"
|
||||
)]
|
||||
|
||||
if industry not in INDUSTRY_FUNCTIONS:
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text=f"Error: Unknown industry '{industry}'. Must be one of: {', '.join(INDUSTRY_FUNCTIONS.keys())}"
|
||||
)]
|
||||
|
||||
try:
|
||||
# Import and call the appropriate industry function
|
||||
from edgar.ai import helpers
|
||||
function_name = INDUSTRY_FUNCTIONS[industry]
|
||||
get_companies = getattr(helpers, function_name)
|
||||
companies = get_companies()
|
||||
|
||||
# Select companies
|
||||
if company_tickers:
|
||||
# Filter to specified tickers
|
||||
selected = companies[companies['ticker'].isin(company_tickers)].copy()
|
||||
if len(selected) == 0:
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text=f"Error: None of the specified tickers found in {industry} industry"
|
||||
)]
|
||||
else:
|
||||
# Use top N companies with tickers
|
||||
public = companies[companies['ticker'].notna()].copy()
|
||||
if len(public) == 0:
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text=f"Error: No public companies found in {industry} industry"
|
||||
)]
|
||||
selected = public.head(limit)
|
||||
|
||||
# Compare financials
|
||||
response_parts = [
|
||||
f"# {industry.replace('_', ' ').title()} Industry Comparison",
|
||||
f"",
|
||||
f"Comparing {len(selected)} companies over {periods} {'annual' if annual else 'quarterly'} periods",
|
||||
"",
|
||||
]
|
||||
|
||||
for _, row in selected.iterrows():
|
||||
ticker = row['ticker']
|
||||
try:
|
||||
company = Company(ticker)
|
||||
stmt = company.income_statement(
|
||||
periods=periods,
|
||||
annual=annual,
|
||||
concise_format=True
|
||||
)
|
||||
|
||||
response_parts.append(f"## {ticker} - {row['name']}")
|
||||
response_parts.append("")
|
||||
response_parts.append(stmt.to_llm_string())
|
||||
response_parts.append("")
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not get financials for {ticker}: {e}")
|
||||
response_parts.append(f"## {ticker} - {row['name']}")
|
||||
response_parts.append(f"*Financial data not available: {str(e)}*")
|
||||
response_parts.append("")
|
||||
|
||||
# Combine response
|
||||
response_text = "\n".join(response_parts)
|
||||
|
||||
# Check output size (larger limit for comparative data)
|
||||
response_text = check_output_size(response_text, max_tokens=5000)
|
||||
|
||||
return [TextContent(type="text", text=response_text)]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in industry comparison: {e}", exc_info=True)
|
||||
return [TextContent(
|
||||
type="text",
|
||||
text=format_error_with_suggestions(e)
|
||||
)]
|
||||
137
venv/lib/python3.10/site-packages/edgar/ai/mcp/tools/utils.py
Normal file
137
venv/lib/python3.10/site-packages/edgar/ai/mcp/tools/utils.py
Normal file
@@ -0,0 +1,137 @@
|
||||
"""
|
||||
Utility functions for MCP tool handlers.
|
||||
|
||||
Provides helper functions for output management, error handling,
|
||||
and data formatting for MCP responses.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def check_output_size(data: str, max_tokens: int = 2000) -> str:
|
||||
"""
|
||||
Prevent context overflow with intelligent summarization.
|
||||
|
||||
Estimates token count and truncates/summarizes if needed to stay
|
||||
within context window limits.
|
||||
|
||||
Args:
|
||||
data: The text data to check
|
||||
max_tokens: Maximum allowed tokens (default: 2000)
|
||||
|
||||
Returns:
|
||||
Original data if under limit, truncated data otherwise
|
||||
"""
|
||||
# Rough estimation: 1 token ≈ 4 characters
|
||||
estimated_tokens = len(data) / 4
|
||||
|
||||
if estimated_tokens > max_tokens:
|
||||
# Simple truncation with ellipsis
|
||||
# TODO: Implement smarter summarization in future
|
||||
char_limit = int(max_tokens * 4 * 0.9) # 90% of limit to be safe
|
||||
truncated = data[:char_limit]
|
||||
logger.warning(f"Output truncated: {int(estimated_tokens)} tokens -> {max_tokens} tokens")
|
||||
return f"{truncated}\n\n... (output truncated to stay within token limit)"
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def format_error_with_suggestions(error: Exception) -> str:
|
||||
"""
|
||||
Provide helpful error messages with alternatives.
|
||||
|
||||
Creates AI-friendly error messages that include specific suggestions
|
||||
for common error types.
|
||||
|
||||
Args:
|
||||
error: The exception that occurred
|
||||
|
||||
Returns:
|
||||
Formatted error message with suggestions
|
||||
"""
|
||||
error_type = type(error).__name__
|
||||
error_message = str(error)
|
||||
|
||||
# Define helpful suggestions for common errors
|
||||
suggestions_map = {
|
||||
"CompanyNotFound": [
|
||||
"Try searching by CIK instead of ticker",
|
||||
"Use the full company name",
|
||||
"Check spelling of ticker symbol"
|
||||
],
|
||||
"NoFinancialsAvailable": [
|
||||
"Company may not have filed recent 10-K/10-Q",
|
||||
"Try include_financials=False for basic info",
|
||||
"Check filing history with edgar_market_monitor tool"
|
||||
],
|
||||
"FileNotFoundError": [
|
||||
"The requested filing may not be available",
|
||||
"Try a different form type or date range",
|
||||
"Verify the company has filed this type of document"
|
||||
],
|
||||
"HTTPError": [
|
||||
"SEC EDGAR website may be temporarily unavailable",
|
||||
"Check your internet connection",
|
||||
"Try again in a few moments"
|
||||
],
|
||||
"ValueError": [
|
||||
"Check that all required parameters are provided",
|
||||
"Verify parameter formats (e.g., valid ticker symbols)",
|
||||
"Review the tool's parameter documentation"
|
||||
]
|
||||
}
|
||||
|
||||
suggestions = suggestions_map.get(error_type, [
|
||||
"Try rephrasing your request",
|
||||
"Check parameter values",
|
||||
"Consult the tool documentation"
|
||||
])
|
||||
|
||||
# Format the error response
|
||||
response_parts = [
|
||||
f"Error: {error_message}",
|
||||
f"Error Type: {error_type}",
|
||||
"",
|
||||
"Suggestions:"
|
||||
]
|
||||
|
||||
for i, suggestion in enumerate(suggestions, 1):
|
||||
response_parts.append(f"{i}. {suggestion}")
|
||||
|
||||
return "\n".join(response_parts)
|
||||
|
||||
|
||||
def build_company_profile(company: Any, detail_level: str = "standard") -> str:
|
||||
"""
|
||||
Build a company profile summary.
|
||||
|
||||
Args:
|
||||
company: Company object
|
||||
detail_level: Level of detail (minimal/standard/detailed)
|
||||
|
||||
Returns:
|
||||
Formatted company profile text
|
||||
"""
|
||||
parts = [f"Company: {company.name}"]
|
||||
|
||||
# Add CIK
|
||||
parts.append(f"CIK: {company.cik}")
|
||||
|
||||
# Add ticker if available
|
||||
if hasattr(company, 'tickers') and company.tickers:
|
||||
parts.append(f"Ticker: {company.tickers[0]}")
|
||||
|
||||
# Add industry/sector if available and detail level permits
|
||||
if detail_level in ["standard", "detailed"]:
|
||||
if hasattr(company, 'sic_description'):
|
||||
parts.append(f"Industry: {company.sic_description}")
|
||||
|
||||
# Add description for detailed level
|
||||
if detail_level == "detailed":
|
||||
if hasattr(company, 'description') and company.description:
|
||||
parts.append(f"\nDescription: {company.description}")
|
||||
|
||||
return "\n".join(parts)
|
||||
Reference in New Issue
Block a user