Added chat interface.
This commit is contained in:
parent
8a78e45440
commit
54e5017c38
@ -10,7 +10,7 @@
|
||||
<link href="/assets/dasfad/favicon-32x32.png" rel="icon" sizes="32x32" type="image/png">
|
||||
<link href="/assets/dasfad/favicon-16x16.png" rel="icon" sizes="16x16" type="image/png">
|
||||
<link href="/assets/dasfad/favicon-96x96.png" rel="icon" sizes="96x96" type="image/png">
|
||||
<link rel="preload" href="/node_modules/.vite/deps/HavokPhysics.wasm" as="fetch">
|
||||
<link as="fetch" href="/node_modules/.vite/deps/HavokPhysics.wasm" rel="preload">
|
||||
<title>DASFAD</title>
|
||||
<!-- <link as="script" href="/newRelic.js" rel="preload">
|
||||
<script defer src="/newRelic.js"></script> -->
|
||||
|
||||
@ -102,6 +102,74 @@ export class DiagramManager {
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Chat event listeners for AI-powered diagram creation
|
||||
document.addEventListener('chatCreateEntity', (event: CustomEvent) => {
|
||||
const {entity} = event.detail;
|
||||
this._logger.debug('chatCreateEntity', entity);
|
||||
const object = new DiagramObject(this._scene, this.onDiagramEventObservable, {
|
||||
diagramEntity: entity,
|
||||
actionManager: this._diagramEntityActionManager
|
||||
});
|
||||
this._diagramObjects.set(entity.id, object);
|
||||
this.onDiagramEventObservable.notifyObservers({
|
||||
type: DiagramEventType.ADD,
|
||||
entity: entity
|
||||
}, DiagramEventObserverMask.TO_DB);
|
||||
});
|
||||
|
||||
document.addEventListener('chatRemoveEntity', (event: CustomEvent) => {
|
||||
const {target} = event.detail;
|
||||
this._logger.debug('chatRemoveEntity', target);
|
||||
const entity = this.findEntityByIdOrLabel(target);
|
||||
if (entity) {
|
||||
const diagramObject = this._diagramObjects.get(entity.id);
|
||||
if (diagramObject) {
|
||||
diagramObject.dispose();
|
||||
this._diagramObjects.delete(entity.id);
|
||||
this.onDiagramEventObservable.notifyObservers({
|
||||
type: DiagramEventType.REMOVE,
|
||||
entity: entity
|
||||
}, DiagramEventObserverMask.TO_DB);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('chatModifyEntity', (event: CustomEvent) => {
|
||||
const {target, updates} = event.detail;
|
||||
this._logger.debug('chatModifyEntity', target, updates);
|
||||
const entity = this.findEntityByIdOrLabel(target);
|
||||
if (entity) {
|
||||
const diagramObject = this._diagramObjects.get(entity.id);
|
||||
if (diagramObject) {
|
||||
if (updates.text !== undefined) {
|
||||
diagramObject.text = updates.text;
|
||||
}
|
||||
// Note: color and position updates would require additional DiagramObject methods
|
||||
const updatedEntity = {...entity, ...updates};
|
||||
this.onDiagramEventObservable.notifyObservers({
|
||||
type: DiagramEventType.MODIFY,
|
||||
entity: updatedEntity
|
||||
}, DiagramEventObserverMask.TO_DB);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('chatListEntities', () => {
|
||||
this._logger.debug('chatListEntities');
|
||||
const entities = Array.from(this._diagramObjects.values()).map(obj => ({
|
||||
id: obj.diagramEntity.id,
|
||||
template: obj.diagramEntity.template,
|
||||
text: obj.diagramEntity.text || '',
|
||||
position: obj.diagramEntity.position
|
||||
}));
|
||||
const responseEvent = new CustomEvent('chatListEntitiesResponse', {
|
||||
detail: {entities},
|
||||
bubbles: true
|
||||
});
|
||||
document.dispatchEvent(responseEvent);
|
||||
});
|
||||
|
||||
this._logger.debug("DiagramManager constructed");
|
||||
}
|
||||
|
||||
@ -135,6 +203,21 @@ export class DiagramManager {
|
||||
return appConfigInstance;
|
||||
}
|
||||
|
||||
private findEntityByIdOrLabel(target: string): DiagramEntity | null {
|
||||
// First try direct ID match
|
||||
const byId = this._diagramObjects.get(target);
|
||||
if (byId) {
|
||||
return byId.diagramEntity;
|
||||
}
|
||||
// Then try label match (case-insensitive)
|
||||
const targetLower = target.toLowerCase();
|
||||
for (const [, obj] of this._diagramObjects) {
|
||||
if (obj.diagramEntity.text?.toLowerCase() === targetLower) {
|
||||
return obj.diagramEntity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private onDiagramEvent(event: DiagramEvent) {
|
||||
let diagramObject = this._diagramObjects.get(event?.entity?.id);
|
||||
|
||||
@ -2,7 +2,7 @@ import VrApp from '../../vrApp';
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {Affix, Burger, Group, Menu, Alert, Button, Text} from "@mantine/core";
|
||||
import VrTemplate from "../vrTemplate";
|
||||
import {IconStar, IconInfoCircle} from "@tabler/icons-react";
|
||||
import {IconStar, IconInfoCircle, IconMessageCircle} from "@tabler/icons-react";
|
||||
import VrMenuItem from "../components/vrMenuItem";
|
||||
import CreateDiagramModal from "./createDiagramModal";
|
||||
import ManageDiagramsModal from "./manageDiagramsModal";
|
||||
@ -19,6 +19,7 @@ import {DefaultScene} from "../../defaultScene";
|
||||
import VREntryPrompt from "../components/VREntryPrompt";
|
||||
import ComingSoonBadge from "../components/ComingSoonBadge";
|
||||
import UpgradeBadge from "../components/UpgradeBadge";
|
||||
import ChatPanel from "../components/ChatPanel";
|
||||
|
||||
let vrApp: VrApp = null;
|
||||
|
||||
@ -118,6 +119,7 @@ export default function VrExperience() {
|
||||
const [rerender, setRerender] = useState(0);
|
||||
const [dbName, setDbName] = useState(params.db);
|
||||
const [showVRPrompt, setShowVRPrompt] = useState(false);
|
||||
const [chatOpen, setChatOpen] = useState(!isMobileVRDevice()); // Show chat by default on desktop
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = document.getElementById('vrCanvas');
|
||||
@ -340,10 +342,30 @@ export default function VrExperience() {
|
||||
onClick={getClickHandler(configState, openConfig)}
|
||||
availableIcon={getFeatureIndicator(configState)}/>
|
||||
)}
|
||||
|
||||
<Menu.Divider/>
|
||||
<VrMenuItem
|
||||
tip="Toggle AI chat assistant for creating entities"
|
||||
label={chatOpen ? "Hide Chat" : "Show Chat"}
|
||||
onClick={() => setChatOpen(!chatOpen)}
|
||||
availableIcon={<IconMessageCircle size={16}/>}/>
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
</Affix>
|
||||
<canvas id="vrCanvas" style={{zIndex: 1000, width: '100%', height: '100vh'}}/>
|
||||
|
||||
<div style={{display: 'flex', height: '100vh', width: '100vw', overflow: 'hidden'}}>
|
||||
<div style={{flex: 1, position: 'relative', minWidth: 0}}>
|
||||
<canvas id="vrCanvas" style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
zIndex: 1000
|
||||
}}/>
|
||||
</div>
|
||||
{chatOpen && <ChatPanel onClose={() => setChatOpen(false)}/>}
|
||||
</div>
|
||||
|
||||
{/* VR Entry Prompt - Rendered AFTER canvas to ensure it's on top in DOM order */}
|
||||
<VREntryPrompt
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
/// <reference types="vitest" />
|
||||
import {defineConfig} from "vite";
|
||||
import {defineConfig, loadEnv} from "vite";
|
||||
|
||||
/** @type {import('vite').UserConfig} */
|
||||
export default defineConfig({
|
||||
export default defineConfig(({mode}) => {
|
||||
const env = loadEnv(mode, process.cwd(), '');
|
||||
return {
|
||||
test: {},
|
||||
define: {},
|
||||
build: {
|
||||
@ -23,6 +25,7 @@ export default defineConfig({
|
||||
}
|
||||
},
|
||||
server: {
|
||||
allowedHosts: true,
|
||||
port: 3001,
|
||||
proxy: {
|
||||
'^/sync/.*': {
|
||||
@ -36,6 +39,22 @@ export default defineConfig({
|
||||
'^/api/images': {
|
||||
target: 'https://www.deepdiagram.com/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'^/api/claude': {
|
||||
target: 'https://api.anthropic.com',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api\/claude/, ''),
|
||||
configure: (proxy) => {
|
||||
proxy.on('proxyReq', (proxyReq) => {
|
||||
|
||||
const apiKey = env.ANTHROPIC_API_KEY;
|
||||
console.log(` API KEY: ${apiKey}`);
|
||||
if (apiKey) {
|
||||
proxyReq.setHeader('x-api-key', apiKey);
|
||||
proxyReq.setHeader('anthropic-version', '2023-06-01');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,9 +73,24 @@ export default defineConfig({
|
||||
'^/api/images': {
|
||||
target: 'https://www.deepdiagram.com/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
'^/api/claude': {
|
||||
target: 'https://api.anthropic.com',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api\/claude/, ''),
|
||||
configure: (proxy) => {
|
||||
proxy.on('proxyReq', (proxyReq) => {
|
||||
const apiKey = env.ANTHROPIC_API_KEY;
|
||||
console.log(` API KEY: ${apiKey}`);
|
||||
if (apiKey) {
|
||||
proxyReq.setHeader('x-api-key', apiKey);
|
||||
proxyReq.setHeader('anthropic-version', '2023-06-01');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
base: "/"
|
||||
|
||||
})
|
||||
};
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user