rawireview / review_api.py
walker11's picture
Upload 6 files
4b4d390 verified
import os
import requests
import random
import logging
import json
try:
from PyPDF2 import PdfReader
except ImportError:
# Fallback for Docker environment
from pypdf import PdfReader
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Check for environment variable or use a default value for testing
def get_api_key():
api_key = os.environ.get('DEEPSEEK_API_KEY')
if not api_key:
logger.warning("No DEEPSEEK_API_KEY environment variable found. Using mock responses.")
return api_key
# Mock evaluation result for testing
def get_mock_evaluation(story_excerpt):
# Use a short excerpt of the story in the evaluation to make it look personalized
story_start = story_excerpt[:100].replace("\n", " ").strip()
if len(story_start) > 50:
story_start = story_start[:50] + "..."
# Generate random scores but keep them reasonable
unity_score = random.randint(6, 9)
characters_score = random.randint(6, 9)
decisive_moment_score = random.randint(7, 10)
language_score = random.randint(5, 9)
time_place_score = random.randint(6, 9)
plot_score = random.randint(7, 10)
ending_score = random.randint(6, 10)
message_score = random.randint(6, 9)
total_score = unity_score + characters_score + decisive_moment_score + language_score + \
time_place_score + plot_score + ending_score + message_score
# Mock evaluation text
return {
"evaluation": f"""📋 التقييم:
وحدة الحدث: {unity_score}/10
القصة تدور حول حدث رئيسي بشكل جيد، وتحافظ على تماسك الأحداث.
الشخصيات المحدودة والمعرّفة: {characters_score}/10
الشخصيات محددة بوضوح ومتميزة، مع تطوير مناسب للشخصيات الرئيسية.
التركيز على لحظة حاسمة: {decisive_moment_score}/10
القصة تبني بمهارة نحو لحظة التحول الرئيسية التي تغير مسار الأحداث.
الإيجاز واقتصاد اللغة: {language_score}/10
اللغة موجزة ومعبرة، تنقل المعاني بفعالية دون إطناب غير ضروري.
وحدة الزمان والمكان: {time_place_score}/10
هناك استخدام متناسق للإطار الزماني والمكاني، مما يعزز تماسك القصة.
حبكة جيدة البناء: {plot_score}/10
الحبكة متطورة بشكل منطقي ومتماسك، مع تسلسل واضح للأحداث.
نهاية مؤثرة: {ending_score}/10
النهاية تترك انطباعًا قويًا وتوفر إغلاقًا مناسبًا للأحداث.
رسالة أو موضوع واضح: {message_score}/10
تُظهر القصة رسالة واضحة تتطور بشكل طبيعي من خلال الأحداث.
النتيجة النهائية: {total_score}/80
{"هذا عمل أدبي متميز يتسم بقوة البناء والتماسك. القصة تحقق توازنًا جيدًا بين تطوير الشخصيات وتقدم الحبكة." if total_score > 65 else "رغم وجود عناصر قوية في القصة، هناك مجال للتحسين في بعض الجوانب. ننصح بالتركيز على تعزيز تماسك الأحداث وتطوير الشخصيات بشكل أعمق."}
ملاحظة: بداية القصة "{story_start}" تظهر إمكانات جيدة وتجذب اهتمام القارئ.""",
"fixed_story": None
}
def review_story(pdf_path):
"""
Review a story from a PDF file
"""
try:
# Load text from PDF
text = ""
try:
with open(pdf_path, "rb") as f:
reader = PdfReader(f)
text = "\n".join([p.extract_text() for p in reader.pages if p.extract_text()])
text = " ".join(text.split())
except Exception as e:
logger.error(f"PDF loading failed: {e}")
return {"evaluation": f"Error loading PDF: {e}", "fixed_story": None}
# Get evaluation
api_key = get_api_key()
if not api_key:
# Return mock evaluation
logger.info("Using mock evaluation for PDF")
return get_mock_evaluation(text)
# Use API for evaluation
return call_api_for_evaluation(text)
except Exception as e:
logger.error(f"Error in review_story: {e}")
return {"evaluation": f"Error processing story: {e}", "fixed_story": None}
def review_story_text(story_text):
"""
Review a story provided as text directly
"""
try:
# Get evaluation
api_key = get_api_key()
if not api_key:
# Return mock evaluation
logger.info("Using mock evaluation for text")
return get_mock_evaluation(story_text)
# Use API for evaluation
return call_api_for_evaluation(story_text)
except Exception as e:
logger.error(f"Error in review_story_text: {e}")
return {"evaluation": f"Error processing story text: {e}", "fixed_story": None}
def call_api_for_evaluation(story):
"""
Call the DeepSeek API for story evaluation
"""
api_key = get_api_key()
if not api_key:
return get_mock_evaluation(story)
evaluation_prompt = f"""
You are a professional literary critic specializing in the art of the short story. Your task is to evaluate the following story according to 8 essential criteria used in literary criticism. You must write the full evaluation in Modern Standard Arabic, using a clear and organized style.
🔹 For each criterion:
Give a score out of 10.
Write a brief explanation (one or two lines) that justifies the score.
🔹 At the end of the evaluation:
Add up the scores to get a final result out of 80.
If the score is above 65: Praise the story as a successful and well-crafted literary work.
If the score is 65 or lower: Provide constructive criticism that highlights the main weaknesses and suggests how to improve them.
Start the evaluation with a title that includes an emoji, such as: 📋 التقييم:
🔹 The evaluation criteria are:
1. Unity of event: Does the story revolve around a single main incident or situation?
2. Limited and defined characters: Does the story include a small number of clear and distinctive characters?
3. Focus on a decisive moment: Does the story highlight a turning point or critical decision?
4. Conciseness and economy of language: Is the language focused and free of unnecessary details?
5. Unity of time and place: Does the story take place in a specific time and setting?
6. Well-structured plot: Is there a clear logical sequence (beginning, middle, end)?
7. Impactful ending: Does the ending leave an emotional or intellectual impact?
8. Clear message or theme: Does the story convey a specific idea or feeling clearly?
Evaluate the following story based on these criteria:
{story}
"""
url = "https://api.deepseek.com/v1/chat/completions"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
payload_eval = {
"model": "deepseek-chat",
"messages": [
{"role": "system", "content": "You are a formal short story evaluator."},
{"role": "user", "content": evaluation_prompt.strip()}
],
"temperature": random.uniform(0.9, 1.0),
"max_tokens": 2500
}
try:
logger.info("Sending request to DeepSeek API")
response_eval = requests.post(url, headers=headers, json=payload_eval)
if response_eval.status_code != 200:
logger.error(f"API Error: {response_eval.status_code} - {response_eval.text}")
return {"evaluation": f"Error from API: {response_eval.text}", "fixed_story": None}
evaluation_result = response_eval.json()["choices"][0]["message"]["content"]
logger.info("Successfully received evaluation from API")
return {
"evaluation": evaluation_result.strip(),
"fixed_story": None
}
except Exception as e:
logger.error(f"API call failed: {e}")
return {"evaluation": f"Error calling API: {e}", "fixed_story": None}