MCPを使い、ChatGPTなどのAIとAutoCADを連携させて自動で作図するためのPythonソースコード
MCPを使い、ChatGPTなどのAIとAutoCADを連携させて自動で作図するためのPythonソースコードを書いて。
AutoCADとAIを連携させるためのMCP(Model Context Protocol)サーバーとPythonクライアントコードを作成します。以下に完全な実装を提供します。
1. MCPサーバー (AutoCAD連携用)
```python
# mcp_autocad_server.py
import asyncio
import json
import sys
import pythoncom
import win32com.client
from mcp import MCPServer, ClientSession
from mcp.server.models import InitializationOptions
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class AutoCADMCPServer(MCPServer):
def __init__(self):
super().__init__("autocad-mcp-server")
self.autocad_app = None
self.current_drawing = None
def connect_to_autocad(self):
"""AutoCADに接続"""
try:
pythoncom.CoInitialize()
self.autocad_app = win32com.client.Dispatch("AutoCAD.Application")
logger.info("AutoCADに接続しました")
return True
except Exception as e:
logger.error(f"AutoCAD接続エラー: {e}")
return False
def get_active_document(self):
"""アクティブなドキュメントを取得"""
try:
if self.autocad_app:
self.current_drawing = self.autocad_app.ActiveDocument
return self.current_drawing
return None
except Exception as e:
logger.error(f"ドキュメント取得エラー: {e}")
return None
async def initialize(self, session: ClientSession):
"""ツールの登録"""
tools = [
{
"name": "create_line",
"description": "2点間に直線を作成",
"inputSchema": {
"type": "object",
"properties": {
"start_x": {"type": "number", "description": "始点X座標"},
"start_y": {"type": "number", "description": "始点Y座標"},
"end_x": {"type": "number", "description": "終点X座標"},
"end_y": {"type": "number", "description": "終点Y座標"}
},
"required": ["start_x", "start_y", "end_x", "end_y"]
}
},
{
"name": "create_circle",
"description": "円を作成",
"inputSchema": {
"type": "object",
"properties": {
"center_x": {"type": "number", "description": "中心X座標"},
"center_y": {"type": "number", "description": "中心Y座標"},
"radius": {"type": "number", "description": "半径"}
},
"required": ["center_x", "center_y", "radius"]
}
},
{
"name": "create_rectangle",
"description": "矩形を作成",
"inputSchema": {
"type": "object",
"properties": {
"x": {"type": "number", "description": "左下X座標"},
"y": {"type": "number", "description": "左下Y座標"},
"width": {"type": "number", "description": "幅"},
"height": {"type": "number", "description": "高さ"}
},
"required": ["x", "y", "width", "height"]
}
},
{
"name": "create_text",
"description": "テキストを作成",
"inputSchema": {
"type": "object",
"properties": {
"x": {"type": "number", "description": "挿入点X座標"},
"y": {"type": "number", "description": "挿入点Y座標"},
"text": {"type": "string", "description": "テキスト内容"},
"height": {"type": "number", "description": "文字高さ"}
},
"required": ["x", "y", "text"]
}
},
{
"name": "get_drawing_info",
"description": "現在の図面情報を取得",
"inputSchema": {
"type": "object",
"properties": {}
}
}
]
for tool in tools:
await session.register_tool(
tool["name"],
tool["description"],
tool["inputSchema"]
)
# AutoCADに接続
self.connect_to_autocad()
async def handle_tool_call(self, session: ClientSession, name: str, arguments: dict):
"""ツール呼び出しの処理"""
try:
if name == "create_line":
return await self.create_line(**arguments)
elif name == "create_circle":
return await self.create_circle(**arguments)
elif name == "create_rectangle":
return await self.create_rectangle(**arguments)
elif name == "create_text":
return await self.create_text(**arguments)
elif name == "get_drawing_info":
return await self.get_drawing_info()
else:
return {"error": f"未知のツール: {name}"}
except Exception as e:
logger.error(f"ツール実行エラー: {e}")
return {"error": str(e)}
async def create_line(self, start_x, start_y, end_x, end_y):
"""直線を作成"""
try:
doc = self.get_active_document()
if not doc:
return {"error": "AutoCADドキュメントが見つかりません"}
model_space = doc.ModelSpace
start_point = win32com.client.Variant(win32com.client.pythoncom.VT_ARRAY | win32com.client.pythoncom.VT_R8, [start_x, start_y, 0])
end_point = win32com.client.Variant(win32com.client.pythoncom.VT_ARRAY | win32com.client.pythoncom.VT_R8, [end_x, end_y, 0])
line = model_space.AddLine(start_point, end_point)
doc.Regen(True)
return {"success": True, "message": f"直線を作成しました: ({start_x},{start_y}) to ({end_x},{end_y})"}
except Exception as e:
return {"error": f"直線作成エラー: {e}"}
async def create_circle(self, center_x, center_y, radius):
"""円を作成"""
try:
doc = self.get_active_document()
if not doc:
return {"error": "AutoCADドキュメントが見つかりません"}
model_space = doc.ModelSpace
center = win32com.client.Variant(win32com.client.pythoncom.VT_ARRAY | win32com.client.pythoncom.VT_R8, [center_x, center_y, 0])
circle = model_space.AddCircle(center, radius)
doc.Regen(True)
return {"success": True, "message": f"円を作成しました: 中心({center_x},{center_y}), 半径{radius}"}
except Exception as e:
return {"error": f"円作成エラー: {e}"}
async def create_rectangle(self, x, y, width, height):
"""矩形を作成"""
try:
doc = self.get_active_document()
if not doc:
return {"error": "AutoCADドキュメントが見つかりません"}
model_space = doc.ModelSpace
points = [
[x, y, 0],
[x + width, y, 0],
[x + width, y + height, 0],
[x, y + height, 0],
[x, y, 0]
]
for i in range(4):
start = win32com.client.Variant(win32com.client.pythoncom.VT_ARRAY | win32com.client.pythoncom.VT_R8, points[i])
end = win32com.client.Variant(win32com.client.pythoncom.VT_ARRAY | win32com.client.pythoncom.VT_R8, points[i+1])
model_space.AddLine(start, end)
doc.Regen(True)
return {"success": True, "message": f"矩形を作成しました: 位置({x},{y}), サイズ{width}x{height}"}
except Exception as e:
return {"error": f"矩形作成エラー: {e}"}
async def create_text(self, x, y, text, height=10):
"""テキストを作成"""
try:
doc = self.get_active_document()
if not doc:
return {"error": "AutoCADドキュメントが見つかりません"}
model_space = doc.ModelSpace
insertion_point = win32com.client.Variant(win32com.client.pythoncom.VT_ARRAY | win32com.client.pythoncom.VT_R8, [x, y, 0])
text_obj = model_space.AddText(text, insertion_point, height)
doc.Regen(True)
return {"success": True, "message": f"テキストを作成しました: '{text}' at ({x},{y})"}
except Exception as e:
return {"error": f"テキスト作成エラー: {e}"}
async def get_drawing_info(self):
"""図面情報を取得"""
try:
doc = self.get_active_document()
if not doc:
return {"error": "AutoCADドキュメントが見つかりません"}
info = {
"name": doc.Name,
"path": doc.FullName if hasattr(doc, 'FullName') else "未保存",
"units": doc.InsUnits if hasattr(doc, 'InsUnits') else "Unknown"
}
return {"drawing_info": info}
except Exception as e:
return {"error": f"図面情報取得エラー: {e}"}
async def main():
server = AutoCADMCPServer()
async with server.run_transport() as session:
await session.wait_until_done()
if __name__ == "__main__":
asyncio.run(main())
```
2. MCPクライアント (AI連携用)
```python
# mcp_autocad_client.py
import asyncio
import json
from mcp import ClientSession, StdioServerParameters
from mcp.client import create_mcp_client
import openai
from typing import Dict, Any
class AutoCADMCPClient:
def __init__(self, openai_api_key: str = None):
self.openai_client = openai.OpenAI(api_key=openai_api_key) if openai_api_key else None
self.mcp_session = None
async def connect_to_mcp_server(self, server_script_path: str):
"""MCPサーバーに接続"""
server_params = StdioServerParameters(
command="python",
args=[server_script_path]
)
async with create_mcp_client(server_params) as (client, sessions):
self.mcp_session = sessions[0]
print("MCPサーバーに接続しました")
async def process_natural_language_command(self, command: str) -> Dict[str, Any]:
"""自然言語コマンドを処理"""
if not self.openai_client:
return {"error": "OpenAI APIキーが設定されていません"}
# 利用可能なツールを取得
available_tools = [
{
"type": "function",
"function": {
"name": "create_line",
"description": "2点間に直線を作成",
"parameters": {
"type": "object",
"properties": {
"start_x": {"type": "number"},
"start_y": {"type": "number"},
"end_x": {"type": "number"},
"end_y": {"type": "number"}
},
"required": ["start_x", "start_y", "end_x", "end_y"]
}
}
},
{
"type": "function",
"function": {
"name": "create_circle",
"description": "円を作成",
"parameters": {
"type": "object",
"properties": {
"center_x": {"type": "number"},
"center_y": {"type": "number"},
"radius": {"type": "number"}
},
"required": ["center_x", "center_y", "radius"]
}
}
},
{
"type": "function",
"function": {
"name": "create_rectangle",
"description": "矩形を作成",
"parameters": {
"type": "object",
"properties": {
"x": {"type": "number"},
"y": {"type": "number"},
"width": {"type": "number"},
"height": {"type": "number"}
},
"required": ["x", "y", "width", "height"]
}
}
},
{
"type": "function",
"function": {
"name": "create_text",
"description": "テキストを作成",
"parameters": {
"type": "object",
"properties": {
"x": {"type": "number"},
"y": {"type": "number"},
"text": {"type": "string"},
"height": {"type": "number"}
},
"required": ["x", "y", "text"]
}
}
},
{
"type": "function",
"function": {
"name": "get_drawing_info",
"description": "現在の図面情報を取得",
"parameters": {
"type": "object",
"properties": {}
}
}
}
]
# OpenAI APIでコマンドを解析
response = self.openai_client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "あなたはAutoCAD作図アシスタントです。ユーザーの自然言語コマンドをAutoCAD操作に変換します。座標は適切な数値を推定してください。"},
{"role": "user", "content": command}
],
tools=available_tools,
tool_choice="auto"
)
message = response.choices[0].message
if message.tool_calls:
tool_call = message.tool_calls[0]
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
# MCPサーバーでツールを実行
result = await self.mcp_session.call_tool(function_name, function_args)
return result
else:
return {"message": message.content}
async def execute_direct_command(self, tool_name: str, **kwargs):
"""直接ツールを実行"""
if not self.mcp_session:
return {"error": "MCPサーバーに接続されていません"}
result = await self.mcp_session.call_tool(tool_name, kwargs)
return result
async def main():
# クライアントの設定
client = AutoCADMCPClient(openai_api_key="your-openai-api-key-here")
# MCPサーバーに接続
await client.connect_to_mcp_server("mcp_autocad_server.py")
# 自然言語コマンドの例
commands = [
"原点から(100,100)まで直線を引いて",
"中心(50,50)、半径30の円を作成して",
"左下(10,10)で幅80、高さ60の四角形を描いて",
"座標(25,25)に'Hello AutoCAD'というテキストを追加して",
"現在の図面情報を教えて"
]
for command in commands:
print(f"\nコマンド: {command}")
result = await client.process_natural_language_command(command)
print(f"結果: {result}")
# 各コマンドの間に少し待機
await asyncio.sleep(1)
if __name__ == "__main__":
asyncio.run(main())
```
3. シンプルな使用例
```python
# simple_example.py
import asyncio
from mcp_autocad_client import AutoCADMCPClient
async def simple_demo():
"""シンプルなデモ"""
client = AutoCADMCPClient()
# MCPサーバーに接続
await client.connect_to_mcp_server("mcp_autocad_server.py")
# 直接コマンド実行
commands = [
("create_line", {"start_x": 0, "start_y": 0, "end_x": 100, "end_y": 100}),
("create_circle", {"center_x": 50, "center_y": 50, "radius": 25}),
("create_rectangle", {"x": 10, "y": 10, "width": 80, "height": 60}),
("create_text", {"x": 25, "y": 25, "text": "AutoCAD AI", "height": 5})
]
for tool_name, args in commands:
print(f"実行: {tool_name} {args}")
result = await client.execute_direct_command(tool_name, **args)
print(f"結果: {result}")
await asyncio.sleep(0.5)
if __name__ == "__main__":
asyncio.run(simple_demo())
```
4. 必要な依存関係
```txt
# requirements.txt
mcp>=1.0.0
pywin32>=300
openai>=1.0.0
asyncio
pythoncom
```
セットアップ手順
1. 必要なパッケージをインストール:
```bash
pip install mcp pywin32 openai
```
1. AutoCADがインストールされていることを確認
2. OpenAI APIキーを設定 (自然言語処理を使用する場合):
```python
client = AutoCADMCPClient(openai_api_key="your-api-key")
```
1. MCPサーバーを起動:
```bash
python mcp_autocad_server.py
```
主な機能
· 直線作成: 2点間の直線描画
· 円作成: 中心座標と半径指定での円描画
· 矩形作成: 位置とサイズ指定での四角形描画
· テキスト追加: 指定位置へのテキスト配置
· 図面情報取得: 現在の図面状態の確認
· 自然言語処理: ChatGPTとの連携によるコマンド解釈
このシステムにより、AIが自然言語でAutoCAD操作を指示でき、自動的に作図を実行できます。MCPプロトコルを使用しているため、様々なAIモデルと連携可能です。
コメント
コメントを投稿