IvanMiao commited on
Commit
aeea3ef
·
1 Parent(s): 71cf823
app.py CHANGED
@@ -1,7 +1,8 @@
1
  import gradio as gr
 
2
  from process.ocr import perform_raw_ocr, correct_text_with_ai
3
  from process.interpretation import get_interpretation
4
- from process.translation import get_tranlaton
5
  from process.gradio_css import CUSTOM_CSS
6
 
7
 
@@ -28,7 +29,7 @@ def update_api_keys(mistral_key, gemini_key):
28
  return "API keys saved"
29
 
30
 
31
- def ocr_workflow_wrapper(file, mistral_key):
32
  """
33
  Manages the OCR workflow, processing an uploaded file to extract text.
34
 
@@ -41,21 +42,19 @@ def ocr_workflow_wrapper(file, mistral_key):
41
  """
42
  if not mistral_key:
43
  error_msg = "Error: Mistral API Key not set."
44
- yield error_msg, error_msg + "\n\n"
45
  return
46
- if not file:
47
  error_msg = "Error: File/Text not found."
48
- yield error_msg, error_msg + "\n\n"
49
  return
50
 
51
- yield "Processing...", "⏳ Processing, please wait...\n\n"
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 + "\n\n"
59
 
60
 
61
  def ai_correct(current_text: str, mistral_key: str):
@@ -71,20 +70,19 @@ def ai_correct(current_text: str, mistral_key: str):
71
  """
72
  if not mistral_key:
73
  error_msg = "Error: Mistral API Key not set."
74
- yield error_msg, error_msg + "\n\n"
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
- yield "⏳ AI Correcting text...", "⏳ AI Correcting text...\n\n*Please wait...*"
82
  try:
83
  result = correct_text_with_ai(current_text, mistral_key)
84
  yield result, result
85
  except Exception as e:
86
  error_msg = f"Error : {e}"
87
- yield error_msg, error_msg + "\n\n"
88
 
89
 
90
  def interpretation_workflow(text: str, genre: str, learn_language: str, target_language: str, gemini_key: str):
@@ -107,11 +105,11 @@ def interpretation_workflow(text: str, genre: str, learn_language: str, target_l
107
  if not text or text.strip() == "":
108
  yield "Error: Text is empty"
109
  return
110
- if not learn_language or target_language:
111
  yield "Error: Language not selected"
 
112
 
113
- if genre.lower() in ["general", "news"]:
114
- yield f"⏳ Generating interpretation for genre: {[genre]} ... (10s - 2min)"
115
  result = get_interpretation(genre.lower(), gemini_key, text, learn_language, target_language)
116
  yield result
117
  else:
@@ -139,9 +137,8 @@ def translation_workflow(text: str, target_language: str, gemini_key):
139
  if not target_language:
140
  yield "Error: Language not selected"
141
 
142
- if target_language in ["Deutsch", "English", "Français", "Русский язык", "中文"]:
143
- yield f"⏳ Generating interpretation for target_language: {[target_language]} ..."
144
- result = get_tranlaton(text, gemini_key, target_language)
145
  yield result
146
  else:
147
  yield "not implemented yet"
@@ -206,6 +203,7 @@ with gr.Blocks(theme=gr.themes.Monochrome(), css=CUSTOM_CSS) as demo:
206
  with gr.Tab("Formatted Text"):
207
  text_markdown = gr.Markdown(
208
  value="*Processed text will appear here...*\n\n",
 
209
  )
210
 
211
  # Hook the ocr button to click event
@@ -228,15 +226,16 @@ with gr.Blocks(theme=gr.themes.Monochrome(), css=CUSTOM_CSS) as demo:
228
 
229
  with gr.Row():
230
  with gr.Column(scale=1):
231
- prof_language_seletor = gr.Dropdown(["DE", "EN", "FR", "RU", "ZH"], label="Prof's Language", value="EN")
232
- learn_language_seletor = gr.Dropdown(["DE", "EN", "FR", "RU", "ZH"], label="Language to Learn", value="EN")
233
- style_seletor = gr.Dropdown(["General", "Paper", "News", "Narrative", "Poem", "Philosophy"], label="Genre")
234
  interpret_button = gr.Button("Generate Interpretation", variant="primary")
235
 
236
  with gr.Column(scale=2):
237
  gr.Markdown("### COURSE")
238
  interpretation_output = gr.Markdown(
239
  value="*Interpretation will appear here after processing...*\n\n",
 
240
  show_copy_button=True
241
  )
242
 
@@ -251,7 +250,7 @@ with gr.Blocks(theme=gr.themes.Monochrome(), css=CUSTOM_CSS) as demo:
251
  with gr.Row():
252
  with gr.Column(scale=1):
253
  target_language_selector = gr.Dropdown(
254
- ["Deutsch", "English", "Français", "Русский язык", "中文"],
255
  value="English",
256
  label="Target Language",
257
  interactive=True)
@@ -260,6 +259,7 @@ with gr.Blocks(theme=gr.themes.Monochrome(), css=CUSTOM_CSS) as demo:
260
  with gr.Column(scale=2):
261
  interpretation_output = gr.Markdown(
262
  value="*Translation will appear here ...*\n\n",
 
263
  show_copy_button=True
264
  )
265
 
 
1
  import gradio as gr
2
+ from gradio import File
3
  from process.ocr import perform_raw_ocr, correct_text_with_ai
4
  from process.interpretation import get_interpretation
5
+ from process.translation import get_translaton
6
  from process.gradio_css import CUSTOM_CSS
7
 
8
 
 
29
  return "API keys saved"
30
 
31
 
32
+ def ocr_workflow_wrapper(file: File, mistral_key: str):
33
  """
34
  Manages the OCR workflow, processing an uploaded file to extract text.
35
 
 
42
  """
43
  if not mistral_key:
44
  error_msg = "Error: Mistral API Key not set."
45
+ yield error_msg, error_msg
46
  return
47
+ if not file or file.name == "":
48
  error_msg = "Error: File/Text not found."
49
+ yield error_msg, error_msg
50
  return
51
 
 
 
52
  try:
53
  result = perform_raw_ocr(file, mistral_key)
54
  yield result, f"\n{result}\n"
55
  except Exception as e:
56
  error_msg = f"An error occurred during processing: {str(e)}"
57
+ yield error_msg, error_msg
58
 
59
 
60
  def ai_correct(current_text: str, mistral_key: str):
 
70
  """
71
  if not mistral_key:
72
  error_msg = "Error: Mistral API Key not set."
73
+ yield error_msg, error_msg
74
  return
75
  if not current_text or current_text.strip() == "":
76
  error_msg = "*No text to correct. Upload a file, or paste text into 'Raw Text' box first*"
77
  yield error_msg, error_msg
78
  return
79
 
 
80
  try:
81
  result = correct_text_with_ai(current_text, mistral_key)
82
  yield result, result
83
  except Exception as e:
84
  error_msg = f"Error : {e}"
85
+ yield error_msg, error_msg
86
 
87
 
88
  def interpretation_workflow(text: str, genre: str, learn_language: str, target_language: str, gemini_key: str):
 
105
  if not text or text.strip() == "":
106
  yield "Error: Text is empty"
107
  return
108
+ if not learn_language or not target_language:
109
  yield "Error: Language not selected"
110
+ return
111
 
112
+ if genre.lower() in ["general", "news", "philosophy"]:
 
113
  result = get_interpretation(genre.lower(), gemini_key, text, learn_language, target_language)
114
  yield result
115
  else:
 
137
  if not target_language:
138
  yield "Error: Language not selected"
139
 
140
+ if target_language in ["العربية", "Deutsch", "Español", "English", "Français", "Italiano", "日本語", "Русский язык", "中文"]:
141
+ result = get_translaton(text, gemini_key, target_language)
 
142
  yield result
143
  else:
144
  yield "not implemented yet"
 
203
  with gr.Tab("Formatted Text"):
204
  text_markdown = gr.Markdown(
205
  value="*Processed text will appear here...*\n\n",
206
+ label="Formatted Text"
207
  )
208
 
209
  # Hook the ocr button to click event
 
226
 
227
  with gr.Row():
228
  with gr.Column(scale=1):
229
+ prof_language_seletor = gr.Dropdown(["AR", "DE", "ES", "EN", "FR", "IT", "JA", "RU", "ZH"], label="Prof's Language", value="EN")
230
+ learn_language_seletor = gr.Dropdown(["AR", "DE", "ES", "EN", "FR", "IT", "JA", "RU", "ZH"], label="Language to Learn", value="EN")
231
+ style_seletor = gr.Dropdown(["General", "News", "Philosophy", "Narrative", "Poem", "Paper"], label="Genre")
232
  interpret_button = gr.Button("Generate Interpretation", variant="primary")
233
 
234
  with gr.Column(scale=2):
235
  gr.Markdown("### COURSE")
236
  interpretation_output = gr.Markdown(
237
  value="*Interpretation will appear here after processing...*\n\n",
238
+ label="Interpretation Result",
239
  show_copy_button=True
240
  )
241
 
 
250
  with gr.Row():
251
  with gr.Column(scale=1):
252
  target_language_selector = gr.Dropdown(
253
+ ["العربية", "Deutsch", "Español", "English", "Français", "Italiano", "日本語", "Русский язык", "中文"],
254
  value="English",
255
  label="Target Language",
256
  interactive=True)
 
259
  with gr.Column(scale=2):
260
  interpretation_output = gr.Markdown(
261
  value="*Translation will appear here ...*\n\n",
262
+ label="Translation Result",
263
  show_copy_button=True
264
  )
265
 
process/interpretation.py CHANGED
@@ -1,11 +1,11 @@
1
  from google import genai
2
  from google.genai import types
3
- from process.sys_prompt import GENERAL_PROMPT, NEWS_PROMPT
4
 
5
 
6
  NARRATIVE_PROMPT = ""
7
  POEM_PROMPT = ""
8
- PHILO_PROMPT = ""
9
 
10
  def get_interpretation(genre: str,
11
  api_key: str,
@@ -18,9 +18,13 @@ def get_interpretation(genre: str,
18
  if not text:
19
  return "Error: text not found."
20
 
21
- client = genai.Client(api_key=api_key)
 
 
 
 
22
 
23
- lang_map ={"DE": "German", "EN": "English", "FR": "French", "RU":"Russian", "ZH": "Chinese"}
24
  learn_lang = lang_map.get(learn_language.upper(), "English")
25
  prof_lang = lang_map.get(prof_language.upper(), "English")
26
  genres = {
@@ -30,7 +34,7 @@ def get_interpretation(genre: str,
30
  "poem": POEM_PROMPT,
31
  "philosophy": PHILO_PROMPT
32
  }
33
- if genre.lower() in ["general", "news"]:
34
  sys_prompt = genres[genre.lower()].replace("[LEARN_LANGUAGE]", learn_lang).replace("[PROF_LANGUAGE]", prof_lang)
35
 
36
  response = client.models.generate_content(
 
1
  from google import genai
2
  from google.genai import types
3
+ from process.sys_prompt import GENERAL_PROMPT, NEWS_PROMPT, PHILO_PROMPT
4
 
5
 
6
  NARRATIVE_PROMPT = ""
7
  POEM_PROMPT = ""
8
+
9
 
10
  def get_interpretation(genre: str,
11
  api_key: str,
 
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 = {
 
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(
process/ocr.py CHANGED
@@ -1,16 +1,21 @@
1
  from mistralai import Mistral
2
  from mistralai.models import OCRResponse
3
-
4
 
5
  OCR_MODEL = "mistral-ocr-latest"
6
  CHAT_MODEL = "mistral-large-latest"
7
 
8
 
9
- def ocr_from_file(file_path, api_key, mode="image"):
10
 
11
  if not api_key:
12
  raise ValueError("Mistral API Key is required.")
13
- client = Mistral(api_key=api_key)
 
 
 
 
 
14
  uploaded_image = client.files.upload(
15
  file={
16
  "file_name": file_path,
@@ -51,11 +56,15 @@ def get_combined_markdown(ocr_response: OCRResponse) -> str:
51
  return "\n\n".join(markdowns)
52
 
53
 
54
- def correct_text_with_ai(text: str, api_key: str):
55
 
56
  if not api_key:
57
  raise ValueError("Mistral API Key is required.")
58
- client = Mistral(api_key=api_key)
 
 
 
 
59
 
60
  response = client.chat.complete(
61
  model=CHAT_MODEL,
@@ -85,8 +94,8 @@ def correct_text_with_ai(text: str, api_key: str):
85
  return(response.choices[0].message.content)
86
 
87
 
88
- def perform_raw_ocr(input_file, api_key):
89
- if input_file != None:
90
  file_ext = input_file.name.split('.')[-1].lower()
91
  else:
92
  return "File/Text not found"
 
1
  from mistralai import Mistral
2
  from mistralai.models import OCRResponse
3
+ from gradio import File
4
 
5
  OCR_MODEL = "mistral-ocr-latest"
6
  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,
 
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,
 
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"
process/sys_prompt.py CHANGED
@@ -89,6 +89,50 @@ NEWS_PROMPT = """
89
  * Clear and logical in language, able to deconstruct complex news content into easily understandable parts.
90
  """
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  NARRATIVE_PROMPT = ""
93
  POEM_PROMPT = ""
94
- PHILO_PROMPT = ""
 
89
  * Clear and logical in language, able to deconstruct complex news content into easily understandable parts.
90
  """
91
 
92
+
93
+ PHILO_PROMPT = """
94
+ ## Core Purpose and Goals:
95
+
96
+ * To assist students with **intermediate to advanced `[LEARN_LANGUAGE]` proficiency** in mastering sophisticated aspects of the language through the deep analysis of complex, authentic **philosophical and literary** texts.
97
+ * To explain complex grammatical phenomena and syntactic structures, particularly those characteristic of philosophical argumentation or literary prose in `[LEARN_LANGUAGE]`.
98
+ * To analyze and clarify idiomatic expressions, domain-specific terminology (especially philosophical and literary terms), and fixed phrases found in the `[LEARN_LANGUAGE]` text.
99
+ * To deconstruct long, complex sentences in `[LEARN_LANGUAGE]`, analyzing their internal logical relationships, information hierarchy, and argumentative chains.
100
+ * To deeply explore rhetorical devices (e.g., metaphors, irony, paradoxes) and any cultural, historical, or philosophical allusions within the text.
101
+ * To reveal the underlying logical connections—such as causality, contrast, or dialectical progression—between sentences and paragraphs.
102
+ * To analyze the macro-structure, authorial intent, and organizational methods of the text, adapting the analysis to its specific genre (e.g., argumentative structure of an essay, narrative framework of prose).
103
+ * To deliver instruction primarily in **`[PROF_LANGUAGE]`**, while flexibly using `[LEARN_LANGUAGE]` and English for clarification. When relevant, to introduce etymological insights from source languages (e.g., Latin, Ancient Greek) to aid vocabulary comprehension.
104
+ * To demonstrate profound understanding of the text's **philosophical or literary** subject matter, interpreting it from a broader intellectual perspective to help the student grasp its full context and deeper meaning.
105
+
106
+ ## Behaviors and Rules:
107
+
108
+ ### 1) Text Selection and Presentation:
109
+
110
+ * a) Use the challenging and profound `[LEARN_LANGUAGE]` text chosen by the user as the core material for analysis.
111
+ * b) When presenting the text, add annotations or highlights to key terminology and complex structures as needed to aid understanding.
112
+
113
+ ### 2) Explanation and Analysis:
114
+
115
+ * a) Explain **advanced or complex grammar points** within the text, focusing on syntactic structures common to its specific style and genre. **Omit basic grammar explanations.**
116
+ * b) Elucidate commonly used `[LEARN_LANGUAGE]` idioms, domain-specific terminology, and fixed phrases, providing contextual examples.
117
+ * c) Analyze the architecture of complex sentences to help the student map their logical flow and information hierarchy.
118
+ * d) Discuss rhetorical devices in the text and how the author uses language to construct an argument, shape opinion, or create a literary effect.
119
+ * e) Explain any cultural allusions, historical backgrounds, or philosophical concepts necessary to understand the text, providing essential context.
120
+ * f) Analyze the logical connectors and relationships between sentences and paragraphs, showing how the discourse unfolds.
121
+ * g) Explain the text's overall structure, argumentation methods, or narrative techniques, adapting the analysis to the text's genre (e.g., philosophical essay, literary prose).
122
+ * h) For each part of the analysis, deliver a **coherent, continuous lecture-style talk**, integrating all knowledge points into a unified and flowing explanation.
123
+
124
+ ### 3) Language Usage:
125
+
126
+ * a) Primarily use **`[PROF_LANGUAGE]`** and **`[LEARN_LANGUAGE]`** for instruction, with English readily available as an auxiliary language for clarification.
127
+ * b) When discussing etymology, introduce it based on its relevance to the `[LEARN_LANGUAGE]` and its practical utility for understanding modern vocabulary, especially philosophical terms.
128
+ * c) Demonstrate rigorous, clear, and precise language, especially when explaining complex concepts and structural analyses.
129
+
130
+ ## Overall Tone:
131
+
132
+ * **Knowledgeable and Rigorous:** Demonstrating deep expertise in `[LEARN_LANGUAGE]` linguistics as well as the philosophical and literary subject matter of the text.
133
+ * **Patient and Inspiring:** Encouraging the student to engage in critical thinking and deep reading.
134
+ * **Clear and Logical:** Capable of deconstructing complex material into understandable components.
135
+ """
136
+
137
  NARRATIVE_PROMPT = ""
138
  POEM_PROMPT = ""
 
process/translation.py CHANGED
@@ -9,15 +9,29 @@ 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_tranlaton(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
- client = genai.Client(api_key=api_key)
 
 
 
20
 
 
 
 
 
 
 
 
 
 
 
 
21
  lang_map = {"Deutsch": "German", "English": "English", "Français": "French", "Русский язык": "Russain", "中文": "Chinese"}
22
  tar_lang = lang_map.get(target_language, "English")
23
  sys_prompt = SYS_PROMPT_TRANSLATION.replace("[TARGET_LANGUAGE]", tar_lang)
 
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)