IvanMiao commited on
Commit
79a1ae4
·
1 Parent(s): f4c577e

fix: ruff lint&format

Browse files
app.py CHANGED
@@ -12,113 +12,117 @@ GEMINI_API_KEY = ""
12
 
13
 
14
  def update_api_keys(mistral_key, gemini_key):
15
- """
16
- Updates the global MISTRAL_API_KEY and GEMINI_API_KEY variables.
17
 
18
- Args:
19
- mistral_key: The Mistral API key.
20
- gemini_key: The Gemini API key.
21
 
22
- Returns:
23
- A string confirming that the API keys have been saved.
24
- """
25
- global MISTRAL_API_KEY, GEMINI_API_KEY
26
 
27
- MISTRAL_API_KEY = mistral_key
28
- GEMINI_API_KEY = gemini_key
29
 
30
- return "API keys saved"
31
 
32
 
33
  def ocr_workflow_wrapper(file: File, mistral_key: str):
34
- """
35
- Manages the OCR workflow, processing an uploaded file to extract text.
36
-
37
- Args:
38
- file: The file object to process (image, PDF, or text).
39
- mistral_key: The Mistral API key for OCR processing.
40
-
41
- Yields:
42
- Status messages and the extracted text or error messages.
43
- """
44
- if not mistral_key:
45
- error_msg = "Error: Mistral API Key not set."
46
- yield error_msg, error_msg
47
- return
48
- if not file or file.name == "":
49
- error_msg = "Error: File/Text not found."
50
- yield error_msg, error_msg
51
- return
52
-
53
- try:
54
- result = perform_raw_ocr(file, mistral_key)
55
- yield result, f"\n{result}\n"
56
- except Exception as e:
57
- error_msg = f"An error occurred during processing: {str(e)}"
58
- yield error_msg, error_msg
59
 
60
 
61
  def ai_correct(current_text: str, mistral_key: str):
62
- """
63
- Corrects the provided text using an AI model.
64
-
65
- Args:
66
- current_text: The text to be corrected.
67
- mistral_key: The Mistral API key for AI correction.
68
-
69
- Yields:
70
- Status messages and the corrected text or error messages.
71
- """
72
- if not mistral_key:
73
- error_msg = "Error: Mistral API Key not set."
74
- yield error_msg, error_msg
75
- return
76
- if not current_text or current_text.strip() == "":
77
- error_msg = "*No text to correct. Upload a file, or paste text into 'Raw Text' box first*"
78
- yield error_msg, error_msg
79
- return
80
-
81
- try:
82
- result = correct_text_with_ai(current_text, mistral_key)
83
- yield result, result
84
- except Exception as e:
85
- error_msg = f"Error : {e}"
86
- yield error_msg, error_msg
87
-
88
-
89
- def interpretation_workflow(text: str, genre: str, learn_language: str, target_language: str, gemini_key: str):
90
- """
91
- Generates an interpretation of the text based on genre and language settings.
92
-
93
- Args:
94
- text: The text to interpret.
95
- genre: The genre of the text (e.g., "general", "news").
96
- learn_language: The language being learned.
97
- target_language: The language for the interpretation output.
98
- gemini_key: The Gemini API key for interpretation.
99
-
100
- Yields:
101
- Status messages and the generated interpretation or error messages.
102
- """
103
- if not gemini_key:
104
- yield "Error: Gemini api key not found."
105
- return
106
- if not text or text.strip() == "":
107
- yield "Error: Text is empty"
108
- return
109
- if not learn_language or not target_language:
110
- yield "Error: Language not selected"
111
- return
112
-
113
- if genre.lower() in ["general", "news", "philosophy"]:
114
- result = get_interpretation(genre.lower(), gemini_key, text, learn_language, target_language)
115
- yield result
116
- else:
117
- yield "not implemented yet"
 
 
 
 
118
 
119
 
120
  def translation_workflow(text: str, target_language: str, gemini_key):
121
- """
122
  Translates the provided text to the target language.
123
 
124
  Args:
@@ -129,21 +133,31 @@ def translation_workflow(text: str, target_language: str, gemini_key):
129
  Yields:
130
  Status messages and the translated text or error messages.
131
  """
132
- if not gemini_key:
133
- yield "Error: Gemini api key not found."
134
- return
135
- if not text or text.strip() == "":
136
- yield "Error: Text is empty"
137
- return
138
- if not target_language:
139
- yield "Error: Language not selected"
140
-
141
- existin_languages = ["العربية", "Deutsch", "Español", "English", "Français", "Italiano", "日本語", "Русский язык", "中文"]
142
- if target_language in existin_languages:
143
- result = get_translaton(text, gemini_key, target_language)
144
- yield result
145
- else:
146
- yield "not implemented yet"
 
 
 
 
 
 
 
 
 
 
147
 
148
 
149
  def agent_workflow(text: str, prof_language: str, mistral_key: str, gemini_key: str):
@@ -151,7 +165,7 @@ def agent_workflow(text: str, prof_language: str, mistral_key: str, gemini_key:
151
  return "Error: Both Mistral and Gemini API keys are required."
152
  if not text or not text.strip():
153
  return "Error: Input text is empty."
154
-
155
  try:
156
  agent = AutomatedAnalysisAgent(mistral_key=mistral_key, gemini_key=gemini_key)
157
  result = agent.run(text, prof_language=prof_language)
@@ -161,153 +175,195 @@ def agent_workflow(text: str, prof_language: str, mistral_key: str, gemini_key:
161
 
162
 
163
  with gr.Blocks(theme=gr.themes.Monochrome(), css=CUSTOM_CSS) as demo:
164
- gr.Markdown("# 📚 LogosAI - Intensive Reading in Any Language", elem_classes=["section-header"])
165
-
166
- # --- API Key ---
167
- with gr.Accordion("API Configuration", open=True):
168
- with gr.Row():
169
- with gr.Column(scale=2):
170
- mistral_api = gr.Textbox(
171
- label="Mistral API Key",
172
- type="password",
173
- placeholder="Enter your key",
174
- info="OCR recognition & text processing"
175
- )
176
- with gr.Column(scale=2):
177
- gemini_api = gr.Textbox(
178
- label="Gemini API Key",
179
- type="password",
180
- placeholder="Enter your key",
181
- info="text interpretation"
182
- )
183
- with gr.Column(scale=1):
184
- update_keys_button = gr.Button("Save keys")
185
-
186
- api_key_status_output = gr.Markdown()
187
-
188
- update_keys_button.click(
189
- fn=update_api_keys,
190
- inputs=[mistral_api, gemini_api],
191
- outputs=api_key_status_output
192
- )
193
-
194
- # --- Text Processing ---
195
- gr.Markdown("---")
196
- with gr.Tab("Text"):
197
-
198
- with gr.Row():
199
- with gr.Column(scale=1):
200
- gr.Markdown("### Upload documents")
201
- file_input = gr.File(
202
- label="Upload Image/PDF/text",
203
- file_types=["image", ".pdf", ".txt"]
204
- )
205
- process_button = gr.Button("1. File Process (OCR/Read)", variant="primary")
206
- ai_correct_button = gr.Button("2. AI Correct", variant="primary")
207
- with gr.Column(scale=2):
208
- gr.Markdown("### Processed result")
209
- with gr.Tabs():
210
- with gr.Tab("Raw Text"):
211
- text_display = gr.Textbox(
212
- label="Raw Text(editable)",
213
- lines=15,
214
- max_lines=20,
215
- show_copy_button=True,
216
- value="",
217
- interactive=True
218
- )
219
- with gr.Tab("Formatted Text"):
220
- text_markdown = gr.Markdown(
221
- value="*Processed text will appear here...*\n\n",
222
- label="Formatted Text"
223
- )
224
-
225
- # Hook the ocr button to click event
226
- process_button.click(
227
- fn=ocr_workflow_wrapper,
228
- inputs=[file_input, mistral_api],
229
- outputs=[text_display, text_markdown]
230
- )
231
-
232
- # AI correction button to click event
233
- ai_correct_button.click(
234
- fn=ai_correct,
235
- inputs=[text_display, mistral_api],
236
- outputs=[text_display, text_markdown]
237
- )
238
-
239
- # --- Agent ---
240
- with gr.Tab("Agent"):
241
- gr.Markdown("### Automated Analysis")
242
- with gr.Row():
243
- with gr.Column(scale=1):
244
- agent_prof_language_selector = gr.Dropdown(["AR", "DE", "ES", "EN", "FR", "IT", "JA", "RU", "ZH"], label="Prof's Language", value="EN")
245
- agent_run_button = gr.Button("Run Automated Analysis", variant="primary")
246
- with gr.Column(scale=2):
247
- gr.Markdown("### Agent Result")
248
- agent_output = gr.Markdown(
249
- value="*Agent analysis will appear here...*\n\n",
250
- label="Agent Result"
251
- )
252
-
253
- agent_run_button.click(
254
- fn=agent_workflow,
255
- inputs=[text_display, agent_prof_language_selector, mistral_api, gemini_api],
256
- outputs=agent_output
257
- )
258
-
259
-
260
- # --- Text Interpertation ---
261
- with gr.Tab("🎓 Interpretation"):
262
- gr.Markdown("### Configure Interpretation Settings")
263
-
264
- with gr.Row():
265
- with gr.Column(scale=1):
266
- prof_language_seletor = gr.Dropdown(["AR", "DE", "ES", "EN", "FR", "IT", "JA", "RU", "ZH"], label="Prof's Language", value="EN")
267
- learn_language_seletor = gr.Dropdown(["AR", "DE", "ES", "EN", "FR", "IT", "JA", "RU", "ZH"], label="Language to Learn", value="EN")
268
- style_seletor = gr.Dropdown(["General", "News", "Philosophy", "Narrative", "Poem", "Paper"], label="Genre")
269
- interpret_button = gr.Button("Generate Interpretation", variant="primary")
270
-
271
- with gr.Column(scale=2):
272
- gr.Markdown("### COURSE")
273
- interpretation_output = gr.Markdown(
274
- value="*Interpretation will appear here after processing...*\n\n",
275
- label="Interpretation Result",
276
- show_copy_button=True
277
- )
278
-
279
- interpret_button.click(
280
- fn=interpretation_workflow,
281
- inputs=[text_display, style_seletor, learn_language_seletor, prof_language_seletor, gemini_api],
282
- outputs=interpretation_output
283
- )
284
-
285
- # --- Translation ---
286
- with gr.Tab("Translation"):
287
- gr.Markdown("### Configure Translation Settings")
288
- with gr.Row():
289
- with gr.Column(scale=1):
290
- target_language_selector = gr.Dropdown(
291
- ["العربية", "Deutsch", "Español", "English", "Français", "Italiano", "日本語", "Русский язык", "中文"],
292
- value="English",
293
- label="Target Language",
294
- interactive=True)
295
- translation_button = gr.Button("Translate!", variant="primary")
296
-
297
- with gr.Column(scale=2):
298
- interpretation_output = gr.Markdown(
299
- value="*Translation will appear here ...*\n\n",
300
- label="Translation Result",
301
- show_copy_button=True
302
- )
303
-
304
- translation_button.click(
305
- fn=translation_workflow,
306
- inputs=[text_display, target_language_selector, gemini_api],
307
- outputs=interpretation_output
308
- )
309
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
 
311
 
312
  if __name__ == "__main__":
313
- demo.launch(mcp_server=True)
 
12
 
13
 
14
  def update_api_keys(mistral_key, gemini_key):
15
+ """
16
+ Updates the global MISTRAL_API_KEY and GEMINI_API_KEY variables.
17
 
18
+ Args:
19
+ mistral_key: The Mistral API key.
20
+ gemini_key: The Gemini API key.
21
 
22
+ Returns:
23
+ A string confirming that the API keys have been saved.
24
+ """
25
+ global MISTRAL_API_KEY, GEMINI_API_KEY
26
 
27
+ MISTRAL_API_KEY = mistral_key
28
+ GEMINI_API_KEY = gemini_key
29
 
30
+ return "API keys saved"
31
 
32
 
33
  def ocr_workflow_wrapper(file: File, mistral_key: str):
34
+ """
35
+ Manages the OCR workflow, processing an uploaded file to extract text.
36
+
37
+ Args:
38
+ file: The file object to process (image, PDF, or text).
39
+ mistral_key: The Mistral API key for OCR processing.
40
+
41
+ Yields:
42
+ Status messages and the extracted text or error messages.
43
+ """
44
+ if not mistral_key:
45
+ error_msg = "Error: Mistral API Key not set."
46
+ yield error_msg, error_msg
47
+ return
48
+ if not file or file.name == "":
49
+ error_msg = "Error: File/Text not found."
50
+ yield error_msg, error_msg
51
+ return
52
+
53
+ try:
54
+ result = perform_raw_ocr(file, mistral_key)
55
+ yield result, f"\n{result}\n"
56
+ except Exception as e:
57
+ error_msg = f"An error occurred during processing: {str(e)}"
58
+ yield error_msg, error_msg
59
 
60
 
61
  def ai_correct(current_text: str, mistral_key: str):
62
+ """
63
+ Corrects the provided text using an AI model.
64
+
65
+ Args:
66
+ current_text: The text to be corrected.
67
+ mistral_key: The Mistral API key for AI correction.
68
+
69
+ Yields:
70
+ Status messages and the corrected text or error messages.
71
+ """
72
+ if not mistral_key:
73
+ error_msg = "Error: Mistral API Key not set."
74
+ yield error_msg, error_msg
75
+ return
76
+ if not current_text or current_text.strip() == "":
77
+ error_msg = "*No text to correct. Upload a file, or paste text into 'Raw Text' box first*"
78
+ yield error_msg, error_msg
79
+ return
80
+
81
+ try:
82
+ result = correct_text_with_ai(current_text, mistral_key)
83
+ yield result, result
84
+ except Exception as e:
85
+ error_msg = f"Error : {e}"
86
+ yield error_msg, error_msg
87
+
88
+
89
+ def interpretation_workflow(
90
+ text: str, genre: str, learn_language: str, target_language: str, gemini_key: str
91
+ ):
92
+ """
93
+ Generates an interpretation of the text based on genre and language settings.
94
+
95
+ Args:
96
+ text: The text to interpret.
97
+ genre: The genre of the text (e.g., "general", "news").
98
+ learn_language: The language being learned.
99
+ target_language: The language for the interpretation output.
100
+ gemini_key: The Gemini API key for interpretation.
101
+
102
+ Yields:
103
+ Status messages and the generated interpretation or error messages.
104
+ """
105
+ if not gemini_key:
106
+ yield "Error: Gemini api key not found."
107
+ return
108
+ if not text or text.strip() == "":
109
+ yield "Error: Text is empty"
110
+ return
111
+ if not learn_language or not target_language:
112
+ yield "Error: Language not selected"
113
+ return
114
+
115
+ if genre.lower() in ["general", "news", "philosophy"]:
116
+ result = get_interpretation(
117
+ genre.lower(), gemini_key, text, learn_language, target_language
118
+ )
119
+ yield result
120
+ else:
121
+ yield "not implemented yet"
122
 
123
 
124
  def translation_workflow(text: str, target_language: str, gemini_key):
125
+ """
126
  Translates the provided text to the target language.
127
 
128
  Args:
 
133
  Yields:
134
  Status messages and the translated text or error messages.
135
  """
136
+ if not gemini_key:
137
+ yield "Error: Gemini api key not found."
138
+ return
139
+ if not text or text.strip() == "":
140
+ yield "Error: Text is empty"
141
+ return
142
+ if not target_language:
143
+ yield "Error: Language not selected"
144
+
145
+ existin_languages = [
146
+ "العربية",
147
+ "Deutsch",
148
+ "Español",
149
+ "English",
150
+ "Français",
151
+ "Italiano",
152
+ "日本語",
153
+ "Русский язык",
154
+ "中文",
155
+ ]
156
+ if target_language in existin_languages:
157
+ result = get_translaton(text, gemini_key, target_language)
158
+ yield result
159
+ else:
160
+ yield "not implemented yet"
161
 
162
 
163
  def agent_workflow(text: str, prof_language: str, mistral_key: str, gemini_key: str):
 
165
  return "Error: Both Mistral and Gemini API keys are required."
166
  if not text or not text.strip():
167
  return "Error: Input text is empty."
168
+
169
  try:
170
  agent = AutomatedAnalysisAgent(mistral_key=mistral_key, gemini_key=gemini_key)
171
  result = agent.run(text, prof_language=prof_language)
 
175
 
176
 
177
  with gr.Blocks(theme=gr.themes.Monochrome(), css=CUSTOM_CSS) as demo:
178
+ gr.Markdown(
179
+ "# 📚 LogosAI - Intensive Reading in Any Language",
180
+ elem_classes=["section-header"],
181
+ )
182
+
183
+ # --- API Key ---
184
+ with gr.Accordion("API Configuration", open=True):
185
+ with gr.Row():
186
+ with gr.Column(scale=2):
187
+ mistral_api = gr.Textbox(
188
+ label="Mistral API Key",
189
+ type="password",
190
+ placeholder="Enter your key",
191
+ info="OCR recognition & text processing",
192
+ )
193
+ with gr.Column(scale=2):
194
+ gemini_api = gr.Textbox(
195
+ label="Gemini API Key",
196
+ type="password",
197
+ placeholder="Enter your key",
198
+ info="text interpretation",
199
+ )
200
+ with gr.Column(scale=1):
201
+ update_keys_button = gr.Button("Save keys")
202
+
203
+ api_key_status_output = gr.Markdown()
204
+
205
+ update_keys_button.click(
206
+ fn=update_api_keys,
207
+ inputs=[mistral_api, gemini_api],
208
+ outputs=api_key_status_output,
209
+ )
210
+
211
+ # --- Text Processing ---
212
+ gr.Markdown("---")
213
+ with gr.Tab("Text"):
214
+ with gr.Row():
215
+ with gr.Column(scale=1):
216
+ gr.Markdown("### Upload documents")
217
+ file_input = gr.File(
218
+ label="Upload Image/PDF/text", file_types=["image", ".pdf", ".txt"]
219
+ )
220
+ process_button = gr.Button(
221
+ "1. File Process (OCR/Read)", variant="primary"
222
+ )
223
+ ai_correct_button = gr.Button("2. AI Correct", variant="primary")
224
+ with gr.Column(scale=2):
225
+ gr.Markdown("### Processed result")
226
+ with gr.Tabs():
227
+ with gr.Tab("Raw Text"):
228
+ text_display = gr.Textbox(
229
+ label="Raw Text(editable)",
230
+ lines=15,
231
+ max_lines=20,
232
+ show_copy_button=True,
233
+ value="",
234
+ interactive=True,
235
+ )
236
+ with gr.Tab("Formatted Text"):
237
+ text_markdown = gr.Markdown(
238
+ value="*Processed text will appear here...*\n\n",
239
+ label="Formatted Text",
240
+ )
241
+
242
+ # Hook the ocr button to click event
243
+ process_button.click(
244
+ fn=ocr_workflow_wrapper,
245
+ inputs=[file_input, mistral_api],
246
+ outputs=[text_display, text_markdown],
247
+ )
248
+
249
+ # AI correction button to click event
250
+ ai_correct_button.click(
251
+ fn=ai_correct,
252
+ inputs=[text_display, mistral_api],
253
+ outputs=[text_display, text_markdown],
254
+ )
255
+
256
+ # --- Agent ---
257
+ with gr.Tab("Agent"):
258
+ gr.Markdown("### Automated Analysis")
259
+ with gr.Row():
260
+ with gr.Column(scale=1):
261
+ agent_prof_language_selector = gr.Dropdown(
262
+ ["AR", "DE", "ES", "EN", "FR", "IT", "JA", "RU", "ZH"],
263
+ label="Prof's Language",
264
+ value="EN",
265
+ )
266
+ agent_run_button = gr.Button(
267
+ "Run Automated Analysis", variant="primary"
268
+ )
269
+ with gr.Column(scale=2):
270
+ gr.Markdown("### Agent Result")
271
+ agent_output = gr.Markdown(
272
+ value="*Agent analysis will appear here...*\n\n",
273
+ label="Agent Result",
274
+ )
275
+
276
+ agent_run_button.click(
277
+ fn=agent_workflow,
278
+ inputs=[
279
+ text_display,
280
+ agent_prof_language_selector,
281
+ mistral_api,
282
+ gemini_api,
283
+ ],
284
+ outputs=agent_output,
285
+ )
286
+
287
+ # --- Text Interpertation ---
288
+ with gr.Tab("🎓 Interpretation"):
289
+ gr.Markdown("### Configure Interpretation Settings")
290
+
291
+ with gr.Row():
292
+ with gr.Column(scale=1):
293
+ prof_language_seletor = gr.Dropdown(
294
+ ["AR", "DE", "ES", "EN", "FR", "IT", "JA", "RU", "ZH"],
295
+ label="Prof's Language",
296
+ value="EN",
297
+ )
298
+ learn_language_seletor = gr.Dropdown(
299
+ ["AR", "DE", "ES", "EN", "FR", "IT", "JA", "RU", "ZH"],
300
+ label="Language to Learn",
301
+ value="EN",
302
+ )
303
+ style_seletor = gr.Dropdown(
304
+ ["General", "News", "Philosophy", "Narrative", "Poem", "Paper"],
305
+ label="Genre",
306
+ )
307
+ interpret_button = gr.Button(
308
+ "Generate Interpretation", variant="primary"
309
+ )
310
+
311
+ with gr.Column(scale=2):
312
+ gr.Markdown("### COURSE")
313
+ interpretation_output = gr.Markdown(
314
+ value="*Interpretation will appear here after processing...*\n\n",
315
+ label="Interpretation Result",
316
+ show_copy_button=True,
317
+ )
318
+
319
+ interpret_button.click(
320
+ fn=interpretation_workflow,
321
+ inputs=[
322
+ text_display,
323
+ style_seletor,
324
+ learn_language_seletor,
325
+ prof_language_seletor,
326
+ gemini_api,
327
+ ],
328
+ outputs=interpretation_output,
329
+ )
330
+
331
+ # --- Translation ---
332
+ with gr.Tab("Translation"):
333
+ gr.Markdown("### Configure Translation Settings")
334
+ with gr.Row():
335
+ with gr.Column(scale=1):
336
+ target_language_selector = gr.Dropdown(
337
+ [
338
+ "العربية",
339
+ "Deutsch",
340
+ "Español",
341
+ "English",
342
+ "Français",
343
+ "Italiano",
344
+ "日本語",
345
+ "Русский язык",
346
+ "中文",
347
+ ],
348
+ value="English",
349
+ label="Target Language",
350
+ interactive=True,
351
+ )
352
+ translation_button = gr.Button("Translate!", variant="primary")
353
+
354
+ with gr.Column(scale=2):
355
+ interpretation_output = gr.Markdown(
356
+ value="*Translation will appear here ...*\n\n",
357
+ label="Translation Result",
358
+ show_copy_button=True,
359
+ )
360
+
361
+ translation_button.click(
362
+ fn=translation_workflow,
363
+ inputs=[text_display, target_language_selector, gemini_api],
364
+ outputs=interpretation_output,
365
+ )
366
 
367
 
368
  if __name__ == "__main__":
369
+ demo.launch(mcp_server=True)
process/agent.py CHANGED
@@ -1,4 +1,3 @@
1
-
2
  import json
3
  from google import genai
4
  from google.genai import types
@@ -33,6 +32,7 @@ Example output:
33
  }
34
  """
35
 
 
36
  class AutomatedAnalysisAgent:
37
  def __init__(self, mistral_key: str, gemini_key: str):
38
  if not mistral_key or not gemini_key:
@@ -53,11 +53,15 @@ class AutomatedAnalysisAgent:
53
  temperature=0.0,
54
  response_mime_type="application/json",
55
  ),
56
- contents=[text]
57
  )
58
  directives = json.loads(response.text)
59
  # Basic validation
60
- if "language" not in directives or "genre" not in directives or "correction_needed" not in directives:
 
 
 
 
61
  raise ValueError("Invalid JSON structure from analysis model.")
62
  return directives
63
  except Exception as e:
@@ -75,7 +79,7 @@ class AutomatedAnalysisAgent:
75
 
76
  # 1. Get analysis directives from the agent's brain
77
  directives = self._get_analysis_directives(text)
78
-
79
  processed_text = text
80
  # 2. Conditionally apply AI correction
81
  if directives.get("correction_needed", False):
@@ -93,10 +97,9 @@ class AutomatedAnalysisAgent:
93
  api_key=self.gemini_key,
94
  text=processed_text,
95
  learn_language=directives.get("language", "EN"),
96
- prof_language=prof_language
97
  )
98
  return interpretation
99
  except Exception as e:
100
  print(f"Error during interpretation: {e}")
101
  return f"An error occurred during the final interpretation step: {e}"
102
-
 
 
1
  import json
2
  from google import genai
3
  from google.genai import types
 
32
  }
33
  """
34
 
35
+
36
  class AutomatedAnalysisAgent:
37
  def __init__(self, mistral_key: str, gemini_key: str):
38
  if not mistral_key or not gemini_key:
 
53
  temperature=0.0,
54
  response_mime_type="application/json",
55
  ),
56
+ contents=[text],
57
  )
58
  directives = json.loads(response.text)
59
  # Basic validation
60
+ if (
61
+ "language" not in directives
62
+ or "genre" not in directives
63
+ or "correction_needed" not in directives
64
+ ):
65
  raise ValueError("Invalid JSON structure from analysis model.")
66
  return directives
67
  except Exception as e:
 
79
 
80
  # 1. Get analysis directives from the agent's brain
81
  directives = self._get_analysis_directives(text)
82
+
83
  processed_text = text
84
  # 2. Conditionally apply AI correction
85
  if directives.get("correction_needed", False):
 
97
  api_key=self.gemini_key,
98
  text=processed_text,
99
  learn_language=directives.get("language", "EN"),
100
+ prof_language=prof_language,
101
  )
102
  return interpretation
103
  except Exception as e:
104
  print(f"Error during interpretation: {e}")
105
  return f"An error occurred during the final interpretation step: {e}"
 
process/gradio_css.py CHANGED
@@ -15,4 +15,4 @@ rest = """
15
  max-width: 1200px !important;
16
  margin: auto !important;
17
  }
18
- """
 
15
  max-width: 1200px !important;
16
  margin: auto !important;
17
  }
18
+ """
process/interpretation.py CHANGED
@@ -7,42 +7,52 @@ NARRATIVE_PROMPT = ""
7
  POEM_PROMPT = ""
8
 
9
 
10
- def get_interpretation(genre: str,
11
- api_key: str,
12
- text: str,
13
- learn_language: str,
14
- prof_language: str) -> str:
15
-
16
- if not api_key:
17
- return "Error: Gemini API Key not found."
18
- if not text:
19
- return "Error: text not found."
20
-
21
- try:
22
- client = genai.Client(api_key=api_key)
23
- except Exception as e:
24
- return f"ERROR: {str(e)}"
25
-
26
-
27
- lang_map ={"AR": "Arabic", "DE": "German", "ES": "Spanish", "EN": "English", "FR": "French", "IT": "Italian", "JA": "Japanese", "RU":"Russian", "ZH": "Chinese"}
28
- learn_lang = lang_map.get(learn_language.upper(), "English")
29
- prof_lang = lang_map.get(prof_language.upper(), "English")
30
- genres = {
31
- "general": GENERAL_PROMPT,
32
- "news": NEWS_PROMPT,
33
- "narrative": NARRATIVE_PROMPT,
34
- "poem": POEM_PROMPT,
35
- "philosophy": PHILO_PROMPT
36
- }
37
- if genre.lower() in ["general", "news", "philosophy"]:
38
- sys_prompt = genres[genre.lower()].replace("[LEARN_LANGUAGE]", learn_lang).replace("[PROF_LANGUAGE]", prof_lang)
39
-
40
- response = client.models.generate_content(
41
- model="gemini-2.5-pro",
42
- config=types.GenerateContentConfig(
43
- system_instruction=sys_prompt,
44
- temperature=0.3,
45
- ),
46
- contents=[text]
47
- )
48
- return response.text
 
 
 
 
 
 
 
 
 
 
 
7
  POEM_PROMPT = ""
8
 
9
 
10
+ def get_interpretation(
11
+ genre: str, api_key: str, text: str, learn_language: str, prof_language: str
12
+ ) -> str:
13
+ if not api_key:
14
+ return "Error: Gemini API Key not found."
15
+ if not text:
16
+ return "Error: text not found."
17
+
18
+ try:
19
+ client = genai.Client(api_key=api_key)
20
+ except Exception as e:
21
+ return f"ERROR: {str(e)}"
22
+
23
+ lang_map = {
24
+ "AR": "Arabic",
25
+ "DE": "German",
26
+ "ES": "Spanish",
27
+ "EN": "English",
28
+ "FR": "French",
29
+ "IT": "Italian",
30
+ "JA": "Japanese",
31
+ "RU": "Russian",
32
+ "ZH": "Chinese",
33
+ }
34
+ learn_lang = lang_map.get(learn_language.upper(), "English")
35
+ prof_lang = lang_map.get(prof_language.upper(), "English")
36
+ genres = {
37
+ "general": GENERAL_PROMPT,
38
+ "news": NEWS_PROMPT,
39
+ "narrative": NARRATIVE_PROMPT,
40
+ "poem": POEM_PROMPT,
41
+ "philosophy": PHILO_PROMPT,
42
+ }
43
+ if genre.lower() in ["general", "news", "philosophy"]:
44
+ sys_prompt = (
45
+ genres[genre.lower()]
46
+ .replace("[LEARN_LANGUAGE]", learn_lang)
47
+ .replace("[PROF_LANGUAGE]", prof_lang)
48
+ )
49
+
50
+ response = client.models.generate_content(
51
+ model="gemini-2.5-pro",
52
+ config=types.GenerateContentConfig(
53
+ system_instruction=sys_prompt,
54
+ temperature=0.3,
55
+ ),
56
+ contents=[text],
57
+ )
58
+ return response.text
process/ocr.py CHANGED
@@ -7,72 +7,68 @@ CHAT_MODEL = "mistral-large-latest"
7
 
8
 
9
  def ocr_from_file(file_path, api_key: str, mode="image"):
10
-
11
- if not api_key:
12
- raise ValueError("Mistral API Key is required.")
13
-
14
- try:
15
- client = Mistral(api_key=api_key)
16
- except Exception as e:
17
- raise ValueError("API invalid.")
18
-
19
- uploaded_image = client.files.upload(
20
- file={
21
- "file_name": file_path,
22
- "content": open(file_path, "rb"),
23
- },
24
- purpose="ocr"
25
- )
26
- signed_url = client.files.get_signed_url(file_id=uploaded_image.id)
27
-
28
- if mode == "image":
29
- ocr_response = client.ocr.process(
30
- model=OCR_MODEL,
31
- document={
32
- "type": "image_url",
33
- "image_url": signed_url.url,
34
- },
35
- include_image_base64=True
36
- )
37
- elif mode == "pdf":
38
- ocr_response = client.ocr.process(
39
- model=OCR_MODEL,
40
- document={
41
- "type": "document_url",
42
- "document_url": signed_url.url,
43
- },
44
- include_image_base64=True
45
- )
46
-
47
- return ocr_response
48
 
49
 
50
  def get_combined_markdown(ocr_response: OCRResponse) -> str:
 
 
 
51
 
52
- markdowns: list[str] = []
53
- for page in ocr_response.pages:
54
- markdowns.append(page.markdown)
55
-
56
- return "\n\n".join(markdowns)
57
 
58
 
59
  def correct_text_with_ai(text: str, api_key: str) -> str:
60
-
61
- if not api_key:
62
- raise ValueError("Mistral API Key is required.")
63
-
64
- try:
65
- client = Mistral(api_key=api_key)
66
- except Exception as e:
67
- return f"ERROR: {str(e)}"
68
-
69
- response = client.chat.complete(
70
- model=CHAT_MODEL,
71
- messages=[
72
- {
73
- "role": "system",
74
- "content":
75
- """You are an expert proofreader specializing in Markdown formatting and OCR error correction. Your task is to meticulously review provided Markdown text that has been generated via OCR.
76
  Your primary goal is to identify and correct **typographical errors, spelling mistakes, and redundant symbols** that are clearly a result of the OCR process.
77
  Additionally, you must correct any illogical or jumbled line breaks to ensure proper Markdown paragraph formatting.
78
 
@@ -82,31 +78,28 @@ def correct_text_with_ai(text: str, api_key: str) -> str:
82
  * Markdown formatting errors
83
  * Jumbled or incorrect line breaks for proper paragraphing
84
 
85
- After your thorough review, output the carefully corrected Markdown text. JUST the text."""
86
- },
87
- {
88
- "role": "user",
89
- "content": text
90
- },
91
- ],
92
- temperature=0.1,
93
- )
94
- return(response.choices[0].message.content)
95
 
96
 
97
  def perform_raw_ocr(input_file: File, api_key: str):
98
- if input_file and input_file.name:
99
- file_ext = input_file.name.split('.')[-1].lower()
100
- else:
101
- return "File/Text not found"
102
-
103
- if file_ext == "txt":
104
- with open(input_file, "r", encoding="utf-8") as f:
105
- return f.read()
106
- elif file_ext == "pdf":
107
- file_type = "pdf"
108
- else:
109
- file_type = "image"
110
- response = ocr_from_file(input_file, api_key, file_type)
111
- res_text = get_combined_markdown(response)
112
- return res_text
 
7
 
8
 
9
  def ocr_from_file(file_path, api_key: str, mode="image"):
10
+ if not api_key:
11
+ raise ValueError("Mistral API Key is required.")
12
+
13
+ try:
14
+ client = Mistral(api_key=api_key)
15
+ except Exception:
16
+ raise ValueError("API invalid.")
17
+
18
+ uploaded_image = client.files.upload(
19
+ file={
20
+ "file_name": file_path,
21
+ "content": open(file_path, "rb"),
22
+ },
23
+ purpose="ocr",
24
+ )
25
+ signed_url = client.files.get_signed_url(file_id=uploaded_image.id)
26
+
27
+ if mode == "image":
28
+ ocr_response = client.ocr.process(
29
+ model=OCR_MODEL,
30
+ document={
31
+ "type": "image_url",
32
+ "image_url": signed_url.url,
33
+ },
34
+ include_image_base64=True,
35
+ )
36
+ elif mode == "pdf":
37
+ ocr_response = client.ocr.process(
38
+ model=OCR_MODEL,
39
+ document={
40
+ "type": "document_url",
41
+ "document_url": signed_url.url,
42
+ },
43
+ include_image_base64=True,
44
+ )
45
+
46
+ return ocr_response
 
47
 
48
 
49
  def get_combined_markdown(ocr_response: OCRResponse) -> str:
50
+ markdowns: list[str] = []
51
+ for page in ocr_response.pages:
52
+ markdowns.append(page.markdown)
53
 
54
+ return "\n\n".join(markdowns)
 
 
 
 
55
 
56
 
57
  def correct_text_with_ai(text: str, api_key: str) -> str:
58
+ if not api_key:
59
+ raise ValueError("Mistral API Key is required.")
60
+
61
+ try:
62
+ client = Mistral(api_key=api_key)
63
+ except Exception as e:
64
+ return f"ERROR: {str(e)}"
65
+
66
+ response = client.chat.complete(
67
+ model=CHAT_MODEL,
68
+ messages=[
69
+ {
70
+ "role": "system",
71
+ "content": """You are an expert proofreader specializing in Markdown formatting and OCR error correction. Your task is to meticulously review provided Markdown text that has been generated via OCR.
 
 
72
  Your primary goal is to identify and correct **typographical errors, spelling mistakes, and redundant symbols** that are clearly a result of the OCR process.
73
  Additionally, you must correct any illogical or jumbled line breaks to ensure proper Markdown paragraph formatting.
74
 
 
78
  * Markdown formatting errors
79
  * Jumbled or incorrect line breaks for proper paragraphing
80
 
81
+ After your thorough review, output the carefully corrected Markdown text. JUST the text.""",
82
+ },
83
+ {"role": "user", "content": text},
84
+ ],
85
+ temperature=0.1,
86
+ )
87
+ return response.choices[0].message.content
 
 
 
88
 
89
 
90
  def perform_raw_ocr(input_file: File, api_key: str):
91
+ if input_file and input_file.name:
92
+ file_ext = input_file.name.split(".")[-1].lower()
93
+ else:
94
+ return "File/Text not found"
95
+
96
+ if file_ext == "txt":
97
+ with open(input_file, "r", encoding="utf-8") as f:
98
+ return f.read()
99
+ elif file_ext == "pdf":
100
+ file_type = "pdf"
101
+ else:
102
+ file_type = "image"
103
+ response = ocr_from_file(input_file, api_key, file_type)
104
+ res_text = get_combined_markdown(response)
105
+ return res_text
process/sys_prompt.py CHANGED
@@ -1,4 +1,4 @@
1
- GENERAL_PROMPT ="""
2
  ## Core Purpose and Goals:
3
 
4
  * To assist students with **intermediate to advanced `[LEARN_LANGUAGE]` proficiency** in mastering sophisticated aspects of the language through the deep analysis of complex, authentic texts.
 
1
+ GENERAL_PROMPT = """
2
  ## Core Purpose and Goals:
3
 
4
  * To assist students with **intermediate to advanced `[LEARN_LANGUAGE]` proficiency** in mastering sophisticated aspects of the language through the deep analysis of complex, authentic texts.
process/translation.py CHANGED
@@ -9,38 +9,37 @@ Do not add any extra information, explanations, or stylistic changes.
9
  Maintain the original meaning and tone as closely as possible.
10
  """
11
 
12
- def get_translaton(text: str, api_key: str, target_language: str) -> str:
13
 
14
- if not api_key:
15
- return "Error: Gemini API Key not found."
16
- if not text:
17
- return "Error: text not found."
 
18
 
19
- try:
20
- client = genai.Client(api_key=api_key)
21
- except Exception as e:
22
- return f"ERROR: {str(e)}"
23
 
24
- lang_map = {
25
- "العربية": "Arabic",
26
- "Deutsch": "German",
27
- "Español": "Spanish",
28
- "English": "English",
29
- "Français": "French",
30
- "Italiano": "Italian",
31
- "日本語": "Japanese",
32
- "Русский язык": "Russian",
33
- "中文": "Chinese"
34
- }
35
- lang_map = {"Deutsch": "German", "English": "English", "Français": "French", "Русский язык": "Russain", "中文": "Chinese"}
36
- tar_lang = lang_map.get(target_language, "English")
37
- sys_prompt = SYS_PROMPT_TRANSLATION.replace("[TARGET_LANGUAGE]", tar_lang)
38
- response = client.models.generate_content(
39
- model="gemini-2.5-pro",
40
- config=types.GenerateContentConfig(
41
- system_instruction=sys_prompt,
42
- temperature=0.1,
43
- ),
44
- contents=[text]
45
- )
46
- return response.text
 
9
  Maintain the original meaning and tone as closely as possible.
10
  """
11
 
 
12
 
13
+ def get_translaton(text: str, api_key: str, target_language: str) -> str:
14
+ if not api_key:
15
+ return "Error: Gemini API Key not found."
16
+ if not text:
17
+ return "Error: text not found."
18
 
19
+ try:
20
+ client = genai.Client(api_key=api_key)
21
+ except Exception as e:
22
+ return f"ERROR: {str(e)}"
23
 
24
+ lang_map = {
25
+ "العربية": "Arabic",
26
+ "Deutsch": "German",
27
+ "Español": "Spanish",
28
+ "English": "English",
29
+ "Français": "French",
30
+ "Italiano": "Italian",
31
+ "日本語": "Japanese",
32
+ "Русский язык": "Russian",
33
+ "中文": "Chinese",
34
+ }
35
+ tar_lang = lang_map.get(target_language, "English")
36
+ sys_prompt = SYS_PROMPT_TRANSLATION.replace("[TARGET_LANGUAGE]", tar_lang)
37
+ response = client.models.generate_content(
38
+ model="gemini-2.5-pro",
39
+ config=types.GenerateContentConfig(
40
+ system_instruction=sys_prompt,
41
+ temperature=0.1,
42
+ ),
43
+ contents=[text],
44
+ )
45
+ return response.text