This commit is contained in:
oliver
2026-08-28 10:11:11 -03:00
parent f533ff8e36
commit 585951c8ce
1380 changed files with 1540268 additions and 0 deletions
+359
View File
@@ -0,0 +1,359 @@
"""
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}.",
}