Files
odoo-expertos.com/directory/services/haiku.py
T
2026-08-28 10:11:11 -03:00

360 lines
13 KiB
Python

"""
Claude Haiku service for content generation.
"""
import json
import logging
from typing import Optional, List, Dict, Any
from anthropic import Anthropic
from ..config import get_settings
from ..models.schemas import HaikuTagsResponse, HaikuContentResponse, TagCategory
logger = logging.getLogger(__name__)
class HaikuService:
"""Service for AI content generation using Claude Haiku."""
def __init__(self):
"""Initialize Anthropic client."""
settings = get_settings()
self.client = Anthropic(api_key=settings.anthropic_api_key)
self.model = "claude-3-5-haiku-20241022"
def _call_haiku(
self,
system_prompt: str,
user_prompt: str,
max_tokens: int = 4096,
) -> str:
"""
Make a call to Claude Haiku.
Args:
system_prompt: System instructions
user_prompt: User message
max_tokens: Maximum response tokens
Returns:
Response text
"""
response = self.client.messages.create(
model=self.model,
max_tokens=max_tokens,
system=system_prompt,
messages=[{"role": "user", "content": user_prompt}],
)
return response.content[0].text
def extract_tags(
self,
company_name: str,
website_markdown: Optional[str],
address: Optional[str] = None,
) -> HaikuTagsResponse:
"""
Extract tags from company information.
Args:
company_name: Company name
website_markdown: Scraped website content
address: Company address
Returns:
Extracted tags with confidence
"""
system_prompt = """You are an expert at analyzing Odoo partner companies.
Extract relevant tags from the provided company information.
Respond with valid JSON only, no other text. Use this exact structure:
{
"services": ["list of services they offer"],
"industries": ["list of industries they serve"],
"modules": ["list of Odoo modules they specialize in"],
"partner_level": "Ready Partner|Silver Partner|Gold Partner|Platinum Partner or null",
"confidence": 0.0 to 1.0
}
Valid services: Implementation, Customization, Training, Support, Migration, Integration, Consulting, Hosting, Development
Valid industries: Manufacturing, Retail, E-commerce, Healthcare, Education, Finance, Logistics, Construction, Food & Beverage, Professional Services
Valid modules: Sales, CRM, Inventory, Accounting, Manufacturing, Website, E-commerce, HR, Project, Purchase, Point of Sale
Only include tags you can confidently identify from the content."""
user_prompt = f"""Company: {company_name}
Address: {address or "Not provided"}
Website content:
{website_markdown[:8000] if website_markdown else "No website content available"}
Extract tags for this Odoo partner company."""
try:
response = self._call_haiku(system_prompt, user_prompt, max_tokens=1024)
# Parse JSON response
data = json.loads(response)
return HaikuTagsResponse(**data)
except json.JSONDecodeError as e:
logger.error(f"Failed to parse tags response: {e}")
return HaikuTagsResponse(confidence=0.0)
except Exception as e:
logger.error(f"Tag extraction failed: {e}")
return HaikuTagsResponse(confidence=0.0)
def generate_company_content(
self,
company_name: str,
city_name: str,
country_name: str,
website_markdown: Optional[str],
services: List[str],
industries: List[str],
modules: List[str],
partner_level: Optional[str] = None,
language: str = "de",
) -> HaikuContentResponse:
"""
Generate SEO-optimized company page content.
Args:
company_name: Company name
city_name: City name
country_name: Country name
website_markdown: Scraped website content
services: List of service tags
industries: List of industry tags
modules: List of module tags
partner_level: Partner certification level
language: Output language code
Returns:
Generated content
"""
lang_instructions = {
"de": "Write all content in German (Deutsch).",
"en": "Write all content in English.",
"es": "Write all content in Spanish (Español).",
"fr": "Write all content in French (Français).",
"pt": "Write all content in Portuguese (Português).",
"ar": "Write all content in Arabic (العربية).",
}
system_prompt = f"""You are an expert SEO content writer for Odoo partner directories.
{lang_instructions.get(language, lang_instructions["en"])}
Create engaging, informative content about an Odoo partner company.
The content should be at least 800 words and SEO-optimized.
Respond with valid JSON only:
{{
"description": "2-3 sentence company description",
"content_html": "Full HTML content with headings, paragraphs, lists",
"meta_title": "SEO title (50-60 chars)",
"meta_description": "SEO meta description (150-160 chars)"
}}
Include:
- Company overview
- Services offered
- Industries served
- Odoo modules expertise
- Why choose this partner
- Location information
Use semantic HTML: <h2>, <h3>, <p>, <ul>, <li>, <strong>"""
tags_info = f"""
Services: {", ".join(services) if services else "Various Odoo services"}
Industries: {", ".join(industries) if industries else "Multiple industries"}
Modules: {", ".join(modules) if modules else "Various Odoo modules"}
Partner Level: {partner_level or "Odoo Partner"}"""
user_prompt = f"""Create content for:
Company: {company_name}
Location: {city_name}, {country_name}
{tags_info}
Website information:
{website_markdown[:6000] if website_markdown else "Limited information available"}
Generate comprehensive SEO content for this Odoo partner's directory page."""
try:
response = self._call_haiku(system_prompt, user_prompt, max_tokens=4096)
data = json.loads(response)
return HaikuContentResponse(**data)
except json.JSONDecodeError as e:
logger.error(f"Failed to parse content response: {e}")
# Return fallback content
return self._generate_fallback_content(
company_name, city_name, country_name, services, language
)
except Exception as e:
logger.error(f"Content generation failed: {e}")
return self._generate_fallback_content(
company_name, city_name, country_name, services, language
)
def _generate_fallback_content(
self,
company_name: str,
city_name: str,
country_name: str,
services: List[str],
language: str,
) -> HaikuContentResponse:
"""Generate basic fallback content when AI generation fails."""
services_text = ", ".join(services) if services else "Odoo implementation"
if language == "de":
description = f"{company_name} ist ein Odoo Partner in {city_name}, {country_name}."
content = f"""<h2>Über {company_name}</h2>
<p>{company_name} ist ein zertifizierter Odoo Partner mit Sitz in {city_name}.
Das Unternehmen bietet professionelle Odoo-Dienstleistungen für Unternehmen in der Region.</p>
<h3>Dienstleistungen</h3>
<p>Als Odoo Partner bietet {company_name} folgende Leistungen: {services_text}.</p>
<h3>Standort</h3>
<p>{company_name} befindet sich in {city_name}, {country_name} und betreut Kunden in der gesamten Region.</p>"""
meta_title = f"{company_name} - Odoo Partner in {city_name}"
meta_desc = f"{company_name} ist Ihr Odoo Partner in {city_name}. Professionelle ERP-Beratung und Implementierung."
else:
description = f"{company_name} is an Odoo partner located in {city_name}, {country_name}."
content = f"""<h2>About {company_name}</h2>
<p>{company_name} is a certified Odoo partner based in {city_name}.
The company provides professional Odoo services for businesses in the region.</p>
<h3>Services</h3>
<p>As an Odoo partner, {company_name} offers: {services_text}.</p>
<h3>Location</h3>
<p>{company_name} is located in {city_name}, {country_name} and serves clients throughout the region.</p>"""
meta_title = f"{company_name} - Odoo Partner in {city_name}"
meta_desc = f"{company_name} is your Odoo partner in {city_name}. Professional ERP consulting and implementation."
return HaikuContentResponse(
description=description,
content_html=content,
meta_title=meta_title[:60],
meta_description=meta_desc[:160],
)
def generate_city_hub_content(
self,
city_name: str,
country_name: str,
company_count: int,
top_services: List[str],
language: str = "de",
) -> Dict[str, str]:
"""
Generate city hub page content.
Args:
city_name: City name
country_name: Country name
company_count: Number of companies in city
top_services: Most common services
language: Output language
Returns:
Dictionary with content sections
"""
lang_instructions = {
"de": "Write in German.",
"en": "Write in English.",
}
system_prompt = f"""You are an SEO expert writing city hub pages for an Odoo partner directory.
{lang_instructions.get(language, "Write in English.")}
Create compelling content (1000+ words) about finding Odoo partners in this city.
Return valid JSON:
{{
"intro": "Introduction paragraph about Odoo partners in this city",
"content_html": "Full HTML content about Odoo services in this city",
"meta_title": "SEO title (50-60 chars)",
"meta_description": "Meta description (150-160 chars)"
}}"""
user_prompt = f"""City: {city_name}, {country_name}
Number of Odoo Partners: {company_count}
Top Services: {", ".join(top_services)}
Create engaging city hub content for this Odoo partner directory."""
try:
response = self._call_haiku(system_prompt, user_prompt)
return json.loads(response)
except Exception as e:
logger.error(f"City hub content generation failed: {e}")
return {
"intro": f"Find Odoo partners in {city_name}.",
"content_html": f"<p>Discover {company_count} Odoo partners in {city_name}, {country_name}.</p>",
"meta_title": f"Odoo Partners in {city_name}",
"meta_description": f"Find {company_count} certified Odoo partners in {city_name}, {country_name}.",
}
def generate_country_hub_content(
self,
country_name: str,
city_count: int,
company_count: int,
top_cities: List[str],
language: str = "de",
) -> Dict[str, str]:
"""
Generate country hub page content.
Args:
country_name: Country name
city_count: Number of cities with partners
company_count: Total companies in country
top_cities: Cities with most partners
language: Output language
Returns:
Dictionary with content sections
"""
lang_instructions = {
"de": "Write in German.",
"en": "Write in English.",
}
system_prompt = f"""You are an SEO expert writing country hub pages for an Odoo partner directory.
{lang_instructions.get(language, "Write in English.")}
Create comprehensive content (1200+ words) about Odoo partners in this country.
Return valid JSON:
{{
"intro": "Introduction about Odoo partners in this country",
"content_html": "Full HTML content about the Odoo ecosystem in this country",
"meta_title": "SEO title (50-60 chars)",
"meta_description": "Meta description (150-160 chars)"
}}"""
user_prompt = f"""Country: {country_name}
Number of Cities: {city_count}
Total Odoo Partners: {company_count}
Top Cities: {", ".join(top_cities)}
Create engaging country hub content for this Odoo partner directory."""
try:
response = self._call_haiku(system_prompt, user_prompt)
return json.loads(response)
except Exception as e:
logger.error(f"Country hub content generation failed: {e}")
return {
"intro": f"Find Odoo partners across {country_name}.",
"content_html": f"<p>Discover {company_count} Odoo partners in {city_count} cities across {country_name}.</p>",
"meta_title": f"Odoo Partners in {country_name}",
"meta_description": f"Find {company_count} certified Odoo partners in {city_count} cities across {country_name}.",
}