Spaces:
Sleeping
Sleeping
Delete question_runner.py
Browse files- question_runner.py +0 -226
question_runner.py
DELETED
|
@@ -1,226 +0,0 @@
|
|
| 1 |
-
# question_runner.py
|
| 2 |
-
|
| 3 |
-
import tempfile
|
| 4 |
-
import re
|
| 5 |
-
from router_client import query_model
|
| 6 |
-
from doc_utils import get_questions_from_doc
|
| 7 |
-
from config import SYNTAX_DOC_URL, MORPHOLOGY_DOC_URL, SEMANTICS_DOC_URL
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
def detect_language(passage):
|
| 11 |
-
"""
|
| 12 |
-
Detect whether the passage is in Latin or Greek based on character analysis.
|
| 13 |
-
|
| 14 |
-
Returns:
|
| 15 |
-
str: 'latin', 'greek', or 'unknown'
|
| 16 |
-
"""
|
| 17 |
-
# Remove whitespace, punctuation, and numbers for analysis
|
| 18 |
-
import string
|
| 19 |
-
punctuation_and_whitespace = set(string.punctuation + string.whitespace + string.digits)
|
| 20 |
-
cleaned = ''.join(char for char in passage if char not in punctuation_and_whitespace)
|
| 21 |
-
|
| 22 |
-
# Greek alphabet ranges (Unicode)
|
| 23 |
-
greek_chars = re.findall(r'[\u0370-\u03FF\u1F00-\u1FFF]', cleaned)
|
| 24 |
-
|
| 25 |
-
# Latin alphabet - look for standard Latin letters
|
| 26 |
-
# Greek text might have some Latin, so we check for Greek-specific patterns
|
| 27 |
-
latin_chars = re.findall(r'[a-zA-Z]', cleaned)
|
| 28 |
-
|
| 29 |
-
if not cleaned:
|
| 30 |
-
return 'unknown'
|
| 31 |
-
|
| 32 |
-
# If we find Greek characters, it's Greek
|
| 33 |
-
if greek_chars and len(greek_chars) > len(cleaned) * 0.3: # At least 30% Greek chars
|
| 34 |
-
return 'greek'
|
| 35 |
-
|
| 36 |
-
# Otherwise assume Latin if it has Latin characters
|
| 37 |
-
if latin_chars and len(latin_chars) > len(cleaned) * 0.3:
|
| 38 |
-
return 'latin'
|
| 39 |
-
|
| 40 |
-
return 'unknown'
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
def get_language_specific_instructions(language, doc_type):
|
| 44 |
-
"""
|
| 45 |
-
Generate language-specific instructions to prevent AI hallucinations
|
| 46 |
-
and incorrect application of grammatical rules.
|
| 47 |
-
|
| 48 |
-
Args:
|
| 49 |
-
language: 'latin' or 'greek'
|
| 50 |
-
doc_type: 'syntax', 'morphology', or 'semantics'
|
| 51 |
-
|
| 52 |
-
Returns:
|
| 53 |
-
str: Language-specific instruction text
|
| 54 |
-
"""
|
| 55 |
-
if language == 'latin':
|
| 56 |
-
if doc_type.lower() == 'morphology':
|
| 57 |
-
return """You are a Latin morphology expert. When analyzing Latin:
|
| 58 |
-
- Focus ONLY on Latin grammatical categories: tense, mood, voice, person, number, case, gender
|
| 59 |
-
- Use traditional Latin grammatical terminology
|
| 60 |
-
- Do NOT apply Greek-specific concepts like the dual number (which does not exist in Latin)
|
| 61 |
-
- Do NOT apply Greek-specific mood distinctions
|
| 62 |
-
- Remember Latin has 6 cases (nominative, genitive, dative, accusative, ablative, vocative)
|
| 63 |
-
- Remember Latin verb system: 6 tenses, 3 moods (indicative, subjunctive, imperative), 3 voices"""
|
| 64 |
-
elif doc_type.lower() == 'syntax':
|
| 65 |
-
return """You are a Latin syntax expert. When analyzing Latin:
|
| 66 |
-
- Apply ONLY Latin syntactic rules and conventions
|
| 67 |
-
- Focus on Latin clause structure, agreement patterns, and word order principles
|
| 68 |
-
- Do NOT assume Greek syntactic conventions (e.g., Greek subjunctive/optative patterns may differ)
|
| 69 |
-
- Remember Latin typically uses SVO/SOV word order with flexible positioning
|
| 70 |
-
- Apply Roman conventions for subordination and clause relationships
|
| 71 |
-
- Do NOT apply Modern Greek or Koine Greek-specific syntax patterns"""
|
| 72 |
-
else: # semantics
|
| 73 |
-
return """You are a Latin semantics expert. When analyzing Latin meaning:
|
| 74 |
-
- Focus on etymological and semantic fields relevant to Latin
|
| 75 |
-
- Use Roman cultural context to interpret meaning
|
| 76 |
-
- Do NOT apply Greek philosophical or semantic frameworks that may not apply to Latin texts
|
| 77 |
-
- Consider the historical period of the text (Classical, Silver Age, etc.)
|
| 78 |
-
- Remember Latin word meanings evolved differently from their Greek cognates"""
|
| 79 |
-
|
| 80 |
-
elif language == 'greek':
|
| 81 |
-
if doc_type.lower() == 'morphology':
|
| 82 |
-
return """You are an Ancient Greek morphology expert. When analyzing Ancient Greek:
|
| 83 |
-
- Focus ONLY on Ancient Greek grammatical categories: tense, mood, voice, person, number, case, gender, dual
|
| 84 |
-
- Use Attic/Ionic Greek conventions as appropriate to the text
|
| 85 |
-
- Remember Greek HAS the dual number (in addition to singular and plural)
|
| 86 |
-
- Remember Greek has 3 moods: indicative, subjunctive, optative
|
| 87 |
-
- Remember Greek has 5 cases (nominative, genitive, dative, accusative, vocative)
|
| 88 |
-
- Do NOT apply Latin-specific grammatical categories (Latin lacks dual, has different mood system)"""
|
| 89 |
-
elif doc_type.lower() == 'syntax':
|
| 90 |
-
return """You are an Ancient Greek syntax expert. When analyzing Ancient Greek:
|
| 91 |
-
- Apply ONLY Ancient Greek syntactic rules and conventions
|
| 92 |
-
- Focus on Greek clause structure, participle usage, and optative/subjunctive patterns
|
| 93 |
-
- Do NOT assume Latin syntactic conventions (Latin lacks Greek optative, uses subjunctive differently)
|
| 94 |
-
- Remember Greek favors parataxis and uses participles extensively
|
| 95 |
-
- Apply Greek conventions for indirect discourse and optative in conditional sentences
|
| 96 |
-
- Do NOT apply Latin syntax patterns"""
|
| 97 |
-
else: # semantics
|
| 98 |
-
return """You are an Ancient Greek semantics expert. When analyzing Greek meaning:
|
| 99 |
-
- Focus on etymological and semantic fields relevant to Ancient Greek
|
| 100 |
-
- Use Hellenic cultural and philosophical context to interpret meaning
|
| 101 |
-
- Do NOT apply Roman cultural frameworks that may not apply to Greek texts
|
| 102 |
-
- Consider whether the text is Attic, Ionic, or another Greek dialect
|
| 103 |
-
- Remember Greek philosophical terminology has specific meanings distinct from Latin usage"""
|
| 104 |
-
|
| 105 |
-
else: # unknown language
|
| 106 |
-
return """You are a classical language expert analyzing a passage of unknown classical language.
|
| 107 |
-
- First identify whether the text is in Latin or Greek
|
| 108 |
-
- Then apply only the grammatical and syntactic rules appropriate to that language
|
| 109 |
-
- Be careful not to mix grammatical conventions between Latin and Greek
|
| 110 |
-
- If unable to determine, ask for clarification"""
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
def create_language_aware_prompt(passage, question, language):
|
| 114 |
-
"""
|
| 115 |
-
Create a prompt that is aware of the language and specific doc type.
|
| 116 |
-
|
| 117 |
-
Args:
|
| 118 |
-
passage: The text to analyze
|
| 119 |
-
question: The question to answer
|
| 120 |
-
language: 'latin', 'greek', or 'unknown'
|
| 121 |
-
|
| 122 |
-
Returns:
|
| 123 |
-
str: The complete prompt
|
| 124 |
-
"""
|
| 125 |
-
language_context = {
|
| 126 |
-
'latin': 'Latin',
|
| 127 |
-
'greek': 'Ancient Greek',
|
| 128 |
-
'unknown': 'Latin or Greek'
|
| 129 |
-
}[language]
|
| 130 |
-
|
| 131 |
-
prompt = f"""You are a classical language expert specializing in {language_context}.
|
| 132 |
-
|
| 133 |
-
LANGUAGE IDENTIFIED: {language.upper()}
|
| 134 |
-
|
| 135 |
-
Given the following {language_context} passage:
|
| 136 |
-
|
| 137 |
-
{passage}
|
| 138 |
-
|
| 139 |
-
Answer the following question concisely and directly:
|
| 140 |
-
|
| 141 |
-
{question}
|
| 142 |
-
|
| 143 |
-
IMPORTANT GUIDELINES:
|
| 144 |
-
- Only apply grammatical and syntactic rules specific to {language_context}
|
| 145 |
-
- Do not confuse or mix conventions from Latin and Greek
|
| 146 |
-
- If the question asks about a grammatical feature that doesn't exist in {language_context}, note that explicitly
|
| 147 |
-
- Be precise about which language's conventions you are applying
|
| 148 |
-
- Provide ONLY your direct answer without explanation of your reasoning process
|
| 149 |
-
- Do NOT repeat the question or reiterate the principles you're using
|
| 150 |
-
- Keep your answer brief and focused
|
| 151 |
-
|
| 152 |
-
Answer:"""
|
| 153 |
-
|
| 154 |
-
return prompt
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
def run_tool(passage, doc_type):
|
| 158 |
-
if not passage.strip():
|
| 159 |
-
return "Please enter a passage to analyze.", None, None
|
| 160 |
-
if not doc_type:
|
| 161 |
-
return "Please select 'Syntax', 'Morphology', or 'Semantics'.", None, None
|
| 162 |
-
|
| 163 |
-
try:
|
| 164 |
-
# Detect the language of the passage
|
| 165 |
-
language = detect_language(passage)
|
| 166 |
-
|
| 167 |
-
if doc_type.lower() == "syntax":
|
| 168 |
-
doc_url = SYNTAX_DOC_URL
|
| 169 |
-
elif doc_type.lower() == "morphology":
|
| 170 |
-
doc_url = MORPHOLOGY_DOC_URL
|
| 171 |
-
else: # semantics
|
| 172 |
-
doc_url = SEMANTICS_DOC_URL
|
| 173 |
-
questions = get_questions_from_doc(doc_url)
|
| 174 |
-
|
| 175 |
-
if not questions or questions[0].startswith("Error"):
|
| 176 |
-
return questions[0], None, None
|
| 177 |
-
|
| 178 |
-
est_seconds = round(len(questions) * 2.5, 1)
|
| 179 |
-
estimated_time_message = f"Estimated generation time: ~{est_seconds} seconds"
|
| 180 |
-
|
| 181 |
-
responses = []
|
| 182 |
-
for idx, question in enumerate(questions):
|
| 183 |
-
# Get language-specific instructions
|
| 184 |
-
language_instructions = get_language_specific_instructions(language, doc_type)
|
| 185 |
-
|
| 186 |
-
# Create language-aware prompt
|
| 187 |
-
base_prompt = create_language_aware_prompt(passage, question, language)
|
| 188 |
-
|
| 189 |
-
# Combine with language-specific instructions
|
| 190 |
-
prompt = f"""{language_instructions}
|
| 191 |
-
|
| 192 |
-
---
|
| 193 |
-
|
| 194 |
-
{base_prompt}"""
|
| 195 |
-
|
| 196 |
-
raw_response, model_used = query_model(prompt)
|
| 197 |
-
|
| 198 |
-
if not raw_response or not model_used:
|
| 199 |
-
formatted_block = f"""Question: {question.strip()}
|
| 200 |
-
Answer:
|
| 201 |
-
<No answer – all models failed or quota exceeded.>
|
| 202 |
-
Language Detected: {language.upper()}
|
| 203 |
-
===
|
| 204 |
-
"""
|
| 205 |
-
else:
|
| 206 |
-
answer = raw_response.split("Answer:")[-1].strip()
|
| 207 |
-
formatted_block = f"""Question: {question.strip()}
|
| 208 |
-
Answer:
|
| 209 |
-
{answer}
|
| 210 |
-
Language Detected: {language.upper()}
|
| 211 |
-
Model used: {model_used}
|
| 212 |
-
===""" # Separator for logic tree parsing
|
| 213 |
-
|
| 214 |
-
responses.append(formatted_block)
|
| 215 |
-
|
| 216 |
-
result = "\n\n".join(responses)
|
| 217 |
-
|
| 218 |
-
with tempfile.NamedTemporaryFile(delete=False, suffix=".txt", mode="w", encoding="utf-8") as f:
|
| 219 |
-
f.write(result)
|
| 220 |
-
file_path = f.name
|
| 221 |
-
|
| 222 |
-
return result, file_path, estimated_time_message
|
| 223 |
-
|
| 224 |
-
except Exception as e:
|
| 225 |
-
return f"An error occurred: {str(e)}", None, None
|
| 226 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|