1+ // Configuration
2+ const OPENAI_API_KEY = process . env . OPENAI_API_KEY ;
3+
4+ // Precomputed point clouds
5+ const POINT_CLOUDS = {
6+ 1 : generateSphere ( 1000 ) ,
7+ 2 : generateCube ( 1000 ) ,
8+ 3 : generateTorus ( 1000 ) ,
9+ 4 : generateCylinder ( 1000 ) ,
10+ 5 : generatePyramid ( 1000 )
11+ } ;
12+
13+ // Function to generate point cloud based on instruction
14+ async function processInstruction ( ) {
15+ const instruction = document . getElementById ( 'instruction' ) . value ;
16+ if ( ! instruction ) {
17+ alert ( 'Please enter an instruction' ) ;
18+ return ;
19+ }
20+
21+ // Show loading spinner
22+ document . getElementById ( 'loading' ) . style . display = 'block' ;
23+
24+ try {
25+ // Call OpenAI API
26+ const response = await fetch ( 'https://api.openai.com/v1/chat/completions' , {
27+ method : 'POST' ,
28+ headers : {
29+ 'Content-Type' : 'application/json' ,
30+ 'Authorization' : `Bearer ${ OPENAI_API_KEY } `
31+ } ,
32+ body : JSON . stringify ( {
33+ model : "gpt-3.5-turbo" ,
34+ messages : [ {
35+ role : "user" ,
36+ content : `Based on this instruction: "${ instruction } ", select the most appropriate 3D shape from these options:
37+ 1: Sphere
38+ 2: Cube
39+ 3: Torus
40+ 4: Cylinder
41+ 5: Pyramid
42+
43+ Return only a JSON object with a single number: {"selection": number}`
44+ } ]
45+ } )
46+ } ) ;
47+
48+ const data = await response . json ( ) ;
49+ const selection = JSON . parse ( data . choices [ 0 ] . message . content ) . selection ;
50+
51+ if ( selection >= 1 && selection <= 5 ) {
52+ visualizePointCloud ( POINT_CLOUDS [ selection ] ) ;
53+ } else {
54+ throw new Error ( response . statusText ) ;
55+ }
56+ } catch ( error ) {
57+ console . error ( 'Error:' , error ) ;
58+ alert ( 'An error occurred while processing your request' ) ;
59+ } finally {
60+ // Hide loading spinner
61+ document . getElementById ( 'loading' ) . style . display = 'none' ;
62+ }
63+ }
64+
65+ // Function to visualize point cloud using Plotly
66+ function visualizePointCloud ( points ) {
67+ const x = points . map ( p => p [ 0 ] ) ;
68+ const y = points . map ( p => p [ 1 ] ) ;
69+ const z = points . map ( p => p [ 2 ] ) ;
70+
71+ const trace = {
72+ type : 'scatter3d' ,
73+ mode : 'markers' ,
74+ x : x ,
75+ y : y ,
76+ z : z ,
77+ marker : {
78+ size : 2 ,
79+ color : z ,
80+ colorscale : 'Viridis' ,
81+ opacity : 0.8
82+ }
83+ } ;
84+
85+ const layout = {
86+ title : '3D Point Cloud Visualization' ,
87+ scene : {
88+ xaxis : { title : 'X' } ,
89+ yaxis : { title : 'Y' } ,
90+ zaxis : { title : 'Z' }
91+ } ,
92+ margin : {
93+ l : 0 ,
94+ r : 0 ,
95+ b : 0 ,
96+ t : 30
97+ }
98+ } ;
99+
100+ Plotly . newPlot ( 'visualization' , [ trace ] , layout ) ;
101+ }
102+
103+ // Point cloud generation functions
104+ function generateSphere ( numPoints ) {
105+ const points = [ ] ;
106+ for ( let i = 0 ; i < numPoints ; i ++ ) {
107+ const theta = Math . random ( ) * 2 * Math . PI ;
108+ const phi = Math . acos ( 2 * Math . random ( ) - 1 ) ;
109+ const r = 1 ;
110+
111+ const x = r * Math . sin ( phi ) * Math . cos ( theta ) ;
112+ const y = r * Math . sin ( phi ) * Math . sin ( theta ) ;
113+ const z = r * Math . cos ( phi ) ;
114+
115+ points . push ( [ x , y , z ] ) ;
116+ }
117+ return points ;
118+ }
119+
120+ function generateCube ( numPoints ) {
121+ const points = [ ] ;
122+ for ( let i = 0 ; i < numPoints ; i ++ ) {
123+ const x = Math . random ( ) * 2 - 1 ;
124+ const y = Math . random ( ) * 2 - 1 ;
125+ const z = Math . random ( ) * 2 - 1 ;
126+ points . push ( [ x , y , z ] ) ;
127+ }
128+ return points ;
129+ }
130+
131+ function generateTorus ( numPoints ) {
132+ const points = [ ] ;
133+ const R = 1 ; // major radius
134+ const r = 0.3 ; // minor radius
135+ for ( let i = 0 ; i < numPoints ; i ++ ) {
136+ const theta = Math . random ( ) * 2 * Math . PI ;
137+ const phi = Math . random ( ) * 2 * Math . PI ;
138+
139+ const x = ( R + r * Math . cos ( phi ) ) * Math . cos ( theta ) ;
140+ const y = ( R + r * Math . cos ( phi ) ) * Math . sin ( theta ) ;
141+ const z = r * Math . sin ( phi ) ;
142+
143+ points . push ( [ x , y , z ] ) ;
144+ }
145+ return points ;
146+ }
147+
148+ function generateCylinder ( numPoints ) {
149+ const points = [ ] ;
150+ const height = 2 ;
151+ const radius = 0.5 ;
152+ for ( let i = 0 ; i < numPoints ; i ++ ) {
153+ const theta = Math . random ( ) * 2 * Math . PI ;
154+ const h = Math . random ( ) * height - height / 2 ;
155+
156+ const x = radius * Math . cos ( theta ) ;
157+ const y = radius * Math . sin ( theta ) ;
158+ const z = h ;
159+
160+ points . push ( [ x , y , z ] ) ;
161+ }
162+ return points ;
163+ }
164+
165+ function generatePyramid ( numPoints ) {
166+ const points = [ ] ;
167+ const size = 2 ;
168+ for ( let i = 0 ; i < numPoints ; i ++ ) {
169+ const x = Math . random ( ) * size - size / 2 ;
170+ const y = Math . random ( ) * size - size / 2 ;
171+ const z = Math . random ( ) * size ;
172+
173+ // Create pyramid shape by scaling z based on distance from center
174+ const distFromCenter = Math . sqrt ( x * x + y * y ) ;
175+ const scale = 1 - ( distFromCenter / ( size / 2 ) ) ;
176+ const finalZ = z * scale ;
177+
178+ points . push ( [ x , y , finalZ ] ) ;
179+ }
180+ return points ;
181+ }
182+
183+ // Add event listener for Enter key
184+ document . getElementById ( 'instruction' ) . addEventListener ( 'keypress' , function ( e ) {
185+ if ( e . key === 'Enter' ) {
186+ processInstruction ( ) ;
187+ }
188+ } ) ;
0 commit comments