import gradio as gr import base64 import os from typing import List, Optional, Dict, Any, Tuple import anthropic import json from pathlib import Path def count_tokens( system: str, content: str, tools: str, files: List[gr.File] | None, api_key: str ) -> Tuple[Dict, str]: try: if not content.strip(): return None, "Error: User Message is required." client = anthropic.Anthropic( api_key=api_key.strip() if api_key.strip() else os.getenv("ANTHROPIC_API_KEY") ) has_pdf = False has_files = bool(files and any(files)) if has_files: message_content = [] for file in files: if not file: continue with open(file.name, "rb") as f: file_data = base64.b64encode(f.read()).decode("utf-8") if file.name.lower().endswith( (".png", ".jpg", ".jpeg", ".gif", ".webp") ): message_content.append( { "type": "image", "source": { "type": "base64", "media_type": f"image/{file.name.split('.')[-1].lower()}", "data": file_data, }, } ) elif file.name.lower().endswith(".pdf"): message_content.append( { "type": "document", "source": { "type": "base64", "media_type": "application/pdf", "data": file_data, }, } ) has_pdf = True message_content.append({"type": "text", "text": content}) final_content = message_content else: final_content = content betas = ["token-counting-2024-11-01"] if has_pdf: betas.append("pdfs-2024-09-25") params = { "betas": betas, "model": "claude-3-5-sonnet-20241022", "messages": [{"role": "user", "content": final_content}], } if system and system.strip(): params["system"] = system.strip() if tools and tools.strip(): try: params["tools"] = json.loads(tools) except json.JSONDecodeError: return None, "Error: Invalid JSON format in Tools input" try: response = client.beta.messages.count_tokens(**params) return params, str(response.input_tokens) except anthropic.APIError as api_error: if "system:" in str(api_error): params.pop("system", None) response = client.beta.messages.count_tokens(**params) return ( params, f"{response.input_tokens} (Note: System prompt was ignored)", ) else: raise except Exception as e: error_msg = str(e) if isinstance(e, anthropic.APIError): error_msg = f"API Error: {e.message}" return None, f"Error: {error_msg}" def create_demo(api_key: Optional[str] = None) -> gr.Blocks: with gr.Blocks(title="Anthropic API Token Counter") as demo: gr.Markdown("# Anthropic API Token Counter") gr.Markdown(""" Count tokens for Anthropic API messages, including system prompts, user messages, tools, images, and PDFs. For more details, see the [official documentation](https://docs.anthropic.com/en/docs/build-with-claude/token-counting). Get your API key from the [Anthropic Console](https://console.anthropic.com/settings/keys). Anthropic API のメッセージのトークン数をカウントします。システムプロンプト、ユーザーメッセージ、ツール、画像、PDFを含むメッセージに対応しています。詳細は[公式ドキュメント](https://docs.anthropic.com/en/docs/build-with-claude/token-counting)を参照してください。API Keyは[Anthropic Console](https://console.anthropic.com/settings/keys)から取得できます。 """) with gr.Row(): with gr.Column(): api_key_input = gr.Textbox( label="Anthropic API Key (Required)", placeholder="Enter your Anthropic API Key", value="", type="password", ) system_input = gr.Textbox( label="System Prompt (Optional)", placeholder="Enter system prompt if needed", lines=3, ) content_input = gr.Textbox( label="User Message (Required)", placeholder="Enter the message you want to send to Claude", lines=5, ) tools_input = gr.Textbox( label="Tools (Optional)", placeholder="""[{ "name": "get_weather", "description": "Get the current weather in a given location", "input_schema": { "type": "object", "properties": { "location": { "type": "string", "description": "The city and state, e.g. San Francisco, CA" } }, "required": ["location"] } }]""", lines=8, ) file_input = gr.File( label="Upload Files (Optional) - Images & PDFs", file_count="multiple", file_types=[".jpg", ".jpeg", ".png", ".gif", ".webp", ".pdf"], ) count_button = gr.Button("Count Tokens") with gr.Column(): request_output = gr.JSON( label="Request", ) token_output = gr.Textbox(label="Token Count", interactive=False) count_button.click( fn=count_tokens, inputs=[ system_input, content_input, tools_input, file_input, api_key_input, ], outputs=[request_output, token_output], ) return demo if __name__ == "__main__": demo = create_demo() demo.launch()