Ë
    ÝÄ'j!%  ã                   ó  — d Z ddlZddlZddlZddlZddlmZ ddlmZ dZ	dZ
h d£Zd	Zd
edefd„Zdefd„Zdedefd„Zdedefd„Zdedefd„Zdedefd„Z	 	 ddededededef
d„Zdededefd„Z	 	 	 	 ddededededededz  defd„Zy)u{  
AI provider abstraction for ticket acknowledgment and activity classification.

Supports three providers via AI_PROVIDER env var:
  - anthropic (default) â€” Claude Haiku
  - openai              â€” GPT-4o Mini via Responses API
  - gemini              â€” Gemini Flash via google-genai SDK

All sync SDK calls are wrapped in asyncio.to_thread to avoid blocking the event loop.
é    N)Úgenaié   )Úsettingsu´  You are a professional support agent at PIT Solution AG. Write a warm, concise acknowledgment for the support ticket below.
Rules:
- Detect the language of the ticket (Subject + Message). Reply in that language. Default to English if unsure.
- Start with a greeting on its own line: 'Hi {customer},' or 'Dear {customer},' (use Hi for informal, Dear for formal tone).
- Then a blank line.
- Then 2-3 sentences: confirm receipt, show you understood the issue, assure the team will look into it.
- Then a blank line.
- End with exactly two lines:
  
  Best regards,
  {current_user}
  PIT Solution AG
- Plain text only â€” no markdown.

Customer name: {customer}
Subject: {title}
Message: {body}a4  Classify this support ticket into exactly one of these Azure DevOps activity types:
Design, Development, Deployment, Documentation, Requirements, Testing

Rules:
- Design: UI/UX, layout, mockups, visual changes
- Development: bugs, features, code changes, integrations
- Deployment: releases, server issues, hosting, configuration
- Documentation: docs, manuals, guides, content updates
- Requirements: requests, specifications, planning
- Testing: QA, test failures, verification

Reply with only the single word. No explanation.

Subject: {title}
Message: {body}>   ÚDesignÚTestingÚ
DeploymentÚDevelopmentÚRequirementsÚDocumentationuä  You are a project manager at Looping Group, a web agency. Analyze this support ticket and suggest relevant tags for the Azure DevOps task.

Choose only from these tag categories (pick all that apply, max 10 total):

Website (tag name â†’ domain/aliases â€” search ALL context fields for any match):
  Aquacolors â†’ aquacolors.fr
  Aquaparc â†’ aquaparc.ch, aquaparc.com
  Aquatico Amarante â†’ aquaticoamarante.pt, aquatico
  Avonturenpark Hellendoorn â†’ avonturenpark.nl, hellendoorn
  Parc Bagatelle â†’ parcbagatelle.fr, bagatelle
  Cobac Parc â†’ cobacparc.fr, cobac
  Drayton Manor Resort Limited â†’ draytonmanor.co.uk, drayton manor, drayton
  Drievliet â†’ drievliet.nl
  FORT FUN GmbH â†’ fortfun.de, fort-fun.de, fort fun, fortfun
  Grand Aquarium de Saint Malo â†’ aquarium-st-malo.com, saint malo, saintmalo
  Aquarium de Touraine â†’ aquariumdetouraine.fr, touraine
  Isla Magica â†’ islamagica.es, isla magica
  Istralandia â†’ istralandia.hr
  La Mer de Sable â†’ lamerdesable.fr, mer de sable
  Looping Group â†’ loopinggroup.com (use ONLY if no specific park/site is mentioned anywhere)
  Mini Chateaux â†’ minichateaux.fr, mini chateaux
  Parc Saint Paul â†’ parcsaintpaul.com, saint paul
  Planete Sauvage â†’ planete-sauvage.fr, planete sauvage
  Pleasurewood Hills â†’ pleasurewoodhills.com, pleasurewood
  Waterworld â†’ waterworlduk.co.uk
  West Midland Safari Park â†’ wmsp.co.uk, west midland safari, west midland
  Zoo de La Fleche â†’ zoo-la-fleche.com, la fleche, lafleche

Technology: WordPress, TYPO3, Shopify, WooCommerce, PHP, JavaScript, HTML/CSS, React, Vue, Laravel, MySQL, API
Issue type: Bug, Feature Request, Content Update, Performance, Security, Design Change, Integration, Migration, SEO
Urgency: Urgent, Critical, Routine

Rules:
- REQUIRED: exactly 1 website tag (use tag name, not domain/alias).
- Check customer email domain (e.g. user@fortfun.de â†’ FORT FUN GmbH), organization name, ticket subject, description, and all comments/replies for any site mention.
- Default to 'Looping Group' ONLY when truly no park/site appears anywhere in any field.
- Include other clearly applicable tags (max 10 total).
- Return semicolon-separated on a single line, no explanation.
- Example: FORT FUN GmbH; WordPress; Bug; Urgent

{context}ÚhtmlÚreturnc                 óL   — t        j                  dd| «      j                  «       S )z$Strip HTML tags, leaving plain text.z<[^>]+>Ú )ÚreÚsubÚstrip)r   s    ú)/var/www/html/zammad-automation/app/ai.pyÚ_strip_htmlr   i   s   € ä�6‰6�*˜c 4Ó(×.Ñ.Ó0Ð0ó    c                  óä   — t         j                  dk(  rt        t         j                  «      S t         j                  dk(  rt        t         j                  «      S t        t         j
                  «      S )z=Return True if the configured AI provider has an API key set.ÚopenaiÚgemini)r   Úai_providerÚboolÚopenai_api_keyÚgemini_api_keyÚanthropic_api_key© r   r   Ú_has_providerr   n   sQ   € ä×Ñ˜xÒ'Ü”H×+Ñ+Ó,Ð,Ü×Ñ˜xÒ'Ü”H×+Ñ+Ó,Ð,Ü”×*Ñ*Ó+Ð+r   Úpromptc                 óÀ   — t        j                  t        j                  ¬«      }|j                  j                  ddd| dœg¬«      }|j                  d   j                  S )N©Úapi_keyzclaude-haiku-4-5-20251001éú   Úuser)ÚroleÚcontent)ÚmodelÚ
max_tokensÚmessagesr   )Ú	anthropicÚ	Anthropicr   r   r*   Úcreater'   Útext)r    ÚclientÚmsgs      r   Ú_call_anthropicr1   w   sX   € Ü× Ñ ¬×)CÑ)CÔD€FØ
�/‰/×
 Ñ
 Ø)ØØ!¨fÑ5Ð6ð !ó €Cð
 �;‰;�q‰>×ÑÐr   c                 óœ   — t        j                  t        j                  ¬«      }|j                  j                  d| ¬«      }|j                  S )Nr"   zgpt-4o-mini)r(   Úinput)r   ÚOpenAIr   r   Ú	responsesr-   Úoutput_text©r    r/   Úresps      r   Ú_call_openair9   �   sE   € Ü�]‰]¤8×#:Ñ#:Ô;€FØ×Ñ×"Ñ"ØØð #ó €Dð ×ÑÐr   c                 óœ   — t        j                  t        j                  ¬«      }|j                  j                  d| ¬«      }|j                  S )Nr"   zgemini-flash-latest)r(   Úcontents)r   ÚClientr   r   ÚmodelsÚgenerate_contentr.   r7   s      r   Ú_call_geminir?   Š   sA   € Ü�\‰\¤(×"9Ñ"9Ô:€FØ�=‰=×)Ñ)Ø#Øð *ó €Dð �9‰9Ðr   c                 ó�   — t         j                  dk(  rt        | «      S t         j                  dk(  rt        | «      S t	        | «      S )z'Dispatch to the configured AI provider.r   r   )r   r   r9   r?   r1   )r    s    r   Ú_call_airA   “   s?   € ä×Ñ˜xÒ'Ü˜FÓ#Ð#Ü×Ñ˜xÒ'Ü˜FÓ#Ð#Ü˜6Ó"Ð"r   Úticket_titleÚticket_body_htmlÚcustomer_nameÚ
agent_namec              ƒ   ó  K  — t        «       st        dt        j                  › d�«      ‚t	        |«      dd }|xs d}|xs d}t
        j                  | |||¬«      }t        j                  t        |«      ƒ d{  –—† S 7 Œ­w)z„Generate a personalised acknowledgment reply in the ticket's language.
    Truncates body to 1500 chars to stay within token limits.zAI provider 'z' selected but API key not setNiÜ  ÚtherezSupport Team)ÚtitleÚbodyÚcustomerÚcurrent_user)
r   ÚRuntimeErrorr   r   r   Ú_ACK_PROMPTÚformatÚasyncioÚ	to_threadrA   )rB   rC   rD   rE   Ú	body_textrJ   rK   r    s           r   Úgenerate_acknowledgmentrR   œ   s‚   è ø€ ô Œ?Ü˜]¬8×+?Ñ+?Ð*@Ð@^Ð_Ó`Ð`äÐ,Ó-¨e¨tÐ4€IØÒ' €HØÒ/ €LÜ×Ñ l¸ÈXÐdpÐÓq€FÜ×"Ñ"¤8¨VÓ4×4Ð4Ð4ús   ‚A8BÁ:A?Á;Bc              ƒ   ó(  K  — t        «       syt        |«      dd }t        j                  | |¬«      }	 t	        j
                  t        |«      ƒ d{  –—† }|j                  «       j                  d«      }|t        v r|S dS 7 Œ/# t        $ r Y yw xY w­w)z‡Classify ticket into a DevOps activity type using AI.
    Falls back to 'Development' if AI is unavailable or returns an invalid value.r	   Ni   )rH   rI   ú.)
r   r   Ú_ACTIVITY_PROMPTrN   rO   rP   rA   r   Ú_VALID_ACTIVITIESÚ	Exception)rB   rC   rQ   r    ÚrawÚactivitys         r   Úclassify_activityrZ   ®   s’   è ø€ ô Œ?ØäÐ,Ó-¨d¨sÐ3€IÜ×$Ñ$¨<¸iÐ$ÓH€FðÜ×%Ñ%¤h°Ó7×7ˆØ—9‘9“;×$Ñ$ SÓ)ˆØ#Ô'8Ñ8ˆxÐK¸mÐKð 8ùô ò ÙðüsF   ‚1B´B ÁBÁ,B Á>BÁ?B Â BÂB Â	BÂBÂBÂBÚcustomer_emailÚcustomer_orgÚarticlesc              ƒ   óT  K  — t        «       syg }|j                  d| › �«       |r|j                  d|› �«       |r|j                  d|› �«       |r|j                  d|› �«       t        |«      dd j                  «       }|r|j                  d|› �«       |rMt	        |dd	 d
«      D ];  \  }}	t        |	«      dd j                  «       }
|
sŒ%|j                  d|› d|
› �«       Œ= dj                  |«      }t        j                  |¬«      }	 t        j                  t        |«      ƒ d{  –—† }|j                  dd«      j                  d«      D �cg c]#  }|j                  «       sŒ|j                  «       ‘Œ% }}dj                  |dd	 «      S 7 Œec c}w # t        $ r Y yw xY w­w)zøSuggest semicolon-separated Azure DevOps tags for a Looping Group website ticket.
    Uses all available context: title, description, customer info, and all article/comment bodies.
    Returns empty string if AI unavailable or classification fails.Ú z	Subject: z
Customer: zCustomer email: zCustomer organization: Niè  zDescription:
é
   r   iô  zComment z:
z

)ÚcontextÚ,ú;z; )r   Úappendr   r   Ú	enumerateÚjoinÚ_TAGS_PROMPTrN   rO   rP   rA   ÚreplaceÚsplitrW   )rB   rC   r[   r\   rD   r]   ÚlinesÚdescriptionÚiÚ	body_htmlr.   ra   r    rX   ÚtÚtagss                   r   Úsuggest_tagsrp   ¾   s™  è ø€ ô Œ?Øà€EØ	‡L�L�9˜\˜NÐ+Ô,ÙØ�‰�z - Ð1Ô2ÙØ�‰Ð'¨Ð'7Ð8Ô9ÙØ�‰Ð.¨|¨nÐ=Ô>äÐ.Ó/°°Ð6×<Ñ<Ó>€KÙØ�‰�~ k ]Ð3Ô4áÜ% h¨s° m°QÓ7ò 	6‰LˆAˆyÜ˜yÓ)¨$¨3Ð/×5Ñ5Ó7ˆDÚØ—‘˜x¨ s¨#¨d¨VÐ4Õ5ð	6ð
 �k‰k˜%Ó €GÜ× Ñ ¨Ð Ó1€FðÜ×%Ñ%¤h°Ó7×7ˆØ#&§;¡;¨s°CÓ#8×#>Ñ#>¸sÓ#CÖQ˜aÀqÇwÁwÅy�—‘•	ÐQˆÐQØ�y‰y˜˜c˜r˜Ó#Ð#ð 8úÚQøäò Ùðüs[   ‚CF(ÃA F(ÄF Ä,FÄ-'F ÅFÅ*FÅ<F ÆF(ÆF ÆF Æ	F%Æ"F(Æ$F%Æ%F()r_   r_   )r_   r_   r_   N)Ú__doc__rO   r   r+   r   Úgoogler   Úconfigr   rM   rU   rV   rg   Ústrr   r   r   r1   r9   r?   rA   rR   rZ   Úlistrp   r   r   r   ú<module>rv      s_  ðñ	ó Û 	Û Û Ý Ý ð
ð ð.ð ò hÐ ð%ð ðT1�cð 1˜có 1ð
,�tó ,ð˜Cð  Có ð˜ð  ó ð˜ð  ó ð#�Sð #˜Só #ð Øñ	5Øð5àð5ð ð5ð ð	5ð
 	ó5ð$¨#ð Àð Èó ð& ØØØ ñ(Øð(àð(ð ð(ð ð	(ð
 ð(ð �T‰kð(ð 	ô(r   