mirror of
https://github.com/hazemKrimi/touch-programming.git
synced 2026-05-01 18:20:26 +00:00
Consume the api locally
This commit is contained in:
+2
-2
@@ -1,5 +1,4 @@
|
|||||||
.container {
|
.container {
|
||||||
max-width: 500px;
|
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
letter-spacing: 0.25rem;
|
letter-spacing: 0.25rem;
|
||||||
@@ -23,12 +22,13 @@
|
|||||||
|
|
||||||
.enter:before {
|
.enter:before {
|
||||||
content: '\21b5';
|
content: '\21b5';
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.enter:after {
|
.enter:after {
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
clear: both;
|
clear: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab:before {
|
.tab:before {
|
||||||
|
|||||||
+37
-9
@@ -2,35 +2,57 @@ import { useEffect, useState } from 'react';
|
|||||||
import './App.css';
|
import './App.css';
|
||||||
|
|
||||||
const KEYS_TO_DISABLE = ['Backspace', 'Shift', 'Alt', 'Control', 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'Escape', 'Delete', 'PageDown', 'PageUp', 'Home', 'End', 'Insert', 'WakeUp', 'Pause', 'ScrollLock', 'ContextMenu', 'BrowserForward', 'BrowserBack', 'CapsLock', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
|
const KEYS_TO_DISABLE = ['Backspace', 'Shift', 'Alt', 'Control', 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'Escape', 'Delete', 'PageDown', 'PageUp', 'Home', 'End', 'Insert', 'WakeUp', 'Pause', 'ScrollLock', 'ContextMenu', 'BrowserForward', 'BrowserBack', 'CapsLock', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
|
||||||
const SNIPPET = 'ctx := context.Background();\nconsole.log("hello");\nfunction() {\n\talert(123);\n}';
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
const [code, setCode] = useState('');
|
||||||
|
const [loaded, setLoaded] = useState(false);
|
||||||
const [characters, setCharacters] = useState([]);
|
const [characters, setCharacters] = useState([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async function() {
|
||||||
|
const response = await fetch('http://localhost:5000/generate?lang=golang&lines=10');
|
||||||
|
const reader = response.body.getReader();
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
const {value, done} = await reader.read();
|
||||||
|
|
||||||
|
setCode(prev => prev + decoder.decode(value));
|
||||||
|
|
||||||
|
if (done) {
|
||||||
|
setLoaded(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function handleKeyPress(event) {
|
function handleKeyPress(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (characters.length === SNIPPET.length) return;
|
if (!loaded) return;
|
||||||
|
if (characters.length === code.length) return;
|
||||||
if (KEYS_TO_DISABLE.includes(event.key)) return;
|
if (KEYS_TO_DISABLE.includes(event.key)) return;
|
||||||
if (SNIPPET[characters.length] === '\n')
|
if (code[characters.length] === '\n')
|
||||||
return setCharacters(
|
return setCharacters(
|
||||||
characters.concat(event.key === 'Enter')
|
characters.concat(event.key === 'Enter')
|
||||||
);
|
);
|
||||||
if (SNIPPET[characters.length] === '\t')
|
if (code[characters.length] === '\t')
|
||||||
return setCharacters(
|
return setCharacters(
|
||||||
characters.concat(event.key === 'Tab')
|
characters.concat(event.key === 'Tab')
|
||||||
);
|
);
|
||||||
|
|
||||||
setCharacters(
|
setCharacters(
|
||||||
characters.concat(event.key === SNIPPET[characters.length])
|
characters.concat(event.key === code[characters.length])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('keydown', handleKeyPress);
|
window.addEventListener('keydown', handleKeyPress);
|
||||||
|
|
||||||
return () => window.removeEventListener('keydown', handleKeyPress);
|
return () => window.removeEventListener('keydown', handleKeyPress);
|
||||||
}, [characters]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [loaded, characters]);
|
||||||
|
|
||||||
function renderCharacterClassName(index) {
|
function renderCharacterClassName(index) {
|
||||||
if (index === characters.length) return 'highlight'
|
if (index === characters.length) return 'highlight'
|
||||||
@@ -40,16 +62,22 @@ function App() {
|
|||||||
return 'correct'
|
return 'correct'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove rendering of spacing characters and render a cursor with the highlight instead.
|
||||||
|
// TODO: Or look into pretty printing libraries.
|
||||||
function renderSpacingCharacter(char) {
|
function renderSpacingCharacter(char) {
|
||||||
if (/^\t$/.test(char)) return 'tab'
|
|
||||||
if (/^\n$/.test(char)) return 'enter'
|
if (/^\n$/.test(char)) return 'enter'
|
||||||
|
if (/^\t$/.test(char)) return 'tab'
|
||||||
if (/^\s$/.test(char)) return 'space'
|
if (/^\s$/.test(char)) return 'space'
|
||||||
|
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className='container'>{SNIPPET.split('').map((char, index) => (
|
function renderClassName(index, char) {
|
||||||
<span className={`${renderCharacterClassName(index)} ${renderSpacingCharacter(char)}`} key={char + index}>{char}</span>
|
return `${renderCharacterClassName(index)} ${renderSpacingCharacter(char)}`.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className='container'>{code.split('').map((char, index) => (
|
||||||
|
<span className={renderClassName(index, char)} key={char + index}>{char}</span>
|
||||||
))}</div>;
|
))}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -1,10 +1,8 @@
|
|||||||
import { StrictMode } from 'react';
|
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import App from './App.jsx';
|
import App from './App.jsx';
|
||||||
|
|
||||||
|
// TODO: Bring back string mode when building and deploying
|
||||||
createRoot(document.getElementById('root')).render(
|
createRoot(document.getElementById('root')).render(
|
||||||
<StrictMode>
|
|
||||||
<App />
|
<App />
|
||||||
</StrictMode>,
|
|
||||||
);
|
);
|
||||||
|
|||||||
+2
-2
@@ -41,9 +41,9 @@ func main() {
|
|||||||
|
|
||||||
ollamaCtx := context.Background()
|
ollamaCtx := context.Background()
|
||||||
content := []llms.MessageContent{
|
content := []llms.MessageContent{
|
||||||
llms.TextParts(llms.ChatMessageTypeSystem, `You are only a code generator. You must not respond with anything else but code and do not format with code fences.`),
|
llms.TextParts(llms.ChatMessageTypeSystem, `You are only a code generator. You must not respond with anything else but code and do not format with code fences. Always use tabs instead of spaces.`),
|
||||||
llms.TextParts(llms.ChatMessageTypeHuman, fmt.Sprintf(`
|
llms.TextParts(llms.ChatMessageTypeHuman, fmt.Sprintf(`
|
||||||
Generate max %d lines of code without any unncessary formatting from a well known open source project in the %s programming language. First line should always be a code comment in this format: Language/Project`, lines, lang)),
|
Generate max %d lines of code without any unncessary formatting from a well known open source project in the %s programming language. First line should always be a code comment in the used language in this format: "// Language/Project"`, lines, lang)),
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := llm.GenerateContent(ollamaCtx, content, llms.WithStreamingFunc(func(streamCtx context.Context, chunk []byte) error {
|
if _, err := llm.GenerateContent(ollamaCtx, content, llms.WithStreamingFunc(func(streamCtx context.Context, chunk []byte) error {
|
||||||
|
|||||||
Reference in New Issue
Block a user