134 lines
6.3 KiB
Python
134 lines
6.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Generate content pools for JingTian sample documents using Azure Claude API.
|
|
Run this once to create data/content_pools.json.
|
|
Makes multiple smaller API calls to avoid timeouts.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
import time
|
|
from pathlib import Path
|
|
|
|
try:
|
|
from anthropic import AnthropicFoundry
|
|
except ImportError:
|
|
print("Error: anthropic package not installed. Run: pip install anthropic")
|
|
sys.exit(1)
|
|
|
|
ENDPOINT = "https://admin-ml6rv1i3-swedencentral.services.ai.azure.com/anthropic/"
|
|
MODEL = "claude-sonnet-4-6"
|
|
API_KEY = os.environ.get("AZURE_CLAUDE_API_KEY", "")
|
|
|
|
OUTPUT_PATH = Path(__file__).parent / "data" / "content_pools.json"
|
|
|
|
SYSTEM = """You are generating realistic content for sample documents used by a Hong Kong IP/trademark law firm called Jingtian & Gongcheng LLP. The sole practitioner is Benjamin Choi (蔡明睿), Partner. His office is at Suites 3203-3207, 32/F, Edinburgh Tower, The Landmark, 15 Queen's Road Central, Central, Hong Kong.
|
|
|
|
Return ONLY valid JSON arrays, no markdown code blocks, no explanation. Use placeholders like {deadline}, {tm_number}, {tm_text}, {client_name}, {contact_person}, {class} where indicated."""
|
|
|
|
PROMPTS = {
|
|
"letter_to_client_bodies": """Generate a JSON array of 10 different letter bodies FROM Jingtian & Gongcheng TO clients regarding trademark matters. Each should be 2-4 paragraphs, formal HK legal style. Varied topics: opposition response needed, examination report received, renewal reminder, registration confirmed, filing update, amendment required, deadline approaching, evidence submission required, hearing notice, costs estimate.
|
|
|
|
Each MUST contain placeholders: {deadline}, {tm_number}, {tm_text}, {client_name}, {contact_person}.
|
|
Start each with "Dear {contact_person},".
|
|
Mix some bilingual (EN/CN) content naturally.""",
|
|
"letter_from_client_bodies": """Generate a JSON array of 10 different letter bodies FROM clients TO Benjamin Choi at Jingtian. These are client instructions/responses, slightly less formal. Varied topics: proceed with filing, approve response, query about status, provide evidence, confirm renewal, change instructions, budget concerns, urgent request, new trademark idea, withdrawal request.
|
|
|
|
Use placeholders: {tm_number}, {tm_text} where relevant. About 70% should include {deadline}.
|
|
Start each with "Dear Mr. Choi," or "Dear Benjamin,".""",
|
|
"email_from_client_bodies": """Generate a JSON array of 10 different SHORT email bodies FROM clients TO Benjamin Choi. Casual/professional email style, 1-3 short paragraphs each. Varied topics: quick follow-up, status check, forwarding a document, asking about costs, confirming a meeting, deadline reminder, new matter inquiry, sending signed docs, travel affecting timeline, board meeting deadline.
|
|
|
|
About 60% should include {deadline}. Use {tm_number} or {tm_text} where natural.
|
|
Start with "Hi Benjamin," or "Dear Benjamin," or "Hi Mr. Choi,".""",
|
|
"memo_bodies": """Generate a JSON array of 8 different internal memo bodies. These are Benjamin Choi's internal notes/reminders about trademark matters. Each should list 2-3 items using numbered placeholders like {tm_number_1}, {tm_text_1}, {deadline_1}, {client_1}, {tm_number_2}, {tm_text_2}, {deadline_2}, {client_2}, etc.
|
|
|
|
Topics: upcoming renewals batch, overdue items, priority matters, quarterly review, opposition deadlines, examination response deadlines, new filings status, billing follow-up.""",
|
|
"short_pools": """Generate a JSON object with these keys:
|
|
|
|
"email_subjects": array of 15 realistic email subject lines for HK trademark correspondence. Use {tm_number} or {tm_text} placeholders. Mix EN/CN.
|
|
|
|
"deadline_phrases": array of 15 different ways to express a deadline. Each contains {deadline}. Mix formal/informal, EN/CN. Examples: "Please respond by {deadline}", "The statutory deadline is {deadline}", "請於{deadline}前回覆".
|
|
|
|
"letter_closings": array of 8 formal letter closing paragraphs (before "Yours faithfully"). HK legal style.
|
|
|
|
"invoice_descriptions": array of 12 invoice line item descriptions for trademark services. Use {class} placeholder where relevant. e.g. "Professional fees for trademark application filing - Class {class}", "Government filing fee for trademark renewal".""",
|
|
}
|
|
|
|
|
|
def call_api(client, prompt, label):
|
|
"""Make a single API call and return parsed JSON."""
|
|
print(f" Generating {label}...", end=" ", flush=True)
|
|
start = time.time()
|
|
|
|
message = client.messages.create(
|
|
model=MODEL,
|
|
system=SYSTEM,
|
|
messages=[{"role": "user", "content": prompt}],
|
|
max_tokens=8000,
|
|
)
|
|
|
|
raw = message.content[0].text.strip()
|
|
|
|
# Strip markdown code blocks if present
|
|
if raw.startswith("```"):
|
|
lines = raw.split("\n")
|
|
raw = "\n".join(lines[1:-1])
|
|
|
|
elapsed = time.time() - start
|
|
print(f"done ({elapsed:.1f}s, {len(raw)} chars)")
|
|
return json.loads(raw)
|
|
|
|
|
|
def main():
|
|
if not API_KEY:
|
|
print("Error: AZURE_CLAUDE_API_KEY environment variable not set.")
|
|
print("Usage: AZURE_CLAUDE_API_KEY=<key> python generate_content_pools.py")
|
|
sys.exit(1)
|
|
|
|
print(f"Connecting to Azure Claude ({MODEL})...")
|
|
client = AnthropicFoundry(
|
|
api_key=API_KEY,
|
|
base_url=ENDPOINT,
|
|
)
|
|
|
|
content_pools = {}
|
|
|
|
# Generate each pool separately
|
|
for key, prompt in PROMPTS.items():
|
|
try:
|
|
result = call_api(client, prompt, key)
|
|
|
|
if key == "short_pools":
|
|
# This returns an object with multiple keys
|
|
content_pools.update(result)
|
|
else:
|
|
content_pools[key] = result
|
|
|
|
except json.JSONDecodeError as e:
|
|
print(f"\n ERROR parsing {key}: {e}")
|
|
print(f" Skipping {key}, continuing...")
|
|
continue
|
|
except Exception as e:
|
|
print(f"\n ERROR calling API for {key}: {e}")
|
|
print(f" Skipping {key}, continuing...")
|
|
continue
|
|
|
|
# Summary
|
|
print("\nContent pools summary:")
|
|
for key, val in content_pools.items():
|
|
if isinstance(val, list):
|
|
print(f" {key}: {len(val)} items")
|
|
|
|
# Save
|
|
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
OUTPUT_PATH.write_text(
|
|
json.dumps(content_pools, indent=2, ensure_ascii=False),
|
|
encoding="utf-8",
|
|
)
|
|
print(f"\nSaved to {OUTPUT_PATH}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|