From 7345849b2ec59d87ff3c16833d4739e87bdb2147 Mon Sep 17 00:00:00 2001 From: phischdev Date: Fri, 19 Jul 2024 00:58:54 +0200 Subject: [PATCH 1/2] Update clustering, etc. SQUASHED: AUTO-COMMIT-src-components-tools-astro-plot.js,AUTO-COMMIT-src-components-tools-astro-view-example-transformer.py,AUTO-COMMIT-src-components-tools-astro-view.html,AUTO-COMMIT-src-components-tools-astro-view.js,AUTO-COMMIT-src-components-tools-astro-view.js.l4a, --- src/components/tools/astro-plot.js | 28 +++++++++----- .../tools/astro-view-example-transformer.py | 14 +++++-- src/components/tools/astro-view.html | 12 +++++- src/components/tools/astro-view.js | 38 ++++++++++++++++++- src/components/tools/astro-view.js.l4a | 2 +- 5 files changed, 77 insertions(+), 17 deletions(-) diff --git a/src/components/tools/astro-plot.js b/src/components/tools/astro-plot.js index 070754a34..69de3bef4 100644 --- a/src/components/tools/astro-plot.js +++ b/src/components/tools/astro-plot.js @@ -64,8 +64,13 @@ export default class AstroPlot extends Morph { return str.slice(0, 100).replace('\n', '
'); } - async displayData(features, clusters) { - if (!clusters) clusters = Array(features.length).fill(0); + async updateLabels(labels) { + // # TODO + let container = this.get('#embedding_plot') + Plotly.restyle(container, 'marker.color', labels) + } + + async displayData(features) { const dataframe = { _push(el) { @@ -81,21 +86,23 @@ export default class AstroPlot extends Morph { plot_title, plot_content, file, - id + id, + cluster }, i) => dataframe._push({ x: umap_embedding[0], y: umap_embedding[1], z: umap_embedding[2], - color: clusters[i], + color: cluster, customdata: { - cluster: 'Cluster ' + clusters[i], + cluster: 'Cluster ' + cluster, content: plot_content, title: plot_title, file, contentAbbr: `${this.displayContent(plot_content)}...` }, // text: ' ' + plot_title, // ' '+ neccessary!! - ids: id || i + ids: id || i, + cluster })); const data = [ @@ -109,7 +116,7 @@ export default class AstroPlot extends Morph { width: 0.5 }, opacity: 0.8, - color: clusters, + color: dataframe.cluster, colorscale: 'Viridis', }, selected: { @@ -164,6 +171,7 @@ export default class AstroPlot extends Morph { container.on('plotly_click', (data) => { + debugger let item = data.points[0]; // Update the plot with new selected points @@ -188,10 +196,10 @@ export default class AstroPlot extends Morph { //const getRealData = async () => await fetch("http://127.0.0.1:5000/dataset/d3-force-main/umap") // const response = await getRealData(); - const features = await getRealData(); //await response.json() - const clusters = await getClusters(); + // const features = await getRealData(); //await response.json() + //const clusters = await getClusters(); - await this.displayData(features, clusters); + // await this.displayData(features); } /* diff --git a/src/components/tools/astro-view-example-transformer.py b/src/components/tools/astro-view-example-transformer.py index 1fd847252..176cd26d9 100644 --- a/src/components/tools/astro-view-example-transformer.py +++ b/src/components/tools/astro-view-example-transformer.py @@ -49,6 +49,14 @@ def reduce(self, df): # multiply whole columns by respective scalar, then add them together return \ - df['method_embedding'] * 0.8 + \ - df['class_name_embedding'] * 0.1 + \ - df['identifier_mean'] + 0.1 \ No newline at end of file + df['method_embedding'] * 0.5 + \ + df['class_name_embedding'] * 0.4 + \ + df['identifier_mean'] + 0.1 + + def cluster(self): + from sklearn.cluster import AgglomerativeClustering + return AgglomerativeClustering( + n_clusters=None, + distance_threshold=130, + linkage='ward' + ) \ No newline at end of file diff --git a/src/components/tools/astro-view.html b/src/components/tools/astro-view.html index ae67d726b..6cef4c7b5 100644 --- a/src/components/tools/astro-view.html +++ b/src/components/tools/astro-view.html @@ -68,6 +68,10 @@ max-height: 300px } + #pool-embedding { + white-space: pre-wrap; + } + .token { margin: 2px; padding: 2px; display:inline-block } @@ -142,6 +146,9 @@
+ @@ -154,8 +161,11 @@ +
diff --git a/src/components/tools/astro-view.js b/src/components/tools/astro-view.js index 5ffe1e019..9a1b0fa96 100644 --- a/src/components/tools/astro-view.js +++ b/src/components/tools/astro-view.js @@ -61,9 +61,11 @@ export default class AstroView extends Morph { get astInspector() { return this.get("#ast"); } get updateButton() { return this.get("#update"); } + get computeEmbeddings() { return this.get("#computeEmbeddings")} get runQueryButton() { return this.get('#runQuery'); } get runMapButton() { return this.get('#runMap'); } get runReduceButton() { return this.get('#runReduce'); } + get runClusterButton() { return this.get('#runCluster')} get autoUpdate() { return this._autoUpdate; } set autoUpdate(bool) { @@ -317,10 +319,25 @@ export default class AstroView extends Morph { } } + async onComputeEmbeddings() { + this.status ="generating embeddings: long running task. check backend logs"; + try { + let language = "typescript"; // HARDCODED CHANGE HERE + let response = await fetch(`${this.api}/dataset/${this.projectName}/make_context_embeddings?language=${language}`, { + method: 'POST', + }) + response = await response.json(); + if (response.error) throw new Error(response.error); + this.status = `generating embeddings: ${JSON.stringify(response.stats)}`; + } catch (e) { + this.status = "generating embeddings: " + e; + } + } + async onRunParse() { this.status = "parser: running..." try { - let language = "typescript"; + let language = "typescript"; // HARDCODED CHANGE HERE let response = await fetch(`${this.api}/dataset/${this.projectName}/parse?language=${language}`, { method: 'POST', }) @@ -397,7 +414,25 @@ export default class AstroView extends Morph { } } + async onRunCluster() { + this.status = "clustering: running..." + let data; + try { + let response = await fetch(`${this.api}/dataset/${this.projectName}/run_cluster`, { + method: 'POST', + }) + response = await response.json(); + if (response.error) throw new Error(response.error); + let clusters = response.clusters; + this.status = "clustering: success. " + clusters + ' clusters found.'; + } catch (e) { + this.status = "clustering: " + e; + return; + } + } + async onItemClicked(e) { + debugger const item = e.detail; let id = item.id; @@ -414,7 +449,6 @@ export default class AstroView extends Morph { const source = item.plot_content; this.sourceCM.setValue(source); - debugger } catch (e) { this.status = "get item: " + e; } diff --git a/src/components/tools/astro-view.js.l4a b/src/components/tools/astro-view.js.l4a index 6ca6df302..a29ad79ad 100644 --- a/src/components/tools/astro-view.js.l4a +++ b/src/components/tools/astro-view.js.l4a @@ -1 +1 @@ -{"type":"Reference","version":"3e2e5524c855d1d6d5b2b4c8626697353c198a0e","content":"/*MD # Astro View - AST Token View spelled wrong\n\nMD*/\n\n\nimport Morph from 'src/components/widgets/lively-morph.js';\nimport SyntaxChecker from 'src/client/syntax.js'\n\nimport { uuid as generateUUID, debounce, flatmap, executeAllTestRunners, promisedEvent, loc, range } from 'utils';\n\nexport default class AstroView extends Morph {\n\n static get defaultSourceURL() { return lively4url + \"/src/components/tools/astro-view-example-source.js\"; }\n static get defaultTransformerSourceURL() { return lively4url + \"/src/components/tools/astro-view-example-transformer.py\"; }\n static get defaultWorkspaceURL() { return lively4url + \"/src/components/tools/astro-view-example-workspace.js\"; }\n \n \n\n /*MD ## UI Accessing MD*/\n get container() { return this.get(\"#content\"); }\n \n // Status Text\n get statusLine() { return this.get(\"#status\"); }\n set status(text) { this.statusLine.innerHTML = text; }\n \n // Source\n get sourceEditor() { return this.get(\"#source\"); } \n get sourceLCM() { return this.sourceEditor.livelyCodeMirror(); }\n get sourceCM() { return this.sourceEditor.currentEditor(); }\n get source() { return this.sourceCM.getValue(); }\n \n // Source Path\n get sourcePath() { return this.get(\"#sourcePath\"); }\n get sourceURL() { return this.sourcePath.value; }\n set sourceURL(urlString) { this.sourcePath.value = urlString; }\n onSourcePathEntered(urlString) { this.loadSourceFile(urlString); }\n \n // Project Name\n get projectNameInput() { return this.get('#projectName'); }\n get projectName() { return this.projectNameInput.value; }\n set projectName(text) { this.projectNameInput.value = text; }\n \n // Transformer Code\n get transformerSourceEditor() { return this.get(\"#transformerSource\"); } \n get transformerSourceLCM() { return this.transformerSourceEditor.livelyCodeMirror(); }\n get transformerSourceCM() { return this.transformerSourceEditor.currentEditor(); }\n get transformerSource() { return this.transformerSourceCM.getValue(); }\n \n // Transformer Code Path\n get transformerSourcePath() { return this.get(\"#transformerSourcePath\"); }\n get transformerSourceURL() { return this.transformerSourcePath.value; }\n set transformerSourceURL(urlString) { this.transformerSourcePath.value = urlString; }\n onTransformerSourcePathEntered(urlString) { this.loadTransformerSourceFile(urlString); }\n \n // Plot\n get astroPlot() { return this.get(\"#astro-plot\"); }\n \n get api() { return \"http://127.0.0.1:5000\"; }\n \n \n get astInspector() { return this.get(\"#ast\"); }\n \n get updateButton() { return this.get(\"#update\"); }\n get runQueryButton() { return this.get('#runQuery'); }\n get runMapButton() { return this.get('#runMap'); }\n get runReduceButton() { return this.get('#runReduce'); }\n \n get autoUpdate() { return this._autoUpdate; }\n set autoUpdate(bool) {\n this.updateButton.classList.toggle(\"on\", bool);\n this.updateButton.querySelector(\"i\").classList.toggle(\"fa-spin\", bool);\n this._autoUpdate = bool;\n }\n onUpdate(evt) {\n if (evt.button === 2) this.autoUpdate = !this.autoUpdate;\n this.update();\n }\n \n log(s) {\n console.log(s)\n }\n\n /*MD ## Initialization MD*/\n\n async loadSourceFile(urlString) {\n console.log(\"LOAD \", urlString);\n this.sourceURL = urlString;\n this.sourceEditor.setURL(lively.paths.normalizePath(urlString, \"\"));\n await this.sourceEditor.loadFile();\n await this.update(); \n }\n \n async loadTransformerSourceFile(urlString) {\n console.log(\"LOAD \", urlString);\n this.transformerSourceURL = urlString;\n this.transformerSourceEditor.setURL(lively.paths.normalizePath(urlString, \"\"));\n await this.transformerSourceEditor.loadFile();\n await this.update(); \n }\n \n async initialize() {\n this.windowTitle = \"Astro View\";\n this.registerButtons();\n\n this.getAllSubmorphs(\"button\").forEach(button => {\n button.addEventListener('contextmenu', e => {\n e.preventDefault();\n e.stopPropagation();\n e.currentTarget.dispatchEvent(new MouseEvent(\"click\", {button: 2}));\n });\n });\n \n await this.sourceEditor.awaitEditor();\n await this.transformerSourceEditor.awaitEditor();\n \n this.sourceEditor.hideToolbar();\n this.astInspector.connectEditor(this.sourceEditor);\n this.sourceLCM.doSave = async () => {\n this.save();\n };\n this.transformerSourceLCM.doSave = async () => {\n this.save();\n };\n \n this.sourceEditor.livelyCodeMirror().editor.on(\"cursorActivity\", (cm) => {\n // #TODO continue here....\n console.log(cm)\n // this.selectPath(pathKeys);\n })\n \n this.debouncedUpdate = this.update::debounce(500);\n this.sourceLCM.addEventListener(\"change\", (() =>\n SyntaxChecker.checkForSyntaxErrors(this.sourceCM))::debounce(200));\n this.sourceLCM.addEventListener(\"change\", () => {\n if (this.autoUpdate) this.debouncedUpdate()\n });\n \n this.debouncedUpdateTransformer = this.updateTransformer::debounce(500);\n this.transformerSourceLCM.addEventListener(\"change\", (() => {\n // SyntaxChecker.checkForSyntaxErrors(this.transformerSourceCM))::debounce(200) \n }));\n this.transformerSourceLCM.addEventListener(\"change\", () => {\n if (this.autoUpdate) this.debouncedUpdateTransformer()\n });\n \n this.sourcePath.addEventListener(\"keyup\", evt => {\n if (evt.code == \"Enter\") this.onSourcePathEntered(this.sourcePath.value);\n });\n this.transformerSourcePath.addEventListener(\"keyup\", evt => {\n if (evt.code == \"Enter\") this.onTransformerSourcePathEntered(this.transformerSourcePath.value);\n });\n \n this.astroPlot.addEventListener('item_click', evt => this.onItemClicked(evt));\n\n const source = this.getAttribute(\"source\");\n if (source) this.loadSourceFile(source);\n \n const transformerSource = this.getAttribute(\"transformerSource\");\n if (transformerSource) this.loadTransformerSourceFile(transformerSource);\n \n this.projectName = this.getAttribute(\"projectName\") || \"\";\n \n this.autoUpdate = true;\n\n this.dispatchEvent(new CustomEvent(\"initialize\"));\n }\n\n onEditorCursorActivity(cm) {\n var from = cm.getCursor(true)\n var to = cm.getCursor(false)\n \n this.get(\"#editorInfo\").textContent = `${cm.indexFromPos(from)}-${cm.indexFromPos(to)}`\n }\n \n async updateTokens() { \n let api = \"http://127.0.0.1:5000\";\n let dataset = \"d3-force-main\";\n \n this.status = \"source updated: fetching...\"\n \n try {\n this.tokens = null;\n \n let response = await fetch(`${api}/tokenize`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n text: this.source\n })\n })\n \n let tokens = await response.json();\n // filter new-lines\n tokens = tokens.filter(ea => !ea.value.match(/^[ \\n]+$/));\n \n this.tokens = tokens;\n } catch (e) {\n this.status = `error fetching tokens: ${e}`;\n this.log(`error fetching tokens: ${e}`);\n }\n \n try {\n let response = await fetch(`${api}/dataset/${dataset}/embedding`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n text: this.source\n }),\n })\n \n let embedding = await response.json()\n this.embedding = embedding;\n } catch (e) {\n this.log(`error fetching embedding: ${e}`);\n this.status = `error fetching embedding: ${e}`;\n }\n \n if (this.embedding) {\n let formatted = JSON.stringify(this.embedding)\n this.get('#pool_embedding').innerText = formatted\n this.get('#astro-plot').showFeature(this.embedding)\n }\n\n this.log('fetched tokens', this.tokens)\n \n if (this.tokens) {\n this.get(\"#tokens\").innerHTML = \"\"\n this.tokens.forEach((token) => {\n let tokenView = \n
\n
{token.id}
\n
this.selectToken(tokenView, token)}\n pointerenter={() => this.hoverToken(tokenView, token, true)}\n pointerleave={() => this.hoverToken(tokenView, token, false)}\n >{token.value}
\n
{token.start}-{token.end}
\n
\n this.get(\"#tokens\").appendChild(tokenView)\n })\n } else {\n this.get(\"#tokens\").innerHTML = \"Error fetching tokens\"\n this.status = `error fetching tokens`;\n }\n }\n \n selectToken(view, token) {\n if (this.selectedTokenView) this.selectedTokenView.classList.remove(\"selected\")\n view.classList.add(\"selected\")\n this.selectedTokenView = view\n \n this.get(\"#embeddings\").innerHTML = \"\"\n let rows = []\n \n let tds = Array.from(token.value)\n .map(ea => ea.charCodeAt(0))\n .map(ea => {ea})\n \n rows.push({...tds})\n \n let table = {...rows}
\n \n this.get(\"#embeddings\").appendChild(table)\n \n }\n \n \n hoverToken(view, token, active) {\n if (active) {\n const start = loc(this.sourceCM.posFromIndex(token.start));\n const end = loc(this.sourceCM.posFromIndex(token.end));\n this.hoverMarker = this.sourceCM.markText(start.asCM(), end.asCM(), {css: \"background-color: #fe3\"});\n } else {\n this.hoverMarker.clear();\n this.hoverMarker = null;\n }\n }\n \n /*MD ## Execution MD*/\n \n async update() {\n this.lastSource = this.source\n this.log(\"source code changed, length: \" + this.source.length + \"\")\n \n try {\n var node = await this.astInspector.treeSitterParse(this.source)\n this.treeSitterRootNode = node.rootNode\n this.astInspector.inspect(this.treeSitterRootNode);\n } catch (e) {\n this.astInspector.inspect({Error: e.message});\n }\n \n this.updateTokens();\n }\n \n async updateTransformer() {\n this.status = \"transformer: sending...\"\n try {\n let response = await fetch(`${this.api}/dataset/${this.projectName}/transformer`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n text: this.transformerSource\n }),\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n this.status = \"transformer: using \" + response.transformer;\n } catch (e) {\n this.status = \"transformer: \" + e;\n }\n }\n \n async onRunParse() {\n this.status = \"parser: running...\"\n try {\n let language = \"typescript\";\n let response = await fetch(`${this.api}/dataset/${this.projectName}/parse?language=${language}`, {\n method: 'POST',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n this.status = `parser: currently ${response.ASTs} ASTs in memory. ${response.features} tokens with embeddings`;\n } catch (e) {\n this.status = \"parser: \" + e;\n }\n }\n \n async onRunQuery() {\n this.status = \"query: running...\"\n try {\n let response = await fetch(`${this.api}/dataset/${this.projectName}/run_query`, {\n method: 'POST',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n this.status = \"query: matched \" + response.matches + \" items in \" + response.files + \" files\";\n } catch (e) {\n this.status = \"query: \" + e;\n }\n }\n \n async onRunMap() {\n this.status = \"map: running...\"\n try {\n let response = await fetch(`${this.api}/dataset/${this.projectName}/run_map`, {\n method: 'POST',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n this.status = (\"map: success. Data columns: \\n\" + response.columns).replaceAll('\\n', '
');\n } catch (e) {\n this.status = \"map: \" + e;\n }\n }\n \n async onRunReduce() {\n this.status = \"reduce: running...\"\n try {\n let response = await fetch(`${this.api}/dataset/${this.projectName}/run_reduce`, {\n method: 'POST',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n this.status = \"reduce: success\";\n } catch (e) {\n this.status = \"reduce: \" + e;\n }\n }\n \n async onRunUmap() {\n this.status = \"umap: running...\"\n let data;\n try {\n let response = await fetch(`${this.api}/dataset/${this.projectName}/run_umap`, {\n method: 'POST',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n data = response.umap;\n this.status = \"umap: success\";\n } catch (e) {\n this.status = \"umap: \" + e;\n return;\n }\n \n try {\n this.astroPlot.displayData(data)\n } catch (e) {\n this.status = \"plot: \" + e;\n }\n }\n \n async onItemClicked(e) {\n const item = e.detail;\n let id = item.id;\n \n this.status = \"get item: running...\"\n try {\n let response = await fetch(`${this.api}/dataset/${this.projectName}/embeddings/${id}`, {\n method: 'GET',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n this.status = \"get item: success\";\n \n const item = JSON.parse(response.item);\n const source = item.plot_content;\n \n this.sourceCM.setValue(source);\n debugger\n } catch (e) {\n this.status = \"get item: \" + e;\n }\n }\n\n async save() {\n if (this.sourceURL) {\n await this.sourceEditor.saveFile();\n }\n if (this.transformerSourceURL) {\n await this.transformerSourceEditor.saveFile();\n }\n this.update();\n }\n\n /*MD ## Lively Integration MD*/\n\n livelyPrepareSave() {\n this.setAttribute('source', this.sourceURL);\n this.setAttribute('transformerSource', this.transformerSourceURL);\n this.setAttribute('projectName', this.projectName);\n \n console.log(\"PREPARE SAVE (AST Explorer)\");\n }\n \n livelyMigrate(other) {\n }\n\n async livelyExample() {\n await this.loadSourceFile(AstroView.defaultSourceURL);\n await this.loadTransformerSourceFile(AstroView.defaultTransformerSourceURL)\n }\n}"} \ No newline at end of file +{"type":"Reference","version":"d81cbd8e321e79fc3bf3e4e4ae9dc648ea5f3908","content":"/*MD # Astro View - AST Token View spelled wrong\n\nMD*/\n\n\nimport Morph from 'src/components/widgets/lively-morph.js';\nimport SyntaxChecker from 'src/client/syntax.js'\n\nimport { uuid as generateUUID, debounce, flatmap, executeAllTestRunners, promisedEvent, loc, range } from 'utils';\n\nexport default class AstroView extends Morph {\n\n static get defaultSourceURL() { return lively4url + \"/src/components/tools/astro-view-example-source.js\"; }\n static get defaultTransformerSourceURL() { return lively4url + \"/src/components/tools/astro-view-example-transformer.py\"; }\n static get defaultWorkspaceURL() { return lively4url + \"/src/components/tools/astro-view-example-workspace.js\"; }\n \n \n\n /*MD ## UI Accessing MD*/\n get container() { return this.get(\"#content\"); }\n \n // Status Text\n get statusLine() { return this.get(\"#status\"); }\n set status(text) { this.statusLine.innerHTML = text; }\n \n // Source\n get sourceEditor() { return this.get(\"#source\"); } \n get sourceLCM() { return this.sourceEditor.livelyCodeMirror(); }\n get sourceCM() { return this.sourceEditor.currentEditor(); }\n get source() { return this.sourceCM.getValue(); }\n \n // Source Path\n get sourcePath() { return this.get(\"#sourcePath\"); }\n get sourceURL() { return this.sourcePath.value; }\n set sourceURL(urlString) { this.sourcePath.value = urlString; }\n onSourcePathEntered(urlString) { this.loadSourceFile(urlString); }\n \n // Project Name\n get projectNameInput() { return this.get('#projectName'); }\n get projectName() { return this.projectNameInput.value; }\n set projectName(text) { this.projectNameInput.value = text; }\n \n // Transformer Code\n get transformerSourceEditor() { return this.get(\"#transformerSource\"); } \n get transformerSourceLCM() { return this.transformerSourceEditor.livelyCodeMirror(); }\n get transformerSourceCM() { return this.transformerSourceEditor.currentEditor(); }\n get transformerSource() { return this.transformerSourceCM.getValue(); }\n \n // Transformer Code Path\n get transformerSourcePath() { return this.get(\"#transformerSourcePath\"); }\n get transformerSourceURL() { return this.transformerSourcePath.value; }\n set transformerSourceURL(urlString) { this.transformerSourcePath.value = urlString; }\n onTransformerSourcePathEntered(urlString) { this.loadTransformerSourceFile(urlString); }\n \n // Plot\n get astroPlot() { return this.get(\"#astro-plot\"); }\n \n get api() { return \"http://127.0.0.1:5000\"; }\n \n \n get astInspector() { return this.get(\"#ast\"); }\n \n get updateButton() { return this.get(\"#update\"); }\n get computeEmbeddings() { return this.get(\"#computeEmbeddings\")}\n get runQueryButton() { return this.get('#runQuery'); }\n get runMapButton() { return this.get('#runMap'); }\n get runReduceButton() { return this.get('#runReduce'); }\n get runClusterButton() { return this.get('#runCluster')}\n \n get autoUpdate() { return this._autoUpdate; }\n set autoUpdate(bool) {\n this.updateButton.classList.toggle(\"on\", bool);\n this.updateButton.querySelector(\"i\").classList.toggle(\"fa-spin\", bool);\n this._autoUpdate = bool;\n }\n onUpdate(evt) {\n if (evt.button === 2) this.autoUpdate = !this.autoUpdate;\n this.update();\n }\n \n log(s) {\n console.log(s)\n }\n\n /*MD ## Initialization MD*/\n\n async loadSourceFile(urlString) {\n console.log(\"LOAD \", urlString);\n this.sourceURL = urlString;\n this.sourceEditor.setURL(lively.paths.normalizePath(urlString, \"\"));\n await this.sourceEditor.loadFile();\n await this.update(); \n }\n \n async loadTransformerSourceFile(urlString) {\n console.log(\"LOAD \", urlString);\n this.transformerSourceURL = urlString;\n this.transformerSourceEditor.setURL(lively.paths.normalizePath(urlString, \"\"));\n await this.transformerSourceEditor.loadFile();\n await this.update(); \n }\n \n async initialize() {\n this.windowTitle = \"Astro View\";\n this.registerButtons();\n\n this.getAllSubmorphs(\"button\").forEach(button => {\n button.addEventListener('contextmenu', e => {\n e.preventDefault();\n e.stopPropagation();\n e.currentTarget.dispatchEvent(new MouseEvent(\"click\", {button: 2}));\n });\n });\n \n await this.sourceEditor.awaitEditor();\n await this.transformerSourceEditor.awaitEditor();\n \n this.sourceEditor.hideToolbar();\n this.astInspector.connectEditor(this.sourceEditor);\n this.sourceLCM.doSave = async () => {\n this.save();\n };\n this.transformerSourceLCM.doSave = async () => {\n this.save();\n };\n \n this.sourceEditor.livelyCodeMirror().editor.on(\"cursorActivity\", (cm) => {\n // #TODO continue here....\n console.log(cm)\n // this.selectPath(pathKeys);\n })\n \n this.debouncedUpdate = this.update::debounce(500);\n this.sourceLCM.addEventListener(\"change\", (() =>\n SyntaxChecker.checkForSyntaxErrors(this.sourceCM))::debounce(200));\n this.sourceLCM.addEventListener(\"change\", () => {\n if (this.autoUpdate) this.debouncedUpdate()\n });\n \n this.debouncedUpdateTransformer = this.updateTransformer::debounce(500);\n this.transformerSourceLCM.addEventListener(\"change\", (() => {\n // SyntaxChecker.checkForSyntaxErrors(this.transformerSourceCM))::debounce(200) \n }));\n this.transformerSourceLCM.addEventListener(\"change\", () => {\n if (this.autoUpdate) this.debouncedUpdateTransformer()\n });\n \n this.sourcePath.addEventListener(\"keyup\", evt => {\n if (evt.code == \"Enter\") this.onSourcePathEntered(this.sourcePath.value);\n });\n this.transformerSourcePath.addEventListener(\"keyup\", evt => {\n if (evt.code == \"Enter\") this.onTransformerSourcePathEntered(this.transformerSourcePath.value);\n });\n \n this.astroPlot.addEventListener('item_click', evt => this.onItemClicked(evt));\n\n const source = this.getAttribute(\"source\");\n if (source) this.loadSourceFile(source);\n \n const transformerSource = this.getAttribute(\"transformerSource\");\n if (transformerSource) this.loadTransformerSourceFile(transformerSource);\n \n this.projectName = this.getAttribute(\"projectName\") || \"\";\n \n this.autoUpdate = true;\n\n this.dispatchEvent(new CustomEvent(\"initialize\"));\n }\n\n onEditorCursorActivity(cm) {\n var from = cm.getCursor(true)\n var to = cm.getCursor(false)\n \n this.get(\"#editorInfo\").textContent = `${cm.indexFromPos(from)}-${cm.indexFromPos(to)}`\n }\n \n async updateTokens() { \n let api = \"http://127.0.0.1:5000\";\n let dataset = \"d3-force-main\";\n \n this.status = \"source updated: fetching...\"\n \n try {\n this.tokens = null;\n \n let response = await fetch(`${api}/tokenize`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n text: this.source\n })\n })\n \n let tokens = await response.json();\n // filter new-lines\n tokens = tokens.filter(ea => !ea.value.match(/^[ \\n]+$/));\n \n this.tokens = tokens;\n } catch (e) {\n this.status = `error fetching tokens: ${e}`;\n this.log(`error fetching tokens: ${e}`);\n }\n \n try {\n let response = await fetch(`${api}/dataset/${dataset}/embedding`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n text: this.source\n }),\n })\n \n let embedding = await response.json()\n this.embedding = embedding;\n } catch (e) {\n this.log(`error fetching embedding: ${e}`);\n this.status = `error fetching embedding: ${e}`;\n }\n \n if (this.embedding) {\n let formatted = JSON.stringify(this.embedding)\n this.get('#pool_embedding').innerText = formatted\n this.get('#astro-plot').showFeature(this.embedding)\n }\n\n this.log('fetched tokens', this.tokens)\n \n if (this.tokens) {\n this.get(\"#tokens\").innerHTML = \"\"\n this.tokens.forEach((token) => {\n let tokenView = \n
\n
{token.id}
\n
this.selectToken(tokenView, token)}\n pointerenter={() => this.hoverToken(tokenView, token, true)}\n pointerleave={() => this.hoverToken(tokenView, token, false)}\n >{token.value}
\n
{token.start}-{token.end}
\n
\n this.get(\"#tokens\").appendChild(tokenView)\n })\n } else {\n this.get(\"#tokens\").innerHTML = \"Error fetching tokens\"\n this.status = `error fetching tokens`;\n }\n }\n \n selectToken(view, token) {\n if (this.selectedTokenView) this.selectedTokenView.classList.remove(\"selected\")\n view.classList.add(\"selected\")\n this.selectedTokenView = view\n \n this.get(\"#embeddings\").innerHTML = \"\"\n let rows = []\n \n let tds = Array.from(token.value)\n .map(ea => ea.charCodeAt(0))\n .map(ea => {ea})\n \n rows.push({...tds})\n \n let table = {...rows}
\n \n this.get(\"#embeddings\").appendChild(table)\n \n }\n \n \n hoverToken(view, token, active) {\n if (active) {\n const start = loc(this.sourceCM.posFromIndex(token.start));\n const end = loc(this.sourceCM.posFromIndex(token.end));\n this.hoverMarker = this.sourceCM.markText(start.asCM(), end.asCM(), {css: \"background-color: #fe3\"});\n } else {\n this.hoverMarker.clear();\n this.hoverMarker = null;\n }\n }\n \n /*MD ## Execution MD*/\n \n async update() {\n this.lastSource = this.source\n this.log(\"source code changed, length: \" + this.source.length + \"\")\n \n try {\n var node = await this.astInspector.treeSitterParse(this.source)\n this.treeSitterRootNode = node.rootNode\n this.astInspector.inspect(this.treeSitterRootNode);\n } catch (e) {\n this.astInspector.inspect({Error: e.message});\n }\n \n this.updateTokens();\n }\n \n async updateTransformer() {\n this.status = \"transformer: sending...\"\n try {\n let response = await fetch(`${this.api}/dataset/${this.projectName}/transformer`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n text: this.transformerSource\n }),\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n this.status = \"transformer: using \" + response.transformer;\n } catch (e) {\n this.status = \"transformer: \" + e;\n }\n }\n \n async onComputeEmbeddings() {\n this.status =\"generating embeddings: long running task. check backend logs\";\n try {\n let language = \"typescript\"; // HARDCODED CHANGE HERE\n let response = await fetch(`${this.api}/dataset/${this.projectName}/make_context_embeddings?language=${language}`, {\n method: 'POST',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n this.status = `generating embeddings: ${JSON.stringify(response.stats)}`;\n } catch (e) {\n this.status = \"generating embeddings: \" + e;\n }\n }\n \n async onRunParse() {\n this.status = \"parser: running...\"\n try {\n let language = \"typescript\"; // HARDCODED CHANGE HERE\n let response = await fetch(`${this.api}/dataset/${this.projectName}/parse?language=${language}`, {\n method: 'POST',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n this.status = `parser: currently ${response.ASTs} ASTs in memory. ${response.features} tokens with embeddings`;\n } catch (e) {\n this.status = \"parser: \" + e;\n }\n }\n \n async onRunQuery() {\n this.status = \"query: running...\"\n try {\n let response = await fetch(`${this.api}/dataset/${this.projectName}/run_query`, {\n method: 'POST',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n this.status = \"query: matched \" + response.matches + \" items in \" + response.files + \" files\";\n } catch (e) {\n this.status = \"query: \" + e;\n }\n }\n \n async onRunMap() {\n this.status = \"map: running...\"\n try {\n let response = await fetch(`${this.api}/dataset/${this.projectName}/run_map`, {\n method: 'POST',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n this.status = (\"map: success. Data columns: \\n\" + response.columns).replaceAll('\\n', '
');\n } catch (e) {\n this.status = \"map: \" + e;\n }\n }\n \n async onRunReduce() {\n this.status = \"reduce: running...\"\n try {\n let response = await fetch(`${this.api}/dataset/${this.projectName}/run_reduce`, {\n method: 'POST',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n this.status = \"reduce: success\";\n } catch (e) {\n this.status = \"reduce: \" + e;\n }\n }\n \n async onRunUmap() {\n this.status = \"umap: running...\"\n let data;\n try {\n let response = await fetch(`${this.api}/dataset/${this.projectName}/run_umap`, {\n method: 'POST',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n data = response.umap;\n this.status = \"umap: success\";\n } catch (e) {\n this.status = \"umap: \" + e;\n return;\n }\n \n try {\n this.astroPlot.displayData(data)\n } catch (e) {\n this.status = \"plot: \" + e;\n }\n }\n \n async onRunCluster() {\n this.status = \"clustering: running...\"\n let data;\n try {\n let response = await fetch(`${this.api}/dataset/${this.projectName}/run_cluster`, {\n method: 'POST',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n let clusters = response.clusters;\n this.status = \"clustering: success. \" + clusters + ' clusters found.';\n } catch (e) {\n this.status = \"clustering: \" + e;\n return;\n }\n }\n \n async onItemClicked(e) {\n debugger\n const item = e.detail;\n let id = item.id;\n \n this.status = \"get item: running...\"\n try {\n let response = await fetch(`${this.api}/dataset/${this.projectName}/embeddings/${id}`, {\n method: 'GET',\n })\n response = await response.json();\n if (response.error) throw new Error(response.error);\n this.status = \"get item: success\";\n \n const item = JSON.parse(response.item);\n const source = item.plot_content;\n \n this.sourceCM.setValue(source);\n } catch (e) {\n this.status = \"get item: \" + e;\n }\n }\n\n async save() {\n if (this.sourceURL) {\n await this.sourceEditor.saveFile();\n }\n if (this.transformerSourceURL) {\n await this.transformerSourceEditor.saveFile();\n }\n this.update();\n }\n\n /*MD ## Lively Integration MD*/\n\n livelyPrepareSave() {\n this.setAttribute('source', this.sourceURL);\n this.setAttribute('transformerSource', this.transformerSourceURL);\n this.setAttribute('projectName', this.projectName);\n \n console.log(\"PREPARE SAVE (AST Explorer)\");\n }\n \n livelyMigrate(other) {\n }\n\n async livelyExample() {\n await this.loadSourceFile(AstroView.defaultSourceURL);\n await this.loadTransformerSourceFile(AstroView.defaultTransformerSourceURL)\n }\n}"} \ No newline at end of file From 2b10e606e4f7fbf634ecbe9db2b8a7abf362458a Mon Sep 17 00:00:00 2001 From: JensLincke Date: Fri, 19 Jul 2024 15:07:37 +0200 Subject: [PATCH 2/2] fix async editor loading for new codemirror and babyloanian programming SQUASHED: AUTO-COMMIT-src-components-widgets-lively-code-mirror.js,fix-async-editor-loading-for-new-codemirror-and-babyloanian-programming, --- .../babylonian-programming-editor.js | 5 ++++- src/components/tools/openai-audio-chat.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/babylonian-programming-editor/babylonian-programming-editor.js b/src/babylonian-programming-editor/babylonian-programming-editor.js index 66049b323..9f9b0e1db 100644 --- a/src/babylonian-programming-editor/babylonian-programming-editor.js +++ b/src/babylonian-programming-editor/babylonian-programming-editor.js @@ -120,7 +120,9 @@ export default class BabylonianProgrammingEditor extends Morph { var editorComp = this.editorComp() console.log("Babylonian: load editor" + editorComp) - editorComp.addEventListener("editor-loaded", () => { + + // editorComp.addEventListener("editor-loaded", () => { + editorComp.editorLoaded().then(() => { console.log("Babylonian: editor loaded ", this.livelyEditor()) // Patch editor to load/save comments @@ -143,6 +145,7 @@ export default class BabylonianProgrammingEditor extends Morph { "Tab": (cm) => { cm.replaceSelection(" ") }, }) + debugger // Inject styling into CodeMirror const livelyEditorStyle = diff --git a/src/components/tools/openai-audio-chat.js b/src/components/tools/openai-audio-chat.js index 997379898..146220b27 100644 --- a/src/components/tools/openai-audio-chat.js +++ b/src/components/tools/openai-audio-chat.js @@ -140,7 +140,7 @@ export default class OpenaiAudioChat extends Morph { //comboboxes this.voiceBox.setOptions(["alloy", "echo", "fable", "onyx", "nova", "shimmer", "silent"]) if (!this.voiceBox.value) this.voiceBox.value="shimmer" - this.modelBox.setOptions(["gpt-4o", "gpt-4-turbo", "gpt-4", "gpt-3.5-turbo"]) + this.modelBox.setOptions(["gpt-4o","gpt-4o-mini", "gpt-4-turbo", "gpt-4", "gpt-3.5-turbo"]) if (!this.modelBox.value) this.modelBox.value="gpt-3.5-turbo" }