1+ <!DOCTYPE html>
2+ < html lang ="en ">
3+ < head >
4+ < meta charset ="UTF-8 ">
5+ < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
6+ < title > Grammar Checker</ title >
7+ < script src ="https://cdn.tailwindcss.com "> </ script >
8+ < script src ="https://cdnjs.cloudflare.com/ajax/libs/json5/2.2.3/index.min.js "> </ script >
9+ < script src ="https://cdn.jsdelivr.net/npm/languagedetect/languagedetect.js "> </ script >
10+ < style >
11+ .error-spelling { background : rgba (255 , 0 , 0 , 0.2 ); }
12+ .error-grammar { background : rgba (255 , 165 , 0 , 0.2 ); }
13+ .error-style { background : rgba (0 , 128 , 0 , 0.2 ); }
14+ .error-punctuation { background : rgba (0 , 0 , 255 , 0.2 ); }
15+ .tooltip { position : absolute; background : white; border : 1px solid # ccc ; padding : 8px ; border-radius : 4px ; box-shadow : 2px 2px 10px rgba (0 , 0 , 0 , 0.1 ); z-index : 1000 ; max-width : 300px ; }
16+ </ style >
17+ </ head >
18+ < body class ="bg-gray-100 min-h-screen ">
19+ < div class ="container mx-auto max-w-4xl p-6 ">
20+ < h1 class ="text-3xl font-bold text-center mb-6 "> Grammar Checker</ h1 >
21+ < div class ="bg-white rounded-lg shadow-lg p-6 ">
22+ < textarea id ="textInput " class ="w-full h-40 p-4 border rounded-lg mb-4 " placeholder ="Enter your text here... "> </ textarea >
23+ < button id ="checkGrammar " class ="w-full bg-blue-600 text-white py-2 rounded-lg hover:bg-blue-700 transition-colors "> Check Grammar</ button >
24+ < div id ="result " class ="mt-6 p-4 border rounded-lg "> </ div >
25+ </ div >
26+ < div class ="mt-4 flex gap-4 justify-center ">
27+ < div class ="flex items-center "> < span class ="w-4 h-4 inline-block mr-2 error-spelling "> </ span > Spelling</ div >
28+ < div class ="flex items-center "> < span class ="w-4 h-4 inline-block mr-2 error-grammar "> </ span > Grammar</ div >
29+ < div class ="flex items-center "> < span class ="w-4 h-4 inline-block mr-2 error-style "> </ span > Style</ div >
30+ < div class ="flex items-center "> < span class ="w-4 h-4 inline-block mr-2 error-punctuation "> </ span > Punctuation</ div >
31+ </ div >
32+ </ div >
33+
34+ < script >
35+ const grammarChecker = {
36+ init ( ) {
37+ this . checkButton = document . getElementById ( 'checkGrammar' ) ;
38+ this . textInput = document . getElementById ( 'textInput' ) ;
39+ this . resultDiv = document . getElementById ( 'result' ) ;
40+ this . checkButton . addEventListener ( 'click' , ( ) => this . check ( ) ) ;
41+ this . tooltip = null ;
42+ } ,
43+
44+ async check ( ) {
45+ const text = this . textInput . value . trim ( ) ;
46+ if ( ! text ) return ;
47+
48+ this . checkButton . disabled = true ;
49+ this . checkButton . textContent = 'Checking...' ;
50+
51+ try {
52+ const response = await this . callLLM ( text ) ;
53+ this . displayResults ( response ) ;
54+ } catch ( error ) {
55+ console . error ( 'Error:' , error ) ;
56+ this . resultDiv . innerHTML = 'An error occurred while checking the text.' ;
57+ } finally {
58+ this . checkButton . disabled = false ;
59+ this . checkButton . textContent = 'Check Grammar' ;
60+ }
61+ } ,
62+
63+ async callLLM ( text ) {
64+ const prompt = `Act as a grammar checking API. Analyze the following text and return a JSON response in this exact format:
65+ {
66+ "errors": [
67+ {
68+ "type": "spelling|grammar|style|punctuation",
69+ "start": <number>,
70+ "end": <number>,
71+ "text": "<problematic text>",
72+ "suggestion": "<corrected text>",
73+ "description": "<error description>"
74+ }
75+ ]
76+ }
77+
78+ Example input: "I dont like there attitude."
79+ Example response: {
80+ "errors": [
81+ {
82+ "type": "spelling",
83+ "start": 2,
84+ "end": 6,
85+ "text": "dont",
86+ "suggestion": "don't",
87+ "description": "Missing apostrophe in contraction"
88+ },
89+ {
90+ "type": "grammar",
91+ "start": 7,
92+ "end": 12,
93+ "text": "there",
94+ "suggestion": "their",
95+ "description": "Incorrect use of 'there' instead of the possessive 'their'"
96+ }
97+ ]
98+ }
99+
100+ Text to analyze: ${ text } ` ;
101+
102+ const response = await fetch ( 'https://chatgpt.tobiasmue91.workers.dev/' , {
103+ method : 'POST' ,
104+ headers : { "Content-Type" : "application/json" } ,
105+ body : JSON . stringify ( {
106+ model : "gpt-3.5-turbo" ,
107+ messages : [
108+ { role : "user" , content : prompt }
109+ ]
110+ } )
111+ } ) ;
112+
113+ const data = await response . json ( ) ;
114+ const content = data . choices [ 0 ] . message . content ;
115+ return JSON . parse ( content ) ;
116+ } ,
117+
118+ displayResults ( response ) {
119+ const text = this . textInput . value ;
120+ let html = text ;
121+ const errors = response . errors . sort ( ( a , b ) => b . start - a . start ) ;
122+
123+ errors . forEach ( error => {
124+ const errorClass = `error-${ error . type } ` ;
125+ const replacement = `<span class="${ errorClass } " data-error='${ JSON . stringify ( error ) } '>${ error . text } </span>` ;
126+ html = html . substring ( 0 , error . start ) + replacement + html . substring ( error . end ) ;
127+ } ) ;
128+
129+ this . resultDiv . innerHTML = html ;
130+ this . attachErrorListeners ( ) ;
131+ } ,
132+
133+ attachErrorListeners ( ) {
134+ const errorSpans = this . resultDiv . querySelectorAll ( 'span[data-error]' ) ;
135+ errorSpans . forEach ( span => {
136+ span . addEventListener ( 'mouseover' , ( e ) => this . showTooltip ( e ) ) ;
137+ span . addEventListener ( 'mouseout' , ( ) => this . hideTooltip ( ) ) ;
138+ span . addEventListener ( 'click' , ( e ) => this . applyCorrection ( e ) ) ;
139+ } ) ;
140+ } ,
141+
142+ showTooltip ( event ) {
143+ const error = JSON . parse ( event . target . dataset . error ) ;
144+ if ( this . tooltip ) this . hideTooltip ( ) ;
145+
146+ this . tooltip = document . createElement ( 'div' ) ;
147+ this . tooltip . className = 'tooltip' ;
148+ this . tooltip . innerHTML = `
149+ <div class="font-bold">${ error . type . charAt ( 0 ) . toUpperCase ( ) + error . type . slice ( 1 ) } Error</div>
150+ <div class="mt-1">${ error . description } </div>
151+ <div class="mt-2 text-sm text-gray-600">Click to replace with: "${ error . suggestion } "</div>
152+ ` ;
153+
154+ document . body . appendChild ( this . tooltip ) ;
155+ const rect = event . target . getBoundingClientRect ( ) ;
156+ this . tooltip . style . left = `${ rect . left } px` ;
157+ this . tooltip . style . top = `${ rect . bottom + 5 } px` ;
158+ } ,
159+
160+ hideTooltip ( ) {
161+ if ( this . tooltip ) {
162+ this . tooltip . remove ( ) ;
163+ this . tooltip = null ;
164+ }
165+ } ,
166+
167+ applyCorrection ( event ) {
168+ const error = JSON . parse ( event . target . dataset . error ) ;
169+ event . target . textContent = error . suggestion ;
170+ event . target . classList . remove ( `error-${ error . type } ` ) ;
171+ event . target . removeAttribute ( 'data-error' ) ;
172+ this . hideTooltip ( ) ;
173+ }
174+ } ;
175+
176+ document . addEventListener ( 'DOMContentLoaded' , ( ) => grammarChecker . init ( ) ) ;
177+ </ script >
178+ </ body >
179+ </ html >
0 commit comments