
    yjB                       U d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	m
Z
 ddlmZ ddlmZ ddlmZmZmZ dd	lmZ dd
lmZmZ  ej0                  e      Z ed      j6                  ZdZ G d de      ZdOdZ ejB                  dddgfdg dfdddgfdg dfdddgfgejD                  dddgfd d!d"gfd#d$d%gfd&g d'fdd(d)gfdd*d+gfgejF                  d,ddgfd-d!d"gfd.g d/fd0g d1fd2d3d4gfgiZ$d5e%d6<   ejB                  d7d8hejD                  dd7hejF                  dd7hiZ&d9e%d:<   dPd;Z'	 	 	 	 	 	 	 	 dQd<Z(d=Z)d>Z*d?Z+ejB                  e)ejD                  e*ejF                  e+iZ,d@e%dA<   ejB                  dBgejD                  dCdDgejF                  dEgiZ-dFe%dG<   dRdHZ.dRdIZ/ G dJ dKe	      Z0 G dL dMe	      Z1ejB                  f	 	 	 	 	 dSdNZ2y)Tu  İtiraz / şekli inceleme yazısı ayıklama mantığı.

PDF'ten metin çıkarır (pypdf) ve Claude Haiku ile patent ofisinin tespit
ettiği eksiklik maddelerini yapılandırılmış biçimde ayıklar. Üç ofis
desteklenir; her birinin sistem prompt'u, kural anahtar tablosu ve başvuru
numarası regex'i ayrıdır:

- TR (TürkPatent): "Şekli İnceleme" yazısı, formality.rules TR kuralları
- EP (EPO): Communication under Rule 57/58 EPC, formality.epo kuralları
- US (USPTO): Notice to File Missing Parts / Office Action (formal),
  formality.uspto kuralları

Çıkarılan her madde, mümkünse `formality` modülünün kural kimlikleriyle
eşleştirilir — "itiraz → düzeltme → değişiklik evrakı" döngüsünün halkasıdır.
    )annotationsN)APIError)	BaseModelField)	PdfReader)Jurisdiction)LLMNotConfiguredErrorget_anthropic_clientresolve)record_usage)ObjectionItemObjectionReportzobjection.extracti.  c                      e Zd ZdZy)ObjectionExtractionErroruG   PDF okunamadığında veya metin çıkarılamadığında fırlatılır.N)__name__
__module____qualname____doc__     1/tmp/py-stage/app/services/objection/extractor.pyr   r   *   s    Qr   r   c                h   	 t        t        j                  |             }g }|j
                  D ]&  }	 |j                  |j                         xs d       ( dj                  |      j                         }|st	        d      |S # t        $ r}t	        d|       |d}~ww xY w# t        $ r Y w xY w)u   PDF baytlarından düz metin çıkarır.

    Metin tabanlı PDF'ler için çalışır. Taranmış (görüntü) PDF'lerde boş
    veya çok az metin döner — bu durumda LLM katmanı da bir şey bulamaz.
    u   PDF okunamadı: N 
uH   PDF'ten metin çıkarılamadı — belge taranmış görüntü olabilir.)
r   ioBytesIO	Exceptionr   pagesappendextract_textjoinstrip)	pdf_bytesreaderexcpartspagetexts         r   extract_objection_textr)   .   s    2::i01 E 	LL**,23
 99U!!#D&V
 	
 K!  &se$
	  		s(   B #B%	B"BB"%	B10B1zclaims.no_subheadingsu   alt başlıkz
alt baslikzabstract.missing_title)u   özet başlığızozet basligiu   özet sayfasızclaims.numbering_gap
numaralandzbirbirini izleyenzterms.foreign_phrase)u   yabancı dilzyabanci dilu   türkçe karşılzclaims.multi_sentenceu
   tek cümlez	tek cumlezepo.abstract_missingzabstract is missingzno abstractzepo.claims_missingz	no claimszclaims are missingzepo.abstract_too_longabstract exceedszmore than 150 wordszepo.abstract_merit_language)zalleged meritsmeritzcomparison with the prior artzsub-heading
subheadingzsingle sentencezmore than one sentencezuspto.abstract_missingzuspto.claims_missingzuspto.abstract_too_long)zexceeds 150 wordsr+   z	150 wordszuspto.abstract_prior_art)comparez	prior artmeritszuspto.no_dependent_claimszdependent claimzno dependentz/dict[Jurisdiction, list[tuple[str, list[str]]]]_RULE_KEYWORDS_BY_JURISzclaims.numbering_startzabstract.too_longzdict[Jurisdiction, set[str]]_EXTRA_VALID_BY_JURISc                Z    t         |    D ch c]  \  }}|	 c}}t        |    z  S c c}}w N)r0   r1   )jurisdictionrid_s      r   _valid_rule_idsr7      s5    1,?Ql+, , s   'c                    |r|t        |      v r|S | j                         t        |   D ]  \  }}t        fd|D              s|c S  y)u   Bir eksiklik açıklamasını ofisin kural kimliğine eşler.

    Önce LLM'in önerisini doğrular; geçerli bir kimlikse onu kullanır.
    Aksi halde ofisin anahtar kelime tablosuna düşer.
    c              3  &   K   | ]  }|v  
 y wr3   r   ).0kwlows     r   	<genexpr>z_match_rule.<locals>.<genexpr>   s     ,RrSy,s   r   )r7   lowerr0   any)description	llm_guessr4   rule_idkeywordsr<   s        @r   _match_rulerD      sY     Y/,"??



C4\B ,8,,N r   u'  Sen Türk patent başvurularının şekli inceleme uzmanısın. Görevin: TürkPatent'in (Türk Patent ve Marka Kurumu) gönderdiği bir şekli inceleme veya itiraz yazısının metnini alıp, Kurumun tespit ettiği eksiklik maddelerini yapılandırılmış biçimde çıkarmak.

ÇIKARILACAKLAR:
1. items — Kurumun tespit ettiği HER eksiklik ayrı bir madde. Yazıda genellikle tire (-) veya numara ile listelenir. Her madde için:
   - description: eksikliğin metni (Kurumun ifadesiyle, kısaltarak).
   - category: "istemler" | "tarifname" | "ozet" | "resimler" | "genel".
   - rule_id_guess: aşağıdaki listeden uygun olanı, emin değilsen boş bırak:
       claims.no_subheadings        (istemlerde alt başlık kullanılmış)
       abstract.missing_title       (özette buluş başlığı yok)
       claims.numbering_gap         (sayfa/istem numaralandırma hatası)
       claims.numbering_start       (numaralandırma 1'den başlamıyor)
       terms.foreign_phrase         (yabancı ifadenin Türkçe karşılığı yok)
       claims.multi_sentence        (istem tek cümle değil)
       abstract.too_long            (özet 150 kelimeyi aşıyor)
   - suggested_fix: eksikliğin nasıl giderileceğine dair tek cümlelik öneri.
2. deadline — Eksikliklerin giderilmesi için verilen süre (örn. "iki ay"). Yoksa boş.
3. application_number — Yazıdaki başvuru numarası (örn. "2026/005880").
4. letter_reference — Yazının sayı ve tarih bilgisi.

KURALLAR:
- Yalnızca yazıda AÇIKÇA belirtilen eksiklikleri çıkar; yorum ekleme.
- Genel bilgilendirme cümlelerini (yıllık ücret, yayım, tebligat vb.) madde olarak ALMA — yalnızca giderilmesi gereken şekli eksiklikleri al.
- Eksiklik yoksa items boş liste döner.

Çıktı yalnızca structured JSON olarak döner; ek açıklama yapma.
uu  You are an expert in European Patent Office (EPO) formal examination. Your task: read a formal communication issued by the EPO (e.g. under Rule 57/58 EPC, noting missing parts or formal defects) and extract each defect in a structured form.

EXTRACT:
1. items — each defect raised by the EPO is a separate item. They are typically listed by bullet, dash or numbering. For each:
   - description: the defect as stated by the EPO, concisely.
   - category: "claims" | "description" | "abstract" | "drawings" | "general".
   - rule_id_guess: one of the following if appropriate, else leave empty:
       epo.abstract_missing            (no abstract is filed)
       epo.claims_missing              (no claims are filed)
       epo.abstract_too_long           (abstract exceeds 150 words)
       epo.abstract_merit_language     (abstract makes merit/comparison claims)
       claims.no_subheadings           (claims use forbidden sub-headings)
       claims.multi_sentence           (a claim is not a single sentence)
       claims.numbering_gap            (claims/pages not consecutively numbered)
       claims.numbering_start          (claim numbering does not start at 1)
   - suggested_fix: one-sentence remedy suggestion.
2. deadline — period given to remedy the deficiencies (e.g. "two months"). Empty if not stated.
3. application_number — the EP application number (e.g. "EP 21 123 456.7" or "21123456.7").
4. letter_reference — the communication reference and/or date.

RULES:
- Extract only deficiencies the EPO EXPLICITLY raises; do not add interpretation.
- Skip purely informational paragraphs (renewal fees, publication, service of documents, etc.) — only items that the applicant must remedy.
- If there are no deficiencies, items is an empty list.
- Output language: match the communication's language (English/French/German).

Output is structured JSON only; no additional commentary.
u  You are an expert in USPTO formal examination. Your task: read a USPTO formal Office Action (e.g. Notice to File Missing Parts, Notice of Incomplete Application, or formality-related rejection) and extract each deficiency in a structured form.

EXTRACT:
1. items — each deficiency raised by the USPTO is a separate item. They are typically listed by bullet or numbering. For each:
   - description: the deficiency as stated, concisely.
   - category: "claims" | "specification" | "abstract" | "drawings" | "general".
   - rule_id_guess: one of the following if appropriate, else leave empty:
       uspto.abstract_missing          (no Abstract of the Disclosure)
       uspto.claims_missing            (no claims; 37 CFR 1.75)
       uspto.abstract_too_long         (abstract exceeds 150 words; 37 CFR 1.72(b))
       uspto.abstract_prior_art        (abstract compares with prior art; MPEP 608.01(b))
       uspto.no_dependent_claims       (no dependent claims; 37 CFR 1.75(c))
       claims.numbering_gap            (claims/pages not consecutively numbered)
       claims.numbering_start          (claim numbering does not start at 1)
       claims.multi_sentence           (a claim is not a single sentence)
   - suggested_fix: one-sentence remedy suggestion.
2. deadline — period given to reply (e.g. "two months from the mailing date"). Empty if not stated.
3. application_number — the U.S. application number (e.g. "17/123,456" or "17/123456").
4. letter_reference — the Office Action mailing date and/or paper number.

RULES:
- Extract only deficiencies the USPTO EXPLICITLY raises; do not add interpretation.
- Skip purely informational paragraphs (filing receipt, fee schedule, publication, etc.) — only items the applicant must remedy.
- If there are no deficiencies, items is an empty list.
- Output language: match the Office Action (English).

Output is structured JSON only; no additional commentary.
zdict[Jurisdiction, str]_SYSTEM_PROMPTSz\b(20\d{2}/\d{4,6})\bz)\b(EP\s?\d{2}\s?\d{3}\s?\d{3}(?:\.\d)?)\bz\b(\d{8}\.\d)\bz\b(\d{2}/\d{3},?\d{3})\bzdict[Jurisdiction, list[str]]_APP_NUMBER_PATTERNSc                v    t         |   D ]-  }t        j                  ||       }|s|j                  d      c S  y)u?   Metinden ofisin başvuru numarası biçimini regex ile çıkar.   r   )rF   researchgroup)r(   r4   patternms       r   _extract_app_numberrN   %  s<    '5 IIgt$771: r   c                    | j                         dt         }|t        j                  k(  rd|z   S |t        j                  k(  rd|z   S d|z   S )u>   LLM'e gönderilen kullanıcı mesajını ofise göre hazırla.Nus   Aşağıdaki TürkPatent şekli inceleme/itiraz yazısını incele ve tespit edilen eksiklik maddelerini çıkar:

zQRead the following EPO formal communication and extract each deficiency raised:

zSRead the following USPTO formal Office Action and extract each deficiency raised:

)r"   
_MAX_CHARSr   TREP)r(   r4   excerpts      r   _user_messagerT   .  se    jjl;J'G|&>@GH	
 |&%'./	

	!#*	+r   c                      e Zd ZU dZ edd      Zded<    ed      Zded	<    ed
d      Zded<    ed
      Z	ded<   y)_RawObjectionItemu#   Haiku'nun ayıkladığı ham madde..zEksiklik metni)r@   strr@   geneldefaultcategoryr   u(   Tahmini şekli tarayıcı kural kimliği)rZ   r@   rule_id_guesssuggested_fixN)
r   r   r   r   r   r@   __annotations__r[   r\   r]   r   r   r   rV   rV   A  sN    -S.>?K?'*Hc* JM3  r*M3*r   rV   c                      e Zd ZU dZ eed      Zded<    ed      Zded	<    ed      Z	ded
<    ed      Z
ded<   y)_RawObjectionReportu%   Haiku'nun structured output şeması.   )default_factory
max_lengthzlist[_RawObjectionItem]itemsr   rY   rW   deadlineapplication_numberletter_referenceN)r   r   r   r   r   listrd   r^   re   rf   rg   r   r   r   r`   r`   L  sF    /%*4B%OE"O"%Hc%#B//!"-c-r   r`   c                  K   t               }t        | |      }	 t               }t
        |   }t        | |      }	 |j                  j                  t        dd|ddidgd|dgt               d	{   }t        t        |j                  d
|j                  j                                 |j                  }d|_        |j*                  |_        |j,                  |_        |j                  xs ||_        |j.                  D ]k  }
|j.                  j1                  t3        |
j4                  |
j6                  xs dt9        |
j4                  |
j:                  |      |
j<                               m t?        |j.                        |_         |S # t        $ r ||_        |cY S w xY w7 4# t         $ r)}	t"        j%                  d|	       ||_        |cY d	}	~	S d	}	~	wt&        $ r)}	t"        j%                  d|	       ||_        |cY d	}	~	S d	}	~	ww xY ww)uA  İtiraz yazısı metninden eksiklik maddelerini ayıklar.

    Ofise (`jurisdiction`) göre sistem prompt'u, kural anahtar tablosu ve
    başvuru numarası regex'i seçilir. LLM yapılandırılmamışsa (API key yok)
    `extracted=False` ile boş rapor döner — çağıran taraf kullanıcıyı
    bilgilendirir.
    i   r(   type	ephemeral)rj   r(   cache_controluser)rolecontent)model
max_tokenssystemmessagesoutput_formatNzobjection.parse.)rp   usageendpointu-   Objection parse — Anthropic API hatası: %su3   Objection parse — yanıt ayrıştırılamadı: %sTrX   )r@   r[   matched_rule_idr]   )!r   rN   r
   r	   rf   rE   rT   rs   parse_MODELr`   r   ru   valuer>   parsed_outputr   _logwarningr   	extractedre   rg   rd   r   r   r@   r[   rD   r\   r]   len
item_count)pdf_textr4   reportfallback_app_noclientsystem_promptuser_messageresprawr%   items              r   parse_objectionr   U  s     F)(LAO%'
 $L1M <8L__**  #)&,k%:  &,?@- + 
 
 	**'(:(:(@(@(B'CD	

 $(#5#5 FllFO!22F # 6 6 I/F		 

 ,,1' +$$d&8&8,! #00		


 FLL)FMq ! $3!
*  DcJ$3! JCP$3!	s   H
F H6F' 0F$1AF' 8CHF!H F!!H$F' '	H	0GH	HH	 H>H	?HH		H)r#   bytesreturnrW   )r4   r   r   zset[str])r@   rW   rA   rW   r4   r   r   rW   )r(   rW   r4   r   r   rW   )r   rW   r4   r   r   r   )3r   
__future__r   r   loggingrI   	anthropicr   pydanticr   r   pypdfr   app.services.formality.modelsr   app.services.llmr	   r
   r   app.services.llm.usage_logr   app.services.objection.modelsr   r   	getLoggerr   r|   rp   ry   rP   r   r   r)   rQ   rR   USr0   r^   r1   r7   rD   _SYSTEM_PROMPT_TR_SYSTEM_PROMPT_EP_SYSTEM_PROMPT_USrE   rF   rN   rT   rV   r`   r   r   r   r   <module>r      s    # 	  	  %  6 Q Q 3 Hw" 
$	%	+	+ 
Ry RF OO	 ><"@A$C	
 
 ,0C!DE"@	
 
!<"=> OO	"7!GH	-ABC#!67	

 *H	

 $L)	
 
!#46N"OP" OO	!$9=#IJ	+/C!DE%B	

 '.	

 (/	
?/L H /f OO.0CDOO,.FGOO,.FG7 3 ,!$4@* B" H" J OO&OO&OO&,(  OO./OO4
 OO12
7 3 
&+	 +.) . ".HHH Hr   