kayarn commited on
Commit
cb2ca32
·
verified ·
1 Parent(s): 8334e3f

create app.py

Browse files
Files changed (1) hide show
  1. app.py +438 -0
app.py ADDED
@@ -0,0 +1,438 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ GenAI for Easy Read: Open-Source Multimodal Solution
3
+ A Gradio-based prototype for converting documents into accessible Easy Read formats.
4
+ """
5
+ import gradio as gr
6
+ import os
7
+ from typing import List, Tuple, Optional
8
+ import re
9
+
10
+ # ============================================================================
11
+ # DUMMY/MOCK FUNCTIONS FOR BACKEND PROCESSING
12
+ # TODO: Replace these with actual API calls to OpenAI, GlobalSymbols, etc.
13
+ # ============================================================================
14
+
15
+ def split_into_sentences(text: str) -> List[str]:
16
+ """
17
+ Splits text into individual sentences.
18
+ TODO: Enhance with better sentence boundary detection (e.g., using spaCy)
19
+ """
20
+ if not text or not text.strip():
21
+ return []
22
+ # Simple sentence splitting (can be improved with NLP libraries like spaCy)
23
+ sentences = re.split(r'(?<=[.!?])\s+', text.strip())
24
+ return [s.strip() for s in sentences if s.strip()]
25
+
26
+ def convert_to_easy_read(
27
+ pdf_file: Optional[str],
28
+ text_input: Optional[str],
29
+ context: str,
30
+ unalterable_terms: str
31
+ ) -> Tuple[str, List[str], List[str]]:
32
+ """
33
+ Simulates the conversion of complex text to simplified Easy Read format.
34
+ TODO: Replace with actual LLM API call (e.g., OpenAI GPT-4, Anthropic Claude)
35
+ - Process PDF if provided, or use text_input
36
+ - Apply simplification rules
37
+ - Respect context/custom instructions
38
+ - Preserve unalterable terms
39
+ """
40
+ # Use text_input if provided, otherwise dummy text
41
+ input_text = text_input if text_input else (
42
+ "This is sentence one. "
43
+ "This is sentence two. "
44
+ "This is sentence three. "
45
+ "Each sentence can be edited separately."
46
+ )
47
+
48
+ # Split into sentences
49
+ sentences = split_into_sentences(input_text)
50
+
51
+ # Dummy simplified text (sentence-by-sentence)
52
+ dummy_simplified = "\n".join(sentences)
53
+
54
+ # Dummy keyword list for symbol matching
55
+ dummy_keywords = ["person", "help", "document", "read"]
56
+
57
+ return dummy_simplified, dummy_keywords, sentences
58
+
59
+ def update_sentence(sentence_index: int, new_text: str, all_sentences: List[str]) -> str:
60
+ """
61
+ Updates a specific sentence and returns the combined text.
62
+ """
63
+ if 0 <= sentence_index < len(all_sentences):
64
+ all_sentences[sentence_index] = new_text
65
+ return "\n".join(all_sentences)
66
+
67
+ def fetch_symbols_from_libraries(
68
+ keywords: List[str], selected_libraries: List[str]
69
+ ) -> List[str]:
70
+ """
71
+ Fetches symbols from selected symbol libraries based on keywords.
72
+ TODO: Replace with actual API calls to:
73
+ - GlobalSymbols API
74
+ - ARASAAC API
75
+ - AAC Image Library API
76
+ - PiCom API
77
+ """
78
+ # Dummy: Return placeholder image paths
79
+ # In production, these would be URLs or file paths to actual symbols
80
+ dummy_symbols = [
81
+ "https://via.placeholder.com/200x200/4A90E2/FFFFFF?text=Symbol1",
82
+ "https://via.placeholder.com/200x200/50C878/FFFFFF?text=Symbol2",
83
+ "https://via.placeholder.com/200x200/E94B3C/FFFFFF?text=Symbol3",
84
+ "https://via.placeholder.com/200x200/F5A623/FFFFFF?text=Symbol4",
85
+ ]
86
+ return dummy_symbols
87
+
88
+ def generate_ai_image(prompt: str) -> Optional[str]:
89
+ """
90
+ Generates an image using AI based on the provided prompt.
91
+ TODO: Replace with actual AI image generation API call:
92
+ - OpenAI DALL-E
93
+ - Stability AI Stable Diffusion
94
+ - Midjourney API
95
+ - Other image generation services
96
+ """
97
+ # Dummy: Return placeholder image
98
+ return "https://via.placeholder.com/400x400/9B59B6/FFFFFF?text=AI+Generated"
99
+
100
+ def export_to_pdf(text: str, images: List[str]) -> str:
101
+ """
102
+ Exports the Easy Read document to PDF format.
103
+ TODO: Implement PDF generation using libraries like:
104
+ - reportlab
105
+ - fpdf
106
+ - weasyprint
107
+ """
108
+ return "PDF export functionality - TODO: Implement"
109
+
110
+ def export_to_word(text: str, images: List[str]) -> str:
111
+ """
112
+ Exports the Easy Read document to Word format.
113
+ TODO: Implement Word document generation using:
114
+ - python-docx
115
+ """
116
+ return "Word export functionality - TODO: Implement"
117
+
118
+ def generate_audio(text: str) -> str:
119
+ """
120
+ Generates audio narration of the Easy Read text.
121
+ TODO: Implement text-to-speech using:
122
+ - OpenAI TTS API
123
+ - Google Cloud Text-to-Speech
124
+ - Amazon Polly
125
+ - Azure Cognitive Services
126
+ """
127
+ return "Audio generation functionality - TODO: Implement"
128
+
129
+ # ============================================================================
130
+ # GRADIO INTERFACE COMPONENTS
131
+ # ============================================================================
132
+
133
+ def create_convert_handler(
134
+ pdf_file, text_input, context, unalterable_terms, selected_libraries
135
+ ):
136
+ """
137
+ Main handler for the "Convert to Easy Read" button.
138
+ Processes input and returns simplified text and symbol suggestions.
139
+ """
140
+ # Step 1: Convert text to Easy Read format
141
+ simplified_text, keywords, sentences = convert_to_easy_read(
142
+ pdf_file, text_input, context, unalterable_terms
143
+ )
144
+
145
+ # Step 2: Fetch symbols from selected libraries
146
+ symbols = fetch_symbols_from_libraries(keywords, selected_libraries)
147
+
148
+ # Step 3: Create sentence components for display
149
+ sentence_components = []
150
+ for i, sentence in enumerate(sentences):
151
+ sentence_components.append((sentence, i))
152
+
153
+ return simplified_text, symbols, sentences
154
+
155
+ def create_ai_image_handler(prompt: str):
156
+ """Handler for AI image generation tab."""
157
+ if not prompt.strip():
158
+ return None
159
+ return generate_ai_image(prompt)
160
+
161
+ # ============================================================================
162
+ # MAIN GRADIO INTERFACE
163
+ # ============================================================================
164
+
165
+ def create_interface():
166
+ """Creates and configures the main Gradio interface."""
167
+
168
+ with gr.Blocks(theme=gr.themes.Soft()) as app:
169
+ # Store sentences in state
170
+ sentences_state = gr.State([])
171
+
172
+ # ====================================================================
173
+ # HEADER SECTION
174
+ # ====================================================================
175
+ gr.Markdown(
176
+ """
177
+ # GenAI for Easy Read: Open-Source Multimodal Solution
178
+ Convert documents into accessible Easy Read formats with simplified text and supported symbols.
179
+ """,
180
+ elem_classes=["header"]
181
+ )
182
+
183
+ # ====================================================================
184
+ # STEP 1: INPUT SECTION
185
+ # ====================================================================
186
+ gr.Markdown("## Step 1: Input Document or Text")
187
+
188
+ with gr.Row():
189
+ # Left Column: File Upload
190
+ with gr.Column():
191
+ pdf_upload = gr.File(
192
+ label="Upload Document",
193
+ file_types=[".pdf"],
194
+ type="filepath"
195
+ )
196
+
197
+ # Right Column: Text Input
198
+ with gr.Column():
199
+ text_input = gr.Textbox(
200
+ label="Or Paste Text Here",
201
+ lines=10,
202
+ placeholder="Enter your text here..."
203
+ )
204
+
205
+ # Advanced Settings Accordion
206
+ with gr.Accordion("Advanced Settings", open=False):
207
+ context_input = gr.Textbox(
208
+ label="Context/Custom Instructions",
209
+ placeholder="e.g., 'never use term X', 'target audience: children'",
210
+ lines=3
211
+ )
212
+ unalterable_terms_input = gr.Textbox(
213
+ label="Unalterable Terms",
214
+ placeholder="Enter terms that must not be changed (comma-separated)",
215
+ lines=2
216
+ )
217
+
218
+ # ====================================================================
219
+ # STEP 2: SYMBOL CONFIGURATION
220
+ # ====================================================================
221
+ gr.Markdown("## Step 2: Select Symbol Libraries")
222
+
223
+ symbol_libraries = gr.CheckboxGroup(
224
+ choices=[
225
+ "AAC Image Library",
226
+ "GlobalSymbols",
227
+ "ARASAAC",
228
+ "PiCom",
229
+ "AI Realistic Symbols"
230
+ ],
231
+ label="Available Symbol Libraries",
232
+ value=["ARASAAC", "GlobalSymbols"] # Default selections
233
+ )
234
+
235
+ # ====================================================================
236
+ # STEP 3: EASY READ EDITOR
237
+ # ====================================================================
238
+ gr.Markdown("## Step 3: Easy Read Editor")
239
+
240
+ # Convert Button
241
+ convert_btn = gr.Button(
242
+ "Convert to Easy Read",
243
+ variant="primary",
244
+ size="lg"
245
+ )
246
+
247
+ # Main Editor Layout: Text Editing + Image Selection
248
+ with gr.Row():
249
+ # Left Side: Full Text Editor
250
+ with gr.Column(scale=1):
251
+ simplified_text = gr.Textbox(
252
+ label="Full Simplified Text (Editable)",
253
+ lines=15,
254
+ placeholder="Simplified text will appear here after conversion..."
255
+ )
256
+
257
+ # Right Side: Multi-Tab Image Interface
258
+ with gr.Column(scale=1):
259
+ with gr.Tabs() as image_tabs:
260
+ # Tab 1: Symbol Library / Alternatives
261
+ with gr.Tab("Symbol Library / Alternatives"):
262
+ symbol_gallery = gr.Gallery(
263
+ label="Available Symbols",
264
+ show_label=True,
265
+ elem_id="symbol_gallery",
266
+ columns=3,
267
+ rows=2,
268
+ height="auto"
269
+ )
270
+
271
+ # Tab 2: Generate with AI
272
+ with gr.Tab("Generate with AI"):
273
+ ai_prompt = gr.Textbox(
274
+ label="Image Prompt",
275
+ placeholder="Describe the image you want to generate...",
276
+ lines=3
277
+ )
278
+ generate_ai_btn = gr.Button("Generate", variant="secondary")
279
+ ai_generated_image = gr.Image(
280
+ label="Generated Image",
281
+ type="filepath"
282
+ )
283
+
284
+ # Tab 3: Upload / Personal
285
+ with gr.Tab("Upload / Personal"):
286
+ personal_image_upload = gr.Image(
287
+ label="Upload Your Image",
288
+ sources=["upload"],
289
+ type="filepath"
290
+ )
291
+
292
+ # Tab 4: Favorites
293
+ with gr.Tab("Favorites"):
294
+ favorites_gallery = gr.Gallery(
295
+ label="Saved Favorites",
296
+ show_label=True,
297
+ elem_id="favorites_gallery",
298
+ columns=3,
299
+ rows=2,
300
+ height="auto"
301
+ )
302
+
303
+ # ====================================================================
304
+ # INDIVIDUAL SENTENCE EDITOR
305
+ # ====================================================================
306
+ gr.Markdown("## Individual Sentence Editor")
307
+ gr.Markdown("*Edit each sentence separately below*")
308
+
309
+ # Container for individual sentences
310
+ sentence_editor_container = gr.Column()
311
+
312
+ with sentence_editor_container:
313
+ # Dynamic sentence textboxes will be created here
314
+ sentence_textboxes = []
315
+ for i in range(10): # Pre-create 10 textboxes (will show/hide as needed)
316
+ with gr.Row(visible=False) as sentence_row:
317
+ sentence_num = gr.Markdown(f"**Sentence {i+1}:**")
318
+ sentence_box = gr.Textbox(
319
+ label="",
320
+ lines=2,
321
+ show_label=False,
322
+ scale=4
323
+ )
324
+ sentence_textboxes.append((sentence_row, sentence_box, sentence_num))
325
+
326
+ # ====================================================================
327
+ # FOOTER / EXPORT SECTION
328
+ # ====================================================================
329
+ gr.Markdown("## Export Options")
330
+
331
+ with gr.Row():
332
+ export_pdf_btn = gr.Button("Export to PDF", variant="secondary")
333
+ export_word_btn = gr.Button("Export to Word", variant="secondary")
334
+ generate_audio_btn = gr.Button("Generate Audio", variant="secondary")
335
+
336
+ # ====================================================================
337
+ # EVENT HANDLERS
338
+ # ====================================================================
339
+
340
+ def update_sentence_display(sentences):
341
+ """Updates the visibility and content of sentence textboxes"""
342
+ updates = []
343
+ for i, (row, box, num) in enumerate(sentence_textboxes):
344
+ if i < len(sentences):
345
+ # Show this sentence
346
+ updates.extend([
347
+ gr.update(visible=True), # row
348
+ gr.update(value=sentences[i]), # textbox
349
+ gr.update(value=f"**Sentence {i+1}:**") # label
350
+ ])
351
+ else:
352
+ # Hide this sentence
353
+ updates.extend([
354
+ gr.update(visible=False), # row
355
+ gr.update(value=""), # textbox
356
+ gr.update(value="") # label
357
+ ])
358
+ return updates
359
+
360
+ def merge_sentences_to_full_text(*sentence_values):
361
+ """Merges individual sentence values back into full text"""
362
+ # Filter out empty sentences
363
+ sentences = [s for s in sentence_values if s and s.strip()]
364
+ return "\n".join(sentences)
365
+
366
+ # Convert button handler
367
+ def convert_handler(*args):
368
+ simplified_text, symbols, sentences = create_convert_handler(*args)
369
+
370
+ # Update sentence display
371
+ sentence_updates = update_sentence_display(sentences)
372
+
373
+ return [simplified_text, symbols, sentences] + sentence_updates
374
+
375
+ # Collect all outputs for convert button
376
+ convert_outputs = [simplified_text, symbol_gallery, sentences_state]
377
+ for row, box, num in sentence_textboxes:
378
+ convert_outputs.extend([row, box, num])
379
+
380
+ convert_btn.click(
381
+ fn=convert_handler,
382
+ inputs=[
383
+ pdf_upload,
384
+ text_input,
385
+ context_input,
386
+ unalterable_terms_input,
387
+ symbol_libraries
388
+ ],
389
+ outputs=convert_outputs
390
+ )
391
+
392
+ # Update full text when any sentence is edited
393
+ for row, box, num in sentence_textboxes:
394
+ box.change(
395
+ fn=merge_sentences_to_full_text,
396
+ inputs=[b for r, b, n in sentence_textboxes],
397
+ outputs=[simplified_text]
398
+ )
399
+
400
+ # AI image generation handler
401
+ generate_ai_btn.click(
402
+ fn=create_ai_image_handler,
403
+ inputs=[ai_prompt],
404
+ outputs=[ai_generated_image]
405
+ )
406
+
407
+ # Export handlers (placeholder)
408
+ export_pdf_btn.click(
409
+ fn=lambda t, imgs: gr.Info("PDF export - TODO: Implement backend"),
410
+ inputs=[simplified_text, symbol_gallery],
411
+ outputs=[]
412
+ )
413
+
414
+ export_word_btn.click(
415
+ fn=lambda t, imgs: gr.Info("Word export - TODO: Implement backend"),
416
+ inputs=[simplified_text, symbol_gallery],
417
+ outputs=[]
418
+ )
419
+
420
+ generate_audio_btn.click(
421
+ fn=lambda t: gr.Info("Audio generation - TODO: Implement backend"),
422
+ inputs=[simplified_text],
423
+ outputs=[]
424
+ )
425
+
426
+ return app
427
+
428
+ def main():
429
+ """Main entry point for the application."""
430
+ app = create_interface()
431
+ app.launch(
432
+ server_name="0.0.0.0",
433
+ server_port=7860,
434
+ share=False
435
+ )
436
+
437
+ if __name__ == "__main__":
438
+ main()