feat: add EN/ES/RO language selector for AI pitch generation

- db.py: add `language` column to ai_queue; migration; queue_ai() accepts
  language param and re-queues with ON CONFLICT UPDATE so changing language works
- main.py: batch and single assess endpoints accept `language` from request body
- enricher.py: ai_worker_loop reads language column, passes to _assess_one()
- replicate_ai.py: assess_domain() and _build_prompt() accept language param;
  OUTPUT LANGUAGE section injected into prompt so Gemini writes pitch/email in
  the requested language (EN/ES/RO)
- index.html: flag dropdown (🇪🇸/🇬🇧/🇷🇴) next to AI Assess button; aiLang
  state default ES; language sent in all batch assessment requests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-14 08:39:27 +02:00
parent 88c27bfff5
commit 22eae3f9b7
5 changed files with 37 additions and 19 deletions

View File

@@ -54,7 +54,7 @@ async def _ddg_search(query: str) -> str:
return ""
def _build_prompt(a: dict, search_results: str = "") -> str:
def _build_prompt(a: dict, search_results: str = "", language: str = "ES") -> str:
contacts_block = []
if a.get("emails"): contacts_block.append(f" Emails: {', '.join(a['emails'][:3])}")
if a.get("phones"): contacts_block.append(f" Phones: {', '.join(a['phones'][:3])}")
@@ -141,6 +141,10 @@ Profiles found on site: {social_str}
=== WEB SEARCH RESULTS (use to find contacts, verify business identity) ===
{(search_results or "No results.")[:600]}
=== OUTPUT LANGUAGE ===
Write pitch_angle, outreach_email, email_subject, and all human-readable text fields in: {language}
(EN = English | ES = Spanish | RO = Romanian)
=== WHO WE ARE ===
We are a full-service digital agency. We handle EVERYTHING web-related for SMEs:
new website builds, redesigns, landing pages, e-commerce, CMS migrations, speed
@@ -246,7 +250,7 @@ def _parse_output(raw: str) -> dict:
}
async def assess_domain(analysis: dict) -> dict:
async def assess_domain(analysis: dict, language: str = "ES") -> dict:
"""Call Gemini with the full site analysis. Returns parsed assessment."""
async with _sem():
# Build search query from domain / page title for contact lookup
@@ -259,7 +263,7 @@ async def assess_domain(analysis: dict) -> dict:
payload = {
"input": {
"prompt": _build_prompt(analysis, search_results),
"prompt": _build_prompt(analysis, search_results, language),
"images": [],
"videos": [],
"top_p": 0.9,