Initial commit: Chat-to-diagram v1.0
- Chat interface with OpenAI GPT integration - Automatic diagram generation from text descriptions - Tldraw canvas with Dagre layout engine - REST API instead of WebSocket approach 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
99
src/lib/diagram-parser.ts
Normal file
99
src/lib/diagram-parser.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Diagram Parser Utility
|
||||
*
|
||||
* Extracts and validates diagram JSON from AI responses
|
||||
*/
|
||||
|
||||
import { GraphModel } from '@/types/graph';
|
||||
|
||||
/**
|
||||
* Extract diagram JSON from AI response text
|
||||
* Looks for content between [DIAGRAM_START] and [DIAGRAM_END] markers
|
||||
*/
|
||||
export function extractDiagramFromResponse(response: string): GraphModel | null {
|
||||
try {
|
||||
const startMarker = '[DIAGRAM_START]';
|
||||
const endMarker = '[DIAGRAM_END]';
|
||||
|
||||
const startIndex = response.indexOf(startMarker);
|
||||
const endIndex = response.indexOf(endMarker);
|
||||
|
||||
if (startIndex === -1 || endIndex === -1) {
|
||||
console.log('No diagram markers found in response');
|
||||
return null;
|
||||
}
|
||||
|
||||
const jsonStr = response.substring(
|
||||
startIndex + startMarker.length,
|
||||
endIndex
|
||||
).trim();
|
||||
|
||||
const diagram = JSON.parse(jsonStr) as GraphModel;
|
||||
|
||||
// Validate diagram structure
|
||||
if (!validateDiagram(diagram)) {
|
||||
console.error('Invalid diagram structure');
|
||||
return null;
|
||||
}
|
||||
|
||||
return diagram;
|
||||
} catch (error) {
|
||||
console.error('Failed to extract diagram from response:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate diagram structure
|
||||
*/
|
||||
export function validateDiagram(diagram: any): diagram is GraphModel {
|
||||
if (!diagram || typeof diagram !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Array.isArray(diagram.nodes) || !Array.isArray(diagram.edges)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate nodes
|
||||
for (const node of diagram.nodes) {
|
||||
if (!node.id || !node.label || !node.type) {
|
||||
console.error('Invalid node structure:', node);
|
||||
return false;
|
||||
}
|
||||
|
||||
const validTypes = ['start', 'process', 'decision', 'end', 'data', 'default'];
|
||||
if (!validTypes.includes(node.type)) {
|
||||
console.error('Invalid node type:', node.type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate edges
|
||||
for (const edge of diagram.edges) {
|
||||
if (!edge.id || !edge.source || !edge.target) {
|
||||
console.error('Invalid edge structure:', edge);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that source and target nodes exist
|
||||
const sourceExists = diagram.nodes.some((n: any) => n.id === edge.source);
|
||||
const targetExists = diagram.nodes.some((n: any) => n.id === edge.target);
|
||||
|
||||
if (!sourceExists || !targetExists) {
|
||||
console.error('Edge references non-existent node:', edge);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove diagram markers from response text (for display)
|
||||
*/
|
||||
export function stripDiagramMarkers(response: string): string {
|
||||
return response
|
||||
.replace(/\[DIAGRAM_START\][\s\S]*?\[DIAGRAM_END\]/g, '[Diagram generated]')
|
||||
.trim();
|
||||
}
|
||||
Reference in New Issue
Block a user