2026-06-06 20:12:40 +07:00
parent de84b2bf48
commit 97ac0f71f5
13682 changed files with 1125938 additions and 0 deletions
@@ -0,0 +1,461 @@
// ===== AIコンテキスト管理システム =====
class ContextManager {
constructor() {
this.conversationHistory = [];
this.projectState = {
currentProject: null,
tasks: [],
completedTasks: [],
pendingTasks: [],
unityState: {},
createdObjects: [],
modifiedObjects: []
};
this.conditionalFlows = new Map();
this.userPreferences = this.loadUserPreferences();
this.lastActions = [];
this.dependencies = new Map();
this.maxHistorySize = 100;
}
// 会話履歴の追加
addToHistory(entry) {
this.conversationHistory.push({
timestamp: new Date(),
...entry
});
// 最大サイズを超えたら古いものを削除
if (this.conversationHistory.length > this.maxHistorySize) {
this.conversationHistory = this.conversationHistory.slice(-this.maxHistorySize);
}
}
// コンテキストから意図を推測
inferIntent(message) {
const lowerMessage = message.toLowerCase();
const lastAction = this.lastActions[this.lastActions.length - 1];
// 条件分岐パターン
const conditionalPatterns = [
{ pattern: /もし(.+)なら(.+)/i, type: 'if_then' },
{ pattern: /(.+)の場合は(.+)/i, type: 'when_then' },
{ pattern: /(.+)かどうか/i, type: 'check_condition' },
{ pattern: /(.+)または(.+)/i, type: 'or_condition' },
{ pattern: /(.+)かつ(.+)/i, type: 'and_condition' }
];
// 続きの操作パターン
const continuationPatterns = [
{ pattern: /次に|それから|その後/i, type: 'sequence' },
{ pattern: /同じ|もう一つ|さらに/i, type: 'repeat' },
{ pattern: /代わりに|ではなく/i, type: 'alternative' },
{ pattern: /全部|すべて|まとめて/i, type: 'batch' }
];
// パターンマッチング
for (const { pattern, type } of conditionalPatterns) {
const match = message.match(pattern);
if (match) {
return { type, match, context: this.getRelevantContext() };
}
}
for (const { pattern, type } of continuationPatterns) {
if (pattern.test(message)) {
return { type, lastAction, context: this.getRelevantContext() };
}
}
// デフォルトの意図推測
return this.inferFromContext(message);
}
// コンテキストベースの意図推測
inferFromContext(message) {
const intent = {
type: 'direct',
confidence: 0.5,
suggestedActions: []
};
// 現在のプロジェクト状態を考慮
if (this.projectState.pendingTasks.length > 0) {
intent.suggestedActions.push({
action: 'continue_tasks',
tasks: this.projectState.pendingTasks.slice(0, 3)
});
intent.confidence += 0.2;
}
// 最近の操作パターンを考慮
const recentPatterns = this.analyzeRecentActions();
if (recentPatterns.repeatingPattern) {
intent.suggestedActions.push({
action: 'repeat_pattern',
pattern: recentPatterns.pattern
});
intent.confidence += 0.15;
}
// ユーザーの好みを考慮
const preferences = this.matchUserPreferences(message);
if (preferences.length > 0) {
intent.preferences = preferences;
intent.confidence += 0.15;
}
return intent;
}
// 条件分岐フローの作成
createConditionalFlow(condition, trueActions, falseActions = []) {
const flowId = `flow_${Date.now()}`;
this.conditionalFlows.set(flowId, {
condition,
trueActions,
falseActions,
executed: false,
result: null
});
return flowId;
}
// 条件の評価
async evaluateCondition(condition, unityState) {
// シンプルな条件評価
if (condition.type === 'object_exists') {
return unityState.gameObjects?.some(obj => obj.name === condition.objectName);
}
if (condition.type === 'property_check') {
const obj = unityState.gameObjects?.find(o => o.name === condition.objectName);
if (obj && condition.property in obj) {
return obj[condition.property] === condition.value;
}
}
if (condition.type === 'scene_check') {
return unityState.activeScene === condition.sceneName;
}
// より複雑な条件は Unity 側で評価
return false;
}
// 最近の操作パターン分析
analyzeRecentActions() {
if (this.lastActions.length < 3) {
return { repeatingPattern: false };
}
// 繰り返しパターンの検出
const recentActions = this.lastActions.slice(-5);
const patterns = {};
for (let i = 0; i < recentActions.length - 1; i++) {
const pattern = `${recentActions[i].type}_${recentActions[i + 1].type}`;
patterns[pattern] = (patterns[pattern] || 0) + 1;
}
// 最も頻繁なパターンを見つける
const mostFrequent = Object.entries(patterns)
.sort(([, a], [, b]) => b - a)[0];
if (mostFrequent && mostFrequent[1] >= 2) {
return {
repeatingPattern: true,
pattern: mostFrequent[0],
frequency: mostFrequent[1]
};
}
return { repeatingPattern: false };
}
// ユーザーの好みをマッチング
matchUserPreferences(message) {
const preferences = [];
const lowerMessage = message.toLowerCase();
// 色の好み
if (this.userPreferences.favoriteColors) {
for (const color of this.userPreferences.favoriteColors) {
if (lowerMessage.includes(color)) {
preferences.push({ type: 'color', value: color });
}
}
}
// UIレイアウトの好み
if (this.userPreferences.uiLayout && lowerMessage.includes('ui')) {
preferences.push({
type: 'ui_layout',
value: this.userPreferences.uiLayout
});
}
// 命名規則の好み
if (this.userPreferences.namingConvention) {
preferences.push({
type: 'naming',
value: this.userPreferences.namingConvention
});
}
return preferences;
}
// タスク間の依存関係を設定
setDependency(taskId, dependsOn) {
if (!this.dependencies.has(taskId)) {
this.dependencies.set(taskId, []);
}
this.dependencies.get(taskId).push(dependsOn);
}
// 実行可能なタスクを取得
getExecutableTasks() {
const completed = new Set(this.projectState.completedTasks.map(t => t.id));
const executable = [];
for (const task of this.projectState.pendingTasks) {
const deps = this.dependencies.get(task.id) || [];
if (deps.every(dep => completed.has(dep))) {
executable.push(task);
}
}
return executable;
}
// プロジェクト状態の更新
updateProjectState(update) {
Object.assign(this.projectState, update);
// Unity状態の同期
if (update.unityState) {
this.projectState.unityState = {
...this.projectState.unityState,
...update.unityState
};
}
}
// アクションの記録
recordAction(action) {
this.lastActions.push({
...action,
timestamp: new Date()
});
// 最大20アクションまで保持
if (this.lastActions.length > 20) {
this.lastActions = this.lastActions.slice(-20);
}
}
// ユーザー設定の読み込み
loadUserPreferences() {
// 実際にはファイルやDBから読み込む
return {
favoriteColors: ['blue', 'green', 'purple'],
uiLayout: 'center',
namingConvention: 'camelCase',
defaultMaterial: 'Standard',
preferredUnits: 'meters'
};
}
// 関連するコンテキストを取得
getRelevantContext() {
return {
recentObjects: this.projectState.createdObjects.slice(-5),
pendingTasks: this.projectState.pendingTasks.slice(0, 5),
lastActions: this.lastActions.slice(-3),
currentScene: this.projectState.unityState.activeScene
};
}
// コンテキストのサマリーを生成
generateContextSummary() {
const summary = {
projectName: this.projectState.currentProject?.name || 'Unnamed Project',
totalTasks: this.projectState.tasks.length,
completedTasks: this.projectState.completedTasks.length,
pendingTasks: this.projectState.pendingTasks.length,
createdObjects: this.projectState.createdObjects.length,
recentActions: this.lastActions.slice(-5).map(a => a.type),
activeFlows: this.conditionalFlows.size
};
return summary;
}
// コンテキストのクリア
clearContext() {
this.conversationHistory = [];
this.projectState = {
currentProject: null,
tasks: [],
completedTasks: [],
pendingTasks: [],
unityState: {},
createdObjects: [],
modifiedObjects: []
};
this.conditionalFlows.clear();
this.lastActions = [];
this.dependencies.clear();
}
}
// シングルトンインスタンス
export const contextManager = new ContextManager();
// ヘルパー関数
export function analyzeUserIntent(message, sendUnityCommand) {
const intent = contextManager.inferIntent(message);
// 条件分岐の処理
if (intent.type === 'if_then') {
const [, condition, action] = intent.match;
return {
type: 'conditional',
condition: parseCondition(condition),
action: parseAction(action),
execute: async () => {
const state = await sendUnityCommand('get_scene_info', {});
const result = await contextManager.evaluateCondition(
parseCondition(condition),
state
);
if (result) {
return await executeAction(parseAction(action), sendUnityCommand);
}
return 'Condition not met';
}
};
}
// 連続操作の処理
if (intent.type === 'sequence') {
return {
type: 'sequence',
previousAction: intent.lastAction,
suggestedNext: getNextInSequence(intent.lastAction),
execute: async () => {
const next = getNextInSequence(intent.lastAction);
if (next) {
return await executeAction(next, sendUnityCommand);
}
return 'No next action in sequence';
}
};
}
// デフォルト処理
return {
type: 'direct',
intent,
execute: async () => {
return await processDirectCommand(message, sendUnityCommand);
}
};
}
// 条件のパース
function parseCondition(conditionText) {
// シンプルな条件パース実装
if (conditionText.includes('存在')) {
const match = conditionText.match(/(.+)が存在/);
if (match) {
return {
type: 'object_exists',
objectName: match[1].trim()
};
}
}
return { type: 'unknown', text: conditionText };
}
// アクションのパース
function parseAction(actionText) {
// シンプルなアクションパース実装
return {
type: 'parsed_action',
text: actionText,
commands: extractCommands(actionText)
};
}
// コマンド抽出
function extractCommands(text) {
const commands = [];
// 作成系コマンド
if (text.includes('作成') || text.includes('作る')) {
commands.push({ type: 'create', text });
}
// 移動系コマンド
if (text.includes('移動') || text.includes('動かす')) {
commands.push({ type: 'move', text });
}
// 変更系コマンド
if (text.includes('変更') || text.includes('変える')) {
commands.push({ type: 'modify', text });
}
return commands;
}
// アクション実行
async function executeAction(action, sendUnityCommand) {
// アクションタイプに基づいて適切なUnityコマンドを実行
for (const command of action.commands) {
switch (command.type) {
case 'create':
await sendUnityCommand('create_gameobject', {
name: 'NewObject',
description: command.text
});
break;
case 'move':
// 移動コマンドの実装
break;
case 'modify':
// 変更コマンドの実装
break;
}
}
return `Executed ${action.commands.length} commands`;
}
// 直接コマンドの処理
async function processDirectCommand(message, sendUnityCommand) {
// 既存のコマンド処理ロジック
return 'Direct command processed';
}
// シーケンスの次のアクション取得
function getNextInSequence(lastAction) {
// シーケンスパターンの定義
const sequences = {
'create_ui_button': { next: 'add_button_script', type: 'enhance' },
'create_gameobject': { next: 'add_component', type: 'enhance' },
'create_material': { next: 'assign_material', type: 'apply' }
};
if (lastAction && sequences[lastAction.type]) {
return sequences[lastAction.type];
}
return null;
}